Team Fortress 2 Source Code as on 22/4/2020
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.

629 lines
19 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "c_func_passtime_goal.h"
  9. #include "c_tf_passtime_logic.h"
  10. #include "tf_hud_passtime_reticle.h"
  11. #include "passtime_convars.h"
  12. #include "tf_weapon_passtime_gun.h"
  13. #include "c_tf_player.h"
  14. #include "view.h"
  15. #include "c_tf_playerresource.h"
  16. // memdbgon must be the last include file in a .cpp file!!!
  17. #include "tier0/memdbgon.h"
  18. // The team colors from g_PR are wrong and I couldn't fix that fast enough.
  19. // These colors were sampled from HUD art.
  20. static Color GetTeamColor( int iTeam )
  21. {
  22. switch( iTeam )
  23. {
  24. case TF_TEAM_RED: return Color(0xFF, 0x51, 0x51);
  25. case TF_TEAM_BLUE: return Color(0xA5, 0xDE, 0xFF);
  26. default: return Color(0xF5, 0xE7, 0xDE);
  27. };
  28. }
  29. //-----------------------------------------------------------------------------
  30. // C_PasstimeReticle
  31. //-----------------------------------------------------------------------------
  32. //-----------------------------------------------------------------------------
  33. C_PasstimeReticle::~C_PasstimeReticle()
  34. {
  35. for( int i = 0; i < m_pSprites.Count(); ++i )
  36. {
  37. clienteffects->RemoveEffect( m_pSprites[i] );
  38. }
  39. }
  40. //-----------------------------------------------------------------------------
  41. void C_PasstimeReticle::OnClientThink()
  42. {
  43. if ( !Update() )
  44. {
  45. SetAllAlphas( 0 );
  46. }
  47. }
  48. //-----------------------------------------------------------------------------
  49. void C_PasstimeReticle::AddSprite( CFXQuad *pQuad )
  50. {
  51. Assert( pQuad );
  52. m_pSprites.AddToTail( pQuad );
  53. }
  54. //-----------------------------------------------------------------------------
  55. void C_PasstimeReticle::SetAllOrigins( const Vector &vec )
  56. {
  57. for ( int i = 0; i < m_pSprites.Count(); ++i )
  58. {
  59. m_pSprites[i]->m_FXData.SetOrigin( vec );
  60. }
  61. }
  62. //-----------------------------------------------------------------------------
  63. void C_PasstimeReticle::SetAllNormals( const Vector &vec )
  64. {
  65. for ( int i = 0; i < m_pSprites.Count(); ++i )
  66. {
  67. m_pSprites[i]->m_FXData.SetNormal( vec );
  68. }
  69. }
  70. //-----------------------------------------------------------------------------
  71. void C_PasstimeReticle::SetAllAlphas( byte iA )
  72. {
  73. auto flA = iA / 255.0f;
  74. for ( int i = 0; i < m_pSprites.Count(); ++i )
  75. {
  76. m_pSprites[i]->m_FXData.SetAlpha( flA, flA );
  77. }
  78. }
  79. //-----------------------------------------------------------------------------
  80. void C_PasstimeReticle::SetAllScales( float flScale )
  81. {
  82. for ( int i = 0; i < m_pSprites.Count(); ++i )
  83. {
  84. m_pSprites[i]->m_FXData.SetScale( flScale, flScale );
  85. }
  86. }
  87. //-----------------------------------------------------------------------------
  88. void C_PasstimeReticle::SetOrigin( int i, const Vector &vec )
  89. {
  90. m_pSprites[i]->m_FXData.SetOrigin( vec );
  91. }
  92. //-----------------------------------------------------------------------------
  93. void C_PasstimeReticle::SetNormal( int i, const Vector &normal )
  94. {
  95. m_pSprites[i]->m_FXData.SetNormal( normal );
  96. }
  97. //-----------------------------------------------------------------------------
  98. void C_PasstimeReticle::SetAlpha( int i, byte iA )
  99. {
  100. auto flA = iA / 255.0f;
  101. m_pSprites[i]->m_FXData.SetAlpha( flA, flA );
  102. }
  103. //-----------------------------------------------------------------------------
  104. void C_PasstimeReticle::SetRgba( int i, byte iR, byte iG, byte iB, byte iA )
  105. {
  106. m_pSprites[i]->m_FXData.SetColor( iR / 255.0f, iG / 255.0f, iB / 255.0f );
  107. auto flA = iA / 255.0;
  108. m_pSprites[i]->m_FXData.SetAlpha( flA, flA );
  109. }
  110. //-----------------------------------------------------------------------------
  111. void C_PasstimeReticle::SetScale( int i, float flScale )
  112. {
  113. m_pSprites[i]->m_FXData.SetScale( flScale, flScale );
  114. }
  115. //-----------------------------------------------------------------------------
  116. // C_PasstimeBallReticle
  117. //-----------------------------------------------------------------------------
  118. //-----------------------------------------------------------------------------
  119. static const float k_flBallReticleSize = 64;
  120. C_PasstimeBallReticle::C_PasstimeBallReticle()
  121. {
  122. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_piece_1", k_flBallReticleSize, 360 ) ); // the O
  123. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_piece_2", k_flBallReticleSize, 360 ) ); // the ><
  124. }
  125. //-----------------------------------------------------------------------------
  126. bool C_PasstimeBallReticle::Update()
  127. {
  128. if ( !g_pPasstimeLogic || !g_pPasstimeLogic->GetBall() )
  129. {
  130. return false;
  131. }
  132. auto *pBall = g_pPasstimeLogic->GetBall();
  133. auto *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  134. C_BaseEntity *pTarget = 0;
  135. auto bHomingActive = false;
  136. auto bHaveTarget = g_pPasstimeLogic->GetBallReticleTarget( &pTarget, &bHomingActive );
  137. if ( !pBall || !pLocalPlayer || !bHaveTarget )
  138. {
  139. return false;
  140. }
  141. auto vecTargetPos = pTarget->WorldSpaceCenter();
  142. SetAllOrigins( vecTargetPos );
  143. SetAllNormals( -MainViewForward() );
  144. auto teamColor = GetTeamColor( pTarget->GetTeamNumber() );
  145. auto iAlpha = ( bHomingActive || pLocalPlayer->m_Shared.IsTargetedForPasstimePass() )
  146. ? (int)( (fmodf( gpGlobals->curtime * 3.0f, 1.0f )) * 255 )
  147. : 180;
  148. SetRgba( 0, teamColor.r(), teamColor.g(), teamColor.b(), iAlpha );
  149. SetRgba( 1, teamColor.r(), teamColor.g(), teamColor.b(), iAlpha );
  150. auto flDist = (vecTargetPos - MainViewOrigin()).Length();
  151. auto flScale = RemapValClamped( flDist, 768.0f, 4096.0f, 1.0f, 3.0f );
  152. flScale *= k_flBallReticleSize;
  153. if ( bHomingActive || pLocalPlayer->m_Shared.IsTargetedForPasstimePass() )
  154. {
  155. flScale *= 2;
  156. }
  157. SetScale( 0, flScale );
  158. SetScale( 1, flScale );
  159. return true;
  160. }
  161. //-----------------------------------------------------------------------------
  162. // C_PasstimeGoalReticle
  163. //-----------------------------------------------------------------------------
  164. //-----------------------------------------------------------------------------
  165. C_PasstimeGoalReticle::C_PasstimeGoalReticle( C_FuncPasstimeGoal *pGoal )
  166. {
  167. Assert( pGoal );
  168. m_hGoal.Set( pGoal );
  169. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_piece_1", 256, 50 ) );
  170. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_piece_2", 128, 0 ) );
  171. }
  172. //-----------------------------------------------------------------------------
  173. bool C_PasstimeGoalReticle::Update()
  174. {
  175. if ( !g_pPasstimeLogic || !g_pPasstimeLogic->GetBall() )
  176. {
  177. return false;
  178. }
  179. // don't show if ball isn't being carried by local player
  180. auto *pEnt = g_pPasstimeLogic->GetBall()->GetCarrier();
  181. if ( !pEnt || (pEnt != C_BasePlayer::GetLocalPlayer()) )
  182. {
  183. return false;
  184. }
  185. auto *pGoal = m_hGoal.Get();
  186. if ( !g_pPasstimeLogic || !g_pPasstimeLogic->GetBall() || IsLocalPlayerSpectator()
  187. || !pGoal || pGoal->BGoalTriggerDisabled() || (pGoal->GetTeamNumber() != pEnt->GetTeamNumber()) )
  188. {
  189. return false;
  190. }
  191. auto teamColor = GetTeamColor( pEnt->GetTeamNumber() );
  192. auto vec = pGoal->WorldSpaceCenter();
  193. auto facingFrac = MainViewForward().Dot( (vec - MainViewOrigin()).Normalized() );
  194. if ( facingFrac < 0.6 )
  195. {
  196. return false;
  197. }
  198. facingFrac = RemapValClamped( facingFrac, 0.8f, 1.0f, 1.0f, 0.3f );
  199. // ring
  200. SetOrigin( 0, vec );
  201. auto flPulseSpeed = 10.0f;
  202. auto flPulseFrac = Clamp( FastCos( gpGlobals->curtime * flPulseSpeed ), 0.0f, 1.0f );
  203. SetRgba( 0, teamColor.r(), teamColor.g(), teamColor.b(), flPulseFrac * (120 * facingFrac) );
  204. // arrow
  205. float tmp;
  206. flPulseFrac = 1.0f - modff( gpGlobals->curtime, &tmp );
  207. SetOrigin( 1, vec + Vector(0, 0, flPulseFrac * 64) );
  208. SetAllNormals( -MainViewForward() );
  209. SetRgba( 1, teamColor.r(), teamColor.g(), teamColor.b(), flPulseFrac * (255 * facingFrac) );
  210. return true;
  211. }
  212. //-----------------------------------------------------------------------------
  213. // C_PasstimePassReticle
  214. //-----------------------------------------------------------------------------
  215. const float kPassReticleScale = 64;
  216. //-----------------------------------------------------------------------------
  217. C_PasstimePassReticle::C_PasstimePassReticle()
  218. {
  219. m_flTargetScore = FLT_MAX;
  220. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_passlock", kPassReticleScale, 100 ) ); // the *
  221. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_piece_1", kPassReticleScale, 0 ) ); // the O
  222. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_piece_2", kPassReticleScale, 0 ) ); // the ><
  223. }
  224. //-----------------------------------------------------------------------------
  225. bool C_PasstimePassReticle::Update()
  226. {
  227. if ( !g_pPasstimeLogic || !g_pPasstimeLogic->GetBall() || IsLocalPlayerSpectator() )
  228. {
  229. return false;
  230. }
  231. auto *pBallCarrier = g_pPasstimeLogic->GetBall()->GetCarrier();
  232. if ( !pBallCarrier )
  233. {
  234. return false;
  235. }
  236. if ( (pBallCarrier != C_BasePlayer::GetLocalPlayer()) )
  237. {
  238. return false;
  239. }
  240. SetAllNormals( -MainViewForward() );
  241. // the player's actual pass target always takes precedence, but if it's
  242. // not set, try to find a candidate and display a hint for that
  243. auto *pPassTarget = pBallCarrier->m_Shared.GetPasstimePassTarget();
  244. if ( pPassTarget )
  245. {
  246. m_hTarget = pPassTarget;
  247. auto vecTargetPos = pPassTarget->WorldSpaceCenter();
  248. SetAllOrigins( vecTargetPos );
  249. auto teamColor = GetTeamColor( pBallCarrier->GetTeamNumber() );
  250. auto neutralColor = GetTeamColor( TEAM_UNASSIGNED );
  251. auto iAlpha = (int)( (fmodf( gpGlobals->curtime * 3.0f, 1.0f )) * 255 );
  252. SetRgba( 0, teamColor.r(), teamColor.g(), teamColor.b(), iAlpha );
  253. SetRgba( 1, neutralColor.r(), neutralColor.g(), neutralColor.b(), 255 );
  254. SetRgba( 2, teamColor.r(), teamColor.g(), teamColor.b(), iAlpha );
  255. auto flDist = (vecTargetPos - MainViewOrigin()).Length();
  256. auto flScale = RemapValClamped( flDist, 768.0f, 8192.0f, 1.0f, 8.0f );
  257. SetAllScales( flScale * kPassReticleScale * 2 );
  258. }
  259. else
  260. {
  261. FindPassHintTarget( pBallCarrier );
  262. if ( !m_hTarget )
  263. {
  264. return false;
  265. }
  266. auto flPulseSpeed = 20;
  267. auto flPulseFrac = Clamp( FastCos( gpGlobals->curtime * flPulseSpeed ), 0.3f, 1.0f );
  268. auto iAlpha = 200 * flPulseFrac * Clamp( m_flTargetScore + 0.5f, 0.0f, 1.0f ); // higher flScore is better
  269. auto teamColor = GetTeamColor( TEAM_UNASSIGNED );
  270. auto neutralColor = GetTeamColor( TEAM_UNASSIGNED );
  271. SetRgba( 0, teamColor.r(), teamColor.g(), teamColor.b(), iAlpha );
  272. SetRgba( 1, neutralColor.r(), neutralColor.g(), neutralColor.b(), 80 );
  273. SetRgba( 2, teamColor.r(), teamColor.g(), teamColor.b(), iAlpha );
  274. auto vecTargetPos = m_hTarget->WorldSpaceCenter();
  275. SetAllOrigins( vecTargetPos );
  276. auto flDist = (vecTargetPos - MainViewOrigin()).Length();
  277. auto flScale = RemapValClamped( flDist, 768.0f, 8192.0f, 1.0f, 8.0f );
  278. SetAllScales( flScale * kPassReticleScale );
  279. }
  280. return true;
  281. }
  282. //-----------------------------------------------------------------------------
  283. extern int HudTransform( const Vector &point, Vector &screen );
  284. void C_PasstimePassReticle::FindPassHintTarget( C_TFPlayer *pLocalPlayer )
  285. {
  286. m_hTarget = 0;
  287. m_flTargetScore = -FLT_MAX;
  288. auto flFovDeg = 70;
  289. auto flDotFov = cosf( DEG2RAD( flFovDeg / 2.0f ) );
  290. auto vecViewPos = MainViewOrigin();
  291. auto vecViewFwd = MainViewForward();
  292. auto flMaxPassDist = g_pPasstimeLogic->GetMaxPassRange() - 400; // arbitrary, based on TF_MAX_SPEED
  293. // for each player in front of the local player,
  294. for( int i = 1; i <= MAX_PLAYERS; i++ )
  295. {
  296. auto *pPlayer = ToTFPlayer( UTIL_PlayerByIndex( i ) );
  297. if ( !C_PasstimeGun::BValidPassTarget( pLocalPlayer, pPlayer ) )
  298. {
  299. continue;
  300. }
  301. auto vecTargetPos = pPlayer->EyePosition();
  302. auto vecToTarget = vecTargetPos - vecViewPos;
  303. if ( vecToTarget.NormalizeInPlace() > flMaxPassDist )
  304. {
  305. // the server may disagree on this, so the client is less permissive
  306. // when it guesses in order to prevent false positives
  307. continue; // too far away, probably
  308. }
  309. auto fDotTarget = vecToTarget.Dot( vecViewFwd );
  310. if ( fDotTarget <= flDotFov )
  311. {
  312. continue; // not in front
  313. }
  314. // determine player's distance from center of screen
  315. Vector vecScreenPos;
  316. auto bBehindViewplane = HudTransform( vecTargetPos, vecScreenPos );
  317. if ( bBehindViewplane )
  318. {
  319. continue; // paranoia
  320. }
  321. auto flScore = 0.5f - vecScreenPos.Length2D();
  322. if ( flScore <= m_flTargetScore )
  323. {
  324. continue; // someone else already found that's closer
  325. }
  326. // trace to see if they are visible
  327. // this is the same trace the gun does
  328. trace_t tr;
  329. CTraceFilterSimple tracefilter( pLocalPlayer, COLLISION_GROUP_PROJECTILE );
  330. UTIL_TraceLine( vecViewPos, vecTargetPos, MASK_PLAYERSOLID, &tracefilter, &tr );
  331. if ( tr.m_pEnt != pPlayer )
  332. {
  333. continue; // not visible
  334. }
  335. m_flTargetScore = flScore;
  336. m_hTarget = pPlayer;
  337. }
  338. }
  339. //-----------------------------------------------------------------------------
  340. // C_PasstimeBounceReticle
  341. //-----------------------------------------------------------------------------
  342. C_PasstimeBounceReticle::C_PasstimeBounceReticle()
  343. {
  344. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_passlock", 160, 0 ) ); // the *
  345. AddSprite( CreateReticleSprite( "passtime/hud/passtime_ball_reticle_piece_1", 80, 200 ) ); // the O
  346. }
  347. void C_PasstimeBounceReticle::Show( const Vector &vec, const Vector &normal )
  348. {
  349. SetOrigin( 0, vec );
  350. SetOrigin( 1, vec );//+ (normal * 16) );
  351. SetNormal( 0, normal );
  352. SetNormal( 1, -MainViewForward() );
  353. SetRgba( 0, 255, 255, 0, 200 );
  354. SetRgba( 1, 255, 255, 0, 200 );
  355. }
  356. void C_PasstimeBounceReticle::Hide()
  357. {
  358. SetAllAlphas( 0 );
  359. }
  360. bool C_PasstimeBounceReticle::Update()
  361. {
  362. return !IsLocalPlayerSpectator();
  363. }
  364. //-----------------------------------------------------------------------------
  365. // C_PasstimePlayerReticle
  366. //-----------------------------------------------------------------------------
  367. C_PasstimePlayerReticle::C_PasstimePlayerReticle( C_TFPlayer *pPlayer )
  368. {
  369. m_hPlayer.Set( pPlayer );
  370. AddSprite( CreateReticleSprite( "passtime/hud/passtime_teamicon_red", 128, 0 ) );
  371. AddSprite( CreateReticleSprite( "passtime/hud/passtime_teamicon_blue", 128, 0 ) );
  372. }
  373. //-----------------------------------------------------------------------------
  374. bool C_PasstimePlayerReticle::Update()
  375. {
  376. if ( !g_pPasstimeLogic )
  377. {
  378. return false;
  379. }
  380. auto *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  381. auto *pPlayer = m_hPlayer.Get();
  382. if ( !pLocalPlayer || pLocalPlayer->IsPlayerDead()
  383. || !pPlayer || pPlayer->IsPlayerDead() )
  384. {
  385. return false;
  386. }
  387. if ( pPlayer->m_Shared.GetPercentInvisible() > 0 )
  388. {
  389. // dont' show because player is invisible, friend or foe
  390. return false;
  391. }
  392. auto iFriendsDetail = tf_passtime_player_reticles_friends.GetInt();
  393. auto iEnemiesDetail = tf_passtime_player_reticles_enemies.GetInt();
  394. auto bIsDisguisedEnemy = pPlayer->m_Shared.InCond( TF_COND_DISGUISED )
  395. && ( pPlayer->m_Shared.GetDisguiseTeam() == pLocalPlayer->GetTeamNumber() )
  396. && !pPlayer->m_Shared.IsFullyInvisible();
  397. auto bIsFriend = pLocalPlayer->InSameTeam( pPlayer ) || bIsDisguisedEnemy;
  398. if ( (bIsFriend && (iFriendsDetail <= 0))
  399. || (!bIsFriend && (iEnemiesDetail <= 0)) )
  400. {
  401. // don't show because disabled
  402. return false;
  403. }
  404. if ( !pLocalPlayer->m_Shared.HasPasstimeBall()
  405. && ((bIsFriend && (iFriendsDetail == 1))
  406. || (!bIsFriend && (iEnemiesDetail == 1))))
  407. {
  408. // don't show because not visible unless have ball
  409. return false;
  410. }
  411. if ( pPlayer->IsDormant() )
  412. {
  413. // don't show because not getting updated from server for some reason
  414. // probably not in PVS
  415. return false;
  416. }
  417. auto nTeamNumber = pPlayer->GetTeamNumber();
  418. if ( !pLocalPlayer->InSameTeam( pPlayer ) && bIsFriend ) // they're not on my team but they're showing as a friend, they must be a spy so use my team color
  419. {
  420. nTeamNumber = pLocalPlayer->GetTeamNumber();
  421. }
  422. int iShowSprite, iHideSprite;
  423. if ( nTeamNumber == TF_TEAM_RED )
  424. {
  425. iShowSprite = 0;
  426. iHideSprite = 1;
  427. }
  428. else if ( nTeamNumber == TF_TEAM_BLUE )
  429. {
  430. iShowSprite = 1;
  431. iHideSprite = 0;
  432. }
  433. else
  434. {
  435. return false;
  436. }
  437. auto vecTarget = pPlayer->EyePosition();
  438. int iX, iY;
  439. auto bOnScreen = GetVectorInHudSpace( vecTarget, iX, iY );
  440. if ( !bOnScreen )
  441. {
  442. return false;
  443. }
  444. trace_t tr;
  445. CTraceFilterIgnorePlayers tracefilter( pLocalPlayer, COLLISION_GROUP_PROJECTILE );
  446. UTIL_TraceLine( MainViewOrigin(), vecTarget, MASK_PLAYERSOLID, &tracefilter, &tr );
  447. if ( tr.fraction == 1 )
  448. {
  449. // made it all the way, the guy is visible so hide the icon
  450. return false;
  451. }
  452. auto flDist = (vecTarget - MainViewOrigin()).Length();
  453. auto flScale = RemapValClamped( flDist, 1024.0f, 4096.0f, 80, 128 );
  454. SetAlpha( iHideSprite, 0 );
  455. SetAlpha( iShowSprite, 100 );
  456. SetAllScales( flScale );
  457. SetAllOrigins( vecTarget );
  458. SetAllNormals( -MainViewForward() );
  459. return true;
  460. }
  461. //-----------------------------------------------------------------------------
  462. // C_PasstimeAskForBallReticle
  463. //-----------------------------------------------------------------------------
  464. C_PasstimeAskForBallReticle::C_PasstimeAskForBallReticle( C_TFPlayer *pPlayer )
  465. {
  466. m_hPlayer.Set( pPlayer );
  467. AddSprite( CreateReticleSprite( "passtime/hud/passtime_pass_to_me_prompt", 128, 0 ) );
  468. SetRgba( 0, 255, 255, 255, 200 );
  469. }
  470. //-----------------------------------------------------------------------------
  471. bool C_PasstimeAskForBallReticle::Update()
  472. {
  473. if ( !g_pPasstimeLogic )
  474. {
  475. return false;
  476. }
  477. auto *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  478. auto *pPlayer = m_hPlayer.Get();
  479. if ( !pLocalPlayer || !pPlayer )
  480. {
  481. return false;
  482. }
  483. auto bLocalPlayerObserver = pLocalPlayer->IsObserver();
  484. if ( !bLocalPlayerObserver && pLocalPlayer->IsPlayerDead() )
  485. {
  486. return false;
  487. }
  488. if ( (pPlayer->m_Shared.AskForBallTime() < gpGlobals->curtime) || pPlayer->IsPlayerDead() )
  489. {
  490. return false;
  491. }
  492. if ( !bLocalPlayerObserver && !pLocalPlayer->m_Shared.HasPasstimeBall() && !pPlayer->InSameTeam( pLocalPlayer ) )
  493. {
  494. return false;
  495. }
  496. auto vecTarget = pPlayer->EyePosition();
  497. vecTarget.z += 16;
  498. int iX, iY;
  499. auto bOnScreen = GetVectorInHudSpace( vecTarget, iX, iY );
  500. if ( !bOnScreen )
  501. {
  502. return false;
  503. }
  504. auto flDist = (vecTarget - MainViewOrigin()).Length();
  505. auto flScale = RemapValClamped( flDist, 1024.0f, 4096.0f, 40, 200 );
  506. SetAllScales( flScale );
  507. SetAllOrigins( vecTarget );
  508. SetAllNormals( -MainViewForward() );
  509. SetRgba( 0, 255, 255, 255, (((int)(gpGlobals->curtime * 10)) & 1 ? 200 : 0) );
  510. return true;
  511. }
  512. //-----------------------------------------------------------------------------
  513. // Functions
  514. //-----------------------------------------------------------------------------
  515. //-----------------------------------------------------------------------------
  516. CFXQuad *CreateReticleSprite( const char *pModelName, float flScale, float flSpinSpeed )
  517. {
  518. FXQuadData_t q;
  519. memset(&q, 0, sizeof(q));
  520. q.m_Color.Init(1,1,1);
  521. q.m_flDeltaYaw = flSpinSpeed;
  522. q.m_flDieTime = FLT_MAX;
  523. q.m_flEndAlpha = 1;
  524. q.m_flEndScale = flScale;
  525. q.m_flLifeTime = 0;
  526. q.m_flScaleBias = 0;
  527. q.m_flStartAlpha = 1;
  528. q.m_flStartScale = flScale;
  529. q.m_flYaw = 180;
  530. q.SetMaterial( pModelName );
  531. q.m_uiFlags = 0;
  532. q.m_vecNormal.Init(1,0,0);
  533. q.m_vecOrigin.Init(0,0,0);
  534. CFXQuad *pQuad = new CFXQuad(q);
  535. clienteffects->AddEffect( pQuad );
  536. return pQuad;
  537. }