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.

523 lines
16 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "tf_hud_mediccallers.h"
  9. #include "iclientmode.h"
  10. #include <vgui/ILocalize.h>
  11. #include <vgui/ISurface.h>
  12. #include <vgui/IVGui.h>
  13. #include "view.h"
  14. #include "ivieweffects.h"
  15. #include "viewrender.h"
  16. #include "prediction.h"
  17. #include "GameEventListener.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. #define MEDICCALLER_WIDE (XRES(56))
  21. #define MEDICCALLER_TALL (YRES(48))
  22. #define MEDICCALLER_ARROW_WIDE (XRES(16))
  23. #define MEDICCALLER_ARROW_TALL (YRES(24))
  24. //-----------------------------------------------------------------------------
  25. // Purpose:
  26. //-----------------------------------------------------------------------------
  27. CTFMedicCallerPanel::CTFMedicCallerPanel( Panel *parent, const char *name ) : EditablePanel(parent,name)
  28. {
  29. m_pArrowMaterial = NULL;
  30. m_iDrawArrow = DRAW_ARROW_UP;
  31. m_bOnscreen = false;
  32. m_flPanelScale = 1.0f;
  33. m_bBurning = false;
  34. m_bBleeding = false;
  35. m_nCallerType = CALLER_TYPE_NORMAL;
  36. ListenForGameEvent( "player_calledformedic" );
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Purpose:
  40. //-----------------------------------------------------------------------------
  41. CTFMedicCallerPanel::~CTFMedicCallerPanel( void )
  42. {
  43. if ( m_pArrowMaterial )
  44. {
  45. m_pArrowMaterial->DecrementReferenceCount();
  46. }
  47. }
  48. //-----------------------------------------------------------------------------
  49. // Purpose: Applies scheme settings
  50. //-----------------------------------------------------------------------------
  51. void CTFMedicCallerPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  52. {
  53. BaseClass::ApplySchemeSettings( pScheme );
  54. LoadControlSettings( GetControlSettingFile() );
  55. if ( m_pArrowMaterial )
  56. {
  57. m_pArrowMaterial->DecrementReferenceCount();
  58. }
  59. m_pArrowMaterial = materials->FindMaterial( "HUD/medic_arrow", TEXTURE_GROUP_VGUI );
  60. m_pArrowMaterial->IncrementReferenceCount();
  61. }
  62. //-----------------------------------------------------------------------------
  63. // Purpose:
  64. //-----------------------------------------------------------------------------
  65. void CTFMedicCallerPanel::PerformLayout( void )
  66. {
  67. BaseClass::PerformLayout();
  68. int nWide = XRES(100), nTall = YRES(100);
  69. bool bNormal = ( m_nCallerType == CALLER_TYPE_NORMAL );
  70. bool bAutoCaller = ( m_nCallerType == CALLER_TYPE_AUTO );
  71. // Adjust scale of the panel based on distance to the caller
  72. C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  73. if ( pLocalTFPlayer && m_hEntity )
  74. {
  75. Vector vecDistance = m_hEntity->GetAbsOrigin() - pLocalTFPlayer->GetAbsOrigin();
  76. m_flPanelScale = RemapValClamped( vecDistance.LengthSqr(), 0.0f, (2000.0f * 2000.0f), 1.0f, 0.5f );
  77. }
  78. vgui::Panel *pPanelAuto = FindChildByName( "CallerAuto" );
  79. if ( pPanelAuto )
  80. {
  81. if ( pPanelAuto->IsVisible() != bAutoCaller )
  82. {
  83. pPanelAuto->SetVisible( bAutoCaller );
  84. }
  85. if ( bAutoCaller )
  86. {
  87. pPanelAuto->GetSize( nWide, nTall );
  88. pPanelAuto->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  89. pPanelAuto->SetPos( ( GetWide() - pPanelAuto->GetWide() ) * 0.5, ( GetTall() - pPanelAuto->GetTall() ) * 0.5 );
  90. }
  91. }
  92. vgui::Panel *pPanel = FindChildByName( "CallerBG" );
  93. if ( pPanel )
  94. {
  95. if ( pPanel->IsVisible() != bNormal )
  96. {
  97. pPanel->SetVisible( bNormal );
  98. }
  99. if ( bNormal )
  100. {
  101. pPanel->GetSize( nWide, nTall );
  102. pPanel->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  103. pPanel->SetPos( (GetWide() - pPanel->GetWide()) * 0.5, (GetTall() - pPanel->GetTall()) * 0.5 );
  104. }
  105. }
  106. vgui::Panel *pBurningPanel = FindChildByName( "CallerBurning" );
  107. if ( pBurningPanel )
  108. {
  109. bool bVisible = bNormal && m_bBurning;
  110. if ( pBurningPanel->IsVisible() != bVisible )
  111. {
  112. pBurningPanel->SetVisible( bVisible );
  113. }
  114. if ( bVisible )
  115. {
  116. pBurningPanel->GetSize( nWide, nTall );
  117. pBurningPanel->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  118. pBurningPanel->SetPos( (GetWide() - pBurningPanel->GetWide()) * 0.5, (GetTall() - pBurningPanel->GetTall()) * 0.5 );
  119. }
  120. }
  121. vgui::Panel *pBleedingPanel = FindChildByName( "CallerBleeding" );
  122. if ( pBleedingPanel )
  123. {
  124. bool bVisible = bNormal && m_bBleeding;
  125. if ( pBleedingPanel->IsVisible() != bVisible )
  126. {
  127. pBleedingPanel->SetVisible( bVisible );
  128. }
  129. if ( bVisible )
  130. {
  131. pBleedingPanel->GetSize( nWide, nTall );
  132. pBleedingPanel->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  133. pBleedingPanel->SetPos( (GetWide() - pBleedingPanel->GetWide()) * 0.5, (GetTall() - pBleedingPanel->GetTall()) * 0.5 );
  134. }
  135. }
  136. vgui::Panel *pPanelHealth = FindChildByName( "CallerHealth" );
  137. if ( pPanelHealth )
  138. {
  139. if ( pPanelHealth->IsVisible() != bNormal )
  140. {
  141. pPanelHealth->SetVisible( bNormal );
  142. }
  143. if ( bNormal )
  144. {
  145. pPanelHealth->GetSize( nWide, nTall );
  146. pPanelHealth->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  147. pPanelHealth->SetPos( (GetWide() - pPanelHealth->GetWide()) * 0.5, (GetTall() - pPanelHealth->GetTall()) * 0.5 );
  148. pPanelHealth->SetAlpha( 0 );
  149. }
  150. }
  151. // Revive block
  152. vgui::Panel *pPanelReviveEasy = FindChildByName( "CallerReviveEasy" );
  153. if ( pPanelReviveEasy )
  154. {
  155. bool bReviveEasy = m_nCallerType == CALLER_TYPE_REVIVE_EASY;
  156. if ( pPanelReviveEasy->IsVisible() != bReviveEasy )
  157. {
  158. pPanelReviveEasy->SetVisible( bReviveEasy );
  159. }
  160. if ( bReviveEasy )
  161. {
  162. pPanelReviveEasy->GetSize( nWide, nTall );
  163. pPanelReviveEasy->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  164. pPanelReviveEasy->SetPos( ( GetWide() - pPanelReviveEasy->GetWide() ) * 0.5, ( GetTall() - pPanelReviveEasy->GetTall() ) * 0.5 );
  165. }
  166. }
  167. vgui::Panel *pPanelReviveMedium = FindChildByName( "CallerReviveMedium" );
  168. if ( pPanelReviveMedium )
  169. {
  170. bool bReviveMedium = m_nCallerType == CALLER_TYPE_REVIVE_MEDIUM;
  171. if ( pPanelReviveMedium->IsVisible() != bReviveMedium )
  172. {
  173. pPanelReviveMedium->SetVisible( bReviveMedium );
  174. }
  175. if ( bReviveMedium )
  176. {
  177. pPanelReviveMedium->GetSize( nWide, nTall );
  178. pPanelReviveMedium->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  179. pPanelReviveMedium->SetPos( ( GetWide() - pPanelReviveMedium->GetWide() ) * 0.5, ( GetTall() - pPanelReviveMedium->GetTall() ) * 0.5 );
  180. }
  181. }
  182. vgui::Panel *pPanelReviveHard = FindChildByName( "CallerReviveHard" );
  183. if ( pPanelReviveHard )
  184. {
  185. bool bReviveHard = m_nCallerType == CALLER_TYPE_REVIVE_HARD;
  186. if ( pPanelReviveHard->IsVisible() != bReviveHard )
  187. {
  188. pPanelReviveHard->SetVisible( bReviveHard );
  189. }
  190. if ( bReviveHard )
  191. {
  192. pPanelReviveHard->GetSize( nWide, nTall );
  193. pPanelReviveHard->SetSize ( nWide * m_flPanelScale, nTall * m_flPanelScale );
  194. pPanelReviveHard->SetPos( ( GetWide() - pPanelReviveHard->GetWide() ) * 0.5, ( GetTall() - pPanelReviveHard->GetTall() ) * 0.5 );
  195. }
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose:
  200. //-----------------------------------------------------------------------------
  201. void CTFMedicCallerPanel::GetCallerPosition( const Vector &vecDelta, float flRadius, float *xpos, float *ypos, float *flRotation )
  202. {
  203. // Player Data
  204. Vector playerPosition = MainViewOrigin();
  205. QAngle playerAngles = MainViewAngles();
  206. Vector forward, right, up(0,0,1);
  207. AngleVectors (playerAngles, &forward, NULL, NULL );
  208. forward.z = 0;
  209. VectorNormalize(forward);
  210. CrossProduct( up, forward, right );
  211. float front = DotProduct(vecDelta, forward);
  212. float side = DotProduct(vecDelta, right);
  213. *xpos = flRadius * -side;
  214. *ypos = flRadius * -front;
  215. // Get the rotation (yaw)
  216. *flRotation = atan2(*xpos,*ypos) + M_PI;
  217. *flRotation *= 180 / M_PI;
  218. float yawRadians = -(*flRotation) * M_PI / 180.0f;
  219. float ca = cos( yawRadians );
  220. float sa = sin( yawRadians );
  221. // Rotate it around the circle
  222. *xpos = (int)((ScreenWidth() / 2) + (flRadius * sa));
  223. *ypos = (int)((ScreenHeight() / 2) - (flRadius * ca));
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose:
  227. //-----------------------------------------------------------------------------
  228. void CTFMedicCallerPanel::OnTick( void )
  229. {
  230. if ( !m_hEntity || ( m_hEntity->IsPlayer() && !m_hEntity->IsAlive() ) || gpGlobals->curtime > m_flRemoveAt )
  231. {
  232. MarkForDeletion();
  233. return;
  234. }
  235. // If the local player has started healing this guy, remove it too.
  236. // Also don't draw it if we're dead.
  237. C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  238. if ( pLocalTFPlayer )
  239. {
  240. CBaseEntity *pHealTarget = pLocalTFPlayer->MedicGetHealTarget();
  241. if ( ( pHealTarget && pHealTarget == m_hEntity ) || ( m_hEntity->IsPlayer() && !pLocalTFPlayer->IsAlive() ) )
  242. {
  243. MarkForDeletion();
  244. return;
  245. }
  246. if ( m_hEntity->IsPlayer() )
  247. {
  248. C_TFPlayer *pTFPlayer = ToTFPlayer( m_hEntity );
  249. if ( pTFPlayer )
  250. {
  251. // If we're pointing to an enemy spy and they are no longer disguised, remove ourselves
  252. if ( pTFPlayer->IsPlayerClass( TF_CLASS_SPY ) &&
  253. pTFPlayer->GetTeamNumber() != pLocalTFPlayer->GetTeamNumber() &&
  254. !( pTFPlayer->m_Shared.InCond( TF_COND_DISGUISED ) && pTFPlayer->m_Shared.GetDisguiseTeam() == pLocalTFPlayer->GetTeamNumber() ) )
  255. {
  256. MarkForDeletion();
  257. return;
  258. }
  259. // Updates the state of the caller panel if they are now burning or bleeding, or have stopped while caller panel is still up.
  260. if ( m_nCallerType != CALLER_TYPE_AUTO )
  261. {
  262. m_bBurning = pTFPlayer->m_Shared.InCond( TF_COND_BURNING );
  263. vgui::Panel *pBurningPanel = FindChildByName( "CallerBurning" );
  264. if ( pBurningPanel && pBurningPanel->IsVisible() != m_bBurning )
  265. {
  266. pBurningPanel->SetVisible( m_bBurning );
  267. }
  268. vgui::Panel *pBleedingPanel = FindChildByName( "CallerBleeding" );
  269. m_bBleeding = pTFPlayer->m_Shared.InCond( TF_COND_BLEEDING );
  270. if ( pBleedingPanel && pBleedingPanel->IsVisible() != m_bBleeding )
  271. {
  272. pBleedingPanel->SetVisible( m_bBleeding );
  273. }
  274. }
  275. }
  276. }
  277. }
  278. if ( m_nCallerType == CALLER_TYPE_NORMAL )
  279. {
  280. // Tints caller panel based on health remaining.
  281. vgui::Panel *pPanelHealth = FindChildByName( "CallerHealth" );
  282. if ( pPanelHealth )
  283. {
  284. float flHealth = ( float(m_hEntity->GetHealth()) / float(m_hEntity->GetMaxHealth()) );
  285. int iCallerHurtAlpha = 255 * ( 1 - flHealth ) + 75;
  286. pPanelHealth->SetAlpha( clamp( iCallerHurtAlpha, 0, 255 ) );
  287. }
  288. }
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose:
  292. //-----------------------------------------------------------------------------
  293. void CTFMedicCallerPanel::PaintBackground( void )
  294. {
  295. // If the local player has started healing this guy, remove it too.
  296. //Also don't draw it if we're dead.
  297. C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer();
  298. if ( !pLocalTFPlayer )
  299. return;
  300. if ( !m_hEntity || m_hEntity->IsDormant() )
  301. {
  302. SetAlpha(0);
  303. return;
  304. }
  305. // Reposition the callout based on our target's position
  306. int iX, iY;
  307. Vector vecTarget = (m_hEntity->GetAbsOrigin() + m_vecOffset);
  308. Vector vecDelta = vecTarget - MainViewOrigin();
  309. bool bOnscreen = GetVectorInHudSpace( vecTarget, iX, iY ); // Tested and correct - should NOT be GetVectorInScreenSpace.
  310. int halfWidth = GetWide() / 2;
  311. if( !bOnscreen || iX < halfWidth || iX > ScreenWidth()-halfWidth )
  312. {
  313. // It's off the screen. Position the callout.
  314. VectorNormalize(vecDelta);
  315. float xpos, ypos;
  316. float flRotation;
  317. float flRadius = YRES(100);
  318. GetCallerPosition( vecDelta, flRadius, &xpos, &ypos, &flRotation );
  319. iX = xpos;
  320. iY = ypos;
  321. Vector vCenter = m_hEntity->WorldSpaceCenter( );
  322. if( MainViewRight().Dot( vCenter - MainViewOrigin() ) > 0 )
  323. {
  324. m_iDrawArrow = DRAW_ARROW_RIGHT;
  325. }
  326. else
  327. {
  328. m_iDrawArrow = DRAW_ARROW_LEFT;
  329. }
  330. // Move the icon there
  331. SetPos( iX - halfWidth, iY - (GetTall() / 2) );
  332. SetAlpha( 255 );
  333. }
  334. else
  335. {
  336. // On screen
  337. // If our target isn't visible, we draw transparently
  338. trace_t tr;
  339. UTIL_TraceLine( vecTarget, MainViewOrigin(), MASK_OPAQUE, NULL, COLLISION_GROUP_NONE, &tr );
  340. if ( tr.fraction >= 1.0f )
  341. {
  342. m_bOnscreen = true;
  343. SetAlpha( 0 );
  344. return;
  345. }
  346. m_iDrawArrow = DRAW_ARROW_UP;
  347. SetAlpha( 92 );
  348. SetPos( iX - halfWidth, iY - (GetTall() / 2) );
  349. }
  350. m_bOnscreen = false;
  351. BaseClass::PaintBackground();
  352. }
  353. //-----------------------------------------------------------------------------
  354. // Purpose:
  355. //-----------------------------------------------------------------------------
  356. void CTFMedicCallerPanel::Paint( void )
  357. {
  358. // Don't draw if our target is visible. The particle effect will be doing it for us.
  359. if ( m_bOnscreen )
  360. return;
  361. BaseClass::Paint();
  362. if ( m_iDrawArrow == DRAW_ARROW_UP )
  363. return;
  364. float uA,uB,yA,yB;
  365. int x,y;
  366. GetPos( x,y );
  367. if ( m_iDrawArrow == DRAW_ARROW_LEFT )
  368. {
  369. uA = 1.0;
  370. uB = 0.0;
  371. yA = 0.0;
  372. yB = 1.0;
  373. }
  374. else
  375. {
  376. uA = 0.0;
  377. uB = 1.0;
  378. yA = 0.0;
  379. yB = 1.0;
  380. x += GetWide() - MEDICCALLER_ARROW_WIDE;
  381. }
  382. int iyindent = (GetTall() - MEDICCALLER_ARROW_TALL) * 0.5;
  383. y += iyindent;
  384. CMatRenderContextPtr pRenderContext( materials );
  385. pRenderContext->Bind( m_pArrowMaterial );
  386. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  387. CMeshBuilder meshBuilder;
  388. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  389. meshBuilder.Position3f( x, y, 0.0f );
  390. meshBuilder.TexCoord2f( 0, uA, yA );
  391. meshBuilder.Color4ub( 255, 255, 255, 255 );
  392. meshBuilder.AdvanceVertex();
  393. meshBuilder.Position3f( x + MEDICCALLER_ARROW_WIDE, y, 0.0f );
  394. meshBuilder.TexCoord2f( 0, uB, yA );
  395. meshBuilder.Color4ub( 255, 255, 255, 255 );
  396. meshBuilder.AdvanceVertex();
  397. meshBuilder.Position3f( x + MEDICCALLER_ARROW_WIDE, y + MEDICCALLER_ARROW_TALL, 0.0f );
  398. meshBuilder.TexCoord2f( 0, uB, yB );
  399. meshBuilder.Color4ub( 255, 255, 255, 255 );
  400. meshBuilder.AdvanceVertex();
  401. meshBuilder.Position3f( x, y + MEDICCALLER_ARROW_TALL, 0.0f );
  402. meshBuilder.TexCoord2f( 0, uA, yB );
  403. meshBuilder.Color4ub( 255, 255, 255, 255 );
  404. meshBuilder.AdvanceVertex();
  405. meshBuilder.End();
  406. pMesh->Draw();
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Purpose:
  410. //-----------------------------------------------------------------------------
  411. void CTFMedicCallerPanel::SetEntity( C_BaseEntity *pEntity, float flDuration, Vector &vecOffset )
  412. {
  413. m_hEntity = pEntity;
  414. m_flRemoveAt = gpGlobals->curtime + flDuration;
  415. m_vecOffset = vecOffset;
  416. }
  417. void CTFMedicCallerPanel::SetMedicCallerType( MedicCallerType nType )
  418. {
  419. m_nCallerType = nType;
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Purpose:
  423. //-----------------------------------------------------------------------------
  424. void CTFMedicCallerPanel::AddMedicCaller( C_BaseEntity *pEntity, float flDuration, Vector &vecOffset, MedicCallerType nType /* = CALLER_TYPE_NORMAL */ )
  425. {
  426. CTFMedicCallerPanel *pCaller = new CTFMedicCallerPanel( g_pClientMode->GetViewport(), "MedicCallerPanel" );
  427. vgui::SETUP_PANEL(pCaller);
  428. pCaller->SetBounds( 0,0, MEDICCALLER_WIDE, MEDICCALLER_TALL );
  429. pCaller->SetEntity( pEntity, flDuration, vecOffset );
  430. pCaller->SetMedicCallerType( nType );
  431. pCaller->SetVisible( true );
  432. vgui::ivgui()->AddTickSignal( pCaller->GetVPanel() );
  433. pCaller->OnTick();
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose:
  437. //-----------------------------------------------------------------------------
  438. void CTFMedicCallerPanel::FireGameEvent( IGameEvent *event )
  439. {
  440. if ( m_nCallerType == CALLER_TYPE_AUTO )
  441. {
  442. if ( Q_strcmp( event->GetName(), "player_calledformedic" ) == 0 )
  443. {
  444. if ( m_hEntity && m_hEntity->IsPlayer() )
  445. {
  446. C_TFPlayer *pTFPlayer = ToTFPlayer( m_hEntity );
  447. if ( pTFPlayer )
  448. {
  449. int iCaller = engine->GetPlayerForUserID( event->GetInt( "userid" ) );
  450. if ( pTFPlayer->GetUserID() == iCaller )
  451. {
  452. MarkForDeletion();
  453. }
  454. }
  455. }
  456. }
  457. }
  458. }