diff options
Diffstat (limited to 'game/client/tf/tf_time_panel.cpp')
| -rw-r--r-- | game/client/tf/tf_time_panel.cpp | 1099 |
1 files changed, 1099 insertions, 0 deletions
diff --git a/game/client/tf/tf_time_panel.cpp b/game/client/tf/tf_time_panel.cpp new file mode 100644 index 0000000..c83e23e --- /dev/null +++ b/game/client/tf/tf_time_panel.cpp @@ -0,0 +1,1099 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/EditablePanel.h> + +#include "iclientmode.h" +#include "tf_time_panel.h" +#include "tf_gamerules.h" +#include "c_tf_team.h" +#include "vgui_controls/ScalableImagePanel.h" +#include "econ_controls.h" +#include "vgui/ISurface.h" +#include "tf_hud_arena_player_count.h" +#include "tf_match_description.h" +#include "tf_matchmaking_shared.h" + +using namespace vgui; +extern ConVar tf_hud_show_servertimelimit; +extern ConVar tf_arena_round_time; + +void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ); +bool ShouldUseMatchHUD(); + +DECLARE_BUILD_FACTORY( CTFProgressBar ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFProgressBar::CTFProgressBar( Panel *parent, const char *name ) + : ImagePanel( parent, name ) +{ + m_flPercent = 0.0f; + + m_iTexture = surface()->DrawGetTextureId( "hud/objectives_timepanel_progressbar" ); + if ( m_iTexture == -1 ) // we didn't find it, so create a new one + { + m_iTexture = surface()->CreateNewTextureID(); + surface()->DrawSetTextureFile( m_iTexture, "hud/objectives_timepanel_progressbar", true, false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFProgressBar::Paint() +{ + int wide, tall; + GetSize( wide, tall ); + + float uv1 = 0.0f, uv2 = 1.0f; + Vector2D uv11( uv1, uv1 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + Vector2D uv12( uv1, uv2 ); + + Vertex_t verts[4]; + verts[0].Init( Vector2D( 0, 0 ), uv11 ); + verts[1].Init( Vector2D( wide, 0 ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( 0, tall ), uv12 ); + + // first, just draw the whole thing inactive. + surface()->DrawSetTexture( m_iTexture ); + surface()->DrawSetColor( m_clrInActive ); + surface()->DrawTexturedPolygon( 4, verts ); + + // now, let's calculate the "active" part of the progress bar + if ( m_flPercent < m_flPercentWarning ) + { + surface()->DrawSetColor( m_clrActive ); + } + else + { + surface()->DrawSetColor( m_clrWarning ); + } + + // we're going to do this using quadrants + // ------------------------- + // | | | + // | | | + // | 4 | 1 | + // | | | + // | | | + // ------------------------- + // | | | + // | | | + // | 3 | 2 | + // | | | + // | | | + // ------------------------- + + float flCompleteCircle = ( 2.0f * M_PI ); + float fl90degrees = flCompleteCircle / 4.0f; + + float flEndAngle = flCompleteCircle * ( 1.0f - m_flPercent ); // count DOWN (counter-clockwise) + //float flEndAngle = flCompleteCircle * m_flPercent; // count UP (clockwise) + + float flHalfWide = (float)wide / 2.0f; + float flHalfTall = (float)tall / 2.0f; + + if ( flEndAngle >= fl90degrees * 3.0f ) // >= 270 degrees + { + // draw the first and second quadrants + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 1.0f ); + uv12.Init( 0.5, 1.0f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, tall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + + // draw the third quadrant + uv11.Init( 0.0f, 0.5f ); + uv21.Init( 0.5f, 0.5f ); + uv22.Init( 0.5f, 1.0f ); + uv12.Init( 0.0f, 1.0f ); + + verts[0].Init( Vector2D( 0.0f, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( flHalfWide, flHalfTall ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, tall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, tall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + + // draw the partial fourth quadrant + if ( flEndAngle > fl90degrees * 3.5f ) // > 315 degrees + { + uv11.Init( 0.0f, 0.0f ); + uv21.Init( 0.5f - ( tan(fl90degrees * 4.0f - flEndAngle) * 0.5 ), 0.0f ); + uv22.Init( 0.5f, 0.5f ); + uv12.Init( 0.0f, 0.5f ); + + verts[0].Init( Vector2D( 0.0f, 0.0f ), uv11 ); + verts[1].Init( Vector2D( flHalfWide - ( tan(fl90degrees * 4.0f - flEndAngle) * flHalfTall ), 0.0f ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, flHalfTall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 315 degrees + { + uv11.Init( 0.0f, 0.5f ); + uv21.Init( 0.0f, 0.5f - ( tan(flEndAngle - fl90degrees * 3.0f) * 0.5 ) ); + uv22.Init( 0.5f, 0.5f ); + uv12.Init( 0.0f, 0.5f ); + + verts[0].Init( Vector2D( 0.0f, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( 0.0f, flHalfTall - ( tan(flEndAngle - fl90degrees * 3.0f) * flHalfWide ) ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, flHalfTall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + } + else if ( flEndAngle >= fl90degrees * 2.0f ) // >= 180 degrees + { + // draw the first and second quadrants + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 1.0f ); + uv12.Init( 0.5, 1.0f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, tall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + + // draw the partial third quadrant + if ( flEndAngle > fl90degrees * 2.5f ) // > 225 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 0.5f, 1.0f ); + uv22.Init( 0.0f, 1.0f ); + uv12.Init( 0.0f, 0.5f + ( tan(fl90degrees * 3.0f - flEndAngle) * 0.5 ) ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( flHalfWide, tall ), uv21 ); + verts[2].Init( Vector2D( 0.0f, tall ), uv22 ); + verts[3].Init( Vector2D( 0.0f, flHalfTall + ( tan(fl90degrees * 3.0f - flEndAngle) * flHalfWide ) ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 225 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 0.5f, 1.0f ); + uv22.Init( 0.5f - ( tan( flEndAngle - fl90degrees * 2.0f) * 0.5 ), 1.0f ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( flHalfWide, tall ), uv21 ); + verts[2].Init( Vector2D( flHalfWide - ( tan(flEndAngle - fl90degrees * 2.0f) * flHalfTall ), tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + } + else if ( flEndAngle >= fl90degrees ) // >= 90 degrees + { + // draw the first quadrant + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 0.5f ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + + // draw the partial second quadrant + if ( flEndAngle > fl90degrees * 1.5f ) // > 135 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 1.0f, 0.5f ); + uv22.Init( 1.0f, 1.0f ); + uv12.Init( 0.5f + ( tan(fl90degrees * 2.0f - flEndAngle) * 0.5f ), 1.0f ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( wide, flHalfTall ), uv21 ); + verts[2].Init( Vector2D( wide, tall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide + ( tan(fl90degrees * 2.0f - flEndAngle) * flHalfTall ), tall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 135 degrees + { + uv11.Init( 0.5f, 0.5f ); + uv21.Init( 1.0f, 0.5f ); + uv22.Init( 1.0f, 0.5f + ( tan(flEndAngle - fl90degrees) * 0.5f ) ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, flHalfTall ), uv11 ); + verts[1].Init( Vector2D( wide, flHalfTall ), uv21 ); + verts[2].Init( Vector2D( wide, flHalfTall + ( tan(flEndAngle - fl90degrees) * flHalfWide ) ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + } + else // > 0 degrees + { + if ( flEndAngle > fl90degrees / 2.0f ) // > 45 degrees + { + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 1.0f, 0.0f ); + uv22.Init( 1.0f, 0.5f - ( tan(fl90degrees - flEndAngle) * 0.5 ) ); + uv12.Init( 0.5f, 0.5f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( wide, 0.0f ), uv21 ); + verts[2].Init( Vector2D( wide, flHalfTall - ( tan(fl90degrees - flEndAngle) * flHalfWide ) ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, flHalfTall ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + else // <= 45 degrees + { + uv11.Init( 0.5f, 0.0f ); + uv21.Init( 0.5 + ( tan(flEndAngle) * 0.5 ), 0.0f ); + uv22.Init( 0.5f, 0.5f ); + uv12.Init( 0.5f, 0.0f ); + + verts[0].Init( Vector2D( flHalfWide, 0.0f ), uv11 ); + verts[1].Init( Vector2D( flHalfWide + ( tan(flEndAngle) * flHalfTall ), 0.0f ), uv21 ); + verts[2].Init( Vector2D( flHalfWide, flHalfTall ), uv22 ); + verts[3].Init( Vector2D( flHalfWide, 0.0f ), uv12 ); + + surface()->DrawTexturedPolygon( 4, verts ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudTimeStatus::CTFHudTimeStatus( Panel *parent, const char *name ) : EditablePanel( parent, name ) +{ + m_pTimeValue = new CExLabel( this, "TimePanelValue", L"" ); + m_pProgressBar = NULL; + m_pOvertimeLabel = NULL; + m_pOvertimeBG = NULL; + m_pSuddenDeathLabel = NULL; + m_pSuddenDeathBG = NULL; + m_pWaitingForPlayersBG = NULL; + m_pWaitingForPlayersLabel = NULL; + m_pSetupLabel = NULL; + m_pSetupBG = NULL; + m_pTimerBG = NULL; + m_pServerTimeLabel = NULL; + m_pServerTimeLabelBG = NULL; + + m_flNextThink = 0.0f; + m_iTimerIndex = 0; + + m_iTimerDeltaHead = 0; + for( int i = 0 ; i < NUM_TIMER_DELTA_ITEMS ; i++ ) + { + m_TimerDeltaItems[i].m_flDieTime = 0.0f; + } + + ListenForGameEvent( "teamplay_update_timer" ); + ListenForGameEvent( "teamplay_timer_time_added" ); + ListenForGameEvent( "localplayer_changeteam" ); + + m_nTeam = TEAM_UNASSIGNED; + m_bKothMode = false; + m_bCachedOvertime = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::SetTeamBackground( void ) +{ + m_pTimerBG = dynamic_cast<ScalableImagePanel *>( FindChildByName( "TimePanelBG" ) ); + if ( m_pTimerBG ) + { + if ( TFGameRules() && ( !TFGameRules()->IsInKothMode() || TFGameRules()->IsInWaitingForPlayers() ) ) + { + int iTeam = GetLocalPlayerTeam(); + if ( iTeam == TF_TEAM_RED ) + { + m_pTimerBG->SetImage( "../hud/objectives_timepanel_red_bg" ); + } + else + { + m_pTimerBG->SetImage( "../hud/objectives_timepanel_blue_bg" ); + } + } + else + { + if ( m_nTeam == TF_TEAM_RED ) + { + m_pTimerBG->SetImage( "../hud/objectives_timepanel_red_bg" ); + } + else + { + m_pTimerBG->SetImage( "../hud/objectives_timepanel_blue_bg" ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::FireGameEvent( IGameEvent *event ) +{ + const char *eventName = event->GetName(); + + if ( !Q_strcmp( eventName, "teamplay_update_timer" ) ) + { + if ( TFGameRules() && TFGameRules()->IsInKothMode() ) + { + InvalidateLayout( false, true ); + } + + SetExtraTimePanels(); + } + else if ( !Q_strcmp( eventName, "teamplay_timer_time_added" ) ) + { + int iIndex = event->GetInt( "timer", -1 ); + int nSeconds = event->GetInt( "seconds_added", 0 ); + + SetTimeAdded( iIndex, nSeconds ); + } + else if ( !Q_strcmp( eventName, "localplayer_changeteam" ) ) + { + SetTeamBackground(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::SetTimeAdded( int iIndex, int nSeconds ) +{ + if ( m_iTimerIndex != iIndex ) // make sure this is the timer we're displaying in the HUD + return; + + C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( nSeconds != 0 && pPlayer ) + { + // create a delta item that floats off the top + timer_delta_t *pNewDeltaItem = &m_TimerDeltaItems[m_iTimerDeltaHead]; + + m_iTimerDeltaHead++; + m_iTimerDeltaHead %= NUM_TIMER_DELTA_ITEMS; + + pNewDeltaItem->m_flDieTime = gpGlobals->curtime + m_flDeltaLifetime; + pNewDeltaItem->m_nAmount = nSeconds; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::CheckClockLabelLength( CExLabel *pLabel, Panel *pBG ) +{ + if ( !pLabel || ! pBG ) + return; + + int textWide, textTall; + pLabel->GetContentSize( textWide, textTall ); + + // make sure our string isn't longer than the label it's in + if ( textWide > pLabel->GetWide() ) + { + int xStart, yStart, wideStart, tallStart; + pLabel->GetBounds( xStart, yStart, wideStart, tallStart ); + + int newXPos = xStart + ( wideStart / 2.0f ) - ( textWide / 2.0f ); + pLabel->SetBounds( newXPos, yStart, textWide, tallStart ); + } + + // turn off the background if our text label is wider than it is + if ( pLabel->GetWide() > pBG->GetWide() ) + { + pBG->SetVisible( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::SetExtraTimePanels() +{ + if ( !TFGameRules() ) + return; + + CTeamRoundTimer *pTimer = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( m_iTimerIndex ) ); + + if ( pTimer && pTimer->IsStopWatchTimer() == true ) + { + if( m_pTimerBG ) + m_pTimerBG->SetVisible( false ); + if( m_pProgressBar ) + m_pProgressBar->SetVisible( false ); + if( m_pWaitingForPlayersLabel ) + m_pWaitingForPlayersLabel->SetVisible( false ); + if( m_pWaitingForPlayersBG ) + m_pWaitingForPlayersBG->SetVisible( false ); + if( m_pOvertimeLabel ) + m_pOvertimeLabel->SetVisible( false ); + if( m_pOvertimeBG ) + m_pOvertimeBG->SetVisible( false ); + if( m_pSetupLabel ) + m_pSetupLabel->SetVisible( false ); + if( m_pSetupBG ) + m_pSetupBG->SetVisible( false ); + if( m_pSuddenDeathLabel ) + m_pSuddenDeathLabel->SetVisible( false ); + if( m_pSuddenDeathBG ) + m_pSuddenDeathBG->SetVisible( false ); + if( m_pServerTimeLabel ) + m_pServerTimeLabel->SetVisible( false ); + if ( m_pServerTimeLabelBG ) + m_pServerTimeLabelBG->SetVisible( false ); + return; + } + + bool bInSetup = TFGameRules()->InSetup(); + bool bInWaitingForPlayers = TFGameRules()->IsInWaitingForPlayers(); + + if ( m_pSetupBG && m_pSetupLabel ) + { + // get the time remaining (in seconds) + if ( pTimer ) + { + m_pSetupBG->SetVisible( bInSetup ); + m_pSetupLabel->SetVisible( bInSetup ); + } + } + + // Set the Sudden Death panels to be visible + if ( m_pSuddenDeathBG && m_pSuddenDeathLabel ) + { + bool bInSD = TFGameRules()->InStalemate() == true && TFGameRules()->IsInArenaMode() == false; + + if ( bInSD != m_pSuddenDeathLabel->IsVisible() ) + { + if ( bInSD ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "SuddenDeathLabelPulseRed" ); + } + else + { + g_pClientMode->GetViewportAnimationController()->StopAnimationSequence( this, "SuddenDeathLabelPulseRed" ); + } + } + + m_pSuddenDeathBG->SetVisible( bInSD ); + m_pSuddenDeathLabel->SetVisible( bInSD ); + } + + if ( m_pOvertimeBG && m_pOvertimeLabel ) + { + bool bInOver = TFGameRules()->InOvertime(); + + if ( TFGameRules()->IsInKothMode() ) + { + if ( pTimer ) + { + if ( bInOver ) + { + if ( pTimer->GetTimeRemaining() <= 0 ) + { + bInOver = true; + m_bCachedOvertime = true; + } + else + { + bInOver = false; + } + } + else + { + if ( m_bCachedOvertime ) + { + if ( pTimer->GetTimeRemaining() <= 0 ) + { + bInOver = true; + } + else + { + m_bCachedOvertime = false; + } + } + } + } + } + + if ( bInOver ) + { + // need to turn off the SuddenDeath images if they're on + if ( m_pSuddenDeathBG && m_pSuddenDeathLabel ) + { + m_pSuddenDeathBG->SetVisible( false ); + m_pSuddenDeathLabel->SetVisible( false ); + } + + if ( !m_pOvertimeLabel->IsVisible() ) + { + m_pOvertimeBG->SetVisible( true ); + m_pOvertimeLabel->SetVisible( true ); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "OvertimeLabelPulseRed" ); + + CheckClockLabelLength( m_pOvertimeLabel, m_pOvertimeBG ); + } + } + else + { + m_pOvertimeBG->SetVisible( false ); + m_pOvertimeLabel->SetVisible( false ); + g_pClientMode->GetViewportAnimationController()->StopAnimationSequence( this, "OvertimeLabelPulseRed" ); + } + } + + if ( m_pWaitingForPlayersBG && m_pWaitingForPlayersLabel ) + { + m_pWaitingForPlayersBG->SetVisible( bInWaitingForPlayers ); + m_pWaitingForPlayersLabel->SetVisible( bInWaitingForPlayers ); + + if ( bInWaitingForPlayers ) + { + // can't be waiting for players *AND* in setup at the same time + if ( m_pSetupBG && m_pSetupLabel ) + { + m_pSetupBG->SetVisible( false ); + m_pSetupLabel->SetVisible( false ); + } + + CheckClockLabelLength( m_pWaitingForPlayersLabel, m_pWaitingForPlayersBG ); + } + } + + if ( m_pServerTimeLabel && m_pServerTimeLabelBG ) + { + // This appears in the same space after SetUp and WaitingForPlayers is gone + bool bDisplayServerTimerEnabled = tf_hud_show_servertimelimit.GetInt() && !bInSetup && !bInWaitingForPlayers; + + if ( m_pServerTimeLabel->IsVisible() != bDisplayServerTimerEnabled ) + m_pServerTimeLabel->SetVisible( bDisplayServerTimerEnabled ); + + if ( m_pServerTimeLabelBG->IsVisible() != bDisplayServerTimerEnabled ) + m_pServerTimeLabelBG->SetVisible( bDisplayServerTimerEnabled ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::Reset() +{ + m_flNextThink = gpGlobals->curtime + 0.05f; + m_iTimerIndex = 0; + + m_iTimerDeltaHead = 0; + for( int i = 0 ; i < NUM_TIMER_DELTA_ITEMS ; i++ ) + { + m_TimerDeltaItems[i].m_flDieTime = 0.0f; + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::ApplySchemeSettings( IScheme *pScheme ) +{ + KeyValues *pConditions = NULL; + + if ( TFGameRules() ) + { + const IMatchGroupDescription* pMatch = GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() ); + if ( pMatch && pMatch->m_params.m_bUseMatchHud ) + { + pConditions = new KeyValues( "conditions" ); + AddSubKeyNamed( pConditions, "if_match" ); + } + } + + // load control settings... + LoadControlSettings( "resource/UI/HudObjectiveTimePanel.res", NULL, NULL, pConditions ); + + if ( pConditions ) + { + pConditions->deleteThis(); + } + + m_pProgressBar = dynamic_cast<CTFProgressBar *>( FindChildByName( "TimePanelProgressBar" ) ); + + m_pOvertimeLabel = dynamic_cast<CExLabel *>( FindChildByName( "OvertimeLabel" ) ); + m_pOvertimeBG = FindChildByName( "OvertimeBG" ); + + m_pSuddenDeathLabel = dynamic_cast<CExLabel *>( FindChildByName( "SuddenDeathLabel" ) ); + m_pSuddenDeathBG = FindChildByName( "SuddenDeathBG" ); + + m_pWaitingForPlayersLabel = dynamic_cast<CExLabel *>( FindChildByName( "WaitingForPlayersLabel" ) ); + m_pWaitingForPlayersBG = FindChildByName("WaitingForPlayersBG" ); + + m_pSetupLabel = dynamic_cast<CExLabel *>( FindChildByName( "SetupLabel" ) ); + m_pSetupBG = FindChildByName("SetupBG" ); + + m_pTimerBG = dynamic_cast<ScalableImagePanel *>( FindChildByName( "TimePanelBG" ) ); + SetTeamBackground(); + + m_pServerTimeLabel = dynamic_cast< CExLabel* >( FindChildByName( "ServerTimeLimitLabel" ) ); + m_pServerTimeLabelBG = FindChildByName("ServerTimeLimitLabelBG" ); + + m_flNextThink = 0.0f; + m_iTimerIndex = 0; + + SetExtraTimePanels(); + + BaseClass::ApplySchemeSettings( pScheme ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::OnThink() +{ + if ( m_flNextThink < gpGlobals->curtime ) + { + CTeamRoundTimer *pTimer = dynamic_cast< CTeamRoundTimer* >( ClientEntityList().GetEnt( m_iTimerIndex ) ); + + if ( TFGameRules() ) + { + if ( m_bKothMode != TFGameRules()->IsInKothMode() ) + { + m_bKothMode = TFGameRules()->IsInKothMode(); + InvalidateLayout( false, true ); + } + } + + // get the time remaining (in seconds) + if ( pTimer ) + { + int nTotalTime = pTimer->GetTimerMaxLength(); + int nTimeRemaining = pTimer->GetTimeRemaining(); + int nTimeToDisplay = nTimeRemaining; + + if ( !pTimer->ShowTimeRemaining() ) + { + nTimeToDisplay = nTotalTime - nTimeToDisplay; + } + + if ( m_pTimeValue && m_pTimeValue->IsVisible() ) + { + // set our label + int nMinutes = 0; + int nSeconds = 0; + char temp[256]; + + if ( nTimeToDisplay <= 0 ) + { + nMinutes = 0; + nSeconds = 0; + + if ( TFGameRules() && TFGameRules()->IsInKothMode() ) + { + SetExtraTimePanels(); + } + } + else + { + nMinutes = nTimeToDisplay / 60; + nSeconds = nTimeToDisplay % 60; + } + + Q_snprintf( temp, sizeof( temp ), "%d:%02d", nMinutes, nSeconds ); + m_pTimeValue->SetText( temp ); + } + + // let the progress bar know the percentage of time that's passed ( 0.0 -> 1.0 ) + if ( m_pProgressBar && m_pProgressBar->IsVisible() ) + { + if ( nTotalTime == 0 ) + { + m_pProgressBar->SetPercentage( 0 ); + } + else + { + m_pProgressBar->SetPercentage( ( (float)nTotalTime - nTimeRemaining ) / (float)nTotalTime ); + } + } + + // Optional display of mp_timelimit on HUD + if ( m_pServerTimeLabel && m_pServerTimeLabelBG ) + { + int nServerTimeLimit = mp_timelimit.GetInt() * 60; + + bool bDisplayServerTimerEnabled = tf_hud_show_servertimelimit.GetInt() && + TFGameRules() && + !TFGameRules()->InSetup() && + !TFGameRules()->IsInWaitingForPlayers() && + pTimer->IsRoundMaxTimerSet() && + nServerTimeLimit; + + if ( m_pServerTimeLabel->IsVisible() != bDisplayServerTimerEnabled ) + { + m_pServerTimeLabel->SetVisible( bDisplayServerTimerEnabled ); + } + if ( m_pServerTimeLabelBG->IsVisible() != bDisplayServerTimerEnabled ) + { + m_pServerTimeLabelBG->SetVisible( bDisplayServerTimerEnabled ); + } + + // Only display server timelimit when the round timer isn't showing mp_timelimit (e.g. ctf_2fort) + if ( bDisplayServerTimerEnabled ) + { + wchar_t wzServerTimeHrsLeft[128]; + wchar_t wzServerTimeMinLeft[128]; + wchar_t wzServerTimeSecLeft[128]; + wchar_t wzServerTimeLeft[128]; + + int iTimeLeft = 0; + int iHours = 0; + int iMinutes = 0; + int iSeconds = 0; + + if ( !nServerTimeLimit ) + { + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#TF_HUD_ServerNoTimeLimit" ), 0); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + return; + } + + iTimeLeft = ( TFGameRules() && TFGameRules()->GetTimeLeft() > 0 ) ? TFGameRules()->GetTimeLeft() : 0; + + if ( iTimeLeft == 0 ) + { + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#TF_HUD_ServerChangeOnRoundEnd" ), 0); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + return; + } + + iHours = iTimeLeft / 3600; + iMinutes = (iTimeLeft % 3600) / 60; + iSeconds = (iTimeLeft % 60); + + _snwprintf( wzServerTimeHrsLeft, ARRAYSIZE( wzServerTimeHrsLeft ), L"%i", iHours ); + _snwprintf( wzServerTimeMinLeft, ARRAYSIZE( wzServerTimeMinLeft ), L"%02i", iMinutes ); + _snwprintf( wzServerTimeSecLeft, ARRAYSIZE( wzServerTimeSecLeft ), L"%02i", iSeconds ); + + if (iHours == 0) + { + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#TF_HUD_ServerTimeLeftNoHours" ), 2, wzServerTimeMinLeft, wzServerTimeSecLeft); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + return; + } + + g_pVGuiLocalize->ConstructString_safe( wzServerTimeLeft, g_pVGuiLocalize->Find( "#TF_HUD_ServerTimeLeft" ), 3, wzServerTimeHrsLeft, wzServerTimeMinLeft, wzServerTimeSecLeft); + SetDialogVariable( "servertimeleft", wzServerTimeLeft ); + } + } + } + + m_flNextThink = gpGlobals->curtime + 0.1f; + } + + if ( TFGameRules() && TFGameRules()->IsInArenaMode() == true && tf_arena_round_time.GetInt() > 0 ) + { + CHudArenaPlayerCount *pPlayerCount = ( CHudArenaPlayerCount * )GET_HUDELEMENT( CHudArenaPlayerCount ); + + int iSelfX, iSelfY; + GetPos( iSelfX, iSelfY ); + + if ( pPlayerCount && pPlayerCount->IsVisible() ) + { + int iX, iY, iTall, iWide; + pPlayerCount->GetBounds( iX, iY, iWide, iTall ); + + SetPos( iSelfX, iY + iTall - YRES( 12 ) ); + } + else + { + SetPos( iSelfX, 0 ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Paint the deltas +//----------------------------------------------------------------------------- +void CTFHudTimeStatus::Paint( void ) +{ + BaseClass::Paint(); + + for ( int i = 0 ; i < NUM_TIMER_DELTA_ITEMS ; i++ ) + { + // update all the valid delta items + if ( m_TimerDeltaItems[i].m_flDieTime > gpGlobals->curtime ) + { + // position and alpha are determined from the lifetime + // color is determined by the delta - green for positive, red for negative + + Color c = ( m_TimerDeltaItems[i].m_nAmount > 0 ) ? m_DeltaPositiveColor : m_DeltaNegativeColor; + + float flLifetimePercent = ( m_TimerDeltaItems[i].m_flDieTime - gpGlobals->curtime ) / m_flDeltaLifetime; + + // fade out after half our lifetime + if ( flLifetimePercent < 0.5 ) + { + c[3] = (int)( 255.0f * ( flLifetimePercent / 0.5 ) ); + } + + float flHeight = ( m_flDeltaItemStartPos - m_flDeltaItemEndPos ); + float flYPos = m_flDeltaItemEndPos + flLifetimePercent * flHeight; + + surface()->DrawSetTextFont( m_hDeltaItemFont ); + surface()->DrawSetTextColor( c ); + surface()->DrawSetTextPos( m_flDeltaItemX, (int)flYPos ); + + wchar_t wBuf[20]; + int nMinutes, nSeconds; + int nClockTime = ( m_TimerDeltaItems[i].m_nAmount > 0 ) ? m_TimerDeltaItems[i].m_nAmount : ( m_TimerDeltaItems[i].m_nAmount * -1 ); + nMinutes = nClockTime / 60; + nSeconds = nClockTime % 60; + + if ( m_TimerDeltaItems[i].m_nAmount > 0 ) + { + V_swprintf_safe( wBuf, L"+%d:%02d", nMinutes, nSeconds ); + } + else + { + V_swprintf_safe( wBuf, L"-%d:%02d", nMinutes, nSeconds ); + } + + surface()->DrawPrintText( wBuf, wcslen(wBuf), FONT_DRAW_NONADDITIVE ); + } + } +} + +DECLARE_HUDELEMENT( CTFHudKothTimeStatus ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudKothTimeStatus::CTFHudKothTimeStatus( const char *pElementName ) + : CHudElement( pElementName ) + , BaseClass( NULL, "HudKothTimeStatus" ) + , m_pBluePanel( NULL ) + , m_pRedPanel( NULL ) + , m_pActiveTimerBG( NULL ) + , m_nActiveTeam( TEAM_UNASSIGNED ) +{ + Panel *pParent = g_pClientMode->GetViewport(); + SetParent( pParent ); + + m_pBluePanel = new CTFHudTimeStatus( this, "BlueTimer" ); + m_pRedPanel = new CTFHudTimeStatus( this, "RedTimer" ); + + if ( m_pRedPanel ) + { + m_pRedPanel->SetTeam( TF_TEAM_RED ); + } + + SetHiddenBits( 0 ); + + RegisterForRenderGroup( "mid" ); + RegisterForRenderGroup( "commentary" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudKothTimeStatus::~CTFHudKothTimeStatus() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFHudKothTimeStatus::ShouldDraw() +{ + if ( TFGameRules() ) + { + if ( TFGameRules()->ShowMatchSummary() ) + return false; + + if ( TFGameRules()->IsInKothMode() && !TeamplayRoundBasedRules()->IsInWaitingForPlayers() ) + { + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + if ( pPlayer->GetObserverMode() != OBS_MODE_FREEZECAM ) + { + return CHudElement::ShouldDraw(); + } + } + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudKothTimeStatus::SetVisible( bool bVisible ) +{ + BaseClass::SetVisible( bVisible ); + + if ( ShouldUseMatchHUD() ) + { + UpdateActiveTeam(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudKothTimeStatus::Reset() +{ + if ( m_pBluePanel ) + { + m_pBluePanel->Reset(); + } + + if ( m_pRedPanel ) + { + m_pRedPanel->Reset(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudKothTimeStatus::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + KeyValues *pConditions = NULL; + + if ( TFGameRules() ) + { + const IMatchGroupDescription* pMatch = GetMatchGroupDescription( TFGameRules()->GetCurrentMatchGroup() ); + if ( pMatch && pMatch->m_params.m_bUseMatchHud ) + { + pConditions = new KeyValues( "conditions" ); + AddSubKeyNamed( pConditions, "if_match" ); + } + } + + LoadControlSettings( "resource/UI/HudObjectiveKothTimePanel.res", NULL, NULL, pConditions ); + + m_pActiveTimerBG = FindChildByName( "ActiveTimerBG" ); + + UpdateActiveTeam(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudKothTimeStatus::UpdateActiveTeam( void ) +{ + if ( ShouldUseMatchHUD() ) + { + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pRedPanel, m_nActiveTeam == TF_TEAM_RED ? "ActiveTimerHighlight" : "ActiveTimerDim", false ); + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pBluePanel, m_nActiveTeam == TF_TEAM_BLUE ? "ActiveTimerHighlight" : "ActiveTimerDim", false ); + } + else if ( m_pActiveTimerBG ) + { + if ( m_nActiveTeam != TEAM_UNASSIGNED ) + { + if ( !m_pActiveTimerBG->IsVisible() ) + { + m_pActiveTimerBG->SetVisible( true ); + } + + m_pActiveTimerBG->SetAlpha( 255 ); + + int xNewPos = m_nBlueActiveXPos; + if ( m_nActiveTeam == TF_TEAM_RED ) + { + xNewPos = m_nRedActiveXPos; + } + + int xPos, yPos; + m_pActiveTimerBG->GetPos( xPos, yPos ); + m_pActiveTimerBG->SetPos( xNewPos, yPos ); + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "ActiveTimerBGPulse" ); + } + else + { + if ( m_pActiveTimerBG->IsVisible() ) + { + m_pActiveTimerBG->SetVisible( false ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudKothTimeStatus::Think( void ) +{ + if ( !TFGameRules() || !IsVisible() ) + return; + + int nActiveTeam = TEAM_UNASSIGNED; + + CTeamRoundTimer *pTimer = TFGameRules()->GetBlueKothRoundTimer(); + if ( pTimer ) + { + if ( m_pBluePanel ) + { + if ( pTimer->entindex() != m_pBluePanel->GetTimerIndex() ) + { + m_pBluePanel->SetTimerIndex( pTimer->entindex() ); + } + } + + if ( !pTimer->IsTimerPaused() ) + { + nActiveTeam = TF_TEAM_BLUE; + } + } + + pTimer = TFGameRules()->GetRedKothRoundTimer(); + if ( pTimer ) + { + if ( m_pRedPanel ) + { + if ( pTimer->entindex() != m_pRedPanel->GetTimerIndex() ) + { + m_pRedPanel->SetTimerIndex( pTimer->entindex() ); + } + } + + if ( !pTimer->IsTimerPaused() ) + { + nActiveTeam = TF_TEAM_RED; + } + } + + if ( nActiveTeam != m_nActiveTeam ) + { + m_nActiveTeam = nActiveTeam; + UpdateActiveTeam(); + } +} |