//////////////////////////////////////////////////////////////////////////////
//
// AVP_Behaviour_Alien_Movement.h
//
// Copyright (C) 2007 Rebellion. All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// B E G I N   F I L E   W R A P P E R ///////////////////////////////////////

#ifdef ASURA_USE_PRAGMA_ONCE
#pragma once
#endif

#ifndef __AVP_BEHAVIOUR_ALIEN_MOVEMENT_H__
#define __AVP_BEHAVIOUR_ALIEN_MOVEMENT_H__ 1

// E N D   F I L E   W R A P P E R ///////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// asura
#include "Core/Asura_LinkList.h"
#include "Core/Asura_TemplateTree.h"

// axon
#include "Behaviour/Axon_Project_Behaviour.h"
#include "Core/AVP_Navigation.h"

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////

class Asura_Message;
class Axon_Behaviour;
class AVP_Brain_Actor_Alien;
class AVP_ServerNode_GS2Node;
class AVP_Alien_Movement;

//////////////////////////////////////////////////////////////////////////////
//
// LinkTraversers
//
//////////////////////////////////////////////////////////////////////////////


class LinkTraverser
{
public:
	LinkTraverser() : m_pxMovement( NULL ) {}
	virtual ~LinkTraverser() {}

	void SetMovement( AVP_Alien_Movement* pxMovement ) { m_pxMovement = pxMovement; }

	virtual void OnNewRoute() {}

	virtual bool ShouldStart()		{ return false; }
	virtual bool CanBeInterrupted()	{ return true; }
	virtual bool IsFinished()		{ return false; }
	virtual bool IsInError()		{ return false; }
	virtual bool IsTryToResolveByJumping()		{ return false; }

	virtual void Start()										 {}
	virtual bool HandleMessage( const Asura_Message* pxMessage ) { return false; }
	virtual void PerFrameUpdate( const float fTimeslice )		 {}
	virtual void Update( const float fTimeslice )				 {}
	virtual void Stop()											 {}
	virtual void Pause()										 {}
	virtual void Unpause()										 {}

	// Distance before the route does anything non-standard.
	virtual float GetRouteFreeDistance() const { return 0.0f; }

	virtual bool IsJumping() const { return false; }

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo() {}
#endif

protected:
	AVP_Alien_Movement*     GetMovement() { return m_pxMovement; }
	AVP_Brain_Actor_Alien*  GetAlienBrain();

private:
	AVP_Alien_Movement* m_pxMovement;
};

class StandardLinkTraverser : public LinkTraverser
{
	typedef LinkTraverser PARENT;

public:
	StandardLinkTraverser();

	virtual void OnNewRoute();

	virtual bool ShouldStart();
	virtual bool CanBeInterrupted();
	virtual bool IsInError() { return m_bStuck; }
	virtual bool IsTryToResolveByJumping()	{ return m_bTryToUnstuckByJumping; }

	virtual void Start();
	virtual bool HandleMessage( const Asura_Message* pxMessage );
	virtual void PerFrameUpdate( const float fTimeslice );
	virtual void Stop();

	virtual float GetRouteFreeDistance() const { return m_fLengthUntilNonStandardLink; }

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo();
#endif

protected:
	void CalculateIsConvexRouteSegment();
	void CalculateLengthUntilNonStandardLink();
	void CalculateSplineSegmentParams();
	void UpdateFollowPoint();
	void CalculateAvoidanceSteering( const Asura_Vector_3& xFollowPointSteering, Asura_Vector_3& xSteering );
	void UpdateLengthsWithAnimSpeed( const float fTimeslice );
	void UpdateStuckDetection( const float fTimeslice, bool bLargeAvoidanceSteering );
	
private:

	enum State
	{
		NORMAL,
		PREPARE_TO_SHARP_TURN,
		SHARP_TURN,
	};

	void SwitchToState( const State eState );

	State m_eState;
	float m_fTimeInState;

