summaryrefslogtreecommitdiff
path: root/game/client/tf/tf_teamstatus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/tf_teamstatus.cpp')
-rw-r--r--game/client/tf/tf_teamstatus.cpp621
1 files changed, 621 insertions, 0 deletions
diff --git a/game/client/tf/tf_teamstatus.cpp b/game/client/tf/tf_teamstatus.cpp
new file mode 100644
index 0000000..432b579
--- /dev/null
+++ b/game/client/tf/tf_teamstatus.cpp
@@ -0,0 +1,621 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "iclientmode.h"
+#include <vgui_controls/AnimationController.h>
+#include <vgui_controls/EditablePanel.h>
+#include <vgui_controls/ProgressBar.h>
+
+#include "tf_gamerules.h"
+#include "tf_logic_halloween_2014.h"
+#include "c_tf_playerresource.h"
+#include "tf_playerpanel.h"
+#include "tf_teamstatus.h"
+#include "tf_matchmaking_shared.h"
+#include "tf_match_description.h"
+
+using namespace vgui;
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+CTFTeamStatusPlayerPanel::CTFTeamStatusPlayerPanel( vgui::Panel *parent, const char *name ) : CTFPlayerPanel( parent, name )
+{
+ m_pHealthBar = new vgui::ContinuousProgressBar( this, "healthbar" );
+ m_pOverhealBar = new vgui::ContinuousProgressBar( this, "overhealbar" );
+ m_pClassImageBG = new vgui::Panel( this, "classimagebg" );
+ m_pDeathFlag = new vgui::ImagePanel( this, "DeathPanel" );
+
+ m_iTeam = TEAM_UNASSIGNED;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatusPlayerPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatusPlayerPanel::UpdateBorder( void )
+{
+ // do nothing
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFTeamStatusPlayerPanel::Update( void )
+{
+ if ( !g_TF_PR || !TFGameRules() )
+ return false;
+
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pLocalPlayer || ( pLocalPlayer->GetTeamNumber() < FIRST_GAME_TEAM ) )
+ return false;
+
+ bool bChanged = false;
+ bool bVisible = GetTeam() >= FIRST_GAME_TEAM;
+ int iRespawnWait = -1;
+
+ if ( IsVisible() != bVisible )
+ {
+ SetVisible( bVisible );
+ bChanged = true;
+ }
+
+ if ( bVisible && g_TF_PR )
+ {
+ bool bSameTeamAsLocalPlayer = ( GetTeam() == g_TF_PR->GetTeam( pLocalPlayer->entindex() ) );
+
+ // are we connected with a class?
+ Assert( TF_CLASS_UNDEFINED == 0 );
+ int iClass = -1;
+ bool bAlive = false;
+ int iHealth = -1;
+ bool bIsLocalPlayer = false;
+ if ( m_iPlayerIndex > 0 )
+ {
+ bIsLocalPlayer = pLocalPlayer->entindex() == m_iPlayerIndex;
+
+ iClass = g_TF_PR->GetPlayerClass( m_iPlayerIndex );
+
+ if ( iClass != TF_CLASS_UNDEFINED )
+ {
+ bAlive = g_TF_PR->IsAlive( m_iPlayerIndex );
+ }
+ if ( bAlive )
+ {
+ iHealth = g_TF_PR->GetHealth( m_iPlayerIndex );
+ }
+
+ // calc respawn time remaining
+ if ( !bAlive && ( iClass != TF_CLASS_UNDEFINED ) )
+ {
+ float flRespawnAt = g_TF_PR->GetNextRespawnTime( m_iPlayerIndex );
+ iRespawnWait = ( flRespawnAt - gpGlobals->curtime );
+ if ( iRespawnWait <= 0 )
+ iRespawnWait = -1;
+ }
+
+ // hide class info from the other team?
+ if ( !bSameTeamAsLocalPlayer )
+ {
+ iClass = TF_CLASS_UNDEFINED;
+ }
+ }
+
+ if ( m_iTeam != GetTeam() )
+ {
+ m_iTeam = GetTeam();
+ bChanged = true;
+ }
+
+ if ( m_pClassImageBG )
+ {
+ if ( m_iTeam == TF_TEAM_RED )
+ {
+ Color bgColor( m_ColorPortraitBGRedLocalPlayer );
+ if ( !bIsLocalPlayer )
+ {
+ bgColor = bAlive ? m_ColorPortraitBGRed : m_ColorPortraitBGRedDead;
+ }
+
+ m_pClassImageBG->SetBgColor( bgColor );
+ }
+ else
+ {
+ Color bgColor( m_ColorPortraitBGBlueLocalPlayer );
+ if ( !bIsLocalPlayer )
+ {
+ bgColor = bAlive ? m_ColorPortraitBGBlue : m_ColorPortraitBGBlueDead;
+ }
+ m_pClassImageBG->SetBgColor( bgColor );
+ }
+ }
+
+ // update live state
+ if ( m_pClassImage )
+ {
+ if ( m_bPrevAlive != bAlive )
+ {
+ bChanged = true;
+ m_bPrevAlive = bAlive;
+ if ( !bAlive )
+ {
+ m_pClassImage->SetDrawColor( ( m_iTeam == TF_TEAM_RED ) ? m_ColorPortraitBlendDeadRed : m_ColorPortraitBlendDeadBlue );
+ }
+
+ m_pDeathFlag->SetImage( ( m_iTeam == TF_TEAM_RED ) ? "../HUD/comp_player_status" : "../HUD/comp_player_status_blue" );
+
+ if ( bAlive )
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "TeamStatus_PlayerAlive", false );
+ }
+ else
+ {
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "TeamStatus_PlayerDead", false );
+ }
+ }
+
+ // update class image
+ if ( ( m_iPrevClass != iClass ) || bChanged )
+ {
+ bChanged = true;
+ m_iPrevClass = iClass;
+ if ( iClass < 0 )
+ {
+ m_pClassImage->SetImage( "hud_connecting" );
+ }
+ else if ( iClass == TF_CLASS_UNDEFINED )
+ {
+ int iDeadClass = g_TF_PR->GetPlayerClassWhenKilled( m_iPlayerIndex );
+ if ( !bAlive && !bSameTeamAsLocalPlayer && ( m_iTeam >= FIRST_GAME_TEAM ) && ( iDeadClass > TF_CLASS_UNDEFINED ) )
+ {
+ m_pClassImage->SetImage( VarArgs( "%s_alpha", ( m_iTeam == TF_TEAM_RED ) ? g_pszItemClassImagesRed[iDeadClass + 9] : g_pszItemClassImagesBlue[iDeadClass + 9] ) );
+ }
+ else
+ {
+ m_pClassImage->SetImage( "class_portraits/silhouette_alpha" );
+ }
+ }
+ else
+ {
+ if ( bAlive )
+ {
+ m_pClassImage->SetImage( VarArgs( "%s_alpha", ( m_iTeam == TF_TEAM_RED ) ? g_pszItemClassImagesRed[iClass] : g_pszItemClassImagesBlue[iClass] ) );
+ }
+ else
+ {
+ m_pClassImage->SetImage( VarArgs( "%s_alpha", ( m_iTeam == TF_TEAM_RED ) ? g_pszItemClassImagesRed[iClass + 9] : g_pszItemClassImagesBlue[iClass + 9] ) );
+
+ }
+ }
+ }
+ }
+
+ // update health indicator
+ if ( m_pHealthBar && m_pOverhealBar )
+ {
+ if ( iHealth != m_iPrevHealth )
+ {
+ m_iPrevHealth = iHealth;
+
+ if ( ( iHealth > 0 ) && bSameTeamAsLocalPlayer )
+ {
+ float flMaxHealth = g_TF_PR->GetMaxHealth( m_iPlayerIndex );
+ float flProgress = iHealth / flMaxHealth;
+
+ // health bar
+ if ( !m_pHealthBar->IsVisible() )
+ {
+ m_pHealthBar->SetVisible( true );
+ }
+ m_pHealthBar->SetProgress( ( flProgress >= 1.0f ) ? 1.0f : flProgress );
+
+ if ( flProgress > m_flPercentageHealthMed )
+ {
+ m_pHealthBar->SetFgColor( m_ColorBarHealthHigh );
+ }
+ else if ( flProgress > m_flPercentageHealthLow )
+ {
+ m_pHealthBar->SetFgColor( m_ColorBarHealthMed );
+ }
+ else
+ {
+ m_pHealthBar->SetFgColor( m_ColorBarHealthLow );
+ }
+
+ // overheal bar
+ if ( flProgress > 1.0f )
+ {
+ if ( !m_pOverhealBar->IsVisible() )
+ {
+ m_pOverhealBar->SetVisible( true );
+ }
+ m_pOverhealBar->SetProgress( flProgress - 1.0f );
+ }
+ else
+ {
+ if ( m_pOverhealBar->IsVisible() )
+ {
+ m_pOverhealBar->SetVisible( false );
+ }
+ }
+ }
+ else
+ {
+ if ( m_pHealthBar->IsVisible() )
+ {
+ m_pHealthBar->SetVisible( false );
+ }
+
+ if ( m_pOverhealBar->IsVisible() )
+ {
+ m_pOverhealBar->SetVisible( false );
+ }
+ }
+
+ bChanged = true;
+ }
+ }
+
+ // update respawn time
+ if ( iRespawnWait != m_iPrevRespawnWait )
+ {
+ m_iPrevRespawnWait = iRespawnWait;
+ if ( ( iRespawnWait < 0 ) || !bSameTeamAsLocalPlayer )
+ {
+ SetDialogVariable( "respawntime", "" );
+ }
+ else
+ {
+ SetDialogVariable( "respawntime", VarArgs( "%d", iRespawnWait ) );
+ }
+
+ bChanged = true;
+ }
+
+ // gamerules state
+ if ( TFGameRules()->State_Get() != m_iPrevState )
+ {
+ m_iPrevState = TFGameRules()->State_Get();
+ bChanged = true;
+ }
+ }
+
+ return bChanged;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CTFTeamStatus::CTFTeamStatus( Panel *parent, const char *panelName ) : BaseClass( parent, panelName )
+{
+ m_pPlayerPanelKVs = NULL;
+ m_bReapplyPlayerPanelKVs = false;
+
+ Reset();
+
+ ivgui()->AddTickSignal( GetVPanel(), 100 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFTeamStatus::~CTFTeamStatus()
+{
+ if ( m_pPlayerPanelKVs )
+ {
+ m_pPlayerPanelKVs->deleteThis();
+ m_pPlayerPanelKVs = NULL;
+ }
+}
+
+void SetGrowDir( CTFTeamStatus::EGrowDir* pGrowDir, const char* pszString )
+{
+ if ( FStrEq( pszString, "east" ) )
+ {
+ (*pGrowDir) = CTFTeamStatus::EGrowDir::GROW_EAST;
+ }
+ else if ( FStrEq( pszString, "west" ) )
+ {
+ (*pGrowDir) = CTFTeamStatus::EGrowDir::GROW_WEST;
+ }
+ else
+ {
+ Assert( !"Invalid direction string for team status team grow direction" );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatus::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ SetGrowDir( &m_eTeam1GrowDir, inResourceData->GetString( "team1_grow_dir" ) );
+ SetGrowDir( &m_eTeam2GrowDir, inResourceData->GetString( "team2_grow_dir" ) );
+
+ KeyValues *pItemKV = inResourceData->FindKey( "playerpanels_kv" );
+ if ( pItemKV )
+ {
+ if ( m_pPlayerPanelKVs )
+ {
+ m_pPlayerPanelKVs->deleteThis();
+ }
+ m_pPlayerPanelKVs = new KeyValues( "playerpanels_kv" );
+ pItemKV->CopySubkeys( m_pPlayerPanelKVs );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatus::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_bReapplyPlayerPanelKVs = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatus::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ int iTeam1Count = 0;
+ int iTeam2Count = 0;
+
+ // Tally up how many are on each team so we can scale them appropriately down below
+ for ( int i = 0; i < m_PlayerPanels.Count(); i++ )
+ {
+ if ( m_PlayerPanels[i]->GetTeam() == TF_TEAM_BLUE )
+ {
+ ++iTeam1Count;
+ }
+ else if ( m_PlayerPanels[i]->GetTeam() == TF_TEAM_RED )
+ {
+ ++iTeam2Count;
+ }
+ }
+
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+
+ // Snag local player info
+ int nLocalPlayerTeam = TF_TEAM_COUNT;
+ int nLocalPlayerIndex = -1;
+ if ( pLocalPlayer )
+ {
+ nLocalPlayerIndex = pLocalPlayer->entindex();
+ nLocalPlayerTeam = pLocalPlayer->GetTeamNumber();
+ }
+
+ int iTeam1Processed = 0;
+ int iTeam2Processed = 0;
+
+ for ( int i = 0; i < m_PlayerPanels.Count(); i++ )
+ {
+ if ( m_PlayerPanels[i]->GetPlayerIndex() <= 0 )
+ {
+ m_PlayerPanels[i]->SetVisible( false );
+ continue;
+ }
+
+ bool bIsLocalPlayerPanel = nLocalPlayerIndex == m_PlayerPanels[i]->GetPlayerIndex();
+ int iTeam = m_PlayerPanels[i]->GetTeam();
+ int iXPos = 0;
+
+ // Setup vars
+ EGrowDir& eGrowDir = iTeam == TF_TEAM_BLUE ? m_eTeam1GrowDir : m_eTeam2GrowDir;
+ int& iTeamCount = iTeam == TF_TEAM_BLUE ? iTeam1Count : iTeam2Count;
+ int& iBaseX = iTeam == TF_TEAM_BLUE ? m_iTeam1BaseX : m_iTeam2BaseX;
+ int& iProcessed = iTeam == TF_TEAM_BLUE ? iTeam1Processed : iTeam2Processed;
+ int& iMaxExpand = iTeam == TF_TEAM_BLUE ? m_iTeam1MaxExpand : m_iTeam2MaxExpand;
+ const int iGap = RemapValClamped( iTeamCount, 6, 12, m_i6v6Gap, m_i12v12Gap );
+
+ // Local player is always the innermost panel
+ int nTeamPanelIndex = bIsLocalPlayerPanel ? 0
+ : iTeam == nLocalPlayerTeam ? iProcessed + 1
+ : iProcessed;
+
+ // Setup X-position and widths
+ // Use the max width if less than 6 (to fill out the space)
+ int nNewWide = iTeamCount <= 6 ? m_iMaxSize : ( iMaxExpand - ( iGap * ( iTeamCount - 1 ) ) ) / iTeamCount;
+
+ // How far each panel is apart from each other
+ const int iXStep = iGap + nNewWide;
+ // How many steps out this panel should be
+ const int iXOffset = iXStep * nTeamPanelIndex;
+ // Step out the panels by the step
+ iXPos = eGrowDir == GROW_EAST ? iBaseX + iXOffset // Align the left edge of the left-most panel on the specified point
+ : eGrowDir == GROW_WEST ? iBaseX - iXOffset - nNewWide // Align the right edge of the right-most panel on the specified point
+ : 0;
+
+ // This is expensive, so only do it if we need to
+ if ( nNewWide != m_PlayerPanels[i]->GetWide() )
+ {
+ // We change the width in the KV's then reapply settings so the children will do their
+ // magical proportionaltoparent layout.
+ if ( m_pPlayerPanelKVs )
+ {
+ m_pPlayerPanelKVs->SetInt( "wide", scheme()->GetProportionalNormalizedValueEx( GetScheme(), nNewWide ) );
+ m_PlayerPanels[i]->ApplySettings( m_pPlayerPanelKVs );
+ m_PlayerPanels[i]->InvalidateLayout( false, true );
+ m_PlayerPanels[i]->Update();
+ }
+ }
+
+ if ( !bIsLocalPlayerPanel )
+ {
+ ++iProcessed;
+ }
+
+ m_PlayerPanels[i]->SetPos( iXPos, m_PlayerPanels[i]->GetYPos() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatus::Reset()
+{
+ for ( int i = 0; i < m_PlayerPanels.Count(); i++ )
+ {
+ m_PlayerPanels[i]->Reset();
+ }
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFTeamStatus::ShouldDraw( void )
+{
+ // Get the player and active weapon.
+ C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
+
+ if ( !pPlayer )
+ return false;
+
+ int iLocalTeam = g_TF_PR->GetTeam( pPlayer->entindex() );
+ if ( iLocalTeam < FIRST_GAME_TEAM )
+ return false;
+
+ if ( TFGameRules() )
+ {
+ const IMatchGroupDescription* pMatchDesc = GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() );
+ if ( !pMatchDesc || !pMatchDesc->m_params.m_bUseMatchHud )
+ return false;
+
+ if ( TFGameRules()->ShowMatchSummary() )
+ return false;
+ }
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatus::OnTick()
+{
+ if ( IsVisible() != ShouldDraw() )
+ {
+ SetVisible( ShouldDraw() );
+ }
+
+ if ( IsVisible() )
+ {
+ RecalculatePlayerPanels();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFTeamStatusPlayerPanel *CTFTeamStatus::GetOrAddPanel( int iPanelIndex )
+{
+ if ( iPanelIndex < m_PlayerPanels.Count() )
+ {
+ return m_PlayerPanels[iPanelIndex];
+ }
+ Assert( iPanelIndex == m_PlayerPanels.Count() );
+ CTFTeamStatusPlayerPanel *pPanel = new CTFTeamStatusPlayerPanel( this, VarArgs( "playerpanel%d", iPanelIndex ) );
+ if ( m_pPlayerPanelKVs )
+ {
+ pPanel->ApplySettings( m_pPlayerPanelKVs );
+ pPanel->InvalidateLayout( false, true );
+ InvalidateLayout();
+ }
+ m_PlayerPanels.AddToTail( pPanel );
+ return pPanel;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatus::RecalculatePlayerPanels( void )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer || !g_TF_PR )
+ return;
+
+ int iPanel = 0;
+ bool bNeedsLayout = false;
+ int iLocalTeam = g_TF_PR->GetTeam( pPlayer->entindex() );
+ if ( iLocalTeam >= FIRST_GAME_TEAM )
+ {
+ for ( int i = 1; i <= MAX_PLAYERS; i++ )
+ {
+ if ( !g_TF_PR->IsConnected( i ) )
+ continue;
+
+ int iTeam = g_TF_PR->GetTeam( i );
+ if ( iTeam < FIRST_GAME_TEAM )
+ continue;
+
+ // Add an entry
+ CTFTeamStatusPlayerPanel *pPanel = GetOrAddPanel( iPanel );
+
+ if ( pPanel->GetPlayerIndex() != i )
+ {
+ bNeedsLayout = true;
+ }
+
+ pPanel->SetPlayerIndex( i );
+
+ if ( pPanel->GetPreviousTeam() != pPanel->GetTeam() )
+ {
+ bNeedsLayout = true;
+ }
+
+ ++iPanel;
+ }
+ }
+
+ // Clear out any extra panels
+ for ( int i = iPanel; i < m_PlayerPanels.Count(); i++ )
+ {
+ if ( m_PlayerPanels[i]->GetPlayerIndex() != 0 )
+ {
+ bNeedsLayout = true;
+ }
+
+ m_PlayerPanels[i]->SetPlayerIndex( 0 );
+ }
+
+ UpdatePlayerPanels();
+
+ if ( bNeedsLayout )
+ {
+ InvalidateLayout();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFTeamStatus::UpdatePlayerPanels( void )
+{
+ if ( !g_TF_PR )
+ return;
+
+ for ( int i = 0; i < m_PlayerPanels.Count(); i++ )
+ {
+ m_PlayerPanels[i]->Update();
+ }
+} \ No newline at end of file