diff options
Diffstat (limited to 'game/server/NextBot/NextBotUtil.h')
| -rw-r--r-- | game/server/NextBot/NextBotUtil.h | 278 |
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_ |