//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponShieldGrenade::PrimaryAttack( void )
{
	CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
	if ( !pPlayer )
		return;

	if ( !ComputeEMPFireState() )
		return;

	if ( !GetPrimaryAmmo() )
		return;

	// player "shoot" animation
	PlayAttackAnimation( ACT_VM_THROW );

	ThrowGrenade();

	// Setup for refire
	m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
	CheckRemoveDisguise();

	// If I'm now out of ammo, switch away
	if ( !HasPrimaryAmmo() )
	{
		g_pGameRules->GetNextBestWeapon( pPlayer, NULL );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponCombatPlasmaGrenadeLauncher::PrimaryAttack( void )
{
	CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
	if (!pPlayer)
		return;
	
	WeaponSound(SINGLE);

	// Fire the bullets
	Vector vecSrc = pPlayer->Weapon_ShootPosition( );

	PlayAttackAnimation( GetPrimaryAttackActivity() );

	// Launch the grenade
	Vector vecForward;
	pPlayer->EyeVectors( &vecForward );
	Vector vecOrigin = pPlayer->EyePosition();
	vecOrigin += (vecForward);

#if !defined( CLIENT_DLL )
	float flSpeed = 1200;

	CGrenadeAntiPersonnel* pGrenade = CGrenadeAntiPersonnel::Create(vecOrigin, vecForward * flSpeed, pPlayer );
	pGrenade->SetModel( "models/weapons/w_grenade.mdl" );
	pGrenade->SetBounceSound( "PlasmaGrenade.Bounce" );
	pGrenade->SetDamage( weapon_combat_plasmagrenadelauncher_damage.GetFloat() );
	pGrenade->SetDamageRadius( weapon_combat_plasmagrenadelauncher_radius.GetFloat() );
	pGrenade->SetExplodeOnContact( true );
#endif

	m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
	m_iClip1 = m_iClip1 - 1;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponCombatLaserRifle::PrimaryAttack( void )
{
	CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
	if (!pPlayer)
		return;
	
	WeaponSound(SINGLE);

	// Fire the bullets
	Vector vecSrc = pPlayer->Weapon_ShootPosition( );
	Vector vecAiming;
	pPlayer->EyeVectors( &vecAiming );

	PlayAttackAnimation( GetPrimaryAttackActivity() );

	// Reduce the spread if the player's ducking
	Vector vecSpread = GetBulletSpread();
	vecSpread *= m_flInaccuracy;

	TFGameRules()->FireBullets( CTakeDamageInfo( this, pPlayer, weapon_combat_laserrifle_damage.GetFloat(), DMG_PLASMA), 1, 
		vecSrc, vecAiming, vecSpread, weapon_combat_laserrifle_range.GetFloat(), m_iPrimaryAmmoType, 0, entindex(), 0 );

	m_flInaccuracy += 0.3;
	m_flInaccuracy = clamp(m_flInaccuracy, 0, 1);

	m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
	m_iClip1 = m_iClip1 - 1;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponHarpoon::ItemPostFrame( void )
{
	CBasePlayer *pOwner = ToBasePlayer( GetOwner() );
	if (!pOwner)
		return;

	// Look for button downs
	if ( (pOwner->m_afButtonPressed & IN_ATTACK) && !m_flStartedThrowAt && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
	{
		// If we don't have a harpoon, throw one out. Otherwise, yank it back.
		if ( m_bActiveHarpoon )
		{
			YankHarpoon();
		}
		else
		{
			m_bActiveHarpoon = true;
			m_flStartedThrowAt = gpGlobals->curtime;
			PlayAttackAnimation( ACT_VM_PULLBACK );
			m_flCantThrowUntil = gpGlobals->curtime + SequenceDuration();
		}
	}
	else if ( m_flCantThrowUntil && m_bActiveHarpoon && !(pOwner->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime) && (m_flCantThrowUntil <= gpGlobals->curtime)  )
	{
		m_flNextPrimaryAttack = gpGlobals->curtime;
		PrimaryAttack();
		m_flStartedThrowAt = 0;
		m_flCantThrowUntil = 0;
	}
	else if ( (pOwner->m_nButtons & IN_ATTACK2) && (m_flNextPrimaryAttack <= gpGlobals->curtime) )
	{
		PlayAttackAnimation( ACT_VM_SECONDARYATTACK );
		m_flSecondaryAttackAt = gpGlobals->curtime + SequenceDuration() * 0.3;
		m_flNextPrimaryAttack = gpGlobals->curtime + SequenceDuration();
	}
	else if ( m_flSecondaryAttackAt && m_flSecondaryAttackAt < gpGlobals->curtime )
	{
		SecondaryAttack();
		m_flSecondaryAttackAt = 0;
	}

	//  No buttons down?
	if ( !((pOwner->m_nButtons & IN_ATTACK) || (pOwner->m_nButtons & IN_ATTACK2) || (pOwner->m_nButtons & IN_RELOAD)) )
	{
		WeaponIdle( );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponHarpoon::ThrowGrenade( void )
{
	CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
	if ( !pPlayer )
		return;

	BaseClass::WeaponSound(WPN_DOUBLE);

	// Calculate launch velocity (3 seconds for max distance)
	float flThrowTime = min( (gpGlobals->curtime - m_flStartedThrowAt), 3.0 );
	float flSpeed = 1000 + (200 * flThrowTime);

	PlayAttackAnimation( ACT_VM_PRIMARYATTACK );

	// If the player's crouched, roll the grenade
	if ( pPlayer->GetFlags() & FL_DUCKING )
	{
		// Launch the grenade
		Vector vecForward;
		QAngle vecAngles = pPlayer->EyeAngles();
		// Throw it up just a tad
		vecAngles.x = -1;
		AngleVectors( vecAngles, &vecForward, NULL, NULL);
		Vector vecOrigin;
		VectorLerp( pPlayer->EyePosition(), pPlayer->GetAbsOrigin(), 0.25f, vecOrigin );
		vecOrigin += (vecForward * 16);
		vecForward = vecForward * flSpeed;
		CreateHarpoon(vecOrigin, vecForward, pPlayer );
	}
	else
	{
		// Launch the grenade
		Vector vecForward;
		QAngle vecAngles = pPlayer->EyeAngles();
		AngleVectors( vecAngles, &vecForward, NULL, NULL);
		Vector vecOrigin = pPlayer->EyePosition();
		vecOrigin += (vecForward * 16);
		vecForward = vecForward * flSpeed;
		CreateHarpoon(vecOrigin, vecForward, pPlayer );
	}

	pPlayer->RemoveAmmo( 1, m_iPrimaryAmmoType );
}
//-----------------------------------------------------------------------------
// Purpose: Firing
//-----------------------------------------------------------------------------
void CWeaponRocketLauncher::PrimaryAttack( void )
{
	CBaseTFPlayer *pPlayer = ( CBaseTFPlayer* )GetOwner();
	if ( !pPlayer )
		return;

	if ( !ComputeEMPFireState() )
		return;

	// Weapon "Fire" sound.
	WeaponSound( SINGLE );

	// Play the attack animation (need one for rocket launcher - deploy?)
	PlayAttackAnimation( GetPrimaryAttackActivity() );

	// Fire the rocket (Get the position and angles).
	Vector vecFirePos = pPlayer->Weapon_ShootPosition();
	Vector vecFireAng;
	pPlayer->EyeVectors( &vecFireAng );

	// Shift it down a bit so the firer can see it
	Vector vecRight;
	AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, NULL, &vecRight, NULL );
	vecFirePos += Vector( 0, 0, -8 ) + vecRight * 12;

	// Create the rocket.
#if !defined( CLIENT_DLL )
	CWeaponGrenadeRocket *pRocket = CWeaponGrenadeRocket::Create( vecFirePos, vecFireAng, weapon_rocket_launcher_range.GetFloat(), pPlayer );
#else
	CWeaponGrenadeRocket *pRocket = CWeaponGrenadeRocket::Create( vecFirePos, vecFireAng, 0, pPlayer );
#endif
	if ( pRocket )
	{
		pRocket->SetRealOwner( pPlayer );
#if !defined( CLIENT_DLL )
		pRocket->SetDamage( weapon_rocket_launcher_damage.GetFloat() );
#endif
	}

	// Essentially you are done!
	m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
	m_iClip1 = m_iClip1 - 1;
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponCombat_ChargeablePlasma::PrimaryAttack( void )
{
	CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
	if (!pPlayer)
		return;
	
	WeaponSound(SINGLE);

	// Fire the bullets
	Vector vecSrc = pPlayer->Weapon_ShootPosition( );
	Vector vecAiming;
	pPlayer->EyeVectors( &vecAiming );

	// If we already have a lock target from button down, see if we shouldn't try and get a new one
	// Only do this is the button was released immediately
	if ( !m_hLockTarget || ( m_flLockedAt < gpGlobals->curtime ) )
	{
		m_hLockTarget = GetLockTarget();
	}

	PlayAttackAnimation( GetPrimaryAttackActivity() );

	// Shift it down a bit so the firer can see it
	Vector right;
	AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, NULL, &right, NULL );
	Vector vecStartSpot = vecSrc + Vector(0,0,-8) + right * 12;

	CGuidedPlasma *pShot = CGuidedPlasma::Create(vecStartSpot, vecAiming, m_hLockTarget, m_vecTargetOffset, pPlayer);

	// Set it's charged power level
	if (m_bHasCharge)
		m_flPower = min( MAX_CHARGED_TIME, gpGlobals->curtime - m_flChargeStartTime );
	else
		m_flPower = 0.0f;

	float flDamageMult = RemapVal( m_flPower, 0, MAX_CHARGED_TIME, 1.0, MAX_CHARGED_POWER );
	pShot->SetPowerLevel( flDamageMult );

	m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
	m_iClip1 = m_iClip1 - 1;
	m_hLockTarget = NULL;
}
//-----------------------------------------------------------------------------
// Purpose: Give the harpoon a yank
//-----------------------------------------------------------------------------
void CWeaponHarpoon::YankHarpoon( void )
{
	CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
	if ( !pPlayer )
		return;

#if !defined( CLIENT_DLL )
	if ( m_bActiveHarpoon && m_hHarpoon.Get() )
	{
		// If the harpoon's impaled something, pull it towards me
		CBaseEntity *pTarget = m_hHarpoon->GetImpaledTarget();
		if ( pTarget )
		{
			if ( !pTarget->IsBSPModel() && pTarget->GetMoveType() != MOVETYPE_NONE )
			{
				// Bring him to me!
				EmitSound( "Harpoon.Yank" );

				// Get a yank vector, and raise it a little to get them off the ground if they're on it
				Vector vecOverHere = ( pPlayer->GetAbsOrigin() - pTarget->GetAbsOrigin() );
				VectorNormalize( vecOverHere );
				if ( pTarget->GetFlags() & FL_ONGROUND )
				{
					pTarget->SetGroundEntity( NULL );
					vecOverHere.z = 0.5;
				}
				pTarget->ApplyAbsVelocityImpulse( vecOverHere * 500 );

				PlayAttackAnimation( ACT_VM_HAULBACK );
			}
		}
		m_hHarpoon->SetThink( SUB_Remove );
		m_hHarpoon->SetNextThink( gpGlobals->curtime + 5.0 );
		m_hHarpoon = NULL;
		m_bActiveHarpoon = false;
	}

	DetachRope();
#endif
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponCombatBaseGrenade::PrimaryAttack( void )
{
	CBasePlayer *pPlayer = dynamic_cast<CBasePlayer*>( GetOwner() );
	if ( !pPlayer )
		return;

	if ( !ComputeEMPFireState() )
		return;

	// player "shoot" animation
	PlayAttackAnimation( ACT_VM_THROW );

	ThrowGrenade();

	// Setup for refire
	m_flNextPrimaryAttack = gpGlobals->curtime + 1.0;
	CheckRemoveDisguise();

	// If I'm now out of ammo, switch away
	if ( !HasPrimaryAmmo() )
	{
		pPlayer->SelectLastItem();
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponLaserRifle::PrimaryAttack( void )
{
	CBaseTFPlayer *pPlayer = ToBaseTFPlayer( m_hOwner );
	if ( !pPlayer )
		return;
	
	if ( !ComputeEMPFireState() )
		return;

	WeaponSound(SINGLE);

	PlayAttackAnimation( GetPrimaryAttackActivity() );

	pPlayer->m_fEffects |= EF_MUZZLEFLASH;

	// Fire the beam: BLOW OFF AUTOAIM
	Vector vecSrc	 = pPlayer->Weapon_ShootPosition( pPlayer->GetOrigin() );
	Vector vecAiming, right, up;
	pPlayer->EyeVectors( &vecAiming, &right, &up);

	Vector vecSpread = VECTOR_CONE_4DEGREES;

	// Get endpoint
	float x, y, z;
	do {
		x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5);
		y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5);
		z = x*x+y*y;
	} while (z > 1);
	Vector vecDir = vecAiming + x * vecSpread.x * right + y * vecSpread.y * up;
	Vector vecEnd = vecSrc + vecDir * weapon_laserrifle_range.GetFloat();

	trace_t tr;
	float damagefactor = TFGameRules()->WeaponTraceLine(vecSrc, vecEnd, MASK_SHOT, pPlayer, DMG_ENERGYBEAM, &tr);

	// Hit target?
	if (tr.fraction != 1.0)
	{
		CBaseEntity *pEntity = CBaseEntity::Instance(tr.u.ent);
		if ( pEntity )
		{
			ClearMultiDamage();
			float flDamage = GetDamage( (tr.endpos - vecSrc).Length(), tr.hitgroup );
			flDamage *= damagefactor;  
			pEntity->TraceAttack( CTakeDamageInfo( pPlayer, pPlayer, flDamage, DMG_ENERGYBEAM ), vecDir, &tr );
			ApplyMultiDamage( pPlayer, pPlayer );
		}

		g_pEffects->EnergySplash( tr.endpos, tr.plane.normal );
	}

	// Get hacked gun position
	AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, NULL, &right, NULL );
	Vector vecTracerSrc = vecSrc + Vector (0,0,-8) + right * 12 + vecDir * 16;

	// Laser beam
	CBroadcastRecipientFilter filter;
	te->BeamPoints( filter, 0.0,
					&vecTracerSrc, 
					&tr.endpos, 
					m_iSpriteTexture, 
					0,		// Halo index
					0,		// Start frame
					0,		// Frame rate
					0.2,	// Life
					15,		// Width
					15,		// EndWidth
					0,		// FadeLength
					0,		// Amplitude
					200,	// r
					200,	// g
					255,	// b
					255,	// a
					255	);	// speed

	pPlayer->m_iAmmo[m_iPrimaryAmmoType]--;
	m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();

	CheckRemoveDisguise();
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponCombatBurstRifle::PrimaryAttack( void )
{
	CBaseTFPlayer *pPlayer = (CBaseTFPlayer*)GetOwner();
	if (!pPlayer)
		return;
	
	WeaponSound(SINGLE);

	// Fire the bullets
	Vector vecSrc = pPlayer->Weapon_ShootPosition( );
	Vector vecSpread = GetBulletSpread();
	Vector vecAiming, vecRight, vecUp;
	pPlayer->EyeVectors( &vecAiming, &vecRight, &vecUp );

	// Add some inaccuracy
	int seed = 0;
	float x, y, z;
	do 
	{
		float x1, x2, y1, y2;

		// Note the additional seed because otherwise we get the same set of random #'s and will get stuck
		//  in an infinite loop here potentially
		// FIXME:  Can we use a gaussian random # function instead?  ywb
		x1 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );
		x2 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );
		y1 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );
		y2 = SHARED_RANDOMFLOAT_SEED( -0.5, 0.5, ++seed );

		x = x1 + x2;
		y = y1 + y2;

		z = x*x+y*y;
	} while (z > 1);
	Vector vecDir = vecAiming + x * vecSpread.x * vecRight + y * vecSpread.y * vecUp;

	PlayAttackAnimation( GetPrimaryAttackActivity() );

	// Shift it down a bit so the firer can see it
	Vector right, forward;
	AngleVectors( pPlayer->EyeAngles() + pPlayer->m_Local.m_vecPunchAngle, &forward, &right, NULL );
	Vector vecStartSpot = vecSrc;

	// Get the firing position
#ifdef CLIENT_DLL
	// On our client, grab the viewmodel's firing position
	Vector vecWorldOffset = vecStartSpot + Vector(0,0,-8) + right * 12 + forward * 16;
#else
	// For everyone else, grab the weapon model's position
	/*
	Vector vecWorldOffset;
	QAngle angIgnore;
	GetAttachment( LookupAttachment( "muzzle" ), vecWorldOffset, angIgnore );
	*/

	Vector vecWorldOffset = vecStartSpot + Vector(0,0,-8) + right * 12 + forward * 16;
#endif
	Vector gunOffset = vecWorldOffset - vecStartSpot;

	CPowerPlasmaProjectile *pPlasma = CPowerPlasmaProjectile::CreatePredicted( vecStartSpot, vecDir, gunOffset, DMG_ENERGYBEAM, pPlayer );
	if ( pPlasma )
	{
		pPlasma->SetDamage( weapon_combat_burstrifle_damage.GetFloat() );
		pPlasma->m_hOwner = pPlayer;
		pPlasma->SetPower( 2.0 );
		pPlasma->SetMaxRange( weapon_combat_burstrifle_range.GetFloat() );
		pPlasma->Activate();
	}

	m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate();
	m_iClip1 = m_iClip1 - 1;
}