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.

1157 lines
39 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "hudelement.h"
  8. #include "iclientmode.h"
  9. #include <KeyValues.h>
  10. #include <vgui/IScheme.h>
  11. #include <vgui/ISurface.h>
  12. #include <vgui/ISystem.h>
  13. #include <vgui_controls/AnimationController.h>
  14. #include <vgui_controls/EditablePanel.h>
  15. #include <vgui/ISurface.h>
  16. #include <vgui/IImage.h>
  17. #include <vgui_controls/Label.h>
  18. #include "c_tf_playerresource.h"
  19. #include "tf_playermodelpanel.h"
  20. #include "econ_item_description.h"
  21. #include "hud_numericdisplay.h"
  22. #include "c_team.h"
  23. #include "c_tf_player.h"
  24. #include "tf_shareddefs.h"
  25. #include "tf_hud_playerstatus.h"
  26. #include "tf_gamerules.h"
  27. #include "tf_logic_halloween_2014.h"
  28. #include "tf_logic_player_destruction.h"
  29. #include "tf_wheel_of_doom.h"
  30. #include "confirm_dialog.h"
  31. using namespace vgui;
  32. ConVar cl_hud_playerclass_use_playermodel( "cl_hud_playerclass_use_playermodel", "1", FCVAR_ARCHIVE, "Use player model in player class HUD." );
  33. #ifdef STAGING_ONLY
  34. ConVar cl_hud_playerclass_playermodel_lod( "cl_hud_playerclass_playermodel_lod", "0", FCVAR_ARCHIVE, "Adjust lod on player model in the player class HUD." );
  35. #endif // STAGING_ONLY
  36. ConVar cl_hud_playerclass_playermodel_showed_confirm_dialog( "cl_hud_playerclass_playermodel_showed_confirm_dialog", "0", FCVAR_ARCHIVE | FCVAR_HIDDEN );
  37. extern ConVar tf_max_health_boost;
  38. static const char *g_szBlueClassImages[] =
  39. {
  40. "",
  41. "../hud/class_scoutblue",
  42. "../hud/class_sniperblue",
  43. "../hud/class_soldierblue",
  44. "../hud/class_demoblue",
  45. "../hud/class_medicblue",
  46. "../hud/class_heavyblue",
  47. "../hud/class_pyroblue",
  48. "../hud/class_spyblue",
  49. "../hud/class_engiblue",
  50. "../hud/class_scoutblue",
  51. };
  52. static const char *g_szRedClassImages[] =
  53. {
  54. "",
  55. "../hud/class_scoutred",
  56. "../hud/class_sniperred",
  57. "../hud/class_soldierred",
  58. "../hud/class_demored",
  59. "../hud/class_medicred",
  60. "../hud/class_heavyred",
  61. "../hud/class_pyrored",
  62. "../hud/class_spyred",
  63. "../hud/class_engired",
  64. "../hud/class_scoutred",
  65. };
  66. enum
  67. {
  68. HUD_HEALTH_NO_ANIM = 0,
  69. HUD_HEALTH_BONUS_ANIM,
  70. HUD_HEALTH_DYING_ANIM,
  71. };
  72. DECLARE_BUILD_FACTORY( CTFClassImage );
  73. //-----------------------------------------------------------------------------
  74. // Purpose:
  75. //-----------------------------------------------------------------------------
  76. CTFHudPlayerClass::CTFHudPlayerClass( Panel *parent, const char *name ) : EditablePanel( parent, name )
  77. {
  78. m_pClassImage = NULL;
  79. m_pClassImageBG = NULL;
  80. m_pSpyImage = NULL;
  81. m_pSpyOutlineImage = NULL;
  82. m_pPlayerModelPanel = NULL;
  83. m_pPlayerModelPanelBG = NULL;
  84. m_pCarryingWeaponPanel = NULL;
  85. m_pCarryingLabel = NULL;
  86. m_pCarryingOwnerLabel = NULL;
  87. m_pCarryingBG = NULL;
  88. m_nTeam = TEAM_UNASSIGNED;
  89. m_nClass = TF_CLASS_UNDEFINED;
  90. m_nDisguiseTeam = TEAM_UNASSIGNED;
  91. m_nDisguiseClass = TF_CLASS_UNDEFINED;
  92. m_hDisguiseWeapon = NULL;
  93. m_flNextThink = 0.0f;
  94. m_nKillStreak = 0;
  95. #ifdef STAGING_ONLY
  96. m_nLOD = -1;
  97. #endif // STAGING_ONLY
  98. m_bUsePlayerModel = cl_hud_playerclass_use_playermodel.GetBool();
  99. ListenForGameEvent( "localplayer_changedisguise" );
  100. ListenForGameEvent( "post_inventory_application" );
  101. ListenForGameEvent( "localplayer_pickup_weapon" );
  102. for ( int i = 0; i < TF_CLASS_COUNT_ALL; i++ )
  103. {
  104. // The materials are given to vgui via the SetImage() function, which prepends
  105. // the "vgui/", so we need to precache them with the same.
  106. if ( g_szBlueClassImages[i] && g_szBlueClassImages[i][0] )
  107. {
  108. PrecacheMaterial( VarArgs( "vgui/%s", g_szBlueClassImages[i] ) );
  109. PrecacheMaterial( VarArgs( "vgui/%s_cloak", g_szBlueClassImages[i] ) );
  110. PrecacheMaterial( VarArgs( "vgui/%s_halfcloak", g_szBlueClassImages[i] ) );
  111. }
  112. if ( g_szRedClassImages[i] && g_szRedClassImages[i][0] )
  113. {
  114. PrecacheMaterial( VarArgs( "vgui/%s", g_szRedClassImages[i] ) );
  115. PrecacheMaterial( VarArgs( "vgui/%s_cloak", g_szRedClassImages[i] ) );
  116. PrecacheMaterial( VarArgs( "vgui/%s_halfcloak", g_szRedClassImages[i] ) );
  117. }
  118. }
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose:
  122. //-----------------------------------------------------------------------------
  123. void CTFHudPlayerClass::Reset()
  124. {
  125. m_flNextThink = gpGlobals->curtime + 0.05f;
  126. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HudSpyDisguiseHide" );
  127. }
  128. //-----------------------------------------------------------------------------
  129. // Purpose:
  130. //-----------------------------------------------------------------------------
  131. void CTFHudPlayerClass::ApplySchemeSettings( IScheme *pScheme )
  132. {
  133. // load control settings...
  134. LoadControlSettings( "resource/UI/HudPlayerClass.res" );
  135. m_nTeam = TEAM_UNASSIGNED;
  136. m_nClass = TF_CLASS_UNDEFINED;
  137. m_nDisguiseTeam = TEAM_UNASSIGNED;
  138. m_nDisguiseClass = TF_CLASS_UNDEFINED;
  139. m_hDisguiseWeapon = NULL;
  140. m_flNextThink = 0.0f;
  141. m_nCloakLevel = 0;
  142. m_nLoadoutPosition = LOADOUT_POSITION_PRIMARY;
  143. m_pClassImage = FindControl<CTFClassImage>( "PlayerStatusClassImage", false );
  144. m_pClassImageBG = FindControl<CTFImagePanel>( "PlayerStatusClassImageBG", false );
  145. m_pSpyImage = FindControl<CTFImagePanel>( "PlayerStatusSpyImage", false );
  146. m_pSpyOutlineImage = FindControl<CTFImagePanel>( "PlayerStatusSpyOutlineImage", false );
  147. m_pPlayerModelPanel = FindControl<CTFPlayerModelPanel>( "classmodelpanel", false );
  148. m_pPlayerModelPanelBG = FindControl<CTFImagePanel>( "classmodelpanelBG", false );
  149. m_pCarryingWeaponPanel = FindControl< EditablePanel >( "CarryingWeapon", false );
  150. if ( m_pCarryingWeaponPanel )
  151. {
  152. m_pCarryingLabel = m_pCarryingWeaponPanel->FindControl< CExLabel >( "CarryingLabel" );
  153. m_pCarryingOwnerLabel = m_pCarryingWeaponPanel->FindControl< Label >( "OwnerLabel" );
  154. m_pCarryingBG = m_pCarryingWeaponPanel->FindControl< CTFImagePanel >( "CarryingBackground" );
  155. }
  156. BaseClass::ApplySchemeSettings( pScheme );
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose:
  160. //-----------------------------------------------------------------------------
  161. void CTFHudPlayerClass::OnThink()
  162. {
  163. if ( m_flNextThink > gpGlobals->curtime )
  164. return;
  165. m_flNextThink = gpGlobals->curtime + 0.5f;
  166. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  167. if ( !pPlayer )
  168. return;
  169. bool bTeamChange = false;
  170. // set our background colors
  171. if ( m_nTeam != pPlayer->GetTeamNumber() )
  172. {
  173. bTeamChange = true;
  174. m_nTeam = pPlayer->GetTeamNumber();
  175. }
  176. int nCloakLevel = 0;
  177. bool bCloakChange = false;
  178. float flInvis = pPlayer->GetPercentInvisible();
  179. if ( flInvis > 0.9 )
  180. {
  181. nCloakLevel = 2;
  182. }
  183. else if ( flInvis > 0.1 )
  184. {
  185. nCloakLevel = 1;
  186. }
  187. if ( nCloakLevel != m_nCloakLevel )
  188. {
  189. m_nCloakLevel = nCloakLevel;
  190. bCloakChange = true;
  191. }
  192. bool bLoadoutPositionChange = false;
  193. int nLoadoutSlot = pPlayer->GetActiveTFWeapon() ? pPlayer->GetActiveTFWeapon()->GetAttributeContainer()->GetItem()->GetStaticData()->GetLoadoutSlot( m_nClass ) : LOADOUT_POSITION_PRIMARY;
  194. if ( m_nLoadoutPosition != nLoadoutSlot )
  195. {
  196. m_nLoadoutPosition = nLoadoutSlot;
  197. bLoadoutPositionChange = true;
  198. }
  199. bool bPlayerClassModeChange = false;
  200. if ( m_bUsePlayerModel != cl_hud_playerclass_use_playermodel.GetBool() )
  201. {
  202. m_bUsePlayerModel = cl_hud_playerclass_use_playermodel.GetBool();
  203. bPlayerClassModeChange = true;
  204. }
  205. #ifdef STAGING_ONLY
  206. if ( m_nLOD != cl_hud_playerclass_playermodel_lod.GetInt() && m_pPlayerModelPanel )
  207. {
  208. m_nLOD = cl_hud_playerclass_playermodel_lod.GetInt();
  209. m_pPlayerModelPanel->SetLOD( m_nLOD );
  210. }
  211. #endif // STAGING_ONLY
  212. bool bForceEyeUpdate = false;
  213. // set our class image
  214. if ( m_nClass != pPlayer->GetPlayerClass()->GetClassIndex() || bTeamChange || bCloakChange || bLoadoutPositionChange || bPlayerClassModeChange ||
  215. (
  216. m_nClass == TF_CLASS_SPY &&
  217. (
  218. m_nDisguiseClass != pPlayer->m_Shared.GetDisguiseClass() ||
  219. m_nDisguiseTeam != pPlayer->m_Shared.GetDisguiseTeam() ||
  220. m_hDisguiseWeapon != pPlayer->m_Shared.GetDisguiseWeapon()
  221. )
  222. )
  223. )
  224. {
  225. bForceEyeUpdate = true;
  226. m_nClass = pPlayer->GetPlayerClass()->GetClassIndex();
  227. if ( m_nClass == TF_CLASS_SPY && pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) )
  228. {
  229. if ( !pPlayer->m_Shared.InCond( TF_COND_DISGUISING ) )
  230. {
  231. m_nDisguiseTeam = pPlayer->m_Shared.GetDisguiseTeam();
  232. m_nDisguiseClass = pPlayer->m_Shared.GetDisguiseClass();
  233. m_hDisguiseWeapon = pPlayer->m_Shared.GetDisguiseWeapon();
  234. }
  235. }
  236. else
  237. {
  238. m_nDisguiseTeam = TEAM_UNASSIGNED;
  239. m_nDisguiseClass = TF_CLASS_UNDEFINED;
  240. m_hDisguiseWeapon = NULL;
  241. }
  242. if ( m_bUsePlayerModel && m_pPlayerModelPanel && m_pPlayerModelPanelBG )
  243. {
  244. m_pPlayerModelPanel->SetVisible( true );
  245. m_pPlayerModelPanelBG->SetVisible( true );
  246. UpdateModelPanel();
  247. }
  248. else if ( m_pClassImage && m_pSpyImage )
  249. {
  250. if ( m_pPlayerModelPanel )
  251. m_pPlayerModelPanel->SetVisible( false );
  252. if ( m_pPlayerModelPanelBG )
  253. m_pPlayerModelPanelBG->SetVisible( false );
  254. m_pClassImage->SetVisible( true );
  255. m_pClassImageBG->SetVisible( true );
  256. int iCloakState = 0;
  257. if ( pPlayer->IsPlayerClass( TF_CLASS_SPY ) )
  258. {
  259. iCloakState = m_nCloakLevel;
  260. }
  261. if ( m_nDisguiseTeam != TEAM_UNASSIGNED || m_nDisguiseClass != TF_CLASS_UNDEFINED )
  262. {
  263. m_pSpyImage->SetVisible( true );
  264. m_pClassImage->SetClass( m_nDisguiseTeam, m_nDisguiseClass, iCloakState );
  265. }
  266. else
  267. {
  268. m_pSpyImage->SetVisible( false );
  269. m_pClassImage->SetClass( m_nTeam, m_nClass, iCloakState );
  270. }
  271. }
  272. }
  273. if ( m_pCarryingWeaponPanel )
  274. {
  275. // Don't show if we're disguised (the panels overlap)
  276. bool bShowCarryingWeaponPanel = m_nDisguiseClass == TF_CLASS_UNDEFINED;
  277. if ( pPlayer->GetActiveTFWeapon() && pPlayer->GetActiveTFWeapon()->GetAttributeContainer() )
  278. {
  279. CEconItemView* pItem = pPlayer->GetActiveTFWeapon()->GetAttributeContainer()->GetItem();
  280. if ( pItem )
  281. {
  282. CSteamID playerSteamID;
  283. pPlayer->GetSteamID( &playerSteamID );
  284. // We're holding a weapon we dont own!
  285. if ( playerSteamID.GetAccountID() != pItem->GetAccountID() && m_pCarryingLabel )
  286. {
  287. locchar_t wszLocString [128];
  288. // Construct and set the weapon's name
  289. g_pVGuiLocalize->ConstructString_safe( wszLocString, L"%s1", 1, CEconItemLocalizedFullNameGenerator( GLocalizationProvider(), pItem->GetItemDefinition(), pItem->GetItemQuality() ).GetFullName() );
  290. m_pCarryingWeaponPanel->SetDialogVariable( "carrying", wszLocString );
  291. // Get and set the rarity color of the weapon
  292. const char* pszColorName = GetItemSchema()->GetRarityColor( pItem->GetItemDefinition()->GetRarity() );
  293. pszColorName = pszColorName ? pszColorName : "TanLight";
  294. if ( pszColorName )
  295. {
  296. m_pCarryingLabel->SetColorStr( pszColorName );
  297. }
  298. bool bHasOwner = false;
  299. locchar_t wszPlayerName [128];
  300. CBasePlayer *pOwner = GetPlayerByAccountID( pItem->GetAccountID() );
  301. // Bots will not work here, so don't fill this out if there's no owner
  302. if ( pOwner )
  303. {
  304. // Fill out the actual owner's name
  305. locchar_t wszStolenString[128];
  306. g_pVGuiLocalize->ConvertANSIToUnicode( pOwner->GetPlayerName(), wszPlayerName, sizeof(wszPlayerName) );
  307. g_pVGuiLocalize->ConstructString_safe( wszStolenString, g_pVGuiLocalize->Find( "TF_WhoDropped" ), 1, wszPlayerName );
  308. m_pCarryingOwnerLabel->SetText( wszStolenString );
  309. bHasOwner = true;
  310. }
  311. else
  312. {
  313. m_pCarryingOwnerLabel->SetText( "" );
  314. }
  315. int nMaxWide = 0, nMaxTall = 0;
  316. // Resize the panel to just be the width of whichever label is longer
  317. int nTall, nWide;
  318. m_pCarryingLabel->SizeToContents();
  319. m_pCarryingLabel->GetContentSize( nWide, nTall );
  320. nMaxWide = Max( nMaxWide, nWide );
  321. nMaxTall = Max( nMaxTall, nTall );
  322. m_pCarryingOwnerLabel->SizeToContents();
  323. m_pCarryingOwnerLabel->GetContentSize( nWide, nTall );
  324. nMaxWide = Max( nMaxWide, nWide );
  325. nMaxTall = Max( nMaxTall, nTall );
  326. m_pCarryingBG->SetWide( nMaxWide + ( m_pCarryingLabel->GetXPos() * 2 ) );
  327. m_pCarryingBG->SetTall( bHasOwner ? m_pCarryingOwnerLabel->GetYPos() + m_pCarryingOwnerLabel->GetTall() + YRES( 2 )
  328. : m_pCarryingLabel->GetYPos() + m_pCarryingLabel->GetTall() + YRES( 2 ) );
  329. }
  330. else
  331. {
  332. bShowCarryingWeaponPanel = false;
  333. }
  334. }
  335. }
  336. else
  337. {
  338. bShowCarryingWeaponPanel = false;
  339. }
  340. if ( CTFPlayerDestructionLogic::GetRobotDestructionLogic() && ( CTFPlayerDestructionLogic::GetRobotDestructionLogic()->GetType() == CTFPlayerDestructionLogic::TYPE_PLAYER_DESTRUCTION ) )
  341. {
  342. if ( pPlayer->HasTheFlag() )
  343. {
  344. bShowCarryingWeaponPanel = false;
  345. }
  346. }
  347. m_pCarryingWeaponPanel->SetVisible( bShowCarryingWeaponPanel );
  348. }
  349. if ( m_bUsePlayerModel && m_pPlayerModelPanel )
  350. {
  351. bool bPlaySparks = false;
  352. int iKillStreak = pPlayer->m_Shared.GetStreak( CTFPlayerShared::kTFStreak_Kills );
  353. if ( iKillStreak != m_nKillStreak && iKillStreak > 0 )
  354. {
  355. bPlaySparks = true;
  356. }
  357. m_nKillStreak = iKillStreak;
  358. m_pPlayerModelPanel->SetEyeGlowEffect( pPlayer->GetEyeGlowEffect(), pPlayer->GetEyeGlowColor( false ), pPlayer->GetEyeGlowColor( true ), bForceEyeUpdate, bPlaySparks );
  359. }
  360. }
  361. static void HudPlayerClassUsePlayerModelDialogCallback( bool bConfirmed, void *pContext )
  362. {
  363. cl_hud_playerclass_use_playermodel.SetValue( bConfirmed );
  364. }
  365. //-----------------------------------------------------------------------------
  366. // Purpose:
  367. //-----------------------------------------------------------------------------
  368. void CTFHudPlayerClass::UpdateModelPanel()
  369. {
  370. if ( !m_bUsePlayerModel )
  371. {
  372. return;
  373. }
  374. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  375. if ( !pPlayer || !pPlayer->IsAlive() )
  376. {
  377. return;
  378. }
  379. if ( !cl_hud_playerclass_playermodel_showed_confirm_dialog.GetBool() )
  380. {
  381. // only show this message one time
  382. ShowConfirmDialog( "#GameUI_HudPlayerClassUsePlayerModelDialogTitle",
  383. "#GameUI_HudPlayerClassUsePlayerModelDialogMessage",
  384. "#GameUI_HudPlayerClassUsePlayerModelDialogConfirm",
  385. "#GameUI_HudPlayerClassUsePlayerModelDialogCancel",
  386. &HudPlayerClassUsePlayerModelDialogCallback );
  387. cl_hud_playerclass_playermodel_showed_confirm_dialog.SetValue( true );
  388. }
  389. // hide old UI
  390. if ( m_pSpyImage )
  391. m_pSpyImage->SetVisible( false );
  392. if ( m_pClassImage )
  393. m_pClassImage->SetVisible( false );
  394. if ( m_pClassImageBG )
  395. m_pClassImageBG->SetVisible( false );
  396. if ( m_pPlayerModelPanel && m_pPlayerModelPanel->IsVisible() )
  397. {
  398. int nClass;
  399. int nTeam;
  400. int nItemSlot = m_nLoadoutPosition;
  401. CEconItemView *pWeapon = NULL;
  402. bool bDisguised = pPlayer->m_Shared.InCond( TF_COND_DISGUISED );
  403. if ( bDisguised )
  404. {
  405. nClass = pPlayer->m_Shared.GetDisguiseClass();
  406. nTeam = pPlayer->m_Shared.GetDisguiseTeam();
  407. if ( pPlayer->m_Shared.GetDisguiseWeapon() )
  408. {
  409. CAttributeContainer *pCont = pPlayer->m_Shared.GetDisguiseWeapon()->GetAttributeContainer();
  410. pWeapon = pCont ? pCont->GetItem() : NULL;
  411. if ( pWeapon )
  412. {
  413. nItemSlot = pWeapon->GetStaticData()->GetLoadoutSlot( nClass );
  414. }
  415. }
  416. }
  417. else
  418. {
  419. nClass = pPlayer->GetPlayerClass()->GetClassIndex();
  420. nTeam = pPlayer->GetTeamNumber();
  421. CTFWeaponBase *pEnt = dynamic_cast< CTFWeaponBase* >( pPlayer->GetEntityForLoadoutSlot( nItemSlot ) );
  422. if ( pEnt )
  423. {
  424. pWeapon = pEnt->GetAttributeContainer()->GetItem();
  425. }
  426. }
  427. bool bIsRobot = false;
  428. int iRobot = 0;
  429. CALL_ATTRIB_HOOK_INT_ON_OTHER( pPlayer, iRobot, appear_as_mvm_robot );
  430. bIsRobot = iRobot ? true : false;
  431. m_pPlayerModelPanel->ClearCarriedItems();
  432. m_pPlayerModelPanel->SetToPlayerClass( nClass, bIsRobot );
  433. m_pPlayerModelPanel->SetTeam( nTeam );
  434. if ( pWeapon )
  435. {
  436. m_pPlayerModelPanel->AddCarriedItem( pWeapon );
  437. }
  438. for ( int wbl = pPlayer->GetNumWearables()-1; wbl >= 0; wbl-- )
  439. {
  440. C_TFWearable *pItem = dynamic_cast<C_TFWearable*>( pPlayer->GetWearable( wbl ) );
  441. if ( !pItem )
  442. continue;
  443. if ( pItem->IsViewModelWearable() )
  444. continue;
  445. if ( pItem->IsDisguiseWearable() && !bDisguised )
  446. continue;
  447. if ( !pItem->IsDisguiseWearable() && bDisguised )
  448. continue;
  449. CAttributeContainer *pCont = pItem->GetAttributeContainer();
  450. CEconItemView *pEconItemView = pCont ? pCont->GetItem() : NULL;
  451. if ( pEconItemView && pEconItemView->IsValid() )
  452. {
  453. m_pPlayerModelPanel->AddCarriedItem( pEconItemView );
  454. }
  455. }
  456. m_pPlayerModelPanel->HoldItemInSlot( nItemSlot );
  457. }
  458. }
  459. //-----------------------------------------------------------------------------
  460. // Purpose:
  461. //-----------------------------------------------------------------------------
  462. void CTFHudPlayerClass::FireGameEvent( IGameEvent * event )
  463. {
  464. const char* pszEventName = event->GetName();
  465. if ( FStrEq( "localplayer_changedisguise", pszEventName ) )
  466. {
  467. if ( m_pSpyImage && m_pSpyOutlineImage )
  468. {
  469. bool bFadeIn = event->GetBool( "disguised", false );
  470. if ( bFadeIn )
  471. {
  472. m_pSpyImage->SetAlpha( 0 );
  473. }
  474. else
  475. {
  476. m_pSpyImage->SetAlpha( 255 );
  477. }
  478. m_pSpyOutlineImage->SetAlpha( 0 );
  479. m_pSpyImage->SetVisible( true );
  480. m_pSpyOutlineImage->SetVisible( true );
  481. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( bFadeIn ? "HudSpyDisguiseFadeIn" : "HudSpyDisguiseFadeOut" );
  482. }
  483. UpdateModelPanel();
  484. }
  485. else if ( FStrEq( "post_inventory_application", pszEventName ) )
  486. {
  487. // Force a refresh. if this is for the local player
  488. int iUserID = event->GetInt( "userid" );
  489. C_TFPlayer* pPlayer = ToTFPlayer( C_TFPlayer::GetLocalPlayer() );
  490. if ( pPlayer && pPlayer->GetUserID() == iUserID )
  491. {
  492. UpdateModelPanel();
  493. }
  494. }
  495. else if ( FStrEq( "localplayer_pickup_weapon", pszEventName ) )
  496. {
  497. UpdateModelPanel();
  498. }
  499. }
  500. //-----------------------------------------------------------------------------
  501. // Purpose:
  502. //-----------------------------------------------------------------------------
  503. CTFHealthPanel::CTFHealthPanel( Panel *parent, const char *name ) : vgui::Panel( parent, name )
  504. {
  505. m_flHealth = 1.0f;
  506. m_iMaterialIndex = surface()->DrawGetTextureId( "hud/health_color" );
  507. if ( m_iMaterialIndex == -1 ) // we didn't find it, so create a new one
  508. {
  509. m_iMaterialIndex = surface()->CreateNewTextureID();
  510. surface()->DrawSetTextureFile( m_iMaterialIndex, "hud/health_color", true, false );
  511. }
  512. m_iDeadMaterialIndex = surface()->DrawGetTextureId( "hud/health_dead" );
  513. if ( m_iDeadMaterialIndex == -1 ) // we didn't find it, so create a new one
  514. {
  515. m_iDeadMaterialIndex = surface()->CreateNewTextureID();
  516. surface()->DrawSetTextureFile( m_iDeadMaterialIndex, "hud/health_dead", true, false );
  517. }
  518. }
  519. //-----------------------------------------------------------------------------
  520. // Purpose:
  521. //-----------------------------------------------------------------------------
  522. void CTFHealthPanel::Paint()
  523. {
  524. BaseClass::Paint();
  525. int x, y, w, h;
  526. GetBounds( x, y, w, h );
  527. Vertex_t vert[4];
  528. float uv1 = 0.0f;
  529. float uv2 = 1.0f;
  530. int xpos = 0, ypos = 0;
  531. if ( m_flHealth <= 0 )
  532. {
  533. // Draw the dead material
  534. surface()->DrawSetTexture( m_iDeadMaterialIndex );
  535. vert[0].Init( Vector2D( xpos, ypos ), Vector2D( uv1, uv1 ) );
  536. vert[1].Init( Vector2D( xpos + w, ypos ), Vector2D( uv2, uv1 ) );
  537. vert[2].Init( Vector2D( xpos + w, ypos + h ), Vector2D( uv2, uv2 ) );
  538. vert[3].Init( Vector2D( xpos, ypos + h ), Vector2D( uv1, uv2 ) );
  539. surface()->DrawSetColor( Color(255,255,255,255) );
  540. }
  541. else
  542. {
  543. float flDamageY = h * ( 1.0f - m_flHealth );
  544. // blend in the red "damage" part
  545. surface()->DrawSetTexture( m_iMaterialIndex );
  546. Vector2D uv11( uv1, uv2 - m_flHealth );
  547. Vector2D uv21( uv2, uv2 - m_flHealth );
  548. Vector2D uv22( uv2, uv2 );
  549. Vector2D uv12( uv1, uv2 );
  550. vert[0].Init( Vector2D( xpos, flDamageY ), uv11 );
  551. vert[1].Init( Vector2D( xpos + w, flDamageY ), uv21 );
  552. vert[2].Init( Vector2D( xpos + w, ypos + h ), uv22 );
  553. vert[3].Init( Vector2D( xpos, ypos + h ), uv12 );
  554. surface()->DrawSetColor( GetFgColor() );
  555. }
  556. surface()->DrawTexturedPolygon( 4, vert );
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Purpose:
  560. //-----------------------------------------------------------------------------
  561. CTFHudPlayerHealth::CTFHudPlayerHealth( Panel *parent, const char *name ) : EditablePanel( parent, name )
  562. {
  563. m_pHealthImage = new CTFHealthPanel( this, "PlayerStatusHealthImage" );
  564. m_pHealthImageBG = new ImagePanel( this, "PlayerStatusHealthImageBG" );
  565. m_pHealthBonusImage = new ImagePanel( this, "PlayerStatusHealthBonusImage" );
  566. m_pBuildingHealthImageBG = new ImagePanel( this, "BuildingStatusHealthImageBG" );
  567. m_pBleedImage = new ImagePanel( this, "PlayerStatusBleedImage" );
  568. m_pHookBleedImage = new ImagePanel( this, "PlayerStatusHookBleedImage" );
  569. m_pMarkedForDeathImage = new ImagePanel( this, "PlayerStatusMarkedForDeathImage" );
  570. m_pMarkedForDeathImageSilent = new ImagePanel( this, "PlayerStatusMarkedForDeathSilentImage" );
  571. m_pMilkImage = new ImagePanel( this, "PlayerStatusMilkImage" );
  572. m_pWheelOfDoomImage = new ImagePanel( this, "PlayerStatus_WheelOfDoom" );
  573. m_flNextThink = 0.0f;
  574. m_nBonusHealthOrigX = -1;
  575. m_nBonusHealthOrigY = -1;
  576. m_nBonusHealthOrigW = -1;
  577. m_nBonusHealthOrigH = -1;
  578. // Vaccinator
  579. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_UBER_BULLET_RESIST, BUFF_CLASS_BULLET_RESIST, new ImagePanel( this, "PlayerStatus_MedicUberBulletResistImage" ), "../HUD/defense_buff_bullet_blue", "../HUD/defense_buff_bullet_red" ) );
  580. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_UBER_BLAST_RESIST, BUFF_CLASS_BLAST_RESIST, new ImagePanel( this, "PlayerStatus_MedicUberBlastResistImage" ), "../HUD/defense_buff_explosion_blue", "../HUD/defense_buff_explosion_red" ) );
  581. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_UBER_FIRE_RESIST, BUFF_CLASS_FIRE_RESIST, new ImagePanel( this, "PlayerStatus_MedicUberFireResistImage" ), "../HUD/defense_buff_fire_blue", "../HUD/defense_buff_fire_red" ) );
  582. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_SMALL_BULLET_RESIST, BUFF_CLASS_BULLET_RESIST, new ImagePanel( this, "PlayerStatus_MedicSmallBulletResistImage" ), "../HUD/defense_buff_bullet_blue", "../HUD/defense_buff_bullet_red" ) );
  583. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_SMALL_BLAST_RESIST, BUFF_CLASS_BLAST_RESIST, new ImagePanel( this, "PlayerStatus_MedicSmallBlastResistImage" ), "../HUD/defense_buff_explosion_blue", "../HUD/defense_buff_explosion_red" ) );
  584. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_MEDIGUN_SMALL_FIRE_RESIST, BUFF_CLASS_FIRE_RESIST, new ImagePanel( this, "PlayerStatus_MedicSmallFireResistImage" ), "../HUD/defense_buff_fire_blue", "../HUD/defense_buff_fire_red" ) );
  585. // Soldier buffs
  586. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_OFFENSEBUFF, BUFF_CLASS_SOLDIER_OFFENSE, new ImagePanel( this, "PlayerStatus_SoldierOffenseBuff" ), "../Effects/soldier_buff_offense_blue", "../Effects/soldier_buff_offense_red" ) );
  587. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_DEFENSEBUFF, BUFF_CLASS_SOLDIER_DEFENSE, new ImagePanel( this, "PlayerStatus_SoldierDefenseBuff" ), "../Effects/soldier_buff_defense_blue", "../Effects/soldier_buff_defense_red" ) );
  588. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_REGENONDAMAGEBUFF, BUFF_CLASS_SOLDIER_HEALTHONHIT, new ImagePanel( this, "PlayerStatus_SoldierHealOnHitBuff" ), "../Effects/soldier_buff_healonhit_blue", "../Effects/soldier_buff_healonhit_red" ) );
  589. // Powerup Rune status
  590. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_STRENGTH, RUNE_CLASS_STRENGTH, new ImagePanel( this, "PlayerStatus_RuneStrength" ), "../Effects/powerup_strength_hud", "../Effects/powerup_strength_hud" ) );
  591. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_HASTE, RUNE_CLASS_HASTE, new ImagePanel( this, "PlayerStatus_RuneHaste" ), "../Effects/powerup_haste_hud", "../Effects/powerup_haste_hud" ) );
  592. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_REGEN, RUNE_CLASS_REGEN, new ImagePanel( this, "PlayerStatus_RuneRegen" ), "../Effects/powerup_regen_hud", "../Effects/powerup_regen_hud" ) );
  593. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_RESIST, RUNE_CLASS_RESIST, new ImagePanel( this, "PlayerStatus_RuneResist" ), "../Effects/powerup_resist_hud", "../Effects/powerup_resist_hud" ) );
  594. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_VAMPIRE, RUNE_CLASS_VAMPIRE, new ImagePanel( this, "PlayerStatus_RuneVampire" ), "../Effects/powerup_vampire_hud", "../Effects/powerup_vampire_hud" ) );
  595. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_REFLECT, RUNE_CLASS_REFLECT, new ImagePanel( this, "PlayerStatus_RuneReflect" ), "../Effects/powerup_reflect_hud", "../Effects/powerup_reflect_hud" ) );
  596. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_PRECISION, RUNE_CLASS_PRECISION, new ImagePanel( this, "PlayerStatus_RunePrecision" ), "../Effects/powerup_precision_hud", "../Effects/powerup_precision_hud" ) );
  597. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_AGILITY, RUNE_CLASS_AGILITY, new ImagePanel( this, "PlayerStatus_RuneAgility" ), "../Effects/powerup_agility_hud", "../Effects/powerup_agility_hud" ) );
  598. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_KNOCKOUT, RUNE_CLASS_KNOCKOUT, new ImagePanel( this, "PlayerStatus_RuneKnockout" ), "../Effects/powerup_knockout_hud", "../Effects/powerup_knockout_hud" ) );
  599. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_KING, RUNE_CLASS_KING, new ImagePanel( this, "PlayerStatus_RuneKing" ), "../Effects/powerup_king_hud", "../Effects/powerup_king_hud" ) );
  600. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_PLAGUE, RUNE_CLASS_PLAGUE, new ImagePanel( this, "PlayerStatus_RunePlague" ), "../Effects/powerup_plague_hud", "../Effects/powerup_plague_hud" ) );
  601. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_RUNE_SUPERNOVA, RUNE_CLASS_SUPERNOVA, new ImagePanel( this, "PlayerStatus_RuneSupernova" ), "../Effects/powerup_supernova_hud", "../Effects/powerup_supernova_hud" ) );
  602. #ifdef STAGING_ONLY
  603. // Spy Mark
  604. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_TRANQ_MARKED, DEBUFF_CLASS_SPY_MARKED, new ImagePanel( this, "PlayerStatus_SpyMarked" ), "../Effects/tranq_debuff", "../Effects/tranq_debuff" ) );
  605. #endif // STAGING_ONLY
  606. // Parachute
  607. m_vecBuffInfo.AddToTail( new CTFBuffInfo( TF_COND_PARACHUTE_DEPLOYED, BUFF_CLASS_PARACHUTE, new ImagePanel( this, "PlayerStatus_Parachute" ), "../HUD/hud_parachute_active", "../HUD/hud_parachute_active" ) );
  608. m_iAnimState = HUD_HEALTH_NO_ANIM;
  609. m_bAnimate = true;
  610. }
  611. CTFHudPlayerHealth::~CTFHudPlayerHealth()
  612. {
  613. m_vecBuffInfo.PurgeAndDeleteElements();
  614. }
  615. //-----------------------------------------------------------------------------
  616. // Purpose:
  617. //-----------------------------------------------------------------------------
  618. void CTFHudPlayerHealth::Reset()
  619. {
  620. m_flNextThink = gpGlobals->curtime + 0.05f;
  621. m_nHealth = -1;
  622. m_bBuilding = false;
  623. m_iAnimState = HUD_HEALTH_NO_ANIM;
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Purpose:
  627. //-----------------------------------------------------------------------------
  628. void CTFHudPlayerHealth::ApplySchemeSettings( IScheme *pScheme )
  629. {
  630. // load control settings...
  631. LoadControlSettings( GetResFilename() );
  632. if ( m_pHealthBonusImage )
  633. {
  634. m_pHealthBonusImage->GetBounds( m_nBonusHealthOrigX, m_nBonusHealthOrigY, m_nBonusHealthOrigW, m_nBonusHealthOrigH );
  635. }
  636. m_flNextThink = 0.0f;
  637. BaseClass::ApplySchemeSettings( pScheme );
  638. m_pBuildingHealthImageBG->SetVisible( m_bBuilding );
  639. m_pPlayerLevelLabel = dynamic_cast<CExLabel*>( FindChildByName( "PlayerStatusPlayerLevel" ) );
  640. }
  641. //-----------------------------------------------------------------------------
  642. // Purpose:
  643. //-----------------------------------------------------------------------------
  644. void CTFHudPlayerHealth::SetHealth( int iNewHealth, int iMaxHealth, int iMaxBuffedHealth )
  645. {
  646. // set our health
  647. m_nHealth = iNewHealth;
  648. m_nMaxHealth = iMaxHealth;
  649. m_pHealthImage->SetHealth( (float)(m_nHealth) / (float)(m_nMaxHealth) );
  650. if ( m_pHealthImage )
  651. {
  652. m_pHealthImage->SetFgColor( Color( 255, 255, 255, 255 ) );
  653. }
  654. if ( m_nHealth <= 0 )
  655. {
  656. if ( m_pHealthImageBG->IsVisible() )
  657. {
  658. m_pHealthImageBG->SetVisible( false );
  659. }
  660. if ( m_pBuildingHealthImageBG->IsVisible() )
  661. {
  662. m_pBuildingHealthImageBG->SetVisible( false );
  663. }
  664. HideHealthBonusImage();
  665. }
  666. else
  667. {
  668. if ( !m_pHealthImageBG->IsVisible() )
  669. {
  670. m_pHealthImageBG->SetVisible( true );
  671. }
  672. m_pBuildingHealthImageBG->SetVisible( m_bBuilding );
  673. // are we getting a health bonus?
  674. if ( m_nHealth > m_nMaxHealth )
  675. {
  676. if ( m_pHealthBonusImage && m_nBonusHealthOrigW != -1 )
  677. {
  678. if ( !m_pHealthBonusImage->IsVisible() )
  679. {
  680. m_pHealthBonusImage->SetVisible( true );
  681. }
  682. if ( m_bAnimate && m_iAnimState != HUD_HEALTH_BONUS_ANIM )
  683. {
  684. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthDyingPulseStop" );
  685. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthBonusPulse" );
  686. m_iAnimState = HUD_HEALTH_BONUS_ANIM;
  687. }
  688. m_pHealthBonusImage->SetDrawColor( Color( 255, 255, 255, 255 ) );
  689. // scale the flashing image based on how much health bonus we currently have
  690. float flBoostMaxAmount = ( iMaxBuffedHealth ) - m_nMaxHealth;
  691. float flPercent = MIN( ( m_nHealth - m_nMaxHealth ) / flBoostMaxAmount, 1.0f );
  692. int nPosAdj = RoundFloatToInt( flPercent * m_nHealthBonusPosAdj );
  693. int nSizeAdj = 2 * nPosAdj;
  694. m_pHealthBonusImage->SetBounds( m_nBonusHealthOrigX - nPosAdj,
  695. m_nBonusHealthOrigY - nPosAdj,
  696. m_nBonusHealthOrigW + nSizeAdj,
  697. m_nBonusHealthOrigH + nSizeAdj );
  698. }
  699. }
  700. // are we close to dying?
  701. else if ( m_nHealth < m_nMaxHealth * m_flHealthDeathWarning )
  702. {
  703. if ( m_pHealthBonusImage && m_nBonusHealthOrigW != -1 )
  704. {
  705. if ( !m_pHealthBonusImage->IsVisible() )
  706. {
  707. m_pHealthBonusImage->SetVisible( true );
  708. }
  709. if ( m_bAnimate && m_iAnimState != HUD_HEALTH_DYING_ANIM )
  710. {
  711. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthBonusPulseStop" );
  712. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthDyingPulse" );
  713. m_iAnimState = HUD_HEALTH_DYING_ANIM;
  714. }
  715. m_pHealthBonusImage->SetDrawColor( m_clrHealthDeathWarningColor );
  716. // scale the flashing image based on how much health bonus we currently have
  717. float flBoostMaxAmount = m_nMaxHealth * m_flHealthDeathWarning;
  718. float flPercent = ( flBoostMaxAmount - m_nHealth ) / flBoostMaxAmount;
  719. int nPosAdj = RoundFloatToInt( flPercent * m_nHealthBonusPosAdj );
  720. int nSizeAdj = 2 * nPosAdj;
  721. m_pHealthBonusImage->SetBounds( m_nBonusHealthOrigX - nPosAdj,
  722. m_nBonusHealthOrigY - nPosAdj,
  723. m_nBonusHealthOrigW + nSizeAdj,
  724. m_nBonusHealthOrigH + nSizeAdj );
  725. }
  726. if ( m_pHealthImage )
  727. {
  728. m_pHealthImage->SetFgColor( m_clrHealthDeathWarningColor );
  729. }
  730. }
  731. // turn it off
  732. else
  733. {
  734. HideHealthBonusImage();
  735. }
  736. }
  737. // set our health display value
  738. if ( m_nHealth > 0 )
  739. {
  740. SetDialogVariable( "Health", m_nHealth );
  741. }
  742. else
  743. {
  744. SetDialogVariable( "Health", "" );
  745. }
  746. }
  747. //-----------------------------------------------------------------------------
  748. // Purpose:
  749. //-----------------------------------------------------------------------------
  750. void CTFHudPlayerHealth::SetLevel( int nLevel )
  751. {
  752. if ( m_pPlayerLevelLabel )
  753. {
  754. bool bVisible = ( nLevel >= 0 ) ? true : false;
  755. if ( bVisible )
  756. {
  757. m_pPlayerLevelLabel->SetText( CFmtStr( "%d", nLevel ) );
  758. }
  759. if ( m_pPlayerLevelLabel->IsVisible() != bVisible )
  760. {
  761. m_pPlayerLevelLabel->SetVisible( bVisible );
  762. }
  763. }
  764. };
  765. //-----------------------------------------------------------------------------
  766. // Purpose:
  767. //-----------------------------------------------------------------------------
  768. void CTFHudPlayerHealth::HideHealthBonusImage( void )
  769. {
  770. if ( m_pHealthBonusImage && m_pHealthBonusImage->IsVisible() )
  771. {
  772. if ( m_nBonusHealthOrigW != -1 )
  773. {
  774. m_pHealthBonusImage->SetBounds( m_nBonusHealthOrigX, m_nBonusHealthOrigY, m_nBonusHealthOrigW, m_nBonusHealthOrigH );
  775. }
  776. m_pHealthBonusImage->SetVisible( false );
  777. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthBonusPulseStop" );
  778. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "HudHealthDyingPulseStop" );
  779. m_iAnimState = HUD_HEALTH_NO_ANIM;
  780. }
  781. }
  782. //-----------------------------------------------------------------------------
  783. // Purpose:
  784. //-----------------------------------------------------------------------------
  785. static void SetPlayerHealthImagePanelVisibility( CTFPlayer *pPlayer, ETFCond eCond, vgui::ImagePanel *pImagePanel, int& nXOffset, const Color& colorIfVisible )
  786. {
  787. Assert( pImagePanel != NULL );
  788. if ( pPlayer->m_Shared.InCond( eCond ) && !pImagePanel->IsVisible() )
  789. {
  790. pImagePanel->SetVisible( true );
  791. pImagePanel->SetDrawColor( colorIfVisible );
  792. // Reposition ourselves and increase the offset if we are active
  793. int x,y;
  794. pImagePanel->GetPos( x, y );
  795. pImagePanel->SetPos( nXOffset, y );
  796. nXOffset += 100.f;
  797. }
  798. }
  799. void CTFBuffInfo::Update( CTFPlayer *pPlayer )
  800. {
  801. Assert( m_pImagePanel != NULL && pPlayer != NULL );
  802. if ( pPlayer->m_Shared.InCond( m_eCond ) )
  803. {
  804. if( m_pzsBlueImage && m_pzsBlueImage[0] && m_pzsRedImage && m_pzsRedImage[0] )
  805. {
  806. if( pPlayer->GetTeamNumber() == TF_TEAM_BLUE )
  807. m_pImagePanel->SetImage( m_pzsBlueImage );
  808. else
  809. m_pImagePanel->SetImage( m_pzsRedImage );
  810. }
  811. }
  812. }
  813. void CTFHudPlayerHealth::OnThink()
  814. {
  815. if ( m_flNextThink < gpGlobals->curtime )
  816. {
  817. C_TFPlayer *pPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
  818. if ( pPlayer )
  819. {
  820. SetHealth( pPlayer->GetHealth(), pPlayer->GetMaxHealth(), pPlayer->m_Shared.GetMaxBuffedHealth() );
  821. int color_offset = ((int)(gpGlobals->realtime*10)) % 5;
  822. int color_fade = 160 + (color_offset*10);
  823. // Find our starting point, just above the health '+'
  824. int nXOffset,y;
  825. m_pHealthImage->GetPos( nXOffset, y );
  826. // Nudge over a bit to get centered
  827. nXOffset += 25;
  828. // Turn all the panels off, and below conditionally turn them on
  829. FOR_EACH_VEC( m_vecBuffInfo, i )
  830. {
  831. m_vecBuffInfo[ i ]->m_pImagePanel->SetVisible( false );
  832. }
  833. CUtlVector<BuffClass_t> m_vecActiveClasses;
  834. // Cycle through all the buffs and update them
  835. FOR_EACH_VEC( m_vecBuffInfo, i )
  836. {
  837. // Skip if this class of buff is already being drawn
  838. if( m_vecActiveClasses.Find( m_vecBuffInfo[i]->m_eClass ) != m_vecActiveClasses.InvalidIndex() )
  839. continue;
  840. m_vecBuffInfo[i]->Update( pPlayer );
  841. SetPlayerHealthImagePanelVisibility( pPlayer, m_vecBuffInfo[i]->m_eCond, m_vecBuffInfo[i]->m_pImagePanel, nXOffset, Color( 255, 255, 255, color_fade ) );
  842. // This class of buff is now active.
  843. if( m_vecBuffInfo[i]->m_pImagePanel->IsVisible() )
  844. {
  845. m_vecActiveClasses.AddToTail( m_vecBuffInfo[i]->m_eClass );
  846. }
  847. }
  848. // Turn all the panels off, and below conditionally turn them on
  849. m_pBleedImage->SetVisible( false );
  850. m_pHookBleedImage->SetVisible( false );
  851. m_pMilkImage->SetVisible( false );
  852. m_pMarkedForDeathImage->SetVisible( false );
  853. m_pMarkedForDeathImageSilent->SetVisible( false );
  854. // Old method for goofy color manipulation
  855. int nBloodX = nXOffset;
  856. SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_BLEEDING, m_pBleedImage, nXOffset, Color( color_fade, 0, 0, 255 ) );
  857. SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_GRAPPLINGHOOK_BLEEDING, m_pHookBleedImage, nBloodX, Color( 255, 255, 255, 255 ) ); // draw this on top of bleeding
  858. SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_MAD_MILK, m_pMilkImage, nXOffset, Color( color_fade, color_fade, color_fade, 255 ) );
  859. SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_MARKEDFORDEATH, m_pMarkedForDeathImage, nXOffset, Color( 255 - color_fade, 245 - color_fade, 245 - color_fade, 255 ) );
  860. SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_MARKEDFORDEATH_SILENT, m_pMarkedForDeathImageSilent, nXOffset, Color( 125 - color_fade, 255 - color_fade, 255 - color_fade, 255 ) );
  861. SetPlayerHealthImagePanelVisibility( pPlayer, TF_COND_PASSTIME_PENALTY_DEBUFF, m_pMarkedForDeathImageSilent, nXOffset, Color( 125 - color_fade, 255 - color_fade, 255 - color_fade, 255 ) );
  862. UpdateHalloweenStatus();
  863. }
  864. m_flNextThink = gpGlobals->curtime + 0.05f;
  865. }
  866. }
  867. void CTFHudPlayerHealth::UpdateHalloweenStatus( void )
  868. {
  869. if ( TFGameRules()->IsHalloweenEffectStatusActive() )
  870. {
  871. int status = TFGameRules()->GetHalloweenEffectStatus();
  872. if ( status == EFFECT_WHAMMY )
  873. {
  874. m_pWheelOfDoomImage->SetImage( "..\\HUD\\death_wheel_whammy" );
  875. }
  876. else
  877. {
  878. m_pWheelOfDoomImage->SetImage( VarArgs( "..\\HUD\\death_wheel_%d", status - 1 ) );
  879. }
  880. float timeLeft = TFGameRules()->GetHalloweenEffectTimeLeft();
  881. const float warnExpireTime = 3.0f;
  882. const float blinkInterval = 0.25f;
  883. if ( timeLeft < warnExpireTime )
  884. {
  885. int blink = (int)( timeLeft / blinkInterval );
  886. m_pWheelOfDoomImage->SetVisible( blink & 0x1 );
  887. }
  888. else
  889. {
  890. m_pWheelOfDoomImage->SetVisible( true );
  891. }
  892. }
  893. else
  894. {
  895. m_pWheelOfDoomImage->SetVisible( false );
  896. }
  897. }
  898. DECLARE_HUDELEMENT( CTFHudPlayerStatus );
  899. //-----------------------------------------------------------------------------
  900. // Purpose:
  901. //-----------------------------------------------------------------------------
  902. CTFHudPlayerStatus::CTFHudPlayerStatus( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, "HudPlayerStatus" )
  903. {
  904. Panel *pParent = g_pClientMode->GetViewport();
  905. SetParent( pParent );
  906. m_pHudPlayerClass = new CTFHudPlayerClass( this, "HudPlayerClass" );
  907. m_pHudPlayerHealth = new CTFHudPlayerHealth( this, "HudPlayerHealth" );
  908. SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD );
  909. }
  910. //-----------------------------------------------------------------------------
  911. // Purpose:
  912. //-----------------------------------------------------------------------------
  913. void CTFHudPlayerStatus::ApplySchemeSettings( IScheme *pScheme )
  914. {
  915. BaseClass::ApplySchemeSettings( pScheme );
  916. // HACK: Work around the scheme application order failing
  917. // to reload the player class hud element's scheme in minmode.
  918. static ConVarRef cl_hud_minmode( "cl_hud_minmode", true );
  919. if ( cl_hud_minmode.IsValid() && cl_hud_minmode.GetBool() )
  920. {
  921. m_pHudPlayerClass->InvalidateLayout( false, true );
  922. }
  923. }
  924. //-----------------------------------------------------------------------------
  925. // Purpose:
  926. //-----------------------------------------------------------------------------
  927. bool CTFHudPlayerStatus::ShouldDraw( void )
  928. {
  929. CTFPlayer *pTFPlayer = CTFPlayer::GetLocalTFPlayer();
  930. if ( pTFPlayer && pTFPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
  931. return false;
  932. if ( CTFMinigameLogic::GetMinigameLogic() && CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame() )
  933. return false;
  934. if ( TFGameRules() && TFGameRules()->ShowMatchSummary() )
  935. return false;
  936. return CHudElement::ShouldDraw();
  937. }
  938. //-----------------------------------------------------------------------------
  939. // Purpose:
  940. //-----------------------------------------------------------------------------
  941. void CTFHudPlayerStatus::Reset()
  942. {
  943. if ( m_pHudPlayerClass )
  944. {
  945. m_pHudPlayerClass->Reset();
  946. }
  947. if ( m_pHudPlayerHealth )
  948. {
  949. m_pHudPlayerHealth->Reset();
  950. }
  951. }
  952. //-----------------------------------------------------------------------------
  953. // Purpose:
  954. //-----------------------------------------------------------------------------
  955. void CTFClassImage::SetClass( int iTeam, int iClass, int iCloakstate )
  956. {
  957. char szImage[128];
  958. szImage[0] = '\0';
  959. if ( iTeam == TF_TEAM_BLUE )
  960. {
  961. Q_strncpy( szImage, g_szBlueClassImages[ iClass ], sizeof(szImage) );
  962. }
  963. else
  964. {
  965. Q_strncpy( szImage, g_szRedClassImages[ iClass ], sizeof(szImage) );
  966. }
  967. switch( iCloakstate )
  968. {
  969. case 2:
  970. Q_strncat( szImage, "_cloak", sizeof(szImage), COPY_ALL_CHARACTERS );
  971. break;
  972. case 1:
  973. Q_strncat( szImage, "_halfcloak", sizeof(szImage), COPY_ALL_CHARACTERS );
  974. break;
  975. default:
  976. break;
  977. }
  978. if ( Q_strlen( szImage ) > 0 )
  979. {
  980. SetImage( szImage );
  981. }
  982. }