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

#include "cbase.h"
#include "KeyValues.h"
#include "tf_playerclass_shared.h"
#include "materialsystem/imaterialsystemhardwareconfig.h"
#include "filesystem.h"
#include "tier2/tier2.h"

//=============================================================================
//
// Shared player class data.
//

//=============================================================================
//
// Tables.
//

#define CLASSMODEL_PARITY_BITS		3
#define CLASSMODEL_PARITY_MASK		((1<<CLASSMODEL_PARITY_BITS)-1)


// Client specific.
#ifdef CLIENT_DLL

BEGIN_RECV_TABLE_NOBASE( CTFPlayerClassShared, DT_TFPlayerClassShared )
	RecvPropInt( RECVINFO( m_iClass ) ),
	RecvPropString( RECVINFO( m_iszClassIcon ) ),
	RecvPropString( RECVINFO( m_iszCustomModel ) ),
	RecvPropVector( RECVINFO( m_vecCustomModelOffset ) ),
	RecvPropQAngles( RECVINFO( m_angCustomModelRotation ) ),
	RecvPropBool( RECVINFO( m_bCustomModelRotates ) ),
	RecvPropBool( RECVINFO( m_bCustomModelRotationSet ) ),
	RecvPropBool( RECVINFO( m_bCustomModelVisibleToSelf ) ),
	RecvPropBool( RECVINFO( m_bUseClassAnimations ) ),
	RecvPropInt( RECVINFO(m_iClassModelParity) ),
END_RECV_TABLE()

// Server specific.
#else

BEGIN_SEND_TABLE_NOBASE( CTFPlayerClassShared, DT_TFPlayerClassShared )
	SendPropInt( SENDINFO( m_iClass ), Q_log2( TF_CLASS_COUNT_ALL )+1, SPROP_UNSIGNED ),
	SendPropStringT( SENDINFO( m_iszClassIcon ) ),
	SendPropStringT( SENDINFO( m_iszCustomModel ) ),
	SendPropVector( SENDINFO( m_vecCustomModelOffset ) ),
	SendPropQAngles( SENDINFO( m_angCustomModelRotation ) ),
	SendPropBool( SENDINFO( m_bCustomModelRotates ) ),
	SendPropBool( SENDINFO( m_bCustomModelRotationSet ) ),
	SendPropBool( SENDINFO( m_bCustomModelVisibleToSelf ) ),
	SendPropBool( SENDINFO( m_bUseClassAnimations ) ),
	SendPropInt( SENDINFO(m_iClassModelParity), CLASSMODEL_PARITY_BITS, SPROP_UNSIGNED ),
END_SEND_TABLE()

#endif


//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CTFPlayerClassShared::CTFPlayerClassShared()
{
	Reset();
}

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFPlayerClassShared::Reset( void )
{
	m_iClass.Set( TF_CLASS_UNDEFINED );
#ifdef CLIENT_DLL
	m_iszClassIcon[0] = '\0';
	m_iszCustomModel[0] = '\0';
#else
	m_iszClassIcon.Set( NULL_STRING );
	m_iszCustomModel.Set( NULL_STRING );
#endif
	m_vecCustomModelOffset = vec3_origin;
	m_angCustomModelRotation = vec3_angle;
	m_bCustomModelRotates = true;
	m_bCustomModelRotationSet = false;
	m_bCustomModelVisibleToSelf = true;
	m_bUseClassAnimations = false;
	m_iClassModelParity = 0;
}

#ifndef CLIENT_DLL
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTFPlayerClassShared::SetCustomModel( const char *pszModelName, bool isUsingClassAnimations )
{
	if ( pszModelName && pszModelName[0] )
	{
		bool bAllowPrecache = CBaseEntity::IsPrecacheAllowed();
		CBaseEntity::SetAllowPrecache( true );
		CBaseEntity::PrecacheModel( pszModelName );
		CBaseEntity::SetAllowPrecache( bAllowPrecache );

		m_iszCustomModel.Set( AllocPooledString( pszModelName ) );

		m_bUseClassAnimations = isUsingClassAnimations;
	}
	else
	{
		m_iszCustomModel.Set( NULL_STRING );
		m_vecCustomModelOffset = vec3_origin;
		m_angCustomModelRotation = vec3_angle;
	}

	m_iClassModelParity = (m_iClassModelParity + 1) & CLASSMODEL_PARITY_MASK;
}
#endif // #ifndef CLIENT_DLL

