//========= 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;
}