//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: Support weapon and weapons contained within it
//
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "basetfplayer_shared.h"
#include "weapon_twohandedcontainer.h"
#include "baseviewmodel_shared.h"

// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CWeaponTwoHandedContainer::CWeaponTwoHandedContainer()
{
	m_hRightWeapon = NULL;
	m_hLeftWeapon = NULL;
	SetPredictionEligible( true );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CWeaponTwoHandedContainer::~CWeaponTwoHandedContainer()
{
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponTwoHandedContainer::Spawn( void )
{
	BaseClass::Spawn();
}

#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponTwoHandedContainer::GetViewmodelBoneControllers( CBaseViewModel *pViewModel, float controllers[MAXSTUDIOBONECTRLS])
{
	C_BasePlayer *player = ToBasePlayer( GetOwner() );
	Assert( player );

	if ( !player )
		return;

	// Find the weapon that matches the viewmodel
	if ( m_hLeftWeapon != NULL && player->GetViewModel(0) == pViewModel )
	{
		m_hLeftWeapon->GetViewmodelBoneControllers( pViewModel, controllers);
	}
	else if ( m_hRightWeapon != NULL && player->GetViewModel(1) == pViewModel )
	{
		m_hRightWeapon->GetViewmodelBoneControllers( pViewModel, controllers);
	}
}

#else // CLIENT_DLL

void CWeaponTwoHandedContainer::SetTransmit( CCheckTransmitInfo *pInfo, bool bAlways )
{
	// Skip this work if we're already marked for transmission.
	if ( pInfo->m_pTransmitEdict->Get( entindex() ) )
		return;

	// Send our left and right weapons.
	if ( m_hLeftWeapon )
		m_hLeftWeapon->SetTransmit( pInfo, bAlways );

	if ( m_hRightWeapon )
		m_hRightWeapon->SetTransmit( pInfo, bAlways );

	BaseClass::SetTransmit( pInfo, bAlways );
}

#endif

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
const char *CWeaponTwoHandedContainer::GetViewModel( int viewmodelindex /*=0*/ )
{
	if ( m_hLeftWeapon != NULL && m_hRightWeapon != NULL )
	{
		if ( viewmodelindex == 0 )
		{
			return m_hLeftWeapon->GetViewModel();
		}
		else
		{
			return m_hRightWeapon->GetViewModel();
		}
	}
	return BaseClass::GetViewModel( viewmodelindex );
}

//-----------------------------------------------------------------------------
// Purpose: Get the string to print death notices with
//-----------------------------------------------------------------------------
char *CWeaponTwoHandedContainer::GetDeathNoticeName( void )
{
	// If we have a weapon in our left slot, return it. Otherwise, return this weapon.
	if ( m_hLeftWeapon )
		return m_hLeftWeapon->GetDeathNoticeName();

	return BaseClass::GetDeathNoticeName();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponTwoHandedContainer::ItemPostFrame( void )
{
	// HACK HACK:  Do nonshield first in case it disallows ItemPostFrame on shield
	if ( m_hLeftWeapon != NULL )
	{
// REMOVE WHEN ALL WEAPONS ARE PREDICTED!
#if defined( CLIENT_DLL )
		if ( m_hLeftWeapon->IsPredicted() )
#endif
		m_hLeftWeapon->ItemPostFrame();
	}

	if ( m_hRightWeapon != NULL && m_hRightWeapon->IsPredicted() )
	{
// REMOVE WHEN ALL WEAPONS ARE PREDICTED!
#if defined( CLIENT_DLL )
		if ( m_hRightWeapon->IsPredicted() )
#endif
		m_hRightWeapon->ItemPostFrame();
	}
}

//-----------------------------------------------------------------------------
// Purpose: Called each frame by the player PostThink, if the player's not ready to attack yet
//-----------------------------------------------------------------------------
void CWeaponTwoHandedContainer::ItemBusyFrame( void )
{
	// HACK HACK:  Do nonshield first in case it disallows ItemPostFrame on shield
	if ( m_hLeftWeapon != NULL )
	{
		m_hLeftWeapon->ItemBusyFrame();
	}

	if ( m_hRightWeapon != NULL )
	{
		m_hRightWeapon->ItemBusyFrame();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CWeaponTwoHandedContainer::SetWeapons( CBaseTFCombatWeapon *left, CBaseTFCombatWeapon *right )
{
	CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
	if ( !pOwner )
		return;

	// Do we have a different left weapon?
	if ( m_hLeftWeapon.Get() && m_hLeftWeapon != left )
	{
		// Holster our old one
		m_hLeftWeapon->Holster();
		m_hLeftWeapon = NULL;
	}
	// Do we have a different right weapon?
	if ( m_hRightWeapon.Get() && m_hRightWeapon != right )
	{
		// Holster our old one
		m_hRightWeapon->Holster();
		m_hRightWeapon = NULL;
	}

	// Make new weapons if we need to
	if ( !m_hLeftWeapon )
	{
		m_hLeftWeapon = left;
		if ( m_hLeftWeapon )
		{
			m_hLeftWeapon->SetOwner( pOwner );
			m_hLeftWeapon->Deploy();
			m_hLeftWeapon->SetViewModelIndex( 0 );
			//m_hLeftWeapon->SendWeaponAnim( ACT_IDLE );
		}
	}

	if ( !m_hRightWeapon )
	{
		m_hRightWeapon = right;
		if ( m_hRightWeapon )
		{
			m_hRightWeapon->SetOwner( pOwner );
			m_hRightWeapon->Deploy();
			m_hRightWeapon->SetViewModelIndex( 1 );
			//m_hRightWeapon->SendWeaponAnim( ACT_IDLE );

			UnhideSecondViewmodel();
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Unhide the second viewmodel, in case we're switching from a single weapon
//-----------------------------------------------------------------------------
void CWeaponTwoHandedContainer::UnhideSecondViewmodel( void )
{
	CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );
	if ( pOwner )
	{
		CBaseViewModel *pVM = pOwner->GetViewModel(1);
		if ( pVM )
		{
			pVM->RemoveEffects( EF_NODRAW );
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: Abort any reload we have in progress
//-----------------------------------------------------------------------------
void CWeaponTwoHandedContainer::AbortReload( void )
{
	BaseClass::AbortReload();

	if ( m_hLeftWeapon )
	{
		m_hLeftWeapon->AbortReload();
	}
	if ( m_hRightWeapon )
	{
		m_hRightWeapon->AbortReload();
	}
}

//-----------------------------------------------------------------------------
// Purpose: Return true if the left weapon has any ammo
//-----------------------------------------------------------------------------
bool CWeaponTwoHandedContainer::HasAnyAmmo( void )
{
	if ( m_hLeftWeapon )
		return m_hLeftWeapon->HasAnyAmmo();

	return BaseClass::HasAnyAmmo();
}

//-----------------------------------------------------------------------------
// Purpose: Deploy and start thinking
//-----------------------------------------------------------------------------
bool CWeaponTwoHandedContainer::Deploy( void )
{
	if ( !BaseClass::Deploy() )
		return false;

	if ( m_hLeftWeapon )
	{
		m_hLeftWeapon->Deploy();
	}
	if ( m_hRightWeapon )
	{
		m_hRightWeapon->Deploy();
		UnhideSecondViewmodel();
	}

	return true;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CBaseCombatWeapon *CWeaponTwoHandedContainer::GetLastWeapon( void )
{
	if ( m_hLeftWeapon )
		return m_hLeftWeapon->GetLastWeapon();

	return NULL;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
float CWeaponTwoHandedContainer::GetDefaultAnimSpeed( void )
{
	if ( m_hLeftWeapon )
		return m_hLeftWeapon->GetDefaultAnimSpeed();

	return 1.0;
}

//-----------------------------------------------------------------------------
// Purpose: Stop thinking and holster
//-----------------------------------------------------------------------------
bool CWeaponTwoHandedContainer::Holster( CBaseCombatWeapon *pSwitchingTo )
{
	CBaseTFPlayer *pOwner = ToBaseTFPlayer( GetOwner() );

	// If I'm holstering a weapon for another weapon that supports two-handed, just switch them out
	CBaseTFCombatWeapon	*pWeapon = (CBaseTFCombatWeapon	*)pSwitchingTo;
	if ( pWeapon && pWeapon->SupportsTwoHanded() )
	{
		// For now, holster the left weapon and switch it.
		// In the future, we might want weapons to say which side they'd like to be on
		SetWeapons( pWeapon, m_hRightWeapon );
		
		// We might need to force the new weapon to be in the right animation
		if ( 0 ) //if ( m_hRightWeapon.Get() && m_hRightWeapon->IsReflectingAnimations() )
		{
			pWeapon->SendWeaponAnim( m_hRightWeapon->GetLastReflectedActivity() );
		}

		UnhideSecondViewmodel();
		return false;
	}

	if ( m_hLeftWeapon )
	{
		m_hLeftWeapon->Holster(pSwitchingTo);
	}
	if ( m_hRightWeapon )
	{
		m_hRightWeapon->Holster(pSwitchingTo);
	}

	// We're changing to a single weapon, so hide the second viewmodel
	if ( pOwner )
	{
		CBaseViewModel *pVM = pOwner->GetViewModel(1);
		if ( pVM )
		{
			pVM->AddEffects( EF_NODRAW );
		}
	}

	return BaseClass::Holster(pSwitchingTo);
}

//-----------------------------------------------------------------------------
// Purpose: Get the correct weight of our active weapon
//-----------------------------------------------------------------------------
int CWeaponTwoHandedContainer::GetWeight( void )
{
	if ( !m_hLeftWeapon )
		return BaseClass::GetWeight();

	return m_hLeftWeapon->GetWpnData().iWeight;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : CBaseTFCombatWeapon
//-----------------------------------------------------------------------------
CBaseTFCombatWeapon *CWeaponTwoHandedContainer::GetLeftWeapon( void )
{
	return m_hLeftWeapon;
}

//-----------------------------------------------------------------------------
// Purpose: 
// Output : CBaseTFCombatWeapon
//-----------------------------------------------------------------------------
CBaseTFCombatWeapon *CWeaponTwoHandedContainer::GetRightWeapon( void )
{
	return m_hRightWeapon;
}

LINK_ENTITY_TO_CLASS( weapon_twohandedcontainer, CWeaponTwoHandedContainer );

IMPLEMENT_NETWORKCLASS_ALIASED( WeaponTwoHandedContainer , DT_WeaponTwoHandedContainer )
BEGIN_NETWORK_TABLE( CWeaponTwoHandedContainer , DT_WeaponTwoHandedContainer )
#if !defined( CLIENT_DLL )
	SendPropEHandle( SENDINFO(m_hRightWeapon) ),
	SendPropEHandle( SENDINFO(m_hLeftWeapon) ),
#else
	RecvPropEHandle( RECVINFO(m_hRightWeapon ) ),
	RecvPropEHandle( RECVINFO(m_hLeftWeapon ) ),
#endif
END_NETWORK_TABLE()

BEGIN_PREDICTION_DATA( CWeaponTwoHandedContainer  )

	DEFINE_PRED_FIELD( m_hRightWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
	DEFINE_PRED_FIELD( m_hLeftWeapon, FIELD_EHANDLE, FTYPEDESC_INSENDTABLE ),
#if defined( CLIENT_DLL )
	// DEFINE_FIELD( m_hOldRightWeapon, FIELD_EHANDLE ),
	// DEFINE_FIELD( m_hOldLeftWeapon, FIELD_EHANDLE ),
#endif

END_PREDICTION_DATA()

PRECACHE_WEAPON_REGISTER(weapon_twohandedcontainer);