diff options
Diffstat (limited to 'game/client/cstrike/hud_radar.cpp')
| -rw-r--r-- | game/client/cstrike/hud_radar.cpp | 522 |
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 ); + } +} |