summaryrefslogtreecommitdiff
path: root/game/server/NextBot/NextBotUtil.h
diff options
context:
space:
mode:
Diffstat (limited to 'game/server/NextBot/NextBotUtil.h')
-rw-r--r--game/server/NextBot/NextBotUtil.h278
1 files changed, 278 insertions, 0 deletions
diff --git a/game/server/NextBot/NextBotUtil.h b/game/server/NextBot/NextBotUtil.h
new file mode 100644
index 0000000..75a4221
--- /dev/null
+++ b/game/server/NextBot/NextBotUtil.h
@@ -0,0 +1,278 @@
+// NextBotUtil.h
+// Utilities for the NextBot system
+// Author: Michael Booth, May 2006
+//========= Copyright Valve Corporation, All rights reserved. ============//
+
+#ifndef _NEXT_BOT_UTIL_H_
+#define _NEXT_BOT_UTIL_H_
+
+#include "NextBotLocomotionInterface.h"
+#include "nav_area.h"
+#include "nav_mesh.h"
+#include "nav_pathfind.h"
+
+//--------------------------------------------------------------------------------------------
+/**
+ * A simple filter interface for various NextBot queries
+ */
+class INextBotEntityFilter
+{
+public:
+ // return true if the given entity passes this filter
+ virtual bool IsAllowed( CBaseEntity *entity ) const = 0;
+};
+
+
+// trace filter callback functions. needed for use with the querycache/optimization functionality
+bool VisionTraceFilterFunction( IHandleEntity *pServerEntity, int contentsMask );
+bool IgnoreActorsTraceFilterFunction( IHandleEntity *pServerEntity, int contentsMask );
+
+
+//--------------------------------------------------------------------------------------------
+/**
+ * Trace filter that skips all players and NextBots
+ */
+class NextBotTraceFilterIgnoreActors : public CTraceFilterSimple
+{
+public:
+ NextBotTraceFilterIgnoreActors( const IHandleEntity *passentity, int collisionGroup ) : CTraceFilterSimple( passentity, collisionGroup, IgnoreActorsTraceFilterFunction )
+ {
+ }
+};
+
+
+//--------------------------------------------------------------------------------------------
+/**
+ * Trace filter that skips all players, NextBots, and non-LOS blockers
+ */
+class NextBotVisionTraceFilter : public CTraceFilterSimple
+{
+public:
+ NextBotVisionTraceFilter( const IHandleEntity *passentity, int collisionGroup ) : CTraceFilterSimple( passentity, collisionGroup, VisionTraceFilterFunction )
+ {
+ }
+};
+
+
+//--------------------------------------------------------------------------------------------
+/**
+ * Trace filter that skips all NextBots, but includes Players
+ */
+class NextBotTraceFilterIgnoreNextBots : public CTraceFilterSimple
+{
+public:
+ NextBotTraceFilterIgnoreNextBots( const IHandleEntity *passentity, int collisionGroup )
+ : CTraceFilterSimple( passentity, collisionGroup )
+ {
+ }
+
+ virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
+ {
+ if ( CTraceFilterSimple::ShouldHitEntity( pServerEntity, contentsMask ) )
+ {
+ CBaseEntity *entity = EntityFromEntityHandle( pServerEntity );
+#ifdef TERROR
+ CBasePlayer *player = ToBasePlayer( entity );
+ if ( player && player->IsGhost() )
+ return false;
+#endif // TERROR
+
+ return ( entity->MyNextBotPointer() == NULL );
+ }
+ return false;
+ }
+};
+
+
+//--------------------------------------------------------------------------------------------
+/**
+ * Trace filter that obeys INextBot::IsAbleToBlockMovementOf()
+ */
+class NextBotTraceFilter : public CTraceFilterSimple
+{
+public:
+ NextBotTraceFilter( const IHandleEntity *passentity, int collisionGroup )
+ : CTraceFilterSimple( passentity, collisionGroup )
+ {
+ CBaseEntity *entity = const_cast<CBaseEntity *>(EntityFromEntityHandle( passentity ));
+ m_passBot = entity->MyNextBotPointer();
+ }
+
+ virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
+ {
+ if ( CTraceFilterSimple::ShouldHitEntity( pServerEntity, contentsMask ) )
+ {
+ CBaseEntity *entity = EntityFromEntityHandle( pServerEntity );
+#ifdef TERROR
+ CBasePlayer *player = ToBasePlayer( entity );
+ if ( player && player->IsGhost() )
+ return false;
+#endif // TERROR
+
+ // Skip players on the same team - they're not solid to us, and we'll avoid them
+ if ( entity->IsPlayer() && m_passBot && m_passBot->GetEntity() &&
+ m_passBot->GetEntity()->GetTeamNumber() == entity->GetTeamNumber() )
+ return false;
+
+ INextBot *bot = entity->MyNextBotPointer();
+
+ return ( !bot || bot->IsAbleToBlockMovementOf( m_passBot ) );
+ }
+ return false;
+ }
+
+ const INextBot *m_passBot;
+};
+
+
+//--------------------------------------------------------------------------------------------
+/**
+ * Trace filter that only hits players and NextBots
+ */
+class NextBotTraceFilterOnlyActors : public CTraceFilterSimple
+{
+public:
+ NextBotTraceFilterOnlyActors( const IHandleEntity *passentity, int collisionGroup )
+ : CTraceFilterSimple( passentity, collisionGroup )
+ {
+ }
+
+ virtual TraceType_t GetTraceType() const
+ {
+ return TRACE_ENTITIES_ONLY;
+ }
+
+ virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
+ {
+ if ( CTraceFilterSimple::ShouldHitEntity( pServerEntity, contentsMask ) )
+ {
+ CBaseEntity *entity = EntityFromEntityHandle( pServerEntity );
+
+#ifdef TERROR
+ CBasePlayer *player = ToBasePlayer( entity );
+ if ( player && player->IsGhost() )
+ return false;
+#endif // TERROR
+
+ return ( entity->MyNextBotPointer() || entity->IsPlayer() );
+ }
+ return false;
+ }
+};
+
+
+//--------------------------------------------------------------------------------------------
+/**
+ * Trace filter that skips "traversable" entities. The "when" argument creates
+ * a temporal context for asking if an entity is IMMEDIATELY traversable (like thin
+ * glass that just breaks as we walk through it) or EVENTUALLY traversable (like a
+ * breakable object that will take some time to break through)
+ */
+class NextBotTraversableTraceFilter : public CTraceFilterSimple
+{
+public:
+ NextBotTraversableTraceFilter( INextBot *bot, ILocomotion::TraverseWhenType when = ILocomotion::EVENTUALLY ) : CTraceFilterSimple( bot->GetEntity(), COLLISION_GROUP_NONE )
+ {
+ m_bot = bot;
+ m_when = when;
+ }
+
+ virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
+ {
+ CBaseEntity *entity = EntityFromEntityHandle( pServerEntity );
+
+ if ( m_bot->IsSelf( entity ) )
+ {
+ return false;
+ }
+
+ if ( CTraceFilterSimple::ShouldHitEntity( pServerEntity, contentsMask ) )
+ {
+ return !m_bot->GetLocomotionInterface()->IsEntityTraversable( entity, m_when );
+ }
+
+ return false;
+ }
+
+private:
+ INextBot *m_bot;
+ ILocomotion::TraverseWhenType m_when;
+};
+
+
+//---------------------------------------------------------------------------------------------
+/**
+ * Given a vector of entities, a nav area, and a max travel distance, return
+ * the entity that has the shortest travel distance.
+ */
+inline CBaseEntity *SelectClosestEntityByTravelDistance( INextBot *me, const CUtlVector< CBaseEntity * > &candidateEntities, CNavArea *startArea, float travelRange )
+{
+ // collect nearby walkable areas within travelRange
+ CUtlVector< CNavArea * > nearbyAreaVector;
+ CollectSurroundingAreas( &nearbyAreaVector, startArea, travelRange, me->GetLocomotionInterface()->GetStepHeight(), me->GetLocomotionInterface()->GetDeathDropHeight() );
+
+ // find closest entity in the collected area set
+ CBaseEntity *closeEntity = NULL;
+ float closeTravelRange = FLT_MAX;
+
+ for( int i=0; i<candidateEntities.Count(); ++i )
+ {
+ CBaseEntity *candidate = candidateEntities[i];
+
+ CNavArea *area = TheNavMesh->GetNearestNavArea( candidate, GETNAVAREA_CHECK_LOS, 500.0f );
+
+ if ( area && area->IsMarked() && area->GetCostSoFar() < closeTravelRange )
+ {
+ closeEntity = candidate;
+ closeTravelRange = area->GetCostSoFar();
+ }
+ }
+
+ return closeEntity;
+}
+
+
+#ifdef OBSOLETE
+//--------------------------------------------------------------------------------------------
+/**
+ * Trace filter that skips "traversable" entities, but hits other Actors.
+ * Used for obstacle avoidance.
+ */
+class NextBotMovementAvoidanceTraceFilter : public CTraceFilterSimple
+{
+public:
+ NextBotMovementAvoidanceTraceFilter( INextBot *bot ) : CTraceFilterSimple( bot->GetEntity(), COLLISION_GROUP_NONE )
+ {
+ m_bot = bot;
+ }
+
+ virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask )
+ {
+ CBaseEntity *entity = EntityFromEntityHandle( pServerEntity );
+
+#ifdef TERROR
+ CBasePlayer *player = ToBasePlayer( entity );
+ if ( player && player->IsGhost() )
+ return false;
+#endif // TERROR
+
+ if ( m_bot->IsSelf( entity ) )
+ {
+ return false;
+ }
+
+ if ( CTraceFilterSimple::ShouldHitEntity( pServerEntity, contentsMask ) )
+ {
+ return !m_bot->GetLocomotionInterface()->IsEntityTraversable( entity, ILocomotion::IMMEDIATELY );
+ }
+
+ return false;
+ }
+
+private:
+ INextBot *m_bot;
+};
+#endif
+
+
+#endif // _NEXT_BOT_UTIL_H_