mirror of
https://github.com/nillerusr/source-engine.git
synced 2024-12-29 17:43:01 +00:00
523 lines
13 KiB
C++
523 lines
13 KiB
C++
|
//========= 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 );
|
||
|
}
|
||
|
}
|