diff options
Diffstat (limited to 'game/client/tf/tf_hud_flagstatus.cpp')
| -rw-r--r-- | game/client/tf/tf_hud_flagstatus.cpp | 1436 |
1 files changed, 1436 insertions, 0 deletions
diff --git a/game/client/tf/tf_hud_flagstatus.cpp b/game/client/tf/tf_hud_flagstatus.cpp new file mode 100644 index 0000000..c851ca1 --- /dev/null +++ b/game/client/tf/tf_hud_flagstatus.cpp @@ -0,0 +1,1436 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "hudelement.h" +#include "iclientmode.h" +#include <KeyValues.h> +#include <vgui/IScheme.h> +#include <vgui/ISurface.h> +#include <vgui/ISystem.h> +#include <vgui_controls/AnimationController.h> +#include <vgui_controls/EditablePanel.h> +#include <vgui_controls/ImagePanel.h> +#include <vgui/IVGui.h> +#include <vgui/ISurface.h> +#include <vgui/IImage.h> +#include <vgui_controls/Label.h> + +#include "c_playerresource.h" +#include "teamplay_round_timer.h" +#include "utlvector.h" +#include "entity_capture_flag.h" +#include "c_tf_player.h" +#include "c_team.h" +#include "c_tf_team.h" +#include "c_team_objectiveresource.h" +#include "tf_hud_objectivestatus.h" +#include "tf_spectatorgui.h" +#include "teamplayroundbased_gamerules.h" +#include "tf_gamerules.h" +#include "tf_hud_freezepanel.h" +#include "c_func_capture_zone.h" +#include "clientmode_shared.h" +#include "tf_hud_mediccallers.h" +#include "view.h" +#include "prediction.h" +#include "tf_logic_robot_destruction.h" + +using namespace vgui; + +DECLARE_BUILD_FACTORY( CTFArrowPanel ); +DECLARE_BUILD_FACTORY( CTFFlagStatus ); + +DECLARE_HUDELEMENT( CTFFlagCalloutPanel ); + +ConVar tf_rd_flag_ui_mode( "tf_rd_flag_ui_mode", "3", FCVAR_DEVELOPMENTONLY, "When flags are stolen and not visible: 0 = Show outlines (glows), 1 = Show most valuable enemy flag (icons), 2 = Show all enemy flags (icons), 3 = Show all flags (icons)." ); + +extern ConVar tf_flag_caps_per_round; + +void AddSubKeyNamed( KeyValues *pKeys, const char *pszName ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFArrowPanel::CTFArrowPanel( Panel *parent, const char *name ) : vgui::Panel( parent, name ) +{ + m_RedMaterial.Init( "hud/objectives_flagpanel_compass_red", TEXTURE_GROUP_VGUI ); + m_BlueMaterial.Init( "hud/objectives_flagpanel_compass_blue", TEXTURE_GROUP_VGUI ); + m_NeutralMaterial.Init( "hud/objectives_flagpanel_compass_grey", TEXTURE_GROUP_VGUI ); + m_NeutralRedMaterial.Init( "hud/objectives_flagpanel_compass_grey_with_red", TEXTURE_GROUP_VGUI ); + + m_RedMaterialNoArrow.Init( "hud/objectives_flagpanel_compass_red_noArrow", TEXTURE_GROUP_VGUI ); + m_BlueMaterialNoArrow.Init( "hud/objectives_flagpanel_compass_blue_noArrow", TEXTURE_GROUP_VGUI ); + + m_pMaterial = m_NeutralMaterial; + m_bUseRed = false; + m_flNextColorSwitch = 0.0f; + + ivgui()->AddTickSignal( GetVPanel(), 100 ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFArrowPanel::OnTick( void ) +{ + if ( !m_hEntity.Get() ) + return; + + C_BaseEntity *pEnt = m_hEntity.Get(); + m_pMaterial = m_NeutralMaterial; + + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + + if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) + { + if ( m_bUseRed ) + { + m_pMaterial = m_NeutralRedMaterial; + } + else + { + m_pMaterial = m_NeutralMaterial; + } + + if ( pEnt && TFGameRules()->GetMannVsMachineAlarmStatus() == true ) + { + CCaptureFlag *pFlag = dynamic_cast<CCaptureFlag *>( pEnt ); + if ( pFlag && pFlag->IsStolen() ) + { + if ( m_flNextColorSwitch < gpGlobals->curtime ) + { + m_flNextColorSwitch = gpGlobals->curtime + 0.2f; + m_bUseRed = !m_bUseRed; + } + } + else + { + m_bUseRed = false; + } + } + else + { + m_bUseRed = false; + } + } + else + { + // figure out what material we need to use + if ( pEnt->GetTeamNumber() == TF_TEAM_RED ) + { + m_pMaterial = m_RedMaterial; + + if ( pLocalPlayer && ( pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) ) + { + // is our target a player? + C_BaseEntity *pTargetEnt = pLocalPlayer->GetObserverTarget(); + if ( pTargetEnt && pTargetEnt->IsPlayer() ) + { + // does our target have the flag and are they carrying the flag we're currently drawing? + C_TFPlayer *pTarget = static_cast< C_TFPlayer* >( pTargetEnt ); + if ( pTarget->HasTheFlag() && ( pTarget->GetItem() == pEnt ) ) + { + m_pMaterial = m_RedMaterialNoArrow; + } + } + } + } + else if ( pEnt->GetTeamNumber() == TF_TEAM_BLUE ) + { + m_pMaterial = m_BlueMaterial; + + if ( pLocalPlayer && ( pLocalPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) ) + { + // is our target a player? + C_BaseEntity *pTargetEnt = pLocalPlayer->GetObserverTarget(); + if ( pTargetEnt && pTargetEnt->IsPlayer() ) + { + // does our target have the flag and are they carrying the flag we're currently drawing? + C_TFPlayer *pTarget = static_cast< C_TFPlayer* >( pTargetEnt ); + if ( pTarget->HasTheFlag() && ( pTarget->GetItem() == pEnt ) ) + { + m_pMaterial = m_BlueMaterialNoArrow; + } + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +float CTFArrowPanel::GetAngleRotation( void ) +{ + float flRetVal = 0.0f; + + C_TFPlayer *pPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() ); + C_BaseEntity *pEnt = m_hEntity.Get(); + + if ( pPlayer && pEnt ) + { + QAngle vangles; + Vector eyeOrigin; + float zNear, zFar, fov; + + pPlayer->CalcView( eyeOrigin, vangles, zNear, zFar, fov ); + + Vector vecFlag = pEnt->WorldSpaceCenter() - eyeOrigin; + vecFlag.z = 0; + vecFlag.NormalizeInPlace(); + + Vector forward, right, up; + AngleVectors( vangles, &forward, &right, &up ); + forward.z = 0; + right.z = 0; + forward.NormalizeInPlace(); + right.NormalizeInPlace(); + + float dot = DotProduct( vecFlag, forward ); + float angleBetween = acos( dot ); + + dot = DotProduct( vecFlag, right ); + + if ( dot < 0.0f ) + { + angleBetween *= -1; + } + + flRetVal = RAD2DEG( angleBetween ); + } + + return flRetVal; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFArrowPanel::Paint() +{ + int x = 0; + int y = 0; + ipanel()->GetAbsPos( GetVPanel(), x, y ); + int nWidth = GetWide(); + int nHeight = GetTall(); + + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->MatrixMode( MATERIAL_MODEL ); + pRenderContext->PushMatrix(); + + VMatrix panelRotation; + panelRotation.Identity(); + MatrixBuildRotationAboutAxis( panelRotation, Vector( 0, 0, 1 ), GetAngleRotation() ); +// MatrixRotate( panelRotation, Vector( 1, 0, 0 ), 5 ); + panelRotation.SetTranslation( Vector( x + nWidth/2, y + nHeight/2, 0 ) ); + pRenderContext->LoadMatrix( panelRotation ); + + IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pMaterial ); + + CMeshBuilder meshBuilder; + meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); + + meshBuilder.TexCoord2f( 0, 0, 0 ); + meshBuilder.Position3f( -nWidth/2, -nHeight/2, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.TexCoord2f( 0, 1, 0 ); + meshBuilder.Position3f( nWidth/2, -nHeight/2, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.TexCoord2f( 0, 1, 1 ); + meshBuilder.Position3f( nWidth/2, nHeight/2, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.TexCoord2f( 0, 0, 1 ); + meshBuilder.Position3f( -nWidth/2, nHeight/2, 0 ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + + pMesh->Draw(); + pRenderContext->PopMatrix(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFArrowPanel::IsVisible( void ) +{ + if( IsTakingAFreezecamScreenshot() ) + return false; + + return BaseClass::IsVisible(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFFlagStatus::CTFFlagStatus( Panel *parent, const char *name ) : EditablePanel( parent, name ) +{ + m_pArrow = new CTFArrowPanel( this, "Arrow" ); + m_pStatusIcon = new CTFImagePanel( this, "StatusIcon" ); + m_pBriefcase = new CTFImagePanel( this, "Briefcase" ); + m_hEntity = NULL; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagStatus::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + KeyValues *pConditions = NULL; + + if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() ) + { + pConditions = new KeyValues( "conditions" ); + + if ( pConditions ) + { + AddSubKeyNamed( pConditions, "if_mvm" ); + } + } + + // load control settings... + LoadControlSettings( "resource/UI/FlagStatus.res", NULL, NULL, pConditions ); + + if ( pConditions ) + { + pConditions->deleteThis(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFFlagStatus::IsVisible( void ) +{ + C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer(); + if ( pPlayer && pPlayer->GetObserverMode() == OBS_MODE_FREEZECAM ) + return false; + + return BaseClass::IsVisible(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagStatus::UpdateStatus( void ) +{ + if ( m_hEntity.Get() ) + { + CCaptureFlag *pFlag = dynamic_cast<CCaptureFlag *>( m_hEntity.Get() ); + + if ( pFlag ) + { + const char *pszImage = "../hud/objectives_flagpanel_ico_flag_home"; + const char *pszBombImage = "../hud/bomb_dropped"; + + if ( pFlag->IsDropped() ) + { + pszImage = "../hud/objectives_flagpanel_ico_flag_dropped"; + } + else if ( pFlag->IsStolen() ) + { + pszImage = "../hud/objectives_flagpanel_ico_flag_moving"; + pszBombImage = "../hud/bomb_carried"; + } + + if ( m_pStatusIcon ) + { + m_pStatusIcon->SetImage( pszImage ); + } + + if ( TFGameRules() && TFGameRules()->IsMannVsMachineMode() && m_pBriefcase ) + { + m_pBriefcase->SetImage( pszBombImage ); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFHudFlagObjectives::CTFHudFlagObjectives( Panel *parent, const char *name ) : EditablePanel( parent, name ) +{ + m_pCarriedImage = NULL; + m_pPlayingTo = NULL; + m_bFlagAnimationPlayed = false; + m_bCarryingFlag = false; + m_pSpecCarriedImage = NULL; + m_pPoisonImage = NULL; + m_pPoisonTimeLabel = NULL; + + m_pRedFlag = new CTFFlagStatus( this, "RedFlag" ); + m_pBlueFlag = new CTFFlagStatus( this, "BlueFlag" ); + + m_bPlayingHybrid_CTF_CP = false; + m_bPlayingSpecialDeliveryMode = false; + + vgui::ivgui()->AddTickSignal( GetVPanel(), 250 ); + + ListenForGameEvent( "flagstatus_update" ); + + m_nNumValidFlags = -1; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFHudFlagObjectives::IsVisible( void ) +{ + if( IsTakingAFreezecamScreenshot() ) + return false; + + return BaseClass::IsVisible(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudFlagObjectives::ApplySchemeSettings( IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + KeyValues *pConditions = NULL; + + bool bHybrid = TFGameRules() && TFGameRules()->IsPlayingHybrid_CTF_CP(); + bool bMVM = TFGameRules() && TFGameRules()->IsMannVsMachineMode(); + bool bSpecialDeliveryMode = TFGameRules() && TFGameRules()->IsPlayingSpecialDeliveryMode(); + + int nNumFlags = 0; + + if ( m_pRedFlag && m_pRedFlag->GetEntity() != NULL ) + { + nNumFlags++; + } + + if ( m_pBlueFlag && m_pBlueFlag->GetEntity() != NULL ) + { + nNumFlags++; + } + + if ( nNumFlags == 2 && m_pRedFlag->GetEntity() == m_pBlueFlag->GetEntity() ) + { + // They're both pointing at the same flag! There's really only 1 + nNumFlags = 1; + } + + if ( nNumFlags == 0 ) + { + pConditions = new KeyValues( "conditions" ); + if ( pConditions ) + { + AddSubKeyNamed( pConditions, "if_no_flags" ); + } + + if ( bSpecialDeliveryMode ) + { + AddSubKeyNamed( pConditions, "if_specialdelivery" ); + } + } + else + { + if ( bHybrid || ( nNumFlags == 1 ) || bMVM || bSpecialDeliveryMode ) + { + pConditions = new KeyValues( "conditions" ); + if ( pConditions ) + { + if ( bHybrid ) + { + AddSubKeyNamed( pConditions, "if_hybrid" ); + } + + if ( nNumFlags == 1 || bSpecialDeliveryMode ) + { + AddSubKeyNamed( pConditions, "if_hybrid_single" ); + } + else if ( nNumFlags == 2 ) + { + AddSubKeyNamed( pConditions, "if_hybrid_double" ); + } + + if ( bMVM ) + { + AddSubKeyNamed( pConditions, "if_mvm" ); + } + + if ( bSpecialDeliveryMode ) + { + AddSubKeyNamed( pConditions, "if_specialdelivery" ); + } + } + } + } + + // load control settings... + LoadControlSettings( "resource/UI/HudObjectiveFlagPanel.res", NULL, NULL, pConditions ); + + m_pCarriedImage = dynamic_cast<ImagePanel *>( FindChildByName( "CarriedImage" ) ); + m_pPlayingTo = dynamic_cast<CExLabel *>( FindChildByName( "PlayingTo" ) ); + m_pPlayingToBG = FindChildByName( "PlayingToBG" ); + + m_pCapturePoint = dynamic_cast<CTFArrowPanel *>( FindChildByName( "CaptureFlag" ) ); + + m_pSpecCarriedImage = dynamic_cast<ImagePanel *>( FindChildByName( "SpecCarriedImage" ) ); + + m_pPoisonImage = dynamic_cast<ImagePanel *>( FindChildByName( "PoisonIcon" ) ); + m_pPoisonTimeLabel = dynamic_cast<CExLabel *>( FindChildByName( "PoisonTimeLabel" ) ); + + // outline is always on, so we need to init the alpha to 0 + vgui::Panel *pOutline = FindChildByName( "OutlineImage" ); + if ( pOutline ) + { + pOutline->SetAlpha( 0 ); + } + + if ( pConditions ) + { + pConditions->deleteThis(); + } + + UpdateStatus(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudFlagObjectives::Reset() +{ + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "FlagOutlineHide" ); + + UpdateStatus(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudFlagObjectives::SetPlayingToLabelVisible( bool bVisible ) +{ + if ( m_pPlayingTo && m_pPlayingToBG ) + { + if ( m_pPlayingTo->IsVisible() != bVisible ) + { + m_pPlayingTo->SetVisible( bVisible ); + } + + if ( m_pPlayingToBG->IsVisible() != bVisible ) + { + m_pPlayingToBG->SetVisible( bVisible ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudFlagObjectives::OnTick() +{ + int nNumValidFlags = 0; + + // check that our blue panel still points at a valid flag + if ( m_pBlueFlag && m_pBlueFlag->GetEntity() ) + { + CCaptureFlag *pFlag = dynamic_cast< CCaptureFlag* >( m_pBlueFlag->GetEntity() ); + if ( !pFlag || pFlag->IsDisabled() ) + { + m_pBlueFlag->SetEntity( NULL ); + } + } + + // check that our red panel still points at a valid flag + if ( m_pRedFlag && m_pRedFlag->GetEntity() ) + { + CCaptureFlag *pFlag = dynamic_cast< CCaptureFlag* >( m_pRedFlag->GetEntity() ); + if ( !pFlag || pFlag->IsDisabled() ) + { + m_pRedFlag->SetEntity( NULL ); + } + } + + // iterate through the flags to set their position in our HUD + for ( int i = 0; i<ICaptureFlagAutoList::AutoList().Count(); i++ ) + { + CCaptureFlag *pFlag = static_cast< CCaptureFlag* >( ICaptureFlagAutoList::AutoList()[i] ); + + if ( !pFlag->IsDisabled() || pFlag->IsVisibleWhenDisabled() ) + { + if ( pFlag->GetTeamNumber() == TF_TEAM_RED ) + { + if ( m_pRedFlag ) + { + bool bNeedsUpdate = m_pRedFlag->GetEntity() != pFlag; + m_pRedFlag->SetEntity( pFlag ); + if ( bNeedsUpdate ) + { + UpdateStatus(); + } + } + } + else if ( pFlag->GetTeamNumber() == TF_TEAM_BLUE ) + { + if ( m_pBlueFlag ) + { + bool bNeedsUpdate = m_pBlueFlag->GetEntity() != pFlag; + m_pBlueFlag->SetEntity( pFlag ); + if ( bNeedsUpdate ) + { + UpdateStatus(); + } + } + } + else if ( pFlag->GetTeamNumber() == TEAM_UNASSIGNED ) + { + if ( m_pBlueFlag && !m_pBlueFlag->GetEntity() ) + { + m_pBlueFlag->SetEntity( pFlag ); + + if ( !m_pBlueFlag->IsVisible() ) + { + m_pBlueFlag->SetVisible( true ); + } + + if ( m_pRedFlag && m_pRedFlag->IsVisible() ) + { + m_pRedFlag->SetVisible( false ); + } + } + else if ( m_pRedFlag && !m_pRedFlag->GetEntity() ) + { + // make sure both panels aren't pointing at the same entity + if ( !m_pBlueFlag || ( pFlag != m_pBlueFlag->GetEntity() ) ) + { + m_pRedFlag->SetEntity( pFlag ); + + if ( !m_pRedFlag->IsVisible() ) + { + m_pRedFlag->SetVisible( true ); + } + } + } + } + + nNumValidFlags++; + } + + // VGUI callout panels + if ( CTFRobotDestructionLogic::GetRobotDestructionLogic() && CTFRobotDestructionLogic::GetRobotDestructionLogic()->GetType() == CTFRobotDestructionLogic::TYPE_ROBOT_DESTRUCTION ) + { + if ( tf_rd_flag_ui_mode.GetInt() && !pFlag->IsDisabled() && !pFlag->IsHome() ) + { + Vector vecLocation = pFlag->GetAbsOrigin() + Vector( 0.f, 0.f, 18.f ); + CTFFlagCalloutPanel::AddFlagCalloutIfNotFound( pFlag, FLT_MAX, vecLocation ); + } + } + } + + if ( m_nNumValidFlags != nNumValidFlags ) + { + m_nNumValidFlags = nNumValidFlags; + InvalidateLayout( false, true ); + } + + // are we playing captures for rounds? + if ( !TFGameRules() || ( !TFGameRules()->IsPlayingHybrid_CTF_CP() && !TFGameRules()->IsPlayingSpecialDeliveryMode() && !TFGameRules()->IsMannVsMachineMode() ) ) + { + if ( tf_flag_caps_per_round.GetInt() > 0 ) + { + C_TFTeam *pTeam = GetGlobalTFTeam( TF_TEAM_BLUE ); + if ( pTeam ) + { + SetDialogVariable( "bluescore", pTeam->GetFlagCaptures() ); + } + + pTeam = GetGlobalTFTeam( TF_TEAM_RED ); + if ( pTeam ) + { + SetDialogVariable( "redscore", pTeam->GetFlagCaptures() ); + } + + SetPlayingToLabelVisible( true ); + SetDialogVariable( "rounds", tf_flag_caps_per_round.GetInt() ); + } + else // we're just playing straight score + { + C_TFTeam *pTeam = GetGlobalTFTeam( TF_TEAM_BLUE ); + if ( pTeam ) + { + SetDialogVariable( "bluescore", pTeam->Get_Score() ); + } + + pTeam = GetGlobalTFTeam( TF_TEAM_RED ); + if ( pTeam ) + { + SetDialogVariable( "redscore", pTeam->Get_Score() ); + } + + SetPlayingToLabelVisible( false ); + } + } + + // check the local player to see if they're spectating, OBS_MODE_IN_EYE, and the target entity is carrying the flag + bool bSpecCarriedImage = false; + CCaptureFlag *pPoisonFlag = NULL; + C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( pPlayer ) + { + if ( pPlayer->GetObserverMode() == OBS_MODE_IN_EYE ) + { + // does our target have the flag? + C_BaseEntity *pEnt = pPlayer->GetObserverTarget(); + if ( pEnt && pEnt->IsPlayer() ) + { + C_TFPlayer *pTarget = static_cast< C_TFPlayer* >( pEnt ); + if ( pTarget->HasTheFlag() ) + { + bSpecCarriedImage = true; + if ( pTarget->GetTeamNumber() == TF_TEAM_RED ) + { + if ( m_pSpecCarriedImage ) + { + m_pSpecCarriedImage->SetImage( "../hud/objectives_flagpanel_carried_blue" ); + } + } + else + { + if ( m_pSpecCarriedImage ) + { + m_pSpecCarriedImage->SetImage( "../hud/objectives_flagpanel_carried_red" ); + } + } + } + } + } + + if ( pPlayer->HasTheFlag() && TFGameRules()->IsPowerupMode() ) + { + CCaptureFlag *pFlag = dynamic_cast<CCaptureFlag *>( pPlayer->GetItem() ); + if ( pFlag ) + { + pPoisonFlag = pFlag; + } + } + } + + if ( m_pSpecCarriedImage ) + { + m_pSpecCarriedImage->SetVisible( bSpecCarriedImage ); + } + + if ( m_pPoisonImage ) + { + m_pPoisonImage->SetVisible( pPoisonFlag && pPoisonFlag->IsPoisonous() ); + } + + if ( m_pPoisonTimeLabel ) + { + m_pPoisonTimeLabel->SetVisible( pPoisonFlag && pPoisonFlag->GetPoisonTime() > 0.f && !pPoisonFlag->IsPoisonous() ); + if ( m_pPoisonTimeLabel->IsVisible() ) + { + int nNumSecondsToPoisonous = pPoisonFlag->GetPoisonTime() - gpGlobals->curtime; + m_pPoisonTimeLabel->SetText( CFmtStr( "%d", nNumSecondsToPoisonous ) ); + } + } + + if ( TFGameRules() ) + { + if ( m_bPlayingHybrid_CTF_CP != TFGameRules()->IsPlayingHybrid_CTF_CP() ) + { + m_bPlayingHybrid_CTF_CP = TFGameRules()->IsPlayingHybrid_CTF_CP(); + InvalidateLayout( false, true ); + } + + if ( m_bPlayingSpecialDeliveryMode != TFGameRules()->IsPlayingSpecialDeliveryMode() ) + { + m_bPlayingSpecialDeliveryMode = TFGameRules()->IsPlayingSpecialDeliveryMode(); + InvalidateLayout( false, true ); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudFlagObjectives::SetCarriedImage( const char *pchIcon ) +{ + if ( m_pCarriedImage ) + { + m_pCarriedImage->SetImage( pchIcon ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudFlagObjectives::UpdateStatus( C_BasePlayer *pNewOwner /*= NULL*/, C_BaseEntity *pFlagEntity /*= NULL*/ ) +{ + C_TFPlayer *pLocalPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() ); + + // are we carrying a flag? + CCaptureFlag *pPlayerFlag = NULL; + if ( pLocalPlayer && pLocalPlayer->HasItem() && pLocalPlayer->GetItem()->GetItemID() == TF_ITEM_CAPTURE_FLAG ) + { + if ( !pNewOwner || pNewOwner == pLocalPlayer ) + { + pPlayerFlag = dynamic_cast< CCaptureFlag* >( pLocalPlayer->GetItem() ); + } + } + + if ( !pPlayerFlag && pLocalPlayer && pLocalPlayer == pNewOwner ) + { + pPlayerFlag = dynamic_cast< CCaptureFlag* >( pFlagEntity ); + } + + if ( pPlayerFlag ) + { + m_bCarryingFlag = true; + + // make sure the panels are on, set the initial alpha values, + // set the color of the flag we're carrying, and start the animations + if ( m_pBlueFlag && m_pBlueFlag->IsVisible() ) + { + m_pBlueFlag->SetVisible( false ); + } + + if ( m_pRedFlag && m_pRedFlag->IsVisible() ) + { + m_pRedFlag->SetVisible( false ); + } + + if ( m_pCarriedImage && !m_pCarriedImage->IsVisible() ) + { + int nTeam; + if ( pPlayerFlag->GetType() == TF_FLAGTYPE_ATTACK_DEFEND || + pPlayerFlag->GetType() == TF_FLAGTYPE_TERRITORY_CONTROL || + pPlayerFlag->GetType() == TF_FLAGTYPE_INVADE || + pPlayerFlag->GetType() == TF_FLAGTYPE_RESOURCE_CONTROL ) + { + nTeam = ( ( GetLocalPlayerTeam() == TF_TEAM_BLUE ) ? ( TF_TEAM_BLUE ) : ( TF_TEAM_RED ) ); + } + else + { + // normal CTF behavior (carrying the enemy flag) + nTeam = ( ( GetLocalPlayerTeam() == TF_TEAM_RED ) ? ( TF_TEAM_BLUE ) : ( TF_TEAM_RED ) ); + } + + + char szImage[ MAX_PATH ]; + pPlayerFlag->GetHudIcon( nTeam, szImage, sizeof( szImage ) ); + + SetCarriedImage( szImage ); + m_pCarriedImage->SetVisible( true ); + } + + if ( !m_bFlagAnimationPlayed ) + { + m_bFlagAnimationPlayed = true; + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "FlagOutline" ); + } + + if ( m_pCapturePoint && !m_pCapturePoint->IsVisible() ) + { + m_pCapturePoint->SetVisible( true ); + } + + if ( pLocalPlayer && m_pCapturePoint ) + { + // go through all the capture zones and find ours + for ( int i = 0; i<ICaptureZoneAutoList::AutoList().Count(); i++ ) + { + C_CaptureZone *pCaptureZone = static_cast< C_CaptureZone* >( ICaptureZoneAutoList::AutoList()[i] ); + if ( !pCaptureZone->IsDormant() ) + { + if ( pCaptureZone->GetTeamNumber() == pLocalPlayer->GetTeamNumber() && !pCaptureZone->IsDisabled() ) + { + m_pCapturePoint->SetEntity( pCaptureZone ); + } + } + } + } + } + else + { + // were we carrying the flag? + if ( m_bCarryingFlag ) + { + m_bCarryingFlag = false; + g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "FlagOutline" ); + } + + m_bFlagAnimationPlayed = false; + + if ( m_pCarriedImage && m_pCarriedImage->IsVisible() ) + { + m_pCarriedImage->SetVisible( false ); + } + + if ( m_pCapturePoint && m_pCapturePoint->IsVisible() ) + { + m_pCapturePoint->SetVisible( false ); + } + + if ( m_pBlueFlag ) + { + if ( m_pBlueFlag->GetEntity() != NULL ) + { + if ( !m_pBlueFlag->IsVisible() ) + { + m_pBlueFlag->SetVisible( true ); + } + + m_pBlueFlag->UpdateStatus(); + } + else + { + if ( m_pBlueFlag->IsVisible() ) + { + m_pBlueFlag->SetVisible( false ); + } + } + } + + if ( m_pRedFlag ) + { + if ( m_pRedFlag->GetEntity() != NULL ) + { + if ( !m_pRedFlag->IsVisible() ) + { + m_pRedFlag->SetVisible( true ); + } + + m_pRedFlag->UpdateStatus(); + } + else + { + if ( m_pRedFlag->IsVisible() ) + { + m_pRedFlag->SetVisible( false ); + } + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFHudFlagObjectives::FireGameEvent( IGameEvent *event ) +{ + const char *eventName = event->GetName(); + + if ( FStrEq( eventName, "flagstatus_update" ) ) + { + int nVictimID = event->GetInt( "userid" ); + C_BasePlayer *pNewOwner = USERID2PLAYER( nVictimID ); + + int nFlagEntIndex = event->GetInt( "entindex" ); + C_BaseEntity *pFlagEntity = ClientEntityList().GetEnt( nFlagEntIndex ); + + UpdateStatus( pNewOwner, pFlagEntity ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +#define FLAG_CALLER_WIDE ( XRES( 30 ) ) +#define FLAG_CALLER_TALL ( YRES( 30 ) ) +#define FLAG_CALLER_ARROW_WIDE ( XRES( 8 ) ) +#define FLAG_CALLER_ARROW_TALL ( YRES( 10 ) ) +#define FLAG_CALLER_DISPLAY_ENEMY_ONE 1 +#define FLAG_CALLER_DISPLAY_ENEMY_ALL 2 +#define FLAG_CALLER_DISPLAY_ALL 3 + +CUtlVector< CTFFlagCalloutPanel* > CTFFlagCalloutPanel::m_FlagCalloutPanels; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFFlagCalloutPanel::CTFFlagCalloutPanel( const char *pElementName ) : CHudElement( pElementName ), BaseClass( NULL, pElementName ) +{ + m_FlagCalloutPanels.AddToTail( this ); + + SetParent( g_pClientMode->GetViewport() ); + + RegisterForRenderGroup( "mid" ); + RegisterForRenderGroup( "commentary" ); + SetHiddenBits( HIDEHUD_MISCSTATUS ); + + // SetBounds( 0, 0, FLAG_CALLER_WIDE, FLAG_CALLER_TALL ); + vgui::ivgui()->AddTickSignal( GetVPanel() ); + + m_pFlagCalloutPanel = new CTFImagePanel( this, "FlagCalloutPanel" ); + m_pFlagValueLabel = new Label( this, "FlagValueLabel", "" ); + m_pFlagStatusIcon = new CTFImagePanel( this, "StatusIcon" ); + + m_flRemoveTime = 1.f; + m_flFirstDisplayTime = 1.f; + m_pArrowMaterial = NULL; + m_iDrawArrow = DRAW_ARROW_UP; + m_bFlagVisible = false; // On screen, line-of-sight + + m_flPrevScale = 0.f; + m_nPanelWideOrig = 0; + m_nPanelTallOrig = 0; + m_nLabelWideOrig = 0; + m_nLabelTallOrig = 0; + m_nIconWideOrig = 0; + m_nIconTallOrig = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFFlagCalloutPanel::~CTFFlagCalloutPanel( void ) +{ + bool bFound = false; + FOR_EACH_VEC_BACK( m_FlagCalloutPanels, i ) + { + if ( m_FlagCalloutPanels[i] == this ) + { + m_FlagCalloutPanels.Remove( i ); + bFound = true; + break; + } + } + + // We should have found the panel and returned earlier + Assert( bFound ); + + if ( m_pArrowMaterial ) + { + m_pArrowMaterial->DecrementReferenceCount(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::ApplySchemeSettings( vgui::IScheme *pScheme ) +{ + BaseClass::ApplySchemeSettings( pScheme ); + + LoadControlSettings( "resource/UI/FlagCalloutPanel.res" ); + + if ( m_pArrowMaterial ) + { + m_pArrowMaterial->DecrementReferenceCount(); + } + m_pArrowMaterial = materials->FindMaterial( "HUD/medic_arrow", TEXTURE_GROUP_VGUI ); + m_pArrowMaterial->IncrementReferenceCount(); + + if ( !m_pFlagCalloutPanel ) + return; + + if ( !m_pFlagValueLabel ) + return; + + if ( !m_pFlagStatusIcon ) + return; + + m_pFlagCalloutPanel->GetSize( m_nPanelWideOrig, m_nPanelTallOrig ); + m_pFlagValueLabel->GetSize( m_nLabelWideOrig, m_nLabelTallOrig ); + m_pFlagStatusIcon->GetSize( m_nIconWideOrig, m_nIconTallOrig ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::PerformLayout( void ) +{ + BaseClass::PerformLayout(); + + // SetSize( FLAG_CALLER_WIDE, FLAG_CALLER_TALL ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::GetCalloutPosition( const Vector &vecDelta, float flRadius, float *xpos, float *ypos, float *flRotation ) +{ + // Player Data + QAngle playerAngles = MainViewAngles(); + + Vector forward, right, up( 0.f, 0.f, 1.f ); + AngleVectors( playerAngles, &forward, NULL, NULL ); + forward.z = 0.f; + VectorNormalize( forward ); + CrossProduct( up, forward, right ); + float front = DotProduct( vecDelta, forward ); + float side = DotProduct( vecDelta, right ); + *xpos = flRadius * -side; + *ypos = flRadius * -front; + + // Get the rotation (yaw) + *flRotation = atan2( *xpos, *ypos ) + M_PI; + *flRotation *= 180.f / M_PI; + + float yawRadians = -( *flRotation ) * M_PI / 180.f; + float ca = cos( yawRadians ); + float sa = sin( yawRadians ); + + // Rotate it around the circle + *xpos = (int)( ( ScreenWidth() / 2 ) + ( flRadius * sa ) ); + *ypos = (int)( ( ScreenHeight() / 2 ) - ( flRadius * ca ) ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::OnTick( void ) +{ + int nDisplayMode = tf_rd_flag_ui_mode.GetInt(); + + // Panels self-manage their existence and visibility + C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalTFPlayer || !m_hFlag || m_hFlag->IsHome() || m_hFlag->IsDisabled() || !nDisplayMode ) + { + MarkForDeletion(); + return; + } + + bool bShouldDraw = ShouldShowFlagIconToLocalPlayer(); + + // Only show the most valuable enemy flag in this mode + if ( nDisplayMode == FLAG_CALLER_DISPLAY_ENEMY_ONE ) + { + int nHighestValue = 0; + CCaptureFlag *pMostValuableFlag = NULL; + + for ( int i = 0; i < ICaptureFlagAutoList::AutoList().Count(); ++i ) + { + CCaptureFlag *pFlag = static_cast< CCaptureFlag* >( ICaptureFlagAutoList::AutoList()[i] ); + if ( pFlag && pFlag->GetPointValue() > nHighestValue ) + { + if ( pFlag->IsDisabled() ) + continue; + + if ( pFlag->IsHome() ) + continue; + + if ( pFlag->InSameTeam( pLocalTFPlayer ) ) + continue; + + if ( pFlag->GetPointValue() > nHighestValue ) + { + nHighestValue = pFlag->GetPointValue(); + pMostValuableFlag = pFlag; + } + } + } + + // If we're not it + if ( pMostValuableFlag != m_hFlag ) + bShouldDraw = false; + } + + if ( IsVisible() != bShouldDraw ) + { + if ( !IsVisible() ) + { + m_flFirstDisplayTime = gpGlobals->curtime; + m_flPrevScale = 0.f; + } + + SetVisible( bShouldDraw ); + } + if ( IsEnabled() != bShouldDraw ) + { + SetEnabled( bShouldDraw ); + } + + if ( !bShouldDraw ) + return; + + bool bCarried = ( !m_hFlag->IsDropped() && m_hFlag->GetPrevOwner() ); + if ( bCarried && !prediction->IsFirstTimePredicted() ) + return; + + // Adjust scale based on distance + Vector vecDistance = m_hFlag->GetAbsOrigin() - pLocalTFPlayer->GetAbsOrigin(); + ScaleAndPositionCallout( RemapValClamped( vecDistance.LengthSqr(), ( 1000.f * 1000.f ), ( 4000.f * 4000.f ), 1.f, 0.6f ) ); + + // Reposition the callout based on our target's position + int iX, iY; + Vector vecTarget = ( bCarried ) ? m_hFlag->GetPrevOwner()->GetAbsOrigin() : m_hFlag->GetAbsOrigin(); + Vector vecDelta = vecTarget - MainViewOrigin(); + bool bOnScreen = GetVectorInHudSpace( vecTarget, iX, iY ); + int nHalfWidth = GetWide() / 2; + + if ( !bOnScreen || iX < nHalfWidth || iX > ScreenWidth() - nHalfWidth ) + { + // Only show side panel for a short period of time in this mode + if ( TFGameRules() && TFGameRules()->IsPlayingRobotDestructionMode() && gpGlobals->curtime > m_flFirstDisplayTime + 5.f ) + { + m_iDrawArrow = DRAW_ARROW_UP; + SetAlpha( 0 ); + } + else + { + // It's off the screen. Position the callout. + VectorNormalize( vecDelta ); + float xpos, ypos; + float flRotation; + float flRadius = YRES( 100 ); + GetCalloutPosition( vecDelta, flRadius, &xpos, &ypos, &flRotation ); + + iX = xpos; + iY = ypos; + + Vector vCenter = m_hFlag->WorldSpaceCenter( ); + if ( MainViewRight().Dot( vCenter - MainViewOrigin() ) > 0 ) + { + m_iDrawArrow = DRAW_ARROW_RIGHT; + } + else + { + m_iDrawArrow = DRAW_ARROW_LEFT; + } + + // Move the icon there + SetPos( iX - nHalfWidth, iY - ( GetTall() / 2 ) ); + SetAlpha( 128 ); + } + } + else + { + // On screen + // If our target isn't visible, we draw transparently + trace_t tr; + UTIL_TraceLine( vecTarget, MainViewOrigin(), MASK_VISIBLE, NULL, COLLISION_GROUP_NONE, &tr ); + if ( tr.fraction >= 1.f ) + { + m_bFlagVisible = true; + SetAlpha( 0 ); + return; + } + else + { + m_iDrawArrow = DRAW_ARROW_UP; + SetAlpha( 128 ); + SetPos( iX - nHalfWidth, iY - ( GetTall() / 2 ) ); + } + } + + m_bFlagVisible = false; + + if ( !m_pFlagCalloutPanel ) + return; + + if ( !m_pFlagValueLabel ) + return; + + if ( !m_pFlagStatusIcon ) + return; + + m_pFlagCalloutPanel->SetImage( m_hFlag->GetTeamNumber() == TF_TEAM_BLUE ? "../hud/obj_briefcase_blue" : "../hud/obj_briefcase_red" ); + m_pFlagValueLabel->SetText( CFmtStr( "%i", m_hFlag->GetPointValue() ) ); + + const char *pszImage = "../hud/objectives_flagpanel_ico_flag_home"; + if ( m_hFlag->IsDropped() ) + { + pszImage = "../hud/objectives_flagpanel_ico_flag_dropped"; + } + else if ( m_hFlag->IsStolen() ) + { + pszImage = "../hud/objectives_flagpanel_ico_flag_moving"; + } + m_pFlagStatusIcon->SetImage( pszImage ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::PaintBackground( void ) +{ + C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalTFPlayer ) + return; + + if ( !m_hFlag ) + { + SetAlpha( 0 ); + return; + } + + BaseClass::PaintBackground(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::Paint( void ) +{ + // Don't draw side panels if our target is visible. The particle effect will be doing it for us. + if ( m_bFlagVisible ) + return; + + BaseClass::Paint(); + + if ( m_iDrawArrow == DRAW_ARROW_UP ) + return; + + float uA, uB, yA, yB; + int x, y; + GetPos( x, y ); + if ( m_iDrawArrow == DRAW_ARROW_LEFT ) + { + uA = 1.f; + uB = 0.f; + yA = 0.f; + yB = 1.f; + x -= FLAG_CALLER_ARROW_WIDE; + } + else + { + uA = 0.f; + uB = 1.f; + yA = 0.f; + yB = 1.f; + x += m_pFlagCalloutPanel->GetWide(); + } + + int iyindent = ( GetTall() - FLAG_CALLER_ARROW_TALL ) * 0.5f; + y += iyindent; + + 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.f ); + meshBuilder.TexCoord2f( 0, uA, yA ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x + FLAG_CALLER_ARROW_WIDE, y, 0.f ); + meshBuilder.TexCoord2f( 0, uB, yA ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x + FLAG_CALLER_ARROW_WIDE, y + FLAG_CALLER_ARROW_TALL, 0.f ); + meshBuilder.TexCoord2f( 0, uB, yB ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.Position3f( x, y + FLAG_CALLER_ARROW_TALL, 0.f ); + meshBuilder.TexCoord2f( 0, uA, yB ); + meshBuilder.Color4ub( 255, 255, 255, 255 ); + meshBuilder.AdvanceVertex(); + + meshBuilder.End(); + pMesh->Draw(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::SetFlag( CCaptureFlag *pFlag, float flDuration, Vector &vecOffset ) +{ + m_hFlag = pFlag; + m_flRemoveTime = gpGlobals->curtime + flDuration; + m_vecOffset = vecOffset; + m_flFirstDisplayTime = gpGlobals->curtime; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CTFFlagCalloutPanel *CTFFlagCalloutPanel::AddFlagCalloutIfNotFound( CCaptureFlag *pFlag, float flDuration, Vector &vecLocation ) +{ + // How this system works: + // CTFHudFlagObjectives::OnTick() will attempt to create one panel per-flag that is stolen. + // CTFFlagCalloutPanel::OnTick() tries to manage whether or not the panel is visible, based on the UI mode. + + // See if we have a panel for this flag already + FOR_EACH_VEC_BACK( m_FlagCalloutPanels, i ) + { + if ( m_FlagCalloutPanels[i]->m_hFlag == pFlag ) + { + return NULL; + } + } + + CTFFlagCalloutPanel *pCallout = new CTFFlagCalloutPanel( "FlagCalloutHUD" ); + if ( pCallout ) + { + pCallout->SetFlag( pFlag, flDuration, vecLocation ); + } + return pCallout; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CTFFlagCalloutPanel::ShouldShowFlagIconToLocalPlayer( void ) +{ + C_TFPlayer *pLocalTFPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalTFPlayer ) + return false; + + int nDisplayMode = tf_rd_flag_ui_mode.GetInt(); + + // In "show all" mode, don't show flags on the local player's team that are being carried + if ( m_hFlag->IsStolen() && + m_hFlag->InSameTeam( pLocalTFPlayer ) && + nDisplayMode == FLAG_CALLER_DISPLAY_ALL ) + return false; + + // In all other modes, don't show flags on the local player's team + if ( m_hFlag->InSameTeam( pLocalTFPlayer ) && + nDisplayMode < FLAG_CALLER_DISPLAY_ALL ) + return false; + + // Don't show the player running this flag + if ( m_hFlag->IsStolen() && pLocalTFPlayer == m_hFlag->GetPrevOwner() ) + return false; + + return true; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CTFFlagCalloutPanel::ScaleAndPositionCallout( float flScale /*= 1.f*/ ) +{ + if ( flScale == m_flPrevScale ) + return; + + SetSize( ( FLAG_CALLER_WIDE * flScale ), ( FLAG_CALLER_TALL * flScale ) ); + + if ( !m_pFlagCalloutPanel ) + return; + + if ( !m_pFlagValueLabel ) + return; + + if ( !m_pFlagStatusIcon ) + return; + + // Briefcase - top-left + m_pFlagCalloutPanel->SetSize( ( m_nPanelWideOrig * flScale ), ( m_nPanelTallOrig * flScale ) ); + m_pFlagCalloutPanel->SetPos( 0, 0 ); + + // Label - centered + m_pFlagValueLabel->SetSize( ( m_nLabelWideOrig * flScale ), ( m_nLabelTallOrig * flScale ) ); + m_pFlagValueLabel->SetPos( ( m_pFlagCalloutPanel->GetWide() - m_pFlagValueLabel->GetWide() ) * 0.5f, ( m_pFlagCalloutPanel->GetWide() - m_pFlagValueLabel->GetTall() ) * 0.65f ); + + // Icon - lower-right + m_pFlagStatusIcon->SetSize( ( m_nIconWideOrig * flScale ), ( m_nIconTallOrig * flScale ) ); + m_pFlagStatusIcon->SetPos( ( m_pFlagCalloutPanel->GetWide() - m_pFlagStatusIcon->GetWide() ) * 1.05f, ( m_pFlagCalloutPanel->GetWide() - m_pFlagStatusIcon->GetTall() ) * 0.85f ); + + m_flPrevScale = flScale; +} + |