text: //========= Copyright © 1996-2006, Valve Corporation, All rights reserved. ============//
  //
  // Purpose: CTF Flag.
  //
  //=============================================================================//
  #include "cbase.h"
  #include "entity_capture_flag.h"
  #include "tf_gamerules.h"
  #include "tf_shareddefs.h"
  
  #ifdef CLIENT_DLL
  #include <vgui_controls/Panel.h>
  #include <vgui_controls/ImagePanel.h>
  #include <vgui_controls/EditablePanel.h>
  #include <vgui/IScheme.h>
  #include "hudelement.h"
  #include "iclientmode.h"
  #include "hud_numericdisplay.h"
  #include "tf_imagepanel.h"
  #include "c_tf_player.h"
  #include "c_tf_team.h"
  #include "tf_hud_objectivestatus.h"
  #include "view.h"
  #include "glow_outline_effect.h"
  
  extern CUtlVector<int>	g_Flags;
  
  ConVar cl_flag_return_size( "cl_flag_return_size", "20", FCVAR_CHEAT );
  
  #else
  #include "tf_player.h"
  #include "tf_team.h"
  #include "tf_objective_resource.h"
  #include "tf_gamestats.h"
  #include "func_respawnroom.h"
  #include "datacache/imdlcache.h"
  
  extern ConVar tf_flag_caps_per_round;
  
  ConVar cl_flag_return_height( "cl_flag_return_height", "82", FCVAR_CHEAT );
  
  #endif
  
  
  #ifdef CLIENT_DLL
  
  static void RecvProxy_IsDisabled( const CRecvProxyData *pData, void *pStruct, void *pOut )
  {
  	CCaptureFlag *pFlag = (CCaptureFlag *) pStruct;
  	bool bIsDisabled = ( pData->m_Value.m_Int > 0 );
  
  	if ( pFlag )
  	{
  		pFlag->SetDisabled( bIsDisabled ); 
  	}
  }
  
  #endif
  
  //=============================================================================
  //
  // CTF Flag tables.
  //
  
  IMPLEMENT_NETWORKCLASS_ALIASED( CaptureFlag, DT_CaptureFlag )
  
  BEGIN_NETWORK_TABLE( CCaptureFlag, DT_CaptureFlag )
  
  #ifdef GAME_DLL
  	SendPropBool( SENDINFO( m_bDisabled ) ),
  	SendPropInt( SENDINFO( m_nGameType ), 5, SPROP_UNSIGNED ),
  	SendPropInt( SENDINFO( m_nFlagStatus ), 3, SPROP_UNSIGNED ),
  	SendPropTime( SENDINFO( m_flResetTime ) ),
  	SendPropTime( SENDINFO( m_flNeutralTime ) ),
  	SendPropTime( SENDINFO( m_flMaxResetTime ) ),
  	SendPropEHandle( SENDINFO( m_hPrevOwner ) ),
  #else
  	RecvPropInt( RECVINFO( m_bDisabled ), 0, RecvProxy_IsDisabled ),
  	RecvPropInt( RECVINFO( m_nGameType ) ),
  	RecvPropInt( RECVINFO( m_nFlagStatus ) ),
  	RecvPropTime( RECVINFO( m_flResetTime ) ),
  	RecvPropTime( RECVINFO( m_flNeutralTime ) ),
  	RecvPropTime( RECVINFO( m_flMaxResetTime ) ),
  	RecvPropEHandle( RECVINFO( m_hPrevOwner ) ),
  #endif
  END_NETWORK_TABLE()
  
  BEGIN_DATADESC( CCaptureFlag )
  
  	// Keyfields.
  	DEFINE_KEYFIELD( m_nGameType, FIELD_INTEGER, "GameType" ),
  
  #ifdef GAME_DLL
  	// Inputs.
  	DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ),
  	DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ),
  	DEFINE_INPUTFUNC( FIELD_VOID, "RoundActivate", InputRoundActivate ),
  
  	// Outputs.
  	DEFINE_OUTPUT( m_outputOnReturn, "OnReturn" ),
  	DEFINE_OUTPUT( m_outputOnPickUp, "OnPickUp" ),
  	DEFINE_OUTPUT( m_outputOnDrop, "OnDrop" ),
  	DEFINE_OUTPUT( m_outputOnCapture, "OnCapture" ),
  #endif
  
  END_DATADESC();
  
  LINK_ENTITY_TO_CLASS( item_teamflag, CCaptureFlag );
  
  //=============================================================================
  //
  // CTF Flag functions.
  //
  
  CCaptureFlag::CCaptureFlag()
  {
  #ifdef CLIENT_DLL
  	m_pGlowTrailEffect = NULL;
  	m_pPaperTrailEffect = NULL;
  #else
  	m_hReturnIcon = NULL;
  #endif	
  	UseClientSideAnimation();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  unsigned int CCaptureFlag::GetItemID( void )
  {
  	return TF_ITEM_CAPTURE_FLAG;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Precache the model and sounds.
  //-----------------------------------------------------------------------------
  void CCaptureFlag::Precache( void )
  {
  	PrecacheModel( TF_FLAG_MODEL );
  
  	PrecacheScriptSound( TF_CTF_FLAGSPAWN );
  	PrecacheScriptSound( TF_CTF_ENEMY_STOLEN );
  	PrecacheScriptSound( TF_CTF_ENEMY_DROPPED );
  	PrecacheScriptSound( TF_CTF_ENEMY_CAPTURED );
  	PrecacheScriptSound( TF_CTF_ENEMY_RETURNED );
  	PrecacheScriptSound( TF_CTF_TEAM_STOLEN );
  	PrecacheScriptSound( TF_CTF_TEAM_DROPPED );
  	PrecacheScriptSound( TF_CTF_TEAM_CAPTURED );
  	PrecacheScriptSound( TF_CTF_TEAM_RETURNED );
  
  	PrecacheScriptSound( TF_AD_CAPTURED_SOUND );
  	PrecacheScriptSound( TF_AD_ENEMY_STOLEN );
  	PrecacheScriptSound( TF_AD_ENEMY_DROPPED );
  	PrecacheScriptSound( TF_AD_ENEMY_CAPTURED );
  	PrecacheScriptSound( TF_AD_ENEMY_RETURNED );
  	PrecacheScriptSound( TF_AD_TEAM_STOLEN );
  	PrecacheScriptSound( TF_AD_TEAM_DROPPED );
  	PrecacheScriptSound( TF_AD_TEAM_CAPTURED );
  	PrecacheScriptSound( TF_AD_TEAM_RETURNED );
  
  	PrecacheScriptSound( TF_INVADE_ENEMY_STOLEN );
  	PrecacheScriptSound( TF_INVADE_ENEMY_DROPPED );
  	PrecacheScriptSound( TF_INVADE_ENEMY_CAPTURED );
  	PrecacheScriptSound( TF_INVADE_TEAM_STOLEN );
  	PrecacheScriptSound( TF_INVADE_TEAM_DROPPED );
  	PrecacheScriptSound( TF_INVADE_TEAM_CAPTURED );
  	PrecacheScriptSound( TF_INVADE_FLAG_RETURNED );
  
  	PrecacheParticleSystem( "player_intel_trail_blue" );
  	PrecacheParticleSystem( "player_intel_trail_red" );
  	PrecacheParticleSystem( "player_intel_papertrail" );
  }
  
  #ifndef GAME_DLL
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CCaptureFlag::OnPreDataChanged( DataUpdateType_t updateType )
  {
  	m_nOldFlagStatus = m_nFlagStatus;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CCaptureFlag::OnDataChanged( DataUpdateType_t updateType )
  {
  	if ( m_nOldFlagStatus != m_nFlagStatus )
  	{
  		IGameEvent *pEvent = gameeventmanager->CreateEvent( "flagstatus_update" );
  		if ( pEvent )
  		{
  			gameeventmanager->FireEventClientSide( pEvent );
  		}
  	}
  }
  #endif
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::Spawn( void )
  {
  	// Precache the model and sounds.  Set the flag model.
  	Precache();
  	SetModel( TF_FLAG_MODEL );
  	
  	// Set the flag solid and the size for touching.
  	SetSolid( SOLID_BBOX );
  	SetSolidFlags( FSOLID_NOT_SOLID | FSOLID_TRIGGER );
  	SetSize( vec3_origin, vec3_origin );
  
  	// Bloat the box for player pickup
  	CollisionProp()->UseTriggerBounds( true, 24 );
  
  	// use the initial dynamic prop "m_bStartDisabled" setting to set our own m_bDisabled flag
  #ifdef GAME_DLL
  	m_bDisabled = m_bStartDisabled;
  	m_bStartDisabled = false;
  
  	// Don't allow the intelligence to fade.
  	m_flFadeScale = 0.0f;
  #else
  	m_bDisabled = false;
  #endif
  
  	// Base class spawn.
  	BaseClass::Spawn();
  
  #ifdef GAME_DLL
  	// Save the starting position, so we can reset the flag later if need be.
  	m_vecResetPos = GetAbsOrigin();
  	m_vecResetAng = GetAbsAngles();
  
  	SetFlagStatus( TF_FLAGINFO_NONE );
  	ResetFlagReturnTime();
  	ResetFlagNeutralTime();
  
  	m_bAllowOwnerPickup = true;
  	m_hPrevOwner = NULL;
  
  	m_bCaptured = false;
  
  #else
  
  	// add this element if it isn't already in the list
  	if ( g_Flags.Find( entindex() ) == -1 )
  	{
  		g_Flags.AddToTail( entindex() );
  	}
  
  #endif
  
  	if ( m_bDisabled )
  	{
  		SetDisabled( true );
  	}
  	else
  	{
  		SetDisabled( false );
  	}
  }
  
  #ifdef CLIENT_DLL
  
  // Manage glow effect
  void CCaptureFlag::EnableGlowEffect(void)
  {
  	if (g_GlowObjectManager.HasGlowEffect(this))
  		return;
  
  	switch (GetTeamNumber())
  	{
  	case TF_TEAM_BLUE:
  		g_GlowObjectManager.RegisterGlowObject(this, Vector(0, 0, 255), 128, true, true, 0);
  		break;
  	case TF_TEAM_RED:
  		g_GlowObjectManager.RegisterGlowObject(this, Vector(255, 0, 0), 128, true, true, 0);
  		break;
  	default:
  		return;
  		break;
  	}
  
  }
  
  #endif
  
  #ifdef GAME_DLL
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CCaptureFlag::Activate( void )
  {
  	BaseClass::Activate();
  
  	m_iOriginalTeam = GetTeamNumber();
  	m_nSkin = ( GetTeamNumber() == TEAM_UNASSIGNED ) ? 2 : (GetTeamNumber() - 2);
  }
  #endif
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Reset the flag position state.
  //-----------------------------------------------------------------------------
  void CCaptureFlag::Reset( void )
  {
  #ifdef GAME_DLL
  	// Set the flag position.
  	SetAbsOrigin( m_vecResetPos );
  	SetAbsAngles( m_vecResetAng );
  
  	// No longer dropped, if it was.
  	SetFlagStatus( TF_FLAGINFO_NONE );
  	ResetFlagReturnTime();
  	ResetFlagNeutralTime();
  
  	m_bAllowOwnerPickup = true;
  	m_hPrevOwner = NULL;
  
  	if ( m_nGameType == TF_FLAGTYPE_INVADE )
  	{
  		ChangeTeam( m_iOriginalTeam );
  		m_nSkin = ( GetTeamNumber() == TEAM_UNASSIGNED ) ? 2 : (GetTeamNumber() - 2);
  	}
  
  	SetMoveType( MOVETYPE_NONE );
  #endif 
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CCaptureFlag::ResetMessage( void )
  {
  #ifdef GAME_DLL
  	if ( m_nGameType == TF_FLAGTYPE_CTF )
  	{
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			if ( iTeam == GetTeamNumber() )
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_CTF_ENEMY_RETURNED );
  
  				TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_YOUR_FLAG_RETURNED );
  			}
  			else
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_CTF_TEAM_RETURNED );
  
  				TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_ENEMY_FLAG_RETURNED );
  			}
  		}
  
  		// Returned sound
  		CPASAttenuationFilter filter( this, TF_CTF_FLAGSPAWN );
  		EmitSound( filter, entindex(), TF_CTF_FLAGSPAWN );
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_ATTACK_DEFEND )
  	{
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			if ( iTeam == GetTeamNumber() )
  			{
  				TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_AD_FlagReturned" );
  
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_AD_TEAM_RETURNED );
  			}
  			else
  			{
  				TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_AD_FlagReturned" );
  
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_AD_ENEMY_RETURNED );
  			}
  		}
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_INVADE )
  	{
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_Invade_FlagReturned" );
  
  			CTeamRecipientFilter filter( iTeam, true );
  			EmitSound( filter, entindex(), TF_INVADE_FLAG_RETURNED );
  		}
  	}
  
  	// Output.
  	m_outputOnReturn.FireOutput( this, this );
  
  	if ( m_hReturnIcon.Get() )
  	{
  		UTIL_Remove( m_hReturnIcon );
  		m_hReturnIcon = NULL;
  	}
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::FlagTouch( CBaseEntity *pOther )
  {
  	// Is the flag enabled?
  	if ( IsDisabled() )
  	{
  		return;
  	}
  
  	// The the touch from a live player.
  	if ( !pOther->IsPlayer() || !pOther->IsAlive() )
  	{
  		return;
  	}
  
  #ifdef GAME_DLL
  	// Don't let the person who threw this flag pick it up until it hits the ground.
  	// This way we can throw the flag to people, but not touch it as soon as we throw it ourselves
  	if(  m_hPrevOwner.Get() && m_hPrevOwner.Get() == pOther && m_bAllowOwnerPickup == false )
  	{
  		return;
  	}
  #endif
  
  	// Does my team own this flag? If so, no touch.
  	if ( m_nGameType == TF_FLAGTYPE_CTF && pOther->GetTeamNumber() == GetTeamNumber() )
  	{
  		return;
  	}
  
  	if ( ( m_nGameType == TF_FLAGTYPE_ATTACK_DEFEND || m_nGameType == TF_FLAGTYPE_TERRITORY_CONTROL ) &&
  		   pOther->GetTeamNumber() != GetTeamNumber() )
  	{
  		return;
  	}
  
  	if ( m_nGameType == TF_FLAGTYPE_INVADE && GetTeamNumber() != TEAM_UNASSIGNED )
  	{
  		if ( pOther->GetTeamNumber() != GetTeamNumber() )
  		{
  			return;
  		}
  	}
  
  	// Can't pickup flags during WaitingForPlayers
  	if ( TFGameRules()->IsInWaitingForPlayers() )
  		return;
  
  	// Get the touching player.
  	CTFPlayer *pPlayer = ToTFPlayer( pOther );
  	if ( !pPlayer )
  	{
  		return;
  	}
  
  	// Is the touching player about to teleport?
  	if ( pPlayer->m_Shared.InCond( TF_COND_SELECTED_TO_TELEPORT ) )
  		return;
  
  	// Don't let invulnerable players pickup flags
  	if ( pPlayer->m_Shared.InCond( TF_COND_INVULNERABLE ) )
  		return;
  
  #ifdef GAME_DLL
  	if ( PointInRespawnRoom(pPlayer,pPlayer->WorldSpaceCenter()) )
  		return;
  #endif
  
  	// Pick up the flag.
  	PickUp( pPlayer, true );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::PickUp( CTFPlayer *pPlayer, bool bInvisible )
  {
  	// Is the flag enabled?
  	if ( IsDisabled() )
  		return;
  
  	if ( !TFGameRules()->FlagsMayBeCapped() )
  		return;
  
  #ifdef GAME_DLL
  	if ( !m_bAllowOwnerPickup )
  	{
  		if ( m_hPrevOwner.Get() && m_hPrevOwner.Get() == pPlayer ) 
  		{
  			return;
  		}
  	}
  
  #endif
  
  	// Call into the base class pickup.
  	BaseClass::PickUp( pPlayer, false );
  
  	pPlayer->TeamFortress_SetSpeed();
  
  #ifdef GAME_DLL
  	
  	// Update the parent to set the correct place on the model to attach the flag.
  	int iAttachment = pPlayer->LookupAttachment( "flag" );
  	if( iAttachment != -1 )
  	{
  		SetParent( pPlayer, iAttachment );
  		SetLocalOrigin( vec3_origin );
  		SetLocalAngles( vec3_angle );
  	}
  
  	// Remove the player's disguse if they're a spy
  	if ( pPlayer->GetPlayerClass()->GetClassIndex() == TF_CLASS_SPY )
  	{
  		if ( pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) ||
  			pPlayer->m_Shared.InCond( TF_COND_DISGUISING ))
  		{
  			pPlayer->m_Shared.RemoveDisguise();
  		}
  	}
  
  	// Remove the touch function.
  	SetTouch( NULL );
  
  	m_hPrevOwner = pPlayer;
  	m_bAllowOwnerPickup = true;
  
  	if ( m_nGameType == TF_FLAGTYPE_CTF )
  	{
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			if ( iTeam != pPlayer->GetTeamNumber() )
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_CTF_ENEMY_STOLEN );
  
  				TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_YOUR_FLAG_TAKEN );
  			}
  			else
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_CTF_TEAM_STOLEN );
  
  				// exclude the guy who just picked it up
  				filter.RemoveRecipient( pPlayer );
  
  				TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_ENEMY_FLAG_TAKEN );
  			}
  		}
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_ATTACK_DEFEND )
  	{
  		// Handle messages to the screen.
  		TFTeamMgr()->PlayerCenterPrint( pPlayer, "#TF_AD_TakeFlagToPoint" );
  
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			if ( iTeam != pPlayer->GetTeamNumber() )
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_AD_ENEMY_STOLEN );
  			}
  			else
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_AD_TEAM_STOLEN );
  			}
  		}
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_INVADE )
  	{
  		// Handle messages to the screen.
  		TFTeamMgr()->PlayerCenterPrint( pPlayer, "#TF_Invade_PlayerPickup" );
  		TFTeamMgr()->PlayerTeamCenterPrint( pPlayer, "#TF_Invade_PlayerTeamPickup" );
  
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			if ( iTeam != pPlayer->GetTeamNumber() )
  			{
  				TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_Invade_OtherTeamPickup" );
  
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_INVADE_ENEMY_STOLEN );
  			}
  			else
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_INVADE_TEAM_STOLEN );
  			}
  		}
  
  		// set the flag's team to match the player's team
  		ChangeTeam( pPlayer->GetTeamNumber() );
  		m_nSkin = ( GetTeamNumber() == TEAM_UNASSIGNED ) ? 2 : (GetTeamNumber() - 2);
  	}
  
  	SetFlagStatus( TF_FLAGINFO_STOLEN );
  	ResetFlagReturnTime();
  	ResetFlagNeutralTime();
  
  	IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_flag_event" );
  	if ( event )
  	{
  		event->SetInt( "player", pPlayer->entindex() );
  		event->SetInt( "eventtype", TF_FLAGEVENT_PICKUP );
  		event->SetInt( "priority", 8 );
  		gameeventmanager->FireEvent( event );
  	}
  
  	pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_FLAGPICKUP );
  
  	// Output.
  	m_outputOnPickUp.FireOutput( this, this );
  
  	if ( m_hReturnIcon.Get() )
  	{
  		UTIL_Remove( m_hReturnIcon );
  		m_hReturnIcon = NULL;
  	}
  
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::Capture( CTFPlayer *pPlayer, int nCapturePoint )
  {
  	// Is the flag enabled?
  	if ( IsDisabled() )
  		return;
  
  #ifdef GAME_DLL
  
  	if ( m_nGameType == TF_FLAGTYPE_CTF )
  	{
  		bool bNotify = true;
  
  		// don't play any sounds if this is going to win the round for one of the teams (victory sound will be played instead)
  		if ( tf_flag_caps_per_round.GetInt() > 0 )
  		{
  			int nCaps = TFTeamMgr()->GetFlagCaptures( pPlayer->GetTeamNumber() );
  
  			if ( ( nCaps >= 0 ) && ( tf_flag_caps_per_round.GetInt() - nCaps <= 1 ) )
  			{
  				// this cap is going to win, so don't play a sound
  				bNotify = false;
  			}
  		}
  
  		if ( bNotify )
  		{
  			for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  			{
  				if ( iTeam != pPlayer->GetTeamNumber() )
  				{
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_CTF_ENEMY_CAPTURED );
  
  					TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_YOUR_FLAG_CAPTURED );
  				}
  				else
  				{
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_CTF_TEAM_CAPTURED );
  
  					TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_ENEMY_FLAG_CAPTURED );
  				}
  			}
  		}
  
  		// Reward the player
  		CTF_GameStats.Event_PlayerCapturedPoint( pPlayer );
  
  		// Reward the team
  		if ( tf_flag_caps_per_round.GetInt() > 0 )
  		{
  			TFTeamMgr()->IncrementFlagCaptures( pPlayer->GetTeamNumber() );
  		}
  		else
  		{
  			TFTeamMgr()->AddTeamScore( pPlayer->GetTeamNumber(), TF_CTF_CAPTURED_TEAM_FRAGS );
  		}
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_ATTACK_DEFEND )
  	{
  		char szNumber[64];
  		Q_snprintf( szNumber, sizeof(szNumber), "%d", nCapturePoint );
  
  		// Handle messages to the screen.
  		TFTeamMgr()->PlayerCenterPrint( pPlayer, "#TF_AD_YouSecuredPoint", szNumber );
  		TFTeamMgr()->PlayerTeamCenterPrint( pPlayer, "TF_AD_AttackersSecuredPoint", szNumber );
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			if ( iTeam != pPlayer->GetTeamNumber() )
  			{
  				TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_AD_AttackersSecuredPoint" );
  
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_AD_ENEMY_CAPTURED );
  			}
  			else
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_AD_TEAM_CAPTURED );
  			}
  		}
  
  		// Capture sound
  		CBroadcastRecipientFilter filter;
  		EmitSound( filter, entindex(), TF_AD_CAPTURED_SOUND );
  
  		// Reward the player
  		pPlayer->IncrementFragCount( TF_AD_CAPTURED_FRAGS );
  
  		// TFTODO:: Reward the team	
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_INVADE )
  	{
  		// Handle messages to the screen.
  		TFTeamMgr()->PlayerCenterPrint( pPlayer, "#TF_Invade_PlayerCapture" );
  		TFTeamMgr()->PlayerTeamCenterPrint( pPlayer, "#TF_Invade_PlayerTeamCapture" );
  
  		for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  		{
  			if ( iTeam != pPlayer->GetTeamNumber() )
  			{
  				TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_Invade_OtherTeamCapture" );
  
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_INVADE_ENEMY_CAPTURED );
  			}
  			else
  			{
  				CTeamRecipientFilter filter( iTeam, true );
  				EmitSound( filter, entindex(), TF_INVADE_TEAM_CAPTURED );
  			}
  		}
  
  		// Reward the player
  		pPlayer->IncrementFragCount( TF_INVADE_CAPTURED_FRAGS );
  
  		// Reward the team
  		TFTeamMgr()->AddTeamScore( pPlayer->GetTeamNumber(), TF_INVADE_CAPTURED_TEAM_FRAGS );
  	}
  
  	IGameEvent *event = gameeventmanager->CreateEvent( "teamplay_flag_event" );
  	if ( event )
  	{
  		event->SetInt( "player", pPlayer->entindex() );
  		event->SetInt( "eventtype", TF_FLAGEVENT_CAPTURE );
  		event->SetInt( "priority", 9 );
  		gameeventmanager->FireEvent( event );
  	}
  
  	SetFlagStatus( TF_FLAGINFO_NONE );
  	ResetFlagReturnTime();
  	ResetFlagNeutralTime();
  
  	// Reset the flag.
  	BaseClass::Drop( pPlayer, true );
  
  	Reset();
  
  	pPlayer->TeamFortress_SetSpeed();
  	pPlayer->SpeakConceptIfAllowed( MP_CONCEPT_FLAGCAPTURED );
  	
  	// Output.
  	m_outputOnCapture.FireOutput( this, this );
  
  	m_bCaptured = true;
  	SetNextThink( gpGlobals->curtime + TF_FLAG_THINK_TIME );
  
  	if ( TFGameRules()->InStalemate() )
  	{
  		// whoever capped the flag is the winner, give them enough caps to win
  		CTFTeam *pTeam = pPlayer->GetTFTeam();
  		if ( !pTeam )
  			return;
  
  		// if we still need more caps to trigger a win, give them to us
  		if ( pTeam->GetFlagCaptures() < tf_flag_caps_per_round.GetInt() )
  		{
  			pTeam->SetFlagCaptures( tf_flag_caps_per_round.GetInt() );
  		}	
  	}
  
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: A player drops the flag.
  //-----------------------------------------------------------------------------
  void CCaptureFlag::Drop( CTFPlayer *pPlayer, bool bVisible,  bool bThrown /*= false*/, bool bMessage /*= true*/ )
  {
  	// Is the flag enabled?
  	if ( IsDisabled() )
  		return;
  
  	// Call into the base class drop.
  	BaseClass::Drop( pPlayer, bVisible );
  
  	pPlayer->TeamFortress_SetSpeed();
  
  #ifdef GAME_DLL
  
  	if ( bThrown )
  	{
  		m_bAllowOwnerPickup = false;
  		m_flOwnerPickupTime = gpGlobals->curtime + TF_FLAG_OWNER_PICKUP_TIME;
  	}
  
  	Vector vecStart = GetAbsOrigin();
  	Vector vecEnd = vecStart;
  	vecEnd.z -= 8000.0f;
  	trace_t trace;
  	UTIL_TraceHull( vecStart, vecEnd, WorldAlignMins(), WorldAlignMaxs(), MASK_SOLID, this, COLLISION_GROUP_DEBRIS, &trace );
  	SetAbsOrigin( trace.endpos );
  
  	if ( m_nGameType == TF_FLAGTYPE_CTF )
  	{
  		if ( bMessage  )
  		{
  			for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  			{
  				if ( iTeam != pPlayer->GetTeamNumber() )
  				{
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_CTF_ENEMY_DROPPED );
  
  					TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_YOUR_FLAG_DROPPED );
  				}
  				else
  				{
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_CTF_TEAM_DROPPED );
  
  					TFGameRules()->SendHudNotification( filter, HUD_NOTIFY_ENEMY_FLAG_DROPPED );
  				}
  			}
  		}
  
  		SetFlagReturnIn( TF_CTF_RESET_TIME );
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_INVADE )
  	{
  		if ( bMessage  )
  		{
  			// Handle messages to the screen.
  			TFTeamMgr()->PlayerCenterPrint( pPlayer, "#TF_Invade_PlayerFlagDrop" );
  			TFTeamMgr()->PlayerTeamCenterPrint( pPlayer, "#TF_Invade_FlagDrop" );
  
  			for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  			{
  				if ( iTeam != pPlayer->GetTeamNumber() )
  				{
  					TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_Invade_FlagDrop" );
  
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_INVADE_ENEMY_DROPPED );
  				}
  				else
  				{
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_INVADE_TEAM_DROPPED );
  				}
  			}
  		}
  
  		SetFlagReturnIn( TF_INVADE_RESET_TIME );
  		SetFlagNeutralIn( TF_INVADE_NEUTRAL_TIME );
  	}
  	else if ( m_nGameType == TF_FLAGTYPE_ATTACK_DEFEND )
  	{
  		if ( bMessage  )
  		{
  			for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  			{
  				if ( iTeam != pPlayer->GetTeamNumber() )
  				{
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_AD_ENEMY_DROPPED );
  				}
  				else
  				{
  					CTeamRecipientFilter filter( iTeam, true );
  					EmitSound( filter, entindex(), TF_AD_TEAM_DROPPED );
  				}
  			}
  		}
  
  		SetFlagReturnIn( TF_AD_RESET_TIME );
  	}
  
  	// Reset the flag's angles.
  	SetAbsAngles( m_vecResetAng );
  
  	// Reset the touch function.
  	SetTouch( &CCaptureFlag::FlagTouch );
  
  	SetFlagStatus( TF_FLAGINFO_DROPPED );
  
  	// Output.
  	m_outputOnDrop.FireOutput( this, this );
  
  	m_hReturnIcon = CBaseEntity::Create( "item_teamflag_return_icon", GetAbsOrigin() + Vector(0,0,cl_flag_return_height.GetFloat()), vec3_angle, this );
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  bool CCaptureFlag::IsDropped( void )
  { 
  	return ( m_nFlagStatus == TF_FLAGINFO_DROPPED ); 
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  bool CCaptureFlag::IsHome( void )
  { 
  	return ( m_nFlagStatus == TF_FLAGINFO_NONE ); 
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  bool CCaptureFlag::IsStolen( void )
  { 
  	return ( m_nFlagStatus == TF_FLAGINFO_STOLEN ); 
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  bool CCaptureFlag::IsDisabled( void )
  {
  	return m_bDisabled;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::SetDisabled( bool bDisabled )
  {
  	m_bDisabled = bDisabled;
  
  	if ( bDisabled )
  	{
  		AddEffects( EF_NODRAW );
  
  		SetTouch( NULL );
  		SetThink( NULL );
  	}
  	else
  	{
  		RemoveEffects( EF_NODRAW );
  
  		SetTouch( &CCaptureFlag::FlagTouch );
  		SetThink( &CCaptureFlag::Think );
  		SetNextThink( gpGlobals->curtime );
  	}
  }
  
  //-----------------------------------------------------------------------------------------------
  // GAME DLL Functions
  //-----------------------------------------------------------------------------------------------
  #ifdef GAME_DLL
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::Think( void )
  {
  	// Is the flag enabled?
  	if ( IsDisabled() )
  		return;
  
  	if ( !TFGameRules()->FlagsMayBeCapped() )
  	{
  		SetNextThink( gpGlobals->curtime + TF_FLAG_THINK_TIME );
  		return;
  	}
  
  	if ( m_bCaptured )
  	{
  		m_bCaptured = false;
  		SetTouch( &CCaptureFlag::FlagTouch );
  	}
  
  	if ( IsDropped() )
  	{
  		if ( !m_bAllowOwnerPickup )
  		{
  			if ( m_flOwnerPickupTime && gpGlobals->curtime > m_flOwnerPickupTime )
  			{
  				m_bAllowOwnerPickup = true;
  			}
  		}
  
  		if ( m_nGameType == TF_FLAGTYPE_INVADE )
  		{
  			if ( m_flResetTime && gpGlobals->curtime > m_flResetTime )
  			{
  				Reset();
  				ResetMessage();
  			}
  			else if ( m_flNeutralTime && gpGlobals->curtime > m_flNeutralTime )
  			{
  				for ( int iTeam = TF_TEAM_RED; iTeam < TF_TEAM_COUNT; ++iTeam )
  				{
  					TFTeamMgr()->TeamCenterPrint( iTeam, "#TF_Invade_FlagNeutral" );
  				}
  
  				// reset the team to the original team setting (when it spawned)
  				ChangeTeam( m_iOriginalTeam );
  				m_nSkin = ( GetTeamNumber() == TEAM_UNASSIGNED ) ? 2 : (GetTeamNumber() - 2);
  
  				ResetFlagNeutralTime();
  			}
  		}
  		else
  		{
  			if ( m_flResetTime && gpGlobals->curtime > m_flResetTime )
  			{
  				Reset();
  				ResetMessage();
  			}
  		}
  	}
  
  	SetNextThink( gpGlobals->curtime + TF_FLAG_THINK_TIME );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Sets the flag status
  //-----------------------------------------------------------------------------
  void CCaptureFlag::SetFlagStatus( int iStatus )
  { 
  	MDLCACHE_CRITICAL_SECTION();
  
  	m_nFlagStatus = iStatus; 
  
  	switch ( m_nFlagStatus )
  	{
  	case TF_FLAGINFO_NONE:
  	case TF_FLAGINFO_DROPPED:
  		ResetSequence( LookupSequence("spin") );	// set spin animation if it's not being held
  		break;
  	case TF_FLAGINFO_STOLEN:
  		ResetSequence( LookupSequence("idle") );	// set idle animation if it is being held
  		break;
  	default:
  		AssertOnce( false );	// invalid stats
  		break;
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::InputEnable( inputdata_t &inputdata )
  {
  	SetDisabled( false );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose:
  //-----------------------------------------------------------------------------
  void CCaptureFlag::InputDisable( inputdata_t &inputdata )
  {
  	SetDisabled( true );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  void CCaptureFlag::InputRoundActivate( inputdata_t &inputdata )
  {
  	CTFPlayer *pPlayer = ToTFPlayer( m_hPrevOwner.Get() );
  
  	// If the player has a capture flag, drop it.
  	if ( pPlayer && pPlayer->HasItem() && ( pPlayer->GetItem() == this ) )
  	{
  		Drop( pPlayer, true, false, false );
  	}
  
  	Reset();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Always transmitted to clients
  //-----------------------------------------------------------------------------
  int CCaptureFlag::UpdateTransmitState()
  {
  	// ALWAYS transmit to all clients.
  	return SetTransmitState( FL_EDICT_ALWAYS );
  }
  
  
  #else
  
  float CCaptureFlag::GetReturnProgress()
  {
  	float flEventTime = max( m_flResetTime.m_Value, m_flNeutralTime.m_Value );
  
  	return ( 1.0 - ( ( flEventTime - gpGlobals->curtime ) / m_flMaxResetTime ) );
  }
  
  
  void CCaptureFlag::Simulate( void )
  {
  	BaseClass::Simulate();
  
  	ManageTrailEffects();
  	EnableGlowEffect();
  }
  
  void CCaptureFlag::ManageTrailEffects( void )
  {
  	if ( m_nFlagStatus == TF_FLAGINFO_STOLEN )
  	{
  		if ( m_pGlowTrailEffect == NULL )
  		{
  			char *pEffectName = NULL;
  
  			if ( GetPrevOwner() && GetPrevOwner() != CBasePlayer::GetLocalPlayer() )
  			{
  				switch( GetPrevOwner()->GetTeamNumber() )
  				{
  				case TF_TEAM_BLUE:
  					pEffectName = "player_intel_trail_blue";
  					break;
  				case TF_TEAM_RED:
  					pEffectName = "player_intel_trail_red";
  					break;
  				default:
  					pEffectName = "player_intel_trail_blue";
  					break;
  				}
  
  
  
  				m_pGlowTrailEffect = ParticleProp()->Create( pEffectName, PATTACH_ABSORIGIN_FOLLOW );
  			}
  		}
  
  		if ( GetPrevOwner() )
  		{
  			CTFPlayer *pPlayer = ToTFPlayer( GetPrevOwner() );
  
  			if ( pPlayer )
  			{
  				if ( pPlayer->GetAbsVelocity().Length() >= pPlayer->MaxSpeed() * 0.5f )
  				{
  					if ( m_pPaperTrailEffect == NULL )
  					{
  						m_pPaperTrailEffect = ParticleProp()->Create( "player_intel_papertrail", PATTACH_ABSORIGIN_FOLLOW );
  					}
  				}
  				else
  				{
  					if ( m_pPaperTrailEffect )
  					{
  						ParticleProp()->StopEmission( m_pPaperTrailEffect );
  						m_pPaperTrailEffect = NULL;
  					}
  				}
  			}
  		}
  
  	}
  	else
  	{
  		if ( m_pGlowTrailEffect )
  		{
  			ParticleProp()->StopEmission( m_pGlowTrailEffect );
  			m_pGlowTrailEffect = NULL;
  		}
  
  		if ( m_pPaperTrailEffect )
  		{
  			ParticleProp()->StopEmission( m_pPaperTrailEffect );
  			m_pPaperTrailEffect = NULL;
  		}
  	}
  }
  
  
  #endif
  
  
  LINK_ENTITY_TO_CLASS( item_teamflag_return_icon, CCaptureFlagReturnIcon );
  
  IMPLEMENT_NETWORKCLASS_ALIASED( CaptureFlagReturnIcon, DT_CaptureFlagReturnIcon )
  
  BEGIN_NETWORK_TABLE( CCaptureFlagReturnIcon, DT_CaptureFlagReturnIcon )
  END_NETWORK_TABLE()
  
  CCaptureFlagReturnIcon::CCaptureFlagReturnIcon()
  {
  #ifdef CLIENT_DLL
  	m_pReturnProgressMaterial_Empty = NULL;
  	m_pReturnProgressMaterial_Full = NULL;
  #endif
  }
  
  #ifdef GAME_DLL
  
  void CCaptureFlagReturnIcon::Spawn( void )
  {
  	BaseClass::Spawn();
  
  	UTIL_SetSize( this, Vector(-8,-8,-8), Vector(8,8,8) );
  
  	CollisionProp()->SetCollisionBounds( Vector( -50, -50, -50 ), Vector( 50, 50, 50 ) );
  }
  
  int CCaptureFlagReturnIcon::UpdateTransmitState( void )
  {
  	return SetTransmitState( FL_EDICT_PVSCHECK );
  }
  #endif
  
  #ifdef CLIENT_DLL
  
  typedef struct
  {
  	float maxProgress;
  
  	float vert1x;
  	float vert1y;
  	float vert2x;
  	float vert2y;
  
  	int swipe_dir_x;
  	int swipe_dir_y;
  } progress_segment_t;
  
  
  // This defines the properties of the 8 circle segments
  // in the circular progress bar.
  progress_segment_t Segments[8] = 
  {
  	{ 0.125, 0.5, 0.0, 1.0, 0.0, 1, 0 },
  	{ 0.25,	 1.0, 0.0, 1.0, 0.5, 0, 1 },
  	{ 0.375, 1.0, 0.5, 1.0, 1.0, 0, 1 },
  	{ 0.50,	 1.0, 1.0, 0.5, 1.0, -1, 0 },
  	{ 0.625, 0.5, 1.0, 0.0, 1.0, -1, 0 },
  	{ 0.75,	 0.0, 1.0, 0.0, 0.5, 0, -1 },
  	{ 0.875, 0.0, 0.5, 0.0, 0.0, 0, -1 },
  	{ 1.0,	 0.0, 0.0, 0.5, 0.0, 1, 0 },
  };
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  RenderGroup_t CCaptureFlagReturnIcon::GetRenderGroup( void ) 
  {	
  	return RENDER_GROUP_TRANSLUCENT_ENTITY;	
  }
  
  void CCaptureFlagReturnIcon::GetRenderBounds( Vector& theMins, Vector& theMaxs )
  {
  	theMins.Init( -20, -20, -20 );
  	theMaxs.Init(  20,  20,  20 );
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  int CCaptureFlagReturnIcon::DrawModel( int flags )
  {
  	int nRetVal = BaseClass::DrawModel( flags );
  	
  	DrawReturnProgressBar();
  
  	return nRetVal;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Draw progress bar above the flag indicating when it will return
  //-----------------------------------------------------------------------------
  void CCaptureFlagReturnIcon::DrawReturnProgressBar( void )
  {
  	CCaptureFlag *pFlag = dynamic_cast< CCaptureFlag * > ( GetOwnerEntity() );
  
  	if ( !pFlag )
  		return;
  
  	// Don't draw if this flag is not going to reset
  	if ( pFlag->GetMaxResetTime() <= 0 )
  		return;
  
  	if ( !TFGameRules()->FlagsMayBeCapped() )
  		return;
  
  	if ( !m_pReturnProgressMaterial_Full )
  	{
  		m_pReturnProgressMaterial_Full = materials->FindMaterial( "VGUI/flagtime_full", TEXTURE_GROUP_VGUI );
  	}
  
  	if ( !m_pReturnProgressMaterial_Empty )
  	{
  		m_pReturnProgressMaterial_Empty = materials->FindMaterial( "VGUI/flagtime_empty", TEXTURE_GROUP_VGUI );
  	}
  
  	if ( !m_pReturnProgressMaterial_Full || !m_pReturnProgressMaterial_Empty )
  	{
  		return;
  	}
  
  	CMatRenderContextPtr pRenderContext( materials );
  
  	Vector vOrigin = GetAbsOrigin();
  	QAngle vAngle = vec3_angle;
  
  	// Align it towards the viewer
  	Vector vUp = CurrentViewUp();
  	Vector vRight = CurrentViewRight();
  	if ( fabs( vRight.z ) > 0.95 )	// don't draw it edge-on
  		return;
  
  	vRight.z = 0;
  	VectorNormalize( vRight );
  
  	float flSize = cl_flag_return_size.GetFloat();
  
  	unsigned char ubColor[4];
  	ubColor[3] = 255;
  
  	switch( pFlag->GetTeamNumber() )
  	{
  	case TF_TEAM_RED:
  		ubColor[0] = 255;
  		ubColor[1] = 0;
  		ubColor[2] = 0;
  		break;
  	case TF_TEAM_BLUE:
  		ubColor[0] = 0;
  		ubColor[1] = 0;
  		ubColor[2] = 255;
  		break;
  	default:
  		ubColor[0] = 100;
  		ubColor[1] = 100;
  		ubColor[2] = 100;
  		break;
  	}
  
  	// First we draw a quad of a complete icon, background
  	CMeshBuilder meshBuilder;
  
  	pRenderContext->Bind( m_pReturnProgressMaterial_Empty );
  	IMesh *pMesh = pRenderContext->GetDynamicMesh();
  
  	meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  
  	meshBuilder.Color4ubv( ubColor );
  	meshBuilder.TexCoord2f( 0,0,0 );
  	meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * flSize)).Base() );
  	meshBuilder.AdvanceVertex();
  
  	meshBuilder.Color4ubv( ubColor );
  	meshBuilder.TexCoord2f( 0,1,0 );
  	meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * flSize)).Base() );
  	meshBuilder.AdvanceVertex();
  
  	meshBuilder.Color4ubv( ubColor );
  	meshBuilder.TexCoord2f( 0,1,1 );
  	meshBuilder.Position3fv( (vOrigin + (vRight * flSize) + (vUp * -flSize)).Base() );
  	meshBuilder.AdvanceVertex();
  
  	meshBuilder.Color4ubv( ubColor );
  	meshBuilder.TexCoord2f( 0,0,1 );
  	meshBuilder.Position3fv( (vOrigin + (vRight * -flSize) + (vUp * -flSize)).Base() );
  	meshBuilder.AdvanceVertex();
  
  	meshBuilder.End();
  
  	pMesh->Draw();
  
  	float flProgress = pFlag->GetReturnProgress();
  
  	pRenderContext->Bind( m_pReturnProgressMaterial_Full );
  	pMesh = pRenderContext->GetDynamicMesh();
  
  	vRight *= flSize * 2;
  	vUp *= flSize * -2;
  
  	// Next we're drawing the circular progress bar, in 8 segments
  	// For each segment, we calculate the vertex position that will draw
  	// the slice.
  	int i;
  	for ( i=0;i<8;i++ )
  	{
  		if ( flProgress < Segments[i].maxProgress )
  		{
  			CMeshBuilder meshBuilder_Full;
  
  			meshBuilder_Full.Begin( pMesh, MATERIAL_TRIANGLES, 3 );
  
  			// vert 0 is ( 0.5, 0.5 )
  			meshBuilder_Full.Color4ubv( ubColor );
  			meshBuilder_Full.TexCoord2f( 0, 0.5, 0.5 );
  			meshBuilder_Full.Position3fv( vOrigin.Base() );
  			meshBuilder_Full.AdvanceVertex();
  
  			// Internal progress is the progress through this particular slice
  			float internalProgress = RemapVal( flProgress, Segments[i].maxProgress - 0.125, Segments[i].maxProgress, 0.0, 1.0 );
  			internalProgress = clamp( internalProgress, 0.0, 1.0 );
  
  			// Calculate the x,y of the moving vertex based on internal progress
  			float swipe_x = Segments[i].vert2x - ( 1.0 - internalProgress ) * 0.5 * Segments[i].swipe_dir_x;
  			float swipe_y = Segments[i].vert2y - ( 1.0 - internalProgress ) * 0.5 * Segments[i].swipe_dir_y;
  
  			// vert 1 is calculated from progress
  			meshBuilder_Full.Color4ubv( ubColor );
  			meshBuilder_Full.TexCoord2f( 0, swipe_x, swipe_y );
  			meshBuilder_Full.Position3fv( (vOrigin + (vRight * ( swipe_x - 0.5 ) ) + (vUp *( swipe_y - 0.5 ) ) ).Base() );
  			meshBuilder_Full.AdvanceVertex();
  
  			// vert 2 is ( Segments[i].vert1x, Segments[i].vert1y )
  			meshBuilder_Full.Color4ubv( ubColor );
  			meshBuilder_Full.TexCoord2f( 0, Segments[i].vert2x, Segments[i].vert2y );
  			meshBuilder_Full.Position3fv( (vOrigin + (vRight * ( Segments[i].vert2x - 0.5 ) ) + (vUp *( Segments[i].vert2y - 0.5 ) ) ).Base() );
  			meshBuilder_Full.AdvanceVertex();
  
  			meshBuilder_Full.End();
  
  			pMesh->Draw();
  		}
  	}
  }
  
  #endif
  