Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

463 lines
12 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose: A game system for tracking and updating entity spot state
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "cs_entity_spotting.h"
#include "cs_player.h"
#include "cs_bot.h"
#include "sensorgrenade_projectile.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define ENTITY_SPOT_FREQUENCY 0.5f
static CCSEntitySpotting s_EntitySpotting("CCSEntitySpotting");
CCSEntitySpotting * g_EntitySpotting = &s_EntitySpotting;
ConVar radarvis( "radarvismethod", "1", FCVAR_CHEAT, "0 for traditional method, 1 for more realistic method", true, 0, true, 1 );
ConVar radarpow( "radarvispow", ".4", FCVAR_CHEAT, "the degree to which you can point away from a target, and still see them on radar." );
ConVar radardist( "radarvisdistance", "1000.0f", FCVAR_CHEAT, "at this distance and beyond you need to be point right at someone to see them", true, 10, false, 0 );
ConVar radarmaxdot( "radarvismaxdot", ".996", FCVAR_CHEAT, "how closely you have to point at someone to see them beyond max distance", true, 0, true, 1.0f );
//--------------------------------------------------------------------------------------------------------
// Functors
//--------------------------------------------------------------------------------------------------------
template < typename SpotFunctor >
bool ForEachEntitySpotter( SpotFunctor &func )
{
VPROF( "ForEachEntitySpotter" );
for ( int i = 1; i <= gpGlobals->maxClients; ++i )
{
CBasePlayer *player = static_cast< CBasePlayer * >( UTIL_PlayerByIndex( i ) );
if ( player == NULL )
continue;
if ( FNullEnt( player->edict() ) )
continue;
if ( !player->IsPlayer() )
continue;
if ( !player->IsConnected() )
continue;
if ( func( player ) == false )
return false;
}
//ActiveGrenadeList activeGrenadeList = TheBots->m_activeGrenadeList;
FOR_EACH_LL( TheCSBots()->m_activeGrenadeList, it )
{
ActiveGrenade *ag = TheCSBots()->m_activeGrenadeList[it];
if ( ag->IsSensor() == false )
continue;
CBaseGrenade *grenade = ag->GetEntity();
if ( grenade == NULL )
continue;
if ( FNullEnt( grenade->edict() ) )
continue;
if ( func( grenade ) == false )
return false;
}
/*
CBaseEntity * pEntity = gEntList.FirstEnt();
while ( pEntity )
{
if ( pEntity == NULL || FNullEnt( pEntity->edict() ) )
{
pEntity = gEntList.NextEnt( pEntity );
continue;
}
if ( FNullEnt( pEntity->edict() ) )
{
pEntity = gEntList.NextEnt( pEntity );
continue;
}
if ( pEntity->IsPlayer() )
{
CBasePlayer *player = static_cast< CBasePlayer * >( pEntity );
if ( !player->IsConnected() )
{
pEntity = gEntList.NextEnt( pEntity );
continue;
}
}
if ( func( pEntity ) == false )
return false;
// else if ( dynamic_cast<CSensorGrenadeProjectile*>( pEntity ) )
// {
// if ( pThrower->IsOtherEnemy( pPlayer ) )
// {
// Vector vDelta = pPlayer->EyePosition() - GetAbsOrigin();
// float flDistance = vDelta.Length();
//
// float flMaxDrawDist = 1024;
// if ( flDistance <= flMaxDrawDist )
// {
// trace_t tr;
// //if ( pCSPlayer->IsAlive() && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec )
// {
// if ( TheCSBots()->IsLineBlockedBySmoke( pPlayer->EyePosition(), GetAbsOrigin(), 1.0f ) )
// {
// continue;
// }
//
// UTIL_TraceLine( pPlayer->EyePosition(), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr );
// if ( tr.fraction != 1 )
// {
// trace_t tr2;
// UTIL_TraceLine( pPlayer->GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr2 );
// if ( tr2.fraction != 1 )
// {
// continue;
// }
// }
//
// pPlayer->SetIsSpotted( true );
// pPlayer->SetIsSpottedBy( nThrowerIndex );
// }
// }
// }
// }
pEntity = gEntList.NextEnt( pEntity );
}*/
return true;
}
//==================================================
// - CanPlayerSeeTargetEntityFunctor -
//
// Determine if a player has spotted a target entity.
// Query IsSpotted() for result
//==================================================
class CanPlayerSeeTargetEntityFunctor
{
public:
CanPlayerSeeTargetEntityFunctor( CBaseEntity *entity, int spottingTeam )
{
m_targetEntity = entity;
m_target = entity->EyePosition();
m_team = spottingTeam;
m_spotted = false;
}
bool operator()( CBaseEntity *spotter )
{
CCSPlayer *csPlayer = ToCSPlayer( spotter );
if ( (csPlayer && csPlayer->IsAlive() == false ) || spotter->GetTeamNumber() != m_team )
return true;
CCSPlayer *csPlayerSpotter = NULL;
bool doTrace = false;
Vector eye, forward;
if ( csPlayer )
{
csPlayerSpotter = csPlayer;
if ( csPlayer->IsBlind() )
return true;
csPlayer->EyePositionAndVectors( &eye, &forward, NULL, NULL );
Vector path( m_target - eye );
float distance = path.Length();
path.NormalizeInPlace();
float dot = DotProduct( forward, path );
if ( dot < 0 )
return true;
int rvm = radarvis.GetInt();
switch ( rvm )
{
case 0:// original method
doTrace = ( ( dot > 0.995f )
|| ( dot > 0.98f && distance < 900 )
|| ( dot > 0.8f && distance < 250 )
);
break;
case 1: // new method method
{
int fov = csPlayer->GetFOVForNetworking() / 2;
float cosfov = cosf( ( float )fov*3.1415f / 180.0f );
float d = distance / radardist.GetFloat();
d = clamp( powf( d, radarpow.GetFloat() ), cosfov, radarmaxdot.GetFloat() );
doTrace = ( dot > d );
}
break;
}
}
else if ( dynamic_cast<CSensorGrenadeProjectile*>( spotter ) )
{
//CCSPlayer *csTargetPlayer = ToCSPlayer( m_targetEntity );
//if ( spotter->IsOtherEnemy( m_targetEntity ) )
{
eye = spotter->GetAbsOrigin();
csPlayerSpotter = ToCSPlayer( dynamic_cast<CSensorGrenadeProjectile*>( spotter )->GetThrower() );
doTrace = true;
/*
Vector vDelta = csTargetPlayer->EyePosition() - spotter->GetAbsOrigin();
float flDistance = vDelta.Length();
float flMaxDrawDist = 1024;
if ( flDistance <= flMaxDrawDist )
{
trace_t tr;
//if ( pCSPlayer->IsAlive() && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec )
{
if ( TheCSBots()->IsLineBlockedBySmoke( csTargetPlayer->EyePosition(), GetAbsOrigin(), 1.0f ) == false )
{
UTIL_TraceLine( csTargetPlayer->EyePosition(), GetAbsOrigin(), MASK_VISIBLE, csTargetPlayer, COLLISION_GROUP_DEBRIS, &tr );
trace_t tr2;
UTIL_TraceLine( csTargetPlayer->GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsOrigin(), MASK_VISIBLE, csTargetPlayer, COLLISION_GROUP_DEBRIS, &tr2 );
if ( tr1.fraction == 1 || tr2.fraction == 1 )
{
continue;
}
}
}
pPlayer->SetIsSpotted( true );
pPlayer->SetIsSpottedBy( nThrowerIndex );
}
}
*/
}
}
if (doTrace && csPlayerSpotter)
{
trace_t tr;
CTraceFilterSkipTwoEntities filter( spotter, m_targetEntity, COLLISION_GROUP_DEBRIS );
UTIL_TraceLine( eye, m_target,
(CONTENTS_OPAQUE|CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_DEBRIS|MASK_OPAQUE_AND_NPCS), &filter, &tr );
if ( tr.fraction == 1.0f && TheCSBots()->IsLineBlockedBySmoke( eye, m_target, 1.0f ) == false )
{
if ( !csPlayer || (csPlayer && csPlayer->GetFogObscuredRatio( m_targetEntity ) < 0.9) )
{
m_spotted = true;
m_spottedBy.AddToTail( csPlayerSpotter->entindex() );
//return false; // spotted already, so no reason to check for other players spotting the same thing.
}
}
}
return true;
}
bool IsSpotted( void ) const
{
return m_spotted;
}
int GetIsSpottedBy( int nUtlIndex ) const
{
if ( nUtlIndex < m_spottedBy.Count() )
return m_spottedBy[nUtlIndex];
return 0;
}
int GetSpottedByCount( void ) const
{
return m_spottedBy.Count();
}
private:
CBaseEntity *m_targetEntity;
Vector m_target;
int m_team;
bool m_spotted;
CUtlVector < int > m_spottedBy;
};
#define BIT_SET( a, b ) ((a)[(b)>>3] & (1<<((b)&7)))
extern bool WasPlayerOccluded( int fromplayer, int toplayer );
//===========================================================
// - GatherNonPVSSpottedEntitiesFunctor -
//
// Given a player, generate a list of spotted entities that
// exist outside of that player's PVS.
// Query GetSpotted for result
//===========================================================
GatherNonPVSSpottedEntitiesFunctor::GatherNonPVSSpottedEntitiesFunctor( CCSPlayer * pPlayer ) : m_pPlayer( pPlayer )
{
if ( pPlayer )
{
m_nSourceTeam = pPlayer->GetAssociatedTeamNumber();
engine->GetPVSForCluster( engine->GetClusterForOrigin( pPlayer->EyePosition() ), sizeof( m_pSourcePVS ), m_pSourcePVS );
// spectators and OBS_ALLOW_ALL observers receive updates on all spottable entities
if ( m_nSourceTeam == TEAM_SPECTATOR )
{
m_bForceSpot = true;
}
else if ( pPlayer->GetObserverMode() != OBS_MODE_NONE )
{
ConVarRef mp_forcecamera( "mp_forcecamera" );
m_bForceSpot = mp_forcecamera.GetInt() == OBS_ALLOW_ALL;
}
else
{
m_bForceSpot = false;
}
}
}
bool GatherNonPVSSpottedEntitiesFunctor::operator()( CBaseEntity * pEntity )
{
if ( !pEntity->edict() || !pEntity->CanBeSpotted() )
{
return true;
}
CBaseEntity *pParent = pEntity->GetRootMoveParent();
int iBitNumber = engine->GetClusterForOrigin( pParent->EyePosition() );
// We only care about entities who are not within this player's PVS
// We include being occluded as being outside of PVS.
if ( !BIT_SET( m_pSourcePVS, iBitNumber ) || ( m_pPlayer && pParent->entindex() <= MAX_PLAYERS && WasPlayerOccluded( pParent->entindex(), m_pPlayer->entindex() ) ) )
{
// target outside of PVS
int nSpotRules = pEntity->GetSpotRules();
bool bForceSpotted = false;
if ( ( nSpotRules & CCSEntitySpotting::SPOT_RULE_ALWAYS_SEEN_BY_FRIEND ) &&
( pEntity->GetTeamNumber() == m_nSourceTeam ) )
bForceSpotted = true;
if ( ( nSpotRules & CCSEntitySpotting::SPOT_RULE_ALWAYS_SEEN_BY_CT ) &&
( TEAM_CT == m_nSourceTeam ) )
bForceSpotted = true;
if ( ( nSpotRules & CCSEntitySpotting::SPOT_RULE_ALWAYS_SEEN_BY_T ) &&
( TEAM_TERRORIST == m_nSourceTeam ) )
bForceSpotted = true;
CBasePlayer * pPlayer = UTIL_PlayerByIndex( pEntity->entindex() );
if ( pPlayer )
{
// do not include dead players, observers, etc
if ( !pPlayer->IsAlive() || pPlayer->IsObserver() || !pPlayer->IsConnected() )
{
return true;
}
}
m_EntitySpotted.Set( pEntity->entindex(), ( m_bForceSpot || pEntity->IsSpotted() || bForceSpotted ) );
}
return true;
}
//--------------------------------------------------------------------------------------------------------
// Entity Spotting Game System
//--------------------------------------------------------------------------------------------------------
CCSEntitySpotting::CCSEntitySpotting( const char * szName ) : CAutoGameSystemPerFrame( szName ),
m_fLastUpdate( 0.0f )
{
}
void CCSEntitySpotting::FrameUpdatePostEntityThink( void )
{
if ( gpGlobals->curtime > ( m_fLastUpdate + ENTITY_SPOT_FREQUENCY ) )
{
UpdateSpottedEntities();
}
}
void CCSEntitySpotting::UpdateSpottedEntities( void )
{
m_fLastUpdate = gpGlobals->curtime;
CBaseEntity * pEntity = gEntList.FirstEnt();
while ( pEntity )
{
if ( pEntity->CanBeSpotted() )
{
int nTeamID = 0;
if ( pEntity->GetSpotRules() & SPOT_RULE_ENEMY )
{
nTeamID = (pEntity->GetTeamNumber( ) == TEAM_CT) ? TEAM_TERRORIST : TEAM_CT;
}
else if ( pEntity->GetSpotRules() & SPOT_RULE_CT )
{
nTeamID = TEAM_CT;
}
else if ( pEntity->GetSpotRules() & SPOT_RULE_T )
{
nTeamID = TEAM_TERRORIST;
}
CanPlayerSeeTargetEntityFunctor canPlayerSeeTargetEntity( pEntity, nTeamID );
ForEachEntitySpotter( canPlayerSeeTargetEntity );
pEntity->SetIsSpotted( canPlayerSeeTargetEntity.IsSpotted( ) );
pEntity->ClearSpottedBy();
if ( canPlayerSeeTargetEntity.IsSpotted() )
{
for ( int i = 0; i < canPlayerSeeTargetEntity.GetSpottedByCount(); i++ )
{
pEntity->SetIsSpottedBy( canPlayerSeeTargetEntity.GetIsSpottedBy( i ) );
}
}
}
pEntity = gEntList.NextEnt( pEntity );
}
}
bool CCSEntitySpotting::Init( void )
{
return true;
}