summaryrefslogtreecommitdiff
path: root/game/client/cstrike/hud_radar.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'game/client/cstrike/hud_radar.cpp')
-rw-r--r--game/client/cstrike/hud_radar.cpp522
1 files changed, 522 insertions, 0 deletions
diff --git a/game/client/cstrike/hud_radar.cpp b/game/client/cstrike/hud_radar.cpp
new file mode 100644
index 0000000..f3368f5
--- /dev/null
+++ b/game/client/cstrike/hud_radar.cpp
@@ -0,0 +1,522 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include <vgui/ISurface.h>
+#include "clientmode_csnormal.h"
+#include "cs_gamerules.h"
+#include "hud_numericdisplay.h"
+#include "voice_status.h"
+#include "c_plantedc4.h"
+#include "weapon_c4.h"
+#include "c_cs_hostage.h"
+#include "c_cs_playerresource.h"
+#include <coordsize.h>
+#include "hud_macros.h"
+#include "vgui/IVGui.h"
+#include "vgui/ILocalize.h"
+#include "mapoverview.h"
+#include "cstrikespectatorgui.h"
+#include "hud_radar.h"
+
+#define RADAR_DOT_NORMAL 0
+#define RADAR_DOT_BOMB (1<<0)
+#define RADAR_DOT_HOSTAGE (1<<1)
+#define RADAR_DOT_BOMBCARRIER (1<<2)
+#define RADAR_DOT_VIP (1<<3)
+#define RADAR_DOT_LARGE_FLASH (1<<4)
+#define RADAR_DOT_BOMB_PLANTED (1<<5)
+#define RADAR_IGNORE_Z (1<<6) //always draw this item as if it was at the same Z as the player
+
+extern CUtlVector< CC4* > g_C4s;
+
+ConVar cl_radartype( "cl_radartype", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE );
+ConVar cl_radaralpha( "cl_radaralpha", "200", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, NULL, true, 0, true, 255 );
+ConVar cl_locationalpha( "cl_locationalpha", "150", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, NULL, true, 0, true, 255 );
+
+DECLARE_HUDELEMENT( CHudRadar );
+DECLARE_HUD_MESSAGE( CHudRadar, UpdateRadar );
+
+static CHudRadar *s_Radar = NULL;
+CUtlVector<CPlayerRadarFlash> g_RadarFlashes;
+
+
+CHudRadar::CHudRadar( const char *pName ) : vgui::Panel( NULL, "HudRadar" ), CHudElement( pName )
+{
+ SetParent( g_pClientMode->GetViewport() );
+
+ m_pBackground = NULL;
+ m_pBackgroundTrans = NULL;
+
+ m_flNextBombFlashTime = 0.0;
+ m_bBombFlash = true;
+
+ m_flNextHostageFlashTime = 0.0;
+ m_bHostageFlash = true;
+ m_bHideRadar = false;
+
+ s_Radar = this;
+
+ SetHiddenBits( HIDEHUD_PLAYERDEAD );
+
+}
+
+
+CHudRadar::~CHudRadar()
+{
+ s_Radar = NULL;
+}
+
+
+void CHudRadar::Init()
+{
+ HOOK_HUD_MESSAGE( CHudRadar, UpdateRadar );
+}
+
+void CHudRadar::LevelInit()
+{
+ m_flNextBombFlashTime = 0.0;
+ m_bBombFlash = true;
+
+ m_flNextHostageFlashTime = 0.0;
+ m_bHostageFlash = true;
+
+ g_RadarFlashes.RemoveAll();
+
+ // Map Overview handles radar duties now.
+ if( g_pMapOverview )
+ g_pMapOverview->SetMode(CCSMapOverview::MAP_MODE_RADAR);
+}
+
+void CHudRadar::Reset()
+{
+ CHudElement::Reset();
+
+ if( g_pMapOverview )
+ g_pMapOverview->SetMode(CCSMapOverview::MAP_MODE_RADAR);
+}
+
+void CHudRadar::MsgFunc_UpdateRadar(bf_read &msg )
+{
+ int iPlayerEntity = msg.ReadByte();
+
+ //Draw objects on the radar
+ //=============================
+ C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ if ( !pLocalPlayer )
+ return;
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+
+ if ( !pCSPR )
+ return;
+
+ //Players
+ for(int i=1;i<=MAX_PLAYERS;i++)
+ {
+ if( i == pLocalPlayer->entindex() )
+ continue;
+
+ C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex(i) );
+
+ if ( pPlayer )
+ {
+ pPlayer->m_bDetected = false;
+ }
+ }
+
+
+ while ( iPlayerEntity > 0 )
+ {
+ int x = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4;
+ int y = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4;
+ int z = msg.ReadSBitLong( COORD_INTEGER_BITS-1 ) * 4;
+ int a = msg.ReadSBitLong( 9 );
+
+ C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex(iPlayerEntity) );
+
+ Vector origin( x, y, z );
+ QAngle angles( 0, a, 0 );
+
+ if ( g_pMapOverview )
+ {
+ g_pMapOverview->SetPlayerPositions( iPlayerEntity-1, origin, angles );
+ }
+
+ iPlayerEntity = msg.ReadByte(); // read index for next player
+
+ if ( !pPlayer )
+ continue;
+
+ bool bOppositeTeams = (pLocalPlayer->GetTeamNumber() != TEAM_UNASSIGNED && pCSPR->GetTeam( pPlayer->entindex() ) != pLocalPlayer->GetTeamNumber());
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [tj] This used to do slightly different logic that caused other players
+ // to twitch while you were observing.
+ //=============================================================================
+ // Don't update players if they are in PVS.
+ if (!pPlayer->IsDormant())
+ {
+ continue;
+ }
+
+ //Don't update players if you are sill alive and they are an enemy.
+ if (bOppositeTeams && !pLocalPlayer->IsObserver())
+ {
+ continue;
+ }
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+ // update origin and angle for players out of my PVS
+ origin = pPlayer->GetAbsOrigin();
+ angles = pPlayer->GetAbsAngles();
+
+ origin.x = x;
+ origin.y = y;
+ angles.y = a;
+
+ pPlayer->SetAbsOrigin( origin );
+ pPlayer->SetAbsAngles( angles );
+ pPlayer->m_bDetected = true;
+ }
+}
+
+
+bool CHudRadar::ShouldDraw()
+{
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+
+ //=============================================================================
+ // HPE_BEGIN:
+ // [tj] Added base class call
+ //=============================================================================
+ return pPlayer && pPlayer->IsAlive() && !m_bHideRadar && CHudElement::ShouldDraw();
+ //=============================================================================
+ // HPE_END
+ //=============================================================================
+}
+
+void CHudRadar::SetVisible(bool state)
+{
+ BaseClass::SetVisible(state);
+
+ if( g_pMapOverview && g_pMapOverview->GetMode() == CCSMapOverview::MAP_MODE_RADAR )
+ {
+ // We are the hud element still, but he is in charge of the new style now.
+ g_pMapOverview->SetVisible( state );
+ }
+}
+
+void CHudRadar::Paint()
+{
+ // We are the hud element still, but Overview is in charge of the new style now.
+ return;
+}
+
+void CHudRadar::WorldToRadar( const Vector location, const Vector origin, const QAngle angles, float &x, float &y, float &z_delta )
+{
+ float x_diff = location.x - origin.x;
+ float y_diff = location.y - origin.y;
+
+ int iRadarRadius = GetWide(); //width of the panel, it resizes now!
+ float fRange = 16 * iRadarRadius; // radar's range
+
+ float flOffset = atan(y_diff/x_diff);
+ flOffset *= 180;
+ flOffset /= M_PI;
+
+ if ((x_diff < 0) && (y_diff >= 0))
+ flOffset = 180 + flOffset;
+ else if ((x_diff < 0) && (y_diff < 0))
+ flOffset = 180 + flOffset;
+ else if ((x_diff >= 0) && (y_diff < 0))
+ flOffset = 360 + flOffset;
+
+ y_diff = -1*(sqrt((x_diff)*(x_diff) + (y_diff)*(y_diff)));
+ x_diff = 0;
+
+ flOffset = angles.y - flOffset;
+
+ flOffset *= M_PI;
+ flOffset /= 180; // now theta is in radians
+
+ float xnew_diff = x_diff * cos(flOffset) - y_diff * sin(flOffset);
+ float ynew_diff = x_diff * sin(flOffset) + y_diff * cos(flOffset);
+
+ // The dot is out of the radar's range.. Scale it back so that it appears on the border
+ if ( (-1 * y_diff) > fRange )
+ {
+ float flScale;
+
+ flScale = ( -1 * y_diff) / fRange;
+
+ xnew_diff /= flScale;
+ ynew_diff /= flScale;
+ }
+ xnew_diff /= 32;
+ ynew_diff /= 32;
+
+ //output
+ x = (iRadarRadius/2) + (int)xnew_diff;
+ y = (iRadarRadius/2) + (int)ynew_diff;
+ z_delta = location.z - origin.z;
+}
+
+void CHudRadar::DrawPlayerOnRadar( int iPlayer, C_CSPlayer *pLocalPlayer )
+{
+ float x, y, z_delta;
+ int iBaseDotSize = ScreenWidth() / 256;
+ int r, g, b, a = 235;
+
+ C_CS_PlayerResource *pCSPR = (C_CS_PlayerResource*)GameResources();
+
+ if ( !pCSPR )
+ return;
+
+ C_CSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( iPlayer ) );
+
+ if ( !pPlayer )
+ return;
+
+ bool bOppositeTeams = (pLocalPlayer->GetTeamNumber() != TEAM_UNASSIGNED && pCSPR->GetTeam( iPlayer ) != pLocalPlayer->GetTeamNumber());
+
+ if ( bOppositeTeams && pPlayer->m_bDetected == false )
+ return;
+
+
+ WorldToRadar( pPlayer->GetAbsOrigin(), pLocalPlayer->GetAbsOrigin(), pLocalPlayer->LocalEyeAngles(), x, y, z_delta );
+
+ if( pCSPR->HasC4( iPlayer ) || pCSPR->IsVIP( iPlayer ) || bOppositeTeams )
+ {
+ r = 250; g = 0; b = 0;
+ }
+ else if ( 0 /*m_bTrackArray[i-1] == true */ ) // Tracked players (friends we want to keep track of on the radar)
+ {
+ iBaseDotSize *= 2;
+ r = 185; g = 20; b = 20;
+ }
+ else
+ {
+ r = 75; g = 75; b = 250;
+ }
+
+ // Handle the radio flashes
+ bool bRadarFlash = false;
+ if ( g_RadarFlashes.Count() > iPlayer )
+ bRadarFlash = g_RadarFlashes[iPlayer].m_bRadarFlash && g_RadarFlashes[iPlayer].m_iNumRadarFlashes > 0;
+
+ if ( bRadarFlash || GetClientVoiceMgr()->IsPlayerSpeaking( iPlayer ) )
+ {
+ r = 230; g = 110; b = 25; a = 245;
+
+ DrawRadarDot( x, y, z_delta, iBaseDotSize, RADAR_DOT_LARGE_FLASH, r, g, b, a );
+ }
+ else
+ {
+ DrawRadarDot( x, y, z_delta, iBaseDotSize, RADAR_DOT_NORMAL, r, g, b, a );
+ }
+}
+
+
+void CHudRadar::DrawEntityOnRadar( CBaseEntity *pEnt, C_CSPlayer *pLocalPlayer, int flags, int r, int g, int b, int a )
+{
+ float x, y, z_delta;
+ int iBaseDotSize = 4;
+
+ WorldToRadar( pEnt->GetAbsOrigin(), pLocalPlayer->GetAbsOrigin(), pLocalPlayer->LocalEyeAngles(), x, y, z_delta );
+
+ if( flags & RADAR_IGNORE_Z )
+ z_delta = 0;
+
+ DrawRadarDot( x, y, z_delta, iBaseDotSize, flags, r, g, b, a );
+}
+
+void CHudRadar::FillRect( int x, int y, int w, int h )
+{
+ int panel_x, panel_y, panel_w, panel_h;
+ GetBounds( panel_x, panel_y, panel_w, panel_h );
+ vgui::surface()->DrawFilledRect( x, y, x+w, y+h );
+}
+
+void CHudRadar::DrawRadarDot( int x, int y, float z_diff, int iBaseDotSize, int flags, int r, int g, int b, int a )
+{
+ vgui::surface()->DrawSetColor( r, g, b, a );
+
+ if ( flags & RADAR_DOT_LARGE_FLASH )
+ {
+ FillRect( x-1, y-1, iBaseDotSize+1, iBaseDotSize+1 );
+ }
+ else if ( z_diff < -128 ) // below the player
+ {
+ z_diff *= -1;
+
+ if ( z_diff > 3096 )
+ {
+ z_diff = 3096;
+ }
+
+ int iBar = (int)( z_diff / 400 ) + 2;
+
+ // Draw an upside-down T shape to symbolize the dot is below the player.
+
+ iBaseDotSize /= 2;
+
+ //horiz
+ FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize );
+
+ //vert
+ FillRect( x, y - iBar*iBaseDotSize, iBaseDotSize, iBar*iBaseDotSize );
+ }
+ else if ( z_diff > 128 ) // above the player
+ {
+ if ( z_diff > 3096 )
+ {
+ z_diff = 3096;
+ }
+
+ int iBar = (int)( z_diff / 400 ) + 2;
+
+ iBaseDotSize /= 2;
+
+ // Draw a T shape to symbolize the dot is above the player.
+
+ //horiz
+ FillRect( x-(2*iBaseDotSize), y, 5*iBaseDotSize, iBaseDotSize );
+
+ //vert
+ FillRect( x, y, iBaseDotSize, iBar*iBaseDotSize );
+ }
+ else
+ {
+ if ( flags & RADAR_DOT_HOSTAGE )
+ {
+ FillRect( x-1, y-1, iBaseDotSize+1, iBaseDotSize+1 );
+ }
+ else if ( flags & RADAR_DOT_BOMB )
+ {
+ if ( flags & RADAR_DOT_BOMB_PLANTED )
+ {
+ iBaseDotSize = 2;
+ // draw an X for the planted bomb
+ FillRect( x, y, iBaseDotSize, iBaseDotSize );
+ FillRect( x-2, y-2, iBaseDotSize, iBaseDotSize );
+ FillRect( x-2, y+2, iBaseDotSize, iBaseDotSize );
+ FillRect( x+2, y-2, iBaseDotSize, iBaseDotSize );
+ FillRect( x+2, y+2, iBaseDotSize, iBaseDotSize );
+ }
+ else
+ {
+ FillRect( x-1, y-1, iBaseDotSize+1, iBaseDotSize+1 );
+ }
+ }
+ else
+ {
+ FillRect( x, y, iBaseDotSize, iBaseDotSize );
+ }
+ }
+}
+
+
+void Radar_FlashPlayer( int iPlayer )
+{
+ if ( g_RadarFlashes.Count() <= iPlayer )
+ {
+ g_RadarFlashes.AddMultipleToTail( iPlayer - g_RadarFlashes.Count() + 1 );
+ }
+
+ CPlayerRadarFlash *pFlash = &g_RadarFlashes[iPlayer];
+ pFlash->m_flNextRadarFlashTime = gpGlobals->curtime;
+ pFlash->m_iNumRadarFlashes = 16;
+ pFlash->m_bRadarFlash = false;
+
+ g_pMapOverview->FlashEntity(iPlayer);
+}
+
+CON_COMMAND( drawradar, "Draws HUD radar" )
+{
+ (GET_HUDELEMENT( CHudRadar ))->DrawRadar();
+}
+
+CON_COMMAND( hideradar, "Hides HUD radar" )
+{
+ (GET_HUDELEMENT( CHudRadar ))->HideRadar();
+}
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+// Location text under radar
+
+DECLARE_HUDELEMENT( CHudLocation );
+
+CHudLocation::CHudLocation( const char *pName ) : vgui::Label( NULL, "HudLocation", "" ), CHudElement( pName )
+{
+ SetParent( g_pClientMode->GetViewport() );
+}
+
+void CHudLocation::Init()
+{
+ // Make sure we get ticked...
+ vgui::ivgui()->AddTickSignal( GetVPanel() );
+}
+
+void CHudLocation::LevelInit()
+{
+}
+
+bool CHudLocation::ShouldDraw()
+{
+ CCSMapOverview *pCSMapOverview = (CCSMapOverview *)GET_HUDELEMENT( CCSMapOverview );
+
+ if( g_pMapOverview && g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_RADAR && pCSMapOverview && pCSMapOverview->ShouldDraw() == true )
+ return true;
+ else if( g_pMapOverview && g_pMapOverview->GetMode() == CMapOverview::MAP_MODE_INSET )
+ return true;
+
+ return false;
+}
+
+void CHudLocation::ApplySchemeSettings(vgui::IScheme *pScheme)
+{
+ BaseClass::ApplySchemeSettings( pScheme );
+
+ m_fgColor = Color( 64, 255, 64, 255 );
+ SetFont( pScheme->GetFont( "ChatFont" ) );
+ SetBorder( NULL );
+ SetBgColor( Color( 0, 0, 0, 0 ) );
+ SetFgColor( m_fgColor );
+}
+
+void CHudLocation::OnTick()
+{
+ m_fgColor[3] = cl_locationalpha.GetInt();
+ SetFgColor( m_fgColor );
+
+ const char *pszLocation = "";
+ C_CSPlayer *pPlayer = C_CSPlayer::GetLocalCSPlayer();
+ if ( pPlayer )
+ {
+ pszLocation = pPlayer->GetLastKnownPlaceName();
+ }
+ SetText( g_pVGuiLocalize->Find( pszLocation ) );
+
+ // We have two different locations based on the Overview mode.
+ // So we just position ourselves below, and center our text in their width.
+ if( g_pMapOverview )
+ {
+ int x = 0, y = 0;
+ int width = 0, height = 0;
+ g_pMapOverview->GetAsPanel()->GetPos( x, y );
+ g_pMapOverview->GetAsPanel()->GetSize( width, height );
+ y += g_pMapOverview->GetAsPanel()->GetTall();
+ SetPos( x, y );
+ SetWide( width );
+ }
+}