diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/hud_controlpointicons.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/hud_controlpointicons.cpp')
| -rw-r--r-- | game/client/hud_controlpointicons.cpp | 1900 |
1 files changed, 1900 insertions, 0 deletions
diff --git a/game/client/hud_controlpointicons.cpp b/game/client/hud_controlpointicons.cpp new file mode 100644 index 0000000..b18ab44 --- /dev/null +++ b/game/client/hud_controlpointicons.cpp @@ -0,0 +1,1900 @@ +//========= 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 + float flPositionX = (ScreenWidth() - iWidest) * 0.5; + float flPositionY = ScreenHeight() - iTall - m_nHeightOffset; + if ( ObjectiveResource() ) + { + float flCustomPositionX = -1.f; + float flCustomPositionY = -1.f; + ObjectiveResource()->GetCapLayoutCustomPosition( flCustomPositionX, flCustomPositionY ); + if ( flCustomPositionX != -1.f ) + { + flPositionX = flCustomPositionX * ScreenWidth(); + } + if ( flCustomPositionY != -1.f ) + { + flPositionY = flCustomPositionY * ScreenHeight(); + } + } + SetBounds( flPositionX, flPositionY, 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_pBar->SetProgressDirection( vgui::CircularProgressBar::PROGRESS_CW ); + m_pBar->SetReverseProgress( true ); + + m_iMidGroupIndex = gHUD.LookupRenderGroupIndexByName( "mid" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CControlPointProgressBar::PerformLayout( void ) +{ + BaseClass::PerformLayout(); + + if ( m_pAttachedToIcon && m_pTeardrop && m_pTeardropSide && m_pAttachedToIcon->GetVPanel() ) + { + 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" ); + } +} |