//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
//=============================================================================

#include "cbase.h"
#include "tf_item_wearable.h"
#include "vcollide_parse.h"
#include "tf_gamerules.h"
#include "animation.h"
#include "basecombatweapon_shared.h"
#ifdef CLIENT_DLL
#include "c_tf_player.h"
#include "model_types.h"
#include "props_shared.h"
#include "tf_mapinfo.h"
#else
#include "tf_player.h"
#endif

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

LINK_ENTITY_TO_CLASS( tf_wearable, CTFWearable );
IMPLEMENT_NETWORKCLASS_ALIASED( TFWearable, DT_TFWearable )

// Network Table --
BEGIN_NETWORK_TABLE( CTFWearable, DT_TFWearable )
#if defined( GAME_DLL )
	SendPropBool( SENDINFO( m_bDisguiseWearable ) ),
	SendPropEHandle( SENDINFO( m_hWeaponAssociatedWith ) ),
#else
	RecvPropBool( RECVINFO( m_bDisguiseWearable ) ),
	RecvPropEHandle( RECVINFO( m_hWeaponAssociatedWith ) ),
#endif // GAME_DLL
END_NETWORK_TABLE()
// -- Network Table

// Data Desc --
BEGIN_DATADESC( CTFWearable )
END_DATADESC()
// -- Data Desc

PRECACHE_REGISTER( tf_wearable );


LINK_ENTITY_TO_CLASS( tf_wearable_vm, CTFWearableVM );
IMPLEMENT_NETWORKCLASS_ALIASED( TFWearableVM, DT_TFWearableVM )

BEGIN_NETWORK_TABLE( CTFWearableVM, DT_TFWearableVM )
END_NETWORK_TABLE()

PRECACHE_REGISTER( tf_wearable_vm );


//-----------------------------------------------------------------------------
// SHARED CODE
//-----------------------------------------------------------------------------

CTFWearable::CTFWearable() : CEconWearable()
{
	m_bDisguiseWearable = false;
	m_hWeaponAssociatedWith = NULL;
#if defined( CLIENT_DLL )
	m_eParticleSystemVisibility = kParticleSystemVisibility_Undetermined;
	m_nWorldModelIndex = 0;
#endif
};

//-----------------------------------------------------------------------------
// SERVER ONLY CODE
//-----------------------------------------------------------------------------

#if defined( GAME_DLL )
void CTFWearable::Break( void )
{
	CPVSFilter filter( GetAbsOrigin() );
	UserMessageBegin( filter, "BreakModel" );
		WRITE_SHORT( GetModelIndex() );
		WRITE_VEC3COORD( GetAbsOrigin() );
		WRITE_ANGLES( GetAbsAngles() );
		WRITE_SHORT( GetSkin() );
	MessageEnd();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CTFWearable::CalculateVisibleClassFor( CBaseCombatCharacter *pPlayer )
{
	if ( m_bDisguiseWearable )
	{
		CTFPlayer *pTFPlayer = ToTFPlayer( pPlayer );
		if ( pTFPlayer )
			return pTFPlayer->m_Shared.GetDisguiseClass();
	}
	return BaseClass::CalculateVisibleClassFor( pPlayer );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int CTFWearable::UpdateTransmitState()
{
	return SetTransmitState( FL_EDICT_FULLCHECK );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int	CTFWearable::ShouldTransmit( const CCheckTransmitInfo *pInfo )
{
	if ( pInfo->m_pClientEnt && GetOwnerEntity() && CBaseEntity::Instance( pInfo->m_pClientEnt ) == GetOwnerEntity() )
	{
		return FL_EDICT_ALWAYS;
	}

	// We have some entities that have no model (ie., "hatless hats") but we still want
	// to transmit them down to clients so that the clients	can do things like update body
	// groups, etc.
	return FL_EDICT_PVSCHECK;
}

#endif

#ifdef CLIENT_DLL
ConVar tf_test_hat_bodygroup( "tf_test_hat_bodygroup", "0", 0, "For testing bodygroups on hats." );
#endif

static int CalcBodyGroup( CBaseCombatCharacter* pOwner, CEconItemView *pItem, const char *pBodyGroup, codecontrolledbodygroupdata_t &ccbgd )
{
#ifdef CLIENT_DLL
	if ( !Q_strnicmp( ccbgd.pFuncName, "test", ARRAYSIZE( "test" ) ) )
	{
		return tf_test_hat_bodygroup.GetInt();
	}
	else if ( !Q_strnicmp( ccbgd.pFuncName, "map_contributor", ARRAYSIZE( "map_contributor" ) ) )
	{
		int iDonationAmount = MapInfo_GetDonationAmount( pItem->GetAccountID(), engine->GetLevelName() );
		return MIN( iDonationAmount / 25, 4 );
	}
#endif
	return 0;
}

//-----------------------------------------------------------------------------
// CLIENT ONLY CODE
//-----------------------------------------------------------------------------

#if defined( CLIENT_DLL )
extern ConVar tf_playergib_forceup;

//-----------------------------------------------------------------------------
// Receive the BreakModel user message
//-----------------------------------------------------------------------------
void HandleBreakModel( bf_read &msg, bool bCheap )
{
	int nModelIndex = (int)msg.ReadShort();
	CUtlVector<breakmodel_t>	aGibs;
	BuildGibList( aGibs, nModelIndex, 1.0f, COLLISION_GROUP_NONE );
	if ( !aGibs.Count() )
		return;

	// Get the origin & angles
	Vector vecOrigin;
	QAngle vecAngles;
	int nSkin = 0;
	msg.ReadBitVec3Coord( vecOrigin );
	if ( !bCheap )
	{
		msg.ReadBitAngles( vecAngles );
		nSkin = (int)msg.ReadShort();
	}
	else
	{
		vecAngles = vec3_angle;
	}

	// Launch it straight up with some random spread
	Vector vecBreakVelocity = Vector(0,0,200);
	AngularImpulse angularImpulse( RandomFloat( 0.0f, 120.0f ), RandomFloat( 0.0f, 120.0f ), 0.0 );
	breakablepropparams_t breakParams( vecOrigin, vecAngles, vecBreakVelocity, angularImpulse );
	breakParams.impactEnergyScale = 1.0f;
	breakParams.nDefaultSkin = nSkin;

	CreateGibsFromList( aGibs, nModelIndex, NULL, breakParams, NULL, -1 , false, true );
}

//-----------------------------------------------------------------------------
// Receive the BreakModel user message
//-----------------------------------------------------------------------------
void __MsgFunc_BreakModel( bf_read &msg )
{
	HandleBreakModel( msg, false );
}

//-----------------------------------------------------------------------------
// Receive the CheapBreakModel user message
//-----------------------------------------------------------------------------
void __MsgFunc_CheapBreakModel( bf_read &msg )
{
	HandleBreakModel( msg, true );
}

//-----------------------------------------------------------------------------
// Receive the BreakModel_Pumpkin user message
//-----------------------------------------------------------------------------
void __MsgFunc_BreakModel_Pumpkin( bf_read &msg )
{
	int nModelIndex = (int)msg.ReadShort();
	CUtlVector<breakmodel_t>	aGibs;
	BuildGibList( aGibs, nModelIndex, 1.0f, COLLISION_GROUP_NONE );
	if ( !aGibs.Count() )
		return;

	// Get the origin & angles
	Vector vecOrigin;
	QAngle vecAngles;
	msg.ReadBitVec3Coord( vecOrigin );
	msg.ReadBitAngles( vecAngles );

	// Launch it straight up with some random spread
	Vector vecBreakVelocity = Vector(0,0,0);
	AngularImpulse angularImpulse( RandomFloat( 0.0f, 120.0f ), RandomFloat( 0.0f, 120.0f ), 0.0 );
	breakablepropparams_t breakParams( vecOrigin /*+ Vector(0,0,20)*/, vecAngles, vecBreakVelocity, angularImpulse );
	breakParams.impactEnergyScale = 1.0f;

	for ( int i=0; i<aGibs.Count(); ++i )
	{
		aGibs[i].burstScale = 1000.f;
	}

	CUtlVector<EHANDLE>	hSpawnedGibs;
	CreateGibsFromList( aGibs, nModelIndex, NULL, breakParams, NULL, -1 , false, true, &hSpawnedGibs );

	// Make the base stay low to the ground.
	for ( int i=0; i<hSpawnedGibs.Count(); ++i )
	{
		CBaseEntity *pGib = hSpawnedGibs[i];
		if ( pGib )
		{
			IPhysicsObject *pPhysObj = pGib->VPhysicsGetObject();
			if ( pPhysObj )
			{
				Vector vecVel;
				AngularImpulse angImp;
				pPhysObj->GetVelocity( &vecVel, &angImp );
				vecVel *= 3.0;
				if ( i == 3 )
				{
					vecVel.z = 300;
				}
				else
				{
					vecVel.z = 400;
				}
				pPhysObj->SetVelocity( &vecVel, &angImp );
			}
		}
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
int	CTFWearable::InternalDrawModel( int flags )
{
	C_TFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );

	if ( pOwner && pOwner->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
	{
		bool bShouldDraw = false;
		const CEconItemView *pItem = GetAttributeContainer()->GetItem();
		if ( pItem )
		{
			econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( "ghost_wearable" );
			if ( pItem->GetItemDefinition()->HasEconTag( tagHandle ) )
				bShouldDraw = true;
		}

		if ( !bShouldDraw )
			return 0;
	}

	bool bUseInvulnMaterial = ( pOwner && pOwner->m_Shared.IsInvulnerable() && 
							    ( !pOwner->m_Shared.InCond( TF_COND_INVULNERABLE_HIDE_UNLESS_DAMAGED ) || gpGlobals->curtime < pOwner->GetLastDamageTime() + 2.0f ) );

	if ( bUseInvulnMaterial && (flags & STUDIO_RENDER) )
	{
		modelrender->ForcedMaterialOverride( *pOwner->GetInvulnMaterialRef() );
	}

	int ret = BaseClass::InternalDrawModel( flags );

	if ( bUseInvulnMaterial && (flags & STUDIO_RENDER) )
	{
		modelrender->ForcedMaterialOverride( NULL );
	}

	return ret;
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CTFWearable::ShouldDraw()
{
	C_TFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() );

	if ( pOwner )
	{
		if ( pOwner->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
		{
			const CEconItemView *pItem = GetAttributeContainer()->GetItem();
			if ( pItem )
			{
				econ_tag_handle_t tagHandle = GetItemSchema()->GetHandleForTag( "ghost_wearable" );
				if ( pItem->GetItemDefinition()->HasEconTag( tagHandle ) )
					return BaseClass::ShouldDraw();
			}

			return false;
		}

		// don't draw cosmetic while sniper is zoom
		if ( pOwner == C_TFPlayer::GetLocalTFPlayer() && pOwner->m_Shared.InCond( TF_COND_ZOOMED ) )
			return false;
	}

	// Don't draw 3rd person wearables if our owner is disguised.
	if ( pOwner && pOwner->m_Shared.InCond( TF_COND_DISGUISED ) && !IsViewModelWearable() )
	{
		C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
		if ( m_bDisguiseWearable && pLocalPlayer )
		{
			int iLocalPlayerTeam = pLocalPlayer->GetTeamNumber();
			if ( pLocalPlayer->m_bIsCoaching && pLocalPlayer->m_hStudent )
			{
				iLocalPlayerTeam = pLocalPlayer->m_hStudent->GetTeamNumber();
			}

			// This wearable is a part of our disguise -- we might want to draw it.
			if ( GetEnemyTeam( pOwner->GetTeamNumber() ) != iLocalPlayerTeam )
			{	
				// The local player is on this spy's team. We don't see the disguise.
				return false;
			}
			else
			{
				if ( pOwner->m_Shared.GetDisguiseClass() == TF_CLASS_SPY &&
					 pOwner->m_Shared.GetDisguiseTeam() == iLocalPlayerTeam )
				{
					// This enemy spy is disguised as a spy on our team, don't draw wearables.
					return false;
				}
				else
				{
					// The local player is an enemy. Show the disguise wearable.
					return BaseClass::ShouldDraw();
				}
			}
		}

		return false;
	}
	else
	{
		// See if the visibility is controlled by a weapon.
		CTFWeaponBase *pWeapon = assert_cast< CTFWeaponBase* >( GetWeaponAssociatedWith() );
		if ( pWeapon )
		{
			// If the weapon isn't active, don't draw
			if ( pOwner && pOwner->GetActiveWeapon() != pWeapon )
			{
				return false;
			}

			if ( !IsViewModelWearable() )
			{
				// If it's the 3rd person wearable, don't draw it when the weapon is hidden
				if ( !pWeapon->ShouldDraw() )
				{
					return false;
				}
			}

			// If the weapon is being repurposed for a taunt dont draw.
			// The Brutal Legend taunt changes your weapon's model to be the guitar,
			// but we dont want things like bot-killer skulls or festive lights
			// to continue to draw
			if( pWeapon->IsBeingRepurposedForTaunt() )
			{
				return false;
			}
		}
		
		return BaseClass::ShouldDraw();
	}
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CTFWearable::ShouldDrawParticleSystems( void )
{
	if ( !BaseClass::ShouldDrawParticleSystems() )
		return false;

	C_TFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
	bool bStealthed = pPlayer->m_Shared.IsStealthed();

	// If we're disguised, this ought to only be getting called on disguise wearables,
	// otherwise we could get two particles showing at once (disguise wearable + real wearable).
	Assert( !pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) || IsDisguiseWearable() );

	if ( bStealthed )
	{
		return false;
	}

	if ( m_eParticleSystemVisibility == kParticleSystemVisibility_Undetermined )
	{
		static CSchemaItemDefHandle pItemDef_MapLoverHat( "World Traveler" );

		m_eParticleSystemVisibility = kParticleSystemVisibility_Shown;

		const CEconItemView *pItem = GetAttributeContainer()->GetItem();
		if ( pItem && pItem->GetStaticData() == pItemDef_MapLoverHat )
		{
			if ( MapInfo_DidPlayerDonate( pItem->GetAccountID(), engine->GetLevelName() ) == false )
			{
				m_eParticleSystemVisibility = kParticleSystemVisibility_Hidden;
			}
		}
	}

	return m_eParticleSystemVisibility == kParticleSystemVisibility_Shown;
}

int CTFWearable::GetWorldModelIndex( void )
{
	if ( m_nWorldModelIndex == 0 )
		return m_nModelIndex;

	static CSchemaItemDefHandle pItemDef_OculusRiftHeadset( "The TF2VRH" );
	const CEconItemView *pItem = GetAttributeContainer()->GetItem();
	if ( pItem && pItem->GetStaticData() == pItemDef_OculusRiftHeadset )
	{
		CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
		if ( pTFPlayer )
		{
			if ( pTFPlayer->IsUsingVRHeadset() && pTFPlayer->GetPlayerClass() )
			{
				const char *pszReplacementModel = pItem->GetStaticData()->GetPlayerDisplayModelAlt( pTFPlayer->GetPlayerClass()->GetClassIndex() );
				if ( pszReplacementModel && pszReplacementModel[0] )
				{
					return modelinfo->GetModelIndex( pszReplacementModel );
				}
			}
		}
	}

	//*********************************************************************************
	// Parachute states
	static CSchemaItemDefHandle pItemDef_BaseJumper( "The B.A.S.E. Jumper" );
	const int iParachuteOpen = modelinfo->GetModelIndex( "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack_open.mdl" );
	const int iParachuteClosed = modelinfo->GetModelIndex( "models/workshop/weapons/c_models/c_paratooper_pack/c_paratrooper_pack.mdl" );
	if ( m_nModelIndex == iParachuteOpen || m_nModelIndex == iParachuteClosed )
	{
		CTFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() );
		if ( pTFPlayer )
		{
			if ( pTFPlayer->m_Shared.InCond( TF_COND_PARACHUTE_DEPLOYED ) )
			{
				return iParachuteOpen;
			}
			else
			{
				return iParachuteClosed;
			}
		}
	}

	if ( GameRules() )
	{
		const char *pBaseName = modelinfo->GetModelName( modelinfo->GetModel( m_nWorldModelIndex ) );
		const char *pTranslatedName = GameRules()->TranslateEffectForVisionFilter( "weapons", pBaseName );

		if ( pTranslatedName != pBaseName )
		{
			return modelinfo->GetModelIndex( pTranslatedName );
		}
	}

	return m_nWorldModelIndex;
}

void CTFWearable::ValidateModelIndex( void )
{
	m_nModelIndex = GetWorldModelIndex();

	BaseClass::ValidateModelIndex();
}

#endif

//-----------------------------------------------------------------------------
// Purpose: Hides or shows masked bodygroups associated with this item.
//-----------------------------------------------------------------------------
bool CTFWearable::UpdateBodygroups( CBaseCombatCharacter* pOwner, int iState )
{
	CTFPlayer *pTFOwner = ToTFPlayer( pOwner );
	if ( !pTFOwner )
		return false;

	bool bBaseUpdate = BaseClass::UpdateBodygroups( pOwner, iState );
	if ( bBaseUpdate && m_bDisguiseWearable )
	{
		CEconItemView *pItem = GetAttributeContainer()->GetItem(); // Safe. Checked in base class call.

		CTFPlayer *pDisguiseTarget = ToTFPlayer( pTFOwner->m_Shared.GetDisguiseTarget() );
		if ( !pDisguiseTarget )
			return false;

		// Update our disguise bodygroup.
		int iDisguiseBody = pTFOwner->m_Shared.GetDisguiseBody();
		int iTeam = pTFOwner->m_Shared.GetDisguiseTeam();
		int iNumBodyGroups = pItem->GetStaticData()->GetNumModifiedBodyGroups( iTeam );
		for ( int i=0; i<iNumBodyGroups; ++i )
		{
			int iBody = 0;
			const char *pszBodyGroup = pItem->GetStaticData()->GetModifiedBodyGroup( iTeam, i, iBody );
			int iBodyGroup = pDisguiseTarget->FindBodygroupByName( pszBodyGroup );

			if ( iBodyGroup == -1 )
				continue;

			::SetBodygroup( pDisguiseTarget->GetModelPtr(), iDisguiseBody, iBodyGroup, iState );
		}

		pTFOwner->m_Shared.SetDisguiseBody( iDisguiseBody );
	}

	CEconItemView *pItem = GetAttributeContainer() ? GetAttributeContainer()->GetItem() : NULL;
	if ( pItem )
	{		
		int iTeam = pTFOwner->GetTeamNumber();
		int iNumBodyGroups = pItem->GetStaticData()->GetNumCodeControlledBodyGroups( iTeam );
		for ( int i=0; i<iNumBodyGroups; ++i )
		{
			codecontrolledbodygroupdata_t ccbgd = { NULL, NULL };
			const char *pszBodyGroup = pItem->GetStaticData()->GetCodeControlledBodyGroup( iTeam, i, ccbgd );
			int iBodyGroup = FindBodygroupByName( pszBodyGroup );
			if ( iBodyGroup != -1 )
			{
				SetBodygroup( iBodyGroup, CalcBodyGroup( pOwner, pItem, pszBodyGroup, ccbgd ) );
			}
		}
	}

	// Additional hidden bodygroups.
	for ( int i=0; i<m_HiddenBodyGroups.Count(); ++i )
	{
		int iBodyGroup = pOwner->FindBodygroupByName( m_HiddenBodyGroups[i] );
		if ( iBodyGroup == -1 )
			continue;
		pOwner->SetBodygroup( iBodyGroup, iState );
	}	

	return true;
}

int CTFWearable::GetSkin()
{
	CTFPlayer *pPlayer = ToTFPlayer( GetOwnerEntity() );
	if ( !pPlayer )
		return 0;

	int iTeamNumber = pPlayer->GetTeamNumber();

#if defined( CLIENT_DLL )
	// Run client-only "is the viewer on the same team as the wielder" logic. Assumed to
	// always be false on the server.
	CTFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
	if ( !pLocalPlayer )
		return 0;

	int iLocalTeam = pLocalPlayer->GetTeamNumber();

	// We only show disguise weapon to the enemy team when owner is disguised
	bool bUseDisguiseWeapon = ( iTeamNumber != iLocalTeam && iLocalTeam > LAST_SHARED_TEAM );

	if ( bUseDisguiseWeapon && pPlayer->m_Shared.InCond( TF_COND_DISGUISED ) )
	{
		if ( pLocalPlayer != pPlayer )
		{
			iTeamNumber = pPlayer->m_Shared.GetDisguiseTeam();
		}
	}
#endif // defined( CLIENT_DLL )

	// See if the item wants to override the skin
	int nSkin = -1;

	CBaseCombatWeapon *pWeapon = assert_cast< CBaseCombatWeapon* >( GetWeaponAssociatedWith() );
	if ( pWeapon )
	{
		CEconItemView *pItem = pWeapon->GetAttributeContainer()->GetItem();
		if ( pItem->IsValid() )
		{
			nSkin = pItem->GetSkin( iTeamNumber );			// if we didn't have custom code, fall back to the item definition
		}
	}

	if ( nSkin != -1 )
	{
		return nSkin;
	}

	return BaseClass::GetSkin();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFWearable::InternalSetPlayerDisplayModel( void )
{
	// Set our model to the player model
	CEconItemView *pItem = GetAttributeContainer()->GetItem();
	if ( pItem && pItem->IsValid() && pItem->GetStaticData() )
	{
		if ( pItem->GetStaticData()->IsContentStreamable() )
		{
			const char *pszPlayerDisplayModelAlt = pItem->GetStaticData()->GetPlayerDisplayModelAlt();
			if ( pszPlayerDisplayModelAlt && pszPlayerDisplayModelAlt[0] )
			{
				modelinfo->RegisterDynamicModel( pszPlayerDisplayModelAlt, IsClient() );
			}
		}
	}

	BaseClass::InternalSetPlayerDisplayModel();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFWearable::AddHiddenBodyGroup( const char* bodygroup )
{
	m_HiddenBodyGroups.AddToHead( bodygroup );
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFWearable::ReapplyProvision( void )
{
	// Disguise wearables never provide
	if ( IsDisguiseWearable() )
	{
#ifdef GAME_DLL
		UpdateModelToClass();
#endif
		return;
	}

	BaseClass::ReapplyProvision();
}

//-----------------------------------------------------------------------------
// Purpose: Attaches the item to the player.
//-----------------------------------------------------------------------------
void CTFWearable::Equip( CBasePlayer* pOwner )
{
	BaseClass::Equip( pOwner );

	CTFPlayer *pTFPlayer = ToTFPlayer( pOwner );
	if ( !pTFPlayer )
		return;

	int iTeamNumber = pTFPlayer->GetTeamNumber();
	if ( m_bDisguiseWearable )
	{
		iTeamNumber = pTFPlayer->m_Shared.GetDisguiseTeam();
	}
	ChangeTeam( iTeamNumber );
	m_nSkin = ( iTeamNumber == (LAST_SHARED_TEAM+1) ) ? 0 : 1;

#ifdef CLIENT_DLL
	pTFPlayer->SetBodygroupsDirty();
#endif

#ifdef GAME_DLL
	// Reapply upgrades for wearables upon equip
	CEconItemView *pItem = ( (CTFWearable *)this )->GetAttributeContainer()->GetItem();
	if ( pTFPlayer && pItem->IsValid() )
	{
		pTFPlayer->ReapplyItemUpgrades( pItem );	
	}
#endif // GAME_DLL
}

//-----------------------------------------------------------------------------
// Purpose: Attaches the item to the player.
//-----------------------------------------------------------------------------
void CTFWearable::UnEquip( CBasePlayer* pOwner )
{
	BaseClass::UnEquip( pOwner );

#ifdef CLIENT_DLL
	CTFPlayer *pTFPlayer = ToTFPlayer( pOwner );
	if ( pTFPlayer )
	{
		pTFPlayer->SetBodygroupsDirty();
	}
#endif
}

//-----------------------------------------------------------------------------
// Purpose: Check for any TF specific restrictions on item use.
//-----------------------------------------------------------------------------
bool CTFWearable::CanEquip( CBaseEntity *pOther )
{
	CEconItemView *pItem = GetAttributeContainer()->GetItem();
	if ( pItem && TFGameRules() )
	{
		CEconItemDefinition* pData = pItem->GetStaticData();
		if ( pData && pData->GetHolidayRestriction() )
		{
			int iHolidayRestriction = UTIL_GetHolidayForString( pData->GetHolidayRestriction() );
			if ( iHolidayRestriction != kHoliday_None && !TFGameRules()->IsHolidayActive( iHolidayRestriction ) )
				return false;
		}		
	}
	return true;
}

#ifdef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFWearable::OnDataChanged( DataUpdateType_t updateType )
{
	BaseClass::OnDataChanged( updateType );

	if ( updateType == DATA_UPDATE_CREATED )
	{
		ListenForGameEvent( "localplayer_changeteam" );

		m_nWorldModelIndex = m_nModelIndex;
	}
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTFWearable::FireGameEvent( IGameEvent *event )
{
	const char *pszEventName = event->GetName();
	if ( Q_strcmp( pszEventName, "localplayer_changeteam" ) == 0 )
	{
		UpdateVisibility();
	}
}

#endif




//-----------------------------------------------------------------------------
// Purpose:
//		Choose shadow type for VM-wearables.
//-----------------------------------------------------------------------------
#if defined( CLIENT_DLL )
ShadowType_t CTFWearableVM::ShadowCastType( void )
{
	if ( ToTFPlayer(GetMoveParent())->ShouldDrawThisPlayer() )
	{
		// Using the viewmodel.
		return SHADOWS_NONE;
	}

	return SHADOWS_RENDER_TO_TEXTURE;
}
#endif