// ========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
// 
// Purpose:
// 
// =============================================================================//
#include "cbase.h"
#include "hudelement.h"
#include "mapoverview.h"
#include "hudelement.h"
#include "hud_macros.h"
#include <filesystem.h>
#include "cs_gamerules.h"
#include "c_team.h"
#include "c_cs_playerresource.h"
#include "c_plantedc4.h"
#include "c_cs_hostage.h"
#include "vtf/vtf.h"
#include "clientmode.h"
#include "voice_status.h"
#include "vgui/ILocalize.h"
#include <vstdlib/vstrtools.h>
#include "view.h"
#include "gameui_util.h"
#include "HUD/sfhudfreezepanel.h"
#include "HUD/sfhudwinpanel.h"
#include "HUD/sfhud_teamcounter.h"
#include "c_plantedc4.h"
#include "c_world.h"
#include "gametypes.h"
#include "hltvreplaysystem.h"
#include "clientmode_shared.h"

//memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

static const float NOTSPOTTEDRADIUS = 1400.0f;
static const float DEAD_FADE_TIME = 4.0f;
static const float GHOST_FADE_TIME = 6.0f;
static const float BOMB_FADE_TIME = 8.0f;
static const float DEFUSER_FADE_TIME = 8.0f;
static const float TIMER_INIT = -1000.0f;
static const int   INVALID_INDEX = -1;

ConVar mapoverview_allow_client_draw( "mapoverview_allow_client_draw", "0", FCVAR_RELEASE, "Allow a client to draw on the map overview" );
ConVar mapoverview_allow_grid_usage( "mapoverview_allow_grid_usage", "0", FCVAR_RELEASE, "When set to 1, allows turning on the (experimental) grid for drawing." );
ConVar mapoverview_icon_scale( "mapoverview_icon_scale", "1.0", FCVAR_RELEASE | FCVAR_ARCHIVE, "Sets the icon scale multiplier for the overview map. Valid values are 0.5 to 3.0.", true, 0.5f, true, 3.0f );

/*******************************************************************************
 * data definitions
 */

static const char* playerIconNames[] = {
	"Greande_HE",
	"Greande_FLASH",
	"Greande_SMOKE",
	"Greande_MOLOTOV",
	"Greande_DECOY",

	"Defuser",
	"AbovePlayer",
	"BelowPlayer",
	"Flashed",
	"PlayerNumber",
	"PlayerNameCT",
	"PlayerNameT",
	// below this, the icons are rotated
	"PlayerIndicator",
	"SpeakingOnMap",
	"HostageTransitOnMap",
	"CTOnMap",
	"CTDeath",
	"CTGhost",
	"TOnMap",
	"TDeath",
	"TGhost",
	"EnemyOnMap",
	"EnemyDeath",
	"EnemyGhost",
	"HostageOnMap",
	"HostageDeath",
	"HostageGhost",
	"DirectionalIndicator",
	"MuzzleFlash",
	"LowHealth",
	"Selected",
	NULL
};

static const char* hostageIconNames[] = {
	"HostageDead",
	"HostageRescued",
	"HostageAlive",
	"HostageTransit",
	NULL
};

static const char* overviewIconNames[] = {
	"BombPlantedIcon",
	"BombPlantedIconMedium",
	"BombPlantedIconFast",
	"HostageZoneIcon",
	NULL
};

static const char *desiredMessageNames[] = {
	"game_newmap",
	"round_start",
	"player_connect",
	"player_info",
	"player_team",
	"player_spawn",
	"player_death",
	"player_disconnect",
	"hostage_killed",
	"hostage_rescued",
	"bomb_defused",
	"bomb_exploded",
	"bomb_planted",
	"bomb_pickup",
	"bomb_dropped",
	"defuser_pickup",
	"defuser_dropped",
	"decoy_started",
	"decoy_detonate",
	"hegrenade_detonate",
	"flashbang_detonate",
	"smokegrenade_detonate",
	"smokegrenade_expired",
	"inferno_startburn",
	"inferno_expire",
	"bot_takeover",
	NULL
};

enum DESIRED_MESSAGE_INDICES
{
	GAME_NEWMAP,
	ROUND_POST_START,
	PLAYER_CONNECT,
	PLAYER_INFO,
	PLAYER_TEAM,
	PLAYER_SPAWN,
	PLAYER_DEATH,
	PLAYER_DISCONNECT,
	HOSTAGE_KILLED,
	HOSTAGE_RESCUED,
	BOMB_DEFUSED,
	BOMB_EXPLODED,
	BOMB_PLANTED,
	BOMB_PICKUP,
	BOMB_DROPPED,
	DEFUSER_PICKUP,
	DEFUSER_DROPPED,
	DECOY_STARTED,
	DECOY_DETONATE,
	HE_DETONATE,
	FLASH_DETONATE,
	SMOKE_DETONATE,
	SMOKE_EXPIRE,
	MOLOTOV_DETONATE,
	MOLOTOV_EXPIRE,
	BOT_TAKEOVER,

};

/***************************************************
 * callback and function declarations
 */

static bool maplessfunc( const char* const & s1, const char* const & s2 )
{
	return V_strcmp( s1, s2 ) < 0;
}

CUtlMap<const char*, int> SFMapOverview::m_messageMap( maplessfunc );

DECLARE_HUDELEMENT( SFMapOverview );
DECLARE_HUD_MESSAGE( SFMapOverview, ProcessSpottedEntityUpdate );

SFUI_BEGIN_GAME_API_DEF
	SFUI_DECL_METHOD( MapLoaded ),
	SFUI_DECL_METHOD( ToggleOverviewMap ),
	SFUI_DECL_METHOD( AllowMapDrawing ),
	SFUI_DECL_METHOD( GetWorldDistance ),
	//SFUI_DECL_METHOD( GetNavPath ),
SFUI_END_GAME_API_DEF( SFMapOverview, MapOverview );

CON_COMMAND( drawoverviewmap, "Draws the overview map" )
{
	( GET_HUDELEMENT( SFMapOverview ) )->ShowMapOverview( true );
}

CON_COMMAND( hideoverviewmap, "Hides the overview map" )
{
	( GET_HUDELEMENT( SFMapOverview ) )->ShowMapOverview( false );
}



/**********************************************************************
 * SFMapOverviewIconPackage code
 */

SFMapOverview::SFMapOverviewIconPackage::SFMapOverviewIconPackage()
{
	ClearAll();
}

SFMapOverview::SFMapOverviewIconPackage::~SFMapOverviewIconPackage()
{
}

void SFMapOverview::SFMapOverviewIconPackage::ClearAll( void )
{
	m_IconPackage = NULL;
	m_IconPackageRotate = NULL;
	V_memset( m_Icons, 0, sizeof( m_Icons ) );

	m_pScaleformUI = NULL;

	m_iCurrentVisibilityFlags = 0;
	m_fCurrentAlpha = 1.0f;

	m_Health = 0;
	m_iPlayerType = 0;
	m_iIndex = INVALID_INDEX;
	m_iEntityID = 0;

	m_bIsActive = false;
	m_bOffMap = true;

	m_bIsLowHealth = false;
	m_bIsSelected = false;
	m_bIsFlashed = false;
	m_bIsFiring = false;

	m_bIsSpotted = false;
	m_fGhostTime = TIMER_INIT;

	m_bIsDead = false;
	m_fDeadTime = TIMER_INIT;
	m_fGrenExpireTime = TIMER_INIT;

	m_IconPackType = ICON_PACK_PLAYER;
	m_bIsRescued = false;

	m_bIsOnLocalTeam = false;

	m_fRoundStartTime = TIMER_INIT;

	m_wcName[0] = 0;

	m_Position = vec3_origin;
	m_Angle.Init();

	m_nGrenadeType = -1;

	m_bIsDefuser = false;
}

void SFMapOverview::SFMapOverviewIconPackage::Init( IScaleformUI* pui, SFVALUE iconPackage )
{
	m_pScaleformUI = pui;
	m_IconPackage = pui->CreateValue( iconPackage );
	m_IconPackageRotate = m_pScaleformUI->Value_GetMember( iconPackage, "RotatedLayer" );

	for ( uint64 i = 0; i < PI_NUM_ICONS && playerIconNames[i] != NULL; i++ )
	{
		if ( i < PI_FIRST_ROTATED )
		{
			m_Icons[i] = pui->Value_GetMember( m_IconPackage, playerIconNames[i] );
		}
		else
		{
			if ( m_IconPackageRotate )
			{
				m_Icons[i] = pui->Value_GetMember( m_IconPackageRotate, playerIconNames[i] );
			}
		}

		if ( m_Icons[i] )
		{
			pui->Value_SetVisible( m_Icons[i], ( m_iCurrentVisibilityFlags & ( 1ll << i ) ) != 0 );
		}
	}

	ScaleformDisplayInfo displayInfo;
	displayInfo.SetAlpha( m_fCurrentAlpha * 100.0f );
	displayInfo.SetVisibility( m_iCurrentVisibilityFlags != 0 );
	m_pScaleformUI->Value_SetDisplayInfo( m_IconPackage, &displayInfo );
}


void SFMapOverview::SFMapOverviewIconPackage::NukeFromOrbit( SFMapOverview* pSFUI )
{
	if ( pSFUI->FlashAPIIsValid() )
	{
		pSFUI->SafeReleaseSFVALUE( m_IconPackage );
		pSFUI->SafeReleaseSFVALUE( m_IconPackageRotate );
		
		for ( uint64 i = 0; i < PI_NUM_ICONS; i++ )
		{
			pSFUI->SafeReleaseSFVALUE( m_Icons[i] );
		}
	}

	ClearAll();
}

void SFMapOverview::SFMapOverviewIconPackage::StartRound( void )
{
	m_Health = 100;

	m_bOffMap = false;
	m_bIsLowHealth = false;
	m_bIsSelected = false;
	m_bIsFlashed = false;
	m_bIsFiring = false;
	m_bIsSpotted = false;
	m_fGhostTime = TIMER_INIT;

	m_bIsDead = false;
	m_fDeadTime = TIMER_INIT;
	m_fGrenExpireTime = TIMER_INIT;

	m_bIsRescued = false;

	m_nAboveOrBelow = R_SAMELEVEL;

	m_fRoundStartTime = gpGlobals->curtime;

	m_nGrenadeType = -1;

	m_Position = vec3_origin;
	m_Angle.Init();

	SetAlpha( 0 );
	SetVisibilityFlags( 0 );
}

bool SFMapOverview::SFMapOverviewIconPackage::IsVisible( void )
{
	return ( m_fCurrentAlpha != 0 && m_iCurrentVisibilityFlags != 0 );
}


