//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Implements the big scary boom-boom machine Antlions fear. // //=============================================================================// #include "cbase.h" #include "baseentity.h" #include "npcevent.h" #include "rotorwash.h" #include "soundenvelope.h" #include "engine/IEngineSound.h" #include "npc_antlion.h" #include "te_effect_dispatch.h" #if HL2_EPISODIC #define THUMPER_RADIUS m_iEffectRadius // this const is only used inside the thumper anyway #else #define THUMPER_RADIUS 1000 #endif #define STATE_CHANGE_MODIFIER 0.02f #define THUMPER_SOUND_DURATION 1.5f #define THUMPER_MIN_SCALE 128 #define THUMPER_MODEL_NAME "models/props_combine/CombineThumper002.mdl" ConVar thumper_show_radius("thumper_show_radius","0",FCVAR_CHEAT,"If true, advisor will use her custom impact damage table."); class CPropThumper : public CBaseAnimating { public: DECLARE_CLASS( CPropThumper, CBaseAnimating ); DECLARE_DATADESC(); virtual void Spawn( void ); virtual void Precache( void ); virtual void Think ( void ); virtual void HandleAnimEvent( animevent_t *pEvent ); virtual void StopLoopingSounds( void ); void InputDisable( inputdata_t &inputdata ); void InputEnable( inputdata_t &inputdata ); void InitMotorSound( void ); void HandleState( void ); void Thump( void ); private: bool m_bEnabled; int m_iHammerAttachment; CSoundPatch* m_sndMotor; EHANDLE m_hRepellantEnt; int m_iDustScale; COutputEvent m_OnThumped; // Fired when thumper goes off #if HL2_EPISODIC int m_iEffectRadius; #endif }; LINK_ENTITY_TO_CLASS( prop_thumper, CPropThumper ); //----------------------------------------------------------------------------- // Save/load //----------------------------------------------------------------------------- BEGIN_DATADESC( CPropThumper ) DEFINE_FIELD( m_bEnabled, FIELD_BOOLEAN ), DEFINE_FIELD( m_hRepellantEnt, FIELD_EHANDLE ), DEFINE_FIELD( m_iHammerAttachment, FIELD_INTEGER ), DEFINE_KEYFIELD( m_iDustScale, FIELD_INTEGER, "dustscale" ), #if HL2_EPISODIC DEFINE_KEYFIELD( m_iEffectRadius, FIELD_INTEGER, "EffectRadius" ), #endif DEFINE_SOUNDPATCH( m_sndMotor ), DEFINE_THINKFUNC( Think ), DEFINE_INPUTFUNC( FIELD_VOID, "Disable", InputDisable ), DEFINE_INPUTFUNC( FIELD_VOID, "Enable", InputEnable ), DEFINE_OUTPUT( m_OnThumped, "OnThumped" ), END_DATADESC() void CPropThumper::Spawn( void ) { char *szModel = (char *)STRING( GetModelName() ); if (!szModel || !*szModel) { szModel = THUMPER_MODEL_NAME; SetModelName( AllocPooledString(szModel) ); } Precache(); SetModel( szModel ); SetSolid( SOLID_VPHYSICS ); SetMoveType( MOVETYPE_NONE ); VPhysicsInitStatic(); BaseClass::Spawn(); m_bEnabled = true; SetThink( &CPropThumper::Think ); SetNextThink( gpGlobals->curtime + 1.0f ); int iSequence = SelectHeaviestSequence ( ACT_IDLE ); if ( iSequence != ACT_INVALID ) { SetSequence( iSequence ); ResetSequenceInfo(); //Do this so we get the nice ramp-up effect. m_flPlaybackRate = random->RandomFloat( 0.0f, 1.0f); } m_iHammerAttachment = LookupAttachment( "hammer" ); CAntlionRepellant *pRepellant = (CAntlionRepellant*)CreateEntityByName( "point_antlion_repellant" ); if ( pRepellant ) { pRepellant->Spawn(); pRepellant->SetAbsOrigin( GetAbsOrigin() ); pRepellant->SetRadius( THUMPER_RADIUS ); m_hRepellantEnt = pRepellant; } if ( m_iDustScale == 0 ) m_iDustScale = THUMPER_MIN_SCALE; #if HL2_EPISODIC if ( m_iEffectRadius == 0 ) m_iEffectRadius = 1000; #endif } void CPropThumper::Precache( void ) { BaseClass::Precache(); PrecacheModel( STRING( GetModelName() ) ); PrecacheScriptSound( "coast.thumper_hit" ); PrecacheScriptSound( "coast.thumper_ambient" ); PrecacheScriptSound( "coast.thumper_dust" ); PrecacheScriptSound( "coast.thumper_startup" ); PrecacheScriptSound( "coast.thumper_shutdown" ); PrecacheScriptSound( "coast.thumper_large_hit" ); } void CPropThumper::InitMotorSound( void ) { CPASAttenuationFilter filter( this ); m_sndMotor = (CSoundEnvelopeController::GetController()).SoundCreate( filter, entindex(), CHAN_STATIC, "coast.thumper_ambient" , ATTN_NORM ); if ( m_sndMotor ) { (CSoundEnvelopeController::GetController()).Play( m_sndMotor, 1.0f, 100 ); } } void CPropThumper::HandleState( void ) { if ( m_bEnabled == false ) { m_flPlaybackRate = MAX( m_flPlaybackRate - STATE_CHANGE_MODIFIER, 0.0f ); } else { m_flPlaybackRate = MIN( m_flPlaybackRate + STATE_CHANGE_MODIFIER, 1.0f ); } (CSoundEnvelopeController::GetController()).Play( m_sndMotor, 1.0f, m_flPlaybackRate * 100 ); } void CPropThumper::Think( void ) { StudioFrameAdvance(); DispatchAnimEvents( this ); SetNextThink( gpGlobals->curtime + 0.1 ); if ( m_sndMotor == NULL ) InitMotorSound(); else HandleState(); } void CPropThumper::Thump ( void ) { if ( m_iHammerAttachment != -1 ) { Vector vOrigin; GetAttachment( m_iHammerAttachment, vOrigin ); CEffectData data; data.m_nEntIndex = entindex(); data.m_vOrigin = vOrigin; data.m_flScale = m_iDustScale * m_flPlaybackRate; DispatchEffect( "ThumperDust", data ); UTIL_ScreenShake( vOrigin, 10.0 * m_flPlaybackRate, m_flPlaybackRate, m_flPlaybackRate / 2, THUMPER_RADIUS * m_flPlaybackRate, SHAKE_START, false ); } EmitSound( "coast.thumper_dust" ); CSoundEnt::InsertSound ( SOUND_THUMPER, GetAbsOrigin(), THUMPER_RADIUS * m_flPlaybackRate, THUMPER_SOUND_DURATION, this ); if ( thumper_show_radius.GetBool() ) { NDebugOverlay::Box( GetAbsOrigin(), Vector(-THUMPER_RADIUS, -THUMPER_RADIUS, -THUMPER_RADIUS), Vector(THUMPER_RADIUS, THUMPER_RADIUS, THUMPER_RADIUS), 255, 64, 64, 255, THUMPER_SOUND_DURATION ); } if ( m_flPlaybackRate < 0.7f ) return; if( m_iDustScale == THUMPER_MIN_SCALE ) EmitSound( "coast.thumper_hit" ); else EmitSound( "coast.thumper_large_hit" ); // Signal that we've thumped m_OnThumped.FireOutput( this, this ); } void CPropThumper::HandleAnimEvent( animevent_t *pEvent ) { if ( pEvent->event == AE_THUMPER_THUMP ) { Thump(); return; } BaseClass::HandleAnimEvent( pEvent ); } //----------------------------------------------------------------------------- // Shuts down sounds //----------------------------------------------------------------------------- void CPropThumper::StopLoopingSounds( void ) { if ( m_sndMotor != NULL ) { (CSoundEnvelopeController::GetController()).SoundDestroy( m_sndMotor ); m_sndMotor = NULL; } BaseClass::StopLoopingSounds(); } void CPropThumper::InputDisable( inputdata_t &inputdata ) { m_bEnabled = false; EmitSound( "coast.thumper_shutdown" ); if ( m_hRepellantEnt ) { variant_t emptyVariant; m_hRepellantEnt->AcceptInput( "Disable", this, this, emptyVariant, 0 ); } } void CPropThumper::InputEnable( inputdata_t &inputdata ) { m_bEnabled = true; EmitSound( "coast.thumper_startup" ); if ( m_hRepellantEnt ) { variant_t emptyVariant; m_hRepellantEnt->AcceptInput( "Enable", this, this, emptyVariant, 0 ); } }