//========= Copyright Valve Corporation, All rights reserved. ============//
// tf_nav_mesh.h
// TF specific nav mesh
// Michael Booth, February 2009

#ifndef TF_NAV_MESH_H
#define TF_NAV_MESH_H

#include "nav_mesh.h"
#include "tf_nav_area.h"
#include "tf_obj_teleporter.h"

#define TF_PLAYER_JUMP_HEIGHT	45.0f			// non crouch-jumping

class CBaseObject;
class CObjectTeleporter;
class CTFPlayer;

//-------------------------------------------------------------------------
// General purpose collector class for ForAllArea-style functor methods
class CTFAreaCollector
{
public:
	bool operator() ( CNavArea *area )
	{
		m_vector.AddToTail( (CTFNavArea *)area );
		return true;
	}

	CUtlVector< CTFNavArea * > m_vector;
};


//-------------------------------------------------------------------------
class CTFNavMesh : public CNavMesh
{
public:
	CTFNavMesh( void );

	virtual CTFNavArea *CreateArea( void ) const;						// CNavArea factory

	virtual void Update( void );										// invoked on each game frame

	virtual unsigned int GetSubVersionNumber( void ) const;									// returns sub-version number of data format used by derived classes
	virtual void SaveCustomData( CUtlBuffer &fileBuffer ) const;							// store custom mesh data for derived classes
	virtual void LoadCustomData( CUtlBuffer &fileBuffer, unsigned int subVersion );			// load custom mesh data for derived classes

	virtual void OnServerActivate( void );								// (EXTEND) invoked when server loads a new map
	virtual void OnRoundRestart( void );								// invoked when a game round restarts

	virtual void FireGameEvent( IGameEvent *event );

	/**
	 * Return true if nav mesh can be trusted for all climbing/jumping decisions because game environment is fairly simple.
	 * Authoritative meshes mean path followers can skip CPU intesive realtime scanning of unpredictable geometry.
	 */
	virtual bool IsAuthoritative( void ) const { return true; }			// TF2 has nice clean environments

	virtual unsigned int GetGenerationTraceMask( void ) const;			// return the mask used by traces when generating the mesh

	void OnObjectChanged();
	bool IsSentryGunHere( CTFNavArea *area ) const;						// return true if a Sentry Gun has been built in the given area

	void CollectBuiltObjects( CUtlVector< CBaseObject * > *collectionVector, int team = TEAM_ANY );	// fill given vector will all objects on the given team

	struct BallisticLaunchInfo
	{
		Vector m_launchSpot;						// where to stand
		float m_aimYaw;								// how to aim
		float m_aimPitch;							// how to aim
		float m_chargeTime;							// how long to charge weapon
	};

	// populate the given vector with ways to launch grenades to hit the given building
	void CollectBallisticAttackInfo( CBaseObject *building, CUtlVector< BallisticLaunchInfo > *infoVector ) const;

	void ResetMeshAttributes( bool bScheduleRecomputation );

	void CollectControlPointAreas( void );

	void DecorateMesh( void );
	void DecorateMeshTacticalHints( void );
	void RemoveAllMeshDecoration( void );

	// populate the given "ambushVector" with good areas to lurk in ambush for the invading enemy team
	void CollectAmbushAreas( CUtlVector< CTFNavArea * > *ambushVector, CTFNavArea *startArea, int teamToAmbush, float searchRadius, float incursionTolerance = 300.0f ) const;

	// populate the given vector with areas that are just outside of the given team's spawn room(s)
	void CollectSpawnRoomThresholdAreas( CUtlVector< CTFNavArea * > *spawnExitAreaVector, int team ) const;

	// populate the given vector with areas that have a bomb travel distance within the given range
	void CollectAreaWithinBombTravelRange( CUtlVector< CTFNavArea * > *spawnExitAreaVector, float minTravel, float maxTravel ) const;

	const CUtlVector< CTFNavArea * > *GetSetupGateDefenseAreas( void ) const;	// return vector of areas that are good for defending enemies coming out of the blue setup gates
	const CUtlVector< CTFNavArea * > *GetControlPointAreas( int pointIndex ) const;		// return vector of areas overlapping the given control point
	CTFNavArea *GetControlPointCenterArea( int pointIndex ) const;				// return area overlapping the center of the given control point
	const CUtlVector< CTFNavArea * > *GetSpawnRoomAreas( int team ) const;		// return vector of areas within the given team spawn room(s)
	const CUtlVector< CTFNavArea * > *GetSpawnRoomExitAreas( int team ) const;	// return vector of areas where the given team exits their spawn room(s)

