Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

228 lines
7.0 KiB

//========= 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;
}