aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/hud_controlpointicons.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'mp/src/game/client/hud_controlpointicons.cpp')
-rw-r--r--mp/src/game/client/hud_controlpointicons.cpp1881
1 files changed, 1881 insertions, 0 deletions
diff --git a/mp/src/game/client/hud_controlpointicons.cpp b/mp/src/game/client/hud_controlpointicons.cpp
new file mode 100644
index 00000000..20d6150b
--- /dev/null
+++ b/mp/src/game/client/hud_controlpointicons.cpp
@@ -0,0 +1,1881 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================
+
+#include "cbase.h"
+#include "hud_controlpointicons.h"
+#include "teamplayroundbased_gamerules.h"
+#include "iclientmode.h"
+#include "c_team_objectiveresource.h"
+#include "c_playerresource.h"
+#include "c_baseplayer.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "hud_macros.h"
+#include "spectatorgui.h"
+#include "c_team.h"
+#include "tf_hud_freezepanel.h"
+#include "tf_hud_objectivestatus.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIconPulseable::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ if ( !m_pPulseImage )
+ {
+ m_pPulseImage = scheme()->GetImage( "../sprites/obj_icons/icon_obj_white", true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIconPulseable::OnSizeChanged(int newWide, int newTall)
+{
+ if ( m_pPulseImage )
+ {
+ // scaling, force the image size to be our size
+ m_pPulseImage->SetSize(newWide, newTall);
+ }
+ BaseClass::OnSizeChanged(newWide, newTall);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIconPulseable::PaintBackground( void )
+{
+ if ( IsInFreezeCam() == true )
+ return;
+
+ if ( GetImage() )
+ {
+ SetAlpha(255);
+ BaseClass::PaintBackground();
+ }
+
+ if ( m_flStartCapAnimStart && gpGlobals->curtime > m_flStartCapAnimStart )
+ {
+ float flElapsedTime = (gpGlobals->curtime - m_flStartCapAnimStart);
+
+ // Pulse the white over the underlying color
+ float flPulseSpeed = 20;
+ if ( m_bAccelerateOverCapture )
+ {
+ float flCapPercentage = ObjectiveResource()->GetCPCapPercentage( m_iCPIndex );
+ flPulseSpeed = RemapValClamped( flCapPercentage, 0, 1, 2, 5 );
+ }
+
+ float flPulseMod = fabs(sin( flElapsedTime * flPulseSpeed ));
+ SetAlpha( 255 * flPulseMod );
+
+ int wide, tall;
+ GetSize( wide, tall );
+
+ // Have to reset these - we're only referencing a material so the
+ // size can be changed by CControlPointIconCapturePulse on a successful cap
+ m_pPulseImage->SetPos( 0, 0 );
+ m_pPulseImage->SetSize( wide, tall );
+
+ m_pPulseImage->Paint();
+
+ // Stop if we're only supposed to do this for a short time
+ if ( m_flPulseTime && flElapsedTime >= m_flPulseTime )
+ {
+ StopPulsing();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIconPulseable::StartPulsing( float flDelay, float flPulseTime, bool bAccelerate )
+{
+ m_flStartCapAnimStart = gpGlobals->curtime + flDelay;
+ m_bAccelerateOverCapture = bAccelerate;
+ m_flPulseTime = flPulseTime;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIconPulseable::StopPulsing( void )
+{
+ m_flStartCapAnimStart = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CControlPointIcon::CControlPointIcon( Panel *parent, const char *pName, int iIndex ) : vgui::EditablePanel( parent, "ControlPointIcon" ), CHudElement( pName )
+{
+ SetHiddenBits( HIDEHUD_MISCSTATUS );
+
+ m_iCPIndex = iIndex;
+ m_pBaseImage = NULL;
+ m_pOverlayImage = NULL;
+ m_pCapImage = NULL;
+ m_pCapHighlightImage = NULL;
+ m_pCapPulseImage = NULL;
+ m_pCapPlayerImage = NULL;
+ m_pCapNumPlayers = NULL;
+ m_bSwipeUp = false;
+ m_flStartCapAnimStart = 0;
+ m_iCapProgressDir = CP_DIR_N;
+ m_iPrevCappers = 0;
+ m_pCountdown = NULL;
+ m_pCPTimerLabel = NULL;
+ m_pCPTimerBG = NULL;
+ m_flCPTimerTime = -1.0;
+ m_bRedText = false;
+
+ ListenForGameEvent( "controlpoint_unlock_updated" );
+ ListenForGameEvent( "controlpoint_timer_updated" );
+
+ ivgui()->AddTickSignal( GetVPanel(), 150 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_cRegularColor = pScheme->GetColor( "TanLight", Color( 235, 226, 202 ) );
+ m_cHighlightColor = pScheme->GetColor( "RedSolid", Color( 192, 28, 0 ) );
+
+ if ( !m_pCapHighlightImage )
+ {
+ m_pCapHighlightImage = new CControlPointIconSwoop( this, "CapHighlightImage" );
+ m_pCapHighlightImage->SetParent( g_pClientMode->GetViewport() );
+ m_pCapHighlightImage->SetZPos( 10 );
+ m_pCapHighlightImage->SetShouldScaleImage( true );
+ }
+
+ if ( !m_pCapPulseImage )
+ {
+ m_pCapPulseImage = new CControlPointIconCapturePulse( this, "CapPulse" );
+ m_pCapPulseImage->SetParent( g_pClientMode->GetViewport() );
+ m_pCapPulseImage->SetZPos( -1 );
+ m_pCapPulseImage->SetVisible( false );
+ m_pCapPulseImage->SetShouldScaleImage( true );
+ }
+
+ if ( !m_pBaseImage )
+ {
+ m_pBaseImage = new CControlPointIconPulseable( this, "BaseImage", m_iCPIndex );
+ m_pBaseImage->SetShouldScaleImage( true );
+ }
+
+ if ( !m_pCapImage )
+ {
+ m_pCapImage = new CControlPointIconCapArrow( this, this, "CapImage" );
+ m_pCapImage->SetZPos( 2 );
+ m_pCapImage->SetVisible( false );
+ }
+
+ if ( !m_pCountdown )
+ {
+ m_pCountdown = new CControlPointCountdown( this, "Countdown" );
+ m_pCountdown->SetZPos( 4 );
+ m_pCountdown->SetVisible( true );
+ }
+
+ if ( !m_pCPTimerLabel )
+ {
+ m_pCPTimerLabel = new CExLabel( this, "CPTimerLabel", L"" );
+ m_pCPTimerLabel->SetZPos( 0 );
+ }
+
+ if ( !m_pCPTimerBG )
+ {
+ m_pCPTimerBG = new vgui::ImagePanel( this, "CPTimerBG" );
+ m_pCPTimerBG->SetZPos( -1 );
+ m_pCPTimerBG->SetShouldScaleImage( true );
+ }
+
+ LoadControlSettings( "resource/UI/ControlPointIcon.res" );
+
+ m_pCapPlayerImage = dynamic_cast<vgui::ImagePanel *>( FindChildByName("CapPlayerImage") );
+ m_pCapNumPlayers = dynamic_cast<vgui::Label *>( FindChildByName("CapNumPlayers") );
+ m_pOverlayImage = dynamic_cast<vgui::ImagePanel *>( FindChildByName("OverlayImage") );
+
+ if ( m_pCPTimerLabel )
+ {
+ m_pCPTimerLabel->SetParent( GetParent() );
+ }
+
+ if ( m_pCPTimerBG )
+ {
+ m_pCPTimerBG->SetParent( GetParent() );
+ }
+
+ UpdateImage();
+ UpdateCapImage();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::FireGameEvent( IGameEvent *event )
+{
+ const char *pszEventName = event->GetName();
+
+ if ( FStrEq( pszEventName, "controlpoint_unlock_updated" ) )
+ {
+ int iIndex = event->GetInt( "index" );
+ if ( iIndex == m_iCPIndex )
+ {
+ float flTime = event->GetFloat( "time" );
+ SetUnlockTime( flTime );
+ }
+ }
+ else if ( FStrEq( pszEventName, "controlpoint_timer_updated" ) )
+ {
+ int iIndex = event->GetInt( "index" );
+ if ( iIndex == m_iCPIndex )
+ {
+ float flTime = event->GetFloat( "time" );
+ SetTimerTime( flTime );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CControlPointIcon::~CControlPointIcon( void )
+{
+ if ( m_pCapHighlightImage )
+ {
+ m_pCapHighlightImage->MarkForDeletion();
+ m_pCapHighlightImage = NULL;
+ }
+
+ if ( m_pCapPulseImage )
+ {
+ m_pCapPulseImage->MarkForDeletion();
+ m_pCapPulseImage = NULL;
+ }
+
+ if ( m_pCPTimerLabel )
+ {
+ m_pCPTimerLabel->MarkForDeletion();
+ m_pCPTimerLabel = NULL;
+ }
+
+ if ( m_pCPTimerBG )
+ {
+ m_pCPTimerBG->MarkForDeletion();
+ m_pCPTimerBG = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::UpdateImage( void )
+{
+ if ( !ObjectiveResource() )
+ return;
+
+ int iOwner = ObjectiveResource()->GetOwningTeam( m_iCPIndex );
+
+ if ( m_pBaseImage )
+ {
+ int iOwnerIcon = ObjectiveResource()->GetCPCurrentOwnerIcon( m_iCPIndex, iOwner );
+ const char *szMatName = GetMaterialNameFromIndex( iOwnerIcon );
+
+ if ( IsPointLocked() && !IsPointUnlockCountdownRunning() )
+ {
+ m_pBaseImage->SetImage( VarArgs("..\\%s_locked", szMatName ) );
+ }
+ else
+ {
+ m_pBaseImage->SetImage( VarArgs("..\\%s", szMatName ) );
+ }
+ }
+
+ if ( m_pOverlayImage )
+ {
+ int iOverlayIcon = ObjectiveResource()->GetOverlayForTeam( m_iCPIndex, iOwner );
+ if ( iOverlayIcon )
+ {
+ const char *szMatName = GetMaterialNameFromIndex( iOverlayIcon );
+ m_pOverlayImage->SetImage( VarArgs("..\\%s", szMatName ) );
+ m_pOverlayImage->SetVisible( true );
+ }
+ else
+ {
+ m_pOverlayImage->SetVisible( false );
+ }
+ }
+
+ // Whenever a successful cap occurs, flash the cap point
+ if ( m_pCapPulseImage )
+ {
+ if ( m_iPrevCappers != 0 && iOwner == m_iPrevCappers )
+ {
+ m_iPrevCappers = 0;
+
+ if ( ShouldDraw() )
+ {
+ m_pCapPulseImage->SetVisible( true );
+ m_pCapPulseImage->StartPulse( gpGlobals->curtime, GetWide() );
+ }
+ m_pBaseImage->StartPulsing( FINISHCAPANIM_SWOOP_LENGTH, 0.5, false );
+ }
+
+ }
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::UpdateCapImage( void )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ if ( m_pCapImage )
+ {
+ int iCappingTeam = ObjectiveResource()->GetCappingTeam( m_iCPIndex );
+ int iOwningTeam = ObjectiveResource()->GetOwningTeam( m_iCPIndex );
+
+ if ( iCappingTeam != TEAM_UNASSIGNED && iCappingTeam != iOwningTeam )
+ {
+ const char *pszCapSwipe = ObjectiveResource()->GetGameSpecificCPCappingSwipe( m_iCPIndex, iCappingTeam );
+ if ( m_bSwipeUp )
+ {
+ m_pCapImage->SetImage( VarArgs("%s_up",pszCapSwipe) );
+ }
+ else
+ {
+ m_pCapImage->SetImage( pszCapSwipe );
+ }
+ m_pCapImage->SetVisible( true );
+
+ // Tell the cap highlight image to fire up if it's our point being capped
+ if ( m_pCapHighlightImage && pPlayer->GetTeamNumber() != iCappingTeam && pPlayer->GetTeamNumber() > LAST_SHARED_TEAM )
+ {
+ if ( ShouldDraw() && GetParent() && GetParent()->IsVisible() )
+ {
+ m_pCapHighlightImage->SetVisible( true );
+ m_pCapHighlightImage->StartSwoop();
+ }
+ m_pBaseImage->StartPulsing( STARTCAPANIM_ICON_SWITCH, 0, true );
+ }
+ else
+ {
+ m_pBaseImage->StartPulsing( 0, 0, true );
+ }
+
+ if ( m_pCapPlayerImage )
+ {
+ m_pCapPlayerImage->SetVisible( true );
+ }
+
+ m_iPrevCappers = iCappingTeam;
+ InvalidateLayout( true );
+ }
+ else
+ {
+ m_pBaseImage->StopPulsing();
+ m_pCapImage->SetVisible( false );
+ if ( m_pCapHighlightImage )
+ {
+ m_pCapHighlightImage->SetVisible( false );
+ }
+ if ( m_pCapPlayerImage )
+ {
+ m_pCapPlayerImage->SetVisible( false );
+ }
+ if ( m_pCapNumPlayers )
+ {
+ m_pCapNumPlayers->SetVisible( false );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Lock cap points when neither team can cap them for map-specific reasons
+//-----------------------------------------------------------------------------
+bool CControlPointIcon::IsPointLocked( void )
+{
+ bool bAnyTeamCanCap = false;
+ for ( int gameteam = FIRST_GAME_TEAM; gameteam < GetNumberOfTeams(); gameteam++ )
+ {
+ // Ignore teams that already own the point
+ if ( ObjectiveResource()->GetOwningTeam(m_iCPIndex) != gameteam )
+ {
+ if ( (ObjectiveResource()->TeamCanCapPoint( m_iCPIndex, gameteam)) )
+ {
+ if ( TeamplayGameRules()->TeamMayCapturePoint( gameteam, m_iCPIndex ) )
+ {
+ bAnyTeamCanCap = true;
+ }
+ }
+ }
+ }
+
+ return ( !bAnyTeamCanCap );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Lock cap points when neither team can cap them for map-specific reasons
+//-----------------------------------------------------------------------------
+bool CControlPointIcon::IsPointUnlockCountdownRunning( void )
+{
+ if ( m_pCountdown && ( TeamplayRoundBasedRules() && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) )
+ {
+ if ( m_pCountdown->GetUnlockTime() > 0 )
+ {
+ int nTimeToUnlock = m_pCountdown->GetUnlockTime() - gpGlobals->curtime;
+ if ( nTimeToUnlock < 6 )
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Used by the intro to fake the pulsing of this icon
+//-----------------------------------------------------------------------------
+void CControlPointIcon::FakePulse( float flTime )
+{
+ if ( m_pCapPulseImage )
+ {
+ m_pCapPulseImage->SetVisible( true );
+ m_pCapPulseImage->StartPulse( flTime, GetWide() );
+ m_pBaseImage->StartPulsing( flTime + FINISHCAPANIM_SWOOP_LENGTH - gpGlobals->curtime, 0.8, false );
+
+ InvalidateLayout();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CControlPointIcon::IsVisible( void )
+{
+ if ( IsInFreezeCam() == true )
+ return false;
+
+ return BaseClass::IsVisible();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::Paint( void )
+{
+ if ( m_bCachedLockedState != IsPointLocked() ||
+ m_bCachedCountdownState != IsPointUnlockCountdownRunning() )
+ {
+ UpdateImage();
+ }
+
+ m_bCachedCountdownState = IsPointUnlockCountdownRunning();
+ m_bCachedLockedState = IsPointLocked();
+
+ BaseClass::Paint();
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ int iBaseXPos, iBaseYPos;
+ ipanel()->GetAbsPos(GetVPanel(), iBaseXPos, iBaseYPos );
+
+ m_pBaseImage->SetBounds( 0, 0, GetWide(), GetTall() );
+ m_pCountdown->SetBounds( 0, 0, GetWide(), GetTall() );
+
+ if ( m_pCapImage->IsVisible() )
+ {
+ m_pCapImage->SetBounds( 0, 0, GetWide(), GetTall() );
+ }
+
+ if ( m_pCapHighlightImage->IsVisible() )
+ {
+ int iHeight = ScreenHeight() * 0.75;
+ m_pCapHighlightImage->SetBounds( iBaseXPos + CAP_BOX_INDENT_X, iBaseYPos - iHeight, GetWide() - (CAP_BOX_INDENT_X*2), iHeight + GetTall() -CAP_BOX_INDENT_Y );
+ }
+
+ int iCappingTeam = ObjectiveResource()->GetCappingTeam( m_iCPIndex );
+ int iPlayers = ObjectiveResource()->GetNumPlayersInArea( m_iCPIndex, iCappingTeam );
+ if ( m_pCapPlayerImage && !m_pCapPlayerImage->IsVisible() && iPlayers )
+ {
+ m_pCapPlayerImage->SetVisible(true);
+ }
+ if ( m_pCapPlayerImage && m_pCapPlayerImage->IsVisible() )
+ {
+ if ( !iPlayers )
+ {
+ // We're a deteriorating point
+ m_pCapPlayerImage->SetVisible( false );
+ if ( m_pCapNumPlayers )
+ {
+ m_pCapNumPlayers->SetVisible( false );
+ }
+ }
+ else
+ {
+ int iXPos, iYPos;
+ if ( ( iPlayers < 2 ) || !m_pCapNumPlayers )
+ {
+ iXPos = (GetWide() - m_pCapPlayerImage->GetWide()) * 0.5;
+ }
+ else
+ {
+ iXPos = (GetWide() - m_pCapPlayerImage->GetWide()) * 0.5 - XRES(4);
+ }
+ iYPos = (GetTall() - m_pCapPlayerImage->GetTall()) * 0.5;
+
+ m_pCapPlayerImage->SetPos( iXPos, iYPos );
+
+ if ( m_pCapNumPlayers )
+ {
+ m_pCapNumPlayers->SetVisible( (iPlayers>1) );
+ SetDialogVariable( "numcappers", iPlayers );
+
+ m_pCapNumPlayers->SetFgColor( Color(0,0,0,255) );
+ }
+ }
+ }
+
+ if ( m_pCapPulseImage )
+ {
+ int iSize = GetWide() * 3;
+ int iXpos = iBaseXPos - ((iSize-GetWide()) * 0.5);
+ int iYpos = iBaseYPos - ((iSize-GetTall()) * 0.5);
+ m_pCapPulseImage->SetBounds( iXpos, iYpos, iSize, iSize );
+ }
+
+ SetTimerTime( m_flCPTimerTime );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::OnTick( void )
+{
+ if ( m_flCPTimerTime < 0 )
+ return;
+
+ if ( !m_pCPTimerLabel || !m_pCPTimerLabel->IsVisible() )
+ return;
+
+ int nTime = 0;
+ if ( m_flCPTimerTime - gpGlobals->curtime > 0 )
+ {
+ nTime = ceil( m_flCPTimerTime - gpGlobals->curtime );
+ }
+
+ if ( nTime <= 10 ) // start flashing with 10 seconds left
+ {
+ if ( m_bRedText )
+ {
+ m_bRedText = false;
+ m_pCPTimerLabel->SetFgColor( m_cRegularColor );
+ }
+ else
+ {
+ m_bRedText = true;
+ m_pCPTimerLabel->SetFgColor( m_cHighlightColor );
+ }
+ }
+
+ char szTime[4];
+ Q_snprintf( szTime, sizeof( szTime ), "%d", nTime );
+ m_pCPTimerLabel->SetText( szTime );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIcon::SetTimerTime( float flTime )
+{
+ m_flCPTimerTime = flTime;
+
+ if ( m_pCPTimerBG && m_pCPTimerLabel )
+ {
+ if ( flTime < 0 )
+ {
+ m_pCPTimerBG->SetVisible( false );
+ m_pCPTimerLabel->SetVisible( false );
+ }
+ else
+ {
+ int xPos, yPos;
+ GetPos( xPos, yPos );
+
+ m_pCPTimerBG->SetPos( xPos, yPos );
+ m_pCPTimerBG->SetVisible( true );
+
+ m_bRedText = false;
+ m_pCPTimerLabel->SetFgColor( m_cRegularColor ); // reset our color
+ m_pCPTimerLabel->SetPos( xPos + GetWide() - XRES(1), yPos + ( GetTall() / 2 ) - ( m_pCPTimerLabel->GetTall() / 2 ) );
+ m_pCPTimerLabel->SetVisible( true );
+ OnTick(); // call this now so our time gets initialized
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudControlPointIcons::CHudControlPointIcons( const char *pName ) : vgui::Panel( NULL, "HudControlPointIcons" ), CHudElement( pName )
+{
+ SetParent( g_pClientMode->GetViewport() );
+ SetHiddenBits( HIDEHUD_MISCSTATUS );
+
+ m_iBackgroundTexture = vgui::surface()->DrawGetTextureId( "vgui/white" );
+ if ( m_iBackgroundTexture == -1 )
+ {
+ m_iBackgroundTexture = vgui::surface()->CreateNewTextureID();
+ vgui::surface()->DrawSetTextureFile( m_iBackgroundTexture, "vgui/white", true, true );
+ }
+
+ Reset();
+
+ // Initialize textures to invalid
+ for( int i = 0; i < ARRAYSIZE( m_iCPTextures ); i++ )
+ {
+ m_iCPTextures[i] = -1;
+ m_iCPCappingTextures[i] = -1;
+ }
+
+ for( int i = FIRST_GAME_TEAM; i < MAX_TEAMS; i++ )
+ {
+ m_iTeamBaseTextures[i] = -1;
+ }
+}
+
+DECLARE_HUDELEMENT( CHudControlPointIcons );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CHudControlPointIcons::~CHudControlPointIcons( void )
+{
+ ShutdownIcons();
+
+ if ( vgui::surface() )
+ {
+ // Clear out all the texture IDs
+ for( int i = 0; i < ARRAYSIZE( m_iCPTextures ); i++ )
+ {
+ if ( m_iCPTextures[i] != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iCPTextures[i] );
+ m_iCPTextures[i] = -1;
+ }
+
+ if ( m_iCPCappingTextures[i] != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iCPCappingTextures[i] );
+ m_iCPCappingTextures[i] = -1;
+ }
+ }
+
+ for( int i = FIRST_GAME_TEAM; i < MAX_TEAMS; i++ )
+ {
+ if ( m_iTeamBaseTextures[i] != -1 )
+ {
+ vgui::surface()->DestroyTextureID( m_iTeamBaseTextures[i] );
+ m_iTeamBaseTextures[i] = -1;
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::Init( void )
+{
+ for( int i = 0; i < ARRAYSIZE( m_iCPTextures ); i++ )
+ {
+ if ( m_iCPTextures[i] == -1 )
+ {
+ m_iCPTextures[i] = vgui::surface()->CreateNewTextureID();
+ }
+
+ if ( m_iCPCappingTextures[i] == -1 )
+ {
+ m_iCPCappingTextures[i] = vgui::surface()->CreateNewTextureID();
+ }
+ }
+
+ for( int i = FIRST_GAME_TEAM; i < MAX_TEAMS; i++ )
+ {
+ if ( m_iTeamBaseTextures[i] == -1 )
+ {
+ m_iTeamBaseTextures[i] = vgui::surface()->CreateNewTextureID();
+ }
+ }
+
+ ListenForGameEvent( "controlpoint_initialized" );
+ ListenForGameEvent( "controlpoint_updateimages" );
+ ListenForGameEvent( "controlpoint_updatelayout" );
+ ListenForGameEvent( "controlpoint_updatecapping" );
+ ListenForGameEvent( "controlpoint_starttouch" );
+ ListenForGameEvent( "controlpoint_endtouch" );
+ ListenForGameEvent( "controlpoint_pulse_element" );
+ ListenForGameEvent( "controlpoint_fake_capture" );
+ ListenForGameEvent( "controlpoint_fake_capture_mult" );
+ ListenForGameEvent( "intro_nextcamera" );
+ ListenForGameEvent( "intro_finish" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::Reset( void )
+{
+ m_iCurrentCP = -1;
+ m_iLastCP = -1;
+ m_flIconExpand = 0;
+ m_flPulseTime = 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CHudControlPointIcons::IsVisible( void )
+{
+ if ( IsInFreezeCam() == true )
+ return false;
+
+ if ( CHudElement::ShouldDraw() == false )
+ return false;
+
+ return BaseClass::IsVisible();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::LevelShutdown( void )
+{
+ ShutdownIcons();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::FireGameEvent( IGameEvent *event )
+{
+ const char *eventname = event->GetName();
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if ( FStrEq( "controlpoint_initialized", eventname ) )
+ {
+ // Create our control points
+ InitIcons();
+ return;
+ }
+
+ if ( FStrEq( "controlpoint_updateimages", eventname ) )
+ {
+ // Update the images of our control point icons
+ int iIndex = event->GetInt( "index" );
+ if ( iIndex == -1 )
+ {
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ m_Icons[i]->UpdateImage();
+ }
+ }
+ else
+ {
+ // Only invalidate the specified cap point
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ if ( m_Icons[i]->GetCapIndex() == iIndex )
+ {
+ m_Icons[i]->UpdateImage();
+ }
+ }
+ }
+ UpdateProgressBarFor( iIndex );
+ return;
+ }
+
+ if ( FStrEq( "controlpoint_updatelayout", eventname ) )
+ {
+ // Update the layout of our control point icons
+ int iIndex = event->GetInt( "index" );
+ if ( iIndex == -1 )
+ {
+ InvalidateLayout();
+ }
+ else
+ {
+ // Only invalidate the specified cap point
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ if ( m_Icons[i]->GetCapIndex() == iIndex )
+ {
+ m_Icons[i]->InvalidateLayout();
+ }
+ }
+ }
+ UpdateProgressBarFor( iIndex );
+ return;
+ }
+
+ if ( FStrEq( "controlpoint_updatecapping", eventname ) )
+ {
+ // Update the capping status of our control point icons
+ int iIndex = event->GetInt( "index" );
+ if ( iIndex == -1 )
+ {
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ m_Icons[i]->UpdateCapImage();
+ }
+ }
+ else
+ {
+ // Only invalidate the specified cap point
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ if ( m_Icons[i]->GetCapIndex() == iIndex )
+ {
+ m_Icons[i]->UpdateCapImage();
+ }
+ }
+ }
+
+ UpdateProgressBarFor( iIndex );
+ return;
+ }
+
+ if ( FStrEq( "controlpoint_starttouch", eventname ) )
+ {
+ int iPlayer = event->GetInt( "player" );
+ if ( pPlayer && iPlayer == pPlayer->entindex() )
+ {
+ m_iCurrentCP = event->GetInt( "area" );
+ UpdateProgressBarFor( m_iCurrentCP );
+ }
+ }
+ else if ( FStrEq( "controlpoint_endtouch", eventname ) )
+ {
+ int iPlayer = event->GetInt( "player" );
+ if ( pPlayer && iPlayer == pPlayer->entindex() )
+ {
+ m_iCurrentCP = -1;
+ UpdateProgressBarFor( m_iCurrentCP );
+ }
+ }
+ else if ( FStrEq( "controlpoint_pulse_element", eventname ) )
+ {
+ int iPlayer = event->GetInt( "player" );
+ if ( pPlayer && iPlayer == pPlayer->entindex() )
+ {
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ m_Icons[i]->FakePulse( gpGlobals->curtime + (i * PULSE_TIME_PER_ICON) );
+ }
+ }
+ }
+ else if ( FStrEq( "controlpoint_fake_capture", eventname ) )
+ {
+ int iPlayer = event->GetInt( "player" );
+ if ( pPlayer && iPlayer == pPlayer->entindex() )
+ {
+ m_iCurrentCP = event->GetInt( "int_data" );
+ m_bFakingCapture = true;
+ m_bFakingCaptureMult = false;
+ m_flFakeCaptureTime = gpGlobals->curtime + FAKE_CAPTURE_TIME + FAKE_CAPTURE_POST_PAUSE;
+ UpdateProgressBarFor( -1 );
+ }
+ }
+ else if ( FStrEq( "controlpoint_fake_capture_mult", eventname ) )
+ {
+ int iPlayer = event->GetInt( "player" );
+ if ( pPlayer && iPlayer == pPlayer->entindex() )
+ {
+ m_iCurrentCP = event->GetInt( "int_data" );
+ m_bFakingCapture = true;
+ m_bFakingCaptureMult = true;
+ m_flFakeCaptureTime = gpGlobals->curtime + FAKE_CAPTURE_TIME + FAKE_CAPTURE_POST_PAUSE;
+ UpdateProgressBarFor( -1 );
+ }
+ }
+ else if ( FStrEq( "intro_nextcamera", eventname ) )
+ {
+ int iPlayer = event->GetInt( "player" );
+ if ( pPlayer && iPlayer == pPlayer->entindex() )
+ {
+ m_iCurrentCP = -1;
+ m_bFakingCapture = false;
+ m_bFakingCaptureMult = false;
+ UpdateProgressBarFor( -1 );
+ }
+ }
+ else if ( FStrEq( "intro_finish", eventname ) )
+ {
+ int iPlayer = event->GetInt( "player" );
+ if ( pPlayer && iPlayer == pPlayer->entindex() )
+ {
+ m_iCurrentCP = -1;
+ m_flPulseTime = 0;
+ m_bFakingCapture = false;
+ m_bFakingCaptureMult = false;
+
+ InitIcons();
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_hTextFont = pScheme->GetFont( "ChatFont" );
+
+ m_clrBackground = pScheme->GetColor( "HudPanelBackground", GetFgColor() );
+ m_clrBorder = pScheme->GetColor( "HudPanelBorder", GetBgColor() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ int iCapPointLines[MAX_CONTROL_POINTS][MAX_CONTROL_POINTS];
+ memset( iCapPointLines, 0, sizeof(int) * MAX_CONTROL_POINTS * MAX_CONTROL_POINTS );
+ bool bUseDefaultLines = true;
+ if ( ObjectiveResource() )
+ {
+ // Allow the objective resource to override it
+ const char *pszLayout = ObjectiveResource()->GetCapLayoutInHUD();
+ if ( pszLayout && pszLayout[0] )
+ {
+ bUseDefaultLines = false;
+
+ // Cap layout is a string with indexes of cap points seperated by ',' to denote
+ // a new line. So "3,1 2" would create a pyramid, with cap point 3 on the
+ // first line, and caps 1 & 2 on the second line.
+ int iLine = 0;
+ int iCapIndex = 0;
+ char szBuffer[MAX_CAPLAYOUT_LENGTH];
+ Q_strncpy( szBuffer, pszLayout, MAX_CAPLAYOUT_LENGTH );
+ char *pszChar = szBuffer;
+ char *pszLastNumber = pszChar;
+ while ( *pszChar )
+ {
+ pszChar++;
+
+ if ( *pszChar == ' ' || *pszChar == ',' )
+ {
+ // Get the number
+ char cOrg = *pszChar;
+ *pszChar = '\0';
+
+ int iCPIndex = atoi( pszLastNumber );
+ int iIconIndex = -1;
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ if ( m_Icons[i]->GetCapIndex() == iCPIndex )
+ {
+ iIconIndex = i;
+ break;
+ }
+ }
+
+ if ( iIconIndex != -1 )
+ {
+ iCapPointLines[iLine][iCapIndex] = iIconIndex+1;
+ *pszChar = cOrg;
+ if ( *pszChar == ',' )
+ {
+ iLine++;
+ iCapIndex = 0;
+ }
+ else
+ {
+ iCapIndex++;
+ }
+ }
+
+ // Walk past the ,/space
+ pszChar++;
+ pszLastNumber = pszChar;
+ }
+ }
+
+ // Now get the trailing number
+ int iCPIndex = atoi( pszLastNumber );
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ if ( m_Icons[i]->GetCapIndex() == iCPIndex )
+ {
+ iCapPointLines[iLine][iCapIndex] = i+1;
+ break;
+ }
+ }
+ }
+ }
+
+ if ( bUseDefaultLines )
+ {
+ // By default, put all the caps on a single line
+ int iCPIndex = 0;
+ for (int iIcon = 0; iIcon < m_Icons.Count(); iIcon++)
+ {
+ iCapPointLines[0][iCPIndex] = iIcon+1;
+ iCPIndex++;
+ }
+ }
+
+ int iTall = m_iIconGapHeight;
+ int iTallest = m_iIconGapHeight;
+ int iWidest = m_iIconGapWidth;
+ int iTotalIconsPerLine[MAX_CONTROL_POINTS];
+ int iLineWidth[MAX_CONTROL_POINTS];
+ memset( iTotalIconsPerLine, 0, sizeof(int) * MAX_CONTROL_POINTS );
+ memset( iLineWidth, 0, sizeof(int) * MAX_CONTROL_POINTS );
+ int iTotalLines = 0;
+
+ // Search through the lines and figure out our overall width & height
+ for ( int iLine = 0; iLine < MAX_CONTROL_POINTS; iLine++ )
+ {
+ // If we've hit a line with nothing in it, we're done
+ if ( !iCapPointLines[iLine][0] )
+ break;
+
+ iTotalLines++;
+
+ iLineWidth[iLine] = m_iIconGapWidth;
+ int iLineTall = 0;
+ for ( int iPosition = 0; iPosition < MAX_CONTROL_POINTS; iPosition++ )
+ {
+ int iIconIndex = iCapPointLines[iLine][iPosition];
+ if ( !iIconIndex )
+ break;
+
+ iIconIndex--;
+
+ // Add the icon dimensions to our counts.
+ if ( iIconIndex >= 0 && iIconIndex < m_Icons.Count() )
+ {
+ m_Icons[iIconIndex]->PerformLayout();
+ iTotalIconsPerLine[iLine]++;
+
+ iLineWidth[iLine] += m_Icons[iIconIndex]->GetWide() + m_iIconGapWidth;
+ int iHeight = m_Icons[iIconIndex]->GetTall();
+ if ( iHeight > iLineTall )
+ {
+ iLineTall = iHeight;
+ }
+ }
+ }
+
+ if ( iLineWidth[iLine] > iWidest )
+ {
+ iWidest = iLineWidth[iLine];
+ }
+ if ( iLineTall > iTallest )
+ {
+ iTallest = iLineTall;
+ }
+ iTall += iLineTall + m_iIconGapHeight;
+ }
+
+ // Setup the main panel
+ SetBounds( (ScreenWidth() - iWidest) * 0.5, ScreenHeight() - iTall - m_nHeightOffset, iWidest, iTall );
+
+ // Now that we know how wide we are, and how many icons are in each line,
+ // we can lay the icons out, centered in the lines.
+ for ( int iLine = 0; iLine < MAX_CONTROL_POINTS; iLine++ )
+ {
+ if ( !iTotalIconsPerLine[iLine] )
+ break;
+
+ int iLineXPos = ((iWidest - iLineWidth[iLine]) * 0.5) + m_iIconGapWidth;
+ int iLineYPos = (iLine * m_iIconGapHeight) + ( iLine * iTallest ) + m_iIconGapHeight;
+ for ( int iPosition = 0; iPosition < MAX_CONTROL_POINTS; iPosition++ )
+ {
+ int iIconIndex = iCapPointLines[iLine][iPosition];
+ if ( !iIconIndex )
+ break;
+
+ iIconIndex--;
+
+ if ( iIconIndex >= 0 && iIconIndex < m_Icons.Count() )
+ {
+ m_Icons[iIconIndex]->SetPos( iLineXPos, iLineYPos );
+ iLineXPos += m_Icons[iIconIndex]->GetWide() + m_iIconGapWidth;
+
+ // If we have multiple lines, swipe up when capping
+ m_Icons[iIconIndex]->SetSwipeUp( iTotalLines > 1 );
+
+ // Set the progress extrusion dir:
+ // N if we're on the top line. Otherwise:
+ // NW if we're left of the center.
+ // NE if we're at or right of the center.
+ int iDir = CP_DIR_N;
+ if ( iLine > 0 )
+ {
+ if ( ((float)(iPosition+1) / (float)iTotalIconsPerLine[iLine]) > 0.5 )
+ {
+ iDir = CP_DIR_NE;
+ }
+ else
+ {
+ iDir = CP_DIR_NW;
+ }
+ }
+
+ m_Icons[iIconIndex]->SetCapProgressDir( iDir );
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::UpdateProgressBarFor( int iIndex )
+{
+ // If they tell us to update all progress bars, update only the one we're standing on
+ if ( iIndex == -1 )
+ {
+ iIndex = m_iCurrentCP;
+ }
+
+ // Ignore requests to display progress bars for points we're not standing on
+ if ( ( m_iCurrentCP != iIndex ) )
+ return;
+
+ // This can happen at level load
+ CTFHudObjectiveStatus *pStatus = GET_HUDELEMENT( CTFHudObjectiveStatus );
+ if ( pStatus && pStatus->GetControlPointProgressBar() )
+ {
+ CControlPointProgressBar *pProgressBar = pStatus->GetControlPointProgressBar();
+ if ( !IsVisible() || iIndex < 0 || iIndex >= ObjectiveResource()->GetNumControlPoints() )
+ {
+ pProgressBar->SetupForPoint( NULL );
+ }
+ else
+ {
+ for (int i = 0; i < m_Icons.Count(); i++)
+ {
+ if ( m_Icons[i]->GetCapIndex() == iIndex )
+ {
+ pProgressBar->SetupForPoint( m_Icons[i] );
+ break;
+ }
+ }
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create the icons we need to display the state of this map's control points
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::InitIcons( void )
+{
+ ShutdownIcons();
+
+ CTFHudObjectiveStatus *pStatus = GET_HUDELEMENT( CTFHudObjectiveStatus );
+ if ( pStatus )
+ {
+ CControlPointProgressBar *pProgressBar = pStatus->GetControlPointProgressBar();
+
+ if ( pProgressBar )
+ {
+ m_iCurrentCP = -1;
+ pProgressBar->SetupForPoint( NULL );
+ }
+ }
+
+ // Create an icon for each visible control point in this miniround
+ int iPoints = ObjectiveResource()->GetNumControlPoints();
+ for ( int i = 0; i < iPoints; i++ )
+ {
+ if ( ObjectiveResource()->IsInMiniRound(i) && ObjectiveResource()->IsCPVisible(i) )
+ {
+ CControlPointIcon *pIcon = new CControlPointIcon( this, VarArgs( "ControlPointIcon%d", i ), i );
+ m_Icons.AddToTail( vgui::SETUP_PANEL(pIcon) );
+ }
+ }
+
+ InvalidateLayout();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::ShutdownIcons( void )
+{
+ for ( int i = 0; i < m_Icons.Count(); i++ )
+ {
+ m_Icons[i]->MarkForDeletion();
+ }
+ m_Icons.RemoveAll();
+
+ // if we remove all the icons, we need to make sure the progress bar isn't holding onto one
+ CTFHudObjectiveStatus *pStatus = GET_HUDELEMENT( CTFHudObjectiveStatus );
+ if ( pStatus )
+ {
+ CControlPointProgressBar *pProgressBar = pStatus->GetControlPointProgressBar();
+ if ( pProgressBar )
+ {
+ m_iCurrentCP = -1;
+ pProgressBar->SetupForPoint( NULL );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::DrawBackgroundBox( int xpos, int ypos, int nBoxWidth, int nBoxHeight, bool bCutCorner )
+{
+ int nCornerCutSize = bCutCorner ? m_nCornerCutSize : 0;
+ vgui::Vertex_t verts[5];
+
+ verts[0].Init( Vector2D( xpos, ypos ) );
+ verts[1].Init( Vector2D( xpos + nBoxWidth, ypos ) );
+ verts[2].Init( Vector2D( xpos + nBoxWidth + 1, ypos + nBoxHeight - nCornerCutSize + 1 ) );
+ verts[3].Init( Vector2D( xpos + nBoxWidth - nCornerCutSize + 1, ypos + nBoxHeight + 1 ) );
+ verts[4].Init( Vector2D( xpos, ypos + nBoxHeight ) );
+
+ vgui::surface()->DrawSetTexture( m_iBackgroundTexture );
+ vgui::surface()->DrawSetColor( Color( m_clrBackground ) );
+ vgui::surface()->DrawTexturedPolygon( 5, verts );
+
+ vgui::Vertex_t borderverts[5];
+
+ borderverts[0].Init( Vector2D( xpos, ypos ) );
+ borderverts[1].Init( Vector2D( xpos + nBoxWidth, ypos ) );
+ borderverts[2].Init( Vector2D( xpos + nBoxWidth, ypos + nBoxHeight - nCornerCutSize ) );
+ borderverts[3].Init( Vector2D( xpos + nBoxWidth - nCornerCutSize, ypos + nBoxHeight ) );
+ borderverts[4].Init( Vector2D( xpos, ypos + nBoxHeight ) );
+
+ vgui::surface()->DrawSetColor( Color( m_clrBorder ) );
+ vgui::surface()->DrawTexturedPolyLine( borderverts, 5 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw the team's base icon at either end of the icon panel
+//-----------------------------------------------------------------------------
+bool CHudControlPointIcons::PaintTeamBaseIcon( int index, float flXPos, float flYPos, float flIconSize )
+{
+ float uv1 = 0.0f;
+ float uv2 = 1.0f;
+
+ // Find out which team owns the far left
+ for ( int i = 0; i < MAX_TEAMS; i++ )
+ {
+ if ( ObjectiveResource()->GetBaseControlPointForTeam(i) == index )
+ {
+ int iTeamBaseIcon = ObjectiveResource()->GetBaseIconForTeam(i);
+ if ( iTeamBaseIcon )
+ {
+ // Draw the Team's Base texture
+ const char *szMatName = GetMaterialNameFromIndex( iTeamBaseIcon );
+
+ vgui::surface()->DrawSetTextureFile( m_iTeamBaseTextures[i], szMatName, true, false );
+
+ Vector2D uv11( uv1, uv1 );
+ Vector2D uv21( uv2, uv1 );
+ Vector2D uv22( uv2, uv2 );
+ Vector2D uv12( uv1, uv2 );
+
+ vgui::Vertex_t vert[4];
+ vert[0].Init( Vector2D( flXPos, flYPos ), uv11 );
+ vert[1].Init( Vector2D( flXPos + flIconSize, flYPos ), uv21 );
+ vert[2].Init( Vector2D( flXPos + flIconSize, flYPos + flIconSize ), uv22 );
+ vert[3].Init( Vector2D( flXPos, flYPos + flIconSize ), uv12 );
+
+ vgui::surface()->DrawSetColor( Color(255,255,255,255) );
+ vgui::surface()->DrawTexturedPolygon( 4, vert );
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CHudControlPointIcons::Paint()
+{
+ if ( IsInFreezeCam() == true )
+ return;
+
+ if( !ObjectiveResource() )
+ return;
+
+ int num = ObjectiveResource()->GetNumControlPoints();
+ if ( num <= 0 )
+ return; // nothing to draw yet
+
+ //DrawBackgroundBox( 0, 0, GetWide(), GetTall(), false );
+ BaseClass::Paint();
+}
+
+
+//========================================================================================================================
+// CONTROL POINT PROGRESS BAR
+//========================================================================================================================
+CControlPointProgressBar::CControlPointProgressBar(Panel *parent) : vgui::EditablePanel( parent, "ControlPointProgressBar" )
+{
+ m_pAttachedToIcon = NULL;
+ m_pBar = NULL;
+ m_pBarText = NULL;
+ m_pTeardrop = NULL;
+ m_pTeardropSide = NULL;
+ m_pBlocked = NULL;
+ m_iOrgHeight = 0;
+ m_iMidGroupIndex = -1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointProgressBar::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ LoadControlSettings( "resource/UI/ControlPointProgressBar.res" );
+
+ m_pBar = dynamic_cast<vgui::CircularProgressBar *>( FindChildByName("ProgressBar") );
+ m_pBarText = dynamic_cast<vgui::Label *>( FindChildByName("ProgressText") );
+ m_pTeardrop = dynamic_cast<CIconPanel *>( FindChildByName("Teardrop") );
+ m_pTeardropSide = dynamic_cast<CIconPanel *>( FindChildByName("TeardropSide") );
+ m_pBlocked = dynamic_cast<CIconPanel *>( FindChildByName("Blocked") );
+ m_iOrgHeight = GetTall();
+
+ m_iMidGroupIndex = gHUD.LookupRenderGroupIndexByName( "mid" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointProgressBar::PerformLayout( void )
+{
+ BaseClass::PerformLayout();
+
+ if ( m_pAttachedToIcon && m_pTeardrop && m_pTeardropSide )
+ {
+ int iIconX, iIconY;
+ ipanel()->GetAbsPos(m_pAttachedToIcon->GetVPanel(), iIconX, iIconY );
+ int iDir = m_pAttachedToIcon->GetCapProgressDir();
+ int iXPos = 0;
+ int iYPos = 0;
+
+ int iEdgeSpace = (GetWide() - m_pTeardrop->GetWide()) * 0.5;
+
+ // Line up our middle with the middle of the icon
+ switch ( iDir )
+ {
+ default:
+ case CP_DIR_N:
+ SetSize( GetWide(), m_iOrgHeight );
+ m_pTeardrop->SetVisible( true );
+ m_pTeardropSide->SetVisible( false );
+ iXPos = iIconX - ((GetWide() - m_pAttachedToIcon->GetWide()) * 0.5);
+ iYPos = iIconY - GetTall();
+ break;
+
+ case CP_DIR_NE:
+ SetSize( GetWide(), m_iOrgHeight );
+ m_pTeardropSide->SetIcon( "cappoint_progressbar_teardrop_right" );
+ m_pTeardrop->SetVisible( false );
+ m_pTeardropSide->SetVisible( true );
+ iXPos = iIconX + m_pAttachedToIcon->GetWide() - iEdgeSpace;
+ iYPos = iIconY - GetTall();
+ break;
+
+ case CP_DIR_NW:
+ SetSize( GetWide(), m_iOrgHeight );
+ m_pTeardropSide->SetIcon( "cappoint_progressbar_teardrop_left" );
+ m_pTeardrop->SetVisible( false );
+ m_pTeardropSide->SetVisible( true );
+ iXPos = iIconX - GetWide() + iEdgeSpace;
+ iYPos = iIconY - GetTall();
+ break;
+ }
+
+ SetPos( iXPos, iYPos );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointProgressBar::Reset( void )
+{
+ m_pAttachedToIcon = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+bool CControlPointProgressBar::IsVisible( void )
+{
+ if ( IsInFreezeCam() == true )
+ return false;
+
+ if ( m_iMidGroupIndex != -1 && gHUD.IsRenderGroupLockedFor( NULL, m_iMidGroupIndex ) )
+ return false;
+
+ return BaseClass::IsVisible();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointProgressBar::Paint( void )
+{
+ if ( m_pAttachedToIcon )
+ {
+ int iCP = m_pAttachedToIcon->GetCapIndex();
+ if ( m_pBar && m_pBar->IsVisible() )
+ {
+ m_pBar->SetProgress( ObjectiveResource()->GetCPCapPercentage( iCP ) );
+ }
+ }
+
+ BaseClass::Paint();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointProgressBar::SetupForPoint( CControlPointIcon *pIcon )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer )
+ return;
+
+ m_pAttachedToIcon = pIcon;
+
+ bool bInWinState = TeamplayRoundBasedRules() ? TeamplayRoundBasedRules()->RoundHasBeenWon() : false;
+
+ if ( m_pAttachedToIcon && !bInWinState )
+ {
+ SetVisible( true );
+
+ int iCP = m_pAttachedToIcon->GetCapIndex();
+ int iCappingTeam = ObjectiveResource()->GetCappingTeam( iCP );
+ int iOwnerTeam = ObjectiveResource()->GetOwningTeam( iCP );
+ int iPlayerTeam = pPlayer->GetTeamNumber();
+ bool bCapBlocked = ObjectiveResource()->CapIsBlocked( iCP );
+
+ if ( !bCapBlocked && iCappingTeam != TEAM_UNASSIGNED && iCappingTeam != iOwnerTeam && iCappingTeam == iPlayerTeam )
+ {
+ m_pBar->SetBgImage( ObjectiveResource()->GetGameSpecificCPBarBG( iCP, iCappingTeam ) );
+ m_pBar->SetFgImage( ObjectiveResource()->GetGameSpecificCPBarFG( iCP, iOwnerTeam ) );
+ m_pBar->SetVisible( true );
+ m_pBlocked->SetVisible( false );
+ m_pBarText->SetVisible( false );
+ }
+ else
+ {
+ m_pBar->SetVisible( false );
+ m_pBlocked->SetVisible( true );
+
+ UpdateBarText();
+ }
+
+ InvalidateLayout();
+ }
+ else
+ {
+ SetVisible( false );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointProgressBar::UpdateBarText( void )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+ if ( !pPlayer || !m_pBarText || !m_pAttachedToIcon )
+ return;
+
+ m_pBarText->SetVisible( true );
+
+ int iCP = m_pAttachedToIcon->GetCapIndex();
+ int iCappingTeam = ObjectiveResource()->GetCappingTeam( iCP );
+ int iPlayerTeam = pPlayer->GetTeamNumber();
+ int iOwnerTeam = ObjectiveResource()->GetOwningTeam( iCP );
+
+ if ( !TeamplayGameRules()->PointsMayBeCaptured() )
+ {
+ m_pBarText->SetText( "#Team_Capture_NotNow" );
+ return;
+ }
+
+ if ( ObjectiveResource()->GetCPLocked( iCP ) )
+ {
+ m_pBarText->SetText( "#Team_Capture_NotNow" );
+ return;
+ }
+
+ if ( mp_blockstyle.GetInt() == 1 && iCappingTeam != TEAM_UNASSIGNED && iCappingTeam != iPlayerTeam )
+ {
+ if ( ObjectiveResource()->IsCPBlocked(iCP) )
+ {
+ m_pBarText->SetText( "#Team_Blocking_Capture" );
+ return;
+ }
+ else if ( iOwnerTeam == TEAM_UNASSIGNED )
+ {
+ m_pBarText->SetText( "#Team_Reverting_Capture" );
+ return;
+ }
+ }
+
+ if ( ObjectiveResource()->GetOwningTeam(iCP) == iPlayerTeam )
+ {
+ // If the opponents can never recapture this point back, we use a different string
+ if ( iPlayerTeam != TEAM_UNASSIGNED )
+ {
+ int iEnemyTeam = ( iPlayerTeam == TF_TEAM_RED ) ? TF_TEAM_BLUE : TF_TEAM_RED;
+ if ( !ObjectiveResource()->TeamCanCapPoint( iCP, iEnemyTeam ) )
+ {
+ m_pBarText->SetText( "#Team_Capture_Owned" );
+ return;
+ }
+ }
+
+ m_pBarText->SetText( "#Team_Capture_OwnPoint" );
+ return;
+ }
+
+ if ( !TeamplayGameRules()->TeamMayCapturePoint( iPlayerTeam, iCP ) )
+ {
+ if ( TeamplayRoundBasedRules() && TeamplayRoundBasedRules()->IsInArenaMode() == true )
+ {
+ m_pBarText->SetText( "#Team_Capture_NotNow" );
+ }
+ else
+ {
+ m_pBarText->SetText( "#Team_Capture_Linear" );
+ }
+
+ return;
+ }
+
+ char szReason[256];
+ if ( !TeamplayGameRules()->PlayerMayCapturePoint( pPlayer, iCP, szReason, sizeof(szReason) ) )
+ {
+ m_pBarText->SetText( szReason );
+ return;
+ }
+
+ bool bHaveRequiredPlayers = true;
+
+ // In Capstyle 1, more players simply cap faster, no required amounts.
+ if ( mp_capstyle.GetInt() != 1 )
+ {
+ int nNumTeammates = ObjectiveResource()->GetNumPlayersInArea( iCP, iPlayerTeam );
+ int nRequiredTeammates = ObjectiveResource()->GetRequiredCappers( iCP, iPlayerTeam );
+ bHaveRequiredPlayers = (nNumTeammates >= nRequiredTeammates);
+ }
+
+ if ( iCappingTeam == iPlayerTeam && bHaveRequiredPlayers )
+ {
+ m_pBarText->SetText( "#Team_Capture_Blocked" );
+ return;
+ }
+
+ if ( !ObjectiveResource()->TeamCanCapPoint( iCP, iPlayerTeam ) )
+ {
+ m_pBarText->SetText( "#Team_Cannot_Capture" );
+ return;
+ }
+
+ m_pBarText->SetText( "#Team_Waiting_for_teammate" );
+}
+
+//========================================================================================================================
+// CONTROL POINT CAPTURE ARROW SWIPE
+//========================================================================================================================
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CControlPointIconCapArrow::CControlPointIconCapArrow( CControlPointIcon *pIcon, Panel *parent, const char *name)
+ : vgui::Panel( parent, name )
+{
+ m_pArrowMaterial = NULL;
+ m_pAttachedToIcon = pIcon;
+ Assert( m_pAttachedToIcon );
+}
+
+bool CControlPointIconCapArrow::IsVisible( void )
+{
+ if ( IsInFreezeCam() == true )
+ return false;
+
+ return BaseClass::IsVisible();
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointIconCapArrow::Paint( void )
+{
+ if ( !m_pArrowMaterial || !m_pAttachedToIcon )
+ return;
+
+ int x = 0;
+ int y = 0;
+ ipanel()->GetAbsPos(GetVPanel(), x,y );
+ int iWidth = GetWide();
+ int iHeight = GetTall();
+
+ // Position the arrow based on the cap percentage
+ float flXa = 0;
+ float flXb = 1.0;
+ float flYa = 0;
+ float flYb = 1.0;
+
+ int iCappingTeam = ObjectiveResource()->GetCappingTeam( m_pAttachedToIcon->GetCapIndex() );
+ float flCapPercentage = ObjectiveResource()->GetCPCapPercentage( m_pAttachedToIcon->GetCapIndex() );
+
+ // The image needs to be remapped to the width of the underlying box,
+ // because we want the arrow head to move off the box at the exact time the cap ends.
+ float flArrowHeadPixelWidth = 15.0;
+ float flArrowBodyPixelWidth = 54.0;
+ float flBoxSize = 33.0;
+
+ // HACK: The arrow has an arrowhead portion that looks like this: >
+ // We want to start with the arrow entering the image, but we want to keep
+ // going until the arrow is fully off the edge. So we include extra width for it.
+ float flImageSize = (flArrowHeadPixelWidth+flArrowBodyPixelWidth);
+ float flMovementInTextureSpace = ( (flBoxSize+flArrowHeadPixelWidth) / flImageSize );
+ float flArrowSizeInTextureSpace = ( flArrowHeadPixelWidth / flImageSize );
+
+ // To help players spot the start & end of a cap, we indent a little on either side.
+ float flIndent = 0.07;
+
+ if ( m_pAttachedToIcon->ShouldSwipeUp() )
+ {
+ flYa = RemapVal( flCapPercentage, 0.0, 1.0, -flMovementInTextureSpace - flIndent, flArrowSizeInTextureSpace - flIndent );
+ flYb = RemapVal( flCapPercentage, 0.0, 1.0, flIndent, flMovementInTextureSpace - flIndent );
+ }
+ else
+ {
+ flIndent = 0.1;
+
+ float flStart = 1.0 - flIndent;
+ float flEnd = 1.0 + flIndent;
+
+ bool bSwipeLeftToRight = ( iCappingTeam % 2 ) ? false : true;
+ if ( bSwipeLeftToRight )
+ {
+ flXa = RemapVal( flCapPercentage, 0.0, 1.0, flStart + flMovementInTextureSpace, flEnd - flArrowSizeInTextureSpace );
+ flXb = RemapVal( flCapPercentage, 0.0, 1.0, flStart, 0.0 );
+ }
+ else
+ {
+ flXa = RemapVal( flCapPercentage, 0.0, 1.0, flStart, 0.0 );
+ flXb = RemapVal( flCapPercentage, 0.0, 1.0, flStart + flMovementInTextureSpace, flEnd - flArrowSizeInTextureSpace );
+ }
+ }
+
+ CMatRenderContextPtr pRenderContext( materials );
+ pRenderContext->Bind( m_pArrowMaterial );
+ IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
+
+ CMeshBuilder meshBuilder;
+ meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
+
+ meshBuilder.Position3f( x, y, 0.0f );
+ meshBuilder.TexCoord2f( 0, flXa, flYa );
+ meshBuilder.TexCoord2f( 1, 0.0f, 0.0f );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x + iWidth, y, 0.0f );
+ meshBuilder.TexCoord2f( 0, flXb, flYa );
+ meshBuilder.TexCoord2f( 1, 1.0f, 0.0f );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x + iWidth, y + iHeight, 0.0f );
+ meshBuilder.TexCoord2f( 0, flXb, flYb );
+ meshBuilder.TexCoord2f( 1, 1.0f, 1.0f );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.Position3f( x, y + iHeight, 0.0f );
+ meshBuilder.TexCoord2f( 0, flXa, flYb );
+ meshBuilder.TexCoord2f( 1, 0.0f, 1.0f );
+ meshBuilder.Color4ub( 255, 255, 255, 255 );
+ meshBuilder.AdvanceVertex();
+
+ meshBuilder.End();
+ pMesh->Draw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CControlPointCountdown::CControlPointCountdown(Panel *parent, const char *name) : vgui::EditablePanel( parent, name )
+{
+ m_bFire5SecRemain = true;
+ m_bFire4SecRemain = true;
+ m_bFire3SecRemain = true;
+ m_bFire2SecRemain = true;
+ m_bFire1SecRemain = true;
+ m_bFire0SecRemain = true;
+
+ m_flUnlockTime = 0.0f;
+
+ vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
+ SetVisible( true );
+
+ SetDialogVariable( "capturetime", "" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointCountdown::ApplySchemeSettings( IScheme *pScheme )
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // load control settings...
+ LoadControlSettings( "resource/UI/ControlPointCountdown.res" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointCountdown::PerformLayout()
+{
+ CExLabel *pLabel = dynamic_cast<CExLabel *>( FindChildByName( "CapCountdownLabel" ) );
+ if ( pLabel )
+ {
+ pLabel->SetBounds( 0, 0, GetWide(), GetTall() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointCountdown::SetUnlockTime( float flTime )
+{
+ m_flUnlockTime = flTime;
+
+ float flTimeDiff = m_flUnlockTime - gpGlobals->curtime;
+ m_bFire5SecRemain = ( flTimeDiff >= 5.0f );
+ m_bFire4SecRemain = ( flTimeDiff >= 4.0f );
+ m_bFire3SecRemain = ( flTimeDiff >= 3.0f );
+ m_bFire2SecRemain = ( flTimeDiff >= 2.0f );
+ m_bFire1SecRemain = ( flTimeDiff >= 1.0f );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CControlPointCountdown::OnTick( void )
+{
+ BaseClass::OnTick();
+
+ C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
+ if ( !pLocalPlayer || ( m_flUnlockTime <= 0.0f ) )
+ {
+ if ( IsVisible() )
+ {
+ SetVisible( false );
+ }
+ return;
+ }
+
+ if ( TeamplayRoundBasedRules() )
+ {
+ if ( TeamplayRoundBasedRules()->IsInWaitingForPlayers() || TeamplayRoundBasedRules()->State_Get() != GR_STATE_RND_RUNNING )
+ {
+ return;
+ }
+ }
+
+ int iTimeLeft = m_flUnlockTime - gpGlobals->curtime;
+ if ( iTimeLeft > 5 || iTimeLeft <= 0 )
+ {
+ if ( iTimeLeft <= 0 && m_bFire0SecRemain )
+ {
+ m_bFire0SecRemain = false;
+ pLocalPlayer->EmitSound( "Announcer.AM_CapEnabledRandom" );
+ m_flUnlockTime = 0.0f;
+ }
+
+ if ( IsVisible() )
+ {
+ SetVisible( false );
+ }
+ return;
+ }
+
+ if ( !IsVisible() )
+ {
+ SetVisible( true );
+ }
+
+ wchar_t wzTimeLeft[128];
+ _snwprintf( wzTimeLeft, ARRAYSIZE( wzTimeLeft ), L"%i", iTimeLeft );
+
+ SetDialogVariable( "capturetime", wzTimeLeft );
+
+ if ( iTimeLeft <= 5 && m_bFire5SecRemain )
+ {
+ m_bFire5SecRemain = false;
+ pLocalPlayer->EmitSound( "Announcer.RoundBegins5Seconds" );
+ }
+ else if ( iTimeLeft <= 4 && m_bFire4SecRemain )
+ {
+ m_bFire4SecRemain = false;
+ pLocalPlayer->EmitSound( "Announcer.RoundBegins4Seconds" );
+ }
+ else if ( iTimeLeft <= 3 && m_bFire3SecRemain )
+ {
+ m_bFire3SecRemain = false;
+ pLocalPlayer->EmitSound( "Announcer.RoundBegins3Seconds" );
+ }
+ else if ( iTimeLeft <= 2 && m_bFire2SecRemain )
+ {
+ m_bFire2SecRemain = false;
+ pLocalPlayer->EmitSound( "Announcer.RoundBegins2Seconds" );
+ }
+ else if ( iTimeLeft <= 1 && m_bFire1SecRemain )
+ {
+ m_bFire1SecRemain = false;
+ m_bFire0SecRemain = true;
+ pLocalPlayer->EmitSound( "Announcer.RoundBegins1Seconds" );
+ }
+}