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.

411 lines
10 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "hud.h"
  9. #include "c_team.h"
  10. #include "tf_shareddefs.h"
  11. #include "tf_gamerules.h"
  12. #include "tf_hud_objectivestatus.h"
  13. #include "tf_hud_statpanel.h"
  14. #include "iclientmode.h"
  15. #include "c_playerresource.h"
  16. #include "tf_hud_building_status.h"
  17. #include "tf_hud_mann_vs_machine_status.h"
  18. #include "tf_hud_tournament.h"
  19. #include "tf_hud_winpanel.h"
  20. #include "tf_tips.h"
  21. #include "tf_mapinfomenu.h"
  22. #include "econ_wearable.h"
  23. #include "c_tf_playerresource.h"
  24. #include "playerspawncache.h"
  25. #include "econ_notifications.h"
  26. #include <spectatorgui.h>
  27. #include "hudelement.h"
  28. #include "tf_spectatorgui.h"
  29. #include "tf_hud_playerstatus.h"
  30. #include "item_model_panel.h"
  31. #include "tf_gamerules.h"
  32. #include "tf_playerpanel.h"
  33. #include "tf_gc_client.h"
  34. #include "tf_lobby_server.h"
  35. #include <vgui/ILocalize.h>
  36. #include <vgui/ISurface.h>
  37. #include <VGuiMatSurface/IMatSystemSurface.h>
  38. #include "vgui_avatarimage.h"
  39. using namespace vgui;
  40. extern ConVar tf_max_health_boost;
  41. //-----------------------------------------------------------------------------
  42. // Purpose:
  43. //-----------------------------------------------------------------------------
  44. CTFPlayerPanel::CTFPlayerPanel( vgui::Panel *parent, const char *name ) : vgui::EditablePanel( parent, name )
  45. {
  46. m_pHealthIcon = new CTFPlayerPanelGUIHealth( this, "HealthIcon" );
  47. m_pClassImage = NULL;
  48. m_bPlayerReadyModeActive = false;
  49. m_pReadyBG = new ScalableImagePanel( this , "ReadyBG" );
  50. m_pReadyImage = new ImagePanel( this, "ReadyImage" );
  51. SetDialogVariable( "chargeamount", "" );
  52. }
  53. //-----------------------------------------------------------------------------
  54. // Purpose:
  55. //-----------------------------------------------------------------------------
  56. void CTFPlayerPanel::Reset( void )
  57. {
  58. m_pHealthIcon->Reset();
  59. m_iPrevHealth = -999;
  60. m_iPrevClass = -999;
  61. m_bPrevAlive = false;
  62. m_iPrevRespawnWait = -999;
  63. m_iPrevCharge = -1;
  64. m_bPrevReady = true;
  65. m_iPrevState = GR_STATE_PREGAME;
  66. m_bPlayerReadyModeActive = false;
  67. m_nGCTeam = TEAM_INVALID;
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose:
  71. //-----------------------------------------------------------------------------
  72. bool CTFPlayerPanel::Update( void )
  73. {
  74. if ( !g_TF_PR || !TFGameRules() )
  75. return false;
  76. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  77. if ( !pLocalPlayer )
  78. return false;
  79. bool bChanged = false;
  80. bool bObserver = pLocalPlayer->GetObserverMode() != OBS_MODE_NONE;
  81. bool bVisible = GetTeam() >= FIRST_GAME_TEAM;
  82. int iRespawnWait = -1;
  83. m_bPlayerReadyModeActive = ( !bObserver &&
  84. TFGameRules()->UsePlayerReadyStatusMode() &&
  85. TFGameRules()->State_Get() == GR_STATE_BETWEEN_RNDS );
  86. CTFGSLobby *pLobby = GTFGCClientSystem()->GetLobby();
  87. if ( pLobby )
  88. {
  89. const CTFLobbyMember *pMember = pLobby->GetMemberDetails( m_steamID );
  90. if ( pMember )
  91. {
  92. // Keep this updated
  93. m_nGCTeam = pMember->team();
  94. if ( !m_iPlayerIndex && pMember->has_last_connect_time() )
  95. {
  96. iRespawnWait = CRTime::RTime32DateAdd( pMember->last_connect_time(), 180, k_ETimeUnitSecond ) - CRTime::RTime32TimeCur();
  97. if ( iRespawnWait <= 0 )
  98. iRespawnWait = -1;
  99. }
  100. }
  101. }
  102. if ( IsVisible() != bVisible )
  103. {
  104. SetVisible( bVisible );
  105. bChanged = true;
  106. }
  107. if ( bVisible )
  108. {
  109. if ( g_TF_PR )
  110. {
  111. // Are we connected with a class?
  112. Assert( TF_CLASS_UNDEFINED == 0 );
  113. int iClass = -1;
  114. bool bAlive = false;
  115. const int k_Health_Dead = -1;
  116. const int k_Health_NotINGame = -2;
  117. int iHealth = k_Health_NotINGame;
  118. if ( m_iPlayerIndex > 0 )
  119. {
  120. iClass = g_TF_PR->GetPlayerClass( m_iPlayerIndex );
  121. if ( iClass != TF_CLASS_UNDEFINED )
  122. {
  123. bAlive = g_TF_PR->IsAlive( m_iPlayerIndex );
  124. iHealth = k_Health_Dead;
  125. }
  126. if ( bAlive )
  127. iHealth = g_TF_PR->GetHealth( m_iPlayerIndex );
  128. // Calc respawn time remaining
  129. if ( iClass != TF_CLASS_UNDEFINED && !bAlive )
  130. {
  131. float flRespawnAt = g_TF_PR->GetNextRespawnTime( m_iPlayerIndex );
  132. iRespawnWait = (flRespawnAt - gpGlobals->curtime);
  133. if ( iRespawnWait <= 0 )
  134. iRespawnWait = -1;
  135. }
  136. // Hide class info from the other team?
  137. if ( !bObserver &&
  138. TFGameRules()->IsCompetitiveMode() &&
  139. GetTeam() != g_TF_PR->GetTeam( pLocalPlayer->entindex() ) )
  140. {
  141. iClass = TF_CLASS_UNDEFINED;
  142. }
  143. }
  144. // Update live state
  145. if ( m_pClassImage )
  146. {
  147. if ( m_bPrevAlive != bAlive )
  148. {
  149. bChanged = true;
  150. m_bPrevAlive = bAlive;
  151. if ( bAlive )
  152. {
  153. m_pClassImage->SetDrawColor( Color( 255, 255, 255, 255 ) );
  154. }
  155. else
  156. {
  157. m_pClassImage->SetDrawColor( Color( 96, 96, 96, 255 ) );
  158. }
  159. UpdateBorder();
  160. }
  161. // Update class image
  162. if ( m_iPrevClass != iClass )
  163. {
  164. bChanged = true;
  165. m_iPrevClass = iClass;
  166. if ( iClass < 0 )
  167. {
  168. m_pClassImage->SetImage( "hud_connecting" );
  169. }
  170. else if ( iClass == TF_CLASS_UNDEFINED )
  171. {
  172. m_pClassImage->SetImage( "hud_class_not_chosen" );
  173. }
  174. else
  175. {
  176. m_pClassImage->SetImage( VarArgs( "%s_alpha", ( GetTeam() == TF_TEAM_RED ) ? g_pszItemClassImagesRed[iClass] : g_pszItemClassImagesBlue[iClass] ) );
  177. }
  178. }
  179. }
  180. // update health indicator
  181. if ( iHealth != m_iPrevHealth && m_pHealthIcon )
  182. {
  183. m_iPrevHealth = iHealth;
  184. if ( iHealth == k_Health_NotINGame )
  185. {
  186. m_pHealthIcon->SetVisible( false );
  187. }
  188. else
  189. {
  190. m_pHealthIcon->SetVisible( true );
  191. if ( iHealth < 0 )
  192. {
  193. Assert( iHealth == k_Health_Dead );
  194. m_pHealthIcon->SetHealth( -1, 1, 1 );
  195. }
  196. else
  197. {
  198. float flMaxHealth = g_TF_PR->GetMaxHealth( m_iPlayerIndex );
  199. float iMaxBuffedHealth = flMaxHealth * tf_max_health_boost.GetFloat(); // Hacky, but it'll work.
  200. m_pHealthIcon->SetHealth( iHealth, flMaxHealth, iMaxBuffedHealth );
  201. bChanged = true;
  202. }
  203. }
  204. }
  205. // Update respawn time text
  206. if ( iRespawnWait != m_iPrevRespawnWait )
  207. {
  208. m_iPrevRespawnWait = iRespawnWait;
  209. if ( iRespawnWait < 0 )
  210. {
  211. SetDialogVariable( "respawntime", "" );
  212. }
  213. else
  214. {
  215. SetDialogVariable( "respawntime", VarArgs( "%d s", iRespawnWait ) );
  216. bChanged = true;
  217. }
  218. }
  219. bool bReadyMode = TFGameRules()->UsePlayerReadyStatusMode();
  220. int iCharge = ( iClass == TF_CLASS_MEDIC ) ? g_TF_PR->GetChargeLevel( m_iPlayerIndex ) : 0;
  221. if ( iCharge != m_iPrevCharge )
  222. {
  223. if ( iCharge > 0 && !( bReadyMode && !bObserver ) )
  224. {
  225. SetDialogVariable( "chargeamount", VarArgs( "%d%%", iCharge ) );
  226. bChanged = true;
  227. }
  228. else
  229. {
  230. SetDialogVariable( "chargeamount", "" );
  231. }
  232. m_iPrevCharge = iCharge;
  233. }
  234. if ( bReadyMode )
  235. {
  236. bool bPlayerReady = false;
  237. if ( m_bPlayerReadyModeActive )
  238. {
  239. if ( m_iPlayerIndex && g_TF_PR->IsConnected( m_iPlayerIndex ) )
  240. {
  241. bPlayerReady = TFGameRules()->IsPlayerReady( m_iPlayerIndex );
  242. }
  243. }
  244. if ( m_pReadyImage && ( m_pReadyImage->IsVisible() != bPlayerReady ) )
  245. {
  246. m_pReadyImage->SetVisible( bPlayerReady );
  247. }
  248. if ( m_pHealthIcon && ( m_pHealthIcon->IsVisible() == m_bPlayerReadyModeActive ) )
  249. {
  250. m_pHealthIcon->SetVisible( !m_bPlayerReadyModeActive );
  251. }
  252. if ( m_pReadyBG && ( m_pReadyBG->IsVisible() != m_bPlayerReadyModeActive ) )
  253. {
  254. m_pReadyBG->SetVisible( m_bPlayerReadyModeActive );
  255. }
  256. if ( TFGameRules()->State_Get() != m_iPrevState )
  257. {
  258. bChanged = true;
  259. }
  260. m_iPrevState = TFGameRules()->State_Get();
  261. }
  262. }
  263. }
  264. return bChanged;
  265. }
  266. //-----------------------------------------------------------------------------
  267. // Purpose:
  268. //-----------------------------------------------------------------------------
  269. void CTFPlayerPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  270. {
  271. BaseClass::ApplySchemeSettings( pScheme );
  272. m_pClassImage = dynamic_cast<CTFClassImage*>( FindChildByName( "classimage" ) );
  273. Reset();
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Purpose:
  277. //-----------------------------------------------------------------------------
  278. void CTFPlayerPanel::SetPlayerIndex( int iIndex )
  279. {
  280. if ( iIndex <= 0 )
  281. {
  282. Setup( iIndex, CSteamID(), "" );
  283. }
  284. else
  285. {
  286. Setup( iIndex, GetSteamIDForPlayerIndex( iIndex ), g_TF_PR->GetPlayerName( iIndex ) );
  287. }
  288. }
  289. //-----------------------------------------------------------------------------
  290. // Purpose:
  291. //-----------------------------------------------------------------------------
  292. void CTFPlayerPanel::Setup( int iPlayerIndex, CSteamID steamID, const char *pszPlayerName, int nLobbyTeam /*= TEAM_INVALID*/ )
  293. {
  294. if ( pszPlayerName == NULL )
  295. pszPlayerName = "";
  296. if ( m_iPlayerIndex != iPlayerIndex
  297. || m_steamID != steamID
  298. || Q_strcmp( m_sPlayerName, pszPlayerName ) )
  299. {
  300. Reset();
  301. m_iPlayerIndex = iPlayerIndex;
  302. m_steamID = steamID;
  303. m_sPlayerName = pszPlayerName;
  304. SetDialogVariable( "playername", m_sPlayerName );
  305. m_nGCTeam = nLobbyTeam;
  306. }
  307. if ( m_iPlayerIndex > 0 || m_steamID.IsValid() )
  308. {
  309. UpdateBorder();
  310. }
  311. }
  312. //-----------------------------------------------------------------------------
  313. // Purpose:
  314. //-----------------------------------------------------------------------------
  315. void CTFPlayerPanel::SetSpecIndex( int iIndex )
  316. {
  317. m_iSpecIndex = iIndex;
  318. if ( m_iSpecIndex > 0 && m_iSpecIndex <= 12 && !m_bPlayerReadyModeActive )
  319. {
  320. SetDialogVariable( "specindex", VarArgs( "%d", m_iSpecIndex ) );
  321. }
  322. else
  323. {
  324. SetDialogVariable( "specindex", "" );
  325. }
  326. }
  327. //-----------------------------------------------------------------------------
  328. // Purpose:
  329. //-----------------------------------------------------------------------------
  330. void CTFPlayerPanel::UpdateBorder( void )
  331. {
  332. if ( !g_TF_PR )
  333. return;
  334. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
  335. if ( !m_bPrevAlive )
  336. {
  337. SetBorder( pScheme->GetBorder("TFFatLineBorder") );
  338. }
  339. else
  340. {
  341. if ( GetTeam() == TF_TEAM_RED )
  342. {
  343. SetBorder( pScheme->GetBorder( "TFFatLineBorderRedBG" ) );
  344. }
  345. else
  346. {
  347. SetBorder( pScheme->GetBorder( "TFFatLineBorderBlueBG" ) );
  348. }
  349. }
  350. }
  351. //-----------------------------------------------------------------------------
  352. // Purpose:
  353. //-----------------------------------------------------------------------------
  354. int CTFPlayerPanel::GetTeam( void )
  355. {
  356. if ( m_nGCTeam != TEAM_INVALID && TFGameRules() )
  357. {
  358. return TFGameRules()->GetGameTeamForGCTeam( (TF_GC_TEAM)m_nGCTeam );
  359. }
  360. else if ( GetPlayerIndex() && g_TF_PR )
  361. {
  362. return g_TF_PR->GetTeam( GetPlayerIndex() );
  363. }
  364. return TEAM_INVALID;
  365. }