//=============================================================================
// AICommand_HeadlessWander
//=============================================================================
// Command used by headless Zeds during the last few moments of their lives.
// Unlike most commands, this one should not allow any transitions to other
// commands. If a Zed begins using this command, it should stay active until
// the Zed dies after bleeding out by some other means.
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================
class AICommand_HeadlessWander extends AICommand
	within KFAIController;

var Controller	EventInstigator;
var float		RandomMoveDist;
var float		DotCheck;
var float		LastHeadlessAttackTime;
var bool		bDebugWander;
var vector		Dest;

static function bool HeadlessWander( KFAIController AI )
{
	local AICommand_HeadlessWander Cmd;

	if( AI != None )
	{
		Cmd = new(AI) class'AICommand_HeadlessWander';
		if( Cmd != None )
		{
			//Cmd.EventInstigator = Controller(UserActor);
			AI.PushCommand(Cmd);
			return true;
		}
	}

	return false;
}

/** Set things up for the start of the command */
function Pushed()
{
	if( Steering != none )
	{
		Steering.EnableDefaultAcceleration();
	}
	/** Make sure I'm not sprinting anymore */
	MyKFPawn.SetSprinting( false );

	/** Disallow AdjustFromWall() instigated jumps over obstructions */
	MyKFPawn.bCanJumpOverWalls = false;
	/** Slow my Pawn's rotation rate */
	RotationRateMultiplier = 0.33f;
	LastHeadlessAttackTime = WorldInfo.TimeSeconds;
	/** Reset my focus and focalpoint */
	Focus = None;
	SetFocalPoint(vect(0,0,0));
	/** Turn off HeadTracking, if it's currently on */
	MyKFPawn.StopLookingAtPawn();
	/** Allow combat, since I might try to blindly swipe at any Zed/player I happen to bump */
	bAllowCombatTransitions = true;
	/** Don't allow notifications from TickMeleeDecision() about being in attack range */
	DisableMeleeRangeEventProbing();
	/** Stop any latent MoveTo/MoveTowards */
	StopAllLatentMovement();
	/** Zero non-falling accel and velocity */
	AIZeroMovementVariables();
	if( MyKFPawn.IsDoingSpecialMove() )
	{
		/** This is a special case - interrupt any current special move I'm doing */
		MyKFPawn.EndSpecialMove();
	}

	if( MyKFPawn != none && MyKFPawn.bCanCloak && MyKFPawn.bIsCloaking )
	{
		/** Uncloak (Stalker) */
		MyKFPawn.SetCloaked( false );
	}
	GotoState( 'RandomWander' );
}

function Popped()
{
	if( Steering != none )
	{
		Steering.DisableDefaultAcceleration();
	}
	super.Popped();
}

function bool AllowTransitionTo( class<GameAICommand> AttemptCommand )
{
	return false; // One way ticket
}

function bool ShouldRunSomewhereElse()
{
	return FRand() < 0.4f;
}

function vector CalcTurnDirection( rotator Direction, float Spread )
{
	local float Radius, ZDelta, YDelta;
	local vector X, Y, Z, Offset;

	Radius = Tan( Spread / 2.0 * PI / 180.f );
	ZDelta = Radius - ( 2 * Radius * FRand() );
	YDelta = Radius - ( 2 * Radius * FRand() );

	GetAxes( Direction, X, Y, Z );

	Offset = ( ZDelta * Z ) + ( YDelta * Y );

	return vector( Direction ) + Offset;
}

state RandomWander
{
	function vector GetRandomMovePoint()
	{
		local float Dot;
		local vector TryPt, RandTryPoint;
		local vector TryDir;
		local int i;
		//TryDir = VRand();
		TryDir = CalcTurnDirection( Pawn.Rotation, 65.f );
		TryDir.Z = 0.f;
		TryDir = Normal(TryDir);
		TryPt = Pawn.Location + TryDir * RandomMoveDist;
		if( bDebugWander )
		{
			PauseAndShowMsg( "WAITING" );
			`log( "Initial TryDir:"$TryDir$" TryPt: "$TryPt );
			DrawDebugSphere( TryPt, 32, 8, 0, 255, 0, TRUE );
		}
		for( i = 0; i < 15; i++ )
		{
			if( bDebugWander )
			{
				PauseAndShowMsg( "WAITING : "$i );
			}
			TryDir = CalcTurnDirection( Pawn.Rotation, RandRange(60,120) ); //VRand();
			TryDir.Z = 0.f;
			TryDir = Normal(TryDir);
			RandTryPoint = Pawn.Location + TryDir * RandomMoveDist;
			Dot = normal( RandTryPoint - Pawn.Location ) dot vector(Pawn.Rotation);
			if( Dot < DotCheck )
			{
				if( bDebugWander )
				{
					`log( "Fail i: "$i$" FAILED DOT CHECK (Dot:"$Dot$" versus DotCheck:"$DotCheck$")" );
					DrawDebugSphere( RandTryPoint, 24, 8, 255, 0, 0, TRUE );
				}
 				continue;
			}
			else if( bDebugWander )
			{
				`log( "Success i: "$i$" DOT: "$Dot$" TryDir: "$TryDir$" RandTryPoint: "$RandTryPoint );
				DrawDebugSphere( RandTryPoint, 24, 8, 0, 0, 255, TRUE );
				DrawDebugLine( Pawn.Location, RandTryPoint, 0, 0, 255, TRUE );
			}

			TryPt = Pawn.Location + TryDir * RandomMoveDist;
			if( PointReachable( TryPt ) )
			{
				//DrawDebugLine( Pawn.Location, Pawn.Location + TryDir * RandomMoveDist, 0, 255, 0, TRUE );
				return TryPt;
			}
		}
		return TryPt;
	}
Begin:
	GetRandomMovePoint();
	if( bDebugWander )
	{
		Sleep(0.f);
		PauseAndShowMsg( "WAITING" );
		Sleep(0.f);
		Goto( 'Begin' );
	}
	//SetMovePoint( GetRandomMovePoint(), none );
	MoveTo( GetRandomMovePoint(), none );
 	if( ShouldRunSomewhereElse() )
 	{
 		GotoState( 'RunSomewhere' );
 	}
// 	if( FRand() < 0.23f )
// 	{
// 		Sleep( RandRange( 0.1f, 0.5f ) );
// 	}
	Goto('Begin');
}

function bool NotifyHearNoise( float Loudness, Actor NoiseMaker, optional Name NoiseType )
{
	`AILog( "HearNoise: "$Loudness$" NoiseMaker: "$NoiseMaker$" Type: "$NoiseType, 'HeadlessWander' );
	return false;
}

state RunSomewhere
{
	function bool RunToDest()
	{
		local Pawn CurEnemy;
		local float CurDistSq, BestDistSq;
		local Pawn BestEnemy;
		local bool bRunToPlayer;

		BestDistSq = MAXINT;
		foreach WorldInfo.AllPawns( class'Pawn', CurEnemy )
		{
			CurDistSq = VSizeSq( CurEnemy.Location - Pawn.Location );
			if( BestEnemy == none || CanSee(CurEnemy) ) 
			{
				if( CurDistSq < BestDistSq )
				{
					BestEnemy = CurEnemy;
					BestDistSq = CurDistSq;
				}
			}
		}

		bRunToPlayer = FRand() < 0.55f;

		BestDistSq = MAXINT;
		foreach WorldInfo.AllPawns( class'Pawn', CurEnemy )
		{
			CurDistSq = VSizeSq( CurEnemy.Location - Pawn.Location );
			if( BestEnemy == none || 
				(bRunToPlayer == Pawn.IsHumanControlled() 
				&& CurDistSq < BestDistSq 
				&& (!bIsPlayer || CanSee(CurEnemy)) ) ) 
			{
				BestEnemy = CurEnemy;
				BestDistSq = CurDistSq;
			}
		}


 		if( BestEnemy != none )
 		{
			Dest = BestEnemy.Location;
			return true;
		}
		return false;
	}
Begin:
	if( RunToDest() )
	{
		MoveTo( Dest );
		Dest = vect(0,0,0);
		GotoState( 'RandomWander' );
	}
	else
	{
		AbortCommand( self );
	}
}

DefaultProperties
{
	bIgnoreNotifies=true
	bIgnoreStepAside=true
	RandomMoveDist=232.f
	DotCheck=0.86f
	bDebugWander=false
}


