//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: Stun Stick- beating stick with a zappy end // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "npcevent.h" #include "weapon_hl2mpbasebasebludgeon.h" #include "IEffects.h" #include "debugoverlay_shared.h" #ifndef CLIENT_DLL #include "npc_metropolice.h" #include "te_effect_dispatch.h" #endif #ifdef CLIENT_DLL #include "iviewrender_beams.h" #include "beam_shared.h" #include "materialsystem/imaterial.h" #include "model_types.h" #include "c_te_effect_dispatch.h" #include "fx_quad.h" #include "fx.h" extern void DrawHalo( IMaterial* pMaterial, const Vector &source, float scale, float const *color, float flHDRColorScale ); extern void FormatViewModelAttachment( Vector &vOrigin, bool bInverse ); #endif // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" extern ConVar metropolice_move_and_melee; #define STUNSTICK_RANGE 75.0f #define STUNSTICK_REFIRE 0.8f #define STUNSTICK_BEAM_MATERIAL "sprites/lgtning.vmt" #define STUNSTICK_GLOW_MATERIAL "sprites/light_glow02_add" #define STUNSTICK_GLOW_MATERIAL2 "effects/blueflare1" #define STUNSTICK_GLOW_MATERIAL_NOZ "sprites/light_glow02_add_noz" #ifdef CLIENT_DLL #define CWeaponStunStick C_WeaponStunStick #endif class CWeaponStunStick : public CBaseHL2MPBludgeonWeapon { DECLARE_CLASS( CWeaponStunStick, CBaseHL2MPBludgeonWeapon ); public: CWeaponStunStick(); DECLARE_NETWORKCLASS(); DECLARE_PREDICTABLE(); #ifndef CLIENT_DLL DECLARE_ACTTABLE(); #endif #ifdef CLIENT_DLL virtual int DrawModel( int flags ); virtual void ClientThink( void ); virtual void OnDataChanged( DataUpdateType_t updateType ); virtual RenderGroup_t GetRenderGroup( void ); virtual void ViewModelDrawn( C_BaseViewModel *pBaseViewModel ); #endif virtual void Precache(); void Spawn(); float GetRange( void ) { return STUNSTICK_RANGE; } float GetFireRate( void ) { return STUNSTICK_REFIRE; } bool Deploy( void ); bool Holster( CBaseCombatWeapon *pSwitchingTo = NULL ); void Drop( const Vector &vecVelocity ); void ImpactEffect( trace_t &traceHit ); void SecondaryAttack( void ) {} void SetStunState( bool state ); bool GetStunState( void ); #ifndef CLIENT_DLL void Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ); int WeaponMeleeAttack1Condition( float flDot, float flDist ); #endif float GetDamageForActivity( Activity hitActivity ); CWeaponStunStick( const CWeaponStunStick & ); private: #ifdef CLIENT_DLL #define NUM_BEAM_ATTACHMENTS 9 struct stunstickBeamInfo_t { int IDs[2]; // 0 - top, 1 - bottom }; stunstickBeamInfo_t m_BeamAttachments[NUM_BEAM_ATTACHMENTS]; // Lookup for arc attachment points on the head of the stick int m_BeamCenterAttachment; // "Core" of the effect (center of the head) void SetupAttachmentPoints( void ); void DrawFirstPersonEffects( void ); void DrawThirdPersonEffects( void ); void DrawEffects( void ); bool InSwing( void ); bool m_bSwungLastFrame; #define FADE_DURATION 0.25f float m_flFadeTime; #endif CNetworkVar( bool, m_bActive ); }; //----------------------------------------------------------------------------- // CWeaponStunStick //----------------------------------------------------------------------------- IMPLEMENT_NETWORKCLASS_ALIASED( WeaponStunStick, DT_WeaponStunStick ) BEGIN_NETWORK_TABLE( CWeaponStunStick, DT_WeaponStunStick ) #ifdef CLIENT_DLL RecvPropInt( RECVINFO( m_bActive ) ), #else SendPropInt( SENDINFO( m_bActive ), 1, SPROP_UNSIGNED ), #endif END_NETWORK_TABLE() BEGIN_PREDICTION_DATA( CWeaponStunStick ) END_PREDICTION_DATA() LINK_ENTITY_TO_CLASS( weapon_stunstick, CWeaponStunStick ); PRECACHE_WEAPON_REGISTER( weapon_stunstick ); #ifndef CLIENT_DLL acttable_t CWeaponStunStick::m_acttable[] = { { ACT_RANGE_ATTACK1, ACT_RANGE_ATTACK_SLAM, true }, { ACT_HL2MP_IDLE, ACT_HL2MP_IDLE_MELEE, false }, { ACT_HL2MP_RUN, ACT_HL2MP_RUN_MELEE, false }, { ACT_HL2MP_IDLE_CROUCH, ACT_HL2MP_IDLE_CROUCH_MELEE, false }, { ACT_HL2MP_WALK_CROUCH, ACT_HL2MP_WALK_CROUCH_MELEE, false }, { ACT_HL2MP_GESTURE_RANGE_ATTACK, ACT_HL2MP_GESTURE_RANGE_ATTACK_MELEE, false }, { ACT_HL2MP_GESTURE_RELOAD, ACT_HL2MP_GESTURE_RELOAD_MELEE, false }, { ACT_HL2MP_JUMP, ACT_HL2MP_JUMP_MELEE, false }, }; IMPLEMENT_ACTTABLE(CWeaponStunStick); #endif //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- CWeaponStunStick::CWeaponStunStick( void ) { // HACK: Don't call SetStunState because this tried to Emit a sound before // any players are connected which is a bug m_bActive = false; #ifdef CLIENT_DLL m_bSwungLastFrame = false; m_flFadeTime = FADE_DURATION; // Start off past the fade point #endif } //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- void CWeaponStunStick::Spawn() { Precache(); BaseClass::Spawn(); AddSolidFlags( FSOLID_NOT_STANDABLE ); } void CWeaponStunStick::Precache() { BaseClass::Precache(); PrecacheScriptSound( "Weapon_StunStick.Activate" ); PrecacheScriptSound( "Weapon_StunStick.Deactivate" ); PrecacheModel( STUNSTICK_BEAM_MATERIAL ); PrecacheModel( "sprites/light_glow02_add.vmt" ); PrecacheModel( "effects/blueflare1.vmt" ); PrecacheModel( "sprites/light_glow02_add_noz.vmt" ); } //----------------------------------------------------------------------------- // Purpose: Get the damage amount for the animation we're doing // Input : hitActivity - currently played activity // Output : Damage amount //----------------------------------------------------------------------------- float CWeaponStunStick::GetDamageForActivity( Activity hitActivity ) { return 40.0f; } //----------------------------------------------------------------------------- // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!) //----------------------------------------------------------------------------- extern ConVar sk_crowbar_lead_time; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponStunStick::ImpactEffect( trace_t &traceHit ) { //#ifndef CLIENT_DLL CEffectData data; data.m_vNormal = traceHit.plane.normal; data.m_vOrigin = traceHit.endpos + ( data.m_vNormal * 4.0f ); DispatchEffect( "StunstickImpact", data ); //#endif //FIXME: need new decals UTIL_ImpactTrace( &traceHit, DMG_CLUB ); } #ifndef CLIENT_DLL int CWeaponStunStick::WeaponMeleeAttack1Condition( float flDot, float flDist ) { // Attempt to lead the target (needed because citizens can't hit manhacks with the crowbar!) CAI_BaseNPC *pNPC = GetOwner()->MyNPCPointer(); CBaseEntity *pEnemy = pNPC->GetEnemy(); if (!pEnemy) return COND_NONE; Vector vecVelocity; AngularImpulse angVelocity; pEnemy->GetVelocity( &vecVelocity, &angVelocity ); // Project where the enemy will be in a little while, add some randomness so he doesn't always hit float dt = sk_crowbar_lead_time.GetFloat(); dt += random->RandomFloat( -0.3f, 0.2f ); if ( dt < 0.0f ) dt = 0.0f; Vector vecExtrapolatedPos; VectorMA( pEnemy->WorldSpaceCenter(), dt, vecVelocity, vecExtrapolatedPos ); Vector vecDelta; VectorSubtract( vecExtrapolatedPos, pNPC->WorldSpaceCenter(), vecDelta ); if ( fabs( vecDelta.z ) > 70 ) { return COND_TOO_FAR_TO_ATTACK; } Vector vecForward = pNPC->BodyDirection2D( ); vecDelta.z = 0.0f; float flExtrapolatedDot = DotProduct2D( vecDelta.AsVector2D(), vecForward.AsVector2D() ); if ((flDot < 0.7) && (flExtrapolatedDot < 0.7)) { return COND_NOT_FACING_ATTACK; } float flExtrapolatedDist = Vector2DNormalize( vecDelta.AsVector2D() ); if( pEnemy->IsPlayer() ) { //Vector vecDir = pEnemy->GetSmoothedVelocity(); //float flSpeed = VectorNormalize( vecDir ); // If player will be in front of me in one-half second, clock his arse. Vector vecProjectEnemy = pEnemy->GetAbsOrigin() + (pEnemy->GetAbsVelocity() * 0.35); Vector vecProjectMe = GetAbsOrigin(); if( (vecProjectMe - vecProjectEnemy).Length2D() <= 48.0f ) { return COND_CAN_MELEE_ATTACK1; } } /* if( metropolice_move_and_melee.GetBool() ) { if( pNPC->IsMoving() ) { flTargetDist *= 1.5f; } } */ float flTargetDist = 48.0f; if ((flDist > flTargetDist) && (flExtrapolatedDist > flTargetDist)) { return COND_TOO_FAR_TO_ATTACK; } return COND_CAN_MELEE_ATTACK1; } void CWeaponStunStick::Operator_HandleAnimEvent( animevent_t *pEvent, CBaseCombatCharacter *pOperator ) { switch( pEvent->event ) { case EVENT_WEAPON_MELEE_HIT: { // Trace up or down based on where the enemy is... // But only if we're basically facing that direction Vector vecDirection; AngleVectors( GetAbsAngles(), &vecDirection ); CBaseEntity *pEnemy = pOperator->MyNPCPointer() ? pOperator->MyNPCPointer()->GetEnemy() : NULL; if ( pEnemy ) { Vector vecDelta; VectorSubtract( pEnemy->WorldSpaceCenter(), pOperator->Weapon_ShootPosition(), vecDelta ); VectorNormalize( vecDelta ); Vector2D vecDelta2D = vecDelta.AsVector2D(); Vector2DNormalize( vecDelta2D ); if ( DotProduct2D( vecDelta2D, vecDirection.AsVector2D() ) > 0.8f ) { vecDirection = vecDelta; } } Vector vecEnd; VectorMA( pOperator->Weapon_ShootPosition(), 32, vecDirection, vecEnd ); // Stretch the swing box down to catch low level physics objects CBaseEntity *pHurt = pOperator->CheckTraceHullAttack( pOperator->Weapon_ShootPosition(), vecEnd, Vector(-16,-16,-40), Vector(16,16,16), GetDamageForActivity( GetActivity() ), DMG_CLUB, 0.5f, false ); // did I hit someone? if ( pHurt ) { // play sound WeaponSound( MELEE_HIT ); CBasePlayer *pPlayer = ToBasePlayer( pHurt ); bool bFlashed = false; // Punch angles if ( pPlayer != NULL && !(pPlayer->GetFlags() & FL_GODMODE) ) { float yawKick = random->RandomFloat( -48, -24 ); //Kick the player angles pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); // If the player's on my head, don't knock him up if ( pPlayer->GetGroundEntity() == pOperator ) { dir = vecDirection; dir.z = 0; } VectorNormalize(dir); dir *= 500.0f; //If not on ground, then don't make them fly! if ( !(pPlayer->GetFlags() & FL_ONGROUND ) ) dir.z = 0.0f; //Push the target back pHurt->ApplyAbsVelocityImpulse( dir ); if ( !bFlashed ) { color32 red = {128,0,0,128}; UTIL_ScreenFade( pPlayer, red, 0.5f, 0.1f, FFADE_IN ); } // Force the player to drop anyting they were holding pPlayer->ForceDropOfCarriedPhysObjects(); } // do effect? } else { WeaponSound( MELEE_MISS ); } } break; default: BaseClass::Operator_HandleAnimEvent( pEvent, pOperator ); break; } } #endif //----------------------------------------------------------------------------- // Purpose: Sets the state of the stun stick //----------------------------------------------------------------------------- void CWeaponStunStick::SetStunState( bool state ) { m_bActive = state; if ( m_bActive ) { //FIXME: START - Move to client-side Vector vecAttachment; QAngle vecAttachmentAngles; GetAttachment( 1, vecAttachment, vecAttachmentAngles ); g_pEffects->Sparks( vecAttachment ); //FIXME: END - Move to client-side EmitSound( "Weapon_StunStick.Activate" ); } else { EmitSound( "Weapon_StunStick.Deactivate" ); } } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CWeaponStunStick::Deploy( void ) { SetStunState( true ); return BaseClass::Deploy(); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- bool CWeaponStunStick::Holster( CBaseCombatWeapon *pSwitchingTo ) { if ( BaseClass::Holster( pSwitchingTo ) == false ) return false; SetStunState( false ); SetWeaponVisible( false ); return true; } //----------------------------------------------------------------------------- // Purpose: // Input : &vecVelocity - //----------------------------------------------------------------------------- void CWeaponStunStick::Drop( const Vector &vecVelocity ) { SetStunState( false ); #ifndef CLIENT_DLL UTIL_Remove( this ); #endif } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CWeaponStunStick::GetStunState( void ) { return m_bActive; } #ifdef CLIENT_DLL //----------------------------------------------------------------------------- // Purpose: Get the attachment point on a viewmodel that a base weapon is using //----------------------------------------------------------------------------- bool UTIL_GetWeaponAttachment( C_BaseCombatWeapon *pWeapon, int attachmentID, Vector &absOrigin, QAngle &absAngles ) { // This is already correct in third-person if ( pWeapon && pWeapon->ShouldDrawUsingViewModel() == false ) { return pWeapon->GetAttachment( attachmentID, absOrigin, absAngles ); } // Otherwise we need to translate the attachment to the viewmodel's version and reformat it CBasePlayer *pOwner = ToBasePlayer( pWeapon->GetOwner() ); if ( pOwner != NULL ) { int ret = pOwner->GetViewModel()->GetAttachment( attachmentID, absOrigin, absAngles ); FormatViewModelAttachment( absOrigin, true ); return ret; } // Wasn't found return false; } #define BEAM_ATTACH_CORE_NAME "sparkrear" //----------------------------------------------------------------------------- // Purpose: Sets up the attachment point lookup for the model //----------------------------------------------------------------------------- void C_WeaponStunStick::SetupAttachmentPoints( void ) { // Setup points for both types of views if ( ShouldDrawUsingViewModel() ) { const char *szBeamAttachNamesTop[NUM_BEAM_ATTACHMENTS] = { "spark1a","spark2a","spark3a","spark4a", "spark5a","spark6a","spark7a","spark8a", "spark9a", }; const char *szBeamAttachNamesBottom[NUM_BEAM_ATTACHMENTS] = { "spark1b","spark2b","spark3b","spark4b", "spark5b","spark6b","spark7b","spark8b", "spark9b", }; // Lookup and store all connections for ( int i = 0; i < NUM_BEAM_ATTACHMENTS; i++ ) { m_BeamAttachments[i].IDs[0] = LookupAttachment( szBeamAttachNamesTop[i] ); m_BeamAttachments[i].IDs[1] = LookupAttachment( szBeamAttachNamesBottom[i] ); } // Setup the center beam point m_BeamCenterAttachment = LookupAttachment( BEAM_ATTACH_CORE_NAME ); } else { // Setup the center beam point m_BeamCenterAttachment = 1; } } //----------------------------------------------------------------------------- // Purpose: Draws the stunstick model (with extra effects) //----------------------------------------------------------------------------- int C_WeaponStunStick::DrawModel( int flags ) { if ( ShouldDraw() == false ) return 0; // Only render these on the transparent pass if ( flags & STUDIO_TRANSPARENCY ) { DrawEffects(); return 1; } return BaseClass::DrawModel( flags ); } //----------------------------------------------------------------------------- // Purpose: Randomly adds extra effects //----------------------------------------------------------------------------- void C_WeaponStunStick::ClientThink( void ) { if ( InSwing() == false ) { if ( m_bSwungLastFrame ) { // Start fading m_flFadeTime = gpGlobals->curtime; m_bSwungLastFrame = false; } return; } // Remember if we were swinging last frame m_bSwungLastFrame = InSwing(); if ( IsEffectActive( EF_NODRAW ) ) return; if ( ShouldDrawUsingViewModel() ) { // Update our effects if ( gpGlobals->frametime != 0.0f && ( random->RandomInt( 0, 3 ) == 0 ) ) { Vector vecOrigin; QAngle vecAngles; // Inner beams BeamInfo_t beamInfo; int attachment = random->RandomInt( 0, 15 ); UTIL_GetWeaponAttachment( this, attachment, vecOrigin, vecAngles ); ::FormatViewModelAttachment( vecOrigin, false ); CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); CBaseEntity *pBeamEnt = pOwner->GetViewModel(); beamInfo.m_vecStart = vec3_origin; beamInfo.m_pStartEnt= pBeamEnt; beamInfo.m_nStartAttachment = attachment; beamInfo.m_pEndEnt = NULL; beamInfo.m_nEndAttachment = -1; beamInfo.m_vecEnd = vecOrigin + RandomVector( -8, 8 ); beamInfo.m_pszModelName = STUNSTICK_BEAM_MATERIAL; beamInfo.m_flHaloScale = 0.0f; beamInfo.m_flLife = 0.05f; beamInfo.m_flWidth = random->RandomFloat( 1.0f, 2.0f ); beamInfo.m_flEndWidth = 0; beamInfo.m_flFadeLength = 0.0f; beamInfo.m_flAmplitude = random->RandomFloat( 16, 32 ); beamInfo.m_flBrightness = 255.0; beamInfo.m_flSpeed = 0.0; beamInfo.m_nStartFrame = 0.0; beamInfo.m_flFrameRate = 1.0f; beamInfo.m_flRed = 255.0f;; beamInfo.m_flGreen = 255.0f; beamInfo.m_flBlue = 255.0f; beamInfo.m_nSegments = 16; beamInfo.m_bRenderable = true; beamInfo.m_nFlags = 0; beams->CreateBeamEntPoint( beamInfo ); } } } //----------------------------------------------------------------------------- // Purpose: Starts the client-side version thinking //----------------------------------------------------------------------------- void C_WeaponStunStick::OnDataChanged( DataUpdateType_t updateType ) { BaseClass::OnDataChanged( updateType ); if ( updateType == DATA_UPDATE_CREATED ) { SetNextClientThink( CLIENT_THINK_ALWAYS ); SetupAttachmentPoints(); } } //----------------------------------------------------------------------------- // Purpose: Tells us we're always a translucent entity //----------------------------------------------------------------------------- RenderGroup_t C_WeaponStunStick::GetRenderGroup( void ) { return RENDER_GROUP_TWOPASS; } //----------------------------------------------------------------------------- // Purpose: Tells us we're always a translucent entity //----------------------------------------------------------------------------- bool C_WeaponStunStick::InSwing( void ) { int activity = GetActivity(); // FIXME: This is needed until the actual animation works if ( ShouldDrawUsingViewModel() == false ) return true; // These are the swing activities this weapon can play if ( activity == GetPrimaryAttackActivity() || activity == GetSecondaryAttackActivity() || activity == ACT_VM_MISSCENTER || activity == ACT_VM_MISSCENTER2 ) return true; return false; } //----------------------------------------------------------------------------- // Purpose: Draw our special effects //----------------------------------------------------------------------------- void C_WeaponStunStick::DrawThirdPersonEffects( void ) { Vector vecOrigin; QAngle vecAngles; float color[3]; float scale; CMatRenderContextPtr pRenderContext( materials ); IMaterial *pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL, NULL, false ); pRenderContext->Bind( pMaterial ); // Get bright when swung if ( InSwing() ) { color[0] = color[1] = color[2] = 0.4f; scale = 22.0f; } else { color[0] = color[1] = color[2] = 0.1f; scale = 20.0f; } // Draw an all encompassing glow around the entire head UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles ); DrawHalo( pMaterial, vecOrigin, scale, color ); if ( InSwing() ) { pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL2, NULL, false ); pRenderContext->Bind( pMaterial ); color[0] = color[1] = color[2] = random->RandomFloat( 0.6f, 0.8f ); scale = random->RandomFloat( 4.0f, 6.0f ); // Draw an all encompassing glow around the entire head UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles ); DrawHalo( pMaterial, vecOrigin, scale, color ); // Update our effects if ( gpGlobals->frametime != 0.0f && ( random->RandomInt( 0, 5 ) == 0 ) ) { Vector vecOrigin; QAngle vecAngles; GetAttachment( 1, vecOrigin, vecAngles ); Vector vForward; AngleVectors( vecAngles, &vForward ); Vector vEnd = vecOrigin - vForward * 1.0f; // Inner beams BeamInfo_t beamInfo; beamInfo.m_vecStart = vEnd; Vector offset = RandomVector( -12, 8 ); offset += Vector(4,4,4); beamInfo.m_vecEnd = vecOrigin + offset; beamInfo.m_pStartEnt= cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) ); beamInfo.m_pEndEnt = cl_entitylist->GetEnt( BEAMENT_ENTITY( entindex() ) ); beamInfo.m_nStartAttachment = 1; beamInfo.m_nEndAttachment = -1; beamInfo.m_nType = TE_BEAMTESLA; beamInfo.m_pszModelName = STUNSTICK_BEAM_MATERIAL; beamInfo.m_flHaloScale = 0.0f; beamInfo.m_flLife = 0.01f; beamInfo.m_flWidth = random->RandomFloat( 1.0f, 3.0f ); beamInfo.m_flEndWidth = 0; beamInfo.m_flFadeLength = 0.0f; beamInfo.m_flAmplitude = random->RandomFloat( 1, 2 ); beamInfo.m_flBrightness = 255.0; beamInfo.m_flSpeed = 0.0; beamInfo.m_nStartFrame = 0.0; beamInfo.m_flFrameRate = 1.0f; beamInfo.m_flRed = 255.0f;; beamInfo.m_flGreen = 255.0f; beamInfo.m_flBlue = 255.0f; beamInfo.m_nSegments = 16; beamInfo.m_bRenderable = true; beamInfo.m_nFlags = FBEAM_SHADEOUT; beams->CreateBeamPoints( beamInfo ); } } } //----------------------------------------------------------------------------- // Purpose: Draw our special effects //----------------------------------------------------------------------------- void C_WeaponStunStick::DrawFirstPersonEffects( void ) { Vector vecOrigin; QAngle vecAngles; float color[3]; float scale; CMatRenderContextPtr pRenderContext( materials ); IMaterial *pMaterial = materials->FindMaterial( STUNSTICK_GLOW_MATERIAL_NOZ, NULL, false ); // FIXME: Needs to work with new IMaterial system! pRenderContext->Bind( pMaterial ); // Find where we are in the fade float fadeAmount = RemapValClamped( gpGlobals->curtime, m_flFadeTime, m_flFadeTime + FADE_DURATION, 1.0f, 0.1f ); // Get bright when swung if ( InSwing() ) { color[0] = color[1] = color[2] = 0.4f; scale = 22.0f; } else { color[0] = color[1] = color[2] = 0.4f * fadeAmount; scale = 20.0f; } if ( color[0] > 0.0f ) { // Draw an all encompassing glow around the entire head UTIL_GetWeaponAttachment( this, m_BeamCenterAttachment, vecOrigin, vecAngles ); DrawHalo( pMaterial, vecOrigin, scale, color ); } // Draw bright points at each attachment location for ( int i = 0; i < (NUM_BEAM_ATTACHMENTS*2)+1; i++ ) { if ( InSwing() ) { color[0] = color[1] = color[2] = random->RandomFloat( 0.05f, 0.5f ); scale = random->RandomFloat( 4.0f, 5.0f ); } else { color[0] = color[1] = color[2] = random->RandomFloat( 0.05f, 0.5f ) * fadeAmount; scale = random->RandomFloat( 4.0f, 5.0f ) * fadeAmount; } if ( color[0] > 0.0f ) { UTIL_GetWeaponAttachment( this, i, vecOrigin, vecAngles ); DrawHalo( pMaterial, vecOrigin, scale, color ); } } } //----------------------------------------------------------------------------- // Purpose: Draw our special effects //----------------------------------------------------------------------------- void C_WeaponStunStick::DrawEffects( void ) { if ( ShouldDrawUsingViewModel() ) { DrawFirstPersonEffects(); } else { DrawThirdPersonEffects(); } } //----------------------------------------------------------------------------- // Purpose: Viewmodel was drawn //----------------------------------------------------------------------------- void C_WeaponStunStick::ViewModelDrawn( C_BaseViewModel *pBaseViewModel ) { // Don't bother when we're not deployed if ( IsWeaponVisible() ) { // Do all our special effects DrawEffects(); } BaseClass::ViewModelDrawn( pBaseViewModel ); } //----------------------------------------------------------------------------- // Purpose: Draw a cheap glow quad at our impact point (with sparks) //----------------------------------------------------------------------------- void StunstickImpactCallback( const CEffectData &data ) { float scale = random->RandomFloat( 16, 32 ); FX_AddQuad( data.m_vOrigin, data.m_vNormal, scale, scale*2.0f, 1.0f, 1.0f, 0.0f, 0.0f, random->RandomInt( 0, 360 ), 0, Vector( 1.0f, 1.0f, 1.0f ), 0.1f, "sprites/light_glow02_add", 0 ); FX_Sparks( data.m_vOrigin, 1, 2, data.m_vNormal, 6, 64, 256 ); } DECLARE_CLIENT_EFFECT( "StunstickImpact", StunstickImpactCallback ); #endif