//=============================================================================
// KFSM_Player_Emote
//=============================================================================
// Play a emote animation sequence
//=============================================================================
// Killing Floor 2
// Copyright (C) 2016 Tripwire Interactive LLC
// - Christian "schneidzekk" Schneider
//=============================================================================

class KFSM_Player_Emote extends KFSM_PlaySingleAnim;

`include(KFGame/KFGameDialog.uci)

/** Camera animation */
var CameraAnim CameraAnim;

/** Stores the last camera mode for restoration after move ends */
var Name LastCameraMode;

/** Camera fades */
var color FadeInColor, FadeOutColor;
var float FadeInTime, FadeOutTime;

var rotator InitialRotation;

/** Time from the end of an emote until the next emote can be done */
var protected const float EmoteCooldownTime;

/** Last time an emote was executed */
var protected float LastEmoteTime;

/** Contains a list of particle systems spawned during the move */
var protected array<ParticleSystemComponent> AnimParticles;

/** Checks to see if this Special Move can be done */
protected function bool InternalCanDoSpecialMove()
{
	if( KFPOwner == none
		|| KFPOwner.Physics == PHYS_Falling
		||  `TimeSinceEx(KFPOwner, LastEmoteTime) < EmoteCooldownTime )
	{
		return false;
	}

	return super.InternalCanDoSpecialMove();
}

/** Disable crosshair */
function bool CanDrawCrosshair()
{
	return false;
}

static function byte PackFlagsBase( KFPawn P )
{
	return class'KFEmoteList'.static.GetEmoteIndex( class'KFEmoteList'.static.GetEquippedEmoteId() );
}

function SpecialMoveStarted( bool bForced, Name PrevMove )
{
	// Clear our anim particles array just in case
	ClearSMParticles();

	super.SpecialMoveStarted( bForced, PrevMove );

	// This ensures the emote animation is always using the correct root bone axis option
	// since it is possible that the previous pooled anim node sequence has not been cleared
	// KFPOwner.BodyStanceNodes[EAS_FullBody].SetRootBoneAxisOption(RBA_Default, RBA_Default, RBA_Default);

	// Cache off starting rotation. Instead of snapping the pawn to the new camera direction, we'll set the camera back
	// to this so that it smoothly blends out of the move.
	InitialRotation = KFPOwner.Rotation;

	// Force weapon to stop playing FX
	if (KFPOwner.WeaponAttachment != none)
	{
		KFPOwner.WeaponAttachment.StopThirdPersonFireEffects(true);
	}
}

function PlayAnimation()
{
	AnimName = class'KFEmoteList'.static.GetEmoteFromIndex( KFPOwner.SpecialMoveFlags );

	PlaySpecialMoveAnim( AnimName, AnimStance, BlendInTime, BlendOutTime, 1.f );

	if( KFPOwner.Role == ROLE_Authority )
	{
		KFGameInfo(KFPOwner.WorldInfo.Game).DialogManager.PlayDialogEvent( KFPOwner, `ACT_DoshTrain );
	}

	// Store camera mode for restoration after move ends
	LastCameraMode = 'FirstPerson';
	if( PCOwner != none && PCOwner.PlayerCamera != none )
	{
		LastCameraMode = PCOwner.PlayerCamera.CameraStyle;
	}

	// Set camera to emote third person camera
	if( PCOwner == none || !PawnOwner.IsLocallyControlled() )
	{
		KFPOwner.SetWeaponAttachmentVisibility( false );
		return;
	}

	if( PCOwner.CanViewCinematics() )
	{
		PCOwner.ClientSetCameraFade( true, FadeInColor, vect2d(1.f, 0.f), FadeInTime, true );
		PCOwner.PlayerCamera.CameraStyle = 'Emote';

		// Switch camera modes immediately in single player or on client
		if( PCOwner.WorldInfo.NetMode != NM_DedicatedServer )
		{
			PCOwner.ClientSetCameraMode( 'Emote' );
		}

		KFPOwner.SetWeaponAttachmentVisibility( false );
	}
}

/** Clears the array of particle systems that were created while this animation was playing */
function ClearSMParticles()
{
	if( AnimParticles.Length > 0 )
	{
		AnimParticles.Remove( 0, AnimParticles.Length );
	}
}

function SetParticlesVisible( bool bWasPlayingCustomAnim )
{
	local PlayerController LocalPC;
	local ParticleSystemComponent PSC;
	local vector Loc;
	local rotator Rot;

	LocalPC = class'WorldInfo'.static.GetWorldInfo().GetALocalPlayerController();

	// Stop our animnotify-created particle systems early if we have any
	foreach AnimParticles( PSC )
	{
		if( PSC == none || !PSC.bAttached )
		{
			continue;
		}

		// This allows the player to see the particle FX from their emote after the move is over.
		// Only reattach particle systems that were actually attached to the pawn. Some may not
		// be attached, in which case their owner will be an Emitter.
		if( LocalPC != none && PSC.Owner == KFPOwner )
		{
			Loc = PSC.GetPosition();
			Rot = PSC.GetRotation();

			// Attach to a player controller and set position/rotation
		    LocalPC.AttachComponent( PSC );
			PSC.SetAbsolute( true, true, true );
			PSC.SetTranslation( Loc );
			PSC.SetRotation( Rot );

			// Playercontrollers are always hidden, so we need to ignore that
			PSC.SetIgnoreOwnerHidden( true );
		}

		if( bWasPlayingCustomAnim && PSC.bIsActive )
		{
			PSC.DeactivateSystem();
		}
	}
}

/** Called from KFPawn::OnAnimNotifyParticleSystemSpawned() */
function OnAnimNotifyParticleSystemSpawned( const AnimNotify_PlayParticleEffect AnimNotifyData, ParticleSystemComponent PSC )
{
	local AnimSequence AnimSeq;

	if( AnimNotifyData.Outer != none )
	{
		AnimSeq = AnimSequence( AnimNotifyData.Outer );
		if( AnimSeq != none && string(AnimSeq.SequenceName) ~= string(AnimName) ) // string conversion so we don't have case mismatches
		{
			PSC.bUseAsOccluder = true;
			AnimParticles.AddItem( PSC );
		}
	}
}

/** Constantly apply rotation while move is active */
function Tick( float DeltaTime )
{
	super.Tick( DeltaTime );

	if( KFPOwner != none )
	{
		// If we're no longer on the ground, we need to kill the special move
		if( KFPOwner.Role == ROLE_Authority && KFPOwner.Physics == PHYS_Falling && KFPOwner.SpecialMoves[KFPOwner.SpecialMove] == self )
		{
			KFPOwner.EndSpecialMove();
		}

		if( KFPOwner.Role != ROLE_SimulatedProxy )
		{
			KFPOwner.SetRotation( InitialRotation );
		}
	}
}

function SpecialMoveEnded( Name PrevMove, Name NextMove )
{
	local bool bWasPlayingCustomAnim;

	// abort animation if something ended the emote early
 	if( KFPOwner.BodyStanceNodes[AnimStance].bIsPlayingCustomAnim )
 	{
		KFPOwner.StopBodyAnim( AnimStance, 0.2 );
		bWasPlayingCustomAnim = true;
	}

	// Don't change attachment visibility if another camera mode has already been set
	KFPOwner.SetWeaponAttachmentVisibility( PCOwner == none || PCOwner.IsEmoteCameraMode() );

	if( PCOwner == none || !KFPOwner.IsLocallyControlled() )
	{
		// Make sure camera settings on the server match
		if( PCOwner != none && PCOwner.IsEmoteCameraMode() )
		{
			PCOwner.SetRotation( InitialRotation );
			PCOwner.PlayerCamera.CameraStyle = LastCameraMode;
		}

		SetParticlesVisible( bWasPlayingCustomAnim );
		ClearSMParticles();

		Super.SpecialMoveEnded( PrevMove, NextMove );
		return;
	}

	// Set our last used emote time so we can enforce a cooldown
	LastEmoteTime = KFPOwner.WorldInfo.TimeSeconds;

	// Stop the camera anim
	if( CameraAnim != none )
	{
		PCOwner.ClientStopCameraAnim( CameraAnim );
	}

	SetParticlesVisible( bWasPlayingCustomAnim );
	ClearSMParticles();

	// Return the camera to the player
	if( PCOwner.IsEmoteCameraMode() )
	{
		PCOwner.ClientSetCameraFade( true, FadeOutColor, vect2d(1.f, 0.f), FadeOutTime, true );
		PCOwner.SetRotation( InitialRotation );
        //Reset camera in case this was a gun fire.  This will resume normal updates next frame for 1st person mode
        PCOwner.PlayerCamera.CameraCache.POV.Rotation = InitialRotation;

		// Switch camera modes immediately in single player or on client
		if( PCOwner.WorldInfo.NetMode != NM_DedicatedServer )
		{
			PCOwner.ClientSetCameraMode( LastCameraMode );
		}
	}

	Super.SpecialMoveEnded( PrevMove, NextMove );
}

/** Make sure aim rotation is the same as our original aim rot */
function bool GetSMAimRotation( out rotator AimRot )
{
	AimRot = InitialRotation;
	return true;
}

DefaultProperties
{
	// ---------------------------------------------
	// SpecialMove
	Handle=KFSM_Player_Emote
	bDisableMovement=true
	bDisablesWeaponFiring=false
	bDisableSteering=true
	bLockPawnRotation=true

	// ---------------------------------------------
	// Animation
	BlendOutTime=0.15f

	// ---------------------------------------------
	// Camera fade
	FadeInColor=(R=0,G=0,B=0)
	FadeInTime=1.5f
	FadeOutColor=(R=0,G=0,B=0)
	FadeOutTime=0.6f

	// ---------------------------------------------
	// KFSM_Player_Emote
	EmoteCooldownTime=6.f
}