	Asura_Vector_3 m_xFollowPoint;
	u_short m_usFollowPointWPIndex;
	union
	{
		u_short m_usFlags;
		struct 
		{
			u_int m_bIsConvexRouteSegment : 1,
                  m_bStuck                : 1,
				  m_bTryToUnstuckByJumping: 1,
				  m_bStraightBefore		  : 1,
				  m_bStraight			  : 1,
				  m_bStraightAfter		  : 1;
		};
	};
	Asura_Vector_3 m_xFirstSplinePosition;
	Asura_Vector_3 m_xLastSplinePosition;
	// Used for detecting when we need to reset our stuck detection stuff.
	u_short m_usPrevRouteIndex;
	// Used for determining if we can put any hops, bursts or darts in.
	float m_fLengthUntilNonStandardLink;

	float m_fTimeInStuckOnPath;
	float m_fFramesInStuckOnPath;
	float m_fTimeCheckOrientationAndPositionStuck;
	float m_fFramesCheckOrientationAndPositionStuck;
	float m_fMaxRouteTraversedDistance;
	float m_fLastMaxRouteFraction;	
	Asura_Matrix_3x3 m_xLastOrientation;
	Asura_Vector_3 m_xLastPosition;
#ifndef ASURA_NO_DEBUG_OUTPUT
	Asura_Vector_3 m_xFollowSteering;
	Asura_Vector_3 m_xAvoidanceSteering;
	Asura_Vector_3 m_xFinalSteering;
#endif
	
};

class SlowLinkTraverser : public StandardLinkTraverser
{
	typedef StandardLinkTraverser PARENT;

public:
	SlowLinkTraverser() {}

	virtual bool ShouldStart() { return false; }

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo();
#endif
};

class JumpLinkTraverser : public LinkTraverser
{
	typedef LinkTraverser PARENT;

public:
	JumpLinkTraverser()
	: m_fTimeInState( 0.0f )
	, m_usFlags( 0 )
	, m_usNextJumpTransitionIndex( 0 )
	, m_usPostNextJumpTransitionIndex( 0 )
	{}

	virtual void OnNewRoute();

	virtual bool ShouldStart();
	virtual bool CanBeInterrupted()	{ return false; }
	virtual bool IsFinished()		{ return m_bFinished; }

	virtual void Start();
	virtual bool HandleMessage( const Asura_Message* pxMessage );
	virtual void PerFrameUpdate( const float fTimeslice );
	virtual void Stop();

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo();
#endif

private:
	void GetNextJumpTransitionIndex( bool bNewRoute );

	u_short GetNextJumpTransitionIndexStartingAt( u_short usStartIndex );

	virtual bool IsJumping() const { return true; }

private:
	float m_fTimeInState;
	union
	{
		u_short m_usFlags;
		struct 
		{
            u_int m_bFinished : 1;
		};
	};
	u_short m_usNextJumpTransitionIndex;
	u_short m_usPostNextJumpTransitionIndex;
};

class GS2LinkTraverser : public LinkTraverser
{
	typedef LinkTraverser PARENT;

public:
	GS2LinkTraverser();

	virtual bool ShouldStart();
	virtual bool CanBeInterrupted()	{ return false; }
	virtual bool IsFinished()		{ return m_bFinished; }
	virtual bool IsInError()		{ return m_bInError; }

	virtual void Start();
	virtual bool HandleMessage( const Asura_Message* pxMessage );
	virtual void PerFrameUpdate( const float fTimeslice );
	virtual void Update( const float fTimeslice );
	virtual void Stop();
	virtual void Pause();
	virtual void Unpause();

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo();
#endif

private:
	enum State
	{
		UNSET,
		VENT_IN,
		ON_GS2,		
		VENT_OUT,
		FINISHED
	};

