//////////////////////////////////////////////////////////////////////////////
//
// AVP_Navigation_Types.h
//
// Copyright (C) 2008 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_NAVIGATION_TYPES_H__
#define __AVP_NAVIGATION_TYPES_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 "AI/Asura_AI_Navigation.h"
#include "Network/Asura_Guid.h"

#if defined(_DEBUG) && !defined(ASURA_NO_DEBUG_OUTPUT)
#include "Core/Asura_List.h"
#include "Camera/Asura_Camera.h"
#include "rendering/Asura_Font_System.h"
#endif

// F O R W A R D   D E C L A R A T I O N S ///////////////////////////////////
class AVP_ServerEntity_Actor;
class AVP_ServerEntity_GamePlayVolume;

//////////////////////////////////////////////////////////////////////////////
//
// AVP_Navigation
//
//////////////////////////////////////////////////////////////////////////////

namespace AVP_Navigation
{
    enum AVP_AI_PATHFINDER_FLAGS
    {
        AVP_AI_PATHFINDER_FLAG_HUMANOID            = ASURA_AI_PATHFINDER_FLAGS_BEGIN_PROJECT_SPECIFIC, // 0x00010000
        AVP_AI_PATHFINDER_FLAG_ALIEN_HIGH_MOBILITY = 0x00020000,
        AVP_AI_PATHFINDER_FLAG_ALIEN_MED_MOBILITY  = 0x00040000,
        AVP_AI_PATHFINDER_FLAG_ALIEN_LOW_MOBILITY  = 0x00080000,
		AVP_AI_PATHFINDER_FLAG_PREDATOR			   = 0x00100000,	
    };

    enum AVP_AI_CONNECTION_FLAGS
    {
        AVP_AI_CONNECTION_FLAG_HUMANOID                 = ASURA_AI_CONNECTION_FLAGS_BEGIN_PROJECT_SPECIFIC, // 0x0100
        AVP_AI_CONNECTION_FLAG_ALIEN                    = 0x0200,
        AVP_AI_CONNECTION_FLAG_TRANSITION_HIGH_MOBILITY = 0x0400,
        AVP_AI_CONNECTION_FLAG_TRANSITION_MED_MOBILITY  = 0x0800,
        AVP_AI_CONNECTION_FLAG_TRANSITION_LOW_MOBILITY  = 0x1000,
		AVP_AI_CONNECTION_FLAG_PREDATOR					= 0x2000,
		AVP_AI_CONNECTION_FLAG_GS2						= 0x4000,
		AVP_AI_CONNECTION_FLAG_ENV_HOOK					= 0x8000

        // Transition mobility:
        // Ceiling -> Floor   = Low
        // Floor   -> Floor   = N/A
        // Wall    -> Floor   = Low
        // Ceiling -> Wall    = Med
        // Floor   -> Wall    = Med
        // Wall    -> Wall    = Med
        // Ceiling -> Ceiling = High
        // Floor   -> Ceiling = High
        // Wall    -> Ceiling = High
    };

    enum AVP_AI_NAVVERTEX_FLAGS
    {
        AVP_AI_NAVVERTEX_FLAG_HUMANOID			= ASURA_AI_NAVVERTEX_FLAG_BEGIN_PROJECT_SPECIFIC, // 0x0100
        AVP_AI_NAVVERTEX_FLAG_ALIEN				= 0x0200,
		AVP_AI_NAVVERTEX_FLAG_PREDATOR			= 0x0400,
		AVP_AI_NAVVERTEX_FLAG_GS2				= 0x0800,
		AVP_AI_NAVVERTEX_FLAG_ENV_HOOK			= 0x1000,
		AVP_AI_NAVVERTEX_FLAG_PREDATOR_JUMP		= 0x2000,
		AVP_AI_NAVVERTEX_FLAG_ALIEN_JUMP		= 0x4000,
		AVP_AI_NAVVERTEX_FLAG_ALIEN_JUMP_OVER	= 0x8000
	};

    enum LinkTransitionType
    {
        LTT_NO_TRANSITION,

        LTT_FLOOR_TO_WALL_CONCAVE,
        LTT_WALL_TO_FLOOR_CONCAVE,

        LTT_FLOOR_TO_WALL_CONVEX,
        LTT_WALL_TO_FLOOR_CONVEX,

        LTT_WALL_TO_CEILING_CONCAVE,
        LTT_CEILING_TO_WALL_CONCAVE,

        LTT_WALL_TO_CEILING_CONVEX,
        LTT_CEILING_TO_WALL_CONVEX,

        LTT_FLOOR_TO_CEILING,
        LTT_CEILING_TO_FLOOR,

		LTT_CEILING_TO_CEILING,
		LTT_FLOOR_TO_FLOOR,

        LTT_WALL_TO_WALL_90_CONCAVE,
        LTT_WALL_TO_WALL_90_CONVEX,
        LTT_WALL_TO_WALL_180,

		LTT_ENVHOOK,
		LTT_ENVHOOK_JUMPOVER,

        NUM_LINK_TRANSITION_TYPES
    };

    enum MovementMode
    {
        MM_SLOW,
        MM_MEDIUM,
        MM_FAST,
        NUM_MOVEMENT_MODES
    };

#ifdef ASURA_TOOLS
	static const char*	s_aszMoveModeStrings[ NUM_MOVEMENT_MODES ]  = 
	{
		"MOVE SLOW",
		"MOVE MEDIUM",
		"MOVE FAST",
	};
#endif

    enum RouteType
    {
        RT_STANDARD,		// Standard straight to the destination route.
        RT_SNEAKY,			// Route keeping in the dark/sticking to cover as much as possible.
        NUM_ROUTE_TYPES
    };

	enum TraverseStyle
	{
		TS_STANDARD,
		TS_ALIEN_INSECTY,
		NUM_TRAVERSE_STYLES
	};

    enum AgilityRating
    {
        AR_LOW,
        AR_MED,
        AR_HIGH,
        NUM_AGILITY_RATINGS
    };

    struct NavData
    {
        NavData()
        : m_eMovementMode( MM_FAST )
        , m_eRouteType( RT_STANDARD )
		, m_eTraverseStyle( TS_STANDARD )
        , m_eRouteAgilityRating( AR_LOW )
        , m_xStartPosition( Asura_Maths::ZeroVector3 )
        , m_xDestinationPosition( Asura_Maths::ZeroVector3 )
        , m_uPathfinderFlags( 0 )
        , m_pusRoute( NULL )
        , m_usRouteLength( 0 )
        , m_usRouteSegmentIndex( 0 )
        , m_usDestinationWPID( ASURA_INVALID_WAYPOINT_ID )
        , m_usCurrentWPID( ASURA_INVALID_WAYPOINT_ID )
        , m_usCurrentZone( ASURA_NAVVERTEX_MAX_ZONE_ID )
        , m_fCharacterWidth( 1.0f )
		, m_fCharacterHeight( 1.0f )
		, m_pusOrigRoute( NULL )
		, m_usOrigRouteLength( 0 )
        {
        }

		~NavData()
		{
			ResetRoute();
		}

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

        void ResetRoute();

		// Copy the config part of NavData.
		void CopyConfigTo( NavData& xRhs ) const
		{
			xRhs.m_eMovementMode        = m_eMovementMode;
			xRhs.m_eRouteType           = m_eRouteType;
			xRhs.m_eTraverseStyle       = m_eTraverseStyle;
			xRhs.m_eRouteAgilityRating  = m_eRouteAgilityRating;
			xRhs.m_xStartPosition       = m_xStartPosition;
			xRhs.m_xDestinationPosition = m_xDestinationPosition;
			xRhs.m_uPathfinderFlags     = m_uPathfinderFlags;
			xRhs.m_usDestinationWPID    = m_usDestinationWPID;
			xRhs.m_usCurrentWPID        = m_usCurrentWPID;
			xRhs.m_usCurrentZone        = m_usCurrentZone;

			xRhs.m_fCharacterWidth  = m_fCharacterWidth;
			xRhs.m_fCharacterHeight = m_fCharacterHeight;
		}

#ifdef ASURA_TOOLS
        bool Verify() const;
#endif

        MovementMode   m_eMovementMode;
        RouteType      m_eRouteType;
		TraverseStyle  m_eTraverseStyle;
        AgilityRating  m_eRouteAgilityRating;

        Asura_Vector_3 m_xStartPosition;
        Asura_Vector_3 m_xDestinationPosition;

        u_int          m_uPathfinderFlags;
        u_short*       m_pusRoute;
        u_short        m_usRouteLength;
        u_short        m_usRouteSegmentIndex;
        u_short        m_usDestinationWPID;
        u_short        m_usCurrentWPID;
        u_short        m_usCurrentZone;

		float          m_fCharacterWidth;
        float          m_fCharacterHeight;

		u_short*       m_pusOrigRoute;
		u_short        m_usOrigRouteLength;
		mutable u_int  m_uConnectionGeneration; // this is not really part of the state and should be changeable.

    private:
		NavData( const NavData& xRhs );
		NavData& operator=( const NavData& xRhs );

        enum { CURRENT_CHUNK_VERSION = 6 };
    };

	// Standard test parameters for the majority of the AVP_Navigation functions.
    struct TestParams
    {
        TestParams()
        : m_uPathfinderFlags( 0 )
        , m_bRejectNonalignedWPs( false )
        , m_xNormal( 0.0f, -1.0f, 0.0f )
        , m_usZone( ASURA_NAVVERTEX_MAX_ZONE_ID )
        {
        }
		TestParams( const u_int uPathfinderFlags, const u_short usZone )
		: m_uPathfinderFlags( uPathfinderFlags )
		, m_bRejectNonalignedWPs( false )
		, m_xNormal( 0.0f, -1.0f, 0.0f )
		, m_usZone( usZone )
		{
		}

        u_int          m_uPathfinderFlags;
        // Whether to reject waypoints that are not orientated the same as us.
        bool           m_bRejectNonalignedWPs;
        Asura_Vector_3 m_xNormal;
        u_short        m_usZone;
    };

	// Parameters for the 'at position' test.

    struct APParams
    {
        APParams() : m_fMaxCoplanarOffset( 0.25f ), m_fMaxPerpendicularOffset( 0.5f ), m_xDestinationNormal( 0.0f, -1.0f, 0.0f ) {}

        // The allowed offset parallel to the local XZ plane at the destination.
        float          m_fMaxCoplanarOffset;
        // The allowed offset in the local Y direction at the destination.
        float          m_fMaxPerpendicularOffset;
        Asura_Vector_3 m_xDestinationNormal;
    };

	// Functors for the various route find and search functions.
	class AStarFunctorBase
	{
	public:
		virtual ~AStarFunctorBase() {}

		// Returns the estimated cost to the goal from the waypoint.
		virtual float EstimateCostToGoal( const int iWaypointIndex )
		{
			return Asura_AI_Navigation_System::DefaultGoalCostEstimateFunction( iWaypointIndex, NULL );
		}
		// Returns the cost associated with travelling this link.
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags )
		{
			return Asura_AI_Navigation_System::DefaultTraversalCostFunction( iWaypointIndex, iLinkIndex, uPathfinderFlags, NULL );
		}
		// Returns whether this waypoint is the goal or not.
		virtual bool IsGoalAchieved( const int iWaypointIndex )
		{
			return Asura_AI_Navigation_System::DefaultGoalAchievedFunction( iWaypointIndex, NULL );
		}
		// Returns whether to ignore the link or not.
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return Asura_AI_Navigation_System::DefaultLinkFlagsTestFunction( pxLink, uPathfinderFlags, NULL );
		}
	};
	class AwayFromFunctor : public AStarFunctorBase
	{
	public:
		virtual float EstimateCostToGoal( const int iWaypointIndex );
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );
		virtual bool IsGoalAchieved( const int iWaypointIndex );

		AwayFromFunctor( const Asura_Vector_3& xStartPosition, const float fRange ) : m_xStartPosition( xStartPosition ), m_fRange( fRange ), m_fRangeSq( fRange * fRange ) {}

	protected:
		Asura_Vector_3 m_xStartPosition;
		float		   m_fRange;
		float		   m_fRangeSq;
	};
	class AwayFromInDirFunctor : public AwayFromFunctor
	{
	public:
		virtual float EstimateCostToGoal( const int iWaypointIndex ) { return 0.0f; }
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

		AwayFromInDirFunctor( const Asura_Vector_3& xStartPosition, const float fRange, const Asura_Vector_3& xDirection )
		: AwayFromFunctor( xStartPosition, fRange )
		, m_xDirection( xDirection )
		{
		}

	protected:
		Asura_Vector_3 m_xDirection;
	};

	bool AlienLinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags );
	bool HumanoidLinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags );
	bool AlienQueenLinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags );
	bool PredatorLinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags );

	float AlienCalculateCostMultiplierDueToMobility( const Asura_AI_NavVertex* pxToWP, const u_int uPathfinderFlags, bool bForceLowMobility );

	class AlienAStarFunctor : public AStarFunctorBase
	{
	public:

		void SetLowMobilityForShortDistance(Asura_Vector_3 xStartPosition, float fDistance);
		void SetAvoidJumping(Asura_Vector_3 xStartPosition, float fDistance);														 
		void SetNoLimit();														 

		virtual float EstimateCostToGoal( const int iWaypointIndex );
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		AlienAStarFunctor() 
		: m_eRouteType( RT_STANDARD )
		, m_bThreatWPIDValid( false )
		, m_uThreatWPID( ASURA_INVALID_WAYPOINT_ID )
		, m_xStartPosition(Asura_Maths::ZeroVector3)
		, m_fDistanceSq(0.0)
		, m_eMovementLimitation(LIMIT_NO_LIMIT)
		{}
		// Constructor explicitly for the sneaky route type.
		AlienAStarFunctor( const u_int iThreatWPID ) 
		: m_eRouteType( RT_SNEAKY )
		, m_bThreatWPIDValid( true )
		, m_uThreatWPID( iThreatWPID )
		, m_xStartPosition(Asura_Maths::ZeroVector3)
		, m_fDistanceSq(0.0)
		, m_eMovementLimitation(LIMIT_NO_LIMIT)
		{}


	protected:

		RouteType m_eRouteType;
		bool	  m_bThreatWPIDValid;
		u_int	  m_uThreatWPID;
		Asura_Vector_3 m_xStartPosition;
		float m_fDistanceSq;
		enum 
		{
			LIMIT_NO_LIMIT,
			LIMIT_LOW_MOBILITY,
			LIMIT_AVOID_JUMPING
		} m_eMovementLimitation;

		typedef AStarFunctorBase PARENT;
				
	};

	class AlienAwayFromFunctor : public AwayFromFunctor
	{
	public:
		void SetLowMobilityForShortDistance(Asura_Vector_3 xStartPosition, float fDistance);
		void SetAvoidJumping(Asura_Vector_3 xStartPosition, float fDistance);														 
		void SetNoLimit();														 
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		AlienAwayFromFunctor( const Asura_Vector_3& xPosition, const float fRange )
		: AwayFromFunctor( xPosition, fRange )
		, m_xStartPosition(Asura_Maths::ZeroVector3)
		, m_fDistanceSq(0.0)
		, m_eMovementLimitation(LIMIT_NO_LIMIT)
		{}

		const Asura_Vector_3& GetStartPosition() const { return m_xStartPosition; }
		float GetDistance() const { return Asura_Maths::Sqrt(m_fDistanceSq); }

	protected:
		Asura_Vector_3 m_xStartPosition;
		float m_fDistanceSq;
		enum 
		{
			LIMIT_NO_LIMIT,
			LIMIT_LOW_MOBILITY,
			LIMIT_AVOID_JUMPING
		} m_eMovementLimitation;

		typedef AwayFromFunctor PARENT;
	};

	class AlienAwayFromInDirFunctor : public AwayFromInDirFunctor
	{
	public:

		void SetLowMobilityForShortDistance(Asura_Vector_3 xStartPosition, float fDistance);
		void SetAvoidJumping(Asura_Vector_3 xStartPosition, float fDistance);														 
		void SetNoLimit();														 
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );


		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		AlienAwayFromInDirFunctor( const Asura_Vector_3& xPosition, const float fRange, const Asura_Vector_3& xDirection )
		: AwayFromInDirFunctor( xPosition, fRange, xDirection )
		, m_xStartPosition(Asura_Maths::ZeroVector3)
		, m_fDistanceSq(0.0)
		, m_eMovementLimitation(LIMIT_NO_LIMIT)
		{}

	protected:
		Asura_Vector_3 m_xStartPosition;
		float m_fDistanceSq;
		enum 
		{
			LIMIT_NO_LIMIT,
			LIMIT_LOW_MOBILITY,
			LIMIT_AVOID_JUMPING
		} m_eMovementLimitation;

		typedef AwayFromInDirFunctor PARENT;

	};

	//---------------------------------------------------------------------
	// Standard FaceHugger AStar Functor
	//---------------------------------------------------------------------
	class FaceHuggerAStarFunctor : public AStarFunctorBase
	{
	public:

		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags ) && !(pxLink->GetFlags() & AVP_AI_CONNECTION_FLAG_GS2);
		}
	protected:
		typedef AStarFunctorBase PARENT;
	};

	class FaceHuggerAwayFromFunctor : public AwayFromFunctor
	{
	public:
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags ) && !(pxLink->GetFlags() & AVP_AI_CONNECTION_FLAG_GS2);
		}

		FaceHuggerAwayFromFunctor( const Asura_Vector_3& xPosition, const float fRange )
			: AwayFromFunctor( xPosition, fRange )
		{}
	protected:

		typedef AwayFromFunctor PARENT;
	};

	class FaceHuggerAwayFromInDirFunctor : public AwayFromFunctor
	{
	public:

		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags ) && !(pxLink->GetFlags() & AVP_AI_CONNECTION_FLAG_GS2);
		}

		FaceHuggerAwayFromInDirFunctor( const Asura_Vector_3& xPosition, const float fRange, const Asura_Vector_3& xDirection )
		: AwayFromFunctor( xPosition, fRange)
		, m_xDirection(xDirection)
		{}

	protected:
		const Asura_Vector_3 m_xDirection;
		typedef AwayFromFunctor PARENT;

	};


	//---------------------------------------------------------------------
	// Standard Humanoid AStar Functor
	//---------------------------------------------------------------------
	class HumanoidAStarFunctor : public AStarFunctorBase
	{
	public:
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return HumanoidLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );
	};

	//---------------------------------------------------------------------
	// Combat Humanoid Functor
	//---------------------------------------------------------------------
	class HumanoidCombatAStarFunctor : public HumanoidAStarFunctor
	{
		typedef HumanoidAStarFunctor PARENT;

	public:

		HumanoidCombatAStarFunctor( Asura_Vector_3 xPosition )
		: m_xPosition( xPosition )
		{

		}

		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

	protected:

		Asura_Vector_3	m_xPosition;
	};

	//---------------------------------------------------------------------
	// HumanoidThreatProximityAStarFunctor
	//---------------------------------------------------------------------
	class HumanoidThreatProximityAStarFunctor : public HumanoidAStarFunctor
	{
		typedef HumanoidAStarFunctor PARENT;

	public:

		HumanoidThreatProximityAStarFunctor( Asura_Vector_3 xPosition )
		: m_xThreatPos( xPosition )
		{

		}

		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

	protected:

		Asura_Vector_3	m_xThreatPos;
	};

	//---------------------------------------------------------------------
	// Alien Queen Functor
	//---------------------------------------------------------------------
	class AlienQueenAStarFunctor : public AStarFunctorBase
	{

	public:

		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienQueenLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );
	};

	class PredatorAStarFunctor : public AStarFunctorBase
	{
	public:
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return PredatorLinkFlagsTest( pxLink, uPathfinderFlags );
		}
	};
	class PredatorAwayFromFunctor : public AwayFromFunctor
	{
	public:
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return PredatorLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		PredatorAwayFromFunctor( const Asura_Vector_3& xPosition, const float fRange ) : AwayFromFunctor( xPosition, fRange ) {}
	};
	class PredatorAwayFromInDirFunctor : public AwayFromInDirFunctor
	{
	public:
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return PredatorLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		PredatorAwayFromInDirFunctor( const Asura_Vector_3& xPosition, const float fRange, const Asura_Vector_3& xDirection )
		: AwayFromInDirFunctor( xPosition, fRange, xDirection )
		{
		}
	};

	class SearchFunctor : public AStarFunctorBase
	{
	public:
		// Returns whether the search should stop or not.
		// This is optional as the search will automatically stop once it reaches the maximum range.
		virtual bool VisitNode( const int iWaypointIndex ) = 0;

		SearchFunctor( const u_short usStartWPID ) : m_usStartWPID( usStartWPID ) {}
		u_short GetStartWPID() const { return m_usStartWPID; }

	protected:
		virtual bool IsGoalAchieved( const int iWaypointIndex ) { return VisitNode( iWaypointIndex ); }

	private:
		u_short m_usStartWPID;
	};
	class BreadthFirstSearch : public SearchFunctor
	{
	public:
		BreadthFirstSearch( const u_short usStartWPID, const float fMaxRange )
		: SearchFunctor( usStartWPID )
		, m_xStartPosition( Asura_Maths::ZeroVector3 )
		, m_fMaxRangeSq( fMaxRange * fMaxRange )
		{
			const Asura_AI_NavVertex* pxStartWP = Asura_AI_Navigation_System::GetWaypoint( usStartWPID );
			Asura_Assert( pxStartWP, "BreadthFirstFunctor - could not get start position" );
			if ( pxStartWP )
			{
				m_xStartPosition = pxStartWP->GetPosition();
			}
		}

	protected:
		virtual float EstimateCostToGoal( const int iWaypointIndex ) { return 0.0f; }
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

		const Asura_Vector_3& GetStartPosition() const { return m_xStartPosition; }
		float GetMaxRangeSq() const { return m_fMaxRangeSq; }
		float GetMaxRange() const { return Asura_Maths::Sqrt( m_fMaxRangeSq ); }

	private:
		Asura_Vector_3 m_xStartPosition;
		float          m_fMaxRangeSq;
	};
	class InDirectionSearch : public SearchFunctor
	{
	public:
		InDirectionSearch( const u_short usStartWPID, const float fMaxRange, const Asura_Vector_3& xDirection )
		: SearchFunctor( usStartWPID )
		, m_xStartPosition( Asura_Maths::ZeroVector3 )
		, m_fMaxRangeSq( fMaxRange * fMaxRange )
		, m_xDirection( xDirection )
		{
			const Asura_AI_NavVertex* pxStartWP = Asura_AI_Navigation_System::GetWaypoint( usStartWPID );
			Asura_Assert( pxStartWP, "InDirectionFunctor - could not get start position" );
			if ( pxStartWP )
			{
				m_xStartPosition = pxStartWP->GetPosition();
			}
		}

	protected:
		virtual float EstimateCostToGoal( const int iWaypointIndex ) { return 0.0f; }
		virtual float EstimateTraversalCost( const int iWaypointIndex, const int iLinkIndex, const u_int uPathfinderFlags );

		const Asura_Vector_3& GetStartPosition() const { return m_xStartPosition; }
		float GetMaxRangeSq() const { return m_fMaxRangeSq; }
		float GetMaxRange() const { return Asura_Maths::Sqrt( m_fMaxRangeSq ); }
		const Asura_Vector_3& GetDirection() const { return m_xDirection; }

	private:
		Asura_Vector_3 m_xStartPosition;
		float          m_fMaxRangeSq;
		Asura_Vector_3 m_xDirection;
	};

	//-------------------------------------------------------------------
	// parameters to be passed into position evaluation fucntions
	//-------------------------------------------------------------------
	struct AVP_PosEvalParams
	{

		AVP_PosEvalParams()
		: m_uActorGuid( ASURA_GUID_UNREGISTERED )
		, m_uStartWaypointID( ASURA_INVALID_WAYPOINT_ID )
		, m_uTestWPID ( ASURA_INVALID_WAYPOINT_ID )
		, m_fEvaluationRange( 0.0f )
		, m_fMinFightingRange( 0.0f )
		, m_fMaxFightingRange( 0.0f )
		, m_xPosition( Asura_Maths::ZeroVector3 )
		, m_uCombatZoneGPVGuid( ASURA_GUID_UNREGISTERED )
		{
		}

		AVP_PosEvalParams( Asura_Guid uActorGuid, u_int uStartWaypointID, float fEvaluationRange, Asura_Guid uCombatZoneGPVGuid = ASURA_GUID_UNREGISTERED )
		: m_uActorGuid( uActorGuid )
		, m_uStartWaypointID( uStartWaypointID )
		, m_uTestWPID ( ASURA_INVALID_WAYPOINT_ID )
		, m_fEvaluationRange( fEvaluationRange )
		, m_fMinFightingRange( 0.0f )
		, m_fMaxFightingRange( 0.0f )
		, m_xPosition( Asura_Maths::ZeroVector3 )
		, m_uCombatZoneGPVGuid( uCombatZoneGPVGuid )
		{
		}

		AVP_PosEvalParams( Asura_Guid uActorGuid, u_int uStartWaypointID, float fEvaluationRange, float fMinFightingRange, float fMaxFightingRange, Asura_Guid uCombatZoneGPVGuid = ASURA_GUID_UNREGISTERED )
		: m_uActorGuid( uActorGuid )
		, m_uStartWaypointID( uStartWaypointID )
		, m_uTestWPID ( ASURA_INVALID_WAYPOINT_ID )
		, m_fEvaluationRange( fEvaluationRange )
		, m_fMinFightingRange( fMinFightingRange )
		, m_fMaxFightingRange( fMaxFightingRange )
		, m_xPosition( Asura_Maths::ZeroVector3 )
		, m_uCombatZoneGPVGuid( uCombatZoneGPVGuid )
		{
		}

		AVP_PosEvalParams( Asura_Guid uActorGuid, u_int uStartWaypointID, float fEvaluationRange, const Asura_Vector_3 xPosition, Asura_Guid uCombatZoneGPVGuid = ASURA_GUID_UNREGISTERED )
		: m_uActorGuid( uActorGuid )
		, m_uStartWaypointID( uStartWaypointID )
		, m_uTestWPID ( ASURA_INVALID_WAYPOINT_ID )
		, m_fEvaluationRange( fEvaluationRange )
		, m_fMinFightingRange( 0.0f )
		, m_fMaxFightingRange( 0.0f )
		, m_xPosition( xPosition )
		, m_uCombatZoneGPVGuid( uCombatZoneGPVGuid )
		{
		}

		Asura_Guid		m_uActorGuid;
		u_int			m_uStartWaypointID;
		u_int			m_uTestWPID;
		float			m_fEvaluationRange;
		float			m_fMinFightingRange;
		float			m_fMaxFightingRange;
		Asura_Vector_3	m_xPosition;
		Asura_Guid		m_uCombatZoneGPVGuid;
	};

	//-------------------------------------------------------------------------
	class PosEvalFunctor : public BreadthFirstSearch
	{
	public:

		enum { MAX_STORED_BEST_WAYPOINTS = 2 };

		typedef u_int( WaypointScoringFn( AVP_PosEvalParams xPosEvalParams ) );
	
		PosEvalFunctor( const u_short usStartWPID, const float fRange, AVP_Navigation::AVP_PosEvalParams xPosEvalParams, WaypointScoringFn* pfnWaypointScoringFn )
		: BreadthFirstSearch( usStartWPID, fRange )
		, m_pfnWaypointScoringFn( pfnWaypointScoringFn )
		, m_xPosEvalParams( xPosEvalParams )
		, m_pxCombatZone( NULL )
		{
			for ( int i = 0; i < MAX_STORED_BEST_WAYPOINTS; ++i )
			{
				m_uBestScores[i] = 0;
				m_uBestWaypoints[i] = ASURA_INVALID_WAYPOINT_ID;
			}

			// For Debugging Only
			#if defined(_DEBUG) && !defined(ASURA_NO_DEBUG_OUTPUT)
			DestoryList();
			#endif
			SetCombatZoneGamePlayVolume();
		}

		// Public Overridden Member Functions...
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return HumanoidLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		virtual bool VisitNode( const int iWaypointIndex );

		// Public Member Data Access Functions...
		u_int GetBestWaypointID( void ) { return m_uBestWaypoints[ 0 ]; }
		u_int GetBestWaypointID( u_int uIndex ) { Asura_Assert( uIndex < 5 , "Index Out Of Range!" ); return m_uBestWaypoints[ uIndex ]; }

		// For Debugging Only
		#if defined(_DEBUG) && !defined(ASURA_NO_DEBUG_OUTPUT)
		// Static Public Member Functions...
		static void RenerWpInfo();
		static void DestoryList();
		#endif

	private:

		// Private Member Functions...
		void SetCombatZoneGamePlayVolume();

		// Private Members Variables...
		WaypointScoringFn*					m_pfnWaypointScoringFn;
		AVP_PosEvalParams					m_xPosEvalParams;
		u_int								m_uBestScores[MAX_STORED_BEST_WAYPOINTS];
		u_int								m_uBestWaypoints[MAX_STORED_BEST_WAYPOINTS];
		AVP_ServerEntity_GamePlayVolume*	m_pxCombatZone;

		// For Debugging Only
		#if defined(_DEBUG) && !defined(ASURA_NO_DEBUG_OUTPUT)
		struct WPInfo
		{
			u_int m_uWPID;
			u_int m_uScore;
		};

		static Asura_List<WPInfo> s_xWPInfoList;
		#endif
	};

	//-------------------------------------------------------------------------

	class HumanoidInDirectionSearch : public InDirectionSearch
	{
		typedef InDirectionSearch PARENT;

	public:

		HumanoidInDirectionSearch( const u_short usStartWPID, const float fMaxRange, const float fMinRangeSq, const Asura_Vector_3& xDirection )
		: InDirectionSearch( usStartWPID, fMaxRange, xDirection )
		, m_fMinRangeSq( fMinRangeSq )
		{
		}

		virtual bool VisitNode( const int iWaypointIndex );

		float GetMinRangeSq() const { return m_fMinRangeSq; }

	private:
		
		float m_fMinRangeSq;
	};

	//-------------------------------------------------------------------------

	class AlienFindCoverInRangeFunctor : public BreadthFirstSearch
	{
	public:
		virtual bool VisitNode( const int iWaypointIndex );
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		AlienFindCoverInRangeFunctor( const u_int uStartWPID, const u_int uThreatWPID, const float fMinRange, const float fMaxRange )
		: BreadthFirstSearch( static_cast< u_short >( uStartWPID ), fMaxRange )
		, m_fMinRangeSq( fMinRange * fMinRange )
		, m_uThreatWPID( uThreatWPID )
		, m_uCoverWPIDResult( ASURA_INVALID_WAYPOINT_ID )
		{
		}
		u_int GetCoverWPID() const { return m_uCoverWPIDResult; }

	protected:
		float m_fMinRangeSq;
		u_int m_uThreatWPID;
		u_int m_uCoverWPIDResult;
	};
	class AlienFindCoverInDirFunctor : public InDirectionSearch
	{
	public:
		virtual bool VisitNode( const int iWaypointIndex );
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		AlienFindCoverInDirFunctor( const u_short usStartWPID, const u_short usThreatWPID, const float fMaxRange, const Asura_Vector_3& xDirection )
		: InDirectionSearch( usStartWPID, fMaxRange, xDirection )
		, m_usThreatWPID( usThreatWPID )
		, m_usNearestCoverWPID( ASURA_INVALID_WAYPOINT_ID )
		, m_fMinRangeSq( 0.0f )
		{
		}
		AlienFindCoverInDirFunctor( const u_short usStartWPID, const u_short usThreatWPID, const float fMaxRange, const Asura_Vector_3& xDirection, const float fMinRange )
		: InDirectionSearch( usStartWPID, fMaxRange, xDirection )
		, m_usThreatWPID( usThreatWPID )
		, m_usNearestCoverWPID( ASURA_INVALID_WAYPOINT_ID )
		, m_fMinRangeSq( fMinRange * fMinRange )
		{
		}
		u_short GetNearestCoverWPID() const { return m_usNearestCoverWPID; }

	protected:
		u_short m_usThreatWPID;
		u_short m_usNearestCoverWPID;
		float   m_fMinRangeSq;
	};
	class AlienFindWallInDirFunctor : public InDirectionSearch
	{
	public:
		virtual bool VisitNode( const int iWaypointIndex );
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		AlienFindWallInDirFunctor( const u_short usStartWPID, const float fMaxRange, const Asura_Vector_3& xDirection )
		: InDirectionSearch( usStartWPID, fMaxRange, xDirection )
		, m_usNearestWallWPID( ASURA_INVALID_WAYPOINT_ID )
		{
		}
		u_short GetNearestWallWPID() const { return m_usNearestWallWPID; }

	private:
		u_short m_usNearestWallWPID;
	};
	class AlienFindFloorInDirFunctor : public InDirectionSearch
	{
	public:
		virtual bool VisitNode( const int iWaypointIndex );
		virtual bool LinkFlagsTest( const Asura_AI_NavConnection* pxLink, const u_int uPathfinderFlags )
		{
			return AlienLinkFlagsTest( pxLink, uPathfinderFlags );
		}

		AlienFindFloorInDirFunctor( const u_short usStartWPID, const float fMaxRange, const Asura_Vector_3& xDirection )
		: InDirectionSearch( usStartWPID, fMaxRange, xDirection )
		, m_usNearestFloorWPID( ASURA_INVALID_WAYPOINT_ID )
		{
		}
		u_short GetNearestFloorWPID() const { return m_usNearestFloorWPID; }

	private:
		u_short m_usNearestFloorWPID;
	};

#if defined(ASURA_SUPPORT_COMMAND_CONSOLE) && !defined(ASURA_NO_DEBUG_OUTPUT)
	void AddCommandConsoleVars();
#endif
}

//////////////////////////////////////////////////////////////////////////////
//
// 
//
//////////////////////////////////////////////////////////////////////////////

#endif //__AVP_NAVIGATION_TYPES_H__
