diff options
Diffstat (limited to 'game/shared/hl2mp/weapon_stunstick.cpp')
| -rw-r--r-- | game/shared/hl2mp/weapon_stunstick.cpp | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/game/shared/hl2mp/weapon_stunstick.cpp b/game/shared/hl2mp/weapon_stunstick.cpp new file mode 100644 index 0000000..9f70698 --- /dev/null +++ b/game/shared/hl2mp/weapon_stunstick.cpp @@ -0,0 +1,902 @@ +//========= 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
\ No newline at end of file |