	void SwitchToState( const State eState );
	bool RequestVentMove( Asura_Guid uGS2StartMoveNode, Asura_Guid uGS2EndMoveNode );
	bool GetAnimHashFromAnimTemplateHash( const Asura_Hash_ID uAnimTemplateHash, Asura_Hash_ID& uAnimHash );
	bool SelectNextGS2Node(const AVP_ServerNode_GS2Node* pxCurrentNode, u_short usRouteIndex, const AVP_ServerNode_GS2Node*& pxNextNode, Asura_Guid& uLinkGuid, bool& bIsNextNodeEnd);
	void BuildOnGS2Behaviour();

private:
	State m_eState;
	float m_fTimeInState;
	union
	{
		u_short m_usFlags;
		struct 
		{
			u_int m_bFinished : 1,
				  m_bInError  : 1;
		};
	};
	u_short			m_usInitialRouteIndex;
	u_short			m_usFinalWPIndex;
	Asura_Guid		m_uVentInStartGuid;
	Asura_Guid		m_uVentInEndGuid;
	Asura_Guid		m_uVentOutStartGuid;
	Asura_Guid		m_uVentOutEndGuid;
	Asura_LinkList< Asura_Guid > m_xGS2LinkGuidList;
	Axon_Behaviour* m_pxGS2Behaviour;
};

class EnvHookLinkTraverser : public LinkTraverser
{
	typedef LinkTraverser PARENT;

public:
	EnvHookLinkTraverser();

	virtual void OnNewRoute();
	virtual bool ShouldStart();
	virtual bool IsFinished()		{ return m_bFinished; }
	virtual bool IsInError()		{ return m_bStuck; }
	virtual bool IsTryToResolveByJumping()	{ return m_bTryToUnstuckByJumping; }

	virtual void Start();
	virtual void PerFrameUpdate( const float fTimeslice );
	virtual void Stop();

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo();
#endif

private:
	void UpdateFollowPoint();
	void UpdateStuckDetection( const float fTimeslice, bool bLargeAvoidanceSteering );

private:
	Asura_Vector_3 m_xFollowPoint;
	union
	{
		u_short m_usFlags;
		struct 
		{
			u_int m_bFinished				: 1,
				  m_bTryToUnstuckByJumping  : 1,
				  m_bStuck					: 1;
		};
	};
	// Used for detecting when we need to reset our stuck detection stuff.
	u_short m_usPrevRouteIndex;

	float m_fTimeInStuckOnPath;
	float m_fFramesInStuckOnPath;
	float m_fTimeCheckOrientationAndPositionStuck;
	float m_fFramesCheckOrientationAndPositionStuck;
	float m_fMaxRouteTraversedDistance;
	float m_fLastMaxRouteFraction;
	Asura_Matrix_3x3 m_xLastOrientation;
	Asura_Vector_3 m_xLastPosition;
	float m_fAvarageVelocity;

};

class DestinationTraverser : public LinkTraverser
{
	typedef LinkTraverser PARENT;

public:
	DestinationTraverser();

	virtual void OnNewRoute();
	virtual bool ShouldStart();
	// We can never finish as we can't tell when we're done - the check for arrival is done in the main movement update.
	virtual bool IsFinished()		{ return false; }
	virtual bool IsInError()		{ return ( m_bStuck || m_bInError ); }
	virtual bool IsTryToResolveByJumping()	{ return m_bTryToUnstuckByJumping; }

	virtual void Start();
	virtual void PerFrameUpdate( const float fTimeslice );
	virtual void Stop();

#ifndef ASURA_NO_DEBUG_OUTPUT
	virtual void RenderDebugInfo();
#endif

private:
	enum State
	{
		UNSET,
		// If the destination is inside our turning circle we have to move directly to it, but only if this is a one-waypoint route
		// (i.e. if we're the first traverser) otherwise we'll already be moving and we can't suddenly stop.
		MOVING_DIRECT_TO_DESTINATION,
		TRAVERSING_TO_DESTINATION,
		TRAVERSING_AVOIDING_ORBIT,
		NUM_STATES
	};

