Counter Strike : Global Offensive Source Code
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.
 
 
 
 
 
 

347 lines
8.8 KiB

//========= Copyright 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "item_sonarpulse.h"
#ifdef CLIENT_DLL
#include "view.h"
#include "materialsystem/imaterialvar.h"
#endif
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define SONARPULSE_MODEL "models/props/props_br/br_sonar/br_sonar.mdl"
#define SONARPULSE_SPEED 270 // in units/sec
#define SONARPULSE_PRICE 1000 // in american dollars
#ifdef CLIENT_DLL
CUtlVector<CSonarPulse*> g_SonarPulsers;
CUtlVector<sonarpulseicon_t> g_SonarPulseIcons;
#endif
#if defined( CLIENT_DLL )
#else
BEGIN_DATADESC( CSonarPulse )
END_DATADESC()
#endif
BEGIN_PREDICTION_DATA( CSonarPulse )
END_PREDICTION_DATA()
IMPLEMENT_NETWORKCLASS_ALIASED( SonarPulse, DT_SonarPulse )
BEGIN_NETWORK_TABLE( CSonarPulse, DT_SonarPulse )
#ifdef CLIENT_DLL
RecvPropBool( RECVINFO(m_bPulseInProgress) ),
RecvPropFloat( RECVINFO(m_flPulseInitTime) )
#else
SendPropBool( SENDINFO(m_bPulseInProgress) ),
SendPropFloat( SENDINFO(m_flPulseInitTime) )
#endif
END_NETWORK_TABLE()
LINK_ENTITY_TO_CLASS_ALIASED( item_sonarpulse, SonarPulse );
PRECACHE_REGISTER( item_sonarpulse );
CSonarPulse::CSonarPulse()
{
#ifndef CLIENT_DLL
m_bPulseInProgress = false;
m_flPulseInitTime = 0;
m_vecPlayersOutsidePulse.RemoveAll();
m_vecPingedPlayers.RemoveAll();
m_flPlaybackRate = 0;
#else
ListenForGameEvent( "add_player_sonar_icon" );
g_SonarPulsers.FindAndFastRemove( this );
g_SonarPulsers.AddToTail( this );
m_pIconMaterial = NULL;
g_SonarPulseIcons.RemoveAll();
#endif
}
CSonarPulse::~CSonarPulse()
{
#ifdef CLIENT_DLL
g_SonarPulsers.FindAndFastRemove( this );
#endif
}
void CSonarPulse::Spawn( void )
{
BaseClass::Spawn();
SetMoveType( MOVETYPE_NONE );
SetSolid( SOLID_VPHYSICS );
SetModel( SONARPULSE_MODEL );
#ifdef CLIENT_DLL
m_pIconMaterial = materials->FindMaterial( "dev/sonar_icon.vmt", TEXTURE_GROUP_OTHER, false );
SetThink( &CSonarPulse::ClientThink );
SetNextClientThink( CLIENT_THINK_ALWAYS );
#else
SetPlaybackRate( 0 );
#endif
}
void CSonarPulse::Precache()
{
PrecacheModel( SONARPULSE_MODEL );
PrecacheSound( "ambient/atmosphere/cs_metalscrapeverb10.wav" );
}
float CSonarPulse::GetPulseRadius( void )
{
if ( !m_bPulseInProgress )
return 0;
float flCurrentDuration = gpGlobals->curtime - m_flPulseInitTime;
return flCurrentDuration * SONARPULSE_SPEED;
}
Vector CSonarPulse::GetPulseOrigin( void )
{
return GetAbsOrigin();
}
#ifdef CLIENT_DLL
void CSonarPulse::ClientThink( void )
{
StudioFrameAdvance();
SetNextClientThink( CLIENT_THINK_ALWAYS );
}
void CSonarPulse::RenderIcons( void )
{
if( !g_SonarPulseIcons.Count() || m_pIconMaterial == NULL )
return;
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( !pLocalPlayer )
return;
Vector vecEyePos = MainViewOrigin(GET_ACTIVE_SPLITSCREEN_SLOT());
CMatRenderContextPtr pRenderContext(materials);
FOR_EACH_VEC_BACK( g_SonarPulseIcons, n )
{
float flLifeTimeRemaining = g_SonarPulseIcons[n].GetLifeRemaining();
if ( flLifeTimeRemaining > 0 )
{
Vector vecIconPos = g_SonarPulseIcons[n].m_vecPos;
Vector vecOrigin;
ScreenTransform( vecIconPos, vecOrigin );
float flSize = RemapValClamped( flLifeTimeRemaining, 10, 9, 1, 32 );
float flEdgeAlpha = 1.0f;
float flTheta = 0.95f;
if ( vecOrigin.Length() > flTheta )
{
vecOrigin = vecOrigin.Normalized() * flTheta;
flSize = MIN( flSize, 24 );
flEdgeAlpha = 0.7f;
}
ConvertNormalizedScreenSpaceToPixelScreenSpace( vecOrigin );
//scale size by distance a bit, as per Brian's request.
flSize *= RemapValClamped( vecEyePos.DistToSqr( vecIconPos ), 1600*1600, 500*500, 0.5f, 1.0f );
vecOrigin.x -= flSize * 0.5f;
vecOrigin.y -= flSize * 0.5f;
IMaterialVar* pVar = m_pIconMaterial->FindVar( "$alpha", NULL );
if ( pVar )
{
pVar->SetFloatValue( flEdgeAlpha * clamp( flLifeTimeRemaining * 0.5f, 0, 1 ) );
}
pRenderContext->DrawScreenSpaceRectangle( m_pIconMaterial,
vecOrigin.x, vecOrigin.y,
flSize, flSize,
0, 0, 32, 32, 32, 32 );
}
else
{
g_SonarPulseIcons.FastRemove( n );
}
}
}
void CSonarPulse::FireGameEvent( IGameEvent *event )
{
if ( Q_strcmp( event->GetName(), "add_player_sonar_icon" ) == 0 )
{
// don't make an icon for the local player - it's confusing
int nUserID = event->GetInt( "userid", -1 );
C_CSPlayer *pLocalPlayer = C_CSPlayer::GetLocalCSPlayer();
if ( pLocalPlayer && pLocalPlayer->GetUserID() == nUserID )
return;
Vector vecPos = Vector( event->GetFloat("pos_x",0), event->GetFloat("pos_y",0), event->GetFloat("pos_z",0) );
sonarpulseicon_t newIcon( vecPos );
g_SonarPulseIcons.AddToTail( newIcon );
//CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByUserId( nUserID ) );
//ConColorMsg( Color(0,255,255,255), "RECEIVE: sonar icon added at [%f, %f, %f] for player: %s\n", vecPos.x, vecPos.y, vecPos.z, pPlayer ? pPlayer->GetPlayerName() : "null" );
}
}
#endif
#ifndef CLIENT_DLL
void CSonarPulse::PulseStart( void )
{
EmitSound( "ambient/atmosphere/cs_metalscrapeverb10.wav" );
m_vecPlayersOutsidePulse.RemoveAll();
m_vecPingedPlayers.RemoveAll();
m_bPulseInProgress = true;
m_flPulseInitTime = gpGlobals->curtime;
SetPlaybackRate( 1 );
SetThink( &CSonarPulse::PulseThink );
SetNextThink( gpGlobals->curtime );
}
void CSonarPulse::PulseReset( void )
{
SetThink( NULL );
SetPlaybackRate( 0 );
m_bPulseInProgress = false;
m_flPulseInitTime = 0;
m_vecPlayersOutsidePulse.RemoveAll();
m_vecPingedPlayers.RemoveAll();
m_flPlaybackRate = 0;
}
bool CSonarPulse::IsOkToPulse( CCSPlayer* pPlayer )
{
return ( pPlayer && pPlayer->IsAlive() && !pPlayer->IsChickenClass() && !pPlayer->IsFlyingDroneClass() && !pPlayer->m_bIsParachuting );
}
void CSonarPulse::PulseThink( void )
{
if ( !m_bPulseInProgress )
{
PulseReset();
return;
}
float flRadius = GetPulseRadius();
Vector vecPulseCenter = GetPulseOrigin();
float flRadSqrCurrent = flRadius * flRadius;
// ping the players that were outside the pulse last think and are now inside
FOR_EACH_VEC_BACK( m_vecPlayersOutsidePulse, n )
{
CCSPlayer *pPlayer = ToCSPlayer( m_vecPlayersOutsidePulse[n] );
if ( IsOkToPulse( pPlayer ) )
{
Vector vecPlayerPos = pPlayer->GetAbsOrigin() + Vector(0,0,40);
float flPlayerDist = vecPlayerPos.DistToSqr( vecPulseCenter );
if ( flPlayerDist < flRadSqrCurrent && !m_vecPingedPlayers.HasElement( pPlayer ) )
{
// The pulse crossed this player - ping them!
pPlayer->EmitSound( "Bot.StuckSound" );
IGameEvent * sonar_ping_event = gameeventmanager->CreateEvent( "add_player_sonar_icon" );
if ( sonar_ping_event )
{
sonar_ping_event->SetInt( "userid", pPlayer->GetUserID() );
sonar_ping_event->SetFloat( "pos_x", vecPlayerPos.x );
sonar_ping_event->SetFloat( "pos_y", vecPlayerPos.y );
sonar_ping_event->SetFloat( "pos_z", vecPlayerPos.z );
gameeventmanager->FireEvent( sonar_ping_event );
}
m_vecPlayersOutsidePulse.FindAndRemove( pPlayer );
m_vecPingedPlayers.AddToTail( pPlayer );
//ConColorMsg( Color(0,255,0,255), "SEND: sonar icon added at [%f, %f, %f] for player: %s\n", vecPlayerPos.x, vecPlayerPos.y, vecPlayerPos.z, pPlayer->GetPlayerName() );
}
}
else
{
// player is invalid for some reason, might have left, been killed, etc
m_vecPlayersOutsidePulse.FindAndRemove( pPlayer );
}
}
// re-gather players to add to the list that are outside the pulse
for ( int i = 1; i <= MAX_PLAYERS; i++ )
{
CCSPlayer *pPlayer = ToCSPlayer( UTIL_PlayerByIndex( i ) );
if ( IsOkToPulse( pPlayer ) )
{
Vector vecPlayerPos = pPlayer->GetAbsOrigin() + Vector(0,0,40);
float flPlayerDist = vecPlayerPos.DistToSqr( vecPulseCenter );
if ( flPlayerDist > flRadSqrCurrent && !m_vecPlayersOutsidePulse.HasElement(pPlayer) )
{
m_vecPlayersOutsidePulse.AddToTail( pPlayer );
}
}
}
if ( m_vecPlayersOutsidePulse.Count() == 0 )
{
PulseReset();
return;
}
SetNextThink( gpGlobals->curtime + 0.1f );
}
void CSonarPulse::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
CCSPlayer *pPlayer = dynamic_cast< CCSPlayer* >( pActivator );
if ( !pPlayer )
return;
int nCost = SONARPULSE_PRICE;
if ( m_bPulseInProgress || pPlayer->GetAccountBalance() < nCost )
{
// we dont have enough money
// play an error sound
Vector soundPosition = GetAbsOrigin() + Vector( 0, 0, 32 );
CPASAttenuationFilter filter( soundPosition );
EmitSound( filter, 0, "Vote.Failed", &GetAbsOrigin() );
return;
}
// deduct the amount
pPlayer->AddAccount( -nCost, false, true, "" );
m_bPulseInProgress = true;
SetThink( &CSonarPulse::PulseStart );
SetNextThink( gpGlobals->curtime + 1 );
EmitSound( "UI.Guardian.TooFarWarning" );
}
#endif // #ifndef CLIENT_DLL