summaryrefslogtreecommitdiff
path: root/game/client/cstrike/VGUI/cstrikespectatorgui.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/cstrike/VGUI/cstrikespectatorgui.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'game/client/cstrike/VGUI/cstrikespectatorgui.cpp')
-rw-r--r--game/client/cstrike/VGUI/cstrikespectatorgui.cpp2324
1 files changed, 2324 insertions, 0 deletions
diff --git a/game/client/cstrike/VGUI/cstrikespectatorgui.cpp b/game/client/cstrike/VGUI/cstrikespectatorgui.cpp
new file mode 100644
index 0000000..9c633c1
--- /dev/null
+++ b/game/client/cstrike/VGUI/cstrikespectatorgui.cpp
@@ -0,0 +1,2324 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "cstrikespectatorgui.h"
+#include "hud.h"
+#include "cs_shareddefs.h"
+
+#include <vgui/ILocalize.h>
+#include <vgui/ISurface.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 <vgui_controls/AnimationController.h>
+#include "voice_status.h"
+#include "hud_radar.h"
+
+using namespace vgui;
+DECLARE_HUDELEMENT( CCSMapOverview )
+
+extern ConVar overview_health;
+extern ConVar overview_names;
+extern ConVar overview_tracks;
+extern ConVar overview_locked;
+extern ConVar overview_alpha;
+extern ConVar cl_radaralpha;
+ConVar cl_radar_locked( "cl_radar_locked", "0", FCVAR_ARCHIVE, "Lock the angle of the radar display?" );
+
+void PreferredOverviewModeChanged( IConVar *pConVar, const char *oldString, float flOldValue )
+{
+ ConVarRef var( pConVar );
+ char cmd[32];
+ V_snprintf( cmd, sizeof( cmd ), "overview_mode %d\n", var.GetInt() );
+ engine->ClientCmd( cmd );
+}
+ConVar overview_preferred_mode( "overview_preferred_mode", "1", FCVAR_ARCHIVE, "Preferred overview mode", PreferredOverviewModeChanged );
+
+ConVar overview_preferred_view_size( "overview_preferred_view_size", "600", FCVAR_ARCHIVE, "Preferred overview view size" );
+
+#define HOSTAGE_RESCUE_DURATION (2.5f)
+#define BOMB_FADE_DURATION (2.5f)
+#define DEATH_ICON_FADE (7.5f)
+#define DEATH_ICON_DURATION (10.0f)
+#define LAST_SEEN_ICON_DURATION (4.0f)
+#define DIFFERENCE_THRESHOLD (200.0f)
+
+// To make your own green radar file from the map overview file, turn this on, and include vtf.lib
+#define no_GENERATE_RADAR_FILE
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+//-----------------------------------------------------------------------------
+CCSSpectatorGUI::CCSSpectatorGUI(IViewPort *pViewPort) : CSpectatorGUI(pViewPort)
+{
+ m_pCTLabel = NULL;
+ m_pCTScore = NULL;
+ m_pTerLabel = NULL;
+ m_pTerScore = NULL;
+ m_pTimer = NULL;
+ m_pTimerLabel = NULL;
+ m_pDivider = NULL;
+ m_pExtraInfo = NULL;
+
+ m_modifiedWidths = false;
+
+ m_scoreWidth = 0;
+ m_extraInfoWidth = 0;
+
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ // Grab some control pointers
+ m_pCTLabel = dynamic_cast<Label *>(FindChildByName("CTScoreLabel"));
+ m_pCTScore = dynamic_cast<Label *>(FindChildByName("CTScoreValue"));
+ m_pTerLabel = dynamic_cast<Label *>(FindChildByName("TerScoreLabel"));
+ m_pTerScore = dynamic_cast<Label *>(FindChildByName("TerScoreValue"));
+
+ m_pTimer = dynamic_cast<Label *>(FindChildByName("timerclock"));
+ m_pTimerLabel = dynamic_cast<Label *>(FindChildByName("timerlabel"));
+
+ m_pDivider = dynamic_cast<Panel *>(FindChildByName("DividerBar"));
+
+ m_pExtraInfo = dynamic_cast<Label *>(FindChildByName("extrainfo"));
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resets the list of players
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::UpdateSpectatorPlayerList()
+{
+ C_Team *cts = GetGlobalTeam( TEAM_CT );
+ if ( cts )
+ {
+ wchar_t frags[ 10 ];
+ _snwprintf( frags, ARRAYSIZE( frags ), L"%i", cts->Get_Score() );
+
+ SetLabelText( "CTScoreValue", frags );
+ }
+
+ C_Team *ts = GetGlobalTeam( TEAM_TERRORIST );
+ if ( ts )
+ {
+ wchar_t frags[ 10 ];
+ _snwprintf( frags, ARRAYSIZE( frags ), L"%i", ts->Get_Score() );
+
+ SetLabelText( "TERScoreValue", frags );
+ }
+}
+
+bool CCSSpectatorGUI::NeedsUpdate( void )
+{
+ C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
+ if ( !player )
+ return false;
+
+ if ( m_nLastAccount != player->GetAccount() )
+ return true;
+
+ if ( m_nLastTime != (int)CSGameRules()->GetRoundRemainingTime() )
+ return true;
+
+ if ( m_nLastSpecMode != player->GetObserverMode() )
+ return true;
+
+ if ( m_nLastSpecTarget != player->GetObserverTarget() )
+ return true;
+
+ return BaseClass::NeedsUpdate();
+}
+
+//=============================================================================
+// HPE_BEGIN:
+// [smessick]
+//=============================================================================
+void CCSSpectatorGUI::ShowPanel( bool bShow )
+{
+ BaseClass::ShowPanel( bShow );
+
+ if ( bShow )
+ {
+ // Resend the overview command.
+ char cmd[32];
+ V_snprintf( cmd, sizeof( cmd ), "overview_mode %d\n", overview_preferred_mode.GetInt() );
+ engine->ClientCmd( cmd );
+ }
+}
+//=============================================================================
+// HPE_END
+//=============================================================================
+
+//-----------------------------------------------------------------------------
+// Purpose: Updates the timer label if one exists
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::UpdateTimer()
+{
+ // these could be NULL if players modified the UI
+ if ( !ControlsPresent() )
+ return;
+
+ Color timerColor = m_pTimer->GetFgColor();
+ if( g_PlantedC4s.Count() > 0 )
+ {
+ m_pTimer->SetText( "\\" ); // bomb icon
+ m_pTimerLabel->SetVisible( false );
+
+ if( g_PlantedC4s[0]->m_flNextGlow > gpGlobals->curtime + 0.1f )
+ timerColor[3] = 80;
+ else
+ timerColor[3] = 255;
+
+ m_pTimer->SetFgColor( timerColor );
+ return;
+ }
+
+ timerColor[3] = 255;
+ m_pTimer->SetFgColor( timerColor );
+ m_pTimer->SetText( "e" ); // clock icon
+
+ m_nLastTime = (int)( CSGameRules()->GetRoundRemainingTime() );
+
+ if ( m_nLastTime < 0 )
+ m_nLastTime = 0;
+
+ wchar_t szText[ 63 ];
+ _snwprintf ( szText, ARRAYSIZE( szText ), L"%d:%02d", (m_nLastTime / 60), (m_nLastTime % 60) );
+ szText[62] = 0;
+
+ SetLabelText("timerlabel", szText );
+ m_pTimerLabel->SetVisible( true );
+}
+
+void CCSSpectatorGUI::UpdateAccount()
+{
+ C_CSPlayer *player = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( !player )
+ return;
+
+ m_nLastAccount = player->GetAccount();
+
+ if ( (player->GetTeamNumber() == TEAM_TERRORIST) || (player->GetTeamNumber() == TEAM_CT) )
+ {
+ wchar_t szText[ 63 ];
+ _snwprintf ( szText, ARRAYSIZE( szText ), L"$%i", m_nLastAccount );
+ szText[62] = 0;
+
+ SetLabelText( "extrainfo", szText );
+ }
+}
+
+
+/*bool CCSSpectatorGUI::CanSpectateTeam( int iTeam )
+{
+ bool bRetVal = true;
+ int iTeamOnly = 0;// TODO = gCSViewPortInterface->GetForceCamera();
+
+ // if we're not a spectator or HLTV and iTeamOnly is set
+ if ( C_BasePlayer::GetLocalPlayer()->GetTeamNumber() // && !gEngfuncs.IsSpectateOnly()
+ && iTeamOnly )
+ {
+ // then we want to force the same team
+ if ( C_BasePlayer::GetLocalPlayer()->GetTeamNumber() != iTeam )
+ {
+ bRetVal = false;
+ }
+ }
+
+ return bRetVal;
+}*/
+
+void CCSSpectatorGUI::Update()
+{
+ BaseClass::Update();
+
+ C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if( pLocalPlayer )
+ {
+ m_nLastSpecMode = pLocalPlayer->GetObserverMode();
+ m_nLastSpecTarget = pLocalPlayer->GetObserverTarget();
+ }
+
+ UpdateTimer();
+
+ UpdateAccount();
+
+ UpdateSpectatorPlayerList();
+
+ if ( pLocalPlayer )
+ {
+ ResizeControls();
+ }
+
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Save off widths for sizing calculations
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::StoreWidths( void )
+{
+ if ( !ControlsPresent() )
+ return;
+
+ if ( !m_modifiedWidths )
+ {
+ m_scoreWidth = m_pCTScore->GetWide();
+ int terScoreWidth = m_pTerScore->GetWide();
+
+ m_extraInfoWidth = m_pExtraInfo->GetWide();
+
+ if ( m_scoreWidth != terScoreWidth )
+ {
+ m_pTerScore = NULL; // We're working with a modified res file. Don't muck things up playing with positioning.
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Resize controls so scores & map names are not cut off
+//-----------------------------------------------------------------------------
+void CCSSpectatorGUI::ResizeControls( void )
+{
+ if ( !ControlsPresent() )
+ return;
+
+ int x1, y1, w1, t1;
+ int x2, y2, w2, t2;
+
+ StoreWidths();
+
+ // ensure scores are wide enough
+ int wCT, hCT, wTer, hTer;
+ m_pCTScore->GetBounds( x1, y1, w1, t1 );
+ m_pCTScore->GetContentSize( wCT, hCT );
+ m_pTerScore->GetBounds( x2, y2, w2, t2 );
+ m_pTerScore->GetContentSize( wTer, hTer );
+
+ int desiredScoreWidth = m_scoreWidth;
+ desiredScoreWidth = MAX( desiredScoreWidth, wCT );
+ desiredScoreWidth = MAX( desiredScoreWidth, wTer );
+
+ int diff = desiredScoreWidth - w1;
+ if ( diff != 0 )
+ {
+ m_pCTScore->GetBounds( x1, y1, w1, t1 );
+ m_pCTScore->SetBounds( x1 - diff, y1, w1 + diff, t1 );
+
+ m_pTerScore->GetBounds( x1, y1, w1, t1 );
+ m_pTerScore->SetBounds( x1 - diff, y1, w1 + diff, t1 );
+
+ m_pCTLabel->GetPos( x1, y1 );
+ m_pCTLabel->SetPos( x1 - diff, y1 );
+
+ m_pTerLabel->GetPos( x1, y1 );
+ m_pTerLabel->SetPos( x1 - diff, y1 );
+
+ m_modifiedWidths = true;
+ }
+
+ // ensure extra info is wide enough
+ int wExtra, hExtra;
+ m_pExtraInfo->GetBounds( x1, y1, w1, t1 );
+ m_pExtraInfo->GetContentSize( wExtra, hExtra );
+
+ int desiredExtraWidth = m_extraInfoWidth;
+ desiredExtraWidth = MAX( desiredExtraWidth, wExtra );
+
+ diff = desiredExtraWidth - w1;
+ if ( diff != 0 )
+ {
+ m_pExtraInfo->GetBounds( x1, y1, w1, t1 );
+ m_pExtraInfo->SetBounds( x1 - diff, y1, w1 + diff, t1 );
+
+ m_pTimer->GetPos( x1, y1 );
+ m_pTimer->SetPos( x1 - diff, y1 );
+
+ m_pTimerLabel->GetPos( x1, y1 );
+ m_pTimerLabel->SetPos( x1 - diff, y1 );
+
+ m_pDivider->GetPos( x1, y1 );
+ m_pDivider->SetPos( x1 - diff, y1 );
+
+ m_pCTScore->GetPos( x1, y1 );
+ m_pCTScore->SetPos( x1 - diff, y1 );
+
+ m_pCTLabel->GetPos( x1, y1 );
+ m_pCTLabel->SetPos( x1 - diff, y1 );
+
+ m_pTerScore->GetPos( x1, y1 );
+ m_pTerScore->SetPos( x1 - diff, y1 );
+
+ m_pTerLabel->GetPos( x1, y1 );
+ m_pTerLabel->SetPos( x1 - diff, y1 );
+
+ m_modifiedWidths = true;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Verify controls are present to resize
+//-----------------------------------------------------------------------------
+bool CCSSpectatorGUI::ControlsPresent( void ) const
+{
+ return ( m_pCTLabel != NULL &&
+ m_pCTScore != NULL &&
+ m_pTerLabel != NULL &&
+ m_pTerScore != NULL &&
+ m_pTimer != NULL &&
+ m_pTimerLabel != NULL &&
+ m_pDivider != NULL &&
+ m_pExtraInfo != NULL );
+}
+
+
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+static int AdjustValue( int curValue, int targetValue, int amount )
+{
+ if ( curValue > targetValue )
+ {
+ curValue -= amount;
+
+ if ( curValue < targetValue )
+ curValue = targetValue;
+ }
+ else if ( curValue < targetValue )
+ {
+ curValue += amount;
+
+ if ( curValue > targetValue )
+ curValue = targetValue;
+ }
+
+ return curValue;
+}
+
+void CCSMapOverview::InitTeamColorsAndIcons()
+{
+ BaseClass::InitTeamColorsAndIcons();
+
+ Q_memset( m_TeamIconsSelf, 0, sizeof(m_TeamIconsSelf) );
+ Q_memset( m_TeamIconsDead, 0, sizeof(m_TeamIconsDead) );
+ Q_memset( m_TeamIconsOffscreen, 0, sizeof(m_TeamIconsOffscreen) );
+ Q_memset( m_TeamIconsDeadOffscreen, 0, sizeof(m_TeamIconsDeadOffscreen) );
+
+ m_bombIconPlanted = -1;
+ m_bombIconDropped = -1;
+ m_bombIconCarried = -1;
+ m_bombRingPlanted = -1;
+ m_bombRingDropped = -1;
+ m_bombRingCarried = -1;
+ m_bombRingCarriedOffscreen = -1;
+ m_radioFlash = -1;
+ m_radioFlashOffscreen = -1;
+ m_radarTint = -1;
+ m_hostageFollowing = -1;
+ m_hostageFollowingOffscreen = -1;
+ m_playerFacing = -1;
+ m_cameraIconFirst = -1;
+ m_cameraIconThird = -1;
+ m_cameraIconFree = -1;
+ m_hostageRescueIcon = -1;
+ m_bombSiteIconA = -1;
+ m_bombSiteIconB = -1;
+
+
+ //setup team red
+ m_TeamColors[MAP_ICON_T] = COLOR_RED;
+ m_TeamIcons[MAP_ICON_T] = AddIconTexture( "sprites/player_red_small" );
+ m_TeamIconsSelf[MAP_ICON_T] = AddIconTexture( "sprites/player_red_self" );
+ m_TeamIconsDead[MAP_ICON_T] = AddIconTexture( "sprites/player_red_dead" );
+ m_TeamIconsOffscreen[MAP_ICON_T] = AddIconTexture( "sprites/player_red_offscreen" );
+ m_TeamIconsDeadOffscreen[MAP_ICON_T] = AddIconTexture( "sprites/player_red_dead_offscreen" );
+
+ // setup team blue
+ m_TeamColors[MAP_ICON_CT] = COLOR_BLUE;
+ m_TeamIcons[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_small" );
+ m_TeamIconsSelf[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_self" );
+ m_TeamIconsDead[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_dead" );
+ m_TeamIconsOffscreen[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_offscreen" );
+ m_TeamIconsDeadOffscreen[MAP_ICON_CT] = AddIconTexture( "sprites/player_blue_dead_offscreen" );
+
+ // setup team other
+ m_TeamColors[MAP_ICON_HOSTAGE] = COLOR_GREY;
+ m_TeamIcons[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_small" );
+ m_TeamIconsSelf[MAP_ICON_HOSTAGE] = -1;
+ m_TeamIconsDead[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_dead" );
+ m_TeamIconsOffscreen[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_offscreen" );
+ m_TeamIconsDeadOffscreen[MAP_ICON_HOSTAGE] = AddIconTexture( "sprites/player_hostage_dead_offscreen" );
+
+ m_bombIconPlanted = AddIconTexture( "sprites/bomb_planted" );
+ m_bombIconDropped = AddIconTexture( "sprites/bomb_dropped" );
+ m_bombIconCarried = AddIconTexture( "sprites/bomb_carried" );
+
+ m_bombRingPlanted = AddIconTexture( "sprites/bomb_planted_ring" );
+ m_bombRingDropped = AddIconTexture( "sprites/bomb_dropped_ring" );
+ m_bombRingCarried = AddIconTexture( "sprites/bomb_carried_ring" );
+ m_bombRingCarriedOffscreen = AddIconTexture( "sprites/bomb_carried_ring_offscreen" );
+
+ m_hostageFollowing = AddIconTexture( "sprites/hostage_following" );
+ m_hostageFollowingOffscreen = AddIconTexture( "sprites/hostage_following_offscreen" );
+ m_playerFacing = AddIconTexture( "sprites/player_tick" );
+ m_cameraIconFirst = AddIconTexture( "sprites/spectator_eye" );
+ m_cameraIconThird = AddIconTexture( "sprites/spectator_3rdcam" );
+ m_cameraIconFree = AddIconTexture( "sprites/spectator_freecam" );
+ m_hostageRescueIcon = AddIconTexture( "sprites/objective_rescue" );;
+ m_bombSiteIconA = AddIconTexture( "sprites/objective_site_a" );;
+ m_bombSiteIconB = AddIconTexture( "sprites/objective_site_b" );;
+
+ m_radioFlash = AddIconTexture("sprites/player_radio_ring");
+ m_radioFlashOffscreen = AddIconTexture("sprites/player_radio_ring_offscreen");
+
+ m_radarTint = AddIconTexture("sprites/radar_trans");
+
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::ApplySchemeSettings(vgui::IScheme *scheme)
+{
+ BaseClass::ApplySchemeSettings( scheme );
+
+ m_hIconFont = scheme->GetFont( "DefaultSmall", true );
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::Update( void )
+{
+ C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if ( !pPlayer )
+ return;
+
+ int team = pPlayer->GetTeamNumber();
+
+ // if dead with fadetoblack on, we can't show anything
+ if ( mp_fadetoblack.GetBool() && team > TEAM_SPECTATOR && !pPlayer->IsAlive() )
+ {
+ SetMode( MAP_MODE_OFF );
+ return;
+ }
+
+ bool inRadarMode = (GetMode() == MAP_MODE_RADAR);
+ int specmode = pPlayer->GetObserverMode();
+ // if alive, we can only be in radar mode
+ if( !inRadarMode && pPlayer->IsAlive())
+ {
+ SetMode( MAP_MODE_RADAR );
+ inRadarMode = true;
+ }
+
+ if( inRadarMode )
+ {
+ if( specmode > OBS_MODE_DEATHCAM )
+ {
+ // If fully dead, we don't want to be radar any more
+ SetMode( m_playerPreferredMode );
+ m_flChangeSpeed = 0;
+ }
+ else
+ {
+ SetFollowEntity(pPlayer->entindex());
+ UpdatePlayers();
+ }
+ }
+
+ BaseClass::Update();
+
+ if ( GetSpectatorMode() == OBS_MODE_CHASE )
+ {
+ // Follow the local player in chase cam, so the map rotates using the local player's angles
+ SetFollowEntity( pPlayer->entindex() );
+ }
+}
+
+//-----------------------------------------------------------------------------
+CCSMapOverview::CSMapPlayer_t* CCSMapOverview::GetCSInfoForPlayerIndex( int index )
+{
+ if ( index < 0 || index >= MAX_PLAYERS )
+ return NULL;
+
+ return &m_PlayersCSInfo[ index ];
+}
+
+//-----------------------------------------------------------------------------
+CCSMapOverview::CSMapPlayer_t* CCSMapOverview::GetCSInfoForPlayer(MapPlayer_t *player)
+{
+ if( player == NULL )
+ return NULL;
+
+ for( int i = 0; i < MAX_PLAYERS; i++ )
+ {
+ if( &m_Players[i] == player )
+ return &m_PlayersCSInfo[i];
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+CCSMapOverview::CSMapPlayer_t* CCSMapOverview::GetCSInfoForHostage(MapPlayer_t *hostage)
+{
+ if( hostage == NULL )
+ return NULL;
+
+ for( int i = 0; i < MAX_HOSTAGES; i++ )
+ {
+ if( &m_Hostages[i] == hostage )
+ return &m_HostagesCSInfo[i];
+ }
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+#define TIME_SPOTS_STAY_SEEN (0.5f)
+#define TIME_UNTIL_ENEMY_SEEN (0.5f)
+// rules that define if you can see a player on the overview or not
+bool CCSMapOverview::CanPlayerBeSeen( MapPlayer_t *player )
+{
+ C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if (!localPlayer || !player )
+ return false;
+
+ CSMapPlayer_t *csPlayer = GetCSInfoForPlayer(player);
+
+ if ( !csPlayer )
+ return false;
+
+ if( GetMode() == MAP_MODE_RADAR )
+ {
+ // This level will be for all the RadarMode thinking. Base class will be the old way for the other modes.
+ float now = gpGlobals->curtime;
+
+ if( player->position == Vector(0,0,0) )
+ return false; // Invalid guy.
+
+ // draw special icons if within time
+ if ( csPlayer->overrideExpirationTime != -1 && csPlayer->overrideExpirationTime > gpGlobals->curtime )
+ return true;
+
+ // otherwise, not dead people
+ if( player->health <= 0 )
+ return false;
+
+ if( localPlayer->GetTeamNumber() == player->team )
+ return true;// always yes for teammates.
+
+ // and a living enemy needs to have been seen recently, and have been for a while
+ if( csPlayer->timeLastSeen != -1
+ && ( now - csPlayer->timeLastSeen < TIME_SPOTS_STAY_SEEN )
+ && ( now - csPlayer->timeFirstSeen > TIME_UNTIL_ENEMY_SEEN )
+ )
+ return true;
+
+ return false;
+ }
+ else if( player->health <= 0 )
+ {
+ // Have to be under the overriden icon time to draw when dead.
+ if ( csPlayer->overrideExpirationTime == -1 || csPlayer->overrideExpirationTime <= gpGlobals->curtime )
+ return false;
+ }
+
+ return BaseClass::CanPlayerBeSeen(player);
+}
+
+bool CCSMapOverview::CanHostageBeSeen( MapPlayer_t *hostage )
+{
+ C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if ( !localPlayer || !hostage )
+ return false;
+
+
+ CSMapPlayer_t *csHostage = GetCSInfoForHostage(hostage);
+
+ if ( !csHostage )
+ return false;
+
+ if( GetMode() == MAP_MODE_RADAR )
+ {
+ // This level will be for all the RadarMode thinking. Base class will be the old way for the other modes.
+ float now = gpGlobals->curtime;
+
+ if( hostage->position == Vector(0,0,0) )
+ return false; // Invalid guy.
+
+ // draw special icons if within time
+ if ( csHostage->overrideExpirationTime != -1 && csHostage->overrideExpirationTime > gpGlobals->curtime )
+ return true;
+
+ // otherwise, not dead people
+ if( hostage->health <= 0 )
+ return false;
+
+ if( localPlayer->GetTeamNumber() == hostage->team )
+ return true;// always yes for teammates.
+
+ // and a living enemy needs to have been seen recently
+ if( csHostage->timeLastSeen != -1 && now - csHostage->timeLastSeen < TIME_SPOTS_STAY_SEEN )
+ return true;
+
+ return false;
+ }
+ else if( hostage->health <= 0 )
+ {
+ // Have to be under the overriden icon time to draw when dead.
+ if ( csHostage->overrideExpirationTime == -1 || csHostage->overrideExpirationTime <= gpGlobals->curtime )
+ return false;
+ }
+
+ return BaseClass::CanPlayerBeSeen(hostage);
+}
+
+CCSMapOverview::CCSMapOverview( const char *pElementName ) : BaseClass( pElementName )
+{
+ m_nRadarMapTextureID = -1;
+
+ g_pMapOverview = this; // for cvars access etc
+
+ // restore non-radar modes
+ switch ( overview_preferred_mode.GetInt() )
+ {
+ case MAP_MODE_INSET:
+ m_playerPreferredMode = MAP_MODE_INSET;
+ break;
+
+ case MAP_MODE_FULL:
+ m_playerPreferredMode = MAP_MODE_FULL;
+ break;
+
+ default:
+ m_playerPreferredMode = MAP_MODE_OFF;
+ break;
+ }
+}
+
+void CCSMapOverview::Init( void )
+{
+ BaseClass::Init();
+
+ // register for events as client listener
+ ListenForGameEvent( "hostage_killed" );
+ ListenForGameEvent( "hostage_rescued" );
+ ListenForGameEvent( "bomb_defused" );
+ ListenForGameEvent( "bomb_exploded" );
+}
+
+CCSMapOverview::~CCSMapOverview()
+{
+ g_pMapOverview = NULL;
+
+ //TODO release Textures ? clear lists
+}
+
+void CCSMapOverview::UpdatePlayers()
+{
+ if( !m_goalIconsLoaded )
+ UpdateGoalIcons();
+
+ UpdateHostages();// Update before players so players can spot them
+
+ UpdateBomb();// Before players so player can properly spot where it is in this update
+
+ UpdateFlashes();
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ float now = gpGlobals->curtime;
+
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+ if( localPlayer == NULL )
+ return;
+
+ MapPlayer_t *localMapPlayer = GetPlayerByUserID(localPlayer->GetUserID());
+ if( localMapPlayer == NULL )
+ return;
+
+ for ( int i = 1; i<= gpGlobals->maxClients; i++)
+ {
+ MapPlayer_t *player = &m_Players[i-1];
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i-1);
+
+ if ( !playerCS )
+ continue;
+
+ // update from global player resources
+ if ( pCSPR->IsConnected(i) )
+ {
+ player->health = pCSPR->GetHealth( i );
+
+ if ( !pCSPR->IsAlive( i ) )
+ {
+ // Safety actually happens after a TKPunish.
+ player->health = 0;
+ playerCS->isDead = true;
+ }
+
+ if ( player->team != pCSPR->GetTeam( i ) )
+ {
+ player->team = pCSPR->GetTeam( i );
+
+ if( player == localMapPlayer )
+ player->icon = m_TeamIconsSelf[ GetIconNumberFromTeamNumber(player->team) ];
+ else
+ player->icon = m_TeamIcons[ GetIconNumberFromTeamNumber(player->team) ];
+
+ player->color = m_TeamColors[ GetIconNumberFromTeamNumber(player->team) ];
+ }
+ }
+
+ Vector position = player->position;
+ QAngle angles = player->angle;
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if ( pPlayer && !pPlayer->IsDormant() )
+ {
+ // update position of active players in our PVS
+ position = pPlayer->EyePosition();
+ angles = pPlayer->EyeAngles();
+
+ SetPlayerPositions( i-1, position, angles );
+ }
+ }
+
+ if ( GetMode() == MAP_MODE_RADAR )
+ {
+ // Check for teammates spotting the bomb
+ if ( m_bomb.state != CSMapBomb_t::BOMB_INVALID && pCSPR->IsBombSpotted() )
+ {
+ SetBombSeen( true );
+ }
+
+ // Check for teammates spotting enemy players
+ for ( int i = 1; i<= gpGlobals->maxClients; ++i )
+ {
+ if ( !pCSPR->IsConnected(i) )
+ continue;
+
+ if ( !pCSPR->IsAlive(i) )
+ continue;
+
+ if ( pCSPR->GetTeam(i) == localMapPlayer->team )
+ continue;
+
+ if ( pCSPR->IsPlayerSpotted(i) )
+ {
+ SetPlayerSeen( i-1 );
+
+ MapPlayer_t *baseEnemy = &m_Players[i-1];
+ if( baseEnemy->health > 0 )
+ {
+ // They were just seen, so if they are alive get rid of their "last known" icon
+ CSMapPlayer_t *csEnemy = GetCSInfoForPlayerIndex(i-1);
+
+ if ( csEnemy )
+ {
+ csEnemy->overrideIcon = -1;
+ csEnemy->overrideIconOffscreen = -1;
+ csEnemy->overridePosition = Vector(0, 0, 0);
+ csEnemy->overrideAngle = QAngle(0, 0, 0);
+ csEnemy->overrideFadeTime = -1;
+ csEnemy->overrideExpirationTime = -1;
+ }
+ }
+ }
+ }
+
+ for( int i = 1; i<= gpGlobals->maxClients; i++ )
+ {
+ MapPlayer_t *player = &m_Players[i-1];
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i-1);
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+
+ if ( !pPlayer || !playerCS )
+ continue;
+
+ float timeSinceLastSeen = now - playerCS->timeLastSeen;
+ if( timeSinceLastSeen < 0.25f )
+ continue;
+ if( player->health <= 0 )
+ continue;// We don't need to spot dead guys, since they always show
+ if( player->team == localMapPlayer->team )
+ continue;// We don't need to spot our own guys
+
+ // Now that everyone has had a say on people they can see for us, go through and handle baddies that can no longer be seen.
+ if( playerCS->timeLastSeen != now && player->health > 0 )
+ {
+ // We are not seen now, but if we were seen recently (and for long enough),
+ // put up a "last known" icon and clear timelastseen
+ // if they are alive. Death icon is more important, which is why the health check above.
+ if( timeSinceLastSeen < 0.5f && ( playerCS->timeLastSeen != -1 ) )
+ {
+ if( now - playerCS->timeFirstSeen > TIME_UNTIL_ENEMY_SEEN )
+ {
+ playerCS->overrideIcon = m_TeamIcons[ GetIconNumberFromTeamNumber(player->team) ];;
+ playerCS->overrideIconOffscreen = m_TeamIconsOffscreen[ GetIconNumberFromTeamNumber(player->team) ];
+ playerCS->overridePosition = player->position;
+ playerCS->overrideFadeTime = -1;
+ playerCS->overrideExpirationTime = now + LAST_SEEN_ICON_DURATION;
+ playerCS->overrideAngle = player->angle;
+ }
+ playerCS->timeLastSeen = -1;
+ playerCS->timeFirstSeen = -1;
+ }
+ }
+ }
+ }
+}
+
+void CCSMapOverview::UpdateHostages()
+{
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ for( int i=0; i < MAX_HOSTAGES; i++ )
+ {
+ if( pCSPR->IsHostageAlive( i ) )
+ {
+ MapPlayer_t *hostage = GetHostageByEntityID( pCSPR->GetHostageEntityID(i) );
+ if( hostage == NULL )
+ hostage = &m_Hostages[i];// Don't have entry yet, so need one. This'll only happen once, at start of map
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ return;
+
+ if( !hostageCS->isDead )
+ {
+ hostage->index = pCSPR->GetHostageEntityID(i);
+ hostage->position = pCSPR->GetHostagePosition( i );
+ hostage->health = 100; // Hostages don't have health available from pCSPR.
+ hostage->angle = QAngle(0, 0, 0); // No facing, like no health
+ hostage->team = TEAM_CT; // CT in terms of who sees them
+ hostage->icon = m_TeamIcons[ MAP_ICON_HOSTAGE ]; // But hostage for icon.
+ hostage->color = m_TeamColors[ MAP_ICON_HOSTAGE ];
+ hostageCS->isHostage = true;
+
+// engine->Con_NPrintf( i + 15, "ID:%d Pos:(%.0f,%.0f,%.0f)", hostage->index, hostage->position.x, hostage->position.y, hostage->position.z );
+ }
+ else
+ {
+// engine->Con_NPrintf( i + 15, "Mostly Dead" );
+ }
+ }
+ else
+ {
+// engine->Con_NPrintf( i + 15, "Dead" );
+ }
+ }
+}
+
+void CCSMapOverview::UpdateBomb()
+{
+ if( m_bomb.state == CSMapBomb_s::BOMB_GONE )
+ return;// no more updates until map restart
+
+ float now = gpGlobals->curtime;
+
+ // First, decide if it has been too long since the bomb has been seen to clear visibility timers.
+ if( now - m_bomb.timeLastSeen >= TIME_SPOTS_STAY_SEEN && m_bomb.timeFirstSeen != -1 )
+ {
+ SetBombSeen( false );
+ }
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ float biggestRadius = 0, smallestRadius = 0;
+ if ( g_PlantedC4s.Count() > 0 )
+ {
+ // bomb is planted
+ C_PlantedC4 *pC4 = g_PlantedC4s[0];
+
+ if( pC4->IsBombActive() )
+ {
+ m_bomb.position = pC4->GetAbsOrigin();
+ m_bomb.state = CSMapBomb_t::BOMB_PLANTED;
+ m_bomb.ringTravelTime = 3.0f;
+ smallestRadius = m_flIconSize;
+ biggestRadius = m_flIconSize * 15.0f;
+ }
+ else
+ {
+ // Defused or exploded
+ m_bomb.state = CSMapBomb_t::BOMB_GONE;
+ }
+ }
+ else if ( pCSPR->HasC4( 0 ) )
+ {
+ // bomb dropped
+ Vector pos = pCSPR->GetC4Postion();
+
+ if ( pos.x != 0 || pos.y != 0 || pos.z != 0 )
+ {
+ m_bomb.position = pos;
+ m_bomb.state = CSMapBomb_t::BOMB_DROPPED;
+ m_bomb.ringTravelTime = 6.0f;
+ smallestRadius = m_flIconSize;
+ biggestRadius = m_flIconSize * 10.0f;
+ }
+ else
+ {
+ m_bomb.state = CSMapBomb_t::BOMB_INVALID;
+ //Not a bomb map. Man, what a weird system instead of IsBombMap. If nobody has it, and it isn't on the ground, then it isn't a bomb map.
+ }
+ }
+ else
+ {
+ for( int i = 1; i<= gpGlobals->maxClients; i++ )
+ {
+ if( pCSPR->HasC4(i) )
+ {
+ C_BasePlayer *pPlayer = UTIL_PlayerByIndex( i );
+ if( pPlayer == NULL || pPlayer->IsDormant() )
+ {
+ // Dormant or no player means we are relying on RadarUpdate messages so we can trust the MapOverview position.
+ MapPlayer_t *player = &m_Players[i-1];
+ m_bomb.position = player->position;
+ }
+ else
+ {
+ // Update players is about to put this Real Data in the player sturct, and we don't want the bomb pos lagged one update behind
+ m_bomb.position = pPlayer->GetAbsOrigin();
+ }
+
+ m_bomb.state = CSMapBomb_t::BOMB_CARRIED;
+ m_bomb.ringTravelTime = 0;
+ smallestRadius = m_flIconSize * 1.2f;
+ biggestRadius = m_flIconSize * 1.2f;
+ break;
+ }
+ }
+ }
+
+ int alpha = GetMasterAlpha();
+
+ if( m_bomb.currentRingRadius == m_bomb.maxRingRadius || m_bomb.ringTravelTime == 0 )
+ {
+ m_bomb.currentRingRadius = smallestRadius;
+ m_bomb.maxRingRadius = biggestRadius;
+ m_bomb.currentRingAlpha = alpha;
+ }
+ else
+ {
+ m_bomb.currentRingRadius += (m_bomb.maxRingRadius - m_flIconSize) * gpGlobals->frametime / m_bomb.ringTravelTime;
+ m_bomb.currentRingRadius = MIN( m_bomb.currentRingRadius, m_bomb.maxRingRadius );
+ m_bomb.currentRingAlpha = (alpha - 55) * ((m_bomb.maxRingRadius - m_bomb.currentRingRadius) / (m_bomb.maxRingRadius - m_flIconSize)) + 55;
+ }
+}
+
+bool CCSMapOverview::ShouldDraw( void )
+{
+ int alpha = GetMasterAlpha();
+ if( alpha == 0 )
+ return false;// we have been set to fully transparent
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [smessick] Turn off large map display when in freezecam.
+ //=============================================================================
+ if ( IsInFreezeCam() && GetMode() == MAP_MODE_FULL )
+ {
+ return false;
+ }
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+
+ float now = gpGlobals->curtime;
+ if( GetMode() == MAP_MODE_RADAR )
+ {
+ if ( (GET_HUDELEMENT( CHudRadar ))->ShouldDraw() == false )
+ {
+ return false;
+ }
+
+ // We have to be alive and not blind to draw in this mode.
+ C_CSPlayer *pCSPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if( !pCSPlayer || pCSPlayer->GetObserverMode() == OBS_MODE_DEATHCAM )
+ {
+ return false;
+ }
+ else if (pCSPlayer->m_flFlashBangTime > now)
+ {
+ return false;
+ }
+ }
+
+ return BaseClass::ShouldDraw();
+}
+
+CCSMapOverview::MapPlayer_t* CCSMapOverview::GetHostageByEntityID( int entityID )
+{
+ for (int i=0; i<MAX_HOSTAGES; i++)
+ {
+ if ( m_Hostages[i].index == entityID )
+ return &m_Hostages[i];
+ }
+
+ return NULL;
+}
+
+CCSMapOverview::MapPlayer_t* CCSMapOverview::GetPlayerByEntityID( int entityID )
+{
+ C_BasePlayer *realPlayer = UTIL_PlayerByIndex(entityID);
+
+ if( realPlayer == NULL )
+ return NULL;
+
+ for (int i=0; i<MAX_PLAYERS; i++)
+ {
+ MapPlayer_t *player = &m_Players[i];
+
+ if ( player->userid == realPlayer->GetUserID() )
+ return player;
+ }
+
+ return NULL;
+}
+
+#define BORDER_WIDTH 4
+bool CCSMapOverview::AdjustPointToPanel(Vector2D *pos)
+{
+ if( pos == NULL )
+ return false;
+
+ int mapInset = GetBorderSize();// This gives us the amount inside the panel that the background is drawing.
+ if( mapInset != 0 )
+ mapInset += BORDER_WIDTH; // And this gives us the border inside the map edge to give us room for offscreen icons.
+
+ int x,y,w,t;
+
+ //MapTpPanel has already offset the x and y. That's why we use 0 for left and top.
+ GetBounds( x,y,w,t );
+
+ bool madeChange = false;
+ if( pos->x < mapInset )
+ {
+ pos->x = mapInset;
+ madeChange = true;
+ }
+ if( pos->x > w - mapInset )
+ {
+ pos->x = w - mapInset;
+ madeChange = true;
+ }
+ if( pos->y < mapInset )
+ {
+ pos->y = mapInset;
+ madeChange = true;
+ }
+ if( pos->y > t - mapInset )
+ {
+ pos->y = t - mapInset;
+ madeChange = true;
+ }
+
+ return madeChange;
+}
+
+void CCSMapOverview::DrawMapTexture()
+{
+ int alpha = GetMasterAlpha();
+
+ if( GetMode() == MAP_MODE_FULL )
+ SetBgColor( Color(0,0,0,0) );// no background in big mode
+ else
+ SetBgColor( Color(0,0,0,alpha * 0.5) );
+
+ int textureIDToUse = m_nMapTextureID;
+ bool foundRadarVersion = false;
+ if( m_nRadarMapTextureID != -1 && GetMode() == MAP_MODE_RADAR )
+ {
+ textureIDToUse = m_nRadarMapTextureID;
+ foundRadarVersion = true;
+ }
+
+ int mapInset = GetBorderSize();
+ int pwidth, pheight;
+ GetSize(pwidth, pheight);
+
+ if ( textureIDToUse > 0 )
+ {
+ // We are drawing to the whole panel with a little border
+ Vector2D panelTL = Vector2D( mapInset, mapInset );
+ Vector2D panelTR = Vector2D( pwidth - mapInset, mapInset );
+ Vector2D panelBR = Vector2D( pwidth - mapInset, pheight - mapInset );
+ Vector2D panelBL = Vector2D( mapInset, pheight - mapInset );
+
+ // So where are those four points on the great big map?
+ Vector2D textureTL = PanelToMap( panelTL );// The top left corner of the display is where on the master map?
+ textureTL /= OVERVIEW_MAP_SIZE;// Texture Vec2D is 0 to 1
+ Vector2D textureTR = PanelToMap( panelTR );
+ textureTR /= OVERVIEW_MAP_SIZE;
+ Vector2D textureBR = PanelToMap( panelBR );
+ textureBR /= OVERVIEW_MAP_SIZE;
+ Vector2D textureBL = PanelToMap( panelBL );
+ textureBL /= OVERVIEW_MAP_SIZE;
+
+ Vertex_t points[4] =
+ {
+ // To draw a textured polygon, the first column is where you want to draw (to), and the second is what you want to draw (from).
+ // We want to draw to the panel (pulled in for a border), and we want to draw the part of the map texture that should be seen.
+ // First column is in panel coords, second column is in 0-1 texture coords
+ Vertex_t( panelTL, textureTL ),
+ Vertex_t( panelTR, textureTR ),
+ Vertex_t( panelBR, textureBR ),
+ Vertex_t( panelBL, textureBL )
+ };
+
+ surface()->DrawSetColor( 255, 255, 255, alpha );
+ surface()->DrawSetTexture( textureIDToUse );
+ surface()->DrawTexturedPolygon( 4, points );
+ }
+
+ // If we didn't find the greenscale version of the map, then at least do a tint.
+ if( !foundRadarVersion && GetMode() == MAP_MODE_RADAR )
+ {
+ surface()->DrawSetColor( 0,255,0, alpha / 4 );
+ surface()->DrawFilledRect( mapInset, mapInset, m_vSize.x - 1 - mapInset, m_vSize.y - 1 - mapInset );
+ }
+}
+
+void CCSMapOverview::DrawBomb()
+{
+ if( m_bomb.state == CSMapBomb_t::BOMB_INVALID )
+ return;
+
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+ if( localPlayer == NULL )
+ return;
+ MapPlayer_t *localMapPlayer = GetPlayerByUserID(localPlayer->GetUserID());
+ if( localMapPlayer == NULL )
+ return;
+ float now = gpGlobals->curtime;
+
+ if( localMapPlayer->team == TEAM_CT )
+ {
+ // CT's only get to see it if...
+
+ if( localMapPlayer->health <= 0 )
+ {
+ if ( mp_forcecamera.GetInt() != OBS_ALLOW_ALL )
+ return;// They're dead and spectating isn't restricted
+ }
+ else if( (m_bomb.timeLastSeen == -1)
+ || ( now - m_bomb.timeLastSeen >= TIME_SPOTS_STAY_SEEN )
+ || ( now - m_bomb.timeFirstSeen < TIME_UNTIL_ENEMY_SEEN )
+ )
+ {
+ return;// It's in view
+ }
+ }
+ // else if you aren't CT you can always see it
+
+ int bombIcon;
+ int bombRing;
+ int bombRingOffscreen;
+ switch(m_bomb.state)
+ {
+ case CSMapBomb_t::BOMB_DROPPED:
+ {
+ bombIcon = m_bombIconDropped;
+ bombRing = m_bombRingDropped;
+ bombRingOffscreen = m_bombRingDropped;
+ break;
+ }
+ case CSMapBomb_t::BOMB_CARRIED:
+ {
+ bombIcon = m_bombIconCarried;
+ bombRing = m_bombRingCarried;
+ bombRingOffscreen = m_bombRingCarriedOffscreen;
+ break;
+ }
+ case CSMapBomb_t::BOMB_PLANTED:
+ {
+ bombIcon = m_bombIconPlanted;
+ bombRing = m_bombRingPlanted;
+ bombRingOffscreen = m_bombRingPlanted;
+ break;
+ }
+ case CSMapBomb_t::BOMB_GONE:
+ {
+ bombIcon = m_bombIconPlanted;
+ bombRing = m_bombRingPlanted;
+ bombRingOffscreen = m_bombRingPlanted;
+ break;
+ }
+ default:
+ return;
+ }
+
+ int alpha = 255;
+
+ if( m_bomb.timeGone != -1 && m_bomb.timeFade <= gpGlobals->curtime )
+ alpha *= 1 - ( (float)(gpGlobals->curtime - m_bomb.timeFade) / (float)(m_bomb.timeGone - m_bomb.timeFade) );
+
+ if( m_bomb.state != CSMapBomb_t::BOMB_GONE )
+ DrawIconCS(bombRing, bombRingOffscreen, m_bomb.position, m_bomb.currentRingRadius, 0, m_bomb.currentRingAlpha);
+ DrawIconCS(bombIcon, bombIcon, m_bomb.position, m_flIconSize, 0, alpha);
+}
+
+bool CCSMapOverview::DrawIconCS( int textureID, int offscreenTextureID, Vector pos, float scale, float angle, int alpha, bool allowRotation, const char *text, Color *textColor, float status, Color *statusColor )
+{
+ if( GetMode() == MAP_MODE_RADAR && cl_radaralpha.GetInt() == 0 )
+ return false;
+
+ if( alpha <= 0 )
+ return false;
+
+ Vector2D pospanel = WorldToMap( pos );
+ pospanel = MapToPanel( pospanel );
+
+ int idToUse = textureID;
+ float angleToUse = angle;
+
+ Vector2D oldPos = pospanel;
+ Vector2D adjustment(0,0);
+ if( AdjustPointToPanel( &pospanel ) )
+ {
+ if( offscreenTextureID == -1 )
+ return false; //Doesn't want to draw if off screen.
+
+ // Move it in to on panel, and change the icon.
+ idToUse = offscreenTextureID;
+ // And point towards the original spot
+ adjustment = Vector2D(pospanel.x - oldPos.x, pospanel.y - oldPos.y);
+ QAngle adjustmentAngles;
+ Vector adjustment3D(adjustment.x, -adjustment.y, 0); // Y gets flipped in WorldToMap
+ VectorAngles(adjustment3D, adjustmentAngles) ;
+ if( allowRotation )
+ {
+ // Some icons don't want to rotate even when off radar
+ angleToUse = adjustmentAngles[YAW];
+
+ // And the angle needs to be in world space, not panel space.
+ if( m_bFollowAngle )
+ {
+ angleToUse += m_fViewAngle;
+ }
+ else
+ {
+ if ( m_bRotateMap )
+ angleToUse += 180.0f;
+ else
+ angleToUse += 90.0f;
+ }
+ }
+
+ // Don't draw names for icons that are offscreen (bunches up and looks bad)
+ text = NULL;
+ }
+
+ int d = GetPixelOffset( scale );
+
+ Vector offset;
+
+ offset.x = -scale; offset.y = scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos1 = WorldToMap( pos + offset );
+ Vector2D pos1Panel = MapToPanel(pos1);
+ pos1Panel.x += adjustment.x;
+ pos1Panel.y += adjustment.y;
+
+ offset.x = scale; offset.y = scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos2 = WorldToMap( pos + offset );
+ Vector2D pos2Panel = MapToPanel(pos2);
+ pos2Panel.x += adjustment.x;
+ pos2Panel.y += adjustment.y;
+
+ offset.x = scale; offset.y = -scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos3 = WorldToMap( pos + offset );
+ Vector2D pos3Panel = MapToPanel(pos3);
+ pos3Panel.x += adjustment.x;
+ pos3Panel.y += adjustment.y;
+
+ offset.x = -scale; offset.y = -scale;
+ VectorYawRotate( offset, angleToUse, offset );
+ Vector2D pos4 = WorldToMap( pos + offset );
+ Vector2D pos4Panel = MapToPanel(pos4);
+ pos4Panel.x += adjustment.x;
+ pos4Panel.y += adjustment.y;
+
+ Vertex_t points[4] =
+ {
+ Vertex_t( pos1Panel, Vector2D(0,0) ),
+ Vertex_t( pos2Panel, Vector2D(1,0) ),
+ Vertex_t( pos3Panel, Vector2D(1,1) ),
+ Vertex_t( pos4Panel, Vector2D(0,1) )
+ };
+
+ surface()->DrawSetColor( 255, 255, 255, alpha );
+ surface()->DrawSetTexture( idToUse );
+ surface()->DrawTexturedPolygon( 4, points );
+
+ pospanel.y += d + 4;
+
+ if ( status >=0.0f && status <= 1.0f && statusColor )
+ {
+ // health bar is 50x3 pixels
+ surface()->DrawSetColor( 0,0,0,255 );
+ surface()->DrawFilledRect( pospanel.x-d, pospanel.y-1, pospanel.x+d, pospanel.y+1 );
+
+ int length = (float)(d*2)*status;
+ surface()->DrawSetColor( statusColor->r(), statusColor->g(), statusColor->b(), 255 );
+ surface()->DrawFilledRect( pospanel.x-d, pospanel.y-1, pospanel.x-d+length, pospanel.y+1 );
+
+ pospanel.y += 3;
+ }
+
+ if ( text && textColor )
+ {
+ wchar_t iconText[ MAX_PLAYER_NAME_LENGTH*2 ];
+
+ g_pVGuiLocalize->ConvertANSIToUnicode( text, iconText, sizeof( iconText ) );
+
+ int wide, tall;
+ surface()->GetTextSize( m_hIconFont, iconText, wide, tall );
+
+ int x = pospanel.x-(wide/2);
+ int y = pospanel.y;
+
+ // draw black shadow text
+ surface()->DrawSetTextColor( 0, 0, 0, 255 );
+ surface()->DrawSetTextPos( x+1, y );
+ surface()->DrawPrintText( iconText, wcslen(iconText) );
+
+ // draw name in color
+ surface()->DrawSetTextColor( textColor->r(), textColor->g(), textColor->b(), 255 );
+ surface()->DrawSetTextPos( x, y );
+ surface()->DrawPrintText( iconText, wcslen(iconText) );
+ }
+
+ return true;
+}
+
+void CCSMapOverview::DrawMapPlayers()
+{
+ DrawGoalIcons();
+ DrawHostages();
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ surface()->DrawSetTextFont( m_hIconFont );
+
+ Color colorGreen( 0, 255, 0, 255 ); // health bar color
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ for (int i=0; i < MAX_PLAYERS; i++)
+ {
+ int alpha = 255;
+ MapPlayer_t *player = &m_Players[i];
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i);
+
+ if ( !playerCS )
+ continue;
+
+ if ( !CanPlayerBeSeen( player ) )
+ continue;
+
+ float status = -1;
+ const char *name = NULL;
+
+ if ( m_bShowNames && CanPlayerNameBeSeen( player ) )
+ name = player->name;
+
+ if ( m_bShowHealth && CanPlayerHealthBeSeen( player ) )
+ status = player->health/100.0f;
+
+ // Now draw them
+ if( playerCS->overrideExpirationTime > gpGlobals->curtime )// If dead, an X, if alive, an alpha'd normal icon
+ {
+ int alphaToUse = alpha;
+ if( playerCS->overrideFadeTime != -1 && playerCS->overrideFadeTime <= gpGlobals->curtime )
+ {
+ // Fade linearly from fade start to disappear
+ alphaToUse *= 1 - (float)(gpGlobals->curtime - playerCS->overrideFadeTime) / (float)(playerCS->overrideExpirationTime - playerCS->overrideFadeTime);
+ }
+
+ DrawIconCS( playerCS->overrideIcon, playerCS->overrideIconOffscreen, playerCS->overridePosition, m_flIconSize * 1.1f, GetViewAngle(), player->health > 0 ? alphaToUse / 2 : alphaToUse, true, name, &player->color, -1, &colorGreen );
+ if( player->health > 0 )
+ DrawIconCS( m_playerFacing, -1, playerCS->overridePosition, m_flIconSize * 1.1f, playerCS->overrideAngle[YAW], player->health > 0 ? alphaToUse / 2 : alphaToUse, true, name, &player->color, status, &colorGreen );
+ }
+ else
+ {
+ float zDifference = 0;
+ if( localPlayer )
+ {
+ if( (localPlayer->GetObserverMode() != OBS_MODE_NONE) && localPlayer->GetObserverTarget() )
+ zDifference = player->position.z - localPlayer->GetObserverTarget()->GetAbsOrigin().z;
+ else
+ zDifference = player->position.z - localPlayer->GetAbsOrigin().z;
+ }
+
+ float sizeForRing = m_flIconSize * 1.4f;
+ float sizeForPlayer = m_flIconSize * 1.1f; // The 1.1 is because the player dots are shrunken a little, so their facing pip can have some space to live
+ if ( zDifference > DIFFERENCE_THRESHOLD )
+ {
+ // A dot above is bigger and a little fuzzy now.
+ sizeForRing *= 1.4f;
+ sizeForPlayer *= 1.4f;
+ alpha *= 0.5f;
+ }
+ else if ( zDifference < -DIFFERENCE_THRESHOLD )
+ {
+ // A dot below is smaller.
+ sizeForRing *= 0.7f;
+ sizeForPlayer *= 0.7f;
+ }
+
+ bool showTalkRing = localPlayer && (localPlayer->GetTeamNumber() == player->team || localPlayer->GetTeamNumber() == TEAM_SPECTATOR);
+
+ if( showTalkRing && playerCS->currentFlashAlpha > 0 )// Flash type
+ {
+ // Make them flash a halo
+ DrawIconCS(m_radioFlash, m_radioFlashOffscreen, player->position, sizeForRing, player->angle[YAW], playerCS->currentFlashAlpha);
+ }
+ else if( showTalkRing && pCSPR->IsAlive( i + 1 ) && GetClientVoiceMgr()->IsPlayerSpeaking( i + 1) ) // Or solid on type
+ {
+ // Make them show a halo
+ DrawIconCS(m_radioFlash, m_radioFlashOffscreen, player->position, sizeForRing, player->angle[YAW], 255);
+ }
+
+ bool doingLocalPlayer = GetPlayerByUserID(localPlayer->GetUserID()) == player;
+ float angleForPlayer = GetViewAngle();
+
+ if( doingLocalPlayer )
+ {
+ sizeForPlayer *= 4.0f; // The self icon is really big since it has a camera view cone attached.
+ angleForPlayer = player->angle[YAW];// And, the self icon now rotates, natch.
+ }
+
+ int offscreenIcon = m_TeamIconsOffscreen[GetIconNumberFromTeamNumber(player->team)];
+ DrawIconCS( player->icon, offscreenIcon, player->position, sizeForPlayer, angleForPlayer, alpha, true, name, &player->color, status, &colorGreen );
+ if( !doingLocalPlayer )
+ {
+ // Draw the facing for everyone but the local player.
+ if( player->health > 0 )
+ DrawIconCS( m_playerFacing, -1, player->position, sizeForPlayer, player->angle[YAW], alpha, true, name, &player->color, status, &colorGreen );
+ }
+ }
+ }
+
+ DrawBomb();// After players so it can draw on top
+}
+
+void CCSMapOverview::DrawHostages()
+{
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+ if ( !pCSPR )
+ return;
+
+ surface()->DrawSetTextFont( m_hIconFont );
+
+ Color colorGreen( 0, 255, 0, 255 ); // health bar color
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ for (int i=0; i < MAX_HOSTAGES; i++)
+ {
+ int alpha = 255;
+ MapPlayer_t *hostage = GetHostageByEntityID( pCSPR->GetHostageEntityID(i) );
+ if( hostage == NULL )
+ continue;
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ continue;
+
+ if ( !CanHostageBeSeen( hostage ) )
+ {
+// engine->Con_NPrintf( i + 30, "Can't be seen." );
+ continue;
+ }
+
+ float status = -1;
+ const char *name = NULL;
+
+ if( hostageCS->overrideExpirationTime > gpGlobals->curtime )// If dead, an X, if alive, an alpha'd normal icon
+ {
+// engine->Con_NPrintf( i + 30, "ID:%d Override Pos:(%.0f,%.0f,%.0f)", hostage->index, hostageCS->overridePosition.x, hostageCS->overridePosition.y, hostageCS->overridePosition.z );
+ int alphaToUse = alpha;
+ if( hostageCS->overrideFadeTime != -1 && hostageCS->overrideFadeTime <= gpGlobals->curtime )
+ {
+ // Fade linearly from fade start to disappear
+ alphaToUse *= 1 - (float)(gpGlobals->curtime - hostageCS->overrideFadeTime) / (float)(hostageCS->overrideExpirationTime - hostageCS->overrideFadeTime);
+ }
+
+ DrawIconCS( hostageCS->overrideIcon, hostageCS->overrideIconOffscreen, hostageCS->overridePosition, m_flIconSize, hostageCS->overrideAngle[YAW], hostage->health > 0 ? alphaToUse / 2 : alphaToUse, true, name, &hostage->color, status, &colorGreen );
+ }
+ else
+ {
+ if( localPlayer && localPlayer->GetTeamNumber() == hostage->team && hostageCS->currentFlashAlpha > 0 )
+ {
+ // Make them flash a halo
+ DrawIconCS(m_radioFlash, m_radioFlashOffscreen, hostage->position, m_flIconSize * 1.4f, hostage->angle[YAW], hostageCS->currentFlashAlpha);
+ }
+
+// engine->Con_NPrintf( i + 30, "ID:%d Pos:(%.0f,%.0f,%.0f)", hostage->index, hostage->position.x, hostage->position.y, hostage->position.z );
+ int normalIcon, offscreenIcon;
+ float zDifference = 0;
+ if( localPlayer )
+ {
+ if( (localPlayer->GetObserverMode() != OBS_MODE_NONE) && localPlayer->GetObserverTarget() )
+ zDifference = hostage->position.z - localPlayer->GetObserverTarget()->GetAbsOrigin().z;
+ else
+ zDifference = hostage->position.z - localPlayer->GetAbsOrigin().z;
+ }
+
+ float sizeForHostage = m_flIconSize;
+ if( zDifference > DIFFERENCE_THRESHOLD )
+ {
+ // A dot above is bigger and a little fuzzy now.
+ sizeForHostage = m_flIconSize * 1.5f;
+ alpha *= 0.5f;
+ }
+ else if( zDifference < -DIFFERENCE_THRESHOLD )
+ {
+ // A dot below is smaller.
+ sizeForHostage = m_flIconSize * 0.6f;
+ }
+
+ normalIcon = hostage->icon;
+ offscreenIcon = m_TeamIconsOffscreen[ MAP_ICON_HOSTAGE ];
+ DrawIconCS( normalIcon, offscreenIcon, hostage->position, sizeForHostage, GetViewAngle(), alpha, true, name, &hostage->color, status, &colorGreen );
+
+ if( pCSPR->IsHostageFollowingSomeone( i ) )
+ {
+ // If they are following a CT, then give them a little extra symbol to show it.
+ DrawIconCS( m_hostageFollowing, m_hostageFollowingOffscreen, hostage->position, sizeForHostage, hostage->angle[YAW], alpha );
+ }
+ }
+ }
+}
+void CCSMapOverview::SetMap(const char * levelname)
+{
+ BaseClass::SetMap(levelname);
+
+ int wide, tall;
+ surface()->DrawGetTextureSize( m_nMapTextureID, wide, tall );
+ if( wide == 0 && tall == 0 )
+ {
+ m_nMapTextureID = -1;
+ m_nRadarMapTextureID = -1;
+ return;// No map image, so no radar image
+ }
+
+ char radarFileName[MAX_PATH];
+ Q_snprintf(radarFileName, MAX_PATH, "%s_radar", m_MapKeyValues->GetString("material"));
+ m_nRadarMapTextureID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile(m_nRadarMapTextureID, radarFileName, true, false);
+ int radarWide = -1;
+ int radarTall = -1;
+ surface()->DrawGetTextureSize(m_nRadarMapTextureID, radarWide, radarTall);
+ bool radarTextureFound = false;
+ if( radarWide == wide && radarTall == tall )
+ {
+ // Unbelievable that these is no failure return from SetTextureFile, and not
+ // even a ValidTexture check on the ID. So I can check if it is different from
+ // the original. It'll be a 32x32 default if not present.
+ radarTextureFound = true;
+ }
+
+ if( !radarTextureFound )
+ {
+ if( !CreateRadarImage(m_MapKeyValues->GetString("material"), radarFileName) )
+ m_nRadarMapTextureID = -1;
+ }
+
+ ClearGoalIcons();
+}
+
+bool CCSMapOverview::CreateRadarImage(const char *mapName, const char * radarFileName)
+{
+#ifdef GENERATE_RADAR_FILE
+ char fullFileName[MAX_PATH];
+ Q_snprintf(fullFileName, MAX_PATH, "materials/%s.vtf", mapName);
+ char fullRadarFileName[MAX_PATH];
+ Q_snprintf(fullRadarFileName, MAX_PATH, "materials/%s.vtf", radarFileName);
+
+ // Not found, so try to make one
+ FileHandle_t fp;
+ fp = ::filesystem->Open( fullFileName, "rb" );
+ if( !fp )
+ {
+ return false;
+ }
+ ::filesystem->Seek( fp, 0, FILESYSTEM_SEEK_TAIL );
+ int srcVTFLength = ::filesystem->Tell( fp );
+ ::filesystem->Seek( fp, 0, FILESYSTEM_SEEK_HEAD );
+
+ CUtlBuffer buf;
+ buf.EnsureCapacity( srcVTFLength );
+ int overviewMapBytesRead = ::filesystem->Read( buf.Base(), srcVTFLength, fp );
+ ::filesystem->Close( fp );
+
+ buf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );// Need to set these explicitly since ->Read goes straight to memory and skips them.
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, overviewMapBytesRead );
+
+ IVTFTexture *radarTexture = CreateVTFTexture();
+ if (radarTexture->Unserialize(buf))
+ {
+ ImageFormat oldImageFormat = radarTexture->Format();
+ radarTexture->ConvertImageFormat(IMAGE_FORMAT_RGBA8888, false);
+ unsigned char *imageData = radarTexture->ImageData(0,0,0);
+ int size = radarTexture->ComputeTotalSize(); // in bytes!
+ unsigned char *pEnd = imageData + size;
+
+ for( ; imageData < pEnd; imageData += 4 )
+ {
+ imageData[0] = 0; // R
+ imageData[2] = 0; // B
+ }
+
+ radarTexture->ConvertImageFormat(oldImageFormat, false);
+
+ buf.Clear();
+ radarTexture->Serialize(buf);
+
+ fp = ::filesystem->Open(fullRadarFileName, "wb");
+ ::filesystem->Write(buf.Base(), buf.TellPut(), fp);
+ ::filesystem->Close(fp);
+ DestroyVTFTexture(radarTexture);
+ buf.Purge();
+
+ // And need a vmt file to go with it.
+ char vmtFilename[MAX_PATH];
+ Q_snprintf(vmtFilename, MAX_PATH, "%s", fullRadarFileName);
+ char *extension = &vmtFilename[Q_strlen(vmtFilename) - 3];
+ *extension++ = 'v';
+ *extension++ = 'm';
+ *extension++ = 't';
+ *extension++ = '\0';
+ fp = ::filesystem->Open(vmtFilename, "wt");
+ ::filesystem->Write("\"UnlitGeneric\"\n", 15, fp);
+ ::filesystem->Write("{\n", 2, fp);
+ ::filesystem->Write("\t\"$translucent\" \"1\"\n", 20, fp);
+ ::filesystem->Write("\t\"$basetexture\" \"", 17, fp);
+ ::filesystem->Write(radarFileName, Q_strlen(radarFileName), fp);
+ ::filesystem->Write("\"\n", 2, fp);
+ ::filesystem->Write("\t\"$vertexalpha\" \"1\"\n", 20, fp);
+ ::filesystem->Write("\t\"$vertexcolor\" \"1\"\n", 20, fp);
+ ::filesystem->Write("\t\"$no_fullbright\" \"1\"\n", 22, fp);
+ ::filesystem->Write("\t\"$ignorez\" \"1\"\n", 16, fp);
+ ::filesystem->Write("}\n", 2, fp);
+ ::filesystem->Close(fp);
+
+ m_nRadarMapTextureID = surface()->CreateNewTextureID();
+ surface()->DrawSetTextureFile( m_nRadarMapTextureID, radarFileName, true, true);
+ return true;
+ }
+#endif
+ return false;
+}
+
+void CCSMapOverview::ResetRound()
+{
+ BaseClass::ResetRound();
+
+ for (int i=0; i<MAX_PLAYERS; i++)
+ {
+ CSMapPlayer_t *p = &m_PlayersCSInfo[i];
+
+ p->isDead = false;
+
+ p->overrideFadeTime = -1;
+ p->overrideExpirationTime = -1;
+ p->overrideIcon = -1;
+ p->overrideIconOffscreen = -1;
+ p->overridePosition = Vector( 0, 0, 0);
+ p->overrideAngle = QAngle(0, 0, 0);
+
+ p->timeLastSeen = -1;
+ p->timeFirstSeen = -1;
+ p->isHostage = false;
+
+ p->flashUntilTime = -1;
+ p->nextFlashPeakTime = -1;
+ p->currentFlashAlpha = 0;
+ }
+
+ for (int i=0; i<MAX_HOSTAGES; i++)
+ {
+ MapPlayer_t *basep = &m_Hostages[i];
+ CSMapPlayer_t *p = &m_HostagesCSInfo[i];
+
+ basep->health = 100;
+ Q_memset( basep->trail, 0, sizeof(basep->trail) );
+ basep->position = Vector( 0, 0, 0 );
+ basep->index = 0;
+
+ p->isDead = false;
+
+ p->overrideFadeTime = -1;
+ p->overrideExpirationTime = -1;
+ p->overrideIcon = -1;
+ p->overrideIconOffscreen = -1;
+ p->overridePosition = Vector( 0, 0, 0);
+ p->overrideAngle = QAngle(0, 0, 0);
+
+ p->timeLastSeen = -1;
+ p->timeFirstSeen = -1;
+ p->isHostage = false;
+
+ p->flashUntilTime = -1;
+ p->nextFlashPeakTime = -1;
+ p->currentFlashAlpha = 0;
+ }
+
+ m_bomb.position = Vector(0,0,0);
+ m_bomb.state = CSMapBomb_t::BOMB_INVALID;
+ m_bomb.timeLastSeen = -1;
+ m_bomb.timeFirstSeen = -1;
+ m_bomb.timeFade = -1;
+ m_bomb.timeGone = -1;
+
+ m_bomb.currentRingRadius = -1;
+ m_bomb.currentRingAlpha = -1;
+ m_bomb.maxRingRadius = -1;
+ m_bomb.ringTravelTime = -1;
+
+ m_goalIconsLoaded = false;
+}
+
+void CCSMapOverview::DrawCamera()
+{
+ C_BasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+
+ if (!localPlayer)
+ return;
+
+ if( localPlayer->GetObserverMode() == OBS_MODE_ROAMING )
+ {
+ // Instead of the programmer-art red dot, we'll draw an icon for when our camera is roaming.
+ int alpha = 255;
+ DrawIconCS(m_cameraIconFree, m_cameraIconFree, localPlayer->GetAbsOrigin(), m_flIconSize * 3.0f, localPlayer->EyeAngles()[YAW], alpha);
+ }
+ else if( localPlayer->GetObserverMode() == OBS_MODE_IN_EYE )
+ {
+ if( localPlayer->GetObserverTarget() )
+ {
+ // Fade it if it is on top of a player dot. And don't rotate it.
+ int alpha = 255 * 0.5f;
+ DrawIconCS(m_cameraIconFirst, m_cameraIconFirst, localPlayer->GetObserverTarget()->GetAbsOrigin(), m_flIconSize * 1.5f, GetViewAngle(), alpha);
+ }
+ }
+ else if( localPlayer->GetObserverMode() == OBS_MODE_CHASE )
+ {
+ if( localPlayer->GetObserverTarget() )
+ {
+ // Or Draw the third-camera a little bigger. (Needs room to be off the dot being followed)
+ int alpha = 255;
+ DrawIconCS(m_cameraIconThird, m_cameraIconThird, localPlayer->GetObserverTarget()->GetAbsOrigin(), m_flIconSize * 3.0f, localPlayer->EyeAngles()[YAW], alpha);
+ }
+ }
+}
+
+void CCSMapOverview::FireGameEvent( IGameEvent *event )
+{
+ const char * type = event->GetName();
+
+ if ( Q_strcmp(type,"hostage_killed") == 0 )
+ {
+ MapPlayer_t *hostage = GetHostageByEntityID( event->GetInt("hostage") );
+
+// DevMsg("Hostage id %d just died.\n", event->GetInt("hostage"));
+
+ if ( !hostage )
+ return;
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ return;
+
+ hostage->health = 0;
+ hostageCS->isDead = true;
+ Q_memset( hostage->trail, 0, sizeof(hostage->trail) ); // clear trails
+
+ hostageCS->overrideIcon = m_TeamIconsDead[MAP_ICON_HOSTAGE];
+ hostageCS->overrideIconOffscreen = hostageCS->overrideIcon;
+ hostageCS->overridePosition = hostage->position;
+ hostageCS->overrideAngle = hostage->angle;
+ hostageCS->overrideFadeTime = gpGlobals->curtime + DEATH_ICON_FADE;
+ hostageCS->overrideExpirationTime = gpGlobals->curtime + DEATH_ICON_DURATION;
+ }
+ else if ( Q_strcmp(type,"hostage_rescued") == 0 )
+ {
+ MapPlayer_t *hostage = GetHostageByEntityID( event->GetInt("hostage") );
+
+// DevMsg("Hostage id %d just got rescued.\n", event->GetInt("hostage"));
+
+ if ( !hostage )
+ return;
+
+ CSMapPlayer_t *hostageCS = GetCSInfoForHostage(hostage);
+
+ if ( !hostageCS )
+ return;
+
+ hostage->health = 0;
+ hostageCS->isDead = true;
+ Q_memset( hostage->trail, 0, sizeof(hostage->trail) ); // clear trails
+
+ hostageCS->overrideIcon = hostage->icon;
+ hostageCS->overrideIconOffscreen = -1;
+ hostageCS->overridePosition = hostage->position;
+ hostageCS->overrideAngle = hostage->angle;
+ hostageCS->overrideFadeTime = gpGlobals->curtime;
+ hostageCS->overrideExpirationTime = gpGlobals->curtime + HOSTAGE_RESCUE_DURATION;
+ }
+ else if ( Q_strcmp(type,"bomb_defused") == 0 )
+ {
+ m_bomb.state = CSMapBomb_t::BOMB_GONE;
+ m_bomb.timeFade = gpGlobals->curtime;
+ m_bomb.timeGone = gpGlobals->curtime + BOMB_FADE_DURATION;
+ }
+ else if ( Q_strcmp(type,"bomb_exploded") == 0 )
+ {
+ m_bomb.state = CSMapBomb_t::BOMB_GONE;
+ m_bomb.timeFade = gpGlobals->curtime;
+ m_bomb.timeGone = gpGlobals->curtime + BOMB_FADE_DURATION;
+ }
+ else if ( Q_strcmp(type,"player_death") == 0 )
+ {
+ MapPlayer_t *player = GetPlayerByUserID( event->GetInt("userid") );
+
+ if ( !player )
+ return;
+
+ player->health = 0;
+ Q_memset( player->trail, 0, sizeof(player->trail) ); // clear trails
+
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayer(player);
+
+ if ( !playerCS )
+ return;
+
+ playerCS->isDead = true;
+ playerCS->overrideIcon = m_TeamIconsDead[GetIconNumberFromTeamNumber(player->team)];
+ playerCS->overrideIconOffscreen = playerCS->overrideIcon;
+ playerCS->overridePosition = player->position;
+ playerCS->overrideAngle = player->angle;
+ playerCS->overrideFadeTime = gpGlobals->curtime + DEATH_ICON_FADE;
+ playerCS->overrideExpirationTime = gpGlobals->curtime + DEATH_ICON_DURATION;
+ }
+ else if ( Q_strcmp(type,"player_team") == 0 )
+ {
+ MapPlayer_t *player = GetPlayerByUserID( event->GetInt("userid") );
+
+ if ( !player )
+ return;
+
+ CBasePlayer *localPlayer = C_BasePlayer::GetLocalPlayer();
+ if( localPlayer == NULL )
+ return;
+ MapPlayer_t *localMapPlayer = GetPlayerByUserID(localPlayer->GetUserID());
+
+ player->team = event->GetInt("team");
+
+ if( player == localMapPlayer )
+ player->icon = m_TeamIconsSelf[ GetIconNumberFromTeamNumber(player->team) ];
+ else
+ player->icon = m_TeamIcons[ GetIconNumberFromTeamNumber(player->team) ];
+
+ player->color = m_TeamColors[ GetIconNumberFromTeamNumber(player->team) ];
+ }
+ else
+ {
+ BaseClass::FireGameEvent(event);
+ }
+}
+
+void CCSMapOverview::SetMode(int mode)
+{
+ if ( mode == MAP_MODE_RADAR )
+ {
+ m_flChangeSpeed = 0; // change size instantly
+ // We want the _output_ of the radar to be consistant, so we need to take the map scale in to account.
+ float desiredZoom = (DESIRED_RADAR_RESOLUTION * m_fMapScale) / (OVERVIEW_MAP_SIZE * m_fFullZoom);
+
+ g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "zoom", desiredZoom, 0.0, 0, vgui::AnimationController::INTERPOLATOR_LINEAR );
+
+ if( CBasePlayer::GetLocalPlayer() )
+ SetFollowEntity( CBasePlayer::GetLocalPlayer()->entindex() );
+
+ SetPaintBackgroundType( 2 );// rounded corners
+ ShowPanel( true );
+ }
+ else if ( mode == MAP_MODE_INSET )
+ {
+ SetPaintBackgroundType( 2 );// rounded corners
+
+ float desiredZoom = (overview_preferred_view_size.GetFloat() * m_fMapScale) / (OVERVIEW_MAP_SIZE * m_fFullZoom);
+
+ g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "zoom", desiredZoom, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ }
+ else
+ {
+ SetPaintBackgroundType( 0 );// square corners
+
+ float desiredZoom = 1.0f;
+
+ g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "zoom", desiredZoom, 0.0f, 0.2f, vgui::AnimationController::INTERPOLATOR_LINEAR );
+ }
+
+ BaseClass::SetMode(mode);
+}
+
+void CCSMapOverview::UpdateSizeAndPosition()
+{
+ int x,y,w,h;
+
+ vgui::surface()->GetScreenSize( w, h );
+
+ switch( m_nMode )
+ {
+ case MAP_MODE_RADAR:
+ {
+ // To allow custom hud scripts to work, get our size from the HudRadar element that people already tweak.
+ int x, y, w, t;
+ (GET_HUDELEMENT( CHudRadar ))->GetBounds(x, y, w, t);
+ m_vPosition.x = x;
+ m_vPosition.y = y;
+
+ if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() )
+ {
+ m_vPosition.y += g_pSpectatorGUI->GetTopBarHeight();
+ }
+
+ m_vSize.x = w;
+ m_vSize.y = w;// Intentionally not 't'. We need to enforce square-ness to prevent people from seeing more of the map by fiddling their HudLayout
+ break;
+ }
+
+ case MAP_MODE_INSET:
+ {
+ m_vPosition.x = XRES(16);
+ m_vPosition.y = YRES(16);
+
+ if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() )
+ {
+ m_vPosition.y += g_pSpectatorGUI->GetTopBarHeight();
+ }
+
+ m_vSize.x = w/4;
+ m_vSize.y = m_vSize.x/1.333;
+ break;
+ }
+
+ case MAP_MODE_FULL:
+ default:
+ {
+ m_vSize.x = w;
+ m_vSize.y = h;
+
+ m_vPosition.x = 0;
+ m_vPosition.y = 0;
+
+ if ( g_pSpectatorGUI && g_pSpectatorGUI->IsVisible() )
+ {
+ m_vPosition.y += g_pSpectatorGUI->GetTopBarHeight();
+ m_vSize.y -= g_pSpectatorGUI->GetTopBarHeight();
+ m_vSize.y -= g_pSpectatorGUI->GetBottomBarHeight();
+ }
+ break;
+ }
+ }
+
+ GetBounds( x,y,w,h );
+
+ if ( m_flChangeSpeed > 0 )
+ {
+ // adjust slowly
+ int pixels = m_flChangeSpeed * gpGlobals->frametime;
+ x = AdjustValue( x, m_vPosition.x, pixels );
+ y = AdjustValue( y, m_vPosition.y, pixels );
+ w = AdjustValue( w, m_vSize.x, pixels );
+ h = AdjustValue( h, m_vSize.y, pixels );
+ }
+ else
+ {
+ // set instantly
+ x = m_vPosition.x;
+ y = m_vPosition.y;
+ w = m_vSize.x;
+ h = m_vSize.y;
+ }
+
+ SetBounds( x,y,w,h );
+}
+
+void CCSMapOverview::SetPlayerSeen( int index )
+{
+ CSMapPlayer_t *pCS = GetCSInfoForPlayerIndex(index);
+
+ float now = gpGlobals->curtime;
+
+ if( pCS )
+ {
+ if( pCS->timeLastSeen == -1 )
+ pCS->timeFirstSeen = now;
+
+ pCS->timeLastSeen = now;
+ }
+}
+
+void CCSMapOverview::SetBombSeen( bool seen )
+{
+ if( seen )
+ {
+ float now = gpGlobals->curtime;
+
+ if( m_bomb.timeLastSeen == -1 )
+ m_bomb.timeFirstSeen = now;
+
+ m_bomb.timeLastSeen = now;
+ }
+ else
+ {
+ m_bomb.timeFirstSeen = -1;
+ m_bomb.timeLastSeen = -1;
+ }
+}
+
+void CCSMapOverview::FlashEntity( int entityID )
+{
+ MapPlayer_t *player = GetPlayerByEntityID(entityID);
+ if( player == NULL )
+ return;
+
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayer(player);
+
+ if ( !playerCS )
+ return;
+
+ playerCS->flashUntilTime = gpGlobals->curtime + 2.0f;
+ playerCS->currentFlashAlpha = 255;
+ playerCS->nextFlashPeakTime = gpGlobals->curtime + 0.5f;
+}
+
+void CCSMapOverview::UpdateFlashes()
+{
+ float now = gpGlobals->curtime;
+ for (int i=0; i<MAX_PLAYERS; i++)
+ {
+ CSMapPlayer_t *playerCS = GetCSInfoForPlayerIndex(i);
+ if( playerCS->flashUntilTime <= now )
+ {
+ // Flashing over.
+ playerCS->currentFlashAlpha = 0;
+ }
+ else
+ {
+ if( playerCS->nextFlashPeakTime <= now )
+ {
+ // Time for a peak
+ playerCS->currentFlashAlpha = 255;
+ playerCS->nextFlashPeakTime = now + 0.5f;
+ playerCS->nextFlashPeakTime = MIN( playerCS->nextFlashPeakTime, playerCS->flashUntilTime );
+ }
+ else
+ {
+ // Just fade away
+ playerCS->currentFlashAlpha -= ((playerCS->currentFlashAlpha * gpGlobals->frametime) / (playerCS->nextFlashPeakTime - now));
+ playerCS->currentFlashAlpha = MAX( 0, playerCS->currentFlashAlpha );
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::SetPlayerPreferredMode( int mode )
+{
+ // A player has given an explicit overview_mode command, so we need to honor that when we are done being the radar.
+ m_playerPreferredMode = mode;
+
+ // save off non-radar preferred modes
+ switch ( mode )
+ {
+ case MAP_MODE_OFF:
+ overview_preferred_mode.SetValue( MAP_MODE_OFF );
+ break;
+
+ case MAP_MODE_INSET:
+ overview_preferred_mode.SetValue( MAP_MODE_INSET );
+ break;
+
+ case MAP_MODE_FULL:
+ overview_preferred_mode.SetValue( MAP_MODE_FULL );
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::SetPlayerPreferredViewSize( float viewSize )
+{
+ overview_preferred_view_size.SetValue( viewSize );
+}
+
+
+//-----------------------------------------------------------------------------
+int CCSMapOverview::GetIconNumberFromTeamNumber( int teamNumber )
+{
+ switch(teamNumber)
+ {
+ case TEAM_TERRORIST:
+ return MAP_ICON_T;
+
+ case TEAM_CT:
+ return MAP_ICON_CT;
+
+ default:
+ return MAP_ICON_HOSTAGE;
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::ClearGoalIcons()
+{
+ m_goalIcons.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::UpdateGoalIcons()
+{
+ // 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;
+
+ Vector bombA = pCSPR->GetBombsiteAPosition();
+ if( bombA != vec3_origin )
+ {
+ CSMapGoal_t bombGoalA;
+ bombGoalA.position = bombA;
+ bombGoalA.iconToUse = m_bombSiteIconA;
+ m_goalIcons.AddToTail( bombGoalA );
+ m_goalIconsLoaded = true;
+ }
+
+ Vector bombB = pCSPR->GetBombsiteBPosition();
+ if( bombB != vec3_origin )
+ {
+ CSMapGoal_t bombGoalB;
+ bombGoalB.position = bombB;
+ bombGoalB.iconToUse = m_bombSiteIconB;
+ m_goalIcons.AddToTail( bombGoalB );
+ m_goalIconsLoaded = true;
+ }
+
+ for( int rescueIndex = 0; rescueIndex < MAX_HOSTAGE_RESCUES; rescueIndex++ )
+ {
+ Vector hostageI = pCSPR->GetHostageRescuePosition( rescueIndex );
+ if( hostageI != vec3_origin )
+ {
+ CSMapGoal_t hostageGoalI;
+ hostageGoalI.position = hostageI;
+ hostageGoalI.iconToUse = m_hostageRescueIcon;
+ m_goalIcons.AddToTail( hostageGoalI );
+ m_goalIconsLoaded = true;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+void CCSMapOverview::DrawGoalIcons()
+{
+ for( int iconIndex = 0; iconIndex < m_goalIcons.Count(); iconIndex++ )
+ {
+ // Goal icons are drawn without turning, but with edge adjustment.
+ CSMapGoal_t *currentIcon = &(m_goalIcons[iconIndex]);
+ int alpha = 255;
+ DrawIconCS(currentIcon->iconToUse, currentIcon->iconToUse, currentIcon->position, m_flIconSize, GetViewAngle(), alpha, false);
+ }
+}
+
+//-----------------------------------------------------------------------------
+bool CCSMapOverview::IsRadarLocked()
+{
+ return cl_radar_locked.GetBool();
+}
+
+//-----------------------------------------------------------------------------
+int CCSMapOverview::GetMasterAlpha( void )
+{
+ // The master alpha is the alpha that the map wants to draw at. The background will be at half that, and the icons
+ // will always be full. (The icons fade themselves for functional reasons like seen-recently.)
+ int alpha = 255;
+ if( GetMode() == MAP_MODE_RADAR )
+ alpha = cl_radaralpha.GetInt();
+ else
+ alpha = overview_alpha.GetFloat() * 255;
+ alpha = clamp( alpha, 0, 255 );
+
+ return alpha;
+}
+
+//-----------------------------------------------------------------------------
+int CCSMapOverview::GetBorderSize( void )
+{
+ switch( GetMode() )
+ {
+ case MAP_MODE_RADAR:
+ return 4;
+ case MAP_MODE_INSET:
+ return 4;
+ case MAP_MODE_FULL:
+ default:
+ return 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+Vector2D CCSMapOverview::PanelToMap( const Vector2D &panelPos )
+{
+ // This is the reversing of baseclass's MapToPanel
+ int pwidth, pheight;
+ GetSize(pwidth, pheight);
+ float viewAngle = GetViewAngle();
+ float fScale = (m_fZoom * m_fFullZoom) / OVERVIEW_MAP_SIZE;
+
+ Vector offset;
+ offset.x = (panelPos.x - (pwidth * 0.5f)) / pheight;
+ offset.y = (panelPos.y - (pheight * 0.5f)) / pheight;
+
+ offset.x /= fScale;
+ offset.y /= fScale;
+
+ VectorYawRotate( offset, -viewAngle, offset );
+
+ Vector2D mapPos;
+ mapPos.x = offset.x + m_MapCenter.x;
+ mapPos.y = offset.y + m_MapCenter.y;
+
+ return mapPos;
+}