//========= Copyright Valve Corporation, All rights reserved. ============//
//
//
//=============================================================================
#include "cbase.h"
#include "tf_weapon_pistol.h"
#include "tf_fx_shared.h"
#include "in_buttons.h"
#include "tf_gamerules.h"

// Client specific.
#ifdef CLIENT_DLL
#include "c_tf_player.h"
#include "c_tf_gamestats.h"
// Server specific.
#else
#include "tf_player.h"
#include "tf_gamestats.h"
#include "ilagcompensationmanager.h"
#endif

//=============================================================================
//
// Weapon Pistol tables.
//
IMPLEMENT_NETWORKCLASS_ALIASED( TFPistol, DT_WeaponPistol )

BEGIN_NETWORK_TABLE( CTFPistol, DT_WeaponPistol )
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CTFPistol )
END_PREDICTION_DATA()

LINK_ENTITY_TO_CLASS( tf_weapon_pistol, CTFPistol );
PRECACHE_WEAPON_REGISTER( tf_weapon_pistol );

// Server specific.
#ifndef CLIENT_DLL
BEGIN_DATADESC( CTFPistol )
END_DATADESC()
#endif

//============================

IMPLEMENT_NETWORKCLASS_ALIASED( TFPistol_Scout, DT_WeaponPistol_Scout )

BEGIN_NETWORK_TABLE( CTFPistol_Scout, DT_WeaponPistol_Scout )
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CTFPistol_Scout )
END_PREDICTION_DATA()

LINK_ENTITY_TO_CLASS( tf_weapon_pistol_scout, CTFPistol_Scout );
PRECACHE_WEAPON_REGISTER( tf_weapon_pistol_scout );

//============================

IMPLEMENT_NETWORKCLASS_ALIASED( TFPistol_ScoutPrimary, DT_WeaponPistol_ScoutPrimary )

BEGIN_NETWORK_TABLE( CTFPistol_ScoutPrimary, DT_WeaponPistol_ScoutPrimary )
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CTFPistol_ScoutPrimary )
END_PREDICTION_DATA()

LINK_ENTITY_TO_CLASS( tf_weapon_handgun_scout_primary, CTFPistol_ScoutPrimary );
PRECACHE_WEAPON_REGISTER( tf_weapon_handgun_scout_primary );


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CTFPistol_ScoutPrimary::CTFPistol_ScoutPrimary()
{
	m_flPushTime = -1.f;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFPistol_ScoutPrimary::PlayWeaponShootSound( void )
{
	BaseClass::PlayWeaponShootSound();

	if ( TFGameRules()->GameModeUsesUpgrades() )
	{
		PlayUpgradedShootSound( "Weapon_Upgrade.DamageBonus" );
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFPistol_ScoutPrimary::SecondaryAttack( void )
{
	CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
	if ( !pOwner )
		return;

	if ( !CanAttack() )
		return;

	if ( m_flNextSecondaryAttack > gpGlobals->curtime )
		return;

	pOwner->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_SECONDARY );
	SendWeaponAnim( ACT_SECONDARY_VM_ALTATTACK );

	m_flNextPrimaryAttack = gpGlobals->curtime + 0.6f;
	m_flNextSecondaryAttack = gpGlobals->curtime + 1.5f;
	m_flPushTime = gpGlobals->curtime + 0.2f;	// Anim delay

	EmitSound( "Weapon_Hands.Push" );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFPistol_ScoutPrimary::Push( void )
{
	CTFPlayer *pOwner = ToTFPlayer( GetPlayerOwner() );
	if ( !pOwner )
		return;

#ifdef GAME_DLL
	lagcompensation->StartLagCompensation( pOwner, pOwner->GetCurrentCommand() );

	CUtlVector< CTFPlayer* > enemyVector;
	CollectPlayers( &enemyVector, GetEnemyTeam( pOwner->GetTeamNumber() ), COLLECT_ONLY_LIVING_PLAYERS );

	for ( int i = 0; i < enemyVector.Count(); ++i )
	{
		CTFPlayer *pVictim = enemyVector[i];

		if ( !pVictim->IsAlive() )
			continue;

		if ( pVictim == pOwner )
			continue;

		if ( pVictim->InSameTeam( pOwner ) )
			continue;

		if ( TFGameRules() && TFGameRules()->IsTruceActive() && pOwner->IsTruceValidForEnt() )
			continue;

		if ( ( pOwner->GetAbsOrigin()- pVictim->GetAbsOrigin() ).LengthSqr() > ( 128.f * 128.f ) )
			continue;

		if ( !pOwner->FVisible( pVictim, MASK_SOLID ) )
			continue;

		Vector vecEyes = pOwner->EyePosition();
		Vector vecForward;
		AngleVectors( pOwner->EyeAngles(), &vecForward );
		CTraceFilterSimple traceFilter( this, COLLISION_GROUP_NONE );
		const Vector vHull = Vector( 16.f, 16.f, 16.f );
		trace_t trace;

		float flDist = 50.f;
		UTIL_TraceHull( vecEyes, vecEyes + vecForward * flDist,  -vHull, vHull, MASK_SOLID, &traceFilter, &trace );
		
		bool bDebug = false;
		if ( bDebug )
		{
			NDebugOverlay::SweptBox( vecEyes, vecEyes + vecForward * flDist, -vHull, vHull, pOwner->EyeAngles(), 255, 0, 0, 40, 5 );
		}

		if ( trace.m_pEnt && trace.m_pEnt == pVictim && trace.fraction < 1.f )
		{
			Vector vecToVictim = pVictim->GetAbsOrigin() - pOwner->GetAbsOrigin();
			VectorNormalize( vecToVictim );
			pVictim->ApplyAirBlastImpulse( vecToVictim * 400.f );
			float flDamage = 1.f;
			CTakeDamageInfo info( pOwner, pVictim, this, flDamage, DMG_MELEE | DMG_NEVERGIB | DMG_CLUB, TF_DMG_CUSTOM_NONE );
			CalculateMeleeDamageForce( &info, vecForward, GetAbsOrigin() + vecForward * flDist, 1.f / flDamage * 80.f );
			pVictim->DispatchTraceAttack( info, vecForward, &trace );
			ApplyMultiDamage();

			CPVSFilter filter( vecToVictim );
			EmitSound( "Weapon_Hands.PushImpact" );

			// Make sure we get credit for the push if the target falls to its death
			pVictim->m_AchievementData.AddDamagerToHistory( pOwner );

			break;			
		}
	}

	pOwner->SpeakWeaponFire();
	CTF_GameStats.Event_PlayerFiredWeapon( pOwner, IsCurrentAttackACrit() );

	lagcompensation->FinishLagCompensation( pOwner );
#else
	C_CTF_GameStats.Event_PlayerFiredWeapon( pOwner, IsCurrentAttackACrit() );
#endif
}

//-----------------------------------------------------------------------------
// Purpose: 
// Input  :  - 
//-----------------------------------------------------------------------------
void CTFPistol_ScoutPrimary::ItemPostFrame()
{
	// Check for smack.
	if ( m_flPushTime > -1.f && gpGlobals->curtime > m_flPushTime )
	{
		Push();
		m_flPushTime = -1.f;
	}

	BaseClass::ItemPostFrame();
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
bool CTFPistol_ScoutPrimary::Holster( CBaseCombatWeapon *pSwitchingTo )
{
	m_flPushTime = -1.f;

	return BaseClass::Holster( pSwitchingTo );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFPistol_ScoutPrimary::Precache( void )
{
	PrecacheScriptSound( "Weapon_Hands.Push" );
	PrecacheScriptSound( "Weapon_Hands.PushImpact" );
	
	BaseClass::Precache();
}

//============================

IMPLEMENT_NETWORKCLASS_ALIASED( TFPistol_ScoutSecondary, DT_WeaponPistol_ScoutSecondary )

BEGIN_NETWORK_TABLE( CTFPistol_ScoutSecondary, DT_WeaponPistol_ScoutSecondary )
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CTFPistol_ScoutSecondary )
END_PREDICTION_DATA()

LINK_ENTITY_TO_CLASS( tf_weapon_handgun_scout_secondary, CTFPistol_ScoutSecondary );
PRECACHE_WEAPON_REGISTER( tf_weapon_handgun_scout_secondary );

//-----------------------------------------------------------------------------
int	CTFPistol_ScoutSecondary::GetDamageType( void ) const
{
	int iBackheadshot = 0;
	CALL_ATTRIB_HOOK_INT( iBackheadshot, back_headshot );
	if ( iBackheadshot )
	{
		return BaseClass::GetDamageType() | DMG_USE_HITLOCATIONS;	
	}
	return BaseClass::GetDamageType();
}