diff options
Diffstat (limited to 'game/client/tf/tf_hud_escort.cpp')
| -rw-r--r-- | game/client/tf/tf_hud_escort.cpp | 1242 |
1 files changed, 1242 insertions, 0 deletions
diff --git a/game/client/tf/tf_hud_escort.cpp b/game/client/tf/tf_hud_escort.cpp new file mode 100644 index 0000000..68c4ca7 --- /dev/null +++ b/game/client/tf/tf_hud_escort.cpp @@ -0,0 +1,1242 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "tf_hud_escort.h" +#include <vgui/IVGui.h> +#include "tf_hud_freezepanel.h" +#include "hud_controlpointicons.h" +#include "teamplayroundbased_gamerules.h" +#include "c_team_train_watcher.h" +#include "iclientmode.h" +#include "tf_gamerules.h" + +using namespace vgui; + +#define TF_ESCORT_RECEDE_COUNTDOWN 20.0f + +#define TF_ESCORT_HILL_MATERIAL "hud/cart_track_arrow" +#define TF_ESCORT_HILL_ALPHA_CYCLE_TIME 750 + +ConVar hud_escort_interp( "hud_escort_interp", "0.2" ); +ConVar hud_escort_test_progress( "hud_escort_test_progress", "-1" ); +ConVar hud_escort_test_speed( "hud_escort_test_speed", "-1" ); + +void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ) +{ + KeyValues *pNewKey = new KeyValues( pszName ); + if ( pNewKey ) + { + pKeys->AddSubKey( pNewKey ); + } +} + +CEscortHillPanel::CEscortHillPanel( vgui::Panel *parent, const char *name ) : vgui::Panel( parent, name ) +{ + m_iTexture = vgui::surface()->DrawGetTextureId( TF_ESCORT_HILL_MATERIAL ); + if ( m_iTexture == -1 ) // we didn't find it, so create a new one + { + m_iTexture = vgui::surface()->CreateNewTextureID(); + vgui::surface()->DrawSetTextureFile( m_iTexture, TF_ESCORT_HILL_MATERIAL, true, false ); + } + + m_flUVScroll = 0.0f; + m_flUVW = 0.0f; + m_bOnHill = false; + m_bFadingOut = true; + m_bDownhill = false; + + ListenForGameEvent( "teamplay_round_start" ); + + vgui::ivgui()->AddTickSignal( GetVPanel(), TF_ESCORT_HILL_ALPHA_CYCLE_TIME ); +} + +void CEscortHillPanel::OnTick( void ) +{ + if ( IsVisible() == false ) + return; + + if ( m_bOnHill ) + { + if ( m_bFadingOut ) + { + GetAnimationController()->RunAnimationCommand( this, "alpha", 32, 0.0, (float)TF_ESCORT_HILL_ALPHA_CYCLE_TIME / 1000, vgui::AnimationController::INTERPOLATOR_LINEAR ); + m_bFadingOut = false; + } + else + { + GetAnimationController()->RunAnimationCommand( this, "alpha", 96, 0.0, (float)TF_ESCORT_HILL_ALPHA_CYCLE_TIME / 1000, vgui::AnimationController::INTERPOLATOR_LINEAR ); + m_bFadingOut = true; + } + } + else + { + SetAlpha( 64 ); + m_bFadingOut = true; + } +} + +void CEscortHillPanel::PerformLayout( void ) +{ + BaseClass::PerformLayout(); + + int nPanelX, nPanelY; + GetBounds( nPanelX, nPanelY, m_nPanelWide, m_nPanelTall ); + + int nTextureWide, nTextureTall; + surface()->DrawGetTextureSize( m_iTexture, nTextureWide, nTextureTall ); + + float flScale = (float)m_nPanelTall / (float)nTextureTall; + float flNewTextureWide = nTextureWide * flScale; + + m_flUVW = m_nPanelWide / flNewTextureWide; + + SetAlpha( 64 ); +} + +void CEscortHillPanel::Paint( void ) +{ + BaseClass::Paint(); + + if ( ObjectiveResource() ) + { + m_bOnHill = ObjectiveResource()->IsTrainOnHill( m_nTeam, m_nHill ); + m_bDownhill = ObjectiveResource()->IsHillDownhill( m_nTeam, m_nHill ); + } + + if ( m_bOnHill ) + { + m_flUVScroll += 0.02; + + if ( m_flUVScroll > 1.0 ) + { + m_flUVScroll -= 1.0; + } + } + + Vertex_t vert[4]; + surface()->DrawSetTexture( m_iTexture ); + + Vector2D uv11( m_flUVScroll, 0 ); + Vector2D uv21( m_flUVW + m_flUVScroll, 0 ); + Vector2D uv22( m_flUVW + m_flUVScroll, 1 ); + Vector2D uv12( m_flUVScroll, 1 ); + + if ( m_bDownhill ) + { + vert[0].Init( Vector2D( 0, 0 ), uv21 ); + vert[1].Init( Vector2D( m_nPanelWide, 0 ), uv11 ); + vert[2].Init( Vector2D( m_nPanelWide, m_nPanelTall ), uv12 ); + vert[3].Init( Vector2D( 0, m_nPanelTall ), uv22 ); + } + else + { + vert[0].Init( Vector2D( 0, 0 ), uv11 ); + vert[1].Init( Vector2D( m_nPanelWide, 0 ), uv21 ); + vert[2].Init( Vector2D( m_nPanelWide, m_nPanelTall ), uv22 ); + vert[3].Init( Vector2D( 0, m_nPanelTall ), uv12 ); + } + + surface()->DrawSetColor( Color(255,255,255,255) ); + surface()->DrawTexturedPolygon( 4, vert ); +} + +void CEscortHillPanel::FireGameEvent( IGameEvent * event ) +{ + if ( FStrEq( "teamplay_round_start", event->GetName() ) ) + { + m_flUVScroll = 0.0f; + } +} + +//======================================================================================================================== +// Escort status indicator that floats above the train when you are interacting with it +//======================================================================================================================== +CEscortStatusTeardrop::CEscortStatusTeardrop(Panel *parent) : vgui::EditablePanel( parent, "EscortTeardrop" ) +{ + m_pBarText = new vgui::Label( this, "ProgressText", "" ); + m_pTeardrop = new CIconPanel( this, "Teardrop" ); + m_pBlocked = new CIconPanel( this, "Blocked" ); + m_pCapping = new ImagePanel( this, "Capping" ); + m_iOrgHeight = 0; + m_iMidGroupIndex = -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEscortStatusTeardrop::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + //LoadControlSettings( "resource/UI/EscortStatusTeardrop.res" ); /*//ControlPointProgressBar.res" );*/ + + m_iOrgHeight = GetTall(); + + m_iMidGroupIndex = gHUD.LookupRenderGroupIndexByName( "mid" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CEscortStatusTeardrop::IsVisible( void ) +{ + if ( IsInFreezeCam() == true ) + return false; + + if ( m_iMidGroupIndex != -1 && gHUD.IsRenderGroupLockedFor( NULL, m_iMidGroupIndex ) ) + return false; + + return BaseClass::IsVisible(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEscortStatusTeardrop::SetupForPoint( int iCPIndex ) +{ + if ( !ObjectiveResource() ) + return; + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer ) + return; + + if ( iCPIndex == -1 ) + { + SetVisible( false ); + return; + } + + bool bInWinState = TeamplayRoundBasedRules() ? TeamplayRoundBasedRules()->RoundHasBeenWon() : false; + + if ( !bInWinState ) + { + SetVisible( true ); + + int iCappingTeam = ObjectiveResource()->GetCappingTeam( iCPIndex ); + int iOwnerTeam = ObjectiveResource()->GetOwningTeam( iCPIndex ); + int iPlayerTeam = pPlayer->GetTeamNumber(); + bool bCapBlocked = ObjectiveResource()->CapIsBlocked( iCPIndex ); + + if ( !bCapBlocked && iCappingTeam != TEAM_UNASSIGNED && iCappingTeam != iOwnerTeam && iCappingTeam == iPlayerTeam ) + { + // it's not blocked and we're capping + + m_pBlocked->SetVisible( false ); + + // replace this with a capping icon + m_pCapping->SetVisible( true ); + + m_pBarText->SetVisible( false ); + } + else + { + // not capping + + m_pCapping->SetVisible( false ); + + m_pBlocked->SetVisible( true ); + UpdateBarText( iCPIndex ); + } + + InvalidateLayout(); + } + else + { + SetVisible( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CEscortStatusTeardrop::UpdateBarText( int iCPIndex ) +{ + if ( !ObjectiveResource() ) + return; + + // If we're not escorting the train we don't show text + if ( iCPIndex == -1 ) + { + m_pBarText->SetVisible( false ); + return; + } + + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( !pPlayer || !m_pBarText ) + return; + + m_pBarText->SetVisible( true ); + + int iCappingTeam = ObjectiveResource()->GetCappingTeam( iCPIndex ); + int iPlayerTeam = pPlayer->GetTeamNumber(); + + if ( !TeamplayGameRules()->PointsMayBeCaptured() ) + { + m_pBarText->SetText( "#Team_Capture_NotNow" ); + return; + } + + // Player is blocking an enemy capture + if ( iCappingTeam != TEAM_UNASSIGNED && iCappingTeam != iPlayerTeam ) + { + if ( ObjectiveResource()->IsCPBlocked( iCPIndex ) ) + { + m_pBarText->SetText( "#Team_Blocking_Capture" ); + return; + } + } + + // player is standing on an already owned cap + if ( ObjectiveResource()->GetOwningTeam( iCPIndex ) == iPlayerTeam ) + { + m_pBarText->SetText( "#Team_Capture_OwnPoint" ); + return; + } + + // disguised spies etc can't cap or block + char szReason[256]; + if ( !TeamplayGameRules()->PlayerMayCapturePoint( pPlayer, iCPIndex, szReason, sizeof(szReason) ) ) + { + m_pBarText->SetText( szReason ); + return; + } + + // we can't capture because it's blocked + if ( iCappingTeam == iPlayerTeam ) + { + m_pBarText->SetText( "#Team_Progress_Blocked" ); + return; + } + + m_pBarText->SetText( "" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudEscortProgressBar::CTFHudEscortProgressBar( vgui::Panel *parent, const char *name ) : vgui::ImagePanel( parent, name ) +{ + m_flPercent = 0.0f; + + SetTeam( TF_TEAM_BLUE ); // default to blue +} + +//----------------------------------------------------------------------------- +// Purpose: Update the escort image position +//----------------------------------------------------------------------------- +void CTFHudEscortProgressBar::SetTeam( int nTeam ) +{ + m_nTeam = nTeam; + + const char *pszMaterial = "hud/cart_track_neutral_opaque"; + + if ( m_nTeam == TF_TEAM_RED ) + { + pszMaterial = "hud/cart_track_red_opaque"; + } + else if ( m_nTeam == TF_TEAM_BLUE ) + { + pszMaterial = "hud/cart_track_blue_opaque"; + } + + m_iTexture = vgui::surface()->DrawGetTextureId( pszMaterial ); + if ( m_iTexture == -1 ) // we didn't find it, so create a new one + { + m_iTexture = vgui::surface()->CreateNewTextureID(); + } + + vgui::surface()->DrawSetTextureFile( m_iTexture, pszMaterial, true, false ); +} + +//----------------------------------------------------------------------------- +// Purpose: Update the escort image position +//----------------------------------------------------------------------------- +void CTFHudEscortProgressBar::Paint() +{ + if ( m_flPercent > 0.0f ) + { + Vertex_t vert[4]; + float uv1 = 0.0f; + float uv2 = 1.0f; + + surface()->DrawSetTexture( m_iTexture ); + + Vector2D uv11( uv1, uv1 ); + Vector2D uv21( uv2, uv1 ); + Vector2D uv22( uv2, uv2 ); + Vector2D uv12( uv1, uv2 ); + + int nBarX, nBarY, nBarW, nBarH; + GetBounds( nBarX, nBarY, nBarW, nBarH ); + + int nMiddle = (int)( (float)(nBarW) * m_flPercent ); + + vert[0].Init( Vector2D( 0, 0 ), uv11 ); + vert[1].Init( Vector2D( nMiddle, 0 ), uv21 ); + vert[2].Init( Vector2D( nMiddle, nBarH ), uv22 ); + vert[3].Init( Vector2D( 0, nBarH ), uv12 ); + + surface()->DrawSetColor( Color(255,255,255,210) ); + surface()->DrawTexturedPolygon( 4, vert ); + + surface()->DrawSetColor( Color(245,229,196,210) ); + surface()->DrawLine( nMiddle - 1, 0, nMiddle - 1, nBarH ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudEscort::CTFHudEscort( Panel *parent, const char *name ) : EditablePanel( parent, name ), m_flProgressHistory("CTFHudEscort::m_flProgressHistory") +{ + m_flProgress = 0.0f; + m_flProgressHistory.Setup( &m_flProgress, 0 ); + + ListenForGameEvent( "escort_speed" ); + ListenForGameEvent( "escort_progress" ); + ListenForGameEvent( "escort_recede" ); + ListenForGameEvent( "controlpoint_initialized" ); + ListenForGameEvent( "controlpoint_updateimages" ); + ListenForGameEvent( "controlpoint_updatecapping" ); + ListenForGameEvent( "controlpoint_starttouch" ); + ListenForGameEvent( "controlpoint_endtouch" ); + ListenForGameEvent( "teamplay_round_start" ); + ListenForGameEvent( "localplayer_respawn" ); + ListenForGameEvent( "localplayer_changeteam" ); + + m_pEscortItemPanel = new EditablePanel( this, "EscortItemPanel" ); + + Assert( m_pEscortItemPanel ); + + m_pSpeedBackwards = new ImagePanel( m_pEscortItemPanel, "Speed_Backwards" ); + m_pCapPlayerImage = new ImagePanel( m_pEscortItemPanel, "CapPlayerImage" ); + m_pCapNumPlayers = new CExLabel( m_pEscortItemPanel, "CapNumPlayers", "" ); + m_pEscortItemImage = new ImagePanel( m_pEscortItemPanel, "EscortItemImage" ); + m_pEscortItemImageBottom = new ImagePanel( m_pEscortItemPanel, "EscortItemImageBottom" ); + m_pBlocked = new ImagePanel( m_pEscortItemPanel, "Blocked" ); + + m_pEscortItemImageAlert = new ImagePanel( m_pEscortItemPanel, "EscortItemImageAlert" ); + + m_pHomeCPIcon = new ImagePanel( this, "HomeCPIcon" ); + + m_pCPTemplate = new ImagePanel( this, "SimpleControlPointTemplate" ); + + // store the background bar so we can use its dimensions for CP placement + m_pLevelBar = new ImagePanel( this, "LevelBar" ); + + m_pStatus = new CEscortStatusTeardrop( m_pEscortItemPanel ); + + m_pHilightSwoop = new CControlPointIconSwoop( this, "EscortHilightSwoop" ); + m_pHilightSwoop->SetParent( g_pClientMode->GetViewport() ); + m_pHilightSwoop->SetZPos( 10 ); + m_pHilightSwoop->SetShouldScaleImage( true ); + + m_pProgressBar = new CTFHudEscortProgressBar( this, "ProgressBar" ); + + m_iCurrentCP = -1; + + m_flRecedeTime = 0; + + m_nTeam = TF_TEAM_BLUE; // blue team by default + m_bTopPanel = true; + + m_bAlarm = false; + + vgui::ivgui()->AddTickSignal( GetVPanel(), 100 ); + + m_bMultipleTrains = false; + m_nNumHills = 0; + + // blue material for multiple tracks colored overlay + m_iBlueMaterialIndex = surface()->DrawGetTextureId( "hud/cart_track_blue" ); + if ( m_iBlueMaterialIndex == -1 ) // we didn't find it, so create a new one + { + m_iBlueMaterialIndex = surface()->CreateNewTextureID(); + } + + surface()->DrawSetTextureFile( m_iBlueMaterialIndex, "hud/cart_track_blue", true, false ); + + // red material for multiple tracks colored overlay + m_iRedMaterialIndex = surface()->DrawGetTextureId( "hud/cart_track_red" ); + if ( m_iRedMaterialIndex == -1 ) // we didn't find it, so create a new one + { + m_iRedMaterialIndex = surface()->CreateNewTextureID(); + } + + surface()->DrawSetTextureFile( m_iRedMaterialIndex, "hud/cart_track_red", true, false ); + + for ( int i = 0 ; i < TEAM_TRAIN_MAX_HILLS ; i++ ) + { + char szPanelName[32]; + Q_snprintf( szPanelName, sizeof(szPanelName), "hill_panel%d", i ); + m_pHillPanels[i] = new CEscortHillPanel( this, szPanelName ); + + if ( m_pHillPanels[i] ) + { + m_pHillPanels[i]->SetHillNumber( i ); + m_pHillPanels[i]->SetTeamNumber( m_nTeam ); + } + } +} + +CTFHudEscort::~CTFHudEscort() +{ + if ( m_pHilightSwoop ) + { + m_pHilightSwoop->MarkForDeletion(); + m_pHilightSwoop = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Hide when we take a freeze cam shot +//----------------------------------------------------------------------------- +bool CTFHudEscort::IsVisible( void ) +{ + if( IsTakingAFreezecamScreenshot() ) + return false; + + if ( IsInFreezeCam() ) + return false; + + if ( !m_bHaveValidPointPositions ) + return false; + + return BaseClass::IsVisible(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudEscort::PerformLayout( void ) +{ + BaseClass::PerformLayout(); + + for ( int i = 0 ; i < TEAM_TRAIN_MAX_HILLS ; i++ ) + { + if ( m_pHillPanels[i] ) + { + m_pHillPanels[i]->SetTeamNumber( m_nTeam ); + m_pHillPanels[i]->SetVisible( false ); + } + } + + if ( ObjectiveResource() ) + { + if ( m_nNumHills > 0 ) + { + if ( m_pLevelBar ) + { + int xpos, ypos, wide, tall, zpos; + m_pLevelBar->GetBounds( xpos, ypos, wide, tall ); + zpos = m_pLevelBar->GetZPos() + 1; + + for ( int i = 0 ; i < m_nNumHills ; i++ ) + { + CEscortHillPanel *pPanel = m_pHillPanels[i]; + + if ( pPanel ) + { + float flStart = 0, flEnd = 0; + ObjectiveResource()->GetHillData( m_nTeam, i, flStart, flEnd ); + + pPanel->SetVisible( true ); + + int xOffset1 = wide * flStart; + int xOffset2 = wide * flEnd; + + pPanel->SetBounds( xpos + xOffset1, ypos, xOffset2 - xOffset1, tall ); + pPanel->SetZPos( zpos ); + } + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudEscort::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + KeyValues *pConditions = NULL; + if ( m_nTeam > LAST_SHARED_TEAM ) + { + pConditions = new KeyValues( "conditions" ); + if ( pConditions ) + { + if ( m_nTeam == TF_TEAM_RED ) + { + AddSubKeyNamed( pConditions, "if_team_red" ); + } + else + { + AddSubKeyNamed( pConditions, "if_team_blue" ); + } + + if ( m_bMultipleTrains ) + { + AddSubKeyNamed( pConditions, "if_multiple_trains" ); + + if ( m_nTeam == TF_TEAM_RED ) + { + AddSubKeyNamed( pConditions, "if_multiple_trains_red" ); + } + else + { + AddSubKeyNamed( pConditions, "if_multiple_trains_blue" ); + } + + if ( m_bTopPanel ) + { + AddSubKeyNamed( pConditions, "if_multiple_trains_top" ); + } + else + { + AddSubKeyNamed( pConditions, "if_multiple_trains_bottom" ); + } + } + else + { + if ( m_nNumHills > 0 ) + { + // we have a single track map with hills + AddSubKeyNamed( pConditions, "if_single_with_hills" ); + + if ( m_nTeam == TF_TEAM_RED ) + { + AddSubKeyNamed( pConditions, "if_single_with_hills_red" ); + } + else + { + AddSubKeyNamed( pConditions, "if_single_with_hills_blue" ); + } + } + } + } + } + + // load control settings... + LoadControlSettings( "resource/UI/ObjectiveStatusEscort.res", NULL, NULL, pConditions ); + + UpdateCPImages(); + + if ( m_pEscortItemImage && m_pEscortItemImageBottom ) + { + if ( m_bMultipleTrains == false ) + { + m_pEscortItemImageBottom->SetVisible( false ); + m_pEscortItemImage->SetVisible( true ); + } + else + { + m_pEscortItemImageBottom->SetVisible( !m_bTopPanel ); + m_pEscortItemImage->SetVisible( m_bTopPanel ); + } + } + + if ( pConditions ) + { + pConditions->deleteThis(); + } + + m_bAlarm = false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudEscort::UpdateAlarmAnimations( void ) +{ + if ( m_bMultipleTrains ) + { + if ( m_pEscortItemImageAlert ) + { + if ( m_bAlarm ) + { + if ( m_pEscortItemImageAlert->IsVisible() == false ) + { + m_pEscortItemImageAlert->SetVisible( true ); + } + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pEscortItemPanel, "HudCartAlarmPulse" ); + } + else + { + if ( m_pEscortItemImageAlert->IsVisible() == true ) + { + m_pEscortItemImageAlert->SetVisible( false ); + } + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pEscortItemPanel, "eventHudCartAlarmPulseStop" ); + } + } + } + else + { + if ( m_pEscortItemImageAlert && m_pEscortItemImageAlert->IsVisible() == true ) + { + m_pEscortItemImageAlert->SetVisible( false ); + } + + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pEscortItemPanel, "eventHudCartAlarmPulseStop" ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Update the escort image position +//----------------------------------------------------------------------------- +void CTFHudEscort::OnTick() +{ + // don't need to do this on non-escort maps (unless we're trying to override the HUD type) + if ( TFGameRules() && ( TFGameRules()->GetGameType() != TF_GAMETYPE_ESCORT ) && ( TFGameRules()->GetHUDType() != TF_HUDTYPE_ESCORT ) ) + return; + + if ( !BaseClass::IsVisible() ) // intentionally skipping our version of IsVisible() to bypass the !m_bHaveValidPointPositions check + return; + + bool bInvalidateLayout = false; + + if ( TFGameRules() ) + { + if ( m_bMultipleTrains != TFGameRules()->HasMultipleTrains() ) + { + // if we don't match, reload our settings + m_bMultipleTrains = TFGameRules()->HasMultipleTrains(); + bInvalidateLayout = true; + } + } + + if ( ObjectiveResource() ) + { + if ( m_nNumHills != ObjectiveResource()->GetNumNodeHillData( m_nTeam ) ) + { + m_nNumHills = ObjectiveResource()->GetNumNodeHillData( m_nTeam ); + bInvalidateLayout = true; + } + } + + if ( bInvalidateLayout ) + { + InvalidateLayout( false, true ); + } + + // if we haven't found any valid points yet, keep trying until we do... + if ( !m_bHaveValidPointPositions ) + { + UpdateCPImages(); + } + + bool bAlarm = ObjectiveResource() && ObjectiveResource()->GetTrackAlarm( m_nTeam ); + if ( bAlarm != m_bAlarm ) + { + m_bAlarm = bAlarm; + UpdateAlarmAnimations(); + } + + // The escort item position approaches its actual pos + int x, y, w, h; + m_pEscortItemPanel->GetBounds( x, y, w, h ); + + m_flProgressHistory.Interpolate( gpGlobals->curtime, hud_escort_interp.GetFloat() ); + + float flProgress = m_flProgress; + + if ( hud_escort_test_progress.GetFloat() >= 0 ) + { + flProgress = hud_escort_test_progress.GetFloat(); + } + + int iBarX, iBarY, iBarW, iBarH; + m_pLevelBar->GetBounds( iBarX, iBarY, iBarW, iBarH ); + + int newX = iBarX + (int)( (float)(iBarW) * m_flProgress ); + + int iSwoopX = newX - XRES(12); + + newX -= ( w / 2 ); + + m_pEscortItemPanel->SetPos( newX, y ); + + if ( m_bShowSwoop ) + { + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + // Tell the cap highlight image to fire up if it's our point being capped + if ( m_pHilightSwoop && pPlayer && pPlayer->GetTeamNumber() > LAST_SHARED_TEAM ) + { + if ( IsVisible() ) + { + ConVarRef cl_hud_minmode( "cl_hud_minmode", true ); + + int parentX, parentY; + GetPos( parentX, parentY ); + + int nYOffset = YRES(138); + int nXOffset = 0; + int nWide = XRES(24); + int nTall = YRES(100); + + if ( m_bMultipleTrains ) + { + nWide = XRES(20); + nTall = YRES(70); + + if ( pPlayer->GetTeamNumber() == m_nTeam ) + { + // top bar + nYOffset = YRES(97); + nXOffset = XRES(2); + } + else + { + // bottom bar + nYOffset = YRES(61); + nXOffset = XRES(2); + } + } + else + { + if ( cl_hud_minmode.IsValid() && cl_hud_minmode.GetBool() ) + { + nYOffset = YRES(96); + nXOffset = XRES(4); + nWide = XRES(16); + nTall = YRES(70); + } + } + + int nMidBarY = iBarY + ( iBarH / 2 ); + m_pHilightSwoop->SetPos( parentX + iSwoopX + nXOffset, parentY + nMidBarY - nYOffset ); + m_pHilightSwoop->SetSize( nWide, nTall ); + m_pHilightSwoop->SetVisible( true ); + m_pHilightSwoop->StartSwoop(); + } + } + + m_bShowSwoop = false; + } + +// char value[64]; + + // 5 second countdown to receding + float flSecondsToRecede = MAX( 0, ( m_flRecedeTime <= 0 ) ? 0 : m_flRecedeTime - gpGlobals->curtime ); + if ( flSecondsToRecede > 0.0f && flSecondsToRecede <= TF_ESCORT_RECEDE_COUNTDOWN ) + { + int iDisplaySeconds = (int)( flSecondsToRecede ) + 1; + m_pEscortItemPanel->SetDialogVariable( "recede", VarArgs( "%d", iDisplaySeconds ) ); + + // we should not be showing the blocked image if we're showing the countdown + m_pBlocked->SetVisible( false ); + } + else + { + m_pEscortItemPanel->SetDialogVariable( "recede", "" ); + } + + // Debug string +// Q_snprintf( value, sizeof(value), "speed: %d progress: %.3f recede %.1f\n", m_iSpeedLevel, flProgress, flSecondsToRecede ); +// SetDialogVariable( "progress", value ); + + if ( m_bMultipleTrains ) + { + if ( m_pProgressBar && !m_pProgressBar->IsVisible() ) + { + m_pProgressBar->SetVisible( true ); + } + + m_pProgressBar->SetPercentage( m_flProgress ); + } + else + { + if ( m_pProgressBar && m_pProgressBar->IsVisible() ) + { + m_pProgressBar->SetVisible( false ); + } + } +} + + +//----------------------------------------------------------------------------- +// Purpose: Receive messages about changes in state +//----------------------------------------------------------------------------- +void CTFHudEscort::FireGameEvent( IGameEvent *event ) +{ + const char *eventName = event->GetName(); + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + + if ( !ObjectiveResource() ) + return; + + // make sure we care about this message + int iTeam = event->GetInt( "team", TEAM_UNASSIGNED ); + if ( iTeam != TEAM_UNASSIGNED && ( iTeam != m_nTeam ) ) + return; + + if ( FStrEq( eventName, "escort_progress" ) ) + { + m_flProgress = event->GetFloat( "progress" ); + + // so we don't interp back to the start position on reset + if ( event->GetBool( "reset" ) ) + { + m_flProgressHistory.ClearHistory(); + } + + m_flProgressHistory.NoteChanged( gpGlobals->curtime, false ); + } + else if ( FStrEq( eventName, "escort_speed" ) ) + { + int iSpeedLevel = event->GetInt( "speed" ); + int nPlayers = event->GetInt( "players" ); + + m_pSpeedBackwards->SetVisible( iSpeedLevel < 0 ); + + bool bShowPlayers = ( iSpeedLevel > 0 ) && ( nPlayers > 0 ); + m_pCapPlayerImage->SetVisible( bShowPlayers ); + m_pCapNumPlayers->SetVisible( bShowPlayers ); + m_pEscortItemPanel->SetDialogVariable( "numcappers", nPlayers ); + + // make sure the point isn't being marked as blocked when we're showing players or moving backwards + if ( bShowPlayers || ( iSpeedLevel < 0 ) ) + { + m_pBlocked->SetVisible( false ); + } + + m_pEscortItemPanel->InvalidateLayout(); + + if ( iSpeedLevel > 0 && m_iSpeedLevel == 0 ) + { + m_bShowSwoop = true; + } + + m_iSpeedLevel = iSpeedLevel; + } + if ( FStrEq( eventName, "escort_recede" ) ) + { + m_flRecedeTime = event->GetFloat( "recedetime" ); + } + else if ( FStrEq( eventName, "controlpoint_initialized" ) ) + { + UpdateCPImages(); + } + else if ( FStrEq( eventName, "controlpoint_updateimages" ) ) + { + // Update the images of our control point icons + int iIndex = event->GetInt( "index" ); + + bool bIsAnyCapBlocked = false; + + // Only invalidate the specified cap point + // unless iIndex is -1, then do them all + for (int i = 0; i < m_Icons.Count(); i++) + { + if ( iIndex != -1 && m_Icons[i]->GetCapIndex() != iIndex ) + continue; + + m_Icons[i]->SetForceOpaqueImages( !m_bMultipleTrains && ( m_nNumHills > 0 ) ); + m_Icons[i]->UpdateImage(); + + if ( ObjectiveResource()->IsCPBlocked( m_Icons[i]->GetCapIndex() ) ) + { + bIsAnyCapBlocked = true; + } + } + + // update our teardrop status + UpdateStatusTeardropFor( m_iCurrentCP ); + + // Assume that there is only one cap area linked to the escort item + m_pBlocked->SetVisible( bIsAnyCapBlocked ); + } + else if ( FStrEq( "controlpoint_updatecapping", eventName ) ) + { + // Update the capping status of our control point icons + int iIndex = event->GetInt( "index" ); + UpdateStatusTeardropFor( iIndex ); + return; + } + else if ( FStrEq( "controlpoint_starttouch", eventName ) ) + { + int iPlayer = event->GetInt( "player" ); + if ( pPlayer && iPlayer == pPlayer->entindex() ) + { + m_iCurrentCP = event->GetInt( "area" ); + UpdateStatusTeardropFor( m_iCurrentCP ); + } + } + else if ( FStrEq( "controlpoint_endtouch", eventName ) ) + { + int iPlayer = event->GetInt( "player" ); + if ( pPlayer && iPlayer == pPlayer->entindex() ) + { + m_iCurrentCP = -1; + UpdateStatusTeardropFor( m_iCurrentCP ); + } + } + else if ( FStrEq( "teamplay_round_start", eventName ) ) + { + InvalidateLayout(); + } + else if ( FStrEq( "localplayer_respawn", eventName ) ) + { + // reset the alarm (will be restarted in OnThink() if needed) + m_bAlarm = false; + UpdateAlarmAnimations(); + } + else if ( FStrEq( "localplayer_changeteam", eventName ) ) + { + // reset the alarm (will be restarted in OnThink() if needed) + m_bAlarm = false; + UpdateAlarmAnimations(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudEscort::UpdateStatusTeardropFor( int iIndex ) +{ + if ( !ObjectiveResource() ) + return; + + if ( m_bMultipleTrains ) + { + // don't draw teardrops for points that aren't in the local group the player cares about (group numbers map to the teams) + if ( iIndex != -1 && ( ObjectiveResource()->GetCPGroup( iIndex ) != ( m_nTeam - 2 ) ) ) // -2 to offset the team numbers to 0 + return; + + // don't draw teardrops if you're not the same team as the local player (top bar is the only one to use the teamdrop) + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer ) + { + if ( m_nTeam != pPlayer->GetTeamNumber() ) + return; + } + } + + if ( iIndex == -1 ) + { + iIndex = m_iCurrentCP; + } + + // Ignore requests to display progress bars for points we're not standing on + if ( ( m_iCurrentCP != iIndex ) ) + return; + + if ( iIndex >= ObjectiveResource()->GetNumControlPoints() ) + { + iIndex = -1; + } + + if ( m_pStatus ) + { + m_pStatus->SetupForPoint( iIndex ); + } +} + +void CTFHudEscort::UpdateCPImages( void ) +{ + if ( !ObjectiveResource() ) + return; + + // delete any existing control points + for ( int i = 0; i < m_Icons.Count(); i++) + { + m_Icons[i]->MarkForDeletion(); + } + m_Icons.RemoveAll(); + + Assert( m_pCPTemplate ); + + // dummy pos + int x, y, w, h; + m_pCPTemplate->GetBounds( x, y, w, h ); + int nZPos = m_pCPTemplate->GetZPos(); + + //bool bSetHome = false; + + int iValidPointPos = 0; // hax, how many points are not at 0.0f + + // Create an icon for each visible control point in this miniround + int iPoints = ObjectiveResource()->GetNumControlPoints(); + for ( int i = 0; i < iPoints; i++ ) + { + bool bValid = true; + + if ( !ObjectiveResource()->IsInMiniRound(i) || + !ObjectiveResource()->IsCPVisible(i) || + ( m_bMultipleTrains && ( ObjectiveResource()->GetCPGroup( i ) != ( m_nTeam - 2 ) ) ) ) // -2 to offset the team numbers to 0 + { + bValid = false; + } + + if ( bValid ) + { + CSimpleControlPoint *pIcon = new CSimpleControlPoint( this, "SimpleControlPointTemplate", i ); + pIcon->SetName( VarArgs("cp_%d", i ) ); + + m_Icons.AddToTail( vgui::SETUP_PANEL(pIcon) ); + + float flDist = ObjectiveResource()->GetPathDistance(i); + + int iBarX, iBarY, iBarW, iBarH; + m_pLevelBar->GetBounds( iBarX, iBarY, iBarW, iBarH ); + + int newX = iBarX + (int)( (float)iBarW * flDist ); + + newX -= ( w / 2 ); + + pIcon->SetBounds( newX, y, w, h ); + pIcon->SetZPos( nZPos ); + pIcon->InvalidateLayout(); + + if ( flDist > 0 ) + { + iValidPointPos++; + } + + pIcon->SetForceOpaqueImages( !m_bMultipleTrains && ( m_nNumHills > 0 ) ); + pIcon->UpdateImage(); + } + + } + + // we don't want to draw if we haven't got good point positions yet + m_bHaveValidPointPositions = ( iValidPointPos > 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudMultipleEscort::CTFHudMultipleEscort( Panel *parent, const char *name ) : EditablePanel( parent, name ) +{ + m_pBluePanel = new CTFHudEscort( this, "BlueEscortPanel" ); + m_pRedPanel = new CTFHudEscort( this, "RedEscortPanel" ); + + if ( m_pRedPanel ) + { + m_pRedPanel->SetTeam( TF_TEAM_RED ); + } + + ListenForGameEvent( "localplayer_changeteam" ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudMultipleEscort::~CTFHudMultipleEscort() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudMultipleEscort::SetVisible( bool state ) +{ + if ( m_pBluePanel ) + { + m_pBluePanel->SetVisible( state ); + } + + if ( m_pRedPanel ) + { + m_pRedPanel->SetVisible( state ); + } + + BaseClass::SetVisible( state ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudMultipleEscort::Reset() +{ + if ( m_pBluePanel ) + { + m_pBluePanel->Reset(); + } + + if ( m_pRedPanel ) + { + m_pRedPanel->Reset(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudMultipleEscort::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + KeyValues *pConditions = NULL; + if ( TFGameRules() && TFGameRules()->HasMultipleTrains() ) + { + pConditions = new KeyValues( "conditions" ); + if ( pConditions ) + { + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + int iPlayerTeam = pPlayer ? pPlayer->GetTeamNumber() : TEAM_UNASSIGNED; + + if ( iPlayerTeam == TF_TEAM_BLUE ) + { + AddSubKeyNamed( pConditions, "if_blue_is_top" ); + } + else + { + AddSubKeyNamed( pConditions, "if_red_is_top" ); + } + } + } + + // load control settings... + LoadControlSettings( "resource/UI/ObjectiveStatusMultipleEscort.res", NULL, NULL, pConditions ); + + if ( pConditions ) + { + pConditions->deleteThis(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudMultipleEscort::FireGameEvent( IGameEvent * event ) +{ + if ( FStrEq( "localplayer_changeteam", event->GetName() ) ) + { + if ( m_pRedPanel && m_pBluePanel ) + { + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + int iPlayerTeam = pPlayer ? pPlayer->GetTeamNumber() : TEAM_UNASSIGNED; + + if ( iPlayerTeam == TF_TEAM_BLUE ) + { + m_pBluePanel->SetTopPanel( true ); + m_pRedPanel->SetTopPanel( false ); + } + else + { + m_pBluePanel->SetTopPanel( false ); + m_pRedPanel->SetTopPanel( true ); + } + } + + InvalidateLayout( false, true ); + + if ( m_pRedPanel && m_pBluePanel ) + { + m_pRedPanel->InvalidateLayout( false, true ); + m_pBluePanel->InvalidateLayout( false, true ); + } + } +} |