//=============================================================================
// AICommand_Crawler_MoveToGoal
//=============================================================================
//
//=============================================================================
// Killing Floor 2
// Copyright (C) 2015 Tripwire Interactive LLC
//=============================================================================

class AICommand_Crawler_MoveToGoal extends AICommand_MoveToGoal
	within KFAIController_ZedCrawler;


//function bool NotifyPlayerBecameVisible( Pawn VisiblePlayer )
//{
//}

/*********************************************************************************************
* Initialization
********************************************************************************************* */

/** Simple constructor that pushes a new instance of the command for the AI */
static function bool CrawlerMoveToGoal( KFAIController_ZedCrawler AI, Actor NewMoveGoal, optional Actor NewMoveFocus, optional float NewMoveOffset,
				optional bool bIsValidCache,
				optional bool bInCanPathfind = true,
				optional bool bInAllowedToAttackDuringMove = true,
				optional bool bInAllowPartialPath = true )
{
    local AICommand_Crawler_MoveToGoal Cmd;

	if( AI != None && NewMoveGoal != None )
	{
		Cmd = new(AI) class'AICommand_Crawler_MoveToGoal';
		if( Cmd != None )
		{
			// Never actually want to move to a controller, substitute pawn instead
			if( Controller(NewMoveGoal) != None )
			{
				NewMoveGoal = Controller(NewMoveGoal).Pawn;
			}

			// Replaced with setting on Cmd, 11/6
			AI.MoveGoal				= NewMoveGoal;
			AI.MoveFocus			= NewMoveFocus;
			AI.MoveOffset			= NewMoveOffset;
			Cmd.MoveToActor			= NewMoveGoal;
			Cmd.bValidRouteCache	= bIsValidCache;
			Cmd.bCanPathfind		= bInCanPathfind;
			Cmd.bAllowedToAttack	= bInAllowedToAttackDuringMove;
			Cmd.bAllowPartialPath	= bInAllowPartialPath;
			AI.SetBasedPosition( AI.MovePosition, vect(0,0,0) );
			AI.PushCommand( Cmd );
			return true;
		}
	}
	return false;
}

/*********************************************************************************************
* MovingToGoal state
* TODO: Look into benefits of moving LeapToWall command code into this command, to avoid 
* interrupting latent movement.
********************************************************************************************* */

function bool NotifyLanded( vector HitNormal, Actor FloorActor )
{
	//`log( "**** NotifyLanded **** Phys: "$Pawn.Physics$" HitNormal: "$HitNormal$" FloorActor: "$FloorActor$" Floor is currently "$Pawn.Floor );

	//bJumpingToWall = false;
	if( HitNormal.Z >= Pawn.WalkableFloorZ && (Pawn.Physics == PHYS_Walking || Pawn.Physics == PHYS_Falling) )
	{
		Pawn.SetPhysics( PHYS_Walking );
		return true;
	}
	
	//bJumpingToWall = false;
	`AILog( GetFuncName()$" setting physics to PHYS_Spider, FloorActor: "$FloorActor, 'Crawler');
	Pawn.SetPhysics(PHYS_Spider);
	return true;
}

state MovingToGoal
{
	event BeginState( name PreviousStateName )
	{
		bSpawnedByEmergeSpecialMove = false;
		super.BeginState( PreviousStateName );

		DisableSeePlayer(0.f);
	}

	function FindDirectPath()
	{
	}

	function bool CanDirectlyReach( actor Goal )
	{
		local KFPathnode KFP;

		KFP = KFPathnode( Goal );

		if( KFP == none )
		{
			if( Pawn.Physics == PHYS_Spider )
			{
				return false;
			}

			return Super.CanDirectlyReach( Goal );
		}

// 		if( Pawn.Physics == PHYS_Walking )
// 		{
// 			if( KFWallPathNode(Goal) != none )
// 			{
// 				`AILog( GetFuncName()$" returning true for goal "$Goal, 'Command_Crawler_MoveToGoal' );
// 				return true;
// 			}
// 		}
		
		if( Pawn.Physics == PHYS_Spider )
		{
			return false;

			if( KFP.bIsDropDownDest )
			{
				`AILog( GetFuncName()$" returning false for goal "$Goal$" because it's a dropdown dest", 'Command_Crawler_MoveToGoal' );
				return false;
			}
			
			if( KFWallPathNode(Goal) != none )
			{
				`AILog( GetFuncName()$" returning false for goal "$Goal, 'Command_Crawler_MoveToGoal' );
				return false;
			}
		}

		return Super.CanDirectlyReach( Goal );
	}

	function bool NotifyBaseChange( actor NewBase, vector NewFloor )
	{
		`AILog( GetFuncName()$" OldBase: "$Pawn.Base$" NewBase: "$NewBase$" NewFloor: "$NewFloor$" OldFloor: "$OldFloor, 'Command_Crawler_MoveToGoal' );

		if( NewFloor != OldFloor && NewFloor == vect(0,0,1) && Pawn.Physics == PHYS_Spider )
		{
			`AILog( GetFuncName()$" setting pawn physics back to walking", 'Command_Crawler_MoveToGoal' );
			Pawn.SetPhysics( PHYS_Walking );
		}
		else
		if( NewFloor != OldFloor && IsDoingLatentMove() && Pawn != none && Pawn.Physics == PHYS_Spider && NewBase != none && !NewBase.IsA('Pawn') && NewBase.bWorldGeometry )
		{
			AIActionStatus = "NotifyBaseChange, to "$NewBase$": But not stopping my movement Dist From Goal: "$VSize(MoveTarget.Location - Pawn.Location);
			`AILog( "NotifyBaseChange, to "$NewBase$": But not stopping my movement Dist From Goal: "$VSize(MoveTarget.Location - Pawn.Location));
		}
		return false;
	}

	function bool NotifyFallingHitWall(vector HitNormal, actor Wall)
	{
		return NotifyHitWall( HitNormal, Wall );
	}

	function bool NotifyHitWall( vector HitNormal, actor Wall )
	{
		if( KFDoorActor( Wall ) == none )
		{
			`AILog( GetFuncName()$"() Wall: "$Wall$" HitNormal: "$HitNormal, 'HitWall' );
		}
		else
		{
			if( KFDoorActor(Wall).WeldIntegrity <= 0 && KFDoorMarker(KFDoorActor(Wall).MyMarker) != none && !KFDoorActor(Wall).IsCompletelyOpen() )
			{
				DisableNotifyHitWall(0.25f);
				WaitForDoor( KFDoorActor(Wall) );
				`AILog( "NotifyHitWall() while in MoveToGoal, Wall: "$Wall$" Using door and waiting for it to open", 'Doors' );
				KFDoorActor(Wall).UseDoor(Pawn);
				return true;
			}
			// NOTE: Unless returning true, if the Wall is a closed door, SuggestMovePreparation event will be called on the associated KFDoorMarker
			`AILog( GetFuncName()$"() Wall: "$Wall$" HitNormal: "$HitNormal$" ran into a door!", 'Doors' );
			if( !KFDoorActor(Wall).IsCompletelyOpen() && KFDoorActor(Wall).WeldIntegrity > 0 && (Pawn.Anchor == KFDoorActor(Wall).MyMarker || (DoorEnemy != none && (DoorEnemy == KFDoorActor(Wall) || PendingDoor == KFDoorActor(Wall)))) )
			{
				`AILog( GetFuncName()$"() calling NotifyAttackDoor for "$Wall, 'Doors' );
				NotifyAttackDoor( KFDoorActor(Wall) );
				return true;
				//`AILog( GetFuncName()$"() has door enemy "$DoorEnemy, 'Doors' );
			}
		}
		`AILog( GetFuncName()$" Wall: "$Wall$" HitNormal: "$HitNormal, 'Command_Crawler_MoveToGoal' );
		if( !Wall.bCanStepUpon )
		{
			`warn( GetFuncName()$"() Wall "$Wall$" bCanStepUpOn is FALSE" );
			return false;
		}

		if( Pawn.Physics == PHYS_Falling )
		{
			`AILog( GetFuncName()$" Wall: "$Wall$" setting physics to PHYS_Spider", 'Crawler' );
			Pawn.SetPhysics( PHYS_Spider );
			Pawn.SetBase( Wall, HitNormal );
			DisableNotifyHitWall(1.f);
			return true;
		}
		return false;
	}

HandleNewFloor:
	`AILog( self$" HandleNewFloor label at "$Pawn.Location$" - trying to move ahead (base: "$Pawn.Base$")", 'Command_Crawler_MoveToGoal' );
	MoveTo( Pawn.Location + vector(Pawn.Rotation) * 512.f );
	`AILog( self$" HandleNewFloor done extra move, location is now "$Pawn.Location$" base is now "$Pawn.Base, 'Command_Crawler_MoveToGoal' );
	if( !HasReachedMoveGoal() )
	{
		bReevaluatePath=true;
		NotifyNeedRepath();
	}
}

DefaultProperties
{
}