	void SwitchToState( const State eState );
	void UpdateRouteFraction();
	void UpdateStuckDetection( const float fTimeslice, bool bLargeAvoidanceSteering );

private:
	State m_eState;
	union
	{
		u_int m_uFlags;
		struct 
		{
            u_int m_bStuck				   : 1,
				  m_bTryToUnstuckByJumping : 1,
				  m_bInError			   : 1;
		};
	};
	// Used for detecting if we get stuck. If we've take more time than we should to traverse the link then we are stuck.
	float m_fTimeInStuckOnPath;
	float m_fFramesInStuckOnPath;
	float m_fTimeCheckOrientationAndPositionStuck;
	float m_fFramesCheckOrientationAndPositionStuck;
	float m_fMaxRouteTraversedDistance;
	float m_fLastMaxRouteFraction;
	Asura_Matrix_3x3 m_xLastOrientation;
	Asura_Vector_3 m_xLastPosition;
	float m_fAvarageVelocity;

#ifndef ASURA_NO_DEBUG_OUTPUT
	Asura_Vector_3 m_xFollowSteering;
	Asura_Vector_3 m_xAvoidanceSteering;
	Asura_Vector_3 m_xFinalSteering;
#endif


};

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Alien_Movement
//
//////////////////////////////////////////////////////////////////////////////

class AVP_Alien_Movement
{
	friend class LinkTraverser;
	friend class StandardLinkTraverser;
	friend class SlowLinkTraverser;
	friend class JumpLinkTraverser;
	friend class GS2LinkTraverser;
	friend class EnvHookLinkTraverser;
	friend class DestinationTraverser;

public:

	enum ExMovementMode
	{
		EMM_IDLE = -1,
		EMM_SLOW = 0,
		EMM_MEDIUM,
		EMM_FAST,		
	};

	AVP_Alien_Movement();
	void SetAlienBrain( AVP_Brain_Actor_Alien* pxBrain ) { m_pxAlienBrain = pxBrain; }
	bool HandleMessage( const Asura_Message* pxMessage );
	void Initialise();
	void Shutdown();
	void Pause();
	void Unpause();
	void PerFrameUpdate( const float fTimeslice );
	void Update( const float fTimeslice );

#ifndef ASURA_NO_DEBUG_OUTPUT
	void RenderDebugInfo();
#endif

	// If you want to specify a particular route type, arrival range, etc, you must do so before calling these functions.
	bool GetToPosition( const Asura_Vector_3& xDestination, float ArrivalRange, AVP_Navigation::AlienAStarFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode, bool bRefineRoute = true );
	bool GetToPosition( u_short usDestinationWPID, float ArrivalRange, AVP_Navigation::AlienAStarFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode, bool bRefineRoute = true );
	bool GetToPosition( const Asura_Vector_3& xDestination, u_short usDestinationWPID, float ArrivalRange, AVP_Navigation::AlienAStarFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode, bool bRefineRoute = true );
	bool GetAwayFromPosition( AVP_Navigation::AlienAwayFromFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode );
	bool FollowSharedRoute( const Asura_Guid uRouteOwner, AVP_Navigation::AlienAStarFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode );
	bool StartMoving(); // deprecate
	void Stop();
	void Abort();
	void Fall();
	// Distance before the route does anything non-standard.
	float GetRouteFreeDistance() const;
	void SetMovementMode( ExMovementMode eMovementMode );
	void SetRouteType( const AVP_Navigation::RouteType eRouteType );
	void SetTraverseStyle( const AVP_Navigation::TraverseStyle eTraverseStyle );
	bool IsBursting() const { return m_bIsBursting; }
	void SetBurst( bool bBurst );
	void SetIgnoreTargetForAvoidCalcuation(Asura_Guid uTargetGuid);
	void ResetIgnoreTargetForAvoidCalcuation();
	Asura_Guid GetIgnoreTargetForAvoidCalcuation() { return m_uIgnoreTargetForAvoidanceID; }
	void SetShouldJumpFromDanger( const bool bJump ) { m_bJumpFromDanger = bJump; }
	bool IsJumpingFromDanger() const { return ( m_eState == JUMPING_FROM_DANGER ); }
	bool IsResolvingStuckByJumping() const { return ( m_eState == RESOLVE_STUCK_BY_JUMPING ); }
	bool IsJumping() const { return m_pxCurrentTraverser ? m_pxCurrentTraverser->IsJumping() : false; }
	bool IsFinished() const { return ( m_bIsFinished ); }
	bool IsInError() const { return m_bInError; }

