summaryrefslogtreecommitdiff
path: root/game/client/tf/tf_hud_robot_destruction_status.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/tf/tf_hud_robot_destruction_status.cpp')
-rw-r--r--game/client/tf/tf_hud_robot_destruction_status.cpp1241
1 files changed, 1241 insertions, 0 deletions
diff --git a/game/client/tf/tf_hud_robot_destruction_status.cpp b/game/client/tf/tf_hud_robot_destruction_status.cpp
new file mode 100644
index 0000000..115f708
--- /dev/null
+++ b/game/client/tf/tf_hud_robot_destruction_status.cpp
@@ -0,0 +1,1241 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+
+#include "cbase.h"
+#include <vgui_controls/AnimationController.h>
+
+#include "tf_hud_freezepanel.h"
+#include "clientmode_shared.h"
+#include "tf_hud_robot_destruction_status.h"
+#include "tf_logic_player_destruction.h"
+#include "c_tf_objective_resource.h"
+#include "c_func_capture_zone.h"
+
+#define ATTACK_BLINK_TIME 2.f
+
+using namespace vgui;
+
+extern ConVar tf_rd_min_points_to_steal;
+extern ConVar tf_rd_steal_rate;
+extern ConVar tf_rd_points_per_steal;
+extern ConVar tf_rd_points_approach_interval;
+extern ConVar tf_rd_points_per_approach;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFHudRobotDestruction_StateImage::CTFHudRobotDestruction_StateImage( Panel *parent, const char *name, const char *pszResFile )
+ : vgui::EditablePanel( parent, name )
+ , m_pImage( NULL )
+ , m_pRobotImage( NULL )
+ , m_pszResFile( pszResFile )
+{
+ m_pImage = new ImagePanel( this, "Image" );
+ m_pRobotImage = new ImagePanel( this, "RobotImage" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_StateImage::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( m_pszResFile );
+
+ ImagePanel* pGlow = dynamic_cast<ImagePanel*>( FindChildByName( "GlowImage", true ) );
+ if ( pGlow )
+ {
+ pGlow->SetAlpha( 0 );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_StateImage::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ int nTeam = TF_TEAM_RED;
+ const CTFHudRobotDestruction_RobotIndicator *pRobotImageParent = dynamic_cast< const CTFHudRobotDestruction_RobotIndicator* >( GetParent()->GetParent() );
+ if ( pRobotImageParent )
+ {
+ nTeam = pRobotImageParent->GetTeamNumber();
+ }
+
+ const char *pszKeyName = nTeam == TF_TEAM_RED ? "redimage" : "blueimage";
+ const char *pszImageName = inResourceData->GetString( pszKeyName );
+ if ( pszImageName && pszImageName[0] )
+ {
+ m_pImage->SetImage( pszImageName );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFHudRobotDestruction_DeadImage::CTFHudRobotDestruction_DeadImage( Panel *parent, const char *name, const char *pszResFile )
+ : CTFHudRobotDestruction_StateImage( parent, name, pszResFile )
+ , m_pRespawnProgressBar( NULL )
+{
+ m_pRespawnProgressBar = new CTFProgressBar( this, "RespawnProgressBar" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_DeadImage::SetProgress( float flProgress )
+{
+ m_pRespawnProgressBar->SetPercentage( flProgress );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFHudRobotDestruction_ActiveImage::CTFHudRobotDestruction_ActiveImage( Panel *parent, const char *name, const char *pszResFile )
+ : CTFHudRobotDestruction_StateImage( parent, name, pszResFile )
+{}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_ActiveImage::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ const CTFHudRobotDestruction_RobotIndicator *pRobotImageParent = dynamic_cast< const CTFHudRobotDestruction_RobotIndicator* >( GetParent()->GetParent() );
+ if ( pRobotImageParent && pRobotImageParent->GetGroup() )
+ {
+ m_pRobotImage->SetImage( pRobotImageParent->GetGroup()->GetHUDIcon() );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFHudRobotDestruction_RobotIndicator::CTFHudRobotDestruction_RobotIndicator( vgui::Panel *pParent, const char *pszName, CTFRobotDestruction_RobotGroup *pGroup )
+ : EditablePanel( pParent, pszName )
+ , m_hGroup( pGroup )
+ , m_pNextRobotIndicator( NULL )
+ , m_pPrevRobotIndicator( NULL )
+{
+ Assert( pGroup );
+
+ m_pSwoop = new CControlPointIconSwoop( this, "Swoop" );
+ m_pSwoop->SetVisible( false );
+ m_pRobotStateContainer = new EditablePanel( this, "RobotStateContainer" );
+ m_pDeadPanel = new CTFHudRobotDestruction_DeadImage( m_pRobotStateContainer, "DeadState", "resource/UI/TFHudRobotDestruction_DeadState.res" );
+ m_pActivePanel = new CTFHudRobotDestruction_ActiveImage( m_pRobotStateContainer, "ActiveState", "resource/UI/TFHudRobotDestruction_ActiveState.res" );
+ m_pShieldedPanel = new CTFHudRobotDestruction_StateImage( m_pRobotStateContainer, "ShieldedState", "resource/UI/TFHudRobotDestruction_ShieldedState.res" );
+ m_flHealthPercentage = 0.f;
+ m_eState = ROBOT_STATE_DEAD;
+
+ vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_RobotIndicator::ApplySchemeSettings( vgui::IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( "resource/UI/TFHudRobotDestruction_RobotIndicator.res" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_RobotIndicator::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ m_pSwoop->SetBounds( 0, 0, GetWide(), GetTall() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_RobotIndicator::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_RobotIndicator::OnTick()
+{
+ if ( !m_hGroup )
+ {
+ SetVisible( false );
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ }
+
+ UpdateState();
+ DoUnderAttackBlink();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_RobotIndicator::DoUnderAttackBlink()
+{
+ if ( !m_hGroup.Get() )
+ return;
+
+ if ( gpGlobals->curtime < ( m_hGroup->GetLastAttackedTime() + ATTACK_BLINK_TIME ) && ( GetLocalPlayerTeam() == m_hGroup->GetTeamNumber() ) )
+ {
+ // Pulse red
+ ImagePanel* pGlow = dynamic_cast<ImagePanel*>( FindChildByName( "GlowImage", true ) );
+ if ( pGlow )
+ {
+ float flAlpha = fabs(sin( gpGlobals->curtime * 10.f )) * 255;
+ pGlow->SetAlpha( flAlpha );
+ }
+ }
+ else
+ {
+ // Stop pulsing, stop ticking
+ ImagePanel* pGlow = dynamic_cast<ImagePanel*>( FindChildByName( "GlowImage", true ) );
+ if ( pGlow )
+ {
+ pGlow->SetAlpha( 0 );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CTFHudRobotDestruction_RobotIndicator::GetGroupNumber() const
+{
+ Assert( m_hGroup );
+ if ( !m_hGroup )
+ {
+ return 0;
+ }
+ return m_hGroup->GetGroupNumber();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int CTFHudRobotDestruction_RobotIndicator::GetTeamNumber() const
+{
+ Assert( m_hGroup );
+ if ( !m_hGroup )
+ {
+ return 0;
+ }
+
+ return m_hGroup->GetTeamNumber();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHudRobotDestruction_RobotIndicator::UpdateState()
+{
+ // Don't do anything if there's no group
+ if ( !m_hGroup.Get() )
+ return;
+
+ eRobotUIState eState = (eRobotUIState)m_hGroup->GetState();
+
+ // Get the time
+ float flStartTime = m_hGroup->GetRespawnStartTime();
+ float flEndTime = m_hGroup->GetRespawnEndTime();
+
+ // Show how much time is remaining
+ m_pDeadPanel->SetDialogVariable( "time", CFmtStr( "%0.0f", Max( 0.f, flEndTime - gpGlobals->curtime ) ) );
+
+ // Figure out what percentage we're at
+ float flDuration = flEndTime - flStartTime;
+ float flProgress = gpGlobals->curtime - flStartTime;
+ m_pDeadPanel->SetProgress( flProgress / flDuration );
+
+ bool bStateVisibility[ NUM_ROBOT_STATES ];
+ memset( bStateVisibility, false, sizeof( bStateVisibility ) );
+
+ bool bDraw = eState != ROBOT_STATE_INACIVE;
+ if ( bDraw )
+ {
+ m_pRobotStateContainer->SetVisible( true );
+ bStateVisibility[ eState ] = true;
+ }
+ else
+ {
+ m_pRobotStateContainer->SetVisible( false );
+ }
+
+ m_eState = eState;
+
+ bool bShowDead = m_eState == ROBOT_STATE_DEAD;
+ m_pActivePanel->SetImageVisible( !bShowDead );
+
+ m_pDeadPanel->SetVisible( bStateVisibility[ ROBOT_STATE_DEAD ] || bShowDead );
+ m_pActivePanel->SetVisible( bStateVisibility[ ROBOT_STATE_ACTIVE ] );
+ m_pShieldedPanel->SetVisible( bStateVisibility[ ROBOT_STATE_SHIELDED ] );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFHUDRobotDestruction::CTFHUDRobotDestruction( Panel *parent, const char *name )
+ : EditablePanel( parent, name )
+ , m_bPlayingRD( false )
+{
+ m_pPlayingTo = NULL;
+ m_pRobotIndicatorKVs = NULL;
+
+ m_pCarriedContainer = new EditablePanel( this, "CarriedContainer" );
+ m_pCarriedImage = new ImagePanel( m_pCarriedContainer, "CarriedImage" );
+ m_pCarriedFlagProgressBar = new CProgressPanel( m_pCarriedContainer, "CarriedProgressBar" );
+ m_pScoreContainer = new EditablePanel( this, "ScoreContainer" );
+ m_pBlueStolenContainer = new EditablePanel( m_pScoreContainer, "BlueStolenContainer" );
+ m_pBlueDroppedPanel = new EditablePanel( m_pBlueStolenContainer, "DroppedIntelContainer" );
+ m_pRedStolenContainer = new EditablePanel( m_pScoreContainer, "RedStolenContainer" );
+ m_pRedDroppedPanel = new EditablePanel( m_pRedStolenContainer, "DroppedIntelContainer" );
+
+ m_pBlueScoreValueContainer = new EditablePanel( m_pScoreContainer, "BlueScoreValueContainer" );
+ m_pRedScoreValueContainer = new EditablePanel( m_pScoreContainer, "RedScoreValueContainer" );
+
+ m_pProgressBarsContainer = new EditablePanel( m_pScoreContainer, "ProgressBarContainer" );
+ m_pBlueVictoryPanel = new EditablePanel( m_pProgressBarsContainer, "BlueVictoryContainer" );
+ m_pBlueProgressBar = new CProgressPanel( m_pProgressBarsContainer, "BlueProgressBarFill" );
+ m_pBlueProgressBarEscrow = new CProgressPanel( m_pProgressBarsContainer, "BlueProgressBarEscrow" );
+
+ m_pRedVictoryPanel = new EditablePanel( m_pProgressBarsContainer, "RedVictoryContainer" );
+ m_pRedProgressBar = new CProgressPanel( m_pProgressBarsContainer, "RedProgressBarFill" );
+ m_pRedProgressBarEscrow = new CProgressPanel( m_pProgressBarsContainer, "RedProgressBarEscrow" );
+
+ m_pCountdownContainer = NULL;
+ m_pTeamLeaderImage = NULL;
+
+ vgui::ivgui()->AddTickSignal( GetVPanel(), 50 );
+
+ ListenForGameEvent( "rd_rules_state_changed" );
+ ListenForGameEvent( "flagstatus_update" );
+ ListenForGameEvent( "rd_team_points_changed" );
+ ListenForGameEvent( "teamplay_round_start" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CTFHUDRobotDestruction::~CTFHUDRobotDestruction()
+{
+ if ( m_pRobotIndicatorKVs )
+ {
+ m_pRobotIndicatorKVs->deleteThis();
+ m_pRobotIndicatorKVs = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CTFHUDRobotDestruction::IsVisible( void )
+{
+ if( IsTakingAFreezecamScreenshot() )
+ return false;
+
+ return BaseClass::IsVisible();
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ KeyValues *pItemKV = inResourceData->FindKey( "robot_kv" );
+ if ( pItemKV )
+ {
+ if ( m_pRobotIndicatorKVs )
+ {
+ m_pRobotIndicatorKVs->deleteThis();
+ }
+ m_pRobotIndicatorKVs = new KeyValues( "robot_kv" );
+ pItemKV->CopySubkeys( m_pRobotIndicatorKVs );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+int SortRobotVec( CTFHudRobotDestruction_RobotIndicator * const *p1, CTFHudRobotDestruction_RobotIndicator * const *p2 )
+{
+ return (*p2)->GetGroupNumber() - (*p1)->GetGroupNumber();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ CTFRobotDestructionLogic* pRoboLogic = CTFRobotDestructionLogic::GetRobotDestructionLogic();
+
+ if ( !pRoboLogic )
+ return;
+
+
+ // load control settings...
+ LoadControlSettings( pRoboLogic->GetResFile() );
+
+ // Clear out any old robot panels and bars
+ m_vecRedRobots.PurgeAndDeleteElements();
+ m_vecBlueRobots.PurgeAndDeleteElements();
+
+ CUtlVector< CTFRobotDestruction_RobotGroup * > vecSeenGroups;
+
+ // Go through all the groups in the map, and create a UI element for each one
+ for ( int i=0; i<IRobotDestructionGroupAutoList::AutoList().Count(); ++i )
+ {
+ CTFRobotDestruction_RobotGroup *pGroup = static_cast< CTFRobotDestruction_RobotGroup* >( IRobotDestructionGroupAutoList::AutoList()[i] );
+
+ if ( pGroup->IsDormant() )
+ continue;
+
+ if ( vecSeenGroups.Find( pGroup ) != vecSeenGroups.InvalidIndex() )
+ {
+ Assert( 0 );
+ DevMsg( "[RD HUD]: %p seen multiple times!\n", pGroup);
+ continue;
+ }
+ vecSeenGroups.AddToTail( pGroup );
+ RobotVector_t &robotVec = pGroup->GetTeamNumber() == TF_TEAM_RED ? m_vecRedRobots : m_vecBlueRobots;
+ const char* pszPanelName = pGroup->GetTeamNumber() == TF_TEAM_RED ? "red" : "blue";
+
+ robotVec[ robotVec.AddToTail() ] = new CTFHudRobotDestruction_RobotIndicator( this, CFmtStr( "%s_group_%d", pszPanelName, robotVec.Count() ), pGroup );
+ }
+
+ // Sort them from lowest group to highest group
+ m_vecRedRobots.Sort( &SortRobotVec );
+ m_vecBlueRobots.Sort( &SortRobotVec );
+
+ m_pCarriedContainer->SetVisible( false );
+
+ m_pCountdownContainer = dynamic_cast<EditablePanel*>( FindChildByName( "CountdownContainer" ) );
+ m_pTeamLeaderImage = dynamic_cast<CTFImagePanel*>( m_pCarriedContainer->FindChildByName( "TeamLeaderImage" ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::PerformLayout()
+{
+ BaseClass::PerformLayout();
+
+ // Sort them from lowest group to highest group
+ m_vecRedRobots.Sort( &SortRobotVec );
+ m_vecBlueRobots.Sort( &SortRobotVec );
+
+ PerformRobotLayout( m_vecRedRobots, TF_TEAM_RED );
+ PerformRobotLayout( m_vecBlueRobots, TF_TEAM_BLUE );
+
+ int nXPos, nYPos;
+ m_pProgressBarsContainer->GetPos( nXPos, nYPos );
+
+ // Store the edges of the score container
+ m_nStealLeftEdge = nXPos + m_nStealLeftEdgeOffset - ( m_pRedStolenContainer->GetWide() / 2.f );
+ m_nStealRightEdge = nXPos + m_pProgressBarsContainer->GetWide() - m_nStealRightEdgeOffset + ( m_pRedStolenContainer->GetWide() / 2.f );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::PerformRobotLayout( RobotVector_t& vecRobots, int nTeam )
+{
+ int nParentX = 0, nParentY = 0, nParentWide = 0, nParentTall = 0;
+ GetBounds( nParentX, nParentY, nParentWide, nParentTall );
+
+ bool bIsRed = nTeam == TF_TEAM_RED;
+ const int nCenterX = nParentX + ( nParentWide * 0.5f );
+ int nActiveIndex = 0;
+ const int nXOffset = m_iRobotXOffset;
+ const int nYOffest = nParentTall - m_iRobotYOffset;
+ const int nXStep = m_iRobotXStep;
+ const int nYStep = m_iRobotYStep;
+ Panel *pPrevPanel = NULL;
+
+ // Position the robot panels, spanning out from the bottom center
+ FOR_EACH_VEC_BACK( vecRobots, i )
+ {
+ CTFHudRobotDestruction_RobotIndicator* pRobot = vecRobots[i];
+ if ( pRobot )
+ {
+ pRobot->ApplySettings( m_pRobotIndicatorKVs );
+ pRobot->UpdateState();
+ pRobot->SetZPos( vecRobots.Count() - i );
+
+ CTFHudRobotDestruction_RobotIndicator *pPrevRobot = dynamic_cast< CTFHudRobotDestruction_RobotIndicator * >( pPrevPanel );
+ if ( pPrevRobot )
+ {
+ pRobot->SetPrevRobotIndicator( pPrevRobot );
+ pPrevRobot->SetNextRobotIndicator( pRobot );
+ }
+
+ int nWide = pRobot->GetWide();
+ // The starting offset
+ int nStartPos = ( ( nXOffset ) + ( nWide * 0.5f ) ) * (bIsRed ? 1 : -1);
+ // The offset between each position
+ int nOffset = bIsRed ? nXStep : -nXStep;
+
+ int nXPos = nCenterX + nStartPos + ( nOffset * nActiveIndex ) - ( nWide * 0.5 );
+ pRobot->SetPos( nXPos, nYOffest - pRobot->GetTall() - ( nYStep * i ) );
+
+ pRobot->InvalidateLayout( true, true );
+
+ // If the state is anything but ROBOT_STATE_INACTIVE, then it's an active panel
+ if ( pRobot->GetState() != ROBOT_STATE_INACIVE )
+ {
+ pPrevPanel = pRobot;
+ ++nActiveIndex;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::Reset()
+{
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "FlagOutlineHide" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::SetPlayingToLabelVisible( bool bVisible )
+{
+ if ( m_pPlayingTo && m_pPlayingToBG )
+ {
+ if ( m_pPlayingTo->IsVisible() != bVisible )
+ {
+ m_pPlayingTo->SetVisible( bVisible );
+ }
+
+ if ( m_pPlayingToBG->IsVisible() != bVisible )
+ {
+ m_pPlayingToBG->SetVisible( bVisible );
+ }
+ }
+}
+
+#ifdef STAGING_ONLY
+ConVar rd_hud_test_bars( "rd_hud_test_bars", 0 );
+#endif
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::OnTick()
+{
+ CTFRobotDestructionLogic* pRoboLogic = CTFRobotDestructionLogic::GetRobotDestructionLogic();
+
+ bool bPlayindRD = ( pRoboLogic != NULL );
+ if ( m_bPlayingRD != bPlayindRD )
+ {
+ if ( bPlayindRD )
+ {
+ InvalidateLayout( true, true );
+ }
+
+ m_bPlayingRD = bPlayindRD;
+ }
+
+ if ( !pRoboLogic )
+ return;
+
+ m_pRedScoreValueContainer->SetDialogVariable( "score", pRoboLogic->GetScore( TF_TEAM_RED ) );
+ m_pBlueScoreValueContainer->SetDialogVariable( "score", pRoboLogic->GetScore( TF_TEAM_BLUE ) );
+
+#ifdef STAGING_ONLY
+ if ( rd_hud_test_bars.GetBool() )
+ {
+ float flProgress = (sin( gpGlobals->curtime ) * 0.5f) + 0.5f;
+ m_pBlueProgressBar->SetProgress( flProgress, true );
+ m_pRedProgressBar->SetProgress( flProgress, true );
+ m_pBlueProgressBarEscrow->SetProgress( 0.f, true );
+ m_pRedProgressBarEscrow->SetProgress( 0.f, true );
+
+ m_pRedScoreValueContainer->SetDialogVariable( "score", flProgress );
+ m_pBlueScoreValueContainer->SetDialogVariable( "score", flProgress );
+ }
+ else
+#endif
+ {
+ int nBlueEscrow = 0, nRedEscrow = 0;
+
+ if ( pRoboLogic->GetType() == CTFRobotDestructionLogic::TYPE_PLAYER_DESTRUCTION )
+ {
+ for ( int i=0; i<ICaptureFlagAutoList::AutoList().Count(); ++i )
+ {
+ CCaptureFlag *pFlag = static_cast< CCaptureFlag* >( ICaptureFlagAutoList::AutoList()[i] );
+
+ if ( pFlag->IsStolen() && pFlag->GetPrevOwner() )
+ {
+ int &nFriendScore = pFlag->GetPrevOwner()->GetTeamNumber() == TF_TEAM_RED ? nRedEscrow : nBlueEscrow;
+
+ nFriendScore += pFlag->GetPointValue();
+ m_pRedDroppedPanel->SetAlpha( 255 );
+ }
+ }
+
+ if ( m_pProgressBarsContainer )
+ {
+ m_pProgressBarsContainer->SetDialogVariable( "red_escrow", nRedEscrow );
+ m_pProgressBarsContainer->SetDialogVariable( "blue_escrow", nBlueEscrow );
+ }
+
+ // update the team leader image
+ if ( m_pTeamLeaderImage )
+ {
+ bool bLocalplayerIsLeader = false;
+ if ( CTFPlayer::GetLocalTFPlayer() && ( CTFPlayer::GetLocalTFPlayer()->GetTeamNumber() > LAST_SHARED_TEAM ) )
+ {
+ if ( CTFPlayer::GetLocalTFPlayer() == pRoboLogic->GetTeamLeader( GetLocalPlayerTeam() ) )
+ {
+ bLocalplayerIsLeader = true;
+ }
+ }
+
+ if ( m_pTeamLeaderImage->IsVisible() != bLocalplayerIsLeader )
+ {
+ m_pTeamLeaderImage->SetVisible( bLocalplayerIsLeader );
+ }
+ }
+
+ // update the countdowns if they exist
+ if ( m_pCountdownContainer )
+ {
+ float flTimeRemaining = pRoboLogic->GetCountdownEndTime() - gpGlobals->curtime;
+ if ( flTimeRemaining > -1 )
+ {
+ if ( !m_pCountdownContainer->IsVisible() )
+ {
+ m_pCountdownContainer->SetVisible( true );
+ }
+
+ ImagePanel* pCountdownImage = dynamic_cast<ImagePanel*>( m_pCountdownContainer->FindChildByName( "CountdownImage", true ) );
+ if ( pCountdownImage )
+ {
+ bool bVisible = true;
+
+ if ( pRoboLogic->IsUsingCustomCountdownImage() )
+ {
+ const char *pszImage = pRoboLogic->GetCountdownImage();
+ if ( pszImage && pszImage[0] )
+ {
+ pCountdownImage->SetImage( pszImage );
+ }
+ else
+ {
+ bVisible = false;
+ }
+ }
+
+ if ( pCountdownImage->IsVisible() != bVisible )
+ {
+ pCountdownImage->SetVisible( bVisible );
+ }
+ }
+
+ CExLabel* pCountdownTime = dynamic_cast<CExLabel*>( m_pCountdownContainer->FindChildByName( "CountdownTime", true ) );
+ CExLabel* pCountdownTimeShadow = dynamic_cast<CExLabel*>( m_pCountdownContainer->FindChildByName( "CountdownTimeShadow", true ) );
+ if ( pCountdownTime )
+ {
+ if ( !pCountdownTime->IsVisible() )
+ {
+ pCountdownTime->SetVisible( true );
+ }
+ }
+ if ( pCountdownTimeShadow )
+ {
+ if ( !pCountdownTimeShadow->IsVisible() )
+ {
+ pCountdownTimeShadow->SetVisible( true );
+ }
+ }
+
+ int nCountdownTime = (int)flTimeRemaining;
+ m_pCountdownContainer->SetDialogVariable( "countdowntime", ( nCountdownTime < 0 ) ? 0 : nCountdownTime );
+ }
+ else
+ {
+ if ( m_pCountdownContainer->IsVisible() )
+ {
+ m_pCountdownContainer->SetVisible( false );
+ }
+ }
+ }
+ }
+ else
+ {
+ // Find the flags if we dont have them yet
+ if ( !m_hRedFlag || !m_hBlueFlag )
+ {
+ for ( int i=0; i<ICaptureFlagAutoList::AutoList().Count(); ++i )
+ {
+ CCaptureFlag *pFlag = static_cast< CCaptureFlag* >( ICaptureFlagAutoList::AutoList()[i] );
+ if ( pFlag->GetTeamNumber() == TF_TEAM_BLUE )
+ {
+ m_hBlueFlag = pFlag;
+ }
+ else
+ {
+ m_hRedFlag = pFlag;
+ }
+ }
+
+ if ( pRoboLogic->GetType() == CTFRobotDestructionLogic::TYPE_ROBOT_DESTRUCTION )
+ {
+ Assert( m_hBlueFlag );
+ Assert( m_hRedFlag );
+ }
+ }
+
+ // A held flag counts towards the stealing team's escrow.
+ // A dropped flag counts towards the original team's escrow.
+ if ( m_hRedFlag && m_hBlueFlag )
+ {
+ if ( m_hRedFlag->IsDropped() )
+ {
+ nRedEscrow += m_hRedFlag->GetPointValue();
+ if ( m_hRedFlag->GetReturnProgress() > 0.8f )
+ {
+ // Blink when we're close to returning
+ int nAlpha = int( gpGlobals->curtime * 10 ) % 10 < 5 ? 255 : 0;
+ m_pRedDroppedPanel->SetAlpha( nAlpha );
+ }
+ }
+ else
+ {
+ nBlueEscrow += m_hRedFlag->GetPointValue();
+ m_pRedDroppedPanel->SetAlpha( 255 );
+ }
+
+ if ( m_hBlueFlag->IsDropped() )
+ {
+ nBlueEscrow += m_hBlueFlag->GetPointValue();
+ if ( m_hBlueFlag->GetReturnProgress() > 0.8f )
+ {
+ // Blink when we're close to returning
+ int nAlpha = int( gpGlobals->curtime * 10 ) % 10 < 5 ? 255 : 0;
+ m_pBlueDroppedPanel->SetAlpha( nAlpha );
+ }
+ }
+ else
+ {
+ nRedEscrow += m_hBlueFlag->GetPointValue();
+ m_pBlueDroppedPanel->SetAlpha( 255 );
+ }
+ }
+ }
+
+ const float flFinaleTime = pRoboLogic->GetFinaleLength();
+ // Get red finale progress. We hide the big scores and show the finale countdown if at max score.
+ float flFinaleProgress = clamp( pRoboLogic->GetFinaleWinTime( TF_TEAM_RED ) - gpGlobals->curtime, 0.f, pRoboLogic->GetFinaleLength() );
+ m_pRedVictoryPanel->SetVisible( flFinaleProgress < flFinaleTime );
+ m_pRedScoreValueContainer->SetVisible( flFinaleProgress >= flFinaleTime );
+ if ( flFinaleProgress < flFinaleTime )
+ {
+ m_pRedVictoryPanel->SetDialogVariable( "victorytime", (int)flFinaleProgress );
+ }
+
+ // Get blue finale progress. We hide the big scores and show the finale countdown if at max score.
+ flFinaleProgress = clamp( pRoboLogic->GetFinaleWinTime( TF_TEAM_BLUE ) - gpGlobals->curtime, 0.f, pRoboLogic->GetFinaleLength() );
+ m_pBlueVictoryPanel->SetVisible( flFinaleProgress < flFinaleTime );
+ m_pBlueScoreValueContainer->SetVisible( flFinaleProgress >= flFinaleTime );
+ if ( flFinaleProgress < flFinaleTime )
+ {
+ m_pBlueVictoryPanel->SetDialogVariable( "victorytime", (int)flFinaleProgress );
+ }
+
+ const float flMaxPoints = pRoboLogic->GetMaxPoints();
+ int nTargetPoints = pRoboLogic->GetTargetScore( TF_TEAM_BLUE );
+ m_pBlueProgressBar->SetProgress( nTargetPoints / flMaxPoints );
+ m_pBlueProgressBarEscrow->SetProgress( ( nTargetPoints + nBlueEscrow ) / flMaxPoints );
+
+ nTargetPoints = pRoboLogic->GetTargetScore( TF_TEAM_RED );
+ m_pRedProgressBar->SetProgress( nTargetPoints / flMaxPoints );
+ m_pRedProgressBarEscrow->SetProgress( ( nTargetPoints + nRedEscrow ) / flMaxPoints );
+ }
+
+ SetPlayingToLabelVisible( true );
+ SetDialogVariable( "rounds", pRoboLogic->GetMaxPoints() );
+ // HACK! Fix the events
+ UpdateCarriedFlagStatus( NULL, NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::PaintBackground()
+{
+ UpdateStolenPoints( TF_TEAM_RED, m_pRedStolenContainer );
+ UpdateStolenPoints( TF_TEAM_BLUE, m_pBlueStolenContainer );
+
+ BaseClass::PaintBackground();
+}
+
+void CTFHUDRobotDestruction::PaintPDPlayerScore( const CTFPlayer* pPlayer )
+{
+ if ( !pPlayer )
+ return;
+
+ // Don't draw the number for ourselves
+ if ( pPlayer == C_BasePlayer::GetLocalPlayer() )
+ return;
+
+ Vector vecPos = pPlayer->GetAbsOrigin();
+ vecPos.z += VEC_HULL_MAX_SCALED( pPlayer ).z + 20;
+
+ int iX, iY;
+ Vector vecWorld( vecPos.x, vecPos.y, vecPos.z );
+ if ( GetVectorInHudSpace( vecWorld, iX, iY ) )
+ {
+ int iCurrentLeadingPoint = 0;
+ if ( pPlayer->HasItem() )
+ {
+ CCaptureFlag *pFlag = dynamic_cast<CCaptureFlag*>( pPlayer->GetItem() );
+ if ( pFlag )
+ {
+ iCurrentLeadingPoint = pFlag->GetPointValue();
+ }
+ }
+
+ wchar_t wszScore[3];
+ V_snwprintf( wszScore, ARRAYSIZE( wszScore ), L"%d", iCurrentLeadingPoint );
+ const int nWidth = V_wcslen( wszScore ) * 15;
+
+ // draw the name
+ vgui::surface()->DrawSetTextFont( m_hPDPlayerScoreFont );
+ vgui::surface()->DrawSetTextPos( iX - ( nWidth / 2 ), iY );
+ vgui::surface()->DrawSetTextColor( m_TextColor );
+
+
+ vgui::surface()->DrawPrintText( wszScore, wcslen( wszScore ), vgui::FONT_DRAW_NONADDITIVE );
+
+ }
+}
+
+void CTFHUDRobotDestruction::Paint()
+{
+ CTFRobotDestructionLogic* pRoboLogic = CTFRobotDestructionLogic::GetRobotDestructionLogic();
+ if ( pRoboLogic && pRoboLogic->GetType() == CTFRobotDestructionLogic::TYPE_PLAYER_DESTRUCTION )
+ {
+ CTFPlayerDestructionLogic* pPDLogic = static_cast< CTFPlayerDestructionLogic* >( pRoboLogic );
+ PaintPDPlayerScore( pPDLogic->GetRedTeamLeader() );
+ PaintPDPlayerScore( pPDLogic->GetBlueTeamLeader() );
+ }
+
+ BaseClass::Paint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::UpdateStolenPoints( int nTeam, EditablePanel* pContainer )
+{
+ CTFRobotDestructionLogic* pRoboLogic = CTFRobotDestructionLogic::GetRobotDestructionLogic();
+ if ( pRoboLogic )
+ {
+ int nStolenPoints = 0;
+ // Get the stolen score for this team
+ CCaptureFlag* pTheirFlag = nTeam == TF_TEAM_RED ? m_hRedFlag : m_hBlueFlag;
+ if ( pTheirFlag )
+ {
+ nStolenPoints = pTheirFlag->GetPointValue();
+ }
+ // Show the stolen panels if the stolen score is anything
+ pContainer->SetVisible( nStolenPoints > 0 );
+ pContainer->SetDialogVariable( "intelvalue", nStolenPoints );
+ }
+
+ // Find our stolen flag
+ CCaptureFlag *pStolenFlag = nTeam == TF_TEAM_RED ? m_hRedFlag : m_hBlueFlag;
+ if ( pStolenFlag && pStolenFlag->IsHome() )
+ {
+ pStolenFlag = NULL;
+ }
+
+
+ C_CaptureZone *pStartCaptureZone = NULL, *pEndCaptureZone = NULL;
+ // Go through all the capture zones and find ours and theirs
+ for ( int i = 0; i<ICaptureZoneAutoList::AutoList().Count(); i++ )
+ {
+ C_CaptureZone *pCaptureZone = static_cast< C_CaptureZone* >( ICaptureZoneAutoList::AutoList()[i] );
+ if ( !pCaptureZone->IsDormant() && !pCaptureZone->IsDisabled() )
+ {
+ if ( pCaptureZone->GetTeamNumber() == nTeam )
+ {
+ pStartCaptureZone = pCaptureZone;
+ }
+ else
+ {
+ pEndCaptureZone = pCaptureZone;
+ }
+ }
+ }
+
+ if ( pStolenFlag && pStartCaptureZone && pEndCaptureZone )
+ {
+ // Use the player's pos if the flag is being carried
+ Vector vecFlagPos = pStolenFlag->GetMoveParent() ? pStolenFlag->GetMoveParent()->GetAbsOrigin() : pStolenFlag->GetAbsOrigin();
+ // Get the distance of the flag between the cap points
+ const float flTotalDist = ( pEndCaptureZone->WorldSpaceCenter() - pStartCaptureZone->WorldSpaceCenter() ).Length() - pEndCaptureZone->BoundingRadius() - pStartCaptureZone->BoundingRadius();
+ const float flFlagDist = ( pEndCaptureZone->WorldSpaceCenter() - vecFlagPos ).Length() - pEndCaptureZone->BoundingRadius();
+ const float flLerp = clamp( flFlagDist / flTotalDist, 0.f, 1.f );
+ // Flip for blue team
+ const float flProgress = nTeam == TF_TEAM_BLUE ? ( 1.f - flLerp ) : flLerp;
+
+ // Calc position
+ int nWide = pContainer->GetWide();
+ const int nXpos = ( ( m_nStealRightEdge - ( m_nStealLeftEdge + nWide ) ) * flProgress ) + m_nStealLeftEdge;
+
+ // Move the panel!
+ int nDummy, nYpos;
+ pContainer->GetPos( nDummy, nYpos );
+ pContainer->SetPos( nXpos, nYpos );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::UpdateCarriedFlagStatus( C_BasePlayer *pNewOwner /*= NULL*/, C_BaseEntity *pFlagEntity /*= NULL*/ )
+{
+ C_TFPlayer *pLocalPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
+
+ // If this is about the other team, we dont care
+ if ( pNewOwner && pNewOwner->GetTeamNumber() != pLocalPlayer->GetTeamNumber() )
+ {
+ return;
+ }
+
+ // are we carrying a flag?
+ CCaptureFlag *pPlayerFlag = NULL;
+ if ( pLocalPlayer && pLocalPlayer->HasItem() && pLocalPlayer->GetItem()->GetItemID() == TF_ITEM_CAPTURE_FLAG )
+ {
+ if ( !pNewOwner || pNewOwner == pLocalPlayer )
+ {
+ pPlayerFlag = dynamic_cast< CCaptureFlag* >( pLocalPlayer->GetItem() );
+ }
+ }
+
+ if ( !pPlayerFlag && pLocalPlayer && pLocalPlayer == pNewOwner )
+ {
+ pPlayerFlag = dynamic_cast< CCaptureFlag* >( pFlagEntity );
+ }
+
+ if ( pPlayerFlag && !pPlayerFlag->IsMarkedForDeletion() && !pPlayerFlag->IsDormant() )
+ {
+ m_pCarriedContainer->SetVisible( true );
+ m_pCarriedContainer->SetDialogVariable( "flagvalue", pPlayerFlag->GetPointValue() );
+ // make sure the panels are on, set the initial alpha values,
+ // set the color of the flag we're carrying, and start the animations
+ if ( m_pCarriedImage && !m_pCarriedImage->IsVisible() )
+ {
+ int nTeam;
+ if ( pPlayerFlag->GetType() == TF_FLAGTYPE_ATTACK_DEFEND ||
+ pPlayerFlag->GetType() == TF_FLAGTYPE_TERRITORY_CONTROL ||
+ pPlayerFlag->GetType() == TF_FLAGTYPE_INVADE ||
+ pPlayerFlag->GetType() == TF_FLAGTYPE_RESOURCE_CONTROL )
+ {
+ nTeam = ( ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? ( TF_TEAM_BLUE ) : ( TF_TEAM_RED ) );
+ }
+ else
+ {
+ // normal CTF behavior (carrying the enemy flag)
+ nTeam = ( ( GetLocalPlayerTeam() == TF_TEAM_RED ) ? ( TF_TEAM_BLUE ) : ( TF_TEAM_RED ) );
+ }
+
+ m_pCarriedImage->SetVisible( true );
+ m_pCarriedFlagProgressBar->SetProgress( 0.f, true ); // Slam to 0 instantly
+ m_pCarriedFlagProgressBar->SetColor( pLocalPlayer->GetTeamNumber() == TF_TEAM_RED ? m_ColorRed : m_ColorBlue );
+ }
+
+ CTFRobotDestructionLogic* pRoboLogic = CTFRobotDestructionLogic::GetRobotDestructionLogic();
+ if ( pRoboLogic )
+ {
+ int nMinToSteal = tf_rd_min_points_to_steal.GetInt();
+ // Current progress
+ float flProgress = float( pPlayerFlag->GetPointValue() ) / float( pRoboLogic->GetMaxPoints() );
+ // What percentage needs to map to the dotted line
+ const float flProgressAtDottedLine = float( nMinToSteal ) / float( pRoboLogic->GetMaxPoints() );
+ // This is where in the texture the dotted line is
+ const float flWhereTheDottedLineIs = 0.25f;
+
+ // We want the progress bar range from [0, The dotted line] map to the progress value [0, Min to steal]
+ if ( flProgress <= flProgressAtDottedLine )
+ {
+ flProgress = RemapValClamped( flProgress, 0.f, flProgressAtDottedLine, 0.f, flWhereTheDottedLineIs );
+ }
+ else // Make the progress bar range from (The dotted line, 1] map to the progress value(Min to steal, 1]
+ {
+ flProgress = RemapValClamped( flProgress, flProgressAtDottedLine, 1.f, flWhereTheDottedLineIs, 1.f );
+ }
+ m_pCarriedFlagProgressBar->SetProgress( flProgress );
+ }
+ }
+ else if ( m_pCarriedImage && m_pCarriedImage->IsVisible() )
+ {
+ m_pCarriedContainer->SetVisible( false );
+ m_pCarriedImage->SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::UpdateRobotElements()
+{
+ m_vecRedRobots.PurgeAndDeleteElements();
+ m_vecBlueRobots.PurgeAndDeleteElements();
+
+ InvalidateLayout( false, true );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::UpdateStolenFlagStatus( int nTeam, C_BaseEntity *pFlag )
+{
+ CCaptureFlag *pPlayerFlag = dynamic_cast< CCaptureFlag* >( pFlag );
+ if ( pPlayerFlag )
+ {
+ EditablePanel *pStolenContainer = nTeam == TF_TEAM_RED ? m_pRedStolenContainer : m_pBlueStolenContainer;
+ Panel* pCarriedImage = pStolenContainer->FindChildByName( "IntelImage" );
+ Panel* pDownImage = pStolenContainer->FindChildByName( "DroppedIntelContainer" );
+ Assert( pCarriedImage && pDownImage );
+
+ if ( !pCarriedImage || !pDownImage )
+ return;
+
+ // Toggle the carried or dropped images
+ bool bIsDropped = pPlayerFlag->IsDropped();
+ pCarriedImage->SetVisible( !bIsDropped );
+ pDownImage->SetVisible( bIsDropped );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTFHUDRobotDestruction::FireGameEvent( IGameEvent * pEvent )
+{
+ CTFRobotDestructionLogic* pRoboLogic = CTFRobotDestructionLogic::GetRobotDestructionLogic();
+
+ if ( !pRoboLogic )
+ return;
+
+ const char *pszEventName = pEvent->GetName();
+
+ if ( FStrEq( "rd_rules_state_changed", pszEventName ) )
+ {
+ UpdateRobotElements();
+ }
+ else if ( FStrEq( pszEventName, "flagstatus_update" ) )
+ {
+ int nVictimID = pEvent->GetInt( "userid" );
+ C_BasePlayer *pNewOwner = USERID2PLAYER( nVictimID );
+
+ int nFlagEntIndex = pEvent->GetInt( "entindex" );
+ C_BaseEntity *pFlagEntity = ClientEntityList().GetEnt( nFlagEntIndex );
+ if ( pFlagEntity )
+ {
+ UpdateCarriedFlagStatus( pNewOwner, pFlagEntity );
+ UpdateStolenFlagStatus( pFlagEntity->GetTeamNumber(), pFlagEntity );
+ }
+ }
+ else if ( FStrEq( pszEventName, "rd_team_points_changed" ) )
+ {
+ // Extract data
+ int nTeam = pEvent->GetInt( "team" );
+ int nPoints = pEvent->GetInt( "points" );
+ RDScoreMethod_t eMethod = RDScoreMethod_t( pEvent->GetInt( "method" ) );
+
+ // Figure out which panel and which anim
+ Panel *pPanel = nTeam == TF_TEAM_RED ? m_pRedScoreValueContainer : m_pBlueScoreValueContainer;
+ bool bPositive = ( nTeam == GetLocalPlayerTeam() && nPoints > 0 ) || ( nTeam != GetLocalPlayerTeam() && nPoints < 0 );
+ const char *pszAnimName = bPositive ? "RDPositiveScorePulse" : "RDNegativeScorePulse";
+
+ g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pPanel, pszAnimName );
+
+ // Make the progress bar blink
+ CProgressPanel *pProgressBar = nTeam == TF_TEAM_RED ? m_pRedProgressBar : m_pBlueProgressBar;
+ pProgressBar->Blink();
+
+ if ( eMethod == SCORE_REACTOR_STEAL )
+ {
+ // Make the OTHER team's escrow progress bar blink
+ CProgressPanel *pEscrowBar = nTeam != TF_TEAM_RED ? m_pRedProgressBarEscrow : m_pBlueProgressBarEscrow;
+ pEscrowBar->Blink();
+ }
+ }
+ else if ( FStrEq( pszEventName, "teamplay_round_start" ) )
+ {
+ // Recalculate the progress speed
+ float flApproachSpeed = ( tf_rd_points_per_approach.GetInt() / tf_rd_points_approach_interval.GetFloat() ) / pRoboLogic->GetMaxPoints();
+ m_pBlueProgressBar->SetApproachSpeed( flApproachSpeed );
+ m_pBlueProgressBarEscrow->SetApproachSpeed( flApproachSpeed );
+ m_pRedProgressBar->SetApproachSpeed( flApproachSpeed );
+ m_pRedProgressBarEscrow->SetApproachSpeed( flApproachSpeed );
+ }
+}
+
+
+
+CTFHUDRobotDestruction::CProgressPanel::CProgressPanel( vgui::Panel *parent, const char *name )
+ : BaseClass( parent, name )
+ , m_nXOrg( 0 )
+ , m_nYOrg( 0 )
+ , m_nWideOrg( 0 )
+ , m_nTallOrg( 0 )
+ , m_flLastScoreTime( 0.f )
+ , m_flEndProgress( 0.f )
+ , m_flCurrentProgress( 0.f )
+ , m_flLastTick( 0.f )
+{
+ ListenForGameEvent( "teamplay_round_start" );
+}
+
+void CTFHUDRobotDestruction::CProgressPanel::CaptureBounds()
+{
+ GetBounds( m_nXOrg, m_nYOrg, m_nWideOrg, m_nTallOrg );
+ if ( GetImage() )
+ {
+ GetImage()->SetSize( m_nWideOrg, m_nTallOrg );
+ }
+}
+
+void CTFHUDRobotDestruction::CProgressPanel::SetProgress( float flProgress, bool bInstant /*= false*/ )
+{
+ if ( bInstant )
+ {
+ m_flEndProgress = m_flCurrentProgress = flProgress;
+ CalculateSize();
+ }
+ else
+ {
+ // Start ticking if the progress is different
+ if ( m_flEndProgress != flProgress )
+ {
+ vgui::ivgui()->AddTickSignal( GetVPanel(), 0 );
+ m_flLastTick = gpGlobals->curtime;
+ }
+
+ // Set end target
+ m_flEndProgress = flProgress;
+ }
+}
+
+void CTFHUDRobotDestruction::CProgressPanel::OnTick()
+{
+ float flDelta = gpGlobals->curtime - m_flLastTick;
+ m_flLastTick = gpGlobals->curtime;
+
+ // Approach the target progress amount
+ m_flCurrentProgress = Approach( m_flEndProgress, m_flCurrentProgress, flDelta * m_flApproachSpeed );
+
+ // Stop ticking if we've met our progress
+ if ( m_flCurrentProgress == m_flEndProgress )
+ {
+ vgui::ivgui()->RemoveTickSignal( GetVPanel() );
+ }
+
+ CalculateSize();
+}
+
+void CTFHUDRobotDestruction::CProgressPanel::PaintBackground()
+{
+ // Resize internal image in here. The other bars use this image too, so we have to move
+ // it right before we paint or else it will be out of position.
+ IImage *pImage = GetImage();
+ if ( pImage )
+ {
+ pImage->SetPos( m_bLeftToRight ? -m_nLeftOffset : -m_flXpos, m_nYOrg );
+ pImage->SetSize( m_nWideOrg, m_nTallOrg );
+ }
+
+ // Find out blink lerp time
+ const float flBlinkPeriod = 0.25f;
+ bool bPastBlink = gpGlobals->curtime > ( m_flLastScoreTime + flBlinkPeriod );
+ // Blink if it's blink time, or else pulse if within threshold, else just be the standard color
+ float flLerp = bPastBlink ? ( m_flCurrentProgress >= m_flBlinkThreshold ? ( ( sin( gpGlobals->curtime * m_flBlinkRate ) * 0.5f ) + 0.5f ) : 1.f )
+ : ( (gpGlobals->curtime - m_flLastScoreTime) / flBlinkPeriod );
+ flLerp = clamp( flLerp, 0.f, 1.f );
+ const float flInverseLerp = 1.f - flLerp;
+ // Get out lerped color
+ Color drawColor( flInverseLerp * m_BrightColor.r() + flLerp * m_StandardColor.r(),
+ flInverseLerp * m_BrightColor.g() + flLerp * m_StandardColor.g(),
+ flInverseLerp * m_BrightColor.b() + flLerp * m_StandardColor.b(),
+ 255 );
+ // Change color in base class (it uses it in PaintBackground)
+ SetDrawColor( drawColor );
+
+ BaseClass::PaintBackground();
+}
+
+void CTFHUDRobotDestruction::CProgressPanel::ApplySettings( KeyValues *inResourceData )
+{
+ BaseClass::ApplySettings( inResourceData );
+
+ int nXpos, nYpos;
+ GetPos( nXpos, nYpos );
+ SetPos( nXpos + m_nLeftOffset, nYpos );
+
+ CaptureBounds();
+ CalculateSize();
+}
+
+void CTFHUDRobotDestruction::CProgressPanel::Blink()
+{
+ m_flLastScoreTime = gpGlobals->curtime;
+}
+
+
+void CTFHUDRobotDestruction::CProgressPanel::FireGameEvent( IGameEvent * pEvent )
+{
+ const char *pszEventName = pEvent->GetName();
+
+ if ( FStrEq( pszEventName, "teamplay_round_start" ) )
+ {
+ // We need to reset the timers here in case we changelevel'd
+ m_flCurrentProgress = 0.f;
+ m_flEndProgress = 0.f;
+
+ // Resize
+ CalculateSize();
+ }
+}
+
+void CTFHUDRobotDestruction::CProgressPanel::CalculateSize()
+{
+ // Find xpos
+ int nProgressWidth = m_nWideOrg - m_nRightOffset - m_nLeftOffset;
+ m_flXpos = m_bLeftToRight ? m_nXOrg
+ : ( 1.f - m_flCurrentProgress) * nProgressWidth + m_nXOrg;
+
+ // Find width
+ m_flWidth = m_flCurrentProgress * nProgressWidth;
+
+ // Resize
+ SetBounds( m_flXpos, m_nYOrg, m_flWidth, m_nTallOrg );
+} \ No newline at end of file