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.

347 lines
8.8 KiB

  1. //========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "item_sonarpulse.h"
  8. #ifdef CLIENT_DLL
  9. #include "view.h"
  10. #include "materialsystem/imaterialvar.h"
  11. #endif
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include "tier0/memdbgon.h"
  14. #define SONARPULSE_MODEL "models/props/props_br/br_sonar/br_sonar.mdl"
  15. #define SONARPULSE_SPEED 270 // in units/sec
  16. #define SONARPULSE_PRICE 1000 // in american dollars
  17. #ifdef CLIENT_DLL
  18. CUtlVector<CSonarPulse*> g_SonarPulsers;
  19. CUtlVector<sonarpulseicon_t> g_SonarPulseIcons;
  20. #endif
  21. #if defined( CLIENT_DLL )
  22. #else
  23. BEGIN_DATADESC( CSonarPulse )
  24. END_DATADESC()
  25. #endif
  26. BEGIN_PREDICTION_DATA( CSonarPulse )
  27. END_PREDICTION_DATA()
  28. IMPLEMENT_NETWORKCLASS_ALIASED( SonarPulse, DT_SonarPulse )
  29. BEGIN_NETWORK_TABLE( CSonarPulse, DT_SonarPulse )
  30. #ifdef CLIENT_DLL
  31. RecvPropBool( RECVINFO(m_bPulseInProgress) ),
  32. RecvPropFloat( RECVINFO(m_flPulseInitTime) )
  33. #else
  34. SendPropBool( SENDINFO(m_bPulseInProgress) ),
  35. SendPropFloat( SENDINFO(m_flPulseInitTime) )
  36. #endif
  37. END_NETWORK_TABLE()
  38. LINK_ENTITY_TO_CLASS_ALIASED( item_sonarpulse, SonarPulse );
  39. PRECACHE_REGISTER( item_sonarpulse );
  40. CSonarPulse::CSonarPulse()
  41. {
  42. #ifndef CLIENT_DLL
  43. m_bPulseInProgress = false;
  44. m_flPulseInitTime = 0;
  45. m_vecPlayersOutsidePulse.RemoveAll();
  46. m_vecPingedPlayers.RemoveAll();
  47. m_flPlaybackRate = 0;
  48. #else
  49. ListenForGameEvent( "add_player_sonar_icon" );
  50. g_SonarPulsers.FindAndFastRemove( this );
  51. g_SonarPulsers.AddToTail( this );
  52. m_pIconMaterial = NULL;
  53. g_SonarPulseIcons.RemoveAll();
  54. #endif
  55. }
  56. CSonarPulse::~CSonarPulse()
  57. {
  58. #ifdef CLIENT_DLL
  59. g_SonarPulsers.FindAndFastRemove( this );
  60. #endif
  61. }
  62. void CSonarPulse::Spawn( void )
  63. {
  64. BaseClass::Spawn();
  65. SetMoveType( MOVETYPE_NONE );
  66. SetSolid( SOLID_VPHYSICS );
  67. SetModel( SONARPULSE_MODEL );
  68. #ifdef CLIENT_DLL
  69. m_pIconMaterial = materials->FindMaterial( "dev/sonar_icon.vmt", TEXTURE_GROUP_OTHER, false );
  70. SetThink( &CSonarPulse::ClientThink );
  71. SetNextClientThink( CLIENT_THINK_ALWAYS );
  72. #else
  73. SetPlaybackRate( 0 );
  74. #endif
  75. }
  76. void CSonarPulse::Precache()
  77. {
  78. PrecacheModel( SONARPULSE_MODEL );
  79. PrecacheSound( "ambient/atmosphere/cs_metalscrapeverb10.wav" );
  80. }
  81. float CSonarPulse::GetPulseRadius( void )
  82. {
  83. if ( !m_bPulseInProgress )
  84. return 0;
  85. float flCurrentDuration = gpGlobals->curtime - m_flPulseInitTime;
  86. return flCurrentDuration * SONARPULSE_SPEED;
  87. }
  88. Vector CSonarPulse::GetPulseOrigin( void )
  89. {
  90. return GetAbsOrigin();
  91. }
  92. #ifdef CLIENT_DLL
  93. void CSonarPulse::ClientThink( void )
  94. {
  95. StudioFrameAdvance();
  96. SetNextClientThink( CLIENT_THINK_ALWAYS );
  97. }
  98. void CSonarPulse::RenderIcons( void )
  99. {
  100. if( !g_SonarPulseIcons.Count() || m_pIconMaterial == NULL )
  101. return;
  102. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  103. if ( !pLocalPlayer )
  104. return;
  105. Vector vecEyePos = MainViewOrigin(GET_ACTIVE_SPLITSCREEN_SLOT());
  106. CMatRenderContextPtr pRenderContext(materials);
  107. FOR_EACH_VEC_BACK( g_SonarPulseIcons, n )
  108. {
  109. float flLifeTimeRemaining = g_SonarPulseIcons[n].GetLifeRemaining();
  110. if ( flLifeTimeRemaining > 0 )
  111. {
  112. Vector vecIconPos = g_SonarPulseIcons[n].m_vecPos;
  113. Vector vecOrigin;
  114. ScreenTransform( vecIconPos, vecOrigin );
  115. float flSize = RemapValClamped( flLifeTimeRemaining, 10, 9, 1, 32 );
  116. float flEdgeAlpha = 1.0f;
  117. float flTheta = 0.95f;
  118. if ( vecOrigin.Length() > flTheta )
  119. {
  120. vecOrigin = vecOrigin.Normalized() * flTheta;
  121. flSize = MIN( flSize, 24 );
  122. flEdgeAlpha = 0.7f;
  123. }
  124. ConvertNormalizedScreenSpaceToPixelScreenSpace( vecOrigin );
  125. //scale size by distance a bit, as per Brian's request.
  126. flSize *= RemapValClamped( vecEyePos.DistToSqr( vecIconPos ), 1600*1600, 500*500, 0.5f, 1.0f );
  127. vecOrigin.x -= flSize * 0.5f;
  128. vecOrigin.y -= flSize * 0.5f;
  129. IMaterialVar* pVar = m_pIconMaterial->FindVar( "$alpha", NULL );
  130. if ( pVar )
  131. {
  132. pVar->SetFloatValue( flEdgeAlpha * clamp( flLifeTimeRemaining * 0.5f, 0, 1 ) );
  133. }
  134. pRenderContext->DrawScreenSpaceRectangle( m_pIconMaterial,
  135. vecOrigin.x, vecOrigin.y,
  136. flSize, flSize,
  137. 0, 0, 32, 32, 32, 32 );
  138. }
  139. else
  140. {
  141. g_SonarPulseIcons.FastRemove( n );
  142. }
  143. }
  144. }
  145. void CSonarPulse::FireGameEvent( IGameEvent *event )
  146. {
  147. if ( Q_strcmp( event->GetName(), "add_player_sonar_icon" ) == 0 )
  148. {
  149. // don't make an icon for the local player - it's confusing
  150. int nUserID = event->GetInt( "userid", -1 );
  151. C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
  152. if ( pLocalPlayer && pLocalPlayer->GetUserID() == nUserID )
  153. return;
  154. Vector vecPos = Vector( event->GetFloat("pos_x",0), event->GetFloat("pos_y",0), event->GetFloat("pos_z",0) );
  155. sonarpulseicon_t newIcon( vecPos );
  156. g_SonarPulseIcons.AddToTail( newIcon );
  157. //CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByUserId( nUserID ) );
  158. //ConColorMsg( Color(0,255,255,255), "RECEIVE: sonar icon added at [%f, %f, %f] for player: %s\n", vecPos.x, vecPos.y, vecPos.z, pPlayer ? pPlayer->GetPlayerName() : "null" );
  159. }
  160. }
  161. #endif
  162. #ifndef CLIENT_DLL
  163. void CSonarPulse::PulseStart( void )
  164. {
  165. EmitSound( "ambient/atmosphere/cs_metalscrapeverb10.wav" );
  166. m_vecPlayersOutsidePulse.RemoveAll();
  167. m_vecPingedPlayers.RemoveAll();
  168. m_bPulseInProgress = true;
  169. m_flPulseInitTime = gpGlobals->curtime;
  170. SetPlaybackRate( 1 );
  171. SetThink( &CSonarPulse::PulseThink );
  172. SetNextThink( gpGlobals->curtime );
  173. }
  174. void CSonarPulse::PulseReset( void )
  175. {
  176. SetThink( NULL );
  177. SetPlaybackRate( 0 );
  178. m_bPulseInProgress = false;
  179. m_flPulseInitTime = 0;
  180. m_vecPlayersOutsidePulse.RemoveAll();
  181. m_vecPingedPlayers.RemoveAll();
  182. m_flPlaybackRate = 0;
  183. }
  184. bool CSonarPulse::IsOkToPulse( CCSPlayer* pPlayer )
  185. {
  186. return ( pPlayer && pPlayer->IsAlive() && !pPlayer->IsChickenClass() && !pPlayer->IsFlyingDroneClass() && !pPlayer->m_bIsParachuting );
  187. }
  188. void CSonarPulse::PulseThink( void )
  189. {
  190. if ( !m_bPulseInProgress )
  191. {
  192. PulseReset();
  193. return;
  194. }
  195. float flRadius = GetPulseRadius();
  196. Vector vecPulseCenter = GetPulseOrigin();
  197. float flRadSqrCurrent = flRadius * flRadius;
  198. // ping the players that were outside the pulse last think and are now inside
  199. FOR_EACH_VEC_BACK( m_vecPlayersOutsidePulse, n )
  200. {
  201. CCSPlayer *pPlayer = ToCSPlayer( m_vecPlayersOutsidePulse[n] );
  202. if ( IsOkToPulse( pPlayer ) )
  203. {
  204. Vector vecPlayerPos = pPlayer->GetAbsOrigin() + Vector(0,0,40);
  205. float flPlayerDist = vecPlayerPos.DistToSqr( vecPulseCenter );
  206. if ( flPlayerDist < flRadSqrCurrent && !m_vecPingedPlayers.HasElement( pPlayer ) )
  207. {
  208. // The pulse crossed this player - ping them!
  209. pPlayer->EmitSound( "Bot.StuckSound" );
  210. IGameEvent * sonar_ping_event = gameeventmanager->CreateEvent( "add_player_sonar_icon" );
  211. if ( sonar_ping_event )
  212. {
  213. sonar_ping_event->SetInt( "userid", pPlayer->GetUserID() );
  214. sonar_ping_event->SetFloat( "pos_x", vecPlayerPos.x );
  215. sonar_ping_event->SetFloat( "pos_y", vecPlayerPos.y );
  216. sonar_ping_event->SetFloat( "pos_z", vecPlayerPos.z );
  217. gameeventmanager->FireEvent( sonar_ping_event );
  218. }
  219. m_vecPlayersOutsidePulse.FindAndRemove( pPlayer );
  220. m_vecPingedPlayers.AddToTail( pPlayer );
  221. //ConColorMsg( Color(0,255,0,255), "SEND: sonar icon added at [%f, %f, %f] for player: %s\n", vecPlayerPos.x, vecPlayerPos.y, vecPlayerPos.z, pPlayer->GetPlayerName() );
  222. }
  223. }
  224. else
  225. {
  226. // player is invalid for some reason, might have left, been killed, etc
  227. m_vecPlayersOutsidePulse.FindAndRemove( pPlayer );
  228. }
  229. }
  230. // re-gather players to add to the list that are outside the pulse
  231. for ( int i = 1; i <= MAX_PLAYERS; i++ )
  232. {
  233. CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
  234. if ( IsOkToPulse( pPlayer ) )
  235. {
  236. Vector vecPlayerPos = pPlayer->GetAbsOrigin() + Vector(0,0,40);
  237. float flPlayerDist = vecPlayerPos.DistToSqr( vecPulseCenter );
  238. if ( flPlayerDist > flRadSqrCurrent && !m_vecPlayersOutsidePulse.HasElement(pPlayer) )
  239. {
  240. m_vecPlayersOutsidePulse.AddToTail( pPlayer );
  241. }
  242. }
  243. }
  244. if ( m_vecPlayersOutsidePulse.Count() == 0 )
  245. {
  246. PulseReset();
  247. return;
  248. }
  249. SetNextThink( gpGlobals->curtime + 0.1f );
  250. }
  251. void CSonarPulse::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
  252. {
  253. CCSPlayer *pPlayer = dynamic_cast< CCSPlayer* >( pActivator );
  254. if ( !pPlayer )
  255. return;
  256. int nCost = SONARPULSE_PRICE;
  257. if ( m_bPulseInProgress || pPlayer->GetAccountBalance() < nCost )
  258. {
  259. // we dont have enough money
  260. // play an error sound
  261. Vector soundPosition = GetAbsOrigin() + Vector( 0, 0, 32 );
  262. CPASAttenuationFilter filter( soundPosition );
  263. EmitSound( filter, 0, "Vote.Failed", &GetAbsOrigin() );
  264. return;
  265. }
  266. // deduct the amount
  267. pPlayer->AddAccount( -nCost, false, true, "" );
  268. m_bPulseInProgress = true;
  269. SetThink( &CSonarPulse::PulseStart );
  270. SetNextThink( gpGlobals->curtime + 1 );
  271. EmitSound( "UI.Guardian.TooFarWarning" );
  272. }
  273. #endif // #ifndef CLIENT_DLL