	void SetGS2Mode(bool bIsGS2Mode) { m_bNotGS2Mode = !bIsGS2Mode; }
	
	void SetAvoidLight() { m_bAvoidLight = true; }
	bool GetAvoidLight() const { return m_bAvoidLight; }

	void ForceJumpOnWaypoint() { m_bJumpOnWaypoint = true; }

	bool ConsiderateAdvanceAlongRoute();

	float GetLengthLeftOnPath() const;
	float GetLengthTraversedOnPath() const;

	ExMovementMode GetCurrentMovementMode() const;
	static float GetMinArrivalRange();
	static float GetMaxArrivalRange();
	static int GetAnimStateFromMovementMode( ExMovementMode eMovementMode );
	static bool GetJumpOverVariation(const Asura_Vector_3& xStartPosition, const Asura_Vector_3& xEndPosition, Asura_Guid uActorGuid, int& iVariation );


protected:
	void SetAttemptedUnstick() { m_bAttemptedUnstick = true; }
	bool HaveAttemptedUnstick() const { return m_bAttemptedUnstick; }

	void CalculatePointSteering( const Asura_Vector_3& xPoint, Asura_Vector_3& xSteering );
	void SetAllDirections( const Asura_Vector_3& xDirection );
	void ForceMoveDirection( const Asura_Vector_3& xDirection );

	// Special version that takes more arguments than the core version and does more fancy stuff.
	bool FindNearestPointOnRoute( const AVP_Navigation::NavData& xNavData, const Asura_Vector_3& xCurrentPosition, const Asura_Vector_3& xActorUp,
		float fLookAheadDistance, Asura_Vector_3& xNearestPosition, u_short& usNearestRouteSegmentIndex, bool bStopOnGS2AndReorientation );

    struct TransitionData
    {
        AVP_Navigation::LinkTransitionType m_eLinkTransitionType;
        Asura_Vector_3                     m_xDestinationPosition;
        Asura_Vector_3                     m_xDestinationNormal;
        u_short                            m_usRouteIndex;

        union
        {
            u_short m_usFlags;
            struct 
            {
                u_int m_bPotentialJump		: 1,
                      m_bMoveAfterwards		: 1;
            };
        };

		bool IsConvex() const;
    };

	u_int									GetNumTransitions() const { return m_xTransitionDataList.Size(); }
	const Asura_LinkList< TransitionData >* GetTransitionDataList() const { return &m_xTransitionDataList; }
	const TransitionData*					GetTransitionDataElt( const u_int uIndex ) const;

	AVP_Brain_Actor_Alien* GetAlienBrain() const { return m_pxAlienBrain; }

private:
	enum State
	{
		FINISHED,
		MOVING,
		FALLING,
		JUMPING_FROM_DANGER,
		TRAVERSING_ROUTE,
		RESOLVE_STUCK_BY_JUMPING,
		NUM_STATES
	};
	enum MovementModeState
	{
		NORMAL,
		ADDING_BURST,
		SLOWED_BY_HIT,
		NUM_MOVEMENT_MODE_STATES
	};
	enum JumpDirection
	{
		JUMP_FORWARDS,
		JUMP_BACKWARDS,
		JUMP_RIGHT,
		JUMP_LEFT
	};

