class SetCustomShootPosition extends AIbehaviortaskScript
{
	private editable var m_offset : Vector3;
	private editable var m_fxOffset : Vector3;
	private editable var m_lockTimer : Float;
	private editable var m_landIndicatorFX : FxResource;
	private editable var m_keepsAcquiring : Bool;
	private editable var m_shootToTheGround : Bool;
	default m_shootToTheGround = true;
	private editable var m_predictionTime : Float;
	private editable var m_waypointTag : CName;
	private var m_refOwner : weak< AIActionTarget_Record >;
	private var m_refAIActionTarget : weak< AIActionTarget_Record >;
	private var m_refCustomWorldPositionTarget : weak< AIActionTarget_Record >;
	private var m_ownerPosition : Vector4;
	private var m_targetPosition : Vector4;
	private var m_direction : Vector4;
	private var m_fxPosition : Vector4;
	private var m_target : weak< GameObject >;
	private var m_owner : weak< GameObject >;
	private var m_fxInstance : FxInstance;
	private var m_targetAcquired : Bool;
	private var m_startTime : Float;
	private var m_shootPointPosition : Vector4;
	private var m_targetsPosition : array< Vector4 >;

	protected override function Activate( context : ScriptExecutionContext )
	{
		m_owner = ( ( NPCPuppet )( ScriptExecutionContext.GetOwner( context ) ) );
		m_startTime = EngineTime.ToFloat( GameInstance.GetTimeSystem( m_owner.GetGame() ).GetSimTime() );
		m_refOwner = TweakDBInterface.GetAIActionTargetRecord( T"AIActionTarget.Owner" );
		m_refAIActionTarget = TweakDBInterface.GetAIActionTargetRecord( T"AIActionTarget.CombatTarget" );
		m_refCustomWorldPositionTarget = TweakDBInterface.GetAIActionTargetRecord( T"AIActionTarget.CustomWorldPosition" );
		if( m_waypointTag != '' )
		{
			GameInstance.FindWaypointsByTag( ScriptExecutionContext.GetOwner( context ).GetGame(), m_waypointTag, m_targetsPosition );
			m_shootPointPosition = m_targetsPosition[ 0 ];
		}
	}

	private static function ApplyTargetOffset( out targetPosition : Vector4, ownerPosition : Vector4, offset : Vector3, shootToTheGround : Bool )
	{
		var forward : Vector4;
		var right : Vector4;
		var up : Vector4;
		forward = targetPosition - ownerPosition;
		if( shootToTheGround )
		{
			targetPosition.Z = ownerPosition.Z;
			forward.Z = 0.0;
		}
		forward = Vector4.Normalize( forward );
		if( Vector4.IsZero( forward ) )
		{
			return;
		}
		right = Vector4.Normalize( Vector4.Cross( forward, Vector4( 0.0, 0.0, 1.0, 0.0 ) ) );
		up = Vector4.Normalize( Vector4.Cross( right, forward ) );
		targetPosition -= ( right * offset.X );
		targetPosition -= ( forward * offset.Y );
		targetPosition -= ( up * offset.Z );
		targetPosition.W = 1.0;
	}

	protected override function Update( context : ScriptExecutionContext ) : AIbehaviorUpdateOutcome
	{
		var trackedLocation : TrackedLocation;
		var currentTime : Float;
		TargetTrackingExtension.GetTrackedLocation( context, m_owner, trackedLocation );
		if( m_keepsAcquiring && ( m_lockTimer > 0.0 ) )
		{
			currentTime = EngineTime.ToFloat( GameInstance.GetTimeSystem( m_owner.GetGame() ).GetSimTime() );
			if( currentTime >= ( m_startTime + m_lockTimer ) )
			{
				m_targetAcquired = true;
			}
		}
		if( !( m_targetAcquired ) )
		{
			AIActionTarget.Get( context, m_refAIActionTarget, false, m_target, m_targetPosition );
			AIActionTarget.Get( context, m_refOwner, false, m_owner, m_ownerPosition );
			m_ownerPosition = m_owner.GetWorldPosition();
			m_targetPosition = m_target.GetWorldPosition();
			m_fxPosition = m_targetPosition;
			ApplyTargetOffset( m_targetPosition, m_ownerPosition, m_offset, m_shootToTheGround );
			ApplyTargetOffset( m_fxPosition, m_ownerPosition, m_fxOffset, m_shootToTheGround );
			m_targetPosition += ( trackedLocation.speed * m_predictionTime );
			m_fxPosition += ( trackedLocation.speed * m_predictionTime );
			if( !( m_keepsAcquiring ) )
			{
				m_targetAcquired = true;
			}
		}
		if( m_waypointTag != '' )
		{
			AIActionTarget.Set( context, m_refCustomWorldPositionTarget, , m_shootPointPosition );
		}
		else
		{
			AIActionTarget.Set( context, m_refCustomWorldPositionTarget, , m_targetPosition );
		}
		if( FxResource.IsValid( m_landIndicatorFX ) )
		{
			SpawnLandVFXs( context, m_landIndicatorFX, m_fxPosition );
		}
		return AIbehaviorUpdateOutcome.IN_PROGRESS;
	}

	private function SpawnLandVFXs( context : ScriptExecutionContext, fx : FxResource, fxposition : Vector4 )
	{
		var transform : WorldTransform;
		var position : WorldPosition;
		if( FxResource.IsValid( fx ) )
		{
			WorldPosition.SetVector4( position, fxposition );
			WorldTransform.SetWorldPosition( transform, position );
			m_fxInstance = CreateFxInstance( context, fx, transform );
		}
	}

	private function CreateFxInstance( context : ScriptExecutionContext, resource : FxResource, transform : WorldTransform ) : FxInstance
	{
		var fx : FxInstance;
		var fxSystem : FxSystem;
		fxSystem = GameInstance.GetFxSystem( GetGame( context ) );
		fx = fxSystem.SpawnEffect( resource, transform );
		return fx;
	}

	protected override function Deactivate( context : ScriptExecutionContext )
	{
		m_targetAcquired = false;
		m_fxInstance.BreakLoop();
	}

}