void SFMapOverview::SFMapOverviewIconPackage::SetIsPlayer( bool value )
{
	m_bIsPlayer = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsSpeaking ( bool value )
{
	m_bIsSpeaking = value && m_bIsOnLocalTeam;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsOffMap( bool value )
{
	m_bOffMap = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsLowHealth( bool value )
{
	m_bIsLowHealth = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsSelected( bool value )
{
	m_bIsSelected = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsFlashed( bool value )
{
	m_bIsFlashed = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsFiring( bool value )
{
	m_bIsFiring = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsAboveOrBelow( int value )
{
	m_nAboveOrBelow = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsMovingHostage( bool value )
{
	m_bIsMovingHostage = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsRescued( bool value )
{
	m_bIsRescued = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsOnLocalTeam( bool value )
{
	m_bIsOnLocalTeam = value;
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsControlledBot( void )
{
	m_bIsDead = true;
	m_bIsSpotted = true;
	m_fDeadTime = TIMER_INIT;
	m_fGhostTime = TIMER_INIT;
}


void SFMapOverview::SFMapOverviewIconPackage::SetIsDead( bool value )
{
	if ( value != m_bIsDead )
	{
		if ( value )
		{
// 			SetIsSpotted( true );
			m_fDeadTime = gpGlobals->curtime;
		}
		else
		{
			m_fDeadTime = TIMER_INIT;
		}

		m_bIsDead = value;
	}

}

void SFMapOverview::SFMapOverviewIconPackage::SetGrenadeExpireTime( float value )
{
	if ( value )
	{
		m_fGrenExpireTime = value;
	}
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsSpotted( bool value )
{
	if ( gpGlobals->curtime - m_fRoundStartTime > 0.25f )
	{
		if ( value != m_bIsSpotted )
		{
			if ( !value )
			{
				m_fGhostTime = gpGlobals->curtime;
			}
			else
			{
				m_fGhostTime = TIMER_INIT;
			}

			m_bIsSpotted = value;
		}
	}
}

void SFMapOverview::SFMapOverviewIconPackage::SetPlayerTeam( int team )
{
	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
	if( pLocalPlayer == NULL )
	{
		return;
	}

	int newType;

	switch( team )
	{
		case TEAM_UNASSIGNED:
			newType = PI_HOSTAGE;
			break;

		case TEAM_TERRORIST:
			newType = pLocalPlayer->GetAssociatedTeamNumber() == TEAM_TERRORIST || pLocalPlayer->IsObserver() ? PI_T : PI_ENEMY;
			break;

		case TEAM_CT:
			newType =pLocalPlayer->GetAssociatedTeamNumber() == TEAM_CT || pLocalPlayer->IsObserver() ? PI_CT : PI_ENEMY;
			break;

		case TEAM_SPECTATOR:
		default:
			newType = 0;
			break;
	}

	if ( m_iPlayerType != newType )
	{
		m_iPlayerType = newType;
		SetVisibilityFlags( 0 );
	}

}


void SFMapOverview::SFMapOverviewIconPackage::SetupIconsFromStates( void )
{
	uint64 flags = 0;
	float alpha = 1;

	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
	if( pLocalPlayer == NULL )
		return;

	bool bShowAll = false;
	if ( pLocalPlayer->IsSpectator() || g_bEngineIsHLTV )
		bShowAll = true;

	if ( m_iPlayerType != 0 )
	{
		flags = 1ll << m_iPlayerType;

		if ( m_bIsDead )
		{
			if ( m_Position.x == 0 && m_Position.y == 0 || !m_bIsSpotted )
			{
				flags = 0;
			}
			else
			{
				float deadElapsedTime = gpGlobals->curtime - m_fDeadTime;
				if ( deadElapsedTime > DEAD_FADE_TIME )
				{
					m_fDeadTime = TIMER_INIT;
					flags = 0;
				}
				else
				{
					alpha = clamp( 1.0f - deadElapsedTime / DEAD_FADE_TIME, 0.0f, 1.0f );

					// the shift below changes the icon to be the dead icon ( the X )
					// rescued hostages are marked as dead, but we don't want to show
					// the X in that case.  So if this guy is a hostage and has been resuced
					// we want to skip the code that changes the icon to the dead icon.

					bool isRescuedNotDead = IsHostageType() && m_bIsRescued;

					if ( !isRescuedNotDead )
					{
						flags <<= 1;
					}
				}
			}
		}
		else if ( !m_bIsSpotted )
		{
			float ghostElapsedTime = gpGlobals->curtime - m_fGhostTime;
			if ( ghostElapsedTime > GHOST_FADE_TIME )
			{
				m_fGhostTime = TIMER_INIT;
				flags = 0;
			}
			else
			{
				alpha = clamp( 1.0f - ghostElapsedTime / GHOST_FADE_TIME, 0.0f, 1.0f );
				// shifting to show the "ghost" icon
				flags <<= 2;
			}
		}
		else
		{
			if ( m_bIsMovingHostage )
			{
				flags |= 1 << PI_HOSTAGE_MOVING;
			}

			if ( m_bIsSpeaking )
			{
				flags |= 1 << PI_SPEAKING;
			}
			
			if ( m_bIsLowHealth )
			{
				flags |= 1 << PI_LOWHEALTH;
			}

			if ( m_bIsSelected )
			{
				flags |= 1 << PI_SELECTED;
			}

			if ( m_bIsFlashed )
			{
				flags |= 1 << PI_FLASHED;
			}

			if ( m_bIsFiring )
			{
				flags |= 1 << PI_MUZZLE_FLASH;
			}	

			bool bSameTeamOrSpec = false;
			if ( m_iPlayerType == PI_CT && (pLocalPlayer->GetAssociatedTeamNumber() == TEAM_CT || bShowAll) )
			{
				flags |= 1 << PI_PLAYER_NAME_CT;
				bSameTeamOrSpec = true;
			}

			if ( m_iPlayerType == PI_T && (pLocalPlayer->GetAssociatedTeamNumber() == TEAM_TERRORIST || bShowAll) )
			{
				flags |= 1 << PI_PLAYER_NAME_T;
				bSameTeamOrSpec = true;
			}

			if ( bSameTeamOrSpec )
				flags |= 1 << PI_PLAYER_NUMBER;
			
			
			flags |= 1 << PI_DIRECTION_INDICATOR;		

			if ( m_bIsPlayer )
			{
				flags |= 1 << PI_PLAYER_INDICATOR;
			}

			if ( m_fGrenExpireTime != TIMER_INIT )
			{
				if ( m_fGrenExpireTime < gpGlobals->curtime )
				{
					m_fGrenExpireTime = TIMER_INIT;
					m_bIsSpotted = false;
				}
			}
		}
	}
	else if ( m_bIsDefuser )
	{
		// only render after we have received a position update
		if ( m_Position != vec3_origin )
		{
			flags |= 1 << PI_DEFUSER;

			if ( m_bIsSpotted ) 
			{
				m_fGhostTime = TIMER_INIT;
				alpha = 1.0f;
			}
			else
			{
				float ghostElapsedTime = gpGlobals->curtime - m_fGhostTime;
				if ( ghostElapsedTime > GHOST_FADE_TIME )
				{
					m_fGhostTime = TIMER_INIT;
					flags = 0;
				}
				else
				{
					alpha = clamp( 1.0f - ghostElapsedTime / GHOST_FADE_TIME, 0.0f, 1.0f );
				}
			}
		}
	}
	else if ( m_nGrenadeType > -1 )
	{
		flags = 1ll << m_nGrenadeType;

		float flFadeTime = 1.0f;

		float deadElapsedTime = (m_fGrenExpireTime <= 0 ) ? 0 : gpGlobals->curtime - m_fGrenExpireTime;
		if ( deadElapsedTime > flFadeTime )
		{
			m_fGrenExpireTime = TIMER_INIT;
			flags = 0;
		}
		else
		{
			alpha = clamp( 1.0f - deadElapsedTime / flFadeTime, 0.0f, 1.0f );
		}
	}

	//GetPlayerSlotIndex( m_iEntityID/*engine->GetPlayerForUserID( m_iEntityID )*/ );

	SetAlpha( alpha );
	SetVisibilityFlags( flags );
}


void SFMapOverview::SFMapOverviewIconPackage::SetVisibilityFlags( uint64 newFlags )
{
	newFlags &= ( ( 1ll << PI_NUM_ICONS )-1 );

	uint64 diffFlags = m_iCurrentVisibilityFlags ^ newFlags;

	if ( diffFlags )
	{
		if ( m_IconPackage )
		{
			bool wantVisible = ( newFlags != 0 );
			if ( ( m_iCurrentVisibilityFlags != 0 ) != wantVisible )
			{
				m_pScaleformUI->Value_SetVisible( m_IconPackage, wantVisible );
			}

			for ( uint64 i = 0; i < PI_NUM_ICONS && ( diffFlags != 0 ); i++, diffFlags >>= 1 )
			{
				if ( (diffFlags & 1) && ( m_Icons[i] ) )
				{
					Assert( m_Icons[i] );
					if ( m_Icons[i] )
					{
						m_pScaleformUI->Value_SetVisible( m_Icons[i], ( newFlags & ( 1ll << i ) ) != 0 );
					}
				}
			}
		}

		m_iCurrentVisibilityFlags = newFlags;
	}
}
 
void SFMapOverview::SFMapOverviewIconPackage::SetAlpha( float newAlpha )
{
	if ( newAlpha != m_fCurrentAlpha )
	{
		m_fCurrentAlpha = newAlpha;

		if ( m_IconPackage )
		{
			ScaleformDisplayInfo displayInfo;
			displayInfo.SetAlpha( m_fCurrentAlpha * 100.0f );
			m_pScaleformUI->Value_SetDisplayInfo( m_IconPackage, &displayInfo );
		}
	}
}

void SFMapOverview::SFMapOverviewIconPackage::SetIsDefuse( bool bValue )
{
	m_bIsDefuser = bValue;
}

void SFMapOverview::SFMapOverviewIconPackage::SetGrenadeType( int nValue )
{
	m_nGrenadeType = nValue;
}

/**********************************************************************
 **********************************************************************
 **********************************************************************
 **********************************************************************
 **********************************************************************
 * SFHudHostageIcon
 */

SFMapOverview::SFMapOverviewHostageIcons::SFMapOverviewHostageIcons()
{
	m_IconPackage = NULL;
	V_memset( m_Icons, 0,sizeof( m_Icons ) );
	m_iCurrentIcon = HI_UNUSED;
}

SFMapOverview::SFMapOverviewHostageIcons::~SFMapOverviewHostageIcons()
{
}
 
void SFMapOverview::SFMapOverviewHostageIcons::Init( IScaleformUI* scaleformui, SFVALUE iconPackage )
{
	m_pScaleformUI = scaleformui;
	m_IconPackage = scaleformui->CreateValue( iconPackage );

	for ( int i = 0; i < HI_NUM_ICONS && hostageIconNames[i] != NULL; i++ )
	{
		m_Icons[i] = m_pScaleformUI->Value_GetMember( m_IconPackage, hostageIconNames[i] );
		if ( m_Icons[i] )
		{
			m_pScaleformUI->Value_SetVisible( m_Icons[i], m_iCurrentIcon == i );
		}
	}

	m_pScaleformUI->Value_SetVisible( m_IconPackage, m_iCurrentIcon != HI_UNUSED );
}

void SFMapOverview::SFMapOverviewHostageIcons::SetStatus( int status )
{
	if ( status != m_iCurrentIcon )
	{
		if ( m_IconPackage )
		{
			if ( m_iCurrentIcon != HI_UNUSED )
			{
				assert(m_Icons[m_iCurrentIcon]);
				m_pScaleformUI->Value_SetVisible( m_Icons[m_iCurrentIcon], false );
			}
			else
			{
				m_pScaleformUI->Value_SetVisible( m_IconPackage, true );
			}

			m_iCurrentIcon = status;

			if ( m_iCurrentIcon != HI_UNUSED )
			{
				assert(m_Icons[m_iCurrentIcon]);
				m_pScaleformUI->Value_SetVisible( m_Icons[m_iCurrentIcon], true );
			}
			else
			{
				m_pScaleformUI->Value_SetVisible( m_IconPackage, false );
			}
		}
	}
}


void SFMapOverview::SFMapOverviewHostageIcons::ReleaseHandles( SFMapOverview* pradar )
{
	if ( m_IconPackage && pradar->FlashAPIIsValid() )
	{
		pradar->SafeReleaseSFVALUE( m_IconPackage );

		for ( int i = 0; i < HI_NUM_ICONS; i++ )
		{
			pradar->SafeReleaseSFVALUE( m_Icons[i] );
		}
	}
}


/**********************************************************************
 **********************************************************************
 **********************************************************************
 **********************************************************************
 **********************************************************************
 * SFMapOverview Code
 *
 */

SFMapOverview::SFMapOverview( const char *value ) : SFHudFlashInterface( value ),
	m_fMapSize( 1.0f ),
	m_fMapScale( 1.0f ),
	m_fPixelToRadarScale( 1.0f ),
	m_fWorldToPixelScale( 1.0f ),
	m_fWorldToRadarScale( 1.0f ),
	m_RadarModule( NULL ),
	m_Radar( NULL ),
	m_IconTranslation( NULL ),
	m_IconRotation( NULL ),
	m_MapRotation( NULL ),
	m_MapTranslation( NULL ),
	m_iNumGoalIcons( 0 ),
	m_iLastPlayerIndex( INVALID_INDEX ),
	m_iLastHostageIndex( INVALID_INDEX ),
	m_iLastGrenadeIndex( INVALID_INDEX ),
	m_iLastDefuserIndex( INVALID_INDEX ),
	m_RadarViewpointWorld( vec3_origin ),
	m_RadarViewpointMap( vec3_origin ),
	m_RadarRotation( 0 ),
	m_BombPosition( vec3_origin ),
	m_DefuserPosition( vec3_origin ),
	m_iCurrentVisibilityFlags( 0 ),
	m_fBombSeenTime( TIMER_INIT ),
	m_fBombAlpha( 0 ),
	m_fDefuserSeenTime( TIMER_INIT ),
	m_fDefuserAlpha( 0.0f ),
	m_LocationText( NULL ),
	m_bFlashLoading( false ),
	m_bFlashReady( false ),
	m_bGotPlayerIcons( false ),	
	m_bShowingHostageZone( false ),
	m_bBombPlanted( false ),
	m_bBombDropped( false ),
	m_nBombEntIndex( -1 ),
	m_bShowBombHighlight( false ),
	m_bShowMapOverview( false ),
	m_bShowAll( false ),
	m_bShowingDashboard( false ),
	m_iObserverMode( OBS_MODE_NONE ),
	m_bTrackDefusers( false ),
	m_bVisible( false )
{
	//SetHiddenBits( HIDEHUD_RADAR );
    m_bWantLateUpdate = true;
	
	m_cDesiredMapName[0] = 0;
	m_cLoadedMapName[0] = 0;
	m_wcLocationString[0] = 0;

	V_memset( m_BombZoneIcons, 0, sizeof( m_BombZoneIcons ) );
	V_memset( m_HostageZoneIcons, 0, sizeof( m_HostageZoneIcons ) );
	V_memset( m_GoalIcons, 0, sizeof( m_GoalIcons ) );
	V_memset( m_HostageStatusIcons, 0, sizeof( m_HostageStatusIcons ) );
	V_memset( m_AllIcons, 0, sizeof( m_AllIcons ) );		

	m_EntitySpotted.ClearAll();
}


SFMapOverview::~SFMapOverview()
{
}

/**************************************
 * hud element functions
 */

void SFMapOverview::Init( void )
{
	// register for events as client listener

	const char** pwalk = &desiredMessageNames[0];

	while( *pwalk != NULL )
	{
		ListenForGameEvent( *pwalk );
		pwalk++;
	}

	if ( ! m_messageMap.Count() )
	{
		const char** pwalk = &desiredMessageNames[0];
		int i = 0;

		while( *pwalk != NULL )
		{
			m_messageMap.Insert( *pwalk++, i++ );
		}
	}

	HOOK_HUD_MESSAGE( SFMapOverview, ProcessSpottedEntityUpdate );
}

void SFMapOverview::LevelInit( void )
{
	if ( !m_bFlashReady && !m_bFlashLoading )
	{
		SFUI_REQUEST_ELEMENT( SF_SS_SLOT( GET_ACTIVE_SPLITSCREEN_SLOT() ), g_pScaleformUI, SFMapOverview, this, MapOverview );
	}

}

void SFMapOverview::LevelShutdown( void )
{
	if ( m_bFlashReady || m_bFlashLoading )
	{
		RemoveFlashElement();
	}
}

bool SFMapOverview::ShouldDraw( void )
{
	if ( IsTakingAFreezecamScreenshot() || !m_bShowMapOverview )
		return false;

	return cl_drawhud.GetBool();// && CHudElement::ShouldDraw();
}

bool SFMapOverview::CanShowOverview( void )
{
	CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
	if ( pLocalPlayer && (pLocalPlayer->GetObserverMode() == OBS_MODE_NONE ||
		pLocalPlayer->GetObserverMode() == OBS_MODE_DEATHCAM || pLocalPlayer->GetObserverMode() == OBS_MODE_FREEZECAM ) )
	{
		return false;
	}
	if ( g_HltvReplaySystem.GetHltvReplayDelay() )
		return false;

	return true;
}


void SFMapOverview::SetActive( bool bActive )
{
	if ( bActive == true && !CanShowOverview() )
		return;

	Show( bActive );
	CHudElement::SetActive( bActive );
}

void SFMapOverview::Show( bool show )
{
	if ( show == true && !CanShowOverview() )
		return;

	if ( m_bFlashReady && show != m_bActive )
	{
		WITH_SLOT_LOCKED
		{
			if ( show )
			{
				m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "showPanel", NULL, 0 );
				m_bVisible = true;
			}
			else
			{
				m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "hidePanel", NULL, 0 );
				m_bVisible = false;
			}
		}

		UpdateAllPlayerNamesAndNumbers();
	}

}

void SFMapOverview::ShowPanel( bool bShow )
{
	if ( bShow != m_bVisible )
	{
		if ( bShow )
		{
			Show( true );
		}
		else
		{
			Show( false );
		}
	}
}

// 
// /**********************************
//  * initialization code goes here
//  */
// 
// 
// these overload the ScaleformFlashInterfaceMixin class
void SFMapOverview::FlashLoaded( void )
{
	m_RadarModule = m_pScaleformUI->Value_GetMember( m_FlashAPI, "RadarModule" );

	if ( !m_RadarModule )
	{
		return;
	}

	m_Radar = m_pScaleformUI->Value_GetMember( m_RadarModule, "Radar" );

	if ( m_Radar )
	{

		m_MapRotation = m_pScaleformUI->Value_GetMember( m_Radar, "MapRotation" );

		if ( m_MapRotation )
		{
			m_MapTranslation =m_pScaleformUI->Value_GetMember( m_MapRotation, "MapTranslation" );
		}


		m_IconRotation = m_pScaleformUI->Value_GetMember( m_Radar, "IconRotation" );

		if ( !m_IconRotation )
		{
			return;
		}

		m_IconTranslation = m_pScaleformUI->Value_GetMember( m_IconRotation, "IconTranslation" );

		if ( !m_IconTranslation )
		{
			return;
		}

		char cHostageZoneIconName[20] = {"HZone0"};

		for ( int i = 0; i < MAX_HOSTAGE_RESCUES; i++ )
		{
			cHostageZoneIconName[5] = '0'+i;
			m_HostageZoneIcons[i] = m_pScaleformUI->Value_GetMember( m_IconTranslation, cHostageZoneIconName );
		}

		m_BombZoneIcons[0] = m_pScaleformUI->Value_GetMember( m_IconTranslation, "BombZoneA" );
		m_BombZoneIcons[1] = m_pScaleformUI->Value_GetMember( m_IconTranslation, "BombZoneB" );

	}

	SFVALUE dashboard = m_pScaleformUI->Value_GetMember( m_RadarModule, "Dashboard" );
	m_AllIcons[RI_DASHBOARD] = dashboard;

	if ( !dashboard )
	{
		return;
	}

	char hostageIconName[20] = {"HostageStatusX"};

	int index = 0;
	SFVALUE hostageIcon;

	do
	{
		hostageIconName[13] = index + '1';
		hostageIcon = m_pScaleformUI->Value_GetMember( dashboard, hostageIconName );
		if ( hostageIcon == NULL )
		{
			break;
		}
		else
		{
			m_HostageStatusIcons[index].Init( m_pScaleformUI, hostageIcon );
			SafeReleaseSFVALUE( hostageIcon );
		}

	} while( ++index < MAX_HOSTAGES );

	for ( int i = 0; overviewIconNames[i] != NULL; i++ )
	{
		m_AllIcons[i] = m_pScaleformUI->Value_GetMember( dashboard, overviewIconNames[i] );
	}

// 	m_LocationText = m_pScaleformUI->TextObject_MakeTextObjectFromMember( dashboard, "Location" );
// 	if ( m_LocationText )
// 	{
// 		m_LocationText->SetText( m_wcLocationString );
// 	}	
}


void SFMapOverview::FlashReady( void )
{
	// these aren't ready until after the first frame, so they have to get connected here instead of in
	// FlashLoaded()

	m_AllIcons[RI_BOMB_ICON_PACKAGE] = m_pScaleformUI->Value_Invoke( m_IconTranslation, "createBombPack", NULL, 0 );
	if ( m_AllIcons[RI_BOMB_ICON_PACKAGE] )
	{
		m_AllIcons[RI_BOMB_ICON_DROPPED] = m_pScaleformUI->Value_GetMember( m_AllIcons[RI_BOMB_ICON_PACKAGE], "DroppedBomb" );
		m_AllIcons[RI_BOMB_ICON_PLANTED] = m_pScaleformUI->Value_GetMember( m_AllIcons[RI_BOMB_ICON_PACKAGE], "PlantedBomb" );
		m_AllIcons[RI_BOMB_ICON_BOMB_CT] = m_pScaleformUI->Value_GetMember( m_AllIcons[RI_BOMB_ICON_PACKAGE], "BombCT" );
		m_AllIcons[RI_BOMB_ICON_BOMB_T] = m_pScaleformUI->Value_GetMember( m_AllIcons[RI_BOMB_ICON_PACKAGE], "BombT" );

		m_AllIcons[RI_BOMB_ICON_BOMB_ABOVE] = m_pScaleformUI->Value_GetMember( m_AllIcons[RI_BOMB_ICON_PACKAGE], "BombAbove" );
		m_AllIcons[RI_BOMB_ICON_BOMB_BELOW] = m_pScaleformUI->Value_GetMember( m_AllIcons[RI_BOMB_ICON_PACKAGE], "BombBelow" );
	}

	for ( int i = 0; i < RI_NUM_ICONS; i++ )
	{
		if ( m_AllIcons[i] )
		{
			m_pScaleformUI->Value_SetVisible( m_AllIcons[i], false );
		}
	}

	m_bFlashLoading = false;
	m_bFlashReady = true;
	ResetForNewMap();

	// there will be a map waiting for us to load

	FlashLoadMap( NULL );

	if ( m_bActive )
	{
		m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "showPanel", NULL, 0 );
	}
	else
	{
		m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "hidePanel", NULL, 0 );
	}
 }

void SFMapOverview::LazyCreateGoalIcons( void )
{
	if ( m_bGotGoalIcons || !m_bFlashReady )
	{
		return;
	}

	// The goal entities don't exist on the client, so we have to get them from the CS Resource.
	C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
	if ( !pCSPR )
	{
		return;
	}

	m_iNumGoalIcons = 0;

	if ( CSGameRules()->IsBombDefuseMap() )
	{

		Vector bombA = pCSPR->GetBombsiteAPosition();
		if( bombA != vec3_origin )
		{
			m_GoalIcons[m_iNumGoalIcons].m_Position = bombA;
			m_GoalIcons[m_iNumGoalIcons].m_Icon = m_BombZoneIcons[0];
			m_pScaleformUI->Value_SetVisible( m_GoalIcons[m_iNumGoalIcons].m_Icon, true );
			m_iNumGoalIcons++;
		}

		Vector bombB = pCSPR->GetBombsiteBPosition();
		if( bombB != vec3_origin )
		{
			m_GoalIcons[m_iNumGoalIcons].m_Position = bombB;
			m_GoalIcons[m_iNumGoalIcons].m_Icon = m_BombZoneIcons[1];
			m_pScaleformUI->Value_SetVisible( m_GoalIcons[m_iNumGoalIcons].m_Icon, true );
			m_iNumGoalIcons++;
		}
	}
	else if ( CSGameRules()->IsHostageRescueMap() )
	{
		for( int rescueIndex = 0; rescueIndex < MAX_HOSTAGE_RESCUES; rescueIndex++ )
		{
			int hIndex = 0;
			Vector hostageI = pCSPR->GetHostageRescuePosition( rescueIndex );
			if( hostageI != vec3_origin )
			{
				m_GoalIcons[m_iNumGoalIcons].m_Position = hostageI;
				m_GoalIcons[m_iNumGoalIcons].m_Icon = m_HostageZoneIcons[hIndex++];
				m_pScaleformUI->Value_SetVisible( m_GoalIcons[m_iNumGoalIcons].m_Icon, true );
				m_iNumGoalIcons++;
			}
		}
	}

	m_bGotGoalIcons = true;

}



bool SFMapOverview::PreUnloadFlash( void )
{
	if ( m_IconTranslation )
	{
		m_pScaleformUI->Value_InvokeWithoutReturn( m_IconTranslation, "removeBombPack", NULL, 0 );
	}

	for ( int i = 0; i < MAX_BOMB_ZONES; i++ )
	{
		SafeReleaseSFVALUE( m_BombZoneIcons[i] );
	}

	for ( int i = 0; i < MAX_HOSTAGE_RESCUES; i++ )
	{
		SafeReleaseSFVALUE( m_HostageZoneIcons[i] );
	}

	while( m_iLastPlayerIndex >= 0 )
	{
		RemovePlayer( m_iLastPlayerIndex );
	}

	while( m_iLastHostageIndex >= 0 )
	{
		RemoveHostage( m_iLastHostageIndex );
	}

	RemoveAllDefusers();

	RemoveAllGrenades();

	SafeReleaseSFVALUE( m_MapRotation );
	SafeReleaseSFVALUE( m_MapTranslation );
	SafeReleaseSFVALUE( m_RadarModule );
	SafeReleaseSFVALUE( m_Radar );
	SafeReleaseSFVALUE( m_IconTranslation );
	SafeReleaseSFVALUE( m_IconRotation );		

	SafeReleaseSFTextObject( m_LocationText );

	int index = 0;
	while( m_HostageStatusIcons[index].m_IconPackage )
	{
		m_HostageStatusIcons[index++].ReleaseHandles( this );
	}

	for ( int i =0 ; i < RI_NUM_ICONS; i++ )
	{
		SafeReleaseSFVALUE( m_AllIcons[i] );
	}

	m_bFlashReady = false;
	m_cDesiredMapName[0] = 0;
	m_cLoadedMapName[0] = 0;

	m_bActive = false;

	return true;
}

// /*********************************************************
//  * set up the background map
//  */

void SFMapOverview::SetMap( const char* pMapName )
{
	FlashLoadMap( pMapName );

	KeyValues* MapKeyValues = new KeyValues( pMapName );

	char tempfile[MAX_PATH];
	Q_snprintf( tempfile, sizeof( tempfile ), "resource/overviews/%s.txt", pMapName );

	if ( !MapKeyValues->LoadFromFile( g_pFullFileSystem, tempfile, "GAME" ) )
	{
		DevMsg( 1, "Error! CMapOverview::SetMap: couldn't load file %s.\n", tempfile );
		m_MapOrigin.x = 0;
		m_MapOrigin.y = 0;
		return;
	}

	// TODO release old texture ?

	m_MapOrigin.x	= MapKeyValues->GetInt( "pos_x" );
	m_MapOrigin.y	= MapKeyValues->GetInt( "pos_y" );
	m_MapOrigin.z   = 0;
	m_fMapScale = MapKeyValues->GetFloat( "scale", 1.0f );
	m_fWorldToPixelScale = 1.0f / m_fMapScale;

	m_fWorldToRadarScale = m_fWorldToPixelScale * m_fPixelToRadarScale;

	MapKeyValues->deleteThis();

}


void SFMapOverview::FlashLoadMap( const char* pMapName )
{
	const char* pMapToLoad = pMapName ? pMapName : m_cDesiredMapName;

	if ( V_strcmp( pMapToLoad, m_cLoadedMapName ) )
	{
		if ( m_bFlashReady )
		{
			if ( pMapToLoad != m_cDesiredMapName )
			{
				V_strncpy( m_cDesiredMapName, pMapToLoad, sizeof( m_cDesiredMapName )+1 );
			}

			WITH_SFVALUEARRAY_SLOT_LOCKED( args, 1 )
			{
				m_pScaleformUI->ValueArray_SetElement( args, 0, pMapToLoad );
				m_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "loadMap", args, 1 );
			}
		}
		else
		{
			if ( pMapToLoad != m_cDesiredMapName )
			{
				V_strncpy( m_cDesiredMapName, pMapToLoad, sizeof( m_cDesiredMapName )+1 );
			}
		}
	}
}

void SFMapOverview::MapLoaded( SCALEFORM_CALLBACK_ARGS_DECL )
{
	// flash passes in the scaledsize / image size
	m_fMapSize = ( float )pui->Params_GetArgAsNumber( obj, 0 );
	m_fPixelToRadarScale = ( float )pui->Params_GetArgAsNumber( obj, 1 );

// 	m_MapOrigin.x	= -(m_fMapSize/2);
// 	m_MapOrigin.y	= -(m_fMapSize/2);

	m_fWorldToRadarScale = m_fWorldToPixelScale * m_fPixelToRadarScale;

	V_strncpy( m_cLoadedMapName, m_cDesiredMapName, sizeof( m_cLoadedMapName )+1 );

	//Get the world's extent
	C_World *world = GetClientWorldEntity();
	if ( !world )
		return;

	Vector worldCenter = ( world->m_WorldMins + world->m_WorldMaxs ) * 0.5f;
}

void SFMapOverview::ToggleOverviewMap( SCALEFORM_CALLBACK_ARGS_DECL )
{
	ShowMapOverview( !IsMapOverviewShown() );
}

// /**********************************************
//  * reset functions
//  */
// 
// 
void SFMapOverview::ResetForNewMap( void )
{
	if ( m_bFlashReady )
	{
		for ( int i = 0; i < 2; i++ )
		{
			m_pScaleformUI->Value_SetVisible( m_BombZoneIcons[i], false );
		}

		for ( int i = 0; i < MAX_HOSTAGE_RESCUES; i++ )
		{
			m_pScaleformUI->Value_SetVisible( m_HostageZoneIcons[i], false );
		}

		while( m_iLastHostageIndex >= 0 )
		{
			RemoveHostage( m_iLastHostageIndex );
		}

		int index = 0;
		while( m_HostageStatusIcons[index].m_IconPackage && ( index < MAX_HOSTAGES ) )
		{
			m_HostageStatusIcons[index++].SetStatus( SFMapOverviewHostageIcons::HI_UNUSED );
		}

		RemoveAllGrenades();
		RemoveAllDefusers();
	}

	m_iNumGoalIcons = 0;
	m_bGotGoalIcons = false;

	ResetRoundVariables();

}

void SFMapOverview::ResetRoundVariables( bool bResetGlobalStates )
{
	SetVisibilityFlags( 0 );
	SetLocationText( NULL );

	m_RadarViewpointWorld = vec3_origin;
	m_RadarViewpointMap = vec3_origin;
	m_RadarRotation = 0;
	m_fBombSeenTime = TIMER_INIT;
	m_fBombAlpha = 0.0f;
	m_fDefuserSeenTime = TIMER_INIT;
	m_fDefuserAlpha = 0.0f;	
	m_bShowingHostageZone = false;

	m_bShowBombHighlight = false;
	m_bShowingDashboard = false;
	m_bShowAll = false;
	m_iObserverMode = OBS_MODE_NONE;
	ApplySpectatorModes(); // reapply here to make sure it stays when it's supposed to

	ConVarRef mp_defuser_allocation( "mp_defuser_allocation" );
	m_bTrackDefusers = ( mp_defuser_allocation.GetInt() == DefuserAllocation::Random );

	if ( bResetGlobalStates )
	{
		m_nBombEntIndex = -1;
		m_BombPosition = vec3_origin;
		m_DefuserPosition = vec3_origin;
		m_bBombIsSpotted = false;
		m_bBombPlanted = false;
		m_bBombDropped = false;
		m_bBombExploded = false;
		m_bBombDefused = false;
	}

	m_EntitySpotted.ClearAll();

	CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
	if ( pLocalPlayer && (pLocalPlayer->GetObserverMode() == OBS_MODE_NONE ) )
		ShowMapOverview( false );
}

void SFMapOverview::ShowMapOverview( bool bValue )
{
	if ( bValue == true && !CanShowOverview() )
		return;

	ClientModeShared *mode = ( ClientModeShared * )GetClientModeNormal();
	if ( mode )
	{
		mode->ReloadScheme();
	}
	
	m_bShowMapOverview = bValue;
}
 

void SFMapOverview::ResetRadar( bool bResetGlobalStates )
{
	for ( int i = 0; i <= m_iLastPlayerIndex; i++ )
	{
		ResetPlayer( i );
	}

	if ( CSGameRules()->IsHostageRescueMap() )
	{
		RemoveStaleHostages();

		for ( int i = 0; i <= m_iLastHostageIndex; i++ )
		{
			ResetHostage( i );
		}

		int index = 0;
		while( m_HostageStatusIcons[index].m_IconPackage && ( index < MAX_HOSTAGES ) )
		{
			m_HostageStatusIcons[index++].SetStatus( SFMapOverviewHostageIcons::HI_UNUSED );
		}
	}

	if ( bResetGlobalStates )
	{
		RemoveAllGrenades();
		RemoveAllDefusers();
	}

	ResetRoundVariables( bResetGlobalStates );
}

void SFMapOverview::ResetRound( void )
{
	ResetRadar( true );

	RefreshGraphs();
}

void SFMapOverview::RefreshGraphs( void )
{
	g_pScaleformUI->Value_InvokeWithoutReturn( m_FlashAPI, "onRefresh", 0, NULL );
}

// /*****************************************************
//  * player icon loading / creating
//  */
// 
bool SFMapOverview::LazyUpdateIconArray( SFMapOverviewIconPackage* pArray, int lastIndex )
{
	bool result = true;
	int i;
	SFMapOverviewIconPackage* pwalk;

	for ( pwalk = pArray, i = 0; i <= lastIndex; i++, pwalk++ )
	{
		if ( pwalk->m_bIsActive && !pwalk->m_IconPackage )
		{
			if ( !LazyCreateIconPackage( pwalk ) )
			{
				// keep going, but remember that at least one wasn't loaded correctly
				result = false;
			}
		}
	}

	return result;
}

void SFMapOverview::LazyCreatePlayerIcons( void )
{
	if ( !m_bFlashReady || m_bGotPlayerIcons )
		return;

	// the following code looks odd, but it insures that all three of the LazyUpdate calls are made
	// even if m_bGotPlayerIcons becomes false early.

	m_bGotPlayerIcons = LazyUpdateIconArray( m_Players, m_iLastPlayerIndex );

	m_bGotPlayerIcons = LazyUpdateIconArray( m_Hostages, m_iLastHostageIndex ) && m_bGotPlayerIcons;

	m_bGotPlayerIcons = LazyUpdateIconArray( m_Grenades, m_iLastGrenadeIndex ) && m_bGotPlayerIcons;

	m_bGotPlayerIcons = LazyUpdateIconArray( m_Defusers, m_iLastDefuserIndex ) && m_bGotPlayerIcons;

}

bool SFMapOverview::LazyCreateIconPackage( SFMapOverviewIconPackage* pIconPack )
{
	if ( m_bFlashReady && pIconPack->m_bIsActive && !pIconPack->m_IconPackage )
	{
		SFVALUE result = NULL;

		WITH_SFVALUEARRAY_SLOT_LOCKED( args, 2 )
		{
			m_pScaleformUI->ValueArray_SetElement( args, 0, pIconPack->m_iIndex );
			m_pScaleformUI->ValueArray_SetElement( args, 1, pIconPack->m_IconPackType );
			result = m_pScaleformUI->Value_Invoke( m_IconTranslation, "overviewCreateIconPack", args, 2 );
		
			pIconPack->Init( m_pScaleformUI, result );

			if ( result )
			{
				m_pScaleformUI->ReleaseValue( result );
			}		
		}

		return true;
	}
	else
	{
		return false;
	}
}

void SFMapOverview::InitIconPackage( SFMapOverviewIconPackage* pPlayer, int iAbsoluteIndex, ICON_PACK_TYPE iconType )
{
	if ( pPlayer->m_bIsActive && m_pScaleformUI )
	{
		RemoveIconPackage( pPlayer );
	}

	pPlayer->m_IconPackType = iconType;
	pPlayer->m_iIndex = iAbsoluteIndex;
	pPlayer->m_bIsActive = true;

	pPlayer->StartRound();

	if ( !pPlayer->m_IconPackage && !LazyCreateIconPackage( pPlayer ) )
	{
		m_bGotPlayerIcons = false;
	}

}

void SFMapOverview::RemoveIconPackage( SFMapOverviewIconPackage* pPackage )
{
	if ( pPackage->m_bIsActive && m_pScaleformUI )
	{
		if ( m_bFlashReady && pPackage->m_IconPackage )
		{
			WITH_SFVALUEARRAY_SLOT_LOCKED( args, 1 )
			{
				m_pScaleformUI->ValueArray_SetElement( args, 0, pPackage->m_IconPackage );
				m_pScaleformUI->Value_InvokeWithoutReturn( m_IconTranslation, "removeIconPack", args, 1 );
			}
		}

		WITH_SLOT_LOCKED
		{
			pPackage->NukeFromOrbit( this );
		}
	}
}

 
// /**********************************************
//  * player and hostage initialization and creation
//  */


SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::CreatePlayer( int index )
{
	SFMapOverviewIconPackage* pPackage = GetRadarPlayer( index );
	InitIconPackage( pPackage, index, ICON_PACK_PLAYER );

	m_iLastPlayerIndex = MAX( index, m_iLastPlayerIndex );

	return pPackage;
}


void SFMapOverview::ResetPlayer( int index )
{
	SFMapOverviewIconPackage* pPackage = GetRadarPlayer( index );
	if ( pPackage->m_bIsActive )
	{
		pPackage->StartRound();
	}

	UpdatePlayerNameAndNumber( pPackage );
}

void SFMapOverview::RemovePlayer( int index )
{
	RemoveIconPackage( GetRadarPlayer( index ) );

	if ( index == m_iLastPlayerIndex )
	{
		while( m_iLastPlayerIndex >= 0 && !m_Players[m_iLastPlayerIndex].m_bIsActive )
		{
			m_iLastPlayerIndex--;
		}
	}

	UpdateAllPlayerNamesAndNumbers();
}

SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::CreateHostage( int index )
{
	SFMapOverviewIconPackage* pPackage = GetRadarHostage( index );
	InitIconPackage( pPackage, index, ICON_PACK_HOSTAGE );

	m_iLastHostageIndex = MAX( index, m_iLastHostageIndex );

	return pPackage;
}

void SFMapOverview::ResetHostage( int index )
{
	SFMapOverviewIconPackage* pPackage = GetRadarHostage( index );
	if ( pPackage->m_bIsActive )
	{
		pPackage->StartRound();
	}
}

void SFMapOverview::RemoveStaleHostages( void )
{
	// Remove hostages that are no longer tracked by the player resource (hostages that have died)

	C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
	if ( !pCSPR )
	{
		return;
	}

	for ( int index = 0; index < MAX_HOSTAGES; index++ )
	{
		SFMapOverviewIconPackage* pPackage = GetRadarHostage( index );
		if ( pPackage->m_bIsActive )
		{
			bool bRemove = true;

			for( int i = 0; i < MAX_HOSTAGES; i++ )
			{
				if ( pCSPR->GetHostageEntityID( i ) == pPackage->m_iEntityID )
				{
					bRemove = false;
					break;
				}
			}

			if ( bRemove )
			{
				RemoveHostage( index );
			}
		}
	}
}

void SFMapOverview::RemoveHostage( int index )
{
	RemoveIconPackage( GetRadarHostage( index ) );

	if ( index == m_iLastHostageIndex )
	{
		while( m_iLastHostageIndex >= 0 && !m_Hostages[m_iLastHostageIndex].m_bIsActive )
		{
			m_iLastHostageIndex--;
		}
	}
}


SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::CreateGrenade( int entityID, int nGrenadeType )
{
	SFMapOverviewIconPackage* pPackage = NULL;
	int index = m_iLastGrenadeIndex+1;

	for ( int i = 0; i <= m_iLastGrenadeIndex; i++ )
	{
		if ( !m_Grenades[i].m_bIsActive )
		{
			index = i;
			break;
		}
	}

	if ( index < MAX_GRENADES )
	{
		pPackage = GetRadarGrenade( index );

		InitIconPackage( pPackage, index, ICON_PACK_GRENADES );

		pPackage->m_iEntityID = entityID;
		pPackage->m_fRoundStartTime = TIMER_INIT;

		m_iLastGrenadeIndex = MAX( index, m_iLastGrenadeIndex );
	}

	return pPackage;
}

void SFMapOverview::RemoveAllGrenades( void )
{
	for ( int i = 0; i <= m_iLastGrenadeIndex; i++ )
	{
		if ( m_Grenades[i].m_bIsActive )
		{
			RemoveGrenade( i );
		}
	}
}


void SFMapOverview::RemoveGrenade( int index )
{
	RemoveIconPackage( GetRadarGrenade( index ) );

	if ( index == m_iLastGrenadeIndex )
	{
		while( m_iLastGrenadeIndex >= 0 && !m_Grenades[m_iLastGrenadeIndex].m_bIsActive )
		{
			m_iLastGrenadeIndex--;
		}
	}
}

SFMapOverview::SFMapOverviewIconPackage * SFMapOverview::GetDefuser( int nEntityID, bool bCreateIfNotFound )
{
	SFMapOverviewIconPackage * pResult = NULL;

	int nIndex = GetDefuseIndexFromEntityID( nEntityID );

	if ( nIndex != INVALID_INDEX )
	{
		pResult = GetRadarDefuser( nIndex );
	}

	if ( pResult == NULL && bCreateIfNotFound )
	{
		pResult = CreateDefuser( nEntityID );
	}

	return pResult;
}



void SFMapOverview::SetDefuserPos( int nEntityID, int x, int y, int z, int a )
{
	if ( !m_bTrackDefusers )
	{
		return;
	}

	SFMapOverviewIconPackage * pDefuser = GetDefuser( nEntityID, true );

	AssertMsg( pDefuser != NULL, "Defuser not found. Update failed." );

	if ( pDefuser )
	{
		pDefuser->m_Position.Init( x, y, z ) ;
		pDefuser->SetAlpha( 1.0f );

		SetIconPackagePosition( pDefuser );
	}
}

// defusers attached to players will update during the PlacePlayer phase
SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::CreateDefuser( int nEntityID )
{
	if ( !m_bTrackDefusers )
	{
		return NULL;
	}

	SFMapOverviewIconPackage* pPackage = NULL;
	int index = m_iLastDefuserIndex+1;

	AssertMsg( GetDefuseIndexFromEntityID( nEntityID ) == INVALID_INDEX, "Defuser entity ID already exists." );

	for ( int i = 0; i <= m_iLastDefuserIndex; i++ )
	{
		if ( !m_Defusers[i].m_bIsActive )
		{
			index = i;
			break;
		}
	}

	if ( index < MAX_PLAYERS )
	{
		pPackage = GetRadarDefuser( index );

		InitIconPackage( pPackage, index, ICON_PACK_DEFUSER );

		pPackage->m_iEntityID = nEntityID;
		pPackage->m_fRoundStartTime = TIMER_INIT;
		pPackage->SetIsSpotted( false );
		pPackage->SetIsDefuse( true );
		pPackage->m_Position = vec3_origin;

		m_iLastDefuserIndex = MAX( index, m_iLastDefuserIndex );
	}
	else
	{
		AssertMsg( false, "m_Defusers array is full" );
	}

	return pPackage;
}

void SFMapOverview::RemoveAllDefusers( void )
{
	for ( int i = 0; i <= m_iLastDefuserIndex; i++ )
	{
		if ( m_Defusers[i].m_bIsActive )
		{
			RemoveDefuser( i );
		}
	}
}

void SFMapOverview::RemoveDefuser( int index )
{
	RemoveIconPackage( GetRadarDefuser( index ) );

	if ( index == m_iLastDefuserIndex )
	{
		while( m_iLastDefuserIndex >= 0 && !m_Defusers[m_iLastDefuserIndex].m_bIsActive )
		{
			m_iLastDefuserIndex--;
		}
	}
}



void SFMapOverview::SetPlayerTeam( int index, int team )
{
	SFMapOverviewIconPackage* pPlayer = GetRadarPlayer( index );
	pPlayer->SetPlayerTeam( team );
}

int SFMapOverview::GetPlayerIndexFromUserID( int userID )
{
	int nEntityID = engine->GetPlayerForUserID( userID );
	for ( int i = 0; i <= m_iLastPlayerIndex; i++ )
	{
		if ( m_Players[i].m_bIsActive && m_Players[i].m_iEntityID == nEntityID )
		{
			return i;
		}
	}

	return INVALID_INDEX;
}

int SFMapOverview::GetHostageIndexFromHostageEntityID( int entityID )
{
	for ( int i = 0; i <= m_iLastHostageIndex; i++ )
	{
		if ( m_Hostages[i].m_bIsActive && m_Hostages[i].m_iEntityID == entityID )
		{
			return i;
		}
	}

	return INVALID_INDEX;
}

int SFMapOverview::GetGrenadeIndexFromEntityID( int entityID )
{
	for ( int i = 0; i <= m_iLastGrenadeIndex; i++ )
	{
		if ( m_Grenades[i].m_bIsActive && m_Grenades[i].m_iEntityID == entityID )
		{
			return i;
		}
	}

	return INVALID_INDEX;
}

int SFMapOverview::GetDefuseIndexFromEntityID( int nEntityID )
{
	for ( int i = 0; i <= m_iLastDefuserIndex; i++ )
	{
		if ( m_Defusers[i].m_bIsActive && m_Defusers[i].m_iEntityID == nEntityID )
		{
			return i;
		}
	}

	return INVALID_INDEX;
}



SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::GetRadarPlayer( int index )
{
	return &m_Players[index];
}

SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::GetRadarHostage( int index )
{
	return &m_Hostages[index];
}

SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::GetRadarGrenade( int index )
{
	return &m_Grenades[index];
}

SFMapOverview::SFMapOverviewIconPackage* SFMapOverview::GetRadarDefuser( int index )
{
	return &m_Defusers[index];
}

// /*************************************************
//  * We don't get updates from the server from players
//  * that are not in our PVS, so there are separate
//  * messages specifically to update the radar
//  */
bool SFMapOverview::MsgFunc_ProcessSpottedEntityUpdate( const CCSUsrMsg_ProcessSpottedEntityUpdate &msg )
{
	if ( msg.new_update() )
	{
		// new spotting frame. clean up.
		m_bBombIsSpotted = false;
		m_EntitySpotted.ClearAll();
	}


	for ( int i = 0; i < msg.entity_updates_size(); i ++ )
	{
		const CCSUsrMsg_ProcessSpottedEntityUpdate::SpottedEntityUpdate &update = msg.entity_updates(i);

		int nEntityID = update.entity_idx();
		if ( nEntityID < 0 || nEntityID >= MAX_EDICTS )
			continue; // GeekPwn2016 range check

		m_EntitySpotted.Set( nEntityID, true );

		const char * szEntityClass = NULL;

		int nClassID =  update.class_id();
		for ( ClientClass *pCur = g_pClientClassHead; pCur; pCur=pCur->m_pNext )
		{
			if (  pCur->m_ClassID == nClassID )
			{
				szEntityClass = pCur->GetName();
				break;
			}
		}

		if ( szEntityClass == NULL )
		{
			Warning( "Unknown entity class received in ProcessSpottedEntityUpdate.\n" );
		}

		// non-class specific data
		// read position and angle
		int x = update.origin_x() * 4;
		int y = update.origin_y() * 4;
		int z = update.origin_z() * 4;
		int a = update.angle_y();


		// Clients are unaware of the defuser class type, so we need to flag defuse entities manually
		if ( update.defuser() )
		{
			SetDefuserPos( nEntityID, x, y, z, a );
		}
		else if ( V_strcmp( "CCSPlayer", szEntityClass ) == 0 )
		{
			SFMapOverviewIconPackage* pPlayerIcon = NULL;

			pPlayerIcon = GetRadarPlayer( nEntityID - 1 );

			pPlayerIcon->m_Position.Init( x, y, z );
			pPlayerIcon->m_Angle.Init( 0, a, 0 );

			// has defuser?
			if (  update.player_has_defuser() )
			{
				SetDefuserPos( nEntityID, x, y, z, a );
			}

			// has C4?
			if (  update.player_has_c4() )
			{
				m_bBombIsSpotted = true;
				m_BombPosition.Init( x, y, 0 );
			}

			// The following code should no longer be necessary with the new spotting system
			//C_CSPlayer *pPlayer =	ToCSPlayer( UTIL_PlayerByIndex( nEntityID ) );

			//// Only update players that are outside of PVS
			//if ( pPlayer && pPlayer->IsDormant() )
			//{
			//	// update origin and angle for players out of my PVS
			//	Vector origin = pPlayer->GetAbsOrigin();
			//	QAngle angles = pPlayer->GetAbsAngles();

			//	origin.x = x;
			//	origin.y = y;
			//	angles.y = a;

			//	pPlayer->SetAbsOrigin( origin );
			//	pPlayer->SetAbsAngles( angles );
			//}
		}
		else if ( V_strcmp( "CC4", szEntityClass ) == 0 || V_strcmp( "CPlantedC4", szEntityClass ) == 0 )
		{
			m_bBombIsSpotted = true;
			m_BombPosition.Init( x, y, 0 );
		}
		else if ( V_strcmp( "CHostage", szEntityClass ) == 0 )
		{
			int hostageIndex = GetHostageIndexFromHostageEntityID( nEntityID );

			if ( hostageIndex == INVALID_INDEX )
			{
				for ( int i = 0; i <= m_iLastHostageIndex; i++ )
				{
					RemoveHostage( i );
				}
			}
			else
			{
				SFMapOverviewIconPackage* pPackage = GetRadarHostage( hostageIndex );

				if ( pPackage )
				{
					pPackage->m_Position.Init( x, y, z );
				}
			}
		}
		else
		{
			Warning( "Unknown entity update received by ProcessSpottedEntityUpdate: %s.\n", szEntityClass );
		}

	}

	return true;
}

void SFMapOverview::UpdateAllPlayerNamesAndNumbers( void )
{
	//int nMaxPlayers = CCSGameRules::GetMaxPlayers();

	for ( int i = 0; i <= MAX_PLAYERS; ++i )
	{
		SFMapOverviewIconPackage* pPackage = GetRadarPlayer( i );
		if ( pPackage )
			UpdatePlayerNameAndNumber( pPackage );
	}
}

void SFMapOverview::UpdatePlayerNameAndNumber( SFMapOverviewIconPackage* pPackage )
{
	int nMaxPlayers = CCSGameRules::GetMaxPlayers();

	// update the player number
	SFHudTeamCounter* pTeamCounter = GET_HUDELEMENT( SFHudTeamCounter );
	if ( pPackage && pPackage->m_Icons[PI_PLAYER_NUMBER] && pPackage->m_Icons[PI_PLAYER_NAME_CT] && pPackage->m_Icons[PI_PLAYER_NAME_T] )
	{
		if ( pTeamCounter )
		{
			int pidx = pTeamCounter->GetPlayerSlotIndex( pPackage->m_iEntityID  );
			if ( pidx != -1 )
			{
				pidx += 1;
				if ( pidx == 10 )
					pidx = 0;

				ISFTextObject* textPanel =	g_pScaleformUI->TextObject_MakeTextObjectFromMember( pPackage->m_Icons[PI_PLAYER_NUMBER], "Text" );	
				if ( textPanel )
				{
					CBasePlayer * pPlayer = CBasePlayer::GetLocalPlayer();
					bool bIsSpec = (pPlayer && (m_bShowAll || pPlayer->GetObserverMode() != OBS_MODE_NONE ));
					WITH_SLOT_LOCKED
					{			
						if ( nMaxPlayers <= 10 && bIsSpec )
							textPanel->SetText( pidx );
						else
							textPanel->SetText( "" );
					}
					SafeReleaseSFTextObject( textPanel );
				}
			}
		}

		int nTeamSlot = PI_PLAYER_NAME_CT;
		if ( pPackage->m_iPlayerType == PI_T )
			nTeamSlot = PI_PLAYER_NAME_T;

		ISFTextObject* textPanelName =	g_pScaleformUI->TextObject_MakeTextObjectFromMember( pPackage->m_Icons[nTeamSlot], "Text" );	
		if ( textPanelName )
		{
			WITH_SLOT_LOCKED
			{
				textPanelName->SetText( pPackage->m_wcName );
			}
			SafeReleaseSFTextObject( textPanelName );
		}
	}
}

//handles all game event messages ( first looks them up in map so there's no long list of strcmps )
void SFMapOverview::FireGameEvent( IGameEvent *event )
{
	const char* eventName = event->GetName();
	int elementIndex = m_messageMap.Find( eventName );
	if ( elementIndex == m_messageMap.InvalidIndex() )
	{
		return;
	}

	SF_SPLITSCREEN_PLAYER_GUARD();

	CBasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
	int EventUserID = event->GetInt( "userid", -1 );
	int LocalPlayerID = ( pLocalPlayer != NULL ) ? pLocalPlayer->GetUserID() : -2;

	DESIRED_MESSAGE_INDICES messageTypeIndex = ( DESIRED_MESSAGE_INDICES )m_messageMap.Element( elementIndex );

	switch( messageTypeIndex )
	{
		case GAME_NEWMAP:
			ResetForNewMap();
			SetMap( event->GetString( "mapname" ) );
		break;

		case ROUND_POST_START:
			ResetRound();
		break;


		case PLAYER_CONNECT:
		case PLAYER_INFO:
		{
			int index = event->GetInt( "index" ); // = entity index - 1
			int userID = index + 1;

			if ( index < 0 || index >= MAX_PLAYERS )
			{
				return;
			}

			SFMapOverviewIconPackage* pPackage = CreatePlayer( index );
			if ( messageTypeIndex == PLAYER_CONNECT )
			{
				pPackage->SetPlayerTeam( TEAM_SPECTATOR );
			}

			pPackage->m_iEntityID = userID;

			const char* name = event->GetString( "name","unknown" );
			if ( CDemoPlaybackParameters_t const *pParameters = engine->GetDemoPlaybackParameters() )
			{
				if ( pParameters->m_bAnonymousPlayerIdentity )
					name = ""; // suppress names for anonymous playback
			}

			V_UTF8ToUnicode( name, pPackage->m_wcName, sizeof( pPackage->m_wcName ) );
		}
		break;

		case PLAYER_TEAM:
		{
			int playerIndex = GetPlayerIndexFromUserID( event->GetInt( "userid" ) );

			if ( playerIndex == INVALID_INDEX )
			{
				return;
			}

			SFMapOverviewIconPackage* pPackage = GetRadarPlayer( playerIndex );
			pPackage->SetPlayerTeam( event->GetInt( "team" ) );

		}
		break;

		case PLAYER_DEATH:
		{
			int playerIndex = GetPlayerIndexFromUserID( event->GetInt( "userid" ) );

			if ( playerIndex == INVALID_INDEX )
			{
				return;
			}

			SFMapOverviewIconPackage* pPackage = GetRadarPlayer( playerIndex );

			if ( pPackage->m_bIsActive )
			{
				pPackage->SetIsDead( true );
				pPackage->m_Health = 0;
			}

			int nDefuseIndex = GetDefuseIndexFromEntityID( engine->GetPlayerForUserID( event->GetInt( "userid" ) ) );

			if ( nDefuseIndex != INVALID_INDEX )
			{
				RemoveDefuser( nDefuseIndex );
			}
		}
		break;

		case PLAYER_SPAWN:
		{
			if ( EventUserID == LocalPlayerID )
			{
				m_bShowMapOverview = false;
			}

			int playerIndex = GetPlayerIndexFromUserID( event->GetInt( "userid" ) );

			if ( playerIndex != INVALID_INDEX )
			{
				SFMapOverviewIconPackage* pPackage = GetRadarPlayer( playerIndex );
				pPackage->m_Health = 100;

				UpdatePlayerNameAndNumber( pPackage );
			}
		}
		break;

		case PLAYER_DISCONNECT:
		{

			int playerIndex = GetPlayerIndexFromUserID( event->GetInt( "userid" ) );

			if ( playerIndex != INVALID_INDEX )
			{
				RemovePlayer( playerIndex );
			}
		}
		break;

		case HOSTAGE_KILLED:
		{
			int hostageIndex = GetHostageIndexFromHostageEntityID( event->GetInt( "hostage" )  );

			if ( hostageIndex == INVALID_INDEX )
			{
				return;
			}

			SFMapOverviewIconPackage* pPackage = GetRadarHostage( hostageIndex );

			if ( pPackage->m_bIsActive )
			{
				pPackage->SetIsDead( true );
			}

		}
		break;

		case HOSTAGE_RESCUED:
		{
			int hostageIndex = GetHostageIndexFromHostageEntityID( event->GetInt( "hostage" )  );

			if ( hostageIndex == INVALID_INDEX )
			{
				return;
			}

			SFMapOverviewIconPackage* pPackage = GetRadarHostage( hostageIndex );

			if ( pPackage->m_bIsActive )
			{
				pPackage->SetIsRescued( true );
			}

		}
		break;

		case BOMB_DEFUSED:
		{
			m_bBombDefused = true;
		}
		break;

		case BOMB_EXPLODED:
		{
			m_bBombExploded = true;
		}
		break;

		case BOMB_PLANTED:
		{
			m_nBombEntIndex = -1;
			m_bBombPlanted = true;
			m_BombPosition.z = 0;
		}
		break;

		case BOMB_PICKUP:
		{
			m_bBombDropped = false;
			m_nBombEntIndex = -1;
		}
		break;

		case BOMB_DROPPED:
		{
			m_nBombEntIndex = event->GetInt( "entindex", -1 );
			m_bBombDropped = true;
		}
		break;

		case DEFUSER_PICKUP:
		{
			int nDefuseIndex = GetDefuseIndexFromEntityID( event->GetInt( "entityid" ) );

			if ( nDefuseIndex != INVALID_INDEX )
			{
				RemoveDefuser( nDefuseIndex );
			}
		}
		break;

		case DEFUSER_DROPPED:
		{
			int nEntityID = event->GetInt( "entityid" );

			CreateDefuser( nEntityID );
		}
		break;

		case DECOY_STARTED:
		{
			if ( pLocalPlayer )
			{
				int userID = event->GetInt( "userid" );
				CBasePlayer* player =  UTIL_PlayerByUserId( userID );

				if ( player )
				{
					bool bShowGrenade = false;

					// if it was placed by a player on our team or if we are a spectator, show the grenade as a grenade icon
					// otherwise, we're going to show it as if it were a fake player
					if ( player->GetAssociatedTeamNumber() == pLocalPlayer->GetAssociatedTeamNumber() || m_bShowAll )
						bShowGrenade = true;
				
					int entityID = event->GetInt( "entityid" );
					int teamNumber = player->GetAssociatedTeamNumber();

					SFMapOverviewIconPackage* pPackage = CreateGrenade( entityID, PI_GRENADE_DECOY );

					if ( pPackage )
					{
						if ( bShowGrenade )
							pPackage->SetGrenadeType( PI_GRENADE_DECOY );
						else
						{
							pPackage->SetPlayerTeam( teamNumber );
							pPackage->SetIsSpotted( true );
						}

						pPackage->m_Position.Init( ( float )event->GetInt( "x" ), ( float )event->GetInt( "y" ), 0.0f );
						pPackage->m_Angle.Init( 0.0f, RandomFloat( 0.0f, 360.0f ), 0.0f );
						SetIconPackagePosition( pPackage );
					}
				}
			}

		}
		break;

		case DECOY_DETONATE:
		{
			int entityID = event->GetInt( "entityid" );
			int i = GetGrenadeIndexFromEntityID( entityID );
			if ( i != INVALID_INDEX )
			{
				SFMapOverviewIconPackage* pPackage = GetRadarGrenade( i );
				pPackage->SetGrenadeExpireTime( gpGlobals->curtime );
				SetIconPackagePosition( pPackage );
			}

			STEAMWORKS_TESTSECRET_AMORTIZE( 23 );
		}
		break;

		case HE_DETONATE:
			{
				int entityID = event->GetInt( "entityid" );
				int userID = event->GetInt( "userid" );
				CBasePlayer* player =  UTIL_PlayerByUserId( userID );
				if ( pLocalPlayer && player )
				{
					// if it was placed by a player on our team or if we are a spectator, show the grenade as usually
					// otherwise, we don't show it at all
					Vector vecGrenade = Vector( ( float )event->GetInt( "x" ), ( float )event->GetInt( "y" ), 0 );
					if ( (player->GetAssociatedTeamNumber() == pLocalPlayer->GetAssociatedTeamNumber() && IsEnemyCloseEnoughToShow( vecGrenade )) || m_bShowAll )
					{
						SFMapOverviewIconPackage* pPackage = CreateGrenade( entityID, PI_GRENADE_HE );
						if ( pPackage )
						{
							pPackage->SetGrenadeType( PI_GRENADE_HE );
							pPackage->SetGrenadeExpireTime( gpGlobals->curtime );		
							pPackage->m_Position.Init( vecGrenade.x, vecGrenade.y, 0.0f );
							pPackage->m_Angle.Init( 0.0f, RandomFloat( 0.0f, 360.0f ), 0.0f );
							SetIconPackagePosition( pPackage );
						}
					}
				}

				STEAMWORKS_TESTSECRET_AMORTIZE( 19 );
			}
			break;

		case FLASH_DETONATE:
			{
				int entityID = event->GetInt( "entityid" );
				int userID = event->GetInt( "userid" );
				CBasePlayer* player =  UTIL_PlayerByUserId( userID );
				if ( pLocalPlayer && player )
				{
					// if it was placed by a player on our team or if we are a spectator, show the grenade as usually
					// otherwise, we don't show it at all
					Vector vecGrenade = Vector( ( float )event->GetInt( "x" ), ( float )event->GetInt( "y" ), 0 );
					if ( (player->GetAssociatedTeamNumber() == pLocalPlayer->GetAssociatedTeamNumber() && IsEnemyCloseEnoughToShow( vecGrenade )) || m_bShowAll )
					{
						SFMapOverviewIconPackage* pPackage = CreateGrenade( entityID, PI_GRENADE_FLASH );
						if ( pPackage )
						{
							pPackage->SetGrenadeType( PI_GRENADE_FLASH );
							pPackage->SetGrenadeExpireTime( gpGlobals->curtime );		
							pPackage->m_Position.Init( vecGrenade.x, vecGrenade.y, 0.0f );
							pPackage->m_Angle.Init( 0.0f, RandomFloat( 0.0f, 360.0f ), 0.0f );
							SetIconPackagePosition( pPackage );
						}
					}
				}

				STEAMWORKS_TESTSECRET_AMORTIZE( 17 );
			}
			break;

		case SMOKE_DETONATE:
			{
				int entityID = event->GetInt( "entityid" );
				int userID = event->GetInt( "userid" );
				CBasePlayer* player =  UTIL_PlayerByUserId( userID );
				if ( pLocalPlayer && player )
				{
					// if it was placed by a player on our team or if we are a spectator, show the grenade as usually
					// otherwise, we don't show it at all
					Vector vecGrenade = Vector( ( float )event->GetInt( "x" ), ( float )event->GetInt( "y" ), 0 );
					if ( (player->GetAssociatedTeamNumber() == pLocalPlayer->GetAssociatedTeamNumber() && IsEnemyCloseEnoughToShow( vecGrenade )) || m_bShowAll )
					{
						SFMapOverviewIconPackage* pPackage = CreateGrenade( entityID, PI_GRENADE_SMOKE );

						if ( pPackage )
						{
							pPackage->SetGrenadeType( PI_GRENADE_SMOKE );
							pPackage->m_Position.Init( vecGrenade.x, vecGrenade.y, 0.0f );
							pPackage->m_Angle.Init( 0.0f, RandomFloat( 0.0f, 360.0f ), 0.0f );
							SetIconPackagePosition( pPackage );
						}
					}
				}
			}
			break;
			
		case SMOKE_EXPIRE:
			{
				int entityID = event->GetInt( "entityid" );
				int i = GetGrenadeIndexFromEntityID( entityID );
				if ( i != INVALID_INDEX )
				{
					SFMapOverviewIconPackage* pPackage = GetRadarGrenade( i );
					pPackage->SetGrenadeExpireTime( gpGlobals->curtime );
					SetIconPackagePosition( pPackage );
				}

				STEAMWORKS_TESTSECRET_AMORTIZE( 11 );
			}
			break;

		case MOLOTOV_DETONATE:
			{
				int entityID = event->GetInt( "entityid" );
				int userID = event->GetInt( "userid" );
				CBasePlayer* player =  UTIL_PlayerByUserId( userID );
				if ( pLocalPlayer && player )
				{
					// if it was placed by a player on our team or if we are a spectator, show the grenade as usually
					// otherwise, we don't show it at all
					Vector vecGrenade = Vector( ( float )event->GetInt( "x" ), ( float )event->GetInt( "y" ), 0 );
					if ( (player->GetAssociatedTeamNumber() == pLocalPlayer->GetAssociatedTeamNumber() && IsEnemyCloseEnoughToShow( vecGrenade )) || m_bShowAll )
					{
						SFMapOverviewIconPackage* pPackage = CreateGrenade( entityID, PI_GRENADE_MOLOTOV );

						if ( pPackage )
						{
							pPackage->SetGrenadeType( PI_GRENADE_MOLOTOV );
							pPackage->m_Position.Init( vecGrenade.x, vecGrenade.y, 0.0f );
							pPackage->m_Angle.Init( 0.0f, RandomFloat( 0.0f, 360.0f ), 0.0f );
							SetIconPackagePosition( pPackage );
						}
					}
				}
			}
			break;

		case MOLOTOV_EXPIRE:
			{
				int entityID = event->GetInt( "entityid" );
				int i = GetGrenadeIndexFromEntityID( entityID );
				if ( i != INVALID_INDEX )
				{
					SFMapOverviewIconPackage* pPackage = GetRadarGrenade( i );
					pPackage->SetGrenadeExpireTime( gpGlobals->curtime );
					SetIconPackagePosition( pPackage );
				}

				STEAMWORKS_TESTSECRET_AMORTIZE( 19 );
			}
			break;

		case BOT_TAKEOVER:
		{
			C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
			if ( pLocalPlayer )
			{
				int userID = event->GetInt( "userid" );
				int localID = pLocalPlayer->GetUserID();

				if (localID == userID )
				{
					ResetRadar( false );
				}
			}

		}
		break;

		default:
			break;
	}
}
// 
// 
// /*****************************************************
//  * these set lazy update the icons and text based
//  * on the values in the state variables
//  */
// 

void SFMapOverview::SetupIconsFromStates( void )
{
	uint64 newFlags = 0;	
	
	if ( CSGameRules()->IsBombDefuseMap() )
	{
		// check to see if the bomb exists before assuming the first exists and trying to get data from it
		if ( !m_bBombDefused && m_bBombPlanted && g_PlantedC4s.Count() > 0 )
		{
			float fPercent = ( g_PlantedC4s[0]->GetDetonationProgress() * 100.0f );

			if ( fPercent > 60.0f )
			{
				newFlags |= 1 << RI_BOMB_IS_PLANTED;
			}
			else if ( fPercent > 30.0f )
			{
				newFlags |= 1 << RI_BOMB_IS_PLANTED_MEDIUM;
			}
			else if ( fPercent > 0.0f )
			{
				newFlags |= 1 << RI_BOMB_IS_PLANTED_FAST;
			}			
		}

		if ( m_fBombAlpha > 0.0f )
		{
			newFlags |= 1 << RI_BOMB_ICON_PACKAGE;
			if ( m_bShowBombHighlight )
			{
				if ( m_bBombPlanted )
				{
					newFlags |= 1 << RI_BOMB_ICON_PLANTED;
				}
				else
				{
					newFlags |= 1 << RI_BOMB_ICON_DROPPED;
				}

				C_CSPlayer *pLocalOrObserver = GetLocalOrInEyeCSPlayer();
				if ( pLocalOrObserver )
				{
					if ( m_BombPosition.z > pLocalOrObserver->GetAbsOrigin().z + 180 )
						newFlags |= 1 << RI_BOMB_ICON_BOMB_ABOVE;
					else if ( m_BombPosition.z < pLocalOrObserver->GetAbsOrigin().z - 180 )
						newFlags |= 1 << RI_BOMB_ICON_BOMB_BELOW;
				}
			}
	
			C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
			if( pLocalPlayer != NULL )
			{
				if ( pLocalPlayer->GetAssociatedTeamNumber() == TEAM_TERRORIST )
				{
					newFlags |= 1 << RI_BOMB_ICON_BOMB_T;
				}
				else
				{
					newFlags |= 1 << RI_BOMB_ICON_BOMB_CT;
				}
			}

			Vector mapPosition;

			WorldToRadar( m_BombPosition, mapPosition );

			Vector newMapPosition = mapPosition;
			newMapPosition -= m_RadarViewpointMap;

			ScaleformDisplayInfo displayInfo;
			displayInfo.SetAlpha( m_fBombAlpha * 100.0f );
			int nBombCarryOffset = 0;
			if ( ((newFlags & (1 << RI_BOMB_ICON_BOMB_T)) || (newFlags & (1 << RI_BOMB_ICON_BOMB_CT))) && !(newFlags & (1 << RI_BOMB_ICON_PLANTED)) )
			{
				nBombCarryOffset = 6;
			}

			displayInfo.SetX( mapPosition.x );
			displayInfo.SetY( mapPosition.y + nBombCarryOffset );
			displayInfo.SetRotation( -m_RadarRotation );
			
			assert( m_AllIcons[RI_BOMB_ICON_PACKAGE] );
			m_pScaleformUI->Value_SetDisplayInfo( m_AllIcons[RI_BOMB_ICON_PACKAGE], &displayInfo );
		}
	}
	else if ( CSGameRules()->IsHostageRescueMap() )
	{
		if ( m_bShowingHostageZone )
		{
			newFlags |= 1 << RI_IN_HOSTAGE_ZONE;
		}
	}

	if ( m_bShowingDashboard )
		newFlags |= 1 << RI_DASHBOARD;

	SetVisibilityFlags( newFlags );	
}

void SFMapOverview::SetVisibilityFlags( uint64 newFlags )
{
	newFlags &= ( ( 1 << RI_NUM_ICONS )-1 );

	uint64 diffFlags = m_iCurrentVisibilityFlags ^ newFlags;

	if ( diffFlags )
	{
		for ( int i = 0; i < RI_NUM_ICONS && ( diffFlags != 0 ); i++, diffFlags >>= 1 )
		{
			if ( diffFlags & 1 )
			{
				if ( m_AllIcons[i] )
					m_pScaleformUI->Value_SetVisible( m_AllIcons[i], ( newFlags & ( 1ll << i ) ) != 0 );
			}
		}

		m_iCurrentVisibilityFlags = newFlags;
	}
}

void SFMapOverview::SetLocationText( wchar_t *newText )
{
	if ( newText == NULL )
	{
		newText = L"";
	}

	if ( V_wcscmp( newText, m_wcLocationString ) )
	{
		V_wcsncpy( m_wcLocationString, newText, sizeof( wchar_t )*MAX_LOCATION_TEXT_LENGTH );

		if ( m_LocationText )
		{
			WITH_SLOT_LOCKED
				m_LocationText->SetText( m_wcLocationString );
		}
	}
}

// 
// /********************************************
//  * "drawing" code.  Actually just sets position / alpha
//  * of the flash objects
//  */
// 
void SFMapOverview::WorldToRadar( const Vector& ptin, Vector& ptout )
{
	ptout.x = ( ptin.x - m_MapOrigin.x ) * m_fWorldToRadarScale;
	ptout.y = ( m_MapOrigin.y - ptin.y ) * m_fWorldToRadarScale;
	ptout.z = 0;
}

void SFMapOverview::RadarToWorld( const Vector& ptin, Vector& ptout )
{
	ptout.x = ( ptin.x + m_MapOrigin.x ) / m_fWorldToRadarScale;
	ptout.y = ( m_MapOrigin.y + ptin.y ) / m_fWorldToRadarScale;
	ptout.z = 0;
}


void SFMapOverview::PositionRadarViewpoint( void )
{
	if ( !m_bFlashReady )
	{
		return;
	}

	int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();

	CBasePlayer * pPlayer = CBasePlayer::GetLocalPlayer();

	if( pPlayer == NULL )
	{
		pPlayer = GetSplitScreenViewPlayer( nSlot );
	}

	// [jbright] Using GetLocalOrigin addresses an issue which
	// causes the center player indicator to not stay centered
	// on the radar. This solution causes the radar to go jump
	// around while in observer mode, so in those cases rely on
	// MainViewOrigin.
// 	if ( pPlayer && m_iObserverMode == OBS_MODE_NONE )
// 	{
// 		m_RadarViewpointWorld = pPlayer->GetLocalOrigin();
// 	}
// 	else
// 	{
// 		m_RadarViewpointWorld = MainViewOrigin( nSlot );
// 	}

	// Get the world's extent
// 	C_World *world = GetClientWorldEntity();
// 	if ( !world )
// 		return;
// 
// 	Vector worldCenter = ( world->m_WorldMins + world->m_WorldMaxs ) * 0.5f;

	m_RadarViewpointWorld = Vector( m_MapOrigin.x, m_MapOrigin.y, 0 );//worldCenter;
	//m_RadarViewpointWorld.z = 0;

	WorldToRadar( m_RadarViewpointWorld, m_RadarViewpointMap );

	m_RadarRotation = 0;

	ScaleformDisplayInfo displayInfo;

	if ( m_MapRotation )
	{
		displayInfo.SetRotation( m_RadarRotation );
		m_pScaleformUI->Value_SetDisplayInfo( m_MapRotation, &displayInfo );

		if ( m_MapTranslation )
		{
			displayInfo.Clear();
			displayInfo.SetX( -(m_fMapSize/2) );
			displayInfo.SetY( -(m_fMapSize/2) );

			m_pScaleformUI->Value_SetDisplayInfo( m_MapTranslation, &displayInfo );
		}
	}

	if ( m_IconRotation )
	{
		displayInfo.Clear();
		displayInfo.SetRotation( m_RadarRotation );
		m_pScaleformUI->Value_SetDisplayInfo( m_IconRotation, &displayInfo );

		if ( m_IconTranslation )
		{
			displayInfo.Clear();
			displayInfo.SetX( -(m_fMapSize/2) - 1 );
			displayInfo.SetY( -(m_fMapSize/2) - 1 );

			m_pScaleformUI->Value_SetDisplayInfo( m_IconTranslation, &displayInfo );
		}
	}

}

void SFMapOverview::PlaceGoalIcons( void )
{
	C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
	if ( !pCSPR )
	{
		return;
	}

	SFMapOverviewGoalIcon* pwalk = m_GoalIcons;
	Vector mapPosition;
	ScaleformDisplayInfo displayInfo;

	for ( int i = 0; i < m_iNumGoalIcons; i++ )
	{
		WorldToRadar( pwalk->m_Position, mapPosition );

		if ( pwalk->m_Icon )
		{
			Vector newMapPosition = mapPosition;
			newMapPosition -= m_RadarViewpointMap;

			displayInfo.SetX( mapPosition.x );
			displayInfo.SetY( mapPosition.y );
			displayInfo.SetRotation( -m_RadarRotation );

			m_pScaleformUI->Value_SetDisplayInfo( pwalk->m_Icon, &displayInfo );
		}
		pwalk++;
	}

}

void SFMapOverview::SetIconPackagePosition( SFMapOverviewIconPackage* pPackage )
{
	if ( !m_bFlashReady )
		return;

	Vector mapPosition;
	ScaleformDisplayInfo displayInfo;
	float mapAngle;

	WorldToRadar( pPackage->m_Position, mapPosition );

	Vector newMapPosition = mapPosition;
	newMapPosition -= m_RadarViewpointMap;
	pPackage->SetIsOffMap( false );
	if ( pPackage->m_bIsDead || !pPackage->m_bIsSpotted )
	{
		mapAngle = -m_RadarRotation;
	}
	else
	{
		mapAngle = -pPackage->m_Angle[YAW]+90;
	}

	displayInfo.SetX( mapPosition.x );
	displayInfo.SetY( mapPosition.y );
	float flScale = mapoverview_icon_scale.GetFloat();
	displayInfo.SetXScale( 120 * flScale );
	displayInfo.SetYScale( 120 * flScale );
	m_pScaleformUI->Value_SetDisplayInfo( pPackage->m_IconPackage, &displayInfo );

	// only rotated the sublayer, the stuff on top doesn't want to be rotated
	//SFVALUE rotatedIcon;
	//rotatedIcon = m_pScaleformUI->Value_GetMember( pPackage->m_IconPackage, "RotatedLayer" );
	if ( pPackage->m_IconPackageRotate )
	{
		ScaleformDisplayInfo rotatedDisplayInfo;
		rotatedDisplayInfo.SetRotation( mapAngle );
		m_pScaleformUI->Value_SetDisplayInfo( pPackage->m_IconPackageRotate, &rotatedDisplayInfo );
	}

	pPackage->SetupIconsFromStates();
}

void SFMapOverview::PlaceHostages( void )
{
	if ( !m_bFlashReady )
	{
		return;
	}

	if ( !CSGameRules()->IsHostageRescueMap() )
	{
		return;
	}


	C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
	if ( !pCSPR )
	{
		return;
	}

	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
	if( pLocalPlayer == NULL )
	{
		return;
	}

	int iNumLiveHostages = 0;
	int iNumDeadHostages = 0;
	int iNumMovingHostages = 0;
	int iNumRescuedHostages = 0;

	bool bIsTerrorist = ( pLocalPlayer->GetAssociatedTeamNumber() == TEAM_TERRORIST );

	if ( bIsTerrorist )
	{
		// Taking over a bot after switching to the terrorist team results in
		// the hostage indicators remaining visible, so we need to remove them.
		for ( int i = 0; i <= m_iLastHostageIndex; i++ )
		{
			if ( GetRadarHostage( i )->m_bIsActive )
				RemoveHostage( i );
		}

		// we also want to show the number of hostages that are still alive
		// and unrescued
		for( int i=0; i < MAX_HOSTAGES; i++ )
		{
			if( pCSPR->IsHostageAlive( i ) )
				iNumLiveHostages++;
		}

	}
	else
	{
	
		// T's can now always see basic hostage info (alive, dead) but not moving or rescued status
		/*
		bool bCanShowHostages = m_bShowAll || ( pLocalPlayer->GetTeamNumber() == TEAM_CT );

		if ( !bCanShowHostages )
		{
			return;
		}
		*/

		// Update hostage status
		for( int i=0; i < MAX_HOSTAGES; i++ )
		{
			int nEntityID = pCSPR->GetHostageEntityID( i );

			if ( nEntityID > 0 )
			{
				SFMapOverviewIconPackage* pHostage =  NULL;

				int nHostageIndex = GetHostageIndexFromHostageEntityID( nEntityID );

				
				if ( nHostageIndex == INVALID_INDEX )
				{
					// Create the hostage in next available slot
					for ( nHostageIndex = 0; nHostageIndex < MAX_HOSTAGES; nHostageIndex++ )
					{
						if ( !m_Hostages[nHostageIndex].m_bIsActive )
						{
							pHostage = CreateHostage( nHostageIndex );
							pHostage->SetPlayerTeam( TEAM_UNASSIGNED );
							pHostage->m_iEntityID =  nEntityID;
							break;
						}
					}
				}
				else
				{
					pHostage = GetRadarHostage( nHostageIndex );
				}


				if ( pHostage )
				{
					if( pCSPR->IsHostageAlive( i ) )
					{
						if ( !pHostage->m_bIsActive )
						{
							
						}

						pHostage->SetIsDead( false );

						if ( pCSPR->IsHostageFollowingSomeone( i ) )
						{
							iNumMovingHostages++;
							pHostage->SetIsMovingHostage( true );
						}
						else
						{
							iNumLiveHostages++;
							pHostage->SetIsMovingHostage( false );
						}
					}
					else if ( i <= m_iLastHostageIndex && pHostage->m_bIsActive )
					{
						if ( pHostage->m_bIsRescued )
						{
							iNumRescuedHostages++;
						}
						else
						{
							iNumDeadHostages++;
						}

						pHostage->SetIsDead( true );
						pHostage->SetIsMovingHostage( false );
					}
				}
			}
		}

		// Update hostage positions
		for( int i = 0; i < MAX_HOSTAGES; i++ )
		{
			SFMapOverviewIconPackage* pHostage = GetRadarHostage( i );

			if ( pHostage->m_bIsActive )
			{
				C_BaseEntity * pEntity = ClientEntityList().GetBaseEntity( pHostage->m_iEntityID );

				if ( pEntity && !pEntity->IsDormant() )
				{
					Assert( dynamic_cast<CHostage*>( pEntity ) );

					pHostage->m_Position = pEntity->GetNetworkOrigin();
				}

				pHostage->SetIsSpotted( true );
				SetIconPackagePosition( pHostage );
			}
		}
	}

	int hostageIndex = 0;

	for ( int i = 0; i < iNumDeadHostages; i++ )
	{
		m_HostageStatusIcons[hostageIndex++].SetStatus( SFMapOverviewHostageIcons::HI_DEAD );
	}

	for ( int i = 0; i < iNumRescuedHostages; i++ )
	{
		m_HostageStatusIcons[hostageIndex++].SetStatus( SFMapOverviewHostageIcons::HI_RESCUED );
	}

	for ( int i = 0; i < iNumMovingHostages; i++ )
	{
		m_HostageStatusIcons[hostageIndex++].SetStatus( SFMapOverviewHostageIcons::HI_TRANSIT );
	}

	for ( int i = 0; i < iNumLiveHostages; i++ )
	{
		m_HostageStatusIcons[hostageIndex++].SetStatus( SFMapOverviewHostageIcons::HI_ALIVE );
	}

	for ( ; hostageIndex < MAX_HOSTAGES && m_HostageStatusIcons[hostageIndex].m_IconPackage != NULL; hostageIndex++ )
	{
		m_HostageStatusIcons[hostageIndex].SetStatus( SFMapOverviewHostageIcons::HI_UNUSED );
	}
}

void SFMapOverview::UpdateAllDefusers( void )
{
	if ( !m_bTrackDefusers )
	{
		return;
	}

	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
	if( pLocalPlayer == NULL )
	{
		return;
	}

	for ( int i = 0; i <= m_iLastDefuserIndex; i++ )
	{
		SFMapOverviewIconPackage * pPackage = GetRadarDefuser( i );

		if ( pPackage && pPackage->m_bIsActive )
		{
			C_BaseEntity * pEntity = ClientEntityList().GetBaseEntity( pPackage->m_iEntityID );

			bool bSpotted = ( pLocalPlayer->GetAssociatedTeamNumber() == TEAM_CT || ( pEntity && pEntity->IsSpotted() ) || m_EntitySpotted.Get( pPackage->m_iEntityID ) );

			pPackage->SetIsSpotted( bSpotted );

			if ( bSpotted && pEntity && !pEntity->IsDormant() )
			{
				SetDefuserPos( pPackage->m_iEntityID,
							   pEntity->GetNetworkOrigin().x,
							   pEntity->GetNetworkOrigin().y,
							   pEntity->GetNetworkOrigin().z,
							   pEntity->GetNetworkAngles().y );
			}
		}

		// update radar position and visibility
		if ( pPackage && pPackage->m_bIsActive )
		{
			SetIconPackagePosition( pPackage );
		}
	}
}





void SFMapOverview::PlacePlayers( void )
{
	if ( !m_bFlashReady )
	{
		return;
	}

	C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
	if ( !pCSPR )
	{
		return;
	}

	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
	if( pLocalPlayer == NULL )
	{
		return;
	}

	int localPlayerIndex = pLocalPlayer->entindex()-1;

	if ( localPlayerIndex == INVALID_INDEX )
	{
		return;
	}

	int localTeamNumber = pLocalPlayer->GetAssociatedTeamNumber();

	SFMapOverviewIconPackage* pwalk = m_Players;
	int playerIndex;

	for ( int i = 0; i <= m_iLastPlayerIndex; i++, pwalk++ )
	{
		if ( pwalk->m_IconPackage && pwalk->m_bIsActive )
		{
			playerIndex = i+1;

			C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( playerIndex ) );

			bool playerIsActive = pPlayer != NULL && !pPlayer->IsDormant();
			int nIsAboveOrBelow = R_SAMELEVEL;

			// we do all the pCSPR stuff because the player may not have been given
			// to us by the server yet.  If that's the case, we can't use the player
			// pointer to find anything out, we have to use the PCSPR which keeps some
			// of this data ( like team numbers, spotted, hasC4 etc.  The dormant means
			// that it's not in our view

			if ( pCSPR->IsConnected( playerIndex ) )
			{
				pwalk->m_Health = pCSPR->GetHealth( playerIndex );

				if ( !pCSPR->IsAlive( playerIndex ) )
				{
					pwalk->m_Health = 0;
					if( pCSPR->GetControlledByPlayer( playerIndex ) )
					{
						pwalk->SetIsControlledBot();
					}
					else
					{
						pwalk->SetIsDead( true );
					}
				}
				else
				{
					pwalk->SetIsDead( false );

					//it's hard to figure out if this player has been spotted, and if spotted has enough info to be
					//shown.

					bool bSameTeam = ( localTeamNumber == pCSPR->GetTeam( playerIndex ) );
					bool bObservingTarget = pLocalPlayer->GetObserverTarget() && (pLocalPlayer->GetObserverTarget() == pPlayer);

					bool bHasValidPosition = playerIsActive || ( pwalk->m_Position.x != 0 || pwalk->m_Position.y != 0 );

					Vector vecEnemy = pwalk->m_Position;
					bool bPlayerSpotted = bObservingTarget || (( m_EntitySpotted.Get( playerIndex ) || ( playerIsActive && pPlayer->IsSpotted() ) ) 
						&& (m_bShowAll || (!bSameTeam && IsEnemyCloseEnoughToShow( vecEnemy ))));

					if ( pPlayer && bHasValidPosition && ( bSameTeam  || m_bShowAll || bPlayerSpotted ) )
					{
						pwalk->SetIsSpotted( true );

						if ( playerIsActive && pPlayer->HasDefuser() )
						{
							// attach a defuser icon to this player if one does not already exist
							if ( GetDefuseIndexFromEntityID( playerIndex ) == INVALID_INDEX ) 
							{
								CreateDefuser( playerIndex );
							}
						}

						if ( playerIsActive && pPlayer->HasC4() && ( bPlayerSpotted || m_bShowAll ) )
						{
							m_bBombIsSpotted = true;
							m_BombPosition = pwalk->m_Position;
						}

						// set is low health
						pwalk->SetIsLowHealth( (playerIsActive && pPlayer->GetHealth() < 40) );

						// set is selected
						C_CSPlayer *pLocalOrObserver = ToCSPlayer( pLocalPlayer->GetObserverTarget() );
						pwalk->SetIsSelected( pLocalOrObserver && pPlayer == pLocalOrObserver );
						
						// set is flashed
						pwalk->SetIsFlashed( pPlayer->IsBlinded() );	

						// set is firing
						pwalk->SetIsFiring( (pPlayer->GetLastFiredWeaponTime() + 0.2) >= gpGlobals->curtime );					
					}
					else
					{
						pwalk->SetIsSpotted( false );
					}
				}

				pwalk->SetPlayerTeam( pCSPR->GetTeam( playerIndex ) );
				pwalk->SetIsOnLocalTeam( localTeamNumber == pCSPR->GetTeam( playerIndex ) );

				pwalk->SetIsPlayer( i == localPlayerIndex );
				pwalk->SetIsSpeaking( GetClientVoiceMgr()->IsPlayerSpeaking( playerIndex ) && GetClientVoiceMgr()->IsPlayerAudible( playerIndex ) );

				UpdatePlayerNameAndNumber( pwalk );
			}
			else
			{
				pwalk->SetIsSpotted( false );
				pwalk->SetIsSpeaking( false );
			}

			// when a player dies the system reports the player's position as the position of
			// the spectator camera.  If we let that happen, the dead player's X migrates from
			// the point they died to follow another player's position.
			//
			// so, never update the icon position for a dead player
			if ( playerIsActive && pwalk->m_bIsSpotted && !pwalk->m_bIsDead )
			{
				// dkorus and pfreese:  Changed from local origin and local angles to last networked version to address jitter issues for pax demo 2011
				pwalk->m_Position = pPlayer->GetNetworkOrigin();

				// only set the angle of the icon if the player isn't above or below us
				if ( nIsAboveOrBelow == R_SAMELEVEL )
					pwalk->m_Angle = pPlayer->GetLocalAngles();
				else
				{
					int nSlot = GET_ACTIVE_SPLITSCREEN_SLOT();
					pwalk->m_Angle = MainViewAngles( nSlot );
				}

				if ( pPlayer->HasC4() )
				{
					m_BombPosition = pwalk->m_Position;
				}
			}

			SetIconPackagePosition( pwalk );
		}
	}
}

bool SFMapOverview::IsEnemyCloseEnoughToShow( Vector vecEnemyPos )
{
	//double check if spotted based on distance
	// we're going to check the distance of this guy from all of the people on our team
	// if they are outside the radius (more or less) of what the radar would allow us to see, consider them not spotted
	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
	if( !pLocalPlayer )
		return false;

	C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
	if ( !pCSPR )
		return false;

	int localTeamNumber = pLocalPlayer->GetAssociatedTeamNumber();

	bool bTooFar = true;
	SFMapOverviewIconPackage* pTeammate = m_Players;
	for ( int j = 0; j <= (m_iLastPlayerIndex); j++, pTeammate++ )
	{
		if ( pCSPR->IsConnected( (j+1) ) && localTeamNumber == pCSPR->GetTeam( (j+1) ) )
		{
			Vector toEnemy = pTeammate->m_Position - vecEnemyPos;
			float dist = toEnemy.LengthSqr();
			if ( dist <= NOTSPOTTEDRADIUS*NOTSPOTTEDRADIUS )
			{
				bTooFar = false;;
			}
		}
	}

	return !bTooFar;
}

void SFMapOverview::UpdateMiscIcons( void )
{
	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
	if ( !pLocalPlayer )
	{
		return;
	}

	// We show the entire dashboard in spectator mode now, so you can see bomb/hostage status, etc.
	m_bShowingDashboard = true;

	// Uncomment this line to disable the radar dashboard in spectator mode:
	// m_bShowingDashboard = ( pLocalPlayer->GetObserverMode() == OBS_MODE_NONE );

	const char *pszLocation = pLocalPlayer->GetLastKnownPlaceName();

	if ( pszLocation )
	{
		SetLocationText( g_pVGuiLocalize->Find( pszLocation ) );
	}
	else
	{
		SetLocationText( NULL );
	}


	C_CS_PlayerResource *pCSPR = ( C_CS_PlayerResource* )GameResources();
	if ( !pCSPR )
	{
		return;
	}

	m_fBombAlpha = 0.0f;
	m_fDefuserAlpha = 0.0f;

	if ( CSGameRules()->IsBombDefuseMap() )
	{
		if ( m_bBombPlanted )
		{
			FOR_EACH_VEC( g_PlantedC4s, iBomb )
			{
				C_PlantedC4 * pC4 = g_PlantedC4s[iBomb];
				if ( pC4 && pC4->IsBombActive() )
				{
					bool bLocalPlayerCanSeeBomb =( pLocalPlayer->GetAssociatedTeamNumber() == TEAM_TERRORIST || m_bShowAll || ( pC4 && !pC4->IsDormant() && pC4->IsSpotted() ) && IsEnemyCloseEnoughToShow( pC4->GetNetworkOrigin() ) );
					if ( bLocalPlayerCanSeeBomb && pC4 && !pC4->IsDormant() )
					{
						m_bBombIsSpotted = true;
						m_BombPosition = pC4->GetNetworkOrigin();
					}
				}
			}
		}
		if ( m_nBombEntIndex != -1 && ( !m_bBombIsSpotted || m_bBombDropped ) )
		{
			C_BaseEntity * pEntity = ClientEntityList().GetBaseEntity( m_nBombEntIndex );

			bool bLocalPlayerCanSeeBomb = pLocalPlayer->GetAssociatedTeamNumber() == TEAM_TERRORIST || m_bShowAll || ( pEntity && !pEntity->IsDormant() && pEntity->IsSpotted() && IsEnemyCloseEnoughToShow( pEntity->GetNetworkOrigin() ) );
			if ( bLocalPlayerCanSeeBomb && pEntity && !pEntity->IsDormant() )
			{
				Assert( pEntity && FClassnameIs( pEntity, "weapon_c4" ) );
				m_bBombIsSpotted = true;
				m_BombPosition = pEntity->GetNetworkOrigin();
			}
		}

		float now = gpGlobals->curtime;
		bool drawBomb = false;

		bool bBombPositionIsValid = ( m_BombPosition.x != 0 || m_BombPosition.y != 0 );

		if ( bBombPositionIsValid && !m_bBombExploded && m_bBombIsSpotted )
		{
			drawBomb = true;
			m_fBombSeenTime = now;
			m_fBombAlpha = 1.0f;
		}
		else if ( m_bBombExploded )
		{
			m_fBombAlpha = 0;
			m_fBombSeenTime = TIMER_INIT;
		}
		else
		{
			m_fBombAlpha = clamp( 1.0f - ( now - m_fBombSeenTime )/BOMB_FADE_TIME, 0.0f, 1.0f );
			if ( m_fBombAlpha > 0 )
			{
				drawBomb = true;
			}
			else
			{
				m_fBombSeenTime = TIMER_INIT;
			}
		}

		if ( drawBomb )
		{
			m_bShowBombHighlight = !m_bBombDefused && ( m_bBombPlanted || m_bBombDropped );
		}
	}
	else if ( CSGameRules()->IsHostageRescueMap() )
	{
		m_bShowingHostageZone = pLocalPlayer->IsInHostageRescueZone();
	}

}

void SFMapOverview::ApplySpectatorModes( void )
{
	C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();

	m_bShowAll = false;
	m_iObserverMode = OBS_MODE_NONE;

	if ( pLocalPlayer )
	{
		m_iObserverMode = pLocalPlayer->GetObserverMode();
		if ( pLocalPlayer->IsSpectator()	|| pLocalPlayer->IsHLTV() )
		{
			m_bShowAll = true;
			return;
		}

	}

// 	if ( m_iObserverMode != OBS_MODE_NONE )
// 	{
// 		// if we're observing in casual, then show everyone everywhere
// 		ConVarRef mp_forcecamera( "mp_forcecamera" );
// 		m_bShowAll = mp_forcecamera.GetInt() == OBS_ALLOW_ALL;
// 	}

}

void SFMapOverview::UpdateGrenades( void )
{
	for ( int i = 0; i <= m_iLastGrenadeIndex; i++ )
	{
		SFMapOverviewIconPackage* pPackage = GetRadarGrenade( i );

		if ( pPackage && pPackage->m_bIsActive )
		{
			SetIconPackagePosition( pPackage );
			if ( !pPackage->IsVisible() )
			{
				RemoveGrenade( i );
			}
		}
	}
}



void SFMapOverview::ProcessInput( void )
{
	LazyCreateGoalIcons();

	LazyCreatePlayerIcons();

	ApplySpectatorModes();
	
	PositionRadarViewpoint();

	PlaceGoalIcons();
	
	PlacePlayers();

	PlaceHostages();

	UpdateGrenades();

	UpdateAllDefusers();

	UpdateMiscIcons();

	SetupIconsFromStates();
}

static inline bool Helper_AllowMapDrawing()
{
	if ( mapoverview_allow_client_draw.GetBool() )
		return true;

	if ( sv_competitive_official_5v5.GetBool() )
		return true;

	if ( C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer() )
	{
		if ( pPlayer->IsHLTV() )
			return true;

		if ( pPlayer->IsSpectator() )
		{
			if ( CSGameRules() && CSGameRules()->IsQueuedMatchmaking() )
				return true;
		}
	}

	return false;
}

void SFMapOverview::AllowMapDrawing( SCALEFORM_CALLBACK_ARGS_DECL )
{
	bool bAllow = Helper_AllowMapDrawing();
	m_pScaleformUI->Params_SetResult( obj, bAllow );
}

void SFMapOverview::GetWorldDistance( SCALEFORM_CALLBACK_ARGS_DECL )
{
	int x1 = ( float )pui->Params_GetArgAsNumber( obj, 0 );
	int y1 = ( float )pui->Params_GetArgAsNumber( obj, 1 );
	int x2 = ( float )pui->Params_GetArgAsNumber( obj, 2 );
	int y2 = ( float )pui->Params_GetArgAsNumber( obj, 3 );

	Vector vecStart;
	Vector vecEnd;
	RadarToWorld( Vector( x1, y1, 0 ), vecStart );
	RadarToWorld( Vector( x2, y2, 0 ), vecEnd );

	float flDist = vecStart.AsVector2D().DistTo( vecEnd.AsVector2D() );

	m_pScaleformUI->Params_SetResult( obj, flDist );
}

/*
void SFMapOverview::GetNavPath( SCALEFORM_CALLBACK_ARGS_DECL )
{
	int x1 = ( float )pui->Params_GetArgAsNumber( obj, 0 );
	int y1 = ( float )pui->Params_GetArgAsNumber( obj, 1 );
	int x2 = ( float )pui->Params_GetArgAsNumber( obj, 2 );
	int y2 = ( float )pui->Params_GetArgAsNumber( obj, 3 );

	Vector vecStart;
	Vector vecEnd;
	RadarToWorld( Vector( x1, y1, 0 ), vecStart );
	RadarToWorld( Vector( x2, y2, 0 ), vecEnd );

	CNavArea *navStartArea = TheNavMesh->GetNearestNavArea( vecStart );
	CNavArea *navEndArea = TheNavMesh->GetNearestNavArea( vecEnd );

	CNavArea *goalArea = NULL;
	NavAreaBuildPath( tArea, ctArea, NULL, cost, &goalArea );

	ShortestPathCost cost = ShortestPathCost();
	float dist_left = NavAreaTravelDistance( TheNavMesh->GetNearestNavArea( ( *left )->GetAbsOrigin() ),
											 TheNavMesh->GetNearestNavArea( CSGameRules()->m_vecMainCTSpawnPos ),
											 cost );

	float dist_right = NavAreaTravelDistance( TheNavMesh->GetNearestNavArea( ( *right )->GetAbsOrigin() ),
											  TheNavMesh->GetNearestNavArea( CSGameRules()->m_vecMainCTSpawnPos ),
											  cost );

	//bool bAllow = Helper_AllowMapDrawing();
	//m_pScaleformUI->Params_SetResult( obj, bAllow );
}
*/