	enum RecomputeReasonType
	{
		RESET,
		SETUP_FINISHED,
		POINT_CAPTURED,
		POINT_UNLOCKED,
		BLOCKED_STATUS_CHANGED,
		MAP_LOGIC
	};
	void ScheduleRecomputationOfInternalData( RecomputeReasonType reason, int whichPoint );


protected:
	virtual void BeginCustomAnalysis( bool bIncremental );
	virtual void PostCustomAnalysis( void );							// invoked when custom analysis step is complete
	virtual void EndCustomAnalysis();

private:
	void ComputeIncursionDistances( void );					// recompute travel distance from each team's spawn room for each nav area
	void ComputeIncursionDistances( CTFNavArea *spawnArea, int team );
	void ComputeInvasionAreas( void );
	void ComputeLegalBombDropAreas( void );
	void ComputeBombTargetDistance();

	void UpdateDebugDisplay( void ) const;

	void OnBlockedAreasChanged( void );

	void ComputeBlockedAreas( void );

	CountdownTimer m_recomputeInternalDataTimer;			// if started, when counts down recompute internal data to give various map logic time to complete
	RecomputeReasonType m_recomputeReason;
	int m_recomputeReasonWhichPoint;
	void RecomputeInternalData( void );

	// Array of areas with sentry danger attributes set.
	CUtlVector< CTFNavArea * > m_sentryAreas;

	CUtlVector< CTFNavArea * > m_setupGateDefenseAreaVector;

	CUtlVector< CTFNavArea * > m_controlPointAreaVector[ MAX_CONTROL_POINTS ];
	CTFNavArea *m_controlPointCenterAreaVector[ MAX_CONTROL_POINTS ];

	CUtlVector< CTFNavArea * > m_redSpawnRoomAreaVector;
	CUtlVector< CTFNavArea * > m_blueSpawnRoomAreaVector;

	CUtlVector< CTFNavArea * > m_redSpawnRoomExitAreaVector;
	CUtlVector< CTFNavArea * > m_blueSpawnRoomExitAreaVector;
	void CollectAndMarkSpawnRoomExits( CTFNavArea *area, CUtlVector< CTFNavArea * > *exitAreaVector );

	CountdownTimer m_watchCartTimer;

	int m_priorBotCount;
};


inline void CTFNavMesh::ScheduleRecomputationOfInternalData( CTFNavMesh::RecomputeReasonType reason, int whichPoint = 0 )
{
	m_recomputeInternalDataTimer.Start( 2.0f );
	m_recomputeReason = reason;
	m_recomputeReasonWhichPoint = whichPoint;
}


inline const CUtlVector< CTFNavArea * > *CTFNavMesh::GetSpawnRoomAreas( int team ) const
{
	if ( team == TF_TEAM_RED )
	{
		return &m_redSpawnRoomAreaVector;
	}

	if ( team == TF_TEAM_BLUE )
	{
		return &m_blueSpawnRoomAreaVector;
	}

	return NULL;
}

inline const CUtlVector< CTFNavArea * > *CTFNavMesh::GetSpawnRoomExitAreas( int team ) const
{
	if ( team == TF_TEAM_RED )
	{
		return &m_redSpawnRoomExitAreaVector;
	}

	if ( team == TF_TEAM_BLUE )
	{
		return &m_blueSpawnRoomExitAreaVector;
	}

	return NULL;
}

inline const CUtlVector< CTFNavArea * > *CTFNavMesh::GetControlPointAreas( int pointIndex ) const
{
	if ( pointIndex < 0 || pointIndex >= MAX_CONTROL_POINTS )
	{
		return NULL;
	}

	return &m_controlPointAreaVector[ pointIndex ];
}

inline CTFNavArea *CTFNavMesh::GetControlPointCenterArea( int pointIndex ) const
{
	if ( pointIndex < 0 || pointIndex >= MAX_CONTROL_POINTS )
	{
		return NULL;
	}

	return m_controlPointCenterAreaVector[ pointIndex ];
}

inline const CUtlVector< CTFNavArea * > *CTFNavMesh::GetSetupGateDefenseAreas( void ) const
{
	return &m_setupGateDefenseAreaVector;
}


inline unsigned int CTFNavMesh::GetGenerationTraceMask( void ) const
{
	return MASK_PLAYERSOLID_BRUSHONLY;
}


inline CTFNavMesh *TheTFNavMesh( void )
{
	return reinterpret_cast< CTFNavMesh * >( TheNavMesh );
}


extern TFNavAttributeType NameToTFAttribute( const char *name );
extern const char *TFAttributeToName( TFNavAttributeType attribute );

#endif // TF_NAV_MESH_H