text: //========= 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"
  
  #ifdef HL2SB
  ConVar    sk_plr_dmg_stunstick	( "sk_plr_dmg_stunstick","0",FCVAR_REPLICATED );
  ConVar    sk_npc_dmg_stunstick	( "sk_npc_dmg_stunstick","0",FCVAR_REPLICATED );
  #endif
  
  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 },
  #ifdef HL2SB
  	{ ACT_MELEE_ATTACK1,	ACT_MELEE_ATTACK_SWING,	true },
  	{ ACT_IDLE_ANGRY,		ACT_IDLE_ANGRY_MELEE,	true },
  #endif
  };
  
  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 )
  {
  #ifndef HL2SB
  	return 40.0f;
  #else
  	if ( ( GetOwner() != NULL ) && ( GetOwner()->IsPlayer() ) )
  		return sk_plr_dmg_stunstick.GetFloat();
  	
  	return sk_npc_dmg_stunstick.GetFloat();
  #endif
  }
  
  //-----------------------------------------------------------------------------
  // 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 );
  
  #ifdef HL2SB
  				CNPC_MetroPolice *pCop = dynamic_cast<CNPC_MetroPolice *>(pOperator);
  #endif
  				bool bFlashed = false;
  
  #ifdef HL2SB
  				if ( pCop != NULL && pPlayer != NULL )
  				{
  					// See if we need to knock out this target
  					if ( pCop->ShouldKnockOutTarget( pHurt ) )
  					{
  						float yawKick = random->RandomFloat( -48, -24 );
  
  						//Kick the player angles
  						pPlayer->ViewPunch( QAngle( -16, yawKick, 2 ) );
  
  						color32 white = {255,255,255,255};
  						UTIL_ScreenFade( pPlayer, white, 0.2f, 1.0f, FFADE_OUT|FFADE_PURGE|FFADE_STAYOUT );
  						bFlashed = true;
  						
  						pCop->KnockOutTarget( pHurt );
  
  						break;
  					}
  					else
  					{
  						// Notify that we've stunned a target
  						pCop->StunnedTarget( pHurt );
  					}
  				}
  #endif
  				
  				// 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
  