// SharedFunctorUtils.h // Useful functors for client and server //========= Copyright Valve Corporation, All rights reserved. ============// //-------------------------------------------------------------------------------------------------------- /** * NOTE: The functors in this file should ideally be game-independant, * and work for any Source based game */ //-------------------------------------------------------------------------------------------------------- #ifndef _SHARED_FUNCTOR_UTILS_H_ #define _SHARED_FUNCTOR_UTILS_H_ #include "debugoverlay_shared.h" #include "vprof.h" //-------------------------------------------------------------------------------------------------------- /** * Finds visible player on given team that we are pointing at. * "team" can be TEAM_ANY * Use with ForEachPlayer() */ template < class PlayerType > class TargetScan { public: TargetScan( PlayerType *me, int team, float aimTolerance = 0.01f, float maxRange = 2000.0f, float closestPointTestDistance = 50.0f, bool debug = false ) { m_me = me; AngleVectors( m_me->EyeAngles(), &m_viewForward ); m_team = team; m_closeDot = 1.0f - aimTolerance; m_bestDot = m_closeDot; m_maxRange = maxRange; m_target = NULL; m_closestPointTestDistance = closestPointTestDistance; m_debug = debug; } virtual bool operator() ( PlayerType *them ) { VPROF( "TargetScan()" ); if ( them != m_me && them->IsAlive() && (m_team == TEAM_ANY || them->GetTeamNumber() == m_team) && IsPotentialTarget( them ) ) { // move the start point out for determining closestPos, to help with close-in checks (healing, etc) Vector closestPos; Vector start = m_me->EyePosition(); Vector end = start + m_viewForward * m_closestPointTestDistance; Vector testPos; CalcClosestPointOnLineSegment( them->WorldSpaceCenter(), start, end, testPos ); start = them->GetAbsOrigin(); end = start; end.z += them->CollisionProp()->OBBMaxs().z; CalcClosestPointOnLineSegment( testPos, start, end, closestPos ); if ( m_debug ) { NDebugOverlay::Cross3D( closestPos, 1, 255, 255, 255, true, -1.0f ); NDebugOverlay::Line( end, start, 255, 0, 0, true, -1.0f ); } Vector to = closestPos - m_me->EyePosition(); to.NormalizeInPlace(); Vector meRangePoint, themRangePoint; m_me->CollisionProp()->CalcNearestPoint( closestPos, &meRangePoint ); them->CollisionProp()->CalcNearestPoint( meRangePoint, &themRangePoint ); float range = meRangePoint.DistTo( themRangePoint ); if ( range > m_maxRange ) { // too far away return true; } float dot = ViewDot( to ); if ( dot > m_closeDot ) { // target is within angle cone, check visibility if ( IsTargetVisible( them ) ) { if ( dot >= m_bestDot ) { m_target = them; m_bestDot = dot; } m_allTargets.AddToTail( them ); } } } return true; } PlayerType *GetTarget( void ) const { return m_target; } const CUtlVector< PlayerType * > &GetAllTargets( void ) const { return m_allTargets; } float GetTargetDot( void ) const { return m_bestDot; } protected: /** * Is the point in our FOV? */ virtual float ViewDot( const Vector &dir ) const { return DotProduct( m_viewForward, dir ); } /** * Is the given actor a visible target? */ virtual bool IsTargetVisible( PlayerType *them ) const { // The default check is a straight-up IsAbleToSee return m_me->IsAbleToSee( them, CBaseCombatCharacter::DISREGARD_FOV ); // already have a dot product checking FOV } /** * Is the given player a possible target at all? */ virtual bool IsPotentialTarget( PlayerType *them ) const { return true; } PlayerType *m_me; Vector m_viewForward; int m_team; float m_closeDot; float m_bestDot; float m_maxRange; float m_closestPointTestDistance; bool m_debug; PlayerType *m_target; CUtlVector< PlayerType * > m_allTargets; }; #endif