class AIMoveToCommandHandler extends AICommandHandlerBase
{
	protected editable inlined var m_outIsDynamicMove : AIArgumentMapping;
	protected editable inlined var m_outMovementTarget : AIArgumentMapping;
	protected editable inlined var m_outMovementTargetPos : AIArgumentMapping;
	protected editable inlined var m_outRotateEntityTowardsFacingTarget : AIArgumentMapping;
	protected editable inlined var m_outFacingTarget : AIArgumentMapping;
	protected editable inlined var m_outMovementType : AIArgumentMapping;
	protected editable inlined var m_outIgnoreNavigation : AIArgumentMapping;
	protected editable inlined var m_outUseStart : AIArgumentMapping;
	protected editable inlined var m_outUseStop : AIArgumentMapping;
	protected editable inlined var m_outDesiredDistanceFromTarget : AIArgumentMapping;
	protected editable inlined var m_outFinishWhenDestinationReached : AIArgumentMapping;

	protected override function UpdateCommand( context : ScriptExecutionContext, command : AICommand ) : AIbehaviorUpdateOutcome
	{
		var currentHighLevelState : gamedataNPCHighLevelState;
		var typedCommand : AIMoveToCommand;
		var isDynamicMove : Bool;
		typedCommand = ( ( AIMoveToCommand )( command ) );
		if( !( typedCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		isDynamicMove = AIPositionSpec.IsEntity( typedCommand.movementTarget );
		ScriptExecutionContext.SetMappingValue( context, m_outIsDynamicMove, isDynamicMove );
		if( isDynamicMove )
		{
			ScriptExecutionContext.SetMappingValue( context, m_outMovementTarget, ( ( weak< weak< GameObject > > )( AIPositionSpec.GetEntity( typedCommand.movementTarget ) ) ) );
		}
		else if( AIPositionSpec.IsEmpty( typedCommand.movementTarget ) )
		{
			ScriptExecutionContext.SetMappingValue( context, m_outMovementTargetPos, MovePolicies.GetInvalidPos() );
		}
		else
		{
			ScriptExecutionContext.SetMappingValue( context, m_outMovementTargetPos, AIPositionSpec.GetWorldPosition( typedCommand.movementTarget ) );
		}
		if( !( ScriptExecutionContext.SetMappingValue( context, m_outRotateEntityTowardsFacingTarget, typedCommand.rotateEntityTowardsFacingTarget ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( AIPositionSpec.IsEntity( typedCommand.facingTarget ) )
		{
			if( !( ScriptExecutionContext.SetMappingValue( context, m_outFacingTarget, ( ( weak< weak< GameObject > > )( AIPositionSpec.GetEntity( typedCommand.facingTarget ) ) ) ) ) )
			{
				return AIbehaviorUpdateOutcome.FAILURE;
			}
		}
		if( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetNPCType() == gamedataNPCType.Drone )
		{
			ScriptExecutionContext.SetEnumMappingValue( context, m_outMovementType, ( ( Int64 )( moveMovementType.Walk ) ) );
			DroneComponent.SetLocomotionWrappers( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ), EnumValueToName( 'moveMovementType', ( ( Int64 )( typedCommand.movementType ) ) ) );
		}
		else if( typedCommand.movementType == moveMovementType.Run )
		{
			currentHighLevelState = ( ( gamedataNPCHighLevelState )( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetPuppetStateBlackboard().GetInt( GetAllBlackboardDefs().PuppetState.HighLevel ) ) );
			if( currentHighLevelState == gamedataNPCHighLevelState.Combat && !( ScriptExecutionContext.SetEnumMappingValue( context, m_outMovementType, ( ( Int64 )( moveMovementType.Sprint ) ) ) ) )
			{
				return AIbehaviorUpdateOutcome.FAILURE;
			}
			else if( !( ScriptExecutionContext.SetEnumMappingValue( context, m_outMovementType, ( ( Int64 )( typedCommand.movementType ) ) ) ) )
			{
				return AIbehaviorUpdateOutcome.FAILURE;
			}
		}
		else if( !( ScriptExecutionContext.SetEnumMappingValue( context, m_outMovementType, ( ( Int64 )( typedCommand.movementType ) ) ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( ScriptExecutionContext.SetMappingValue( context, m_outIgnoreNavigation, typedCommand.ignoreNavigation ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( ScriptExecutionContext.SetMappingValue( context, m_outUseStart, typedCommand.useStart ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( ScriptExecutionContext.SetMappingValue( context, m_outUseStop, typedCommand.useStop ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( ScriptExecutionContext.SetMappingValue( context, m_outDesiredDistanceFromTarget, typedCommand.desiredDistanceFromTarget ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( !( ScriptExecutionContext.SetMappingValue( context, m_outFinishWhenDestinationReached, typedCommand.finishWhenDestinationReached ) ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( typedCommand.alwaysUseStealth )
		{
			NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Stealth );
		}
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

}

class AIMoveOnSplineCommandHandler extends AICommandHandlerBase
{
	protected editable inlined var m_outSpline : AIArgumentMapping;
	protected editable inlined var m_outMovementType : AIArgumentMapping;
	protected editable inlined var m_outRotateTowardsFacingTarget : AIArgumentMapping;
	protected editable inlined var m_outFacingTarget : AIArgumentMapping;
	protected editable inlined var m_outSnapToTerrain : AIArgumentMapping;
	protected editable inlined var m_allowCrowdOnPath : AIArgumentMapping;

	protected override function UpdateCommand( context : ScriptExecutionContext, command : AICommand ) : AIbehaviorUpdateOutcome
	{
		var typedCommand : AIMoveOnSplineCommand;
		var currentHighLevelState : gamedataNPCHighLevelState;
		typedCommand = ( ( AIMoveOnSplineCommand )( command ) );
		if( !( typedCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		if( GetPuppet( context ).GetNPCType() == gamedataNPCType.Drone )
		{
			DroneComponent.SetLocomotionWrappers( GetPuppet( context ), EnumValueToName( 'moveMovementType', ( ( Int64 )( typedCommand.movementType.movementType ) ) ) );
			typedCommand.movementType.movementType = moveMovementType.Walk;
		}
		else if( typedCommand.movementType.movementType == moveMovementType.Run )
		{
			currentHighLevelState = ( ( gamedataNPCHighLevelState )( ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) ).GetPuppetStateBlackboard().GetInt( GetAllBlackboardDefs().PuppetState.HighLevel ) ) );
			if( currentHighLevelState == gamedataNPCHighLevelState.Combat )
			{
				typedCommand.movementType.movementType = moveMovementType.Sprint;
			}
			else
			{
				typedCommand.movementType.movementType = moveMovementType.Walk;
			}
		}
		if( typedCommand.alwaysUseStealth )
		{
			NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Stealth );
		}
		ScriptExecutionContext.SetMappingValue( context, m_outSpline, typedCommand.spline );
		ScriptExecutionContext.SetMappingValue( context, m_outMovementType, typedCommand.movementType );
		ScriptExecutionContext.SetMappingValue( context, m_outRotateTowardsFacingTarget, typedCommand.rotateEntityTowardsFacingTarget );
		ScriptExecutionContext.SetMappingValue( context, m_outFacingTarget, NULL );
		ScriptExecutionContext.SetMappingValue( context, m_outSnapToTerrain, typedCommand.snapToTerrain );
		ScriptExecutionContext.SetMappingValue( context, m_allowCrowdOnPath, typedCommand.allowCrowdOnPath );
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

}

class AIMoveRotateToCommandHandler extends AICommandHandlerBase
{
	protected editable inlined var m_target : AIArgumentMapping;
	protected editable inlined var m_angleTolerance : AIArgumentMapping;
	protected editable inlined var m_angleOffset : AIArgumentMapping;
	protected editable inlined var m_speed : AIArgumentMapping;

	protected override function UpdateCommand( context : ScriptExecutionContext, command : AICommand ) : AIbehaviorUpdateOutcome
	{
		var typedCommand : AIRotateToCommand;
		typedCommand = ( ( AIRotateToCommand )( command ) );
		if( !( typedCommand ) )
		{
			return AIbehaviorUpdateOutcome.FAILURE;
		}
		ScriptExecutionContext.SetMappingValue( context, m_target, AIPositionSpec.GetWorldPosition( typedCommand.target ) );
		ScriptExecutionContext.SetMappingValue( context, m_angleTolerance, typedCommand.angleTolerance );
		ScriptExecutionContext.SetMappingValue( context, m_angleOffset, typedCommand.angleOffset );
		ScriptExecutionContext.SetMappingValue( context, m_speed, typedCommand.speed );
		return AIbehaviorUpdateOutcome.SUCCESS;
	}

}

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

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

}

class AIMoveCommandsDelegate extends ScriptBehaviorDelegate
{
	protected editable inlined var m_animMoveOnSplineCommand : weak< AIAnimMoveOnSplineCommand >;
	private var spline : NodeRef;
	private var useStart : Bool;
	private var useStop : Bool;
	private var reverse : Bool;
	private var controllerSetupName : CName;
	private var blendTime : Float;
	private var globalInBlendTime : Float;
	private var globalOutBlendTime : Float;
	private var turnCharacterToMatchVelocity : Bool;
	private var customStartAnimationName : CName;
	private var customMainAnimationName : CName;
	private var customStopAnimationName : CName;
	private var startSnapToTerrain : Bool;
	private var mainSnapToTerrain : Bool;
	private var stopSnapToTerrain : Bool;
	private var startSnapToTerrainBlendTime : Float;
	private var stopSnapToTerrainBlendTime : Float;

	public function DoStartAnimMoveOnSpline() : Bool
	{
		var c : AIAnimMoveOnSplineCommand;
		c = m_animMoveOnSplineCommand;
		spline = c.spline;
		useStart = c.useStart;
		useStop = c.useStop;
		controllerSetupName = c.controllerSetupName;
		blendTime = c.blendTime;
		globalInBlendTime = c.globalInBlendTime;
		globalOutBlendTime = c.globalOutBlendTime;
		turnCharacterToMatchVelocity = c.turnCharacterToMatchVelocity;
		customStartAnimationName = c.customStartAnimationName;
		customMainAnimationName = c.customMainAnimationName;
		customStopAnimationName = c.customStopAnimationName;
		startSnapToTerrain = c.startSnapToTerrain;
		mainSnapToTerrain = c.mainSnapToTerrain;
		stopSnapToTerrain = c.stopSnapToTerrain;
		startSnapToTerrainBlendTime = c.startSnapToTerrainBlendTime;
		stopSnapToTerrainBlendTime = c.stopSnapToTerrainBlendTime;
		return true;
	}

	public function DoEndAnimMoveOnSpline() : Bool
	{
		m_animMoveOnSplineCommand = NULL;
		return true;
	}


	private var m_moveOnSplineCommand : AIMoveOnSplineCommand;
	private var strafingTarget : weak< GameObject >;
	private var movementType : moveMovementType;
	private var ignoreNavigation : Bool;
	private var startFromClosestPoint : Bool;
	private var splineRecalculation : Bool;
	private var disableFootIK : Bool;
	private var useCombatState : Bool;
	private var useAlertedState : Bool;
	private var noWaitToEndDistance : Float;
	private var noWaitToEndCompanionDistance : Float;
	private var lowestCompanionDistanceToEnd : Float;
	default lowestCompanionDistanceToEnd = 9999999.0f;
	private var previousCompanionDistanceToEnd : Float;
	default previousCompanionDistanceToEnd = 9999999.0f;
	private var maxCompanionDistanceOnSpline : Float;
	private var companion : weak< GameObject >;
	private var ignoreLineOfSightCheck : Bool;
	private var shootingTarget : weak< GameObject >;
	private var minSearchAngle : Float;
	private var maxSearchAngle : Float;
	private var desiredDistance : Float;
	private var deadZoneRadius : Float;
	private var shouldBeInFrontOfCompanion : Bool;
	private var useMatchForSpeedForPlayer : Bool;
	private var lookAtTarget : weak< GameObject >;
	private var distanceToCompanion : Float;
	private var splineEndPoint : Vector4;
	private var hasSplineEndPoint : Bool;
	private var m_playerCompanion : weak< PlayerPuppet >;
	private var m_firstWaitingDemandTimestamp : Float;
	private var useOffMeshLinkReservation : Bool;
	private var allowCrowdOnPath : Bool;

	public export function GetRotateEntity( context : ScriptExecutionContext ) : Bool
	{
		return m_moveOnSplineCommand.rotateEntityTowardsFacingTarget;
	}

	public export function DoStartMoveOnSpline( context : ScriptExecutionContext ) : Bool
	{
		var cmd : AIMoveOnSplineCommand;
		var currentHighLevelState : gamedataNPCHighLevelState;
		var puppetOwner : weak< ScriptedPuppet >;
		cmd = m_moveOnSplineCommand;
		spline = cmd.spline;
		strafingTarget = cmd.facingTarget;
		puppetOwner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		if( !( puppetOwner ) )
		{
			return false;
		}
		ScriptedPuppet.ResetActionSignal( puppetOwner, 'WaitForCompanion' );
		if( puppetOwner.GetNPCType() == gamedataNPCType.Drone )
		{
			DroneComponent.SetLocomotionWrappers( puppetOwner, EnumValueToName( 'moveMovementType', ( ( Int64 )( cmd.movementType.movementType ) ) ) );
			cmd.movementType.movementType = moveMovementType.Walk;
		}
		else if( cmd.movementType.movementType == moveMovementType.Run )
		{
			currentHighLevelState = ( ( gamedataNPCHighLevelState )( puppetOwner.GetPuppetStateBlackboard().GetInt( GetAllBlackboardDefs().PuppetState.HighLevel ) ) );
			if( currentHighLevelState == gamedataNPCHighLevelState.Combat )
			{
				cmd.movementType.movementType = moveMovementType.Sprint;
			}
			else
			{
				cmd.movementType.movementType = moveMovementType.Walk;
			}
		}
		if( cmd.alwaysUseStealth )
		{
			NPCPuppet.ChangeHighLevelState( ScriptExecutionContext.GetOwner( context ), gamedataNPCHighLevelState.Stealth );
		}
		movementType = AIMovementTypeSpec.Resolve( cmd.movementType, puppetOwner );
		ignoreNavigation = cmd.ignoreNavigation;
		startFromClosestPoint = cmd.startFromClosestPoint;
		splineRecalculation = cmd.splineRecalculation;
		disableFootIK = cmd.disableFootIK;
		mainSnapToTerrain = cmd.snapToTerrain;
		useCombatState = cmd.useCombatState;
		useAlertedState = cmd.useAlertedState;
		noWaitToEndDistance = cmd.noWaitToEndDistance;
		noWaitToEndCompanionDistance = cmd.noWaitToEndCompanionDistance;
		useStart = cmd.useStart;
		useStop = cmd.useStop;
		reverse = cmd.reverse;
		useOffMeshLinkReservation = cmd.useOMLReservation;
		allowCrowdOnPath = cmd.allowCrowdOnPath;
		companion = cmd.companion;
		desiredDistance = cmd.desiredDistance;
		deadZoneRadius = cmd.deadZoneRadius;
		matchTargetSpeed = cmd.catchUpWithCompanion;
		teleportToTarget = cmd.teleportToCompanion;
		maxCompanionDistanceOnSpline = cmd.maxCompanionDistanceOnSpline;
		ignoreLineOfSightCheck = cmd.ignoreLineOfSightCheck;
		minSearchAngle = cmd.minSearchAngle;
		maxSearchAngle = cmd.maxSearchAngle;
		if( companion != cmd.shootingTarget )
		{
			shootingTarget = cmd.shootingTarget;
		}
		else
		{
			shootingTarget = NULL;
		}
		lookAtTarget = cmd.lookAtTarget;
		hasSplineEndPoint = false;
		if( companion )
		{
			hasSplineEndPoint = AIScriptUtils.GetEndPointOfSpline( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, splineEndPoint );
		}
		m_playerCompanion = ( ( PlayerPuppet )( companion ) );
		if( ( m_playerCompanion && cmd.useMatchForSpeedForPlayer ) && ( desiredDistance < 0.0 ) )
		{
			useMatchForSpeedForPlayer = true;
		}
		else
		{
			useMatchForSpeedForPlayer = false;
		}
		if( desiredDistance < 0.0 )
		{
			shouldBeInFrontOfCompanion = true;
		}
		else
		{
			shouldBeInFrontOfCompanion = false;
		}
		return true;
	}

	public constexpr export function DoEndMoveOnSpline() : Bool
	{
		return true;
	}

	public export function DoFindClosestPointOnSpline( context : ScriptExecutionContext ) : Bool
	{
		if( !( AIScriptUtils.GetClosestPointOnSpline( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), teleportDestination ) ) )
		{
			return false;
		}
		return true;
	}

	public export function DoFindStartOfTheSpline( context : ScriptExecutionContext ) : Bool
	{
		if( !( AIScriptUtils.GetStartPointOfSpline( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, teleportDestination ) ) )
		{
			return false;
		}
		return true;
	}

	public constexpr function DoFindEndOfTheSpline( context : ScriptExecutionContext ) : Bool
	{
		return false;
	}

	public export function GetIsMoveToSplineNeeded( context : ScriptExecutionContext ) : Bool
	{
		if( AIScriptUtils.IsSplineStartRecalculated( context, spline, splineRecalculation ) )
		{
			return false;
		}
		if( AIScriptUtils.ArePositionsEqual( ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), teleportDestination ) )
		{
			return false;
		}
		return true;
	}

	private function OnWalkingOnSpline( context : ScriptExecutionContext, success : Bool, isCompanionProgressing : Bool )
	{
		if( success || !( isCompanionProgressing ) )
		{
			m_firstWaitingDemandTimestamp = -1.0;
		}
		else if( m_firstWaitingDemandTimestamp < 0.0 )
		{
			m_firstWaitingDemandTimestamp = EngineTime.ToFloat( GameInstance.GetSimTime( ScriptExecutionContext.GetOwner( context ).GetGame() ) );
		}
	}

	private function ShouldBeWaitingDelayed( context : ScriptExecutionContext ) : Bool
	{
		return ( m_firstWaitingDemandTimestamp > 0.0 ) && ( ( EngineTime.ToFloat( GameInstance.GetSimTime( ScriptExecutionContext.GetOwner( context ).GetGame() ) ) - m_firstWaitingDemandTimestamp ) < 4.0 );
	}

	public export function DoUpdateDistanceToCompanionOnSpline( context : ScriptExecutionContext ) : Bool
	{
		var owner : ScriptedPuppet;
		var companionHandle : GameObject;
		var distanceToDestination : Float;
		var companionDistance : Float;
		var closestPointOnSpline : Vector4;
		var incline : Float;
		var distanceToSpline : Float;
		var isCompanionProgressingOnSpline : Bool;
		var movePoliciesComponent : MovePoliciesComponent;
		companionHandle = companion;
		owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		movePoliciesComponent = owner.GetMovePolicesComponent();
		if( !( companionHandle ) || !( owner ) )
		{
			distanceToCompanion = 0.0;
			OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
			return true;
		}
		if( !( IsOnTheSpline( owner, 0.5 ) ) )
		{
			distanceToCompanion = 0.0;
			OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
			return true;
		}
		if( ( !( companionHandle ) || !( owner ) ) || !( AIScriptUtils.GetClosestPointOnSpline( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, companionHandle.GetWorldPosition(), closestPointOnSpline ) ) )
		{
			distanceToCompanion = 0.0;
			OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
			return true;
		}
		if( movePoliciesComponent.IsOnStairs() )
		{
			OnWalkingOnSpline( context, true, true );
			return true;
		}
		if( ( ( maxCompanionDistanceOnSpline > 0.0 ) && !( IsOnTheSpline( ( ( ScriptedPuppet )( companionHandle ) ), 3.0 ) ) ) && ( lowestCompanionDistanceToEnd > 5.0 ) )
		{
			OnWalkingOnSpline( context, false, isCompanionProgressingOnSpline );
			if( !( ShouldBeWaitingDelayed( context ) ) )
			{
				SetWaitForCompanion( owner, true );
			}
			return true;
		}
		if( !( AIScriptUtils.CalculateDistanceToEndFrom( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), distanceToDestination ) ) )
		{
			distanceToCompanion = 0.0;
			OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
			return true;
		}
		if( !( AIScriptUtils.CalculateDistanceToEndFrom( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, companionHandle.GetWorldPosition(), companionDistance ) ) )
		{
			distanceToCompanion = 0.0;
			OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
			return true;
		}
		if( companionDistance < 0.1 )
		{
			OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
			return true;
		}
		incline = owner.GetMovePolicesComponent().GetInclineAngle();
		distanceToSpline = Vector4.Distance( closestPointOnSpline, companion.GetWorldPosition() );
		if( distanceToSpline > AbsF( desiredDistance ) )
		{
			companionDistance += distanceToSpline;
		}
		distanceToCompanion = distanceToDestination - companionDistance;
		isCompanionProgressingOnSpline = previousCompanionDistanceToEnd > companionDistance;
		previousCompanionDistanceToEnd = companionDistance;
		lowestCompanionDistanceToEnd = MinF( lowestCompanionDistanceToEnd, companionDistance );
		if( matchTargetSpeed )
		{
			DoUpdateSpeed( context );
		}
		if( GameObject.IsCooldownActive( owner, 'WaitForCompanion' ) )
		{
			OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
			return true;
		}
		if( desiredDistance < 0.0 )
		{
			if( AbsF( incline ) > 5.0 )
			{
				OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
				return true;
			}
			if( DontWaitToCompanionNearEnd( owner, distanceToDestination, companionDistance ) )
			{
				OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
				return true;
			}
		}
		if( distanceToCompanion <= desiredDistance )
		{
			OnWalkingOnSpline( context, false, isCompanionProgressingOnSpline );
			if( !( ShouldBeWaitingDelayed( context ) ) )
			{
				SetWaitForCompanion( owner, true );
			}
			return true;
		}
		OnWalkingOnSpline( context, true, isCompanionProgressingOnSpline );
		return true;
	}


	private var sprint : Bool;
	private var run : Bool;

	private function DoUpdateSpeed( context : ScriptExecutionContext )
	{
		if( m_playerCompanion )
		{
			if( PlayerPuppet.GetCurrentLocomotionState( m_playerCompanion ) == gamePSMLocomotionStates.Sprint )
			{
				sprint = true;
				run = false;
				return;
			}
		}
		if( distanceToCompanion >= GetSprintSpeedDistance( context ) )
		{
			sprint = true;
			run = false;
		}
		else
		{
			sprint = false;
			run = false;
		}
	}

	public export function DoUpdateWaitForCompanionOnSpline( context : ScriptExecutionContext ) : Bool
	{
		var owner : ScriptedPuppet;
		var companionHandle : GameObject;
		var distanceToDestination : Float;
		var companionDistance : Float;
		var closestPointOnSplineCompanion : Vector4;
		var absoluteDistToCompanion : Float;
		var tolerance : Float;
		var distanceToSpline : Float;
		var movePoliciesComponent : MovePoliciesComponent;
		companionHandle = companion;
		owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		movePoliciesComponent = owner.GetMovePolicesComponent();
		if( ( !( companionHandle ) || !( owner ) ) || !( AIScriptUtils.GetClosestPointOnSpline( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, companionHandle.GetWorldPosition(), closestPointOnSplineCompanion ) ) )
		{
			distanceToCompanion = 0.0;
			return true;
		}
		if( ( ( maxCompanionDistanceOnSpline > 0.0 ) && !( IsOnTheSpline( ( ( ScriptedPuppet )( companionHandle ) ), 3.0 ) ) ) && ( lowestCompanionDistanceToEnd > 5.0 ) )
		{
			distanceToCompanion = 0.0;
			return true;
		}
		if( !( AIScriptUtils.CalculateDistanceToEndFrom( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, ScriptExecutionContext.GetOwner( context ).GetWorldPosition(), distanceToDestination ) ) )
		{
			distanceToCompanion = 0.0;
			return true;
		}
		if( !( AIScriptUtils.CalculateDistanceToEndFrom( ScriptExecutionContext.GetOwner( context ).GetGame(), spline, companionHandle.GetWorldPosition(), companionDistance ) ) )
		{
			distanceToCompanion = 0.0;
			return true;
		}
		if( companionDistance < 0.1 )
		{
			SetWaitForCompanion( owner, false );
			return true;
		}
		distanceToSpline = Vector4.Distance( closestPointOnSplineCompanion, companionHandle.GetWorldPosition() );
		if( distanceToSpline > AbsF( desiredDistance ) )
		{
			companionDistance += distanceToSpline;
		}
		absoluteDistToCompanion = Vector4.Length( owner.GetWorldPosition() - companionHandle.GetWorldPosition() );
		distanceToCompanion = distanceToDestination - companionDistance;
		lowestCompanionDistanceToEnd = MinF( lowestCompanionDistanceToEnd, companionDistance );
		if( movePoliciesComponent.IsOnStairs() )
		{
			SetWaitForCompanion( owner, false );
			return true;
		}
		if( GameObject.IsCooldownActive( owner, 'WaitForCompanion' ) )
		{
			return true;
		}
		if( DontWaitToCompanionNearEnd( owner, distanceToDestination, companionDistance ) )
		{
			return true;
		}
		if( distanceToDestination >= companionDistance )
		{
			if( absoluteDistToCompanion <= 2.0 )
			{
				return true;
			}
		}
		if( shouldBeInFrontOfCompanion )
		{
			tolerance = deadZoneRadius;
		}
		else
		{
			tolerance = -( deadZoneRadius );
		}
		if( distanceToCompanion > ( desiredDistance + tolerance ) )
		{
			SetWaitForCompanion( owner, false );
			return true;
		}
		return true;
	}

	private function DontWaitToCompanionNearEnd( owner : ScriptedPuppet, distanceToDestination : Float, companionDistance : Float ) : Bool
	{
		if( noWaitToEndDistance > 0.0 )
		{
			if( distanceToDestination < noWaitToEndDistance )
			{
				if( noWaitToEndCompanionDistance > 0.0 )
				{
					if( companionDistance < noWaitToEndCompanionDistance )
					{
						SetWaitForCompanion( owner, false );
						return true;
					}
				}
				else
				{
					SetWaitForCompanion( owner, false );
					return true;
				}
			}
		}
		return false;
	}

	private function IsOnTheSpline( target : ScriptedPuppet, tolerance : Float ) : Bool
	{
		var closestPointOnSpline : Vector4;
		var distanceToSpline : Float;
		if( !( target ) || !( AIScriptUtils.GetClosestPointOnSpline( target.GetGame(), spline, target.GetWorldPosition(), closestPointOnSpline ) ) )
		{
			return false;
		}
		distanceToSpline = Vector4.Length( target.GetWorldPosition() - closestPointOnSpline );
		if( distanceToSpline >= tolerance )
		{
			return false;
		}
		return true;
	}


	private var waitForCompanion : Bool;

	private function SetWaitForCompanion( owner : ScriptedPuppet, value : Bool )
	{
		if( GameObject.IsCooldownActive( owner, 'WaitForCompanion' ) )
		{
			return;
		}
		if( waitForCompanion != value )
		{
			if( value )
			{
				ScriptedPuppet.SendActionSignal( owner, 'WaitForCompanion', -1.0 );
			}
			else
			{
				ScriptedPuppet.ResetActionSignal( owner, 'WaitForCompanion' );
			}
			waitForCompanion = value;
			GameObject.StartCooldown( owner, 'WaitForCompanion', 2.0 );
		}
	}

	public function DoEndTeleportToCompanionOnSpline() : Bool
	{
		startFromClosestPoint = true;
		return true;
	}

	public export function DoStartWaitForCompanion() : Bool
	{
		useStart = false;
		return true;
	}

	public export function DoEndWaitForCompanion() : Bool
	{
		startFromClosestPoint = true;
		return true;
	}

	public function SelectSplineTeleportTarget( context : ScriptExecutionContext ) : Bool
	{
		var owner : ScriptedPuppet;
		var center : Vector4;
		var adjustedCenter : Vector4;
		var radius : Float;
		var findResult : NavigationFindPointResult;
		owner = ( ( ScriptedPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		radius = desiredDistance;
		center = companion.GetWorldPosition() - ( ( companion.GetWorldForward() * radius ) * 1.10000002 );
		adjustedCenter = owner.GetMovePolicesComponent().GetClosestPointToPath( center );
		findResult = GameInstance.GetAINavigationSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).FindPointInSphereForCharacter( adjustedCenter, radius, ScriptExecutionContext.GetOwner( context ) );
		if( findResult.status != worldNavigationRequestStatus.OK )
		{
			return false;
		}
		teleportDestination = findResult.point;
		return true;
	}


	private var m_followTargetCommand : AIFollowTargetCommand;
	private var stopWhenDestinationReached : Bool;
	private var teleportToTarget : Bool;
	private var shouldTeleportNow : Bool;
	private var teleportDestination : Vector4;
	private var matchTargetSpeed : Bool;

	public export function GetSprintSpeedDistance( context : ScriptExecutionContext ) : Float
	{
		var actionId : TweakDBID;
		var result : Float;
		var tolerance : Float;
		if( ( ( Int32 )( movementType ) ) == ( ( Int32 )( moveMovementType.Sprint ) ) )
		{
			return -99999.0;
		}
		if( shouldBeInFrontOfCompanion )
		{
			actionId = T"IdleActions.MoveOnSplineWithCompanionParams.moveToFrontSprintSpeedDistance";
			tolerance = -6.0;
		}
		else
		{
			actionId = T"IdleActions.MoveOnSplineWithCompanionParams.catchUpSprintSpeedDistance";
			tolerance = 6.0;
		}
		result = TDB.GetFloat( actionId, 12.0 );
		if( sprint )
		{
			result += tolerance;
		}
		return result;
	}

	public export function GetRunSpeedDistance( context : ScriptExecutionContext ) : Float
	{
		var actionId : TweakDBID;
		var result : Float;
		var tolerance : Float;
		if( ( ( Int32 )( movementType ) ) == ( ( Int32 )( moveMovementType.Run ) ) )
		{
			return -99999.0;
		}
		if( shouldBeInFrontOfCompanion )
		{
			actionId = T"IdleActions.MoveOnSplineWithCompanionParams.moveToFrontRunSpeedDistance";
			tolerance = -3.0;
		}
		else
		{
			actionId = T"IdleActions.MoveOnSplineWithCompanionParams.catchUpRunSpeedDistance";
			tolerance = 3.0;
		}
		result = TDB.GetFloat( actionId, 6.5 );
		if( run && shouldBeInFrontOfCompanion )
		{
			result += tolerance;
		}
		return result;
	}

	public export function GetTeleportDistance( context : ScriptExecutionContext ) : Float
	{
		var actionId : TweakDBID;
		actionId = T"IdleActions.MoveOnSplineWithCompanionParams.catchUpTeleportDistance";
		return TDB.GetFloat( actionId, 20.0 );
	}

	public export function DoStartFollowTarget( context : ScriptExecutionContext ) : Bool
	{
		var cmd : AIFollowTargetCommand;
		cmd = m_followTargetCommand;
		if( !( cmd ) )
		{
			return false;
		}
		companion = cmd.target;
		desiredDistance = cmd.desiredDistance;
		deadZoneRadius = cmd.tolerance;
		stopWhenDestinationReached = cmd.stopWhenDestinationReached;
		movementType = cmd.movementType;
		lookAtTarget = cmd.lookAtTarget;
		matchTargetSpeed = cmd.matchSpeed;
		teleportToTarget = cmd.teleport;
		shouldTeleportNow = false;
		return true;
	}

	public export function SelectFollowTeleportTarget( context : ScriptExecutionContext ) : Bool
	{
		if( !( GameInstance.GetAINavigationSystem( ScriptExecutionContext.GetOwner( context ).GetGame() ).GetFurthestNavmeshPointBehind( companion, 3.0, 3, teleportDestination, , true ) ) )
		{
			return false;
		}
		return true;
	}

}

class IgnoreMoveCommandInCombatCondition extends AIbehaviorconditionScript
{

	protected override function Check( context : ScriptExecutionContext ) : AIbehaviorConditionOutcomes
	{
		var aiComponent : AIHumanComponent;
		aiComponent = GetPuppet( context ).GetAIControllerComponent();
		if( !( aiComponent ) )
		{
			return true;
		}
		if( aiComponent.GetActionBlackboard().GetBool( GetAllBlackboardDefs().AIAction.ignoreInCombatMoveCommand ) )
		{
			return false;
		}
		return true;
	}

}

