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

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A game system for tracking and updating entity spot state
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "cs_entity_spotting.h"
  9. #include "cs_player.h"
  10. #include "cs_bot.h"
  11. #include "sensorgrenade_projectile.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. #define ENTITY_SPOT_FREQUENCY 0.5f
  15. static CCSEntitySpotting s_EntitySpotting("CCSEntitySpotting");
  16. CCSEntitySpotting * g_EntitySpotting = &s_EntitySpotting;
  17. ConVar radarvis( "radarvismethod", "1", FCVAR_CHEAT, "0 for traditional method, 1 for more realistic method", true, 0, true, 1 );
  18. ConVar radarpow( "radarvispow", ".4", FCVAR_CHEAT, "the degree to which you can point away from a target, and still see them on radar." );
  19. 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 );
  20. 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 );
  21. //--------------------------------------------------------------------------------------------------------
  22. // Functors
  23. //--------------------------------------------------------------------------------------------------------
  24. template < typename SpotFunctor >
  25. bool ForEachEntitySpotter( SpotFunctor &func )
  26. {
  27. VPROF( "ForEachEntitySpotter" );
  28. for ( int i = 1; i <= gpGlobals->maxClients; ++i )
  29. {
  30. CBasePlayer *player = static_cast< CBasePlayer * >( UTIL_PlayerByIndex( i ) );
  31. if ( player == NULL )
  32. continue;
  33. if ( FNullEnt( player->edict() ) )
  34. continue;
  35. if ( !player->IsPlayer() )
  36. continue;
  37. if ( !player->IsConnected() )
  38. continue;
  39. if ( func( player ) == false )
  40. return false;
  41. }
  42. //ActiveGrenadeList activeGrenadeList = TheBots->m_activeGrenadeList;
  43. FOR_EACH_LL( TheCSBots()->m_activeGrenadeList, it )
  44. {
  45. ActiveGrenade *ag = TheCSBots()->m_activeGrenadeList[it];
  46. if ( ag->IsSensor() == false )
  47. continue;
  48. CBaseGrenade *grenade = ag->GetEntity();
  49. if ( grenade == NULL )
  50. continue;
  51. if ( FNullEnt( grenade->edict() ) )
  52. continue;
  53. if ( func( grenade ) == false )
  54. return false;
  55. }
  56. /*
  57. CBaseEntity * pEntity = gEntList.FirstEnt();
  58. while ( pEntity )
  59. {
  60. if ( pEntity == NULL || FNullEnt( pEntity->edict() ) )
  61. {
  62. pEntity = gEntList.NextEnt( pEntity );
  63. continue;
  64. }
  65. if ( FNullEnt( pEntity->edict() ) )
  66. {
  67. pEntity = gEntList.NextEnt( pEntity );
  68. continue;
  69. }
  70. if ( pEntity->IsPlayer() )
  71. {
  72. CBasePlayer *player = static_cast< CBasePlayer * >( pEntity );
  73. if ( !player->IsConnected() )
  74. {
  75. pEntity = gEntList.NextEnt( pEntity );
  76. continue;
  77. }
  78. }
  79. if ( func( pEntity ) == false )
  80. return false;
  81. // else if ( dynamic_cast<CSensorGrenadeProjectile*>( pEntity ) )
  82. // {
  83. // if ( pThrower->IsOtherEnemy( pPlayer ) )
  84. // {
  85. // Vector vDelta = pPlayer->EyePosition() - GetAbsOrigin();
  86. // float flDistance = vDelta.Length();
  87. //
  88. // float flMaxDrawDist = 1024;
  89. // if ( flDistance <= flMaxDrawDist )
  90. // {
  91. // trace_t tr;
  92. // //if ( pCSPlayer->IsAlive() && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec )
  93. // {
  94. // if ( TheCSBots()->IsLineBlockedBySmoke( pPlayer->EyePosition(), GetAbsOrigin(), 1.0f ) )
  95. // {
  96. // continue;
  97. // }
  98. //
  99. // UTIL_TraceLine( pPlayer->EyePosition(), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr );
  100. // if ( tr.fraction != 1 )
  101. // {
  102. // trace_t tr2;
  103. // UTIL_TraceLine( pPlayer->GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsOrigin(), MASK_VISIBLE, pPlayer, COLLISION_GROUP_DEBRIS, &tr2 );
  104. // if ( tr2.fraction != 1 )
  105. // {
  106. // continue;
  107. // }
  108. // }
  109. //
  110. // pPlayer->SetIsSpotted( true );
  111. // pPlayer->SetIsSpottedBy( nThrowerIndex );
  112. // }
  113. // }
  114. // }
  115. // }
  116. pEntity = gEntList.NextEnt( pEntity );
  117. }*/
  118. return true;
  119. }
  120. //==================================================
  121. // - CanPlayerSeeTargetEntityFunctor -
  122. //
  123. // Determine if a player has spotted a target entity.
  124. // Query IsSpotted() for result
  125. //==================================================
  126. class CanPlayerSeeTargetEntityFunctor
  127. {
  128. public:
  129. CanPlayerSeeTargetEntityFunctor( CBaseEntity *entity, int spottingTeam )
  130. {
  131. m_targetEntity = entity;
  132. m_target = entity->EyePosition();
  133. m_team = spottingTeam;
  134. m_spotted = false;
  135. }
  136. bool operator()( CBaseEntity *spotter )
  137. {
  138. CCSPlayer *csPlayer = ToCSPlayer( spotter );
  139. if ( (csPlayer && csPlayer->IsAlive() == false ) || spotter->GetTeamNumber() != m_team )
  140. return true;
  141. CCSPlayer *csPlayerSpotter = NULL;
  142. bool doTrace = false;
  143. Vector eye, forward;
  144. if ( csPlayer )
  145. {
  146. csPlayerSpotter = csPlayer;
  147. if ( csPlayer->IsBlind() )
  148. return true;
  149. csPlayer->EyePositionAndVectors( &eye, &forward, NULL, NULL );
  150. Vector path( m_target - eye );
  151. float distance = path.Length();
  152. path.NormalizeInPlace();
  153. float dot = DotProduct( forward, path );
  154. if ( dot < 0 )
  155. return true;
  156. int rvm = radarvis.GetInt();
  157. switch ( rvm )
  158. {
  159. case 0:// original method
  160. doTrace = ( ( dot > 0.995f )
  161. || ( dot > 0.98f && distance < 900 )
  162. || ( dot > 0.8f && distance < 250 )
  163. );
  164. break;
  165. case 1: // new method method
  166. {
  167. int fov = csPlayer->GetFOVForNetworking() / 2;
  168. float cosfov = cosf( ( float )fov*3.1415f / 180.0f );
  169. float d = distance / radardist.GetFloat();
  170. d = clamp( powf( d, radarpow.GetFloat() ), cosfov, radarmaxdot.GetFloat() );
  171. doTrace = ( dot > d );
  172. }
  173. break;
  174. }
  175. }
  176. else if ( dynamic_cast<CSensorGrenadeProjectile*>( spotter ) )
  177. {
  178. //CCSPlayer *csTargetPlayer = ToCSPlayer( m_targetEntity );
  179. //if ( spotter->IsOtherEnemy( m_targetEntity ) )
  180. {
  181. eye = spotter->GetAbsOrigin();
  182. csPlayerSpotter = ToCSPlayer( dynamic_cast<CSensorGrenadeProjectile*>( spotter )->GetThrower() );
  183. doTrace = true;
  184. /*
  185. Vector vDelta = csTargetPlayer->EyePosition() - spotter->GetAbsOrigin();
  186. float flDistance = vDelta.Length();
  187. float flMaxDrawDist = 1024;
  188. if ( flDistance <= flMaxDrawDist )
  189. {
  190. trace_t tr;
  191. //if ( pCSPlayer->IsAlive() && ( flTargetIDCone > flViewCone ) && !bShowAllNamesForSpec )
  192. {
  193. if ( TheCSBots()->IsLineBlockedBySmoke( csTargetPlayer->EyePosition(), GetAbsOrigin(), 1.0f ) == false )
  194. {
  195. UTIL_TraceLine( csTargetPlayer->EyePosition(), GetAbsOrigin(), MASK_VISIBLE, csTargetPlayer, COLLISION_GROUP_DEBRIS, &tr );
  196. trace_t tr2;
  197. UTIL_TraceLine( csTargetPlayer->GetAbsOrigin() + Vector( 0, 0, 16 ), GetAbsOrigin(), MASK_VISIBLE, csTargetPlayer, COLLISION_GROUP_DEBRIS, &tr2 );
  198. if ( tr1.fraction == 1 || tr2.fraction == 1 )
  199. {
  200. continue;
  201. }
  202. }
  203. }
  204. pPlayer->SetIsSpotted( true );
  205. pPlayer->SetIsSpottedBy( nThrowerIndex );
  206. }
  207. }
  208. */
  209. }
  210. }
  211. if (doTrace && csPlayerSpotter)
  212. {
  213. trace_t tr;
  214. CTraceFilterSkipTwoEntities filter( spotter, m_targetEntity, COLLISION_GROUP_DEBRIS );
  215. UTIL_TraceLine( eye, m_target,
  216. (CONTENTS_OPAQUE|CONTENTS_SOLID|CONTENTS_MOVEABLE|CONTENTS_DEBRIS|MASK_OPAQUE_AND_NPCS), &filter, &tr );
  217. if ( tr.fraction == 1.0f && TheCSBots()->IsLineBlockedBySmoke( eye, m_target, 1.0f ) == false )
  218. {
  219. if ( !csPlayer || (csPlayer && csPlayer->GetFogObscuredRatio( m_targetEntity ) < 0.9) )
  220. {
  221. m_spotted = true;
  222. m_spottedBy.AddToTail( csPlayerSpotter->entindex() );
  223. //return false; // spotted already, so no reason to check for other players spotting the same thing.
  224. }
  225. }
  226. }
  227. return true;
  228. }
  229. bool IsSpotted( void ) const
  230. {
  231. return m_spotted;
  232. }
  233. int GetIsSpottedBy( int nUtlIndex ) const
  234. {
  235. if ( nUtlIndex < m_spottedBy.Count() )
  236. return m_spottedBy[nUtlIndex];
  237. return 0;
  238. }
  239. int GetSpottedByCount( void ) const
  240. {
  241. return m_spottedBy.Count();
  242. }
  243. private:
  244. CBaseEntity *m_targetEntity;
  245. Vector m_target;
  246. int m_team;
  247. bool m_spotted;
  248. CUtlVector < int > m_spottedBy;
  249. };
  250. #define BIT_SET( a, b ) ((a)[(b)>>3] & (1<<((b)&7)))
  251. extern bool WasPlayerOccluded( int fromplayer, int toplayer );
  252. //===========================================================
  253. // - GatherNonPVSSpottedEntitiesFunctor -
  254. //
  255. // Given a player, generate a list of spotted entities that
  256. // exist outside of that player's PVS.
  257. // Query GetSpotted for result
  258. //===========================================================
  259. GatherNonPVSSpottedEntitiesFunctor::GatherNonPVSSpottedEntitiesFunctor( CCSPlayer * pPlayer ) : m_pPlayer( pPlayer )
  260. {
  261. if ( pPlayer )
  262. {
  263. m_nSourceTeam = pPlayer->GetAssociatedTeamNumber();
  264. engine->GetPVSForCluster( engine->GetClusterForOrigin( pPlayer->EyePosition() ), sizeof( m_pSourcePVS ), m_pSourcePVS );
  265. // spectators and OBS_ALLOW_ALL observers receive updates on all spottable entities
  266. if ( m_nSourceTeam == TEAM_SPECTATOR )
  267. {
  268. m_bForceSpot = true;
  269. }
  270. else if ( pPlayer->GetObserverMode() != OBS_MODE_NONE )
  271. {
  272. ConVarRef mp_forcecamera( "mp_forcecamera" );
  273. m_bForceSpot = mp_forcecamera.GetInt() == OBS_ALLOW_ALL;
  274. }
  275. else
  276. {
  277. m_bForceSpot = false;
  278. }
  279. }
  280. }
  281. bool GatherNonPVSSpottedEntitiesFunctor::operator()( CBaseEntity * pEntity )
  282. {
  283. if ( !pEntity->edict() || !pEntity->CanBeSpotted() )
  284. {
  285. return true;
  286. }
  287. CBaseEntity *pParent = pEntity->GetRootMoveParent();
  288. int iBitNumber = engine->GetClusterForOrigin( pParent->EyePosition() );
  289. // We only care about entities who are not within this player's PVS
  290. // We include being occluded as being outside of PVS.
  291. if ( !BIT_SET( m_pSourcePVS, iBitNumber ) || ( m_pPlayer && pParent->entindex() <= MAX_PLAYERS && WasPlayerOccluded( pParent->entindex(), m_pPlayer->entindex() ) ) )
  292. {
  293. // target outside of PVS
  294. int nSpotRules = pEntity->GetSpotRules();
  295. bool bForceSpotted = false;
  296. if ( ( nSpotRules & CCSEntitySpotting::SPOT_RULE_ALWAYS_SEEN_BY_FRIEND ) &&
  297. ( pEntity->GetTeamNumber() == m_nSourceTeam ) )
  298. bForceSpotted = true;
  299. if ( ( nSpotRules & CCSEntitySpotting::SPOT_RULE_ALWAYS_SEEN_BY_CT ) &&
  300. ( TEAM_CT == m_nSourceTeam ) )
  301. bForceSpotted = true;
  302. if ( ( nSpotRules & CCSEntitySpotting::SPOT_RULE_ALWAYS_SEEN_BY_T ) &&
  303. ( TEAM_TERRORIST == m_nSourceTeam ) )
  304. bForceSpotted = true;
  305. CBasePlayer * pPlayer = UTIL_PlayerByIndex( pEntity->entindex() );
  306. if ( pPlayer )
  307. {
  308. // do not include dead players, observers, etc
  309. if ( !pPlayer->IsAlive() || pPlayer->IsObserver() || !pPlayer->IsConnected() )
  310. {
  311. return true;
  312. }
  313. }
  314. m_EntitySpotted.Set( pEntity->entindex(), ( m_bForceSpot || pEntity->IsSpotted() || bForceSpotted ) );
  315. }
  316. return true;
  317. }
  318. //--------------------------------------------------------------------------------------------------------
  319. // Entity Spotting Game System
  320. //--------------------------------------------------------------------------------------------------------
  321. CCSEntitySpotting::CCSEntitySpotting( const char * szName ) : CAutoGameSystemPerFrame( szName ),
  322. m_fLastUpdate( 0.0f )
  323. {
  324. }
  325. void CCSEntitySpotting::FrameUpdatePostEntityThink( void )
  326. {
  327. if ( gpGlobals->curtime > ( m_fLastUpdate + ENTITY_SPOT_FREQUENCY ) )
  328. {
  329. UpdateSpottedEntities();
  330. }
  331. }
  332. void CCSEntitySpotting::UpdateSpottedEntities( void )
  333. {
  334. m_fLastUpdate = gpGlobals->curtime;
  335. CBaseEntity * pEntity = gEntList.FirstEnt();
  336. while ( pEntity )
  337. {
  338. if ( pEntity->CanBeSpotted() )
  339. {
  340. int nTeamID = 0;
  341. if ( pEntity->GetSpotRules() & SPOT_RULE_ENEMY )
  342. {
  343. nTeamID = (pEntity->GetTeamNumber( ) == TEAM_CT) ? TEAM_TERRORIST : TEAM_CT;
  344. }
  345. else if ( pEntity->GetSpotRules() & SPOT_RULE_CT )
  346. {
  347. nTeamID = TEAM_CT;
  348. }
  349. else if ( pEntity->GetSpotRules() & SPOT_RULE_T )
  350. {
  351. nTeamID = TEAM_TERRORIST;
  352. }
  353. CanPlayerSeeTargetEntityFunctor canPlayerSeeTargetEntity( pEntity, nTeamID );
  354. ForEachEntitySpotter( canPlayerSeeTargetEntity );
  355. pEntity->SetIsSpotted( canPlayerSeeTargetEntity.IsSpotted( ) );
  356. pEntity->ClearSpottedBy();
  357. if ( canPlayerSeeTargetEntity.IsSpotted() )
  358. {
  359. for ( int i = 0; i < canPlayerSeeTargetEntity.GetSpottedByCount(); i++ )
  360. {
  361. pEntity->SetIsSpottedBy( canPlayerSeeTargetEntity.GetIsSpottedBy( i ) );
  362. }
  363. }
  364. }
  365. pEntity = gEntList.NextEnt( pEntity );
  366. }
  367. }
  368. bool CCSEntitySpotting::Init( void )
  369. {
  370. return true;
  371. }