You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
522 lines
13 KiB
522 lines
13 KiB
//========= 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 ); |
|
} |
|
}
|
|
|