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.
 
 
 
 
 
 

357 lines
9.0 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
#include "cbase.h"
#include "c_plantedc4.h"
#include "engine/IEngineSound.h"
#include "cs_gamerules.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include <bitbuf.h>
#include "precache_register.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
#define PLANTEDC4_MSG_JUSTBLEW 1
#define TIME_TO_DETONATE_WARNING 10
extern ConVar spec_show_xray;
IMPLEMENT_CLIENTCLASS_DT(C_PlantedC4, DT_PlantedC4, CPlantedC4)
RecvPropBool( RECVINFO(m_bBombTicking) ),
RecvPropFloat( RECVINFO(m_flC4Blow) ),
RecvPropFloat( RECVINFO(m_flTimerLength) ),
RecvPropFloat( RECVINFO(m_flDefuseLength) ),
RecvPropFloat( RECVINFO(m_flDefuseCountDown) ),
RecvPropBool( RECVINFO(m_bBombDefused) ),
RecvPropEHandle( RECVINFO(m_hBombDefuser) ),
END_RECV_TABLE()
// PRECACHE_REGISTER_BEGIN( GLOBAL, C_PlantedC4 )
// PRECACHE( PARTICLE_SYSTEM, "bomb_explosion_huge" )
// PRECACHE_REGISTER_END()
CUtlVector< C_PlantedC4* > g_PlantedC4s;
C_PlantedC4::C_PlantedC4() :
m_GlowObject( this, Vector( 1.0f, 1.0f, 1.0f ), 0.0f, false, false )
{
g_PlantedC4s.AddToTail( this );
m_flNextRadarFlashTime = gpGlobals->curtime;
m_bRadarFlash = true;
// Don't beep right away, leave time for the planting sound
m_flNextGlow = gpGlobals->curtime + 1.0;
m_flNextBeep = gpGlobals->curtime + 1.0;
m_hLocalDefusingPlayerHandle = NULL;
}
C_PlantedC4::~C_PlantedC4()
{
g_PlantedC4s.FindAndRemove( this );
}
void C_PlantedC4::SetDormant( bool bDormant )
{
BaseClass::SetDormant( bDormant );
// Remove us from the list of planted C4s.
if ( bDormant )
{
g_PlantedC4s.FindAndRemove( this );
m_bTenSecWarning = false;
}
else
{
if ( g_PlantedC4s.Find( this ) == -1 )
g_PlantedC4s.AddToTail( this );
}
}
void C_PlantedC4::UpdateOnRemove( void )
{
DestroyDefuserRopes();
BaseClass::UpdateOnRemove();
}
void C_PlantedC4::Spawn( void )
{
BaseClass::Spawn();
AddFlag( FL_OBJECT );
SetNextClientThink( CLIENT_THINK_ALWAYS );
m_bTenSecWarning = false;
m_bExplodeWarning = false;
m_bTriggerWarning = false;
DestroyDefuserRopes();
}
void C_PlantedC4::DestroyDefuserRopes( void )
{
FOR_EACH_VEC_BACK( m_hDefuserRopes, i )
{
if ( m_hDefuserRopes[i] )
UTIL_Remove( m_hDefuserRopes[i] );
}
m_hDefuserRopes.RemoveAll();
if ( m_hDefuserMultimeter )
UTIL_Remove( m_hDefuserMultimeter );
}
bool C_PlantedC4::CreateDefuserRopes( void )
{
DestroyDefuserRopes();
// make sure we are being defused
C_CSPlayer *pDefusingPlayer = m_hBombDefuser->Get();
if ( !pDefusingPlayer )
{
DevWarning( "Cannot find defusing player to create bomb defuse wire.\n" );
return false;
}
if ( pDefusingPlayer->IsDormant() )
return false;
if ( !m_hDefuserMultimeter )
{
C_BaseAnimating *pMultimeter = new C_BaseAnimating;
if ( pMultimeter->InitializeAsClientEntity( "models/weapons/w_eq_multimeter.mdl", false ) )
{
pMultimeter->AddSolidFlags( FSOLID_NOT_SOLID );
pMultimeter->AddEffects( EF_BONEMERGE );
pMultimeter->SetParent( pDefusingPlayer );
m_hDefuserMultimeter = pMultimeter;
}
else
{
m_hDefuserMultimeter = NULL;
}
}
if ( !m_hDefuserMultimeter )
{
DevWarning( "Could not create defuser tool model.\n" );
return false;
}
// validate attachments
int nDefuseToolAttachmentA = m_hDefuserMultimeter->LookupAttachment("weapon_defusewire_a");
int nDefuseToolAttachmentB = m_hDefuserMultimeter->LookupAttachment("weapon_defusewire_b");
int nBombClipAttachmentA = LookupAttachment("weapon_defusewire_a");
int nBombClipAttachmentB = LookupAttachment("weapon_defusewire_b");
if ( nDefuseToolAttachmentA < 0 ||
nDefuseToolAttachmentB < 0 ||
nBombClipAttachmentA < 0 ||
nBombClipAttachmentB < 0 )
{
DevWarning( "Could not locate attachment for bomb defuse wire.\n" );
return false;
}
// create the wires
C_RopeKeyframe* pRopeA = C_RopeKeyframe::Create( this, m_hDefuserMultimeter, nBombClipAttachmentA, nDefuseToolAttachmentA, 0.9, "cable/phonecable", 8, ROPE_SIMULATE, ROPE_TYPE_DEFUSECABLES );
if ( pRopeA )
{
pRopeA->AddRopeFlags( ROPE_USE_WIND );
pRopeA->SetSlack( 142 );
pRopeA->AddToLeafSystem();
m_hDefuserRopes[ m_hDefuserRopes.AddToTail() ] = pRopeA;
//pRopeA->AddEffects( EF_NORECEIVESHADOW );
}
else
{
DevWarning( "Failed to create bomb defuse wire.\n" );
return false;
}
C_RopeKeyframe* pRopeB = C_RopeKeyframe::Create( this, m_hDefuserMultimeter, nBombClipAttachmentB, nDefuseToolAttachmentB, 0.9, "cable/phonecable_red", 8, ROPE_SIMULATE, ROPE_TYPE_DEFUSECABLES );
if ( pRopeB )
{
pRopeB->AddRopeFlags( ROPE_USE_WIND );
pRopeB->SetSlack( 142 );
pRopeB->AddToLeafSystem();
m_hDefuserRopes[ m_hDefuserRopes.AddToTail() ] = pRopeB;
//pRopeA->AddEffects( EF_NORECEIVESHADOW );
}
else
{
DevWarning( "Failed to create bomb defuse wire.\n" );
return false;
}
m_hLocalDefusingPlayerHandle = m_hBombDefuser->Get(); // remember this player handle in case it changes
return true;
}
void C_PlantedC4::ClientThink( void )
{
BaseClass::ClientThink();
C_CSPlayer *pDefusingPlayer = m_hBombDefuser->Get();
if ( m_hBombDefuser->Get() != m_hLocalDefusingPlayerHandle )
DestroyDefuserRopes(); // we're still being defused, but the defusing player changed
C_CSPlayer *pLocalPlayer = GetLocalOrInEyeCSPlayer();
if ( pDefusingPlayer && ( pDefusingPlayer != pLocalPlayer || pLocalPlayer->ShouldDraw() ) )
{
if ( m_hDefuserRopes.Count() == 0 )
{
CreateDefuserRopes();
}
}
else
{
DestroyDefuserRopes();
}
// If it's dormant, don't beep or anything..
if ( IsDormant() )
return;
Vector glowColor;
bool bRenderGlow = (CanSeeSpectatorOnlyTools() && spec_show_xray.GetInt());
if ( !m_bBombTicking )
{
// disable C4 thinking if not armed
// undone. we need the bome to resume thinking once it's been actiavted (for training) - mtw
//SetNextClientThink( CLIENT_THINK_NEVER );
if ( m_bBombDefused )
{
glowColor.x = (64.0f/255.0f);
glowColor.y = (255.0f/255.0f);
glowColor.z = (64.0f/255.0f);
m_GlowObject.SetRenderFlags( bRenderGlow, false );
m_GlowObject.SetColor( glowColor );
m_GlowObject.SetAlpha( bRenderGlow ? 0.95f : 0.0f );
}
return;
}
if( ( m_flC4Blow - gpGlobals->curtime ) < 1.0f &&
!m_bTriggerWarning )
{
EmitSound( "C4.ExplodeTriggerTrip" );
int ledAttachmentIndex = LookupAttachment("led");
DispatchParticleEffect( "c4_timer_light_trigger", PATTACH_POINT_FOLLOW, this, ledAttachmentIndex, false, -1 );
m_bTriggerWarning = true;
}
if( ( m_flC4Blow - gpGlobals->curtime ) < 0.0f &&
!m_bExplodeWarning )
{
EmitSound( "C4.ExplodeWarning" );
m_bExplodeWarning = true;
}
if( gpGlobals->curtime > m_flNextBeep )
{
// as it gets closer to going off, increase the radius
CLocalPlayerFilter filter;
float attenuation;
float freq;
//the percent complete of the bomb timer
float fComplete = ( ( m_flC4Blow - gpGlobals->curtime ) / m_flTimerLength );
fComplete = clamp( fComplete, 0.0f, 1.0f );
attenuation = MIN( 0.3 + 0.6 * fComplete, 1.0 );
CSoundParameters params;
if ( ( m_flC4Blow - gpGlobals->curtime ) > 1.0f && GetParametersForSound( "C4.PlantSound", params, NULL ) )
{
EmitSound_t ep( params );
ep.m_SoundLevel = ATTN_TO_SNDLVL( attenuation );
ep.m_pOrigin = &GetAbsOrigin();
EmitSound( filter, SOUND_FROM_WORLD, ep );
}
freq = MAX( 0.1 + 0.9 * fComplete, 0.15 );
m_flNextBeep = gpGlobals->curtime + freq;
}
if( ( m_flC4Blow - gpGlobals->curtime ) <= TIME_TO_DETONATE_WARNING &&
!m_bTenSecWarning )
{
m_bTenSecWarning = true;
if ( !CSGameRules()->IsPlayingTraining() )
{
CLocalPlayerFilter filter;
PlayMusicSelection( filter, CSMUSIC_BOMBTEN );
}
}
glowColor.x = (170.0f/255.0f);
glowColor.y = (0.0f/255.0f);
glowColor.z = (0.0f/255.0f);
if ( (gpGlobals->curtime + 0.25f) > m_flNextGlow )
glowColor.x = (255.0f/255.0f);
if ( gpGlobals->curtime > m_flNextGlow )
{
if ( gpGlobals->curtime > m_flNextGlow && ( m_flC4Blow - gpGlobals->curtime ) > 1.0f )
{
int ledAttachmentIndex = LookupAttachment("led");
DispatchParticleEffect( "c4_timer_light", PATTACH_POINT_FOLLOW, this, ledAttachmentIndex, false, -1 );
}
float freq = 0.1 + 0.9 * ( ( m_flC4Blow - gpGlobals->curtime ) / m_flTimerLength );
if( freq < 0.15 ) freq = 0.15;
m_flNextGlow = gpGlobals->curtime + freq;
}
// Start glowing
m_GlowObject.SetRenderFlags( bRenderGlow, false );
m_GlowObject.SetColor( glowColor );
m_GlowObject.SetAlpha( bRenderGlow ? 0.95f : 0.0f );
}
// Using a new particle system, networked down from the server (KWD)
void C_PlantedC4::Explode( void )
{
// don't hide it in training, we have a particle effect that covers it up and then eventally it all gets removed
if ( !CSGameRules()->IsPlayingTraining() )
AddEffects( EF_NODRAW );
SetDormant( true );
}
float C_PlantedC4::GetDetonationProgress( void )
{
float fComplete = 0.0f;
if ( m_flTimerLength > 0.0f )
{
fComplete = ( ( m_flC4Blow - gpGlobals->curtime ) / m_flTimerLength );
}
return fComplete;
}