//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
bool CTFPlayerClassShared::CustomModelHasChanged( void )
{
	if ( m_iClassModelParity != m_iOldClassModelParity )
	{
		m_iOldClassModelParity = m_iClassModelParity.Get();
		return true;
	}
	return false;
}

//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
#ifdef STAGING_ONLY
ConVar tf_player_use_female_models( "tf_player_use_female_models", "0", FCVAR_CHEAT | FCVAR_REPLICATED, "For testing. Appends '_female' to the model filename loaded" );
#endif

const char	*CTFPlayerClassShared::GetModelName( void ) const						
{ 
	// Does this play have an overridden model?
#ifdef CLIENT_DLL
	if ( m_iszCustomModel[0] )
		return m_iszCustomModel;
#else
	if ( m_iszCustomModel.Get() != NULL_STRING )
		return ( STRING( m_iszCustomModel.Get() ) );
#endif

	#define MAX_MODEL_FILENAME_LENGTH 256
	static char modelFilename[ MAX_MODEL_FILENAME_LENGTH ];

	Q_strncpy( modelFilename, GetPlayerClassData( m_iClass )->GetModelName(), sizeof( modelFilename ) );
	
#ifdef STAGING_ONLY
	if ( tf_player_use_female_models.GetBool() )
	{
		// find the ".mdl" part
		char *ext;
		for( ext = modelFilename; *ext != '\000'; ++ext )
		{
			if ( *ext == '.' )
			{
				V_strncpy( ext, "_female.mdl", sizeof( modelFilename ) - ( ext - modelFilename ) );
				break;
			}
		}

		// make sure the test model is precached
		bool bAllowPrecache = CBaseEntity::IsPrecacheAllowed();
		CBaseEntity::SetAllowPrecache( true );
		CBaseEntity::PrecacheModel( modelFilename );
		CBaseEntity::SetAllowPrecache( bAllowPrecache );
	}
#endif

	return modelFilename;
}

//-----------------------------------------------------------------------------
// Purpose: Initialize the player class.
//-----------------------------------------------------------------------------
const char *g_HACK_GunslingerEngineerArmsOverride = "models\\weapons\\c_models\\c_engineer_gunslinger.mdl";

const char *CTFPlayerClassShared::GetHandModelName( int iHandIndex = 0 ) const
{
	return iHandIndex == 0
		 ? GetPlayerClassData( m_iClass )->m_szHandModelName
		 :g_HACK_GunslingerEngineerArmsOverride;				// this is precached in the CTFRobotArm class
}
//-----------------------------------------------------------------------------
// Purpose: Initialize the player class.
//-----------------------------------------------------------------------------
bool CTFPlayerClassShared::Init( int iClass )
{
	Assert ( ( iClass >= TF_FIRST_NORMAL_CLASS ) && ( iClass <= TF_LAST_NORMAL_CLASS ) );

	Reset();
	m_iClass = iClass;

#ifdef CLIENT_DLL
	V_strncpy( m_iszCustomModel, g_aRawPlayerClassNamesShort[ m_iClass ], sizeof( m_iszCustomModel ) );
#else
	m_iszClassIcon.Set( AllocPooledString( g_aRawPlayerClassNamesShort[ m_iClass ] ) );
#endif

	return true;
}

// If needed, put this into playerclass scripts
bool CTFPlayerClassShared::CanBuildObject( int iObjectType )
{
	bool bFound = false;

	TFPlayerClassData_t  *pData = GetData();

	int i;
	for ( i=0;i<TF_PLAYER_BLUEPRINT_COUNT;i++ )
	{
		if ( iObjectType == pData->m_aBuildable[i] )
		{
			bFound = true;
			break;
		}
	}

	return bFound;
}