mirror of
https://github.com/mapbase-source/source-sdk-2013.git
synced 2025-03-03 17:25:27 +03:00
Merge pull request #377 from Blixibon/mapbase/feature/protagonist-system
HL2 player character switching system
This commit is contained in:
commit
51afe9316e
@ -49,6 +49,8 @@ $Project
|
||||
$File "$SRCDIR\game\shared\mapbase\matchers.h"
|
||||
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.cpp"
|
||||
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.h"
|
||||
$File "$SRCDIR\game\shared\mapbase\protagonist_system.cpp"
|
||||
$File "$SRCDIR\game\shared\mapbase\protagonist_system.h"
|
||||
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]
|
||||
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.h" [$MAPBASE_VSCRIPT]
|
||||
$File "$SRCDIR\game\shared\mapbase\vscript_singletons.cpp" [$MAPBASE_VSCRIPT]
|
||||
|
@ -31,6 +31,9 @@ ConVar cl_npc_speedmod_outtime( "cl_npc_speedmod_outtime", "1.5", FCVAR_CLIENTDL
|
||||
IMPLEMENT_CLIENTCLASS_DT(C_BaseHLPlayer, DT_HL2_Player, CHL2_Player)
|
||||
RecvPropDataTable( RECVINFO_DT(m_HL2Local),0, &REFERENCE_RECV_TABLE(DT_HL2Local) ),
|
||||
RecvPropBool( RECVINFO( m_fIsSprinting ) ),
|
||||
#ifdef MAPBASE
|
||||
RecvPropInt( RECVINFO( m_nProtagonistIndex ) ),
|
||||
#endif
|
||||
#ifdef SP_ANIM_STATE
|
||||
RecvPropFloat( RECVINFO( m_flAnimRenderYaw ) ),
|
||||
RecvPropFloat( RECVINFO( m_flAnimRenderZ ) ),
|
||||
@ -79,6 +82,8 @@ C_BaseHLPlayer::C_BaseHLPlayer()
|
||||
#ifdef MAPBASE
|
||||
ConVarRef scissor("r_flashlightscissor");
|
||||
scissor.SetValue("0");
|
||||
|
||||
m_nProtagonistIndex = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,10 @@ public:
|
||||
|
||||
bool IsWeaponLowered( void ) { return m_HL2Local.m_bWeaponLowered; }
|
||||
|
||||
#ifdef MAPBASE
|
||||
int GetProtagonistIndex() const { return m_nProtagonistIndex; }
|
||||
#endif
|
||||
|
||||
#ifdef SP_ANIM_STATE
|
||||
virtual const Vector& GetRenderOrigin();
|
||||
virtual const QAngle& GetRenderAngles( void );
|
||||
@ -89,6 +93,10 @@ private:
|
||||
bool m_bPlayUseDenySound; // Signaled by PlayerUse, but can be unset by HL2 ladder code...
|
||||
float m_flSpeedMod;
|
||||
float m_flExitSpeedMod;
|
||||
|
||||
#ifdef MAPBASE
|
||||
int m_nProtagonistIndex;
|
||||
#endif
|
||||
|
||||
#ifdef MAPBASE_MP
|
||||
CSinglePlayerAnimState *m_pPlayerAnimState;
|
||||
|
@ -58,6 +58,7 @@
|
||||
#ifdef MAPBASE
|
||||
#include "triggers.h"
|
||||
#include "mapbase/variant_tools.h"
|
||||
#include "mapbase/protagonist_system.h"
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
@ -593,6 +594,8 @@ BEGIN_DATADESC( CHL2_Player )
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "DisableGeigerCounter", InputDisableGeigerCounter ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "ShowSquadHUD", InputShowSquadHUD ),
|
||||
DEFINE_INPUTFUNC( FIELD_VOID, "HideSquadHUD", InputHideSquadHUD ),
|
||||
|
||||
DEFINE_INPUTFUNC( FIELD_STRING, "SetProtagonist", InputSetProtagonist ),
|
||||
#endif
|
||||
|
||||
DEFINE_SOUNDPATCH( m_sndLeeches ),
|
||||
@ -607,6 +610,10 @@ BEGIN_DATADESC( CHL2_Player )
|
||||
|
||||
DEFINE_FIELD( m_flTimeNextLadderHint, FIELD_TIME ),
|
||||
|
||||
#ifdef MAPBASE
|
||||
DEFINE_KEYFIELD( m_iszProtagonistName, FIELD_STRING, "ProtagonistName" ),
|
||||
#endif
|
||||
|
||||
//DEFINE_FIELD( m_hPlayerProxy, FIELD_EHANDLE ), //Shut up class check!
|
||||
|
||||
END_DATADESC()
|
||||
@ -625,6 +632,9 @@ BEGIN_ENT_SCRIPTDESC( CHL2_Player, CBasePlayer, "The HL2 player entity." )
|
||||
DEFINE_SCRIPTFUNC( RemoveCustomSuitDevice, "Removes a custom suit device ID. (1-3)" )
|
||||
DEFINE_SCRIPTFUNC( IsCustomSuitDeviceActive, "Checks if a custom suit device is active." )
|
||||
|
||||
DEFINE_SCRIPTFUNC( GetProtagonistName, "Gets the player's protagonist name." )
|
||||
DEFINE_SCRIPTFUNC( SetProtagonist, "Sets the player's protagonist entry." )
|
||||
|
||||
#ifdef SP_ANIM_STATE
|
||||
DEFINE_SCRIPTFUNC( AddAnimStateLayer, "Adds a custom sequence index as a misc. layer for the singleplayer anim state, wtih parameters for blending in/out, setting the playback rate, holding the animation at the end, and only playing when the player is still." )
|
||||
#endif
|
||||
@ -640,6 +650,10 @@ CHL2_Player::CHL2_Player()
|
||||
|
||||
m_flArmorReductionTime = 0.0f;
|
||||
m_iArmorReductionFrom = 0;
|
||||
|
||||
#ifdef MAPBASE
|
||||
m_nProtagonistIndex = -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
@ -674,6 +688,9 @@ CSuitPowerDevice SuitDeviceCustom[] =
|
||||
IMPLEMENT_SERVERCLASS_ST(CHL2_Player, DT_HL2_Player)
|
||||
SendPropDataTable(SENDINFO_DT(m_HL2Local), &REFERENCE_SEND_TABLE(DT_HL2Local), SendProxy_SendLocalDataTable),
|
||||
SendPropBool( SENDINFO(m_fIsSprinting) ),
|
||||
#ifdef MAPBASE
|
||||
SendPropInt( SENDINFO( m_nProtagonistIndex ), 8, SPROP_UNSIGNED ),
|
||||
#endif
|
||||
#ifdef SP_ANIM_STATE
|
||||
SendPropFloat( SENDINFO(m_flAnimRenderYaw), 0, SPROP_NOSCALE ),
|
||||
SendPropFloat( SENDINFO(m_flAnimRenderZ), 0, SPROP_NOSCALE ),
|
||||
@ -1259,6 +1276,11 @@ void CHL2_Player::Activate( void )
|
||||
#endif
|
||||
|
||||
GetPlayerProxy();
|
||||
|
||||
#ifdef MAPBASE
|
||||
if (m_iszProtagonistName != NULL_STRING)
|
||||
SetProtagonist( STRING( m_iszProtagonistName ) );
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@ -1500,6 +1522,8 @@ CStudioHdr *CHL2_Player::OnNewModel()
|
||||
extern char g_szDefaultPlayerModel[MAX_PATH];
|
||||
extern bool g_bDefaultPlayerLegs;
|
||||
extern bool g_bDefaultPlayerDrawExternally;
|
||||
|
||||
extern char g_szDefaultProtagonist[MAX_PROTAGONIST_NAME];
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -1533,6 +1557,9 @@ void CHL2_Player::Spawn(void)
|
||||
|
||||
SetDrawPlayerLegs( g_bDefaultPlayerLegs );
|
||||
SetDrawPlayerModelExternally( g_bDefaultPlayerDrawExternally );
|
||||
|
||||
if (m_iszProtagonistName == NULL_STRING && *g_szDefaultProtagonist)
|
||||
m_iszProtagonistName = MAKE_STRING( g_szDefaultProtagonist );
|
||||
#endif
|
||||
|
||||
//
|
||||
@ -4087,6 +4114,10 @@ bool CHL2_Player::Weapon_Switch( CBaseCombatWeapon *pWeapon, int viewmodelindex
|
||||
StopZooming();
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
RefreshProtagonistWeaponData( pWeapon );
|
||||
#endif
|
||||
|
||||
return BaseClass::Weapon_Switch( pWeapon, viewmodelindex );
|
||||
}
|
||||
|
||||
@ -4482,6 +4513,144 @@ bool CHL2_Player::IsCustomSuitDeviceActive( int iDeviceID )
|
||||
|
||||
return SuitPower_IsDeviceActive( SuitDeviceCustom[iDeviceID] );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets our protagonist name, if we have one
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CHL2_Player::GetProtagonistName() const
|
||||
{
|
||||
return STRING( m_iszProtagonistName );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Gets our protagonist index, if we have one
|
||||
//-----------------------------------------------------------------------------
|
||||
int CHL2_Player::GetProtagonistIndex() const
|
||||
{
|
||||
return m_nProtagonistIndex;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets our protagonist to the specified entry
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2_Player::InputSetProtagonist( inputdata_t &inputdata )
|
||||
{
|
||||
SetProtagonist( inputdata.value.String() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets our protagonist to the specified entry
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2_Player::SetProtagonist( const char *pszProtagonist )
|
||||
{
|
||||
if (!pszProtagonist || !*pszProtagonist)
|
||||
{
|
||||
ResetProtagonist();
|
||||
return;
|
||||
}
|
||||
|
||||
int nIndex = g_ProtagonistSystem.FindProtagonistIndex( pszProtagonist );
|
||||
if (nIndex == -1)
|
||||
{
|
||||
Warning( "\"%s\" is not a valid protagonist\n", pszProtagonist );
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_nProtagonistIndex != -1)
|
||||
{
|
||||
// Flush any pre-existing data
|
||||
ResetProtagonist();
|
||||
}
|
||||
|
||||
m_nProtagonistIndex = nIndex;
|
||||
m_iszProtagonistName = AllocPooledString( pszProtagonist );
|
||||
|
||||
RefreshProtagonistData();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Resets protagonist data
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2_Player::ResetProtagonist()
|
||||
{
|
||||
SetModel( g_szDefaultPlayerModel );
|
||||
m_nSkin = 0;
|
||||
m_nBody = 0;
|
||||
|
||||
CBaseViewModel *vm = GetViewModel( 1 );
|
||||
if (vm)
|
||||
{
|
||||
extern char g_szDefaultHandsModel[MAX_PATH];
|
||||
vm->SetWeaponModel( g_szDefaultHandsModel, NULL );
|
||||
|
||||
vm->m_nSkin = 0;
|
||||
vm->m_nBody = 0;
|
||||
}
|
||||
|
||||
// RemoveContext will automatically remove contexts by name, regardless of how values are specified
|
||||
char szContexts[128] = { 0 };
|
||||
g_ProtagonistSystem.GetProtagonist_ResponseContexts( this, szContexts, sizeof( szContexts ) );
|
||||
if (szContexts[0])
|
||||
RemoveContext( szContexts );
|
||||
|
||||
m_iszProtagonistName = NULL_STRING;
|
||||
m_nProtagonistIndex = -1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Refreshes protagonist data
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2_Player::RefreshProtagonistData()
|
||||
{
|
||||
if (m_nProtagonistIndex == -1)
|
||||
return;
|
||||
|
||||
g_ProtagonistSystem.PrecacheProtagonist( this, m_nProtagonistIndex );
|
||||
|
||||
const char *pszProtagModel = g_ProtagonistSystem.GetProtagonist_PlayerModel( this );
|
||||
if (pszProtagModel)
|
||||
SetModel( pszProtagModel );
|
||||
|
||||
m_nSkin = g_ProtagonistSystem.GetProtagonist_PlayerModelSkin( this );
|
||||
m_nBody = g_ProtagonistSystem.GetProtagonist_PlayerModelBody( this );
|
||||
|
||||
char szContexts[128] = { 0 };
|
||||
g_ProtagonistSystem.GetProtagonist_ResponseContexts( this, szContexts, sizeof( szContexts ) );
|
||||
if (szContexts[0])
|
||||
AddContext( szContexts );
|
||||
|
||||
RefreshProtagonistWeaponData( GetActiveWeapon() );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Refreshes protagonist data
|
||||
//-----------------------------------------------------------------------------
|
||||
void CHL2_Player::RefreshProtagonistWeaponData( CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
if (m_nProtagonistIndex == -1)
|
||||
return;
|
||||
|
||||
CBaseViewModel *vm = GetViewModel( 1 );
|
||||
if (vm)
|
||||
{
|
||||
const char *pszHandModel = g_ProtagonistSystem.GetProtagonist_HandModel( this, pWeapon );
|
||||
if (pszHandModel)
|
||||
{
|
||||
vm->SetWeaponModel( pszHandModel, NULL );
|
||||
|
||||
vm->m_nSkin = g_ProtagonistSystem.GetProtagonist_HandModelSkin( this, pWeapon );
|
||||
vm->m_nBody = g_ProtagonistSystem.GetProtagonist_HandModelBody( this, pWeapon );
|
||||
}
|
||||
else
|
||||
{
|
||||
extern char g_szDefaultHandsModel[MAX_PATH];
|
||||
vm->SetWeaponModel( g_szDefaultHandsModel, NULL );
|
||||
|
||||
vm->m_nSkin = 0;
|
||||
vm->m_nBody = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -358,6 +358,15 @@ public:
|
||||
void AddCustomSuitDevice( int iDeviceID );
|
||||
void RemoveCustomSuitDevice( int iDeviceID );
|
||||
bool IsCustomSuitDeviceActive( int iDeviceID );
|
||||
|
||||
// Protagonist system
|
||||
const char *GetProtagonistName() const;
|
||||
int GetProtagonistIndex() const;
|
||||
void InputSetProtagonist( inputdata_t &inputdata );
|
||||
void SetProtagonist( const char *pszProtagonist );
|
||||
void ResetProtagonist();
|
||||
void RefreshProtagonistData();
|
||||
void RefreshProtagonistWeaponData( CBaseCombatWeapon *pWeapon );
|
||||
#endif
|
||||
|
||||
CSoundPatch *m_sndLeeches;
|
||||
@ -442,6 +451,12 @@ private:
|
||||
|
||||
friend class CHL2GameMovement;
|
||||
|
||||
#ifdef MAPBASE
|
||||
// Protagonist used by protagonist_system.h
|
||||
string_t m_iszProtagonistName;
|
||||
CNetworkVar( int, m_nProtagonistIndex );
|
||||
#endif
|
||||
|
||||
#ifdef SP_ANIM_STATE
|
||||
CMapbasePlayerAnimState* m_pPlayerAnimState;
|
||||
|
||||
|
@ -4475,6 +4475,11 @@ void CBasePlayer::SetSuitUpdate(const char *name, int fgroup, int iNoRepeatTime)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MAPBASE
|
||||
if ( HasContext("silent_suit", "1") )
|
||||
return;
|
||||
#endif
|
||||
|
||||
// if name == NULL, then clear out the queue
|
||||
|
||||
if (!name)
|
||||
|
@ -48,6 +48,8 @@ $Project
|
||||
$File "$SRCDIR\game\shared\mapbase\matchers.h"
|
||||
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.cpp"
|
||||
$File "$SRCDIR\game\shared\mapbase\mapbase_playeranimstate.h"
|
||||
$File "$SRCDIR\game\shared\mapbase\protagonist_system.cpp"
|
||||
$File "$SRCDIR\game\shared\mapbase\protagonist_system.h"
|
||||
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.cpp" [$MAPBASE_VSCRIPT]
|
||||
$File "$SRCDIR\game\shared\mapbase\vscript_funcs_shared.h" [$MAPBASE_VSCRIPT]
|
||||
$File "$SRCDIR\game\shared\mapbase\vscript_singletons.cpp" [$MAPBASE_VSCRIPT]
|
||||
|
@ -507,6 +507,11 @@ bool CBaseCombatWeapon::UsesHands() const
|
||||
{
|
||||
return GetWpnData().m_bUsesHands;
|
||||
}
|
||||
|
||||
int CBaseCombatWeapon::GetHandRig() const
|
||||
{
|
||||
return GetWpnData().m_nHandRig;
|
||||
}
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -3127,6 +3132,9 @@ BEGIN_ENT_SCRIPTDESC( CBaseCombatWeapon, CBaseAnimating, "The base class for all
|
||||
DEFINE_SCRIPTFUNC( GetViewModel, "Get the weapon's view model." )
|
||||
DEFINE_SCRIPTFUNC( GetDroppedModel, "Get the weapon's unique dropped model if it has one." )
|
||||
|
||||
DEFINE_SCRIPTFUNC( UsesHands, "" )
|
||||
DEFINE_SCRIPTFUNC( GetHandRig, "" )
|
||||
|
||||
DEFINE_SCRIPTFUNC( GetWeight, "Get the weapon's weight." )
|
||||
DEFINE_SCRIPTFUNC( GetPrintName, "" )
|
||||
|
||||
|
@ -423,12 +423,13 @@ public:
|
||||
virtual bool UsesClipsForAmmo2( void ) const;
|
||||
bool IsMeleeWeapon() const;
|
||||
#ifdef MAPBASE
|
||||
float GetViewmodelFOVOverride() const;
|
||||
virtual float GetViewmodelFOVOverride() const;
|
||||
float GetBobScale() const;
|
||||
float GetSwayScale() const;
|
||||
float GetSwaySpeedScale() const;
|
||||
virtual const char *GetDroppedModel( void ) const;
|
||||
bool UsesHands( void ) const;
|
||||
virtual bool UsesHands( void ) const;
|
||||
virtual int GetHandRig( void ) const;
|
||||
#endif
|
||||
|
||||
// derive this function if you mod uses encrypted weapon info files
|
||||
|
@ -6,6 +6,9 @@
|
||||
|
||||
#include "cbase.h"
|
||||
#include "basehlcombatweapon_shared.h"
|
||||
#ifdef MAPBASE
|
||||
#include "mapbase/protagonist_system.h"
|
||||
#endif
|
||||
|
||||
#include "hl2_player_shared.h"
|
||||
|
||||
@ -436,4 +439,66 @@ const WeaponProficiencyInfo_t *CBaseHLCombatWeapon::GetDefaultProficiencyValues(
|
||||
return g_BaseWeaponProficiencyTable;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef MAPBASE
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
const char *CBaseHLCombatWeapon::GetViewModel( int viewmodelindex ) const
|
||||
{
|
||||
if (GetOwner() && GetOwner()->IsPlayer() && viewmodelindex == 0)
|
||||
{
|
||||
const char *pszProtagVM = g_ProtagonistSystem.GetProtagonist_ViewModel( static_cast<CBasePlayer *>(GetOwner()), this );
|
||||
if (pszProtagVM)
|
||||
return pszProtagVM;
|
||||
}
|
||||
|
||||
return BaseClass::GetViewModel( viewmodelindex );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
float CBaseHLCombatWeapon::GetViewmodelFOVOverride() const
|
||||
{
|
||||
if (GetOwner() && GetOwner()->IsPlayer())
|
||||
{
|
||||
float *flVMFOV = g_ProtagonistSystem.GetProtagonist_ViewModelFOV( static_cast<CBasePlayer *>(GetOwner()), this );
|
||||
if (flVMFOV)
|
||||
return *flVMFOV;
|
||||
}
|
||||
|
||||
return BaseClass::GetViewmodelFOVOverride();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
bool CBaseHLCombatWeapon::UsesHands() const
|
||||
{
|
||||
if (GetOwner() && GetOwner()->IsPlayer())
|
||||
{
|
||||
bool *bProtagUsesHands = g_ProtagonistSystem.GetProtagonist_UsesHands( static_cast<CBasePlayer *>(GetOwner()), this );
|
||||
if (bProtagUsesHands)
|
||||
return *bProtagUsesHands;
|
||||
}
|
||||
|
||||
return BaseClass::UsesHands();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose:
|
||||
//-----------------------------------------------------------------------------
|
||||
int CBaseHLCombatWeapon::GetHandRig() const
|
||||
{
|
||||
if (GetOwner() && GetOwner()->IsPlayer())
|
||||
{
|
||||
int *nProtagHandRig = g_ProtagonistSystem.GetProtagonist_HandRig( static_cast<CBasePlayer *>(GetOwner()), this );
|
||||
if (nProtagHandRig)
|
||||
return *nProtagHandRig;
|
||||
}
|
||||
|
||||
return BaseClass::GetHandRig();
|
||||
}
|
||||
#endif
|
||||
|
@ -53,6 +53,13 @@ public:
|
||||
|
||||
virtual void ItemHolsterFrame( void );
|
||||
|
||||
#ifdef MAPBASE
|
||||
virtual const char *GetViewModel( int viewmodelindex = 0 ) const;
|
||||
virtual float GetViewmodelFOVOverride() const;
|
||||
virtual bool UsesHands( void ) const;
|
||||
virtual int GetHandRig( void ) const;
|
||||
#endif
|
||||
|
||||
int m_iPrimaryAttacks; // # of primary attacks performed with this weapon
|
||||
int m_iSecondaryAttacks; // # of secondary attacks performed with this weapon
|
||||
|
||||
|
@ -31,6 +31,9 @@
|
||||
#include "gameinterface.h"
|
||||
#include "mapbase/choreosentence.h"
|
||||
#endif
|
||||
#if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
|
||||
#include "protagonist_system.h"
|
||||
#endif
|
||||
|
||||
// memdbgon must be the last include file in a .cpp file!!!
|
||||
#include "tier0/memdbgon.h"
|
||||
@ -92,6 +95,11 @@ bool g_bDefaultPlayerDrawExternally;
|
||||
char g_szDefaultHandsModel[MAX_PATH];
|
||||
int g_iDefaultHandsSkin;
|
||||
int g_iDefaultHandsBody;
|
||||
|
||||
#ifdef HL2_DLL
|
||||
// See protagonist_system.h
|
||||
char g_szDefaultProtagonist[MAX_PROTAGONIST_NAME];
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum
|
||||
@ -115,6 +123,9 @@ enum
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
MANIFEST_VSCRIPT,
|
||||
#endif
|
||||
#if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
|
||||
MANIFEST_PROTAGONISTS, // See protagonist_system.h
|
||||
#endif
|
||||
|
||||
// Must always be kept below
|
||||
MANIFEST_NUM_TYPES,
|
||||
@ -155,6 +166,9 @@ static const ManifestType_t gm_szManifestFileStrings[MANIFEST_NUM_TYPES] = {
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
{ "vscript", "mapbase_load_vscript", "Should we load map-specific VScript map spawn files? e.g. \"maps/<mapname>_mapspawn.nut\"" },
|
||||
#endif
|
||||
#if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
|
||||
{ "protagonists", "mapbase_load_protagonists", "Should we load map-specific protagonist files? e.g. \"maps/<mapname>_protagonists.txt\"" },
|
||||
#endif
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -243,6 +257,10 @@ public:
|
||||
Q_strncpy( g_szDefaultHandsModel, gameinfo->GetString( "player_default_hands", "models/weapons/v_hands.mdl" ), sizeof( g_szDefaultHandsModel ) );
|
||||
g_iDefaultHandsSkin = gameinfo->GetInt( "player_default_hands_skin", 0 );
|
||||
g_iDefaultHandsBody = gameinfo->GetInt( "player_default_hands_body", 0 );
|
||||
|
||||
#ifdef HL2_DLL
|
||||
Q_strncpy( g_szDefaultProtagonist, gameinfo->GetString( "player_default_protagonist", "" ), sizeof( g_szDefaultProtagonist ) );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
gameinfo->deleteThis();
|
||||
@ -473,6 +491,9 @@ public:
|
||||
#endif
|
||||
#ifdef MAPBASE_VSCRIPT
|
||||
case MANIFEST_VSCRIPT: { VScriptRunScript(value, false); } break;
|
||||
#endif
|
||||
#if defined(HL2_DLL) || defined(HL2_CLIENT_DLL)
|
||||
case MANIFEST_PROTAGONISTS: { g_ProtagonistSystem.LoadProtagonistFile( value ); } break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
732
sp/src/game/shared/mapbase/protagonist_system.cpp
Normal file
732
sp/src/game/shared/mapbase/protagonist_system.cpp
Normal file
@ -0,0 +1,732 @@
|
||||
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
|
||||
//
|
||||
// Purpose: System to easily switch between player characters.
|
||||
//
|
||||
// Author: Blixibon
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#include "cbase.h"
|
||||
#include "protagonist_system.h"
|
||||
#include "weapon_parse.h"
|
||||
#include "filesystem.h"
|
||||
#include "hl2_player_shared.h"
|
||||
#ifdef HL2MP
|
||||
#include "hl2mp_gamerules.h"
|
||||
#endif
|
||||
|
||||
CProtagonistSystem g_ProtagonistSystem;
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
bool CProtagonistSystem::Init()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void CProtagonistSystem::Shutdown()
|
||||
{
|
||||
PurgeProtagonists();
|
||||
}
|
||||
|
||||
void CProtagonistSystem::LevelInitPreEntity()
|
||||
{
|
||||
LoadProtagonistManifest( "scripts/protagonists/protagonists_manifest.txt" );
|
||||
}
|
||||
|
||||
void CProtagonistSystem::LevelShutdownPostEntity()
|
||||
{
|
||||
PurgeProtagonists();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void CProtagonistSystem::LoadProtagonistManifest( const char *pszFile )
|
||||
{
|
||||
KeyValues *pManifest = new KeyValues( "ProtagonistsManifest" );
|
||||
if (pManifest->LoadFromFile( filesystem, pszFile ))
|
||||
{
|
||||
FOR_EACH_SUBKEY( pManifest, pSubKey )
|
||||
{
|
||||
LoadProtagonistFile( pSubKey->GetString() );
|
||||
}
|
||||
}
|
||||
pManifest->deleteThis();
|
||||
}
|
||||
|
||||
void CProtagonistSystem::LoadProtagonistFile( const char *pszFile )
|
||||
{
|
||||
KeyValues *pManifest = new KeyValues( "Protagonists" );
|
||||
if (pManifest->LoadFromFile( filesystem, pszFile ))
|
||||
{
|
||||
FOR_EACH_SUBKEY( pManifest, pProtagKey )
|
||||
{
|
||||
if (!pProtagKey->GetName()[0])
|
||||
continue;
|
||||
|
||||
ProtagonistData_t *pProtag = FindProtagonist( pProtagKey->GetName() );
|
||||
if (!pProtag)
|
||||
{
|
||||
pProtag = &m_Protagonists[m_Protagonists.AddToTail()];
|
||||
V_strncpy( pProtag->szName, pProtagKey->GetName(), sizeof( pProtag->szName ) );
|
||||
}
|
||||
|
||||
FOR_EACH_SUBKEY( pProtagKey, pSubKey )
|
||||
{
|
||||
const char *pszSubKeyName = pSubKey->GetName();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Metadata
|
||||
//----------------------------------------------------------------------------
|
||||
if (FStrEq( pszSubKeyName, "inherits_from" ))
|
||||
{
|
||||
char szParents[128];
|
||||
V_strncpy( szParents, pSubKey->GetString(), sizeof( szParents ) );
|
||||
|
||||
char *pszToken = strtok( szParents, ";" );
|
||||
for (; pszToken != NULL; pszToken = strtok( NULL, ";" ))
|
||||
{
|
||||
if (!pszToken || !*pszToken)
|
||||
continue;
|
||||
|
||||
int nParent = FindProtagonistIndex( pszToken );
|
||||
if (nParent >= 0)
|
||||
{
|
||||
pProtag->vecParents.FindAndRemove( nParent ); // If it already exists, it will be moved to the front
|
||||
|
||||
pProtag->vecParents.AddToTail( nParent );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#else
|
||||
//----------------------------------------------------------------------------
|
||||
// Playermodel
|
||||
//----------------------------------------------------------------------------
|
||||
else if (V_strnicmp( pszSubKeyName, "playermodel", 11 ) == 0)
|
||||
{
|
||||
pszSubKeyName += 11;
|
||||
if (!pszSubKeyName[0])
|
||||
{
|
||||
// Model
|
||||
pProtag->pszPlayerModel = AllocateString( pSubKey->GetString() );
|
||||
}
|
||||
else if (FStrEq( pszSubKeyName, "_skin" ))
|
||||
{
|
||||
// Skin
|
||||
pProtag->nPlayerSkin = pSubKey->GetInt();
|
||||
}
|
||||
else if (FStrEq( pszSubKeyName, "_body" ))
|
||||
{
|
||||
// Bodygroup
|
||||
pProtag->nPlayerBody = pSubKey->GetInt();
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Hands
|
||||
//----------------------------------------------------------------------------
|
||||
else if (V_strnicmp( pszSubKeyName, "hands", 5 ) == 0)
|
||||
{
|
||||
pszSubKeyName += 5;
|
||||
if (!pszSubKeyName[0])
|
||||
{
|
||||
// Model
|
||||
pProtag->pszHandModels[HANDRIG_DEFAULT] = AllocateString( pSubKey->GetString() );
|
||||
}
|
||||
else if (FStrEq( pszSubKeyName, "_skin" ))
|
||||
{
|
||||
// Skin
|
||||
pProtag->nHandSkin = pSubKey->GetInt();
|
||||
}
|
||||
else if (FStrEq( pszSubKeyName, "_body" ))
|
||||
{
|
||||
// Bodygroup
|
||||
pProtag->nHandBody = pSubKey->GetInt();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Other Rigs
|
||||
pszSubKeyName += 1;
|
||||
for (int i = 0; i < NUM_HAND_RIG_TYPES; i++)
|
||||
{
|
||||
extern const char *pHandRigs[NUM_HAND_RIG_TYPES];
|
||||
|
||||
if (V_stricmp( pszSubKeyName, pHandRigs[i] ) == 0)
|
||||
{
|
||||
pProtag->pszHandModels[i] = AllocateString( pSubKey->GetString() );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Responses
|
||||
//----------------------------------------------------------------------------
|
||||
else if (FStrEq( pszSubKeyName, "response_contexts" ))
|
||||
{
|
||||
pProtag->pszResponseContexts = AllocateString( pSubKey->GetString() );
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// Multiplayer
|
||||
//----------------------------------------------------------------------------
|
||||
else if (FStrEq( pszSubKeyName, "team" ))
|
||||
{
|
||||
#ifdef HL2MP
|
||||
if (FStrEq( pszSubKeyName, "combine" ))
|
||||
{
|
||||
pProtag->nTeam = TEAM_COMBINE;
|
||||
}
|
||||
else if (FStrEq( pszSubKeyName, "rebels" ))
|
||||
{
|
||||
pProtag->nTeam = TEAM_REBELS;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
// Try to get a direct integer
|
||||
pProtag->nTeam = atoi( pszSubKeyName );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
//----------------------------------------------------------------------------
|
||||
// Weapon Data
|
||||
//----------------------------------------------------------------------------
|
||||
else if (V_strnicmp( pszSubKeyName, "wpn_viewmodels", 14 ) == 0)
|
||||
{
|
||||
// "wpn_viewmodels_c" = models which support arms
|
||||
bool bHands = FStrEq( pszSubKeyName + 14, "_c" );
|
||||
|
||||
FOR_EACH_SUBKEY( pSubKey, pWeaponKey )
|
||||
{
|
||||
int i = pProtag->dictWpnData.Find( pWeaponKey->GetName() );
|
||||
if (i == pProtag->dictWpnData.InvalidIndex())
|
||||
i = pProtag->dictWpnData.Insert( pWeaponKey->GetName() );
|
||||
|
||||
pProtag->dictWpnData[i].pszVM = AllocateString( pWeaponKey->GetString() );
|
||||
pProtag->dictWpnData[i].bUsesHands = bHands;
|
||||
}
|
||||
}
|
||||
else if (FStrEq( pszSubKeyName, "wpn_data" )) // More expanded/explicit
|
||||
{
|
||||
FOR_EACH_SUBKEY( pSubKey, pWeaponKey )
|
||||
{
|
||||
int i = pProtag->dictWpnData.Find( pWeaponKey->GetName() );
|
||||
if (i == pProtag->dictWpnData.InvalidIndex())
|
||||
i = pProtag->dictWpnData.Insert( pWeaponKey->GetName() );
|
||||
|
||||
const char *pszVM = pWeaponKey->GetString( "viewmodel", NULL );
|
||||
if (pszVM)
|
||||
pProtag->dictWpnData[i].pszVM = AllocateString( pszVM );
|
||||
|
||||
const char *pszHandRig = pWeaponKey->GetString( "hand_rig", NULL );
|
||||
if (pszHandRig)
|
||||
{
|
||||
// If there's a specific rig, then it must use hands
|
||||
pProtag->dictWpnData[i].bUsesHands = true;
|
||||
|
||||
for (int j = 0; j < NUM_HAND_RIG_TYPES; j++)
|
||||
{
|
||||
extern const char *pHandRigs[NUM_HAND_RIG_TYPES];
|
||||
|
||||
if (V_stricmp( pszHandRig, pHandRigs[j] ) == 0)
|
||||
{
|
||||
pProtag->dictWpnData[i].nHandRig = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyValues *pUsesHands = pWeaponKey->FindKey( "uses_hands" );
|
||||
if (pUsesHands)
|
||||
pProtag->dictWpnData[i].bUsesHands = pUsesHands->GetBool();
|
||||
}
|
||||
|
||||
KeyValues *pVMFOV = pWeaponKey->FindKey( "viewmodel_fov" );
|
||||
if (pVMFOV)
|
||||
pProtag->dictWpnData[i].flVMFOV = pVMFOV->GetFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pManifest->deleteThis();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
CProtagonistSystem::ProtagonistData_t *CProtagonistSystem::GetPlayerProtagonist( const CBasePlayer *pPlayer )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
const C_BaseHLPlayer *pHL2Player = static_cast<const C_BaseHLPlayer *>(pPlayer);
|
||||
#else
|
||||
const CHL2_Player *pHL2Player = static_cast<const CHL2_Player *>(pPlayer);
|
||||
#endif
|
||||
if (!pHL2Player)
|
||||
return NULL;
|
||||
|
||||
int i = pHL2Player->GetProtagonistIndex();
|
||||
if (i >= 0 && i < m_Protagonists.Count())
|
||||
{
|
||||
return &g_ProtagonistSystem.m_Protagonists[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CProtagonistSystem::ProtagonistData_t *CProtagonistSystem::FindProtagonist( const char *pszName )
|
||||
{
|
||||
FOR_EACH_VEC( m_Protagonists, i )
|
||||
{
|
||||
if (FStrEq( pszName, m_Protagonists[i].szName ))
|
||||
{
|
||||
return &m_Protagonists[i];
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CProtagonistSystem::ProtagonistData_t *CProtagonistSystem::FindProtagonist( int nIndex )
|
||||
{
|
||||
if (nIndex < 0 || nIndex >= m_Protagonists.Count())
|
||||
return NULL;
|
||||
|
||||
return &m_Protagonists[nIndex];
|
||||
}
|
||||
|
||||
int CProtagonistSystem::FindProtagonistIndex( const char *pszName )
|
||||
{
|
||||
FOR_EACH_VEC( m_Protagonists, i )
|
||||
{
|
||||
if (FStrEq( pszName, m_Protagonists[i].szName ))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const char *CProtagonistSystem::FindProtagonistByModel( const char *pszModelName )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
FOR_EACH_VEC( m_Protagonists, i )
|
||||
{
|
||||
if (m_Protagonists[i].pszPlayerModel && FStrEq( pszModelName, m_Protagonists[i].pszPlayerModel ))
|
||||
{
|
||||
return m_Protagonists[i].szName;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CProtagonistSystem::PrecacheProtagonist( CBaseEntity *pSource, int nIdx )
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
if (nIdx < 0)
|
||||
return;
|
||||
|
||||
ProtagonistData_t &pProtag = m_Protagonists[nIdx];
|
||||
|
||||
// Playermodel
|
||||
if (pProtag.pszPlayerModel)
|
||||
{
|
||||
pSource->PrecacheModel( pProtag.pszPlayerModel );
|
||||
}
|
||||
|
||||
// Hands
|
||||
for (int i = 0; i < NUM_HAND_RIG_TYPES; i++)
|
||||
{
|
||||
if (pProtag.pszHandModels[i])
|
||||
{
|
||||
pSource->PrecacheModel( pProtag.pszHandModels[i] );
|
||||
}
|
||||
}
|
||||
|
||||
// Weapon Data
|
||||
FOR_EACH_DICT_FAST( pProtag.dictWpnData, i )
|
||||
{
|
||||
if (pProtag.dictWpnData[i].pszVM)
|
||||
{
|
||||
pSource->PrecacheModel( pProtag.dictWpnData[i].pszVM );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define GetProtagParamInner( name, ... ) DoGetProtagonist_##name( *pProtag, ##__VA_ARGS__ )
|
||||
|
||||
#define GetProtagParam( name, type, invoke, ... ) \
|
||||
type CProtagonistSystem::GetProtagonist_##name( const CBasePlayer *pPlayer, ##__VA_ARGS__ ) \
|
||||
{ \
|
||||
ProtagonistData_t *pProtag = GetPlayerProtagonist( pPlayer ); \
|
||||
if (!pProtag) \
|
||||
return NULL; \
|
||||
return invoke; \
|
||||
} \
|
||||
type CProtagonistSystem::GetProtagonist_##name( const int nProtagonistIndex, ##__VA_ARGS__ ) \
|
||||
{ \
|
||||
ProtagonistData_t *pProtag = FindProtagonist( nProtagonistIndex ); \
|
||||
if (!pProtag) \
|
||||
return NULL; \
|
||||
return invoke; \
|
||||
} \
|
||||
|
||||
#define GetProtagParamBody( name, type, invoke, body, ... ) \
|
||||
type CProtagonistSystem::GetProtagonist_##name( const CBasePlayer *pPlayer, ##__VA_ARGS__ ) \
|
||||
{ \
|
||||
ProtagonistData_t *pProtag = GetPlayerProtagonist( pPlayer ); \
|
||||
if (!pProtag) \
|
||||
return NULL; \
|
||||
type returnVal = invoke; \
|
||||
body \
|
||||
return returnVal; \
|
||||
} \
|
||||
type CProtagonistSystem::GetProtagonist_##name( const int nProtagonistIndex, ##__VA_ARGS__ ) \
|
||||
{ \
|
||||
ProtagonistData_t *pProtag = FindProtagonist( nProtagonistIndex ); \
|
||||
if (!pProtag) \
|
||||
return NULL; \
|
||||
type returnVal = invoke; \
|
||||
body \
|
||||
return returnVal; \
|
||||
} \
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#else
|
||||
GetProtagParam( PlayerModel, const char*, GetProtagParamInner( PlayerModel ) )
|
||||
GetProtagParam( PlayerModelSkin, int, GetProtagParamInner( PlayerModelSkin ) )
|
||||
GetProtagParam( PlayerModelBody, int, GetProtagParamInner( PlayerModelBody ) )
|
||||
GetProtagParam( HandModel, const char*, GetProtagParamInner( HandModel, pWeapon ), const CBaseCombatWeapon *pWeapon )
|
||||
GetProtagParam( HandModelSkin, int, GetProtagParamInner( HandModelSkin, pWeapon ), const CBaseCombatWeapon *pWeapon )
|
||||
GetProtagParam( HandModelBody, int, GetProtagParamInner( HandModelBody, pWeapon ), const CBaseCombatWeapon *pWeapon )
|
||||
GetProtagParamBody( ResponseContexts, bool, GetProtagParamInner( ResponseContexts, pszContexts, nContextsSize ), {
|
||||
if (pszContexts[0] != '\0')
|
||||
{
|
||||
// Replace trailing comma
|
||||
int nLast = V_strlen( pszContexts )-1;
|
||||
if (pszContexts[nLast] == ',')
|
||||
{
|
||||
Msg( "Removing trailing comma from \"%s\"\n", pszContexts );
|
||||
pszContexts[nLast] = '\0';
|
||||
}
|
||||
}
|
||||
}, char *pszContexts, int nContextsSize )
|
||||
GetProtagParam( Team, int, GetProtagParamInner( Team ) )
|
||||
#endif
|
||||
|
||||
GetProtagParam( ViewModel, const char*, GetProtagParamInner( ViewModel, pWeapon ), const CBaseCombatWeapon *pWeapon )
|
||||
GetProtagParam( ViewModelFOV, float*, GetProtagParamInner( ViewModelFOV, pWeapon ), const CBaseCombatWeapon *pWeapon )
|
||||
GetProtagParam( UsesHands, bool*, GetProtagParamInner( UsesHands, pWeapon ), const CBaseCombatWeapon *pWeapon )
|
||||
GetProtagParam( HandRig, int*, GetProtagParamInner( HandRig, pWeapon ), const CBaseCombatWeapon *pWeapon )
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define GetProtagonistRecurse( funcName, ... ) \
|
||||
FOR_EACH_VEC( pProtag.vecParents, i ) \
|
||||
{ \
|
||||
ProtagonistData_t *pParent = FindProtagonist(pProtag.vecParents[i]); \
|
||||
if (!pParent) \
|
||||
continue; \
|
||||
auto returnVar = funcName( *pParent, ##__VA_ARGS__ ); \
|
||||
if (returnVar) \
|
||||
return returnVar; \
|
||||
} \
|
||||
|
||||
#define GetProtagonistRecurseNoReturn( funcName, ... ) \
|
||||
FOR_EACH_VEC( pProtag.vecParents, i ) \
|
||||
{ \
|
||||
ProtagonistData_t *pParent = FindProtagonist(pProtag.vecParents[i]); \
|
||||
if (!pParent) \
|
||||
continue; \
|
||||
funcName( *pParent, ##__VA_ARGS__ ); \
|
||||
} \
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#else
|
||||
const char *CProtagonistSystem::DoGetProtagonist_PlayerModel( ProtagonistData_t &pProtag )
|
||||
{
|
||||
if (pProtag.pszPlayerModel)
|
||||
return pProtag.pszPlayerModel;
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_PlayerModel )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CProtagonistSystem::DoGetProtagonist_PlayerModelSkin( ProtagonistData_t &pProtag )
|
||||
{
|
||||
if (pProtag.nPlayerSkin >= 0)
|
||||
return pProtag.nPlayerSkin;
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_PlayerModelSkin )
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CProtagonistSystem::DoGetProtagonist_PlayerModelBody( ProtagonistData_t &pProtag )
|
||||
{
|
||||
if (pProtag.nPlayerBody >= 0)
|
||||
return pProtag.nPlayerBody;
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_PlayerModelBody )
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *CProtagonistSystem::DoGetProtagonist_HandModel( ProtagonistData_t &pProtag, const CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
int nRigType = pWeapon ? pWeapon->GetHandRig() : HANDRIG_DEFAULT;
|
||||
if (pProtag.pszHandModels[nRigType])
|
||||
return pProtag.pszHandModels[nRigType];
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_HandModel, pWeapon )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CProtagonistSystem::DoGetProtagonist_HandModelSkin( ProtagonistData_t &pProtag, const CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
if (pProtag.nHandSkin >= 0)
|
||||
return pProtag.nHandSkin;
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_HandModelSkin, pWeapon )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CProtagonistSystem::DoGetProtagonist_HandModelBody( ProtagonistData_t &pProtag, const CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
if (pProtag.nHandBody >= 0)
|
||||
return pProtag.nHandBody;
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_HandModelBody, pWeapon )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CProtagonistSystem::DoGetProtagonist_ResponseContexts( ProtagonistData_t &pProtag, char *pszContexts, int nContextsSize )
|
||||
{
|
||||
if (pProtag.pszResponseContexts)
|
||||
{
|
||||
V_strncat( pszContexts, pProtag.pszResponseContexts, nContextsSize );
|
||||
V_strncat( pszContexts, ",", nContextsSize );
|
||||
}
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurseNoReturn( DoGetProtagonist_ResponseContexts, pszContexts, nContextsSize )
|
||||
|
||||
return pszContexts[0] != '\0';
|
||||
}
|
||||
|
||||
int CProtagonistSystem::DoGetProtagonist_Team( ProtagonistData_t &pProtag )
|
||||
{
|
||||
if (pProtag.nTeam >= -1)
|
||||
return pProtag.nTeam;
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_Team )
|
||||
|
||||
return TEAM_ANY;
|
||||
}
|
||||
#endif
|
||||
|
||||
const char *CProtagonistSystem::DoGetProtagonist_ViewModel( ProtagonistData_t &pProtag, const CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
FOR_EACH_DICT_FAST( pProtag.dictWpnData, i )
|
||||
{
|
||||
// HACKHACK: GetClassname is not const
|
||||
if (!FStrEq( pProtag.dictWpnData.GetElementName( i ), const_cast<CBaseCombatWeapon*>(pWeapon)->GetClassname() ))
|
||||
continue;
|
||||
|
||||
if (pProtag.dictWpnData[i].pszVM)
|
||||
return pProtag.dictWpnData[i].pszVM;
|
||||
break;
|
||||
}
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_ViewModel, pWeapon )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
float *CProtagonistSystem::DoGetProtagonist_ViewModelFOV( ProtagonistData_t &pProtag, const CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
FOR_EACH_DICT_FAST( pProtag.dictWpnData, i )
|
||||
{
|
||||
// HACKHACK: GetClassname is not const
|
||||
if (!FStrEq( pProtag.dictWpnData.GetElementName( i ), const_cast<CBaseCombatWeapon*>(pWeapon)->GetClassname() ))
|
||||
continue;
|
||||
|
||||
return &pProtag.dictWpnData[i].flVMFOV;
|
||||
}
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_ViewModelFOV, pWeapon )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool *CProtagonistSystem::DoGetProtagonist_UsesHands( ProtagonistData_t &pProtag, const CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
FOR_EACH_DICT_FAST( pProtag.dictWpnData, i )
|
||||
{
|
||||
// HACKHACK: GetClassname is not const
|
||||
if (!FStrEq( pProtag.dictWpnData.GetElementName( i ), const_cast<CBaseCombatWeapon*>(pWeapon)->GetClassname() ))
|
||||
continue;
|
||||
|
||||
return &pProtag.dictWpnData[i].bUsesHands;
|
||||
}
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_UsesHands, pWeapon )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int *CProtagonistSystem::DoGetProtagonist_HandRig( ProtagonistData_t &pProtag, const CBaseCombatWeapon *pWeapon )
|
||||
{
|
||||
FOR_EACH_DICT_FAST( pProtag.dictWpnData, i )
|
||||
{
|
||||
// HACKHACK: GetClassname is not const
|
||||
if (!FStrEq( pProtag.dictWpnData.GetElementName( i ), const_cast<CBaseCombatWeapon*>(pWeapon)->GetClassname() ))
|
||||
continue;
|
||||
|
||||
return &pProtag.dictWpnData[i].nHandRig;
|
||||
}
|
||||
|
||||
// Recursively search parent protagonists
|
||||
GetProtagonistRecurse( DoGetProtagonist_HandRig, pWeapon )
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
const char *CProtagonistSystem::FindString( const char *string )
|
||||
{
|
||||
unsigned short i = m_Strings.Find( string );
|
||||
return i == m_Strings.InvalidIndex() ? NULL : m_Strings[i];
|
||||
}
|
||||
|
||||
const char *CProtagonistSystem::AllocateString( const char *string )
|
||||
{
|
||||
int i = m_Strings.Find( string );
|
||||
if (i != m_Strings.InvalidIndex())
|
||||
{
|
||||
return m_Strings[i];
|
||||
}
|
||||
|
||||
int len = Q_strlen( string );
|
||||
char *out = new char[len + 1];
|
||||
Q_memcpy( out, string, len );
|
||||
out[len] = 0;
|
||||
|
||||
return m_Strings[m_Strings.Insert( out )];
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void CProtagonistSystem::PurgeProtagonists()
|
||||
{
|
||||
m_Protagonists.RemoveAll();
|
||||
|
||||
for (unsigned int i = 0; i < m_Strings.Count(); i++)
|
||||
{
|
||||
delete m_Strings[i];
|
||||
}
|
||||
m_Strings.Purge();
|
||||
}
|
||||
|
||||
void CProtagonistSystem::PrintProtagonistData()
|
||||
{
|
||||
Msg( "PROTAGONISTS\n\n" );
|
||||
|
||||
FOR_EACH_VEC( m_Protagonists, i )
|
||||
{
|
||||
ProtagonistData_t &pProtag = m_Protagonists[i];
|
||||
|
||||
Msg( "\t\"%s\"\n", pProtag.szName );
|
||||
|
||||
Msg( "\t\tParents: %i\n", pProtag.vecParents.Count() );
|
||||
if (pProtag.vecParents.Count() > 0)
|
||||
{
|
||||
FOR_EACH_VEC( pProtag.vecParents, j )
|
||||
{
|
||||
ProtagonistData_t *pParent = FindProtagonist( pProtag.vecParents[j] );
|
||||
if (!pParent)
|
||||
continue;
|
||||
|
||||
Msg( "\t\t\t\"%s\"\n", pParent->szName );
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#else
|
||||
if (pProtag.pszPlayerModel)
|
||||
Msg( "\t\tPlayer model: \"%s\" (%i, %i)\n", pProtag.pszPlayerModel, pProtag.nPlayerSkin, pProtag.nPlayerBody );
|
||||
|
||||
for (int j = 0; j < NUM_HAND_RIG_TYPES; j++)
|
||||
{
|
||||
extern const char *pHandRigs[NUM_HAND_RIG_TYPES];
|
||||
if (pProtag.pszHandModels[j])
|
||||
Msg( "\t\tHand %s model: \"%s\" (%i, %i)\n", pHandRigs[j], pProtag.pszHandModels[j], pProtag.nPlayerSkin, pProtag.nPlayerBody );
|
||||
}
|
||||
|
||||
// Weapon Data
|
||||
Msg( "\t\tWeapon Data: %i\n", pProtag.dictWpnData.Count() );
|
||||
FOR_EACH_DICT_FAST( pProtag.dictWpnData, j )
|
||||
{
|
||||
Msg( "\t\t\t%s\n", pProtag.dictWpnData.GetElementName(j) );
|
||||
if (pProtag.dictWpnData[j].pszVM)
|
||||
Msg( "\t\t\t\tViewmodel: \"%s\"\n", pProtag.dictWpnData[j].pszVM );
|
||||
|
||||
Msg( "\t\t\t\tUses hands: %d, hand rig: %i\n", pProtag.dictWpnData[j].bUsesHands, pProtag.dictWpnData[j].nHandRig );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
CON_COMMAND_SHARED( protagonist_reload, "Reloads protagonist data" )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
if (C_BasePlayer::GetLocalPlayer() == NULL)
|
||||
{
|
||||
Msg( "Must be in a level\n" );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_ProtagonistSystem.PurgeProtagonists();
|
||||
g_ProtagonistSystem.LoadProtagonistManifest( "scripts/protagonists/protagonists_manifest.txt" );
|
||||
}
|
||||
|
||||
CON_COMMAND_SHARED( protagonist_dump, "Dumps protagonist data" )
|
||||
{
|
||||
#ifdef CLIENT_DLL
|
||||
if (C_BasePlayer::GetLocalPlayer() == NULL)
|
||||
{
|
||||
Msg( "Must be in a level\n" );
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
g_ProtagonistSystem.PrintProtagonistData();
|
||||
}
|
153
sp/src/game/shared/mapbase/protagonist_system.h
Normal file
153
sp/src/game/shared/mapbase/protagonist_system.h
Normal file
@ -0,0 +1,153 @@
|
||||
//========= Mapbase - https://github.com/mapbase-source/source-sdk-2013 ============//
|
||||
//
|
||||
// Purpose: System to easily switch between player characters.
|
||||
//
|
||||
// Author: Blixibon
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#ifndef PROTAGONIST_SYSTEM_H
|
||||
#define PROTAGONIST_SYSTEM_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#include "c_baseplayer.h"
|
||||
#else
|
||||
#include "player.h"
|
||||
#endif
|
||||
|
||||
#define MAX_PROTAGONIST_NAME 32
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
class CProtagonistSystem : public CAutoGameSystem
|
||||
{
|
||||
public:
|
||||
CProtagonistSystem() : m_Strings( 256, 0, &StringLessThan ) { }
|
||||
~CProtagonistSystem() { PurgeProtagonists(); }
|
||||
|
||||
private:
|
||||
|
||||
struct ProtagonistData_t
|
||||
{
|
||||
ProtagonistData_t()
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
for (int i = 0; i < NUM_HAND_RIG_TYPES; i++)
|
||||
pszHandModels[i] = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
char szName[MAX_PROTAGONIST_NAME];
|
||||
|
||||
CUtlVector<int> vecParents;
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#else
|
||||
// Playermodel
|
||||
const char *pszPlayerModel = NULL;
|
||||
int nPlayerSkin = -1;
|
||||
int nPlayerBody = -1;
|
||||
|
||||
// Hands
|
||||
const char *pszHandModels[NUM_HAND_RIG_TYPES];
|
||||
int nHandSkin = -1;
|
||||
int nHandBody = -1;
|
||||
|
||||
// Responses
|
||||
const char *pszResponseContexts = NULL;
|
||||
|
||||
// Multiplayer
|
||||
int nTeam = TEAM_ANY;
|
||||
#endif
|
||||
|
||||
// Weapon Data
|
||||
struct WeaponDataOverride_t
|
||||
{
|
||||
const char *pszVM = NULL;
|
||||
bool bUsesHands = false;
|
||||
int nHandRig = 0;
|
||||
float flVMFOV = 0.0f;
|
||||
};
|
||||
|
||||
CUtlDict<WeaponDataOverride_t> dictWpnData;
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
bool Init();
|
||||
void Shutdown();
|
||||
void LevelInitPreEntity();
|
||||
void LevelShutdownPostEntity();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void LoadProtagonistManifest( const char *pszFile );
|
||||
void LoadProtagonistFile( const char *pszFile );
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
int FindProtagonistIndex( const char *pszName );
|
||||
const char *FindProtagonistByModel( const char *pszModelName );
|
||||
|
||||
void PrecacheProtagonist( CBaseEntity *pSource, int nIdx );
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#define DeclareProtagonistFunc(type, name, ...) \
|
||||
type GetProtagonist_##name( const CBasePlayer *pPlayer, ##__VA_ARGS__ ); \
|
||||
type GetProtagonist_##name( const int nProtagonistIndex, ##__VA_ARGS__ ); \
|
||||
private: \
|
||||
type DoGetProtagonist_##name( ProtagonistData_t &pProtag, ##__VA_ARGS__ ); \
|
||||
public: \
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
#else
|
||||
DeclareProtagonistFunc( const char*, PlayerModel )
|
||||
DeclareProtagonistFunc( int, PlayerModelSkin )
|
||||
DeclareProtagonistFunc( int, PlayerModelBody )
|
||||
DeclareProtagonistFunc( const char*, HandModel, const CBaseCombatWeapon *pWeapon )
|
||||
DeclareProtagonistFunc( int, HandModelSkin, const CBaseCombatWeapon *pWeapon )
|
||||
DeclareProtagonistFunc( int, HandModelBody, const CBaseCombatWeapon *pWeapon )
|
||||
DeclareProtagonistFunc( bool, ResponseContexts, char *pszContexts, int nContextsSize )
|
||||
DeclareProtagonistFunc( int, Team )
|
||||
#endif
|
||||
|
||||
DeclareProtagonistFunc( const char*, ViewModel, const CBaseCombatWeapon *pWeapon )
|
||||
DeclareProtagonistFunc( float*, ViewModelFOV, const CBaseCombatWeapon *pWeapon )
|
||||
DeclareProtagonistFunc( bool*, UsesHands, const CBaseCombatWeapon *pWeapon )
|
||||
DeclareProtagonistFunc( int*, HandRig, const CBaseCombatWeapon *pWeapon )
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
void PurgeProtagonists();
|
||||
void PrintProtagonistData();
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
|
||||
ProtagonistData_t *GetPlayerProtagonist( const CBasePlayer *pPlayer );
|
||||
ProtagonistData_t *FindProtagonist( const char *pszName );
|
||||
ProtagonistData_t *FindProtagonist( int nIndex );
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
const char *FindString( const char *string );
|
||||
const char *AllocateString( const char *string );
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
private:
|
||||
CUtlVector<ProtagonistData_t> m_Protagonists;
|
||||
|
||||
// Dedicated strings, copied from game string pool
|
||||
CUtlRBTree<const char *> m_Strings;
|
||||
|
||||
};
|
||||
|
||||
extern CProtagonistSystem g_ProtagonistSystem;
|
||||
|
||||
#endif // PROTAGONIST_SYSTEM_H
|
@ -408,6 +408,7 @@ FileWeaponInfo_t::FileWeaponInfo_t()
|
||||
m_flSwaySpeedScale = 1.0f;
|
||||
szDroppedModel[0] = 0;
|
||||
m_bUsesHands = false;
|
||||
m_nHandRig = HANDRIG_DEFAULT;
|
||||
m_nWeaponRestriction = WPNRESTRICT_NONE;
|
||||
#endif
|
||||
}
|
||||
@ -417,6 +418,12 @@ extern ConVar hud_fastswitch;
|
||||
#endif
|
||||
|
||||
#ifdef MAPBASE
|
||||
const char* pHandRigs[NUM_HAND_RIG_TYPES] = {
|
||||
"default",
|
||||
"css",
|
||||
"blender",
|
||||
};
|
||||
|
||||
const char* pWeaponRestrictions[NUM_WEAPON_RESTRICTION_TYPES] = {
|
||||
"none",
|
||||
"player_only",
|
||||
@ -493,6 +500,19 @@ void FileWeaponInfo_t::Parse( KeyValues *pKeyValuesData, const char *szWeaponNam
|
||||
|
||||
m_bUsesHands = ( pKeyValuesData->GetInt( "uses_hands", 0 ) != 0 ) ? true : false;
|
||||
|
||||
const char* pszHandRig = pKeyValuesData->GetString("hand_rig", nullptr);
|
||||
if (pszHandRig)
|
||||
{
|
||||
for (int i = 0; i < NUM_HAND_RIG_TYPES; i++)
|
||||
{
|
||||
if (V_stricmp(pszHandRig, pHandRigs[i]) == 0)
|
||||
{
|
||||
m_nHandRig = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* pszRestrictString = pKeyValuesData->GetString("usage_restriction", nullptr);
|
||||
if (pszRestrictString)
|
||||
{
|
||||
|
@ -59,6 +59,15 @@ class CHudTexture;
|
||||
class KeyValues;
|
||||
|
||||
#ifdef MAPBASE
|
||||
enum HandRigTypes_e
|
||||
{
|
||||
HANDRIG_DEFAULT, // Default HL2 rig
|
||||
HANDRIG_CSS, // CS:S viewmodel rig
|
||||
HANDRIG_BLENDER, // Blender IK rig
|
||||
|
||||
NUM_HAND_RIG_TYPES
|
||||
};
|
||||
|
||||
enum WeaponUsageRestricions_e
|
||||
{
|
||||
WPNRESTRICT_NONE = 0,
|
||||
@ -136,6 +145,7 @@ public:
|
||||
char szDroppedModel[MAX_WEAPON_STRING]; // Model of this weapon when dropped on the ground
|
||||
|
||||
bool m_bUsesHands;
|
||||
int m_nHandRig;
|
||||
|
||||
int m_nWeaponRestriction;
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user