//=============================================================================
// KFTraderTrigger
//=============================================================================
// Trigger used to start Trader interaction
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
// - Christian "schneidzekk" Schneider
//=============================================================================
class KFTraderTrigger extends Trigger_PawnsOnly
	config(Game)
	native
	implements(KFInterface_Usable)
	dependsOn(KFSeqAct_ShowPath);

/** reference to actor to play open/close animations */
var() SkeletalMeshActor	TraderMeshActor;

/** Anim to play when trader is opened or closed (play reverse) */
var() name OpenAnimName;
/** Looping anim to play while trader is open */
var() name IdleLoopAnimName;

/** Sounds for Trader Pod */
var() 	AkEvent					TraderOpenSound;
var() 	AkEvent					TraderCloseSound;

var bool bEnabled;

/** current state of the trader */
var	transient bool  bOpened;

/** Debugging */
var	config bool bLogTrader;
var	const float DistanceOffNavMeshTheTragerIsAllowedToBe;

cpptext
{
#if WITH_EDITOR
	// Suppress "Trigger is not referenced by anything, should be deleted."
	virtual void CheckForErrors() {}
#endif
}

/** KFInterface_Usable */
simulated function bool GetIsUsable( Pawn User )
{
	return bOpened;
}

/** KFInterface_Usable */
function int GetInteractionIndex( Pawn User )
{
	return IMT_UseTrader;
}

/** HUD and Dialog */
event Touch(Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal)
{
	local Pawn P;

	`log("KFTrigger_Trader::Touch! Trader:" @ self, bLogTrader);

	Super.Touch(Other, OtherComp, HitLocation, HitNormal);

	class'KFPlayerController'.static.UpdateInteractionMessages( Other );
	P = Pawn(Other);
	if ( P != None )
	{
		// no KFTraderDialogManager object on dedicated server, so use static function
		class'KFTraderDialogManager'.static.PlayApproachTraderDialog( P.Controller );
	}
}

/** HUD */
event UnTouch(Actor Other)
{
	super.UnTouch( Other );
	class'KFPlayerController'.static.UpdateInteractionMessages( Other );
}

/** Handles trigger interaction */
function bool UsedBy(Pawn User)
{
	local KFPawn_Human KFPH;
	local KFPlayerController KFPC;

   	`log("KFTrigger_Trader::UsedBy! Trader:" @ self, bLogTrader);

 	KFPH = KFPawn_Human(User);

	if ( KFPH == none  )
	{
		return false;
	}

	KFPC = KFPlayerController(User.Controller);

	if ( KFPC != none )
	{
		KFPC.OpenTraderMenu();
	}

	return false;
}

/** Open shop at the start of trader time */
simulated function OpenTrader()
{
	local float AnimDuration;
	local Pawn P;

	SetCollision(true, false);
	bOpened = true;

	if ( WorldInfo.NetMode != NM_DedicatedServer)
	{
		if ( TraderMeshActor != None )
		{
			TraderMeshActor.SkeletalMeshComponent.PlayAnim(OpenAnimName);
			AnimDuration = TraderMeshActor.SkeletalMeshComponent.GetAnimLength(OpenAnimName);
			// Need to run this timer on the GRI since this trigger doesn't tick on clients.
			WorldInfo.GRI.SetTimer(AnimDuration, false, nameof(StartTraderLoopAnim), self);
			TraderMeshActor.PlaySoundBase( TraderOpenSound );
		}

		ShowTraderPath();
	}

	foreach TouchingActors(class'Pawn',  P)
	{
		class'KFPlayerController'.static.UpdateInteractionMessages( P );
	}
}

/** Play a looping animation on the active trader mesh */
simulated function StartTraderLoopAnim()
{
	if ( WorldInfo.NetMode != NM_DedicatedServer && TraderMeshActor != None && bOpened )
	{
		TraderMeshActor.SkeletalMeshComponent.PlayAnim(IdleLoopAnimName,,true);
	}
}

/** Spawn emitter path to the active trader */
simulated function ShowTraderPath()
{
	local PlayerController PC;
	local KFGameReplicationInfo KFGRI;
	local EPathSearchType OldSearchType;
	local KFEmit_TraderPath Path;
	local Actor nodePathRoot;
	local bool bInsideVolume, bPathFound;

	KFGRI = KFGameReplicationInfo(WorldInfo.GRI);

	if( bCollideActors && KFGRI != none && KFGRI.bTraderIsOpen && KFGRI.OpenedTrader == self )
	{
		foreach LocalPlayerControllers( class'PlayerController', PC )
		{
			if( PC.Pawn == none || PC.GetTeamNum() == 255 || !PC.Pawn.IsAliveAndWell() )
			{
				continue;
			}

			if( KFGRI.TraderVolumeCheckType != VCT_None && KFGRI.TraderVolume != none )
			{
				bInsideVolume = class'KFSeqAct_SetTraderVolumeIgnore'.static.IsActorInVolume( PC.Pawn, KFGRI.TraderVolume );
				if( KFGRI.TraderVolumeCheckType == VCT_InVolume )
				{
					if( !bInsideVolume )
					{
						continue;
					}
				}
				else if( KFGRI.TraderVolumeCheckType == VCT_NotInVolume )
				{
					if( bInsideVolume )
					{
						continue;
					}
				}
			}

			// Cache off our previous path search type
			OldSearchType = PC.Pawn.PathSearchType;

			// Generate a path network that excludes bIgnoredByTraderTrail navpoints
			PC.Pawn.PathSearchType = PST_Constraint;
			class'Path_ToTrader'.static.ToTrader( PC.Pawn );
			class'Goal_AtActor'.static.AtActor( PC.Pawn, self,, false );

			// Generate path
			nodePathRoot = PC.FindPathToward(self);
			if( nodePathRoot != none )
			{
				bPathFound = true;
			}
			else
			{
				bPathFound = false;
			}

			if( bPathFound )
			{
				Path = Spawn(class'KFEmit_TraderPath', PC,, PC.Pawn.Location);

				// instead of using the routecache for the last waypoint, use the trader pod mesh
				Path.SetDestination(TraderMeshActor != None ? TraderMeshActor.Location + vect(0,0,100): Location);
			}
			else
			{
				if( class'KFEmit_TraderPath'.default.bShowEmitPathDebugArtifacts )
				{
					DrawDebugLine( PC.Pawn.Location, Location, 255, 0, 0, true);
				}
				`log("ShowTraderPath - No Path Found, KFGRI.OpenedTrader: " @ KFGRI.OpenedTrader @ " trader trigger loc: " @ Location @ " - player loc: " @ PC.Pawn.Location, bLogTrader);
			}

			// Clear path constraints and restore previous path search type
			PC.Pawn.ClearConstraints();
			PC.Pawn.PathSearchType = OldSearchType;
		}

		// This timer only needs to run once, not on all controllers
		WorldInfo.GetALocalPlayerController().SetTimer( 2.0, false, nameOf(ShowTraderPath), self );
	}
}

/** Close shop when trader time is over */
simulated function CloseTrader()
{
	local KFPlayerController KFPC;

	SetCollision(false, false);
	bOpened = false;

	if( WorldInfo.NetMode != NM_DedicatedServer )
	{
		if ( TraderMeshActor != None )
		{
			TraderMeshActor.SkeletalMeshComponent.PlayAnim(OpenAnimName,,,,, true);
			TraderMeshActor.PlaySoundBase( TraderCloseSound );
		}
		foreach LocalPlayerControllers(class'KFPlayerController', KFPC)
		{
		 	KFPC.CloseTraderMenu();
		 	if( KFPC.Pawn != none )
		 	{
				class'KFPlayerController'.static.UpdateInteractionMessages( KFPC.Pawn );
			}
		}
	}
}

/** Called by CheatManager */
simulated function HideTraderPath()
{
	local KFPlayerController KFPC;
	foreach LocalPlayerControllers(class'KFPlayerController', KFPC)
	{
		KFPC.ClearTimer(nameof(ShowTraderPath), self);
	}
}

defaultproperties
{
	Begin Object NAME=CollisionCylinder LegacyClassName=Trigger_TriggerCylinderComponent_Class
		CollisionRadius=+00400.000000
		CollisionHeight=+00160.000000
		BlockZeroExtent=false
	End Object

	// the GRI turns collision on during trader time
	bCollideActors=false

	OpenAnimName=Open
	IdleLoopAnimName=Printing
	DistanceOffNavMeshTheTragerIsAllowedToBe=500
	TraderOpenSound=AkEvent'WW_UI_Menu.Play_UI_Trader_Build_Start'
	TraderCloseSound=AkEvent'WW_UI_Menu.Play_UI_Trader_Build_Stop'

	bEnabled=true
}