	void UpdateMovementModeState( const float fTimeslice );
	void UpdateFallingDueToDamage();
	void UpdatePositionOnRoute();
	void CalculateRouteTransitions();
	LinkTraverser* FindNextTraverser();
	void SwitchToState( const State eNextState );
	bool ActionGetToPosition( const Asura_Vector_3& xDestination, u_short usDestinationWPID, float ArrivalRange, AVP_Navigation::AlienAStarFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode, const bool bRefineRoute );
	bool ActionGetAwayFromPosition( AVP_Navigation::AlienAwayFromFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode );
	bool ActionFollowSharedRoute( const Asura_Guid uRouteOwner, AVP_Navigation::AlienAStarFunctor& xFunctor, AVP_Alien_Movement::ExMovementMode eExMoveMode );
	void ActionFall();
	void RequestMovementAnimState();
	void RequestMove( Asura_Hash_ID uMoveHashID );
	void RequestJumpMove( Asura_Hash_ID uMoveHashID, const Asura_Vector_3& xDestPos, const Asura_Vector_3& xDestNormal );
	void RequestJumpMove( Asura_Hash_ID uMoveHashID, Asura_Hash_ID uJumpHashID, Asura_Hash_ID uJumpAnimHashID, const Asura_Vector_3& xDestPos, const Asura_Matrix_3x3& xDestOrientation, AVP_Alien_Movement::ExMovementMode eExMoveMode );
	void RequestMoveAndJumpMove( Asura_Hash_ID uMoveHashID, Asura_Hash_ID uJumpHashID, Asura_Hash_ID uJumpAnimHashID, const Asura_Matrix_3x3& xTurnOrientation, const Asura_Vector_3& xStartJumpPos, const Asura_Vector_3& xDestPos, const Asura_Matrix_3x3& xDestOrientation, AVP_Alien_Movement::ExMovementMode eExMoveMode );
	void RequestTurn( Asura_Hash_ID uMoveHashID, const Asura_Matrix_3x3& xTurnOrientation );
	void CalculateJump( bool& bNeedToMoveOrTurn, Asura_Hash_ID& uMoveHashID, Asura_Hash_ID& uJumpMoveHashID, Asura_Hash_ID& uJumpAnimHashID, Asura_Matrix_3x3& xTurnOrientation, Asura_Vector_3& xStartJumpPos, Asura_Vector_3& xDestPos, Asura_Matrix_3x3& xDestOrientation, AVP_Alien_Movement::ExMovementMode& eExMoveMode, u_short usRouteIndex, u_short usNextRouteIndex, bool bJumpOver );
	void CalculateTurn( const Asura_Vector_3& xDirection, Asura_Hash_ID &uMoveHashID, Asura_Matrix_3x3& xTurnOrientation);
	Asura_Hash_ID GetFlatJumpAnimHashID(const Asura_Vector_3& xStart,const Asura_Vector_3& xEnd, bool bJumpOver, bool bJumpUp, bool bJumpDown, bool bRunAfterJump) const;
	void RequestIdle();
	bool IsInIdle(float& fTimeInIdle) const;
	void RequestFall();

	void SetInError( bool bInError = true ) { m_bInError = bInError; }
	void SetFinished( bool bIsFinished = true ) { m_bIsFinished = bIsFinished; }

	// Returns whether it changed to the jumping state or not.
	bool UpdateJumping();
	bool AttemptCeilingToFloorJump( const Asura_AI_NavVertex* pxCurrentWP );
	bool AttemptWallToWallJump180( const Asura_AI_NavVertex* pxCurrentWP );
	bool AttemptWallToFloorJump( const JumpDirection eJumpDir, const Asura_Vector_3& xIdealJumpDir );
	bool AttemptWallHop( const JumpDirection eJumpDir, const Asura_Vector_3& xIdealJumpDir );
	bool AttemptWallToWallJump90( const JumpDirection eJumpDir, const Asura_Vector_3& xIdealJumpDir );
	bool AttemptFloorToWallJump( const JumpDirection eJumpDir, const Asura_Vector_3& xIdealJumpDir );
	bool AttemptFloorHop( const JumpDirection eJumpDir, const Asura_Vector_3& xIdealJumpDir );
	bool AttemptJumpToUnStuck();
	const Asura_AI_NavVertex* GetDestinationWaypoint( Asura_Hash_ID uAnimHashID );
	
	void SetSharpTurnSpeedLimit(ExMovementMode eLimit);
	ExMovementMode GetsharpTurnSpeedLimit() const { return m_eLimitsDueToSharpTurnMode; }

	bool CanPlanMove() const;
	void ClearWPDistanceCache();
	float FindDistanceOfWPFromStart(u_short usWPNumber);

	AVP_Alien_Movement& operator=( const AVP_Alien_Movement& xRhs );
	AVP_Alien_Movement( const AVP_Alien_Movement& xRhs );

	private:
	State				   m_eState;
	MovementModeState	   m_eMovementModeState;
	float				   m_fTimeInState;
	AVP_Brain_Actor_Alien* m_pxAlienBrain;

	ExMovementMode m_eLimitsDueToSharpTurnMode;
	ExMovementMode m_eRequestedMoveMode;
	ExMovementMode m_eActualMoveMode;

	union
	{
		// These flags are reset every time we get a new route.
		u_int m_uPerRouteFlags;
		struct 
		{
			u_int m_bInError			: 1,
				  m_bIsFinished			: 1,
				  m_bAttemptedUnstick	: 1,
				  m_bMovementInProgress : 1,
				  m_bAvoidLight			: 1,
				  m_bJumpOnWaypoint		: 1,
				  m_bAbort				: 1;
		};
	};
	union
	{
		// These flags do not get reset.
		u_int m_uPersistentFlags;
		struct 
		{
            u_int m_bJumpFromDanger		: 1,
				  m_bJumpingDisallowed	: 1,
				  m_bIsBursting	        : 1,
				  m_bFallingDisallowed	: 1,
				  m_bFallDueToDamageDeferred : 1,
				  m_bIsShutDown			: 1,
				  m_bNotGS2Mode			: 1;
		};
	};
	float					m_fArrivalRange;
	StandardLinkTraverser	m_xStandardLinkTraverser;
    SlowLinkTraverser		m_xSlowLinkTraverser;
	JumpLinkTraverser		m_xJumpLinkTraverser;
	GS2LinkTraverser		m_xGS2LinkTraverser;
	EnvHookLinkTraverser	m_xEnvHookLinkTraverser;
	DestinationTraverser	m_xDestinationTraverser;
	LinkTraverser*			m_pxCurrentTraverser;

	float m_fTraversalFailureScore;
	float m_fJumpUpdateTimer;
	float m_fPrevPeriodSinceDamage;

	float m_fTimeSinceLastFall;
	float m_fTimeSinceLastJump;

	float m_fRouteTraversedDistance;
	float m_fRouteTotalDistance;
	Asura_Guid m_uIgnoreTargetForAvoidanceID;

	Asura_TemplateTree< u_short, float > m_xWPDistanceFromStartCache;

	// Data shared by the traversers.
	Asura_LinkList< TransitionData > m_xTransitionDataList;

	// Stuff for the static callback from the jump to use and set.
	static bool WaypointRaySearchCallback( const u_int uWPID );
	static const int iNUM_TEST_POSITIONS = 4;
	static Asura_Vector_3 s_axTestPositions[ iNUM_TEST_POSITIONS ];
	static const Asura_AI_NavVertex* s_pxClosestWP;
	static float s_fSmallestDistanceSq;
};

//////////////////////////////////////////////////////////////////////////////
//
// Wrapper behaviour to supply the movement stuff to GS2.
//## This should change. GS2 should not assume movement is implemented using behaviours.
//
//////////////////////////////////////////////////////////////////////////////

class AVP_Behaviour_Alien_MovementWrapper : public Axon_Project_Behaviour
{
	typedef Axon_Project_Behaviour PARENT;

public:
	AVP_Behaviour_Alien_MovementWrapper( AVP_Brain_Actor_Alien* pxAlienBrain );
	bool GetToPosition( const Asura_Vector_3& xPosition );

	virtual void ReadFromChunkStream( Asura_Chunk_Stream& xStream );
	virtual void WriteToChunkStream( Asura_Chunk_Stream& xStream ) const;

protected:
	virtual void PerFrameUpdate( const float fTimeslice );

private:
	AVP_Brain_Actor_Alien* GetAlienBrain() const;

	bool m_bIsMovePending;
	Asura_Vector_3 m_xPosition;
	int m_iRetries;

	enum { CURRENT_CHUNK_VERSION = 0 };
};

#endif //__AVP_BEHAVIOUR_ALIEN_MOVEMENT_H__
