From fa41a327e7753a3b948eac0ca60f9b351db10fe9 Mon Sep 17 00:00:00 2001 From: Peter Covington Date: Wed, 20 Apr 2022 01:48:32 -0400 Subject: [PATCH] Added a data cache to the custom weapons system --- .../server/mapbase/custom_weapon_factory.cpp | 24 +- .../server/mapbase/custom_weapon_factory.h | 45 +- .../game/server/mapbase/weapon_custom_hl2.cpp | 387 ++++++++++-------- .../shared/mapbase/weapon_custom_scripted.cpp | 19 +- .../shared/mapbase/weapon_custom_scripted.h | 2 +- 5 files changed, 278 insertions(+), 199 deletions(-) diff --git a/sp/src/game/server/mapbase/custom_weapon_factory.cpp b/sp/src/game/server/mapbase/custom_weapon_factory.cpp index f7424412..2feaec16 100644 --- a/sp/src/game/server/mapbase/custom_weapon_factory.cpp +++ b/sp/src/game/server/mapbase/custom_weapon_factory.cpp @@ -134,15 +134,28 @@ void CCustomWeaponSystem::LoadCustomWeaponsManifest(const char* file, bool bDont unsigned short FactoryIndex = Factory.Find(pszFactory); if (Factory.IsValidIndex(FactoryIndex)) { + auto* pFactory = Factory.Element(FactoryIndex); + const void* pData = pFactory->ParseDataFromWeaponFile(pkvWeaponScript); + if (!pData) + continue; + unsigned short ClassIndex = m_ClassFactories.Find(pszClassname); if (!m_ClassFactories.IsValidIndex(ClassIndex)) { ClassIndex = m_ClassFactories.Insert(pszClassname); m_ClassFactories[ClassIndex].pOldFactory = EntityFactoryDictionary()->FindFactory(pszClassname); } + else + { + Assert(m_ClassFactories[ClassIndex].pNewFactory); + Assert(m_ClassFactories[ClassIndex].pData); + + m_ClassFactories[ClassIndex].pNewFactory->ReleaseData(m_ClassFactories[ClassIndex].pData); + } m_ClassFactories[ClassIndex].sDataFile = pkvWeapon->GetString(); - m_ClassFactories[ClassIndex].pNewFactory = Factory.Element(FactoryIndex); + m_ClassFactories[ClassIndex].pNewFactory = pFactory; + m_ClassFactories[ClassIndex].pData = pData; EntityFactoryDictionary()->UninstallFactory(pszClassname); EntityFactoryDictionary()->InstallFactory(m_ClassFactories[ClassIndex].pNewFactory, pszClassname); } @@ -160,6 +173,9 @@ void CCustomWeaponSystem::LevelShutdownPostEntity() const CustomClassName_t& entry = m_ClassFactories.Element(i); if (entry.pOldFactory) EntityFactoryDictionary()->InstallFactory(entry.pOldFactory, m_ClassFactories.GetElementName(i)); + + Assert(entry.pData); + entry.pNewFactory->ReleaseData(entry.pData); } m_ClassFactories.Purge(); @@ -176,12 +192,12 @@ void CCustomWeaponSystem::ParseWeapon(CBaseCombatWeapon* pWeapon, const char* pC if (!m_ClassFactories.IsValidIndex(i)) return; - pCustom->ParseCustomFromWeaponFile(m_ClassFactories[i].sDataFile.String()); + pCustom->InitCustomWeaponFromData(m_ClassFactories[i].pData, m_ClassFactories[i].sDataFile.String()); } -CUtlDict& CustomWeaponsFactoryDictionary() +CUtlDict& CustomWeaponsFactoryDictionary() { - static CUtlDict dict; + static CUtlDict dict; return dict; } diff --git a/sp/src/game/server/mapbase/custom_weapon_factory.h b/sp/src/game/server/mapbase/custom_weapon_factory.h index f027ea86..838fd695 100644 --- a/sp/src/game/server/mapbase/custom_weapon_factory.h +++ b/sp/src/game/server/mapbase/custom_weapon_factory.h @@ -14,12 +14,17 @@ DECLARE_PRIVATE_SYMBOLTYPE(CustomWeaponSymbol); -CUtlDict< IEntityFactory*, unsigned short >& CustomWeaponsFactoryDictionary(); +class ICustomWeaponDataLoader : public IEntityFactory +{ +public: + virtual const void* ParseDataFromWeaponFile(KeyValues* pKV) const = 0; + virtual void ReleaseData(const void* pData) const = 0; +}; class ICustomWeapon { public: - virtual void ParseCustomFromWeaponFile(const char* pFileName) = 0; + virtual void InitCustomWeaponFromData(const void* pData, const char *pszWeaponScript) = 0; }; class CCustomWeaponSystem : public CAutoGameSystem @@ -42,19 +47,22 @@ private: typedef struct CustomClassName_s { CustomWeaponSymbol sDataFile; - IEntityFactory* pNewFactory; + ICustomWeaponDataLoader* pNewFactory; IEntityFactory* pOldFactory; + const void* pData; } CustomClassName_t; CUtlDict m_ClassFactories; }; CCustomWeaponSystem* CustomWeaponSystem(); +CUtlDict< ICustomWeaponDataLoader*, unsigned short >& CustomWeaponsFactoryDictionary(); + template -class CCustomWeaponEntityFactory : public IEntityFactory +class CCustomWeaponEntityFactoryBase : public ICustomWeaponDataLoader { public: - CCustomWeaponEntityFactory(const char* pFactoryClass) + CCustomWeaponEntityFactoryBase(const char* pFactoryClass) { CustomWeaponsFactoryDictionary().Insert(pFactoryClass, this); } @@ -80,7 +88,30 @@ public: } }; -#define DEFINE_CUSTOM_WEAPON_FACTORY(factoryName, DLLClassName) \ - static CCustomWeaponEntityFactory custom_weapon_##factoryName##_factory( #factoryName ); +template +class CDefaultCustomWeaponEntityFactory : public CCustomWeaponEntityFactoryBase +{ +public: + CDefaultCustomWeaponEntityFactory(const char *pFactoryClass) : CCustomWeaponEntityFactoryBase(pFactoryClass) + {} + + virtual const void* ParseDataFromWeaponFile(KeyValues* pKV) const + { + Data* pData = new Data; + if (pData && pData->Parse(pKV)) + return pData; + + delete pData; + return nullptr; + } + + virtual void ReleaseData(const void* pData) const + { + delete pData; + } +}; + +#define DEFINE_CUSTOM_WEAPON_FACTORY(factoryName, DLLClassName, DataStruct) \ + static CDefaultCustomWeaponEntityFactory custom_weapon_##factoryName##_factory( #factoryName ); #endif // !CUSTOM_WEAPON_FACTORY_H diff --git a/sp/src/game/server/mapbase/weapon_custom_hl2.cpp b/sp/src/game/server/mapbase/weapon_custom_hl2.cpp index af29357c..86c9733b 100644 --- a/sp/src/game/server/mapbase/weapon_custom_hl2.cpp +++ b/sp/src/game/server/mapbase/weapon_custom_hl2.cpp @@ -49,6 +49,17 @@ int g_nDamageClassTypeBits[ARRAYSIZE(g_ppszDamageClasses)] = { DMG_CLUB|DMG_BURN, }; +typedef struct HL2CustomMeleeData_s +{ + float m_flMeleeRange; + float m_flRefireRate; + float m_flDamage; + float m_flNPCDamage; + byte m_nDamageClass; + + bool Parse(KeyValues*); +} HL2CustomMeleeData_t; + class CHLCustomWeaponMelee : public CBaseHLBludgeonWeapon, public ICustomWeapon { public: @@ -59,8 +70,8 @@ public: CHLCustomWeaponMelee(); - float GetRange(void) { return m_flMeleeRange; } - float GetFireRate(void) { return m_flRefireRate; } + float GetRange(void) { return m_CustomData.m_flMeleeRange; } + float GetFireRate(void) { return m_CustomData.m_flRefireRate; } void AddViewKick(void); float GetDamageForActivity(Activity hitActivity); @@ -76,20 +87,16 @@ public: int GetBackupActivityListCount() { return 0; } const char* GetWeaponScriptName() { return m_iszWeaponScriptName.Get(); } - virtual int GetDamageType() { return g_nDamageClassTypeBits[m_nDamageClass]; } + virtual int GetDamageType() { return g_nDamageClassTypeBits[m_CustomData.m_nDamageClass]; } - virtual void ParseCustomFromWeaponFile(const char* pFileName); + virtual void InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript); private: // Animation event handlers void HandleAnimEventMeleeHit(animevent_t* pEvent, CBaseCombatCharacter* pOperator); private: - float m_flMeleeRange; - float m_flRefireRate; - float m_flDamage; - float m_flNPCDamage; - byte m_nDamageClass; + HL2CustomMeleeData_t m_CustomData; CNetworkString(m_iszWeaponScriptName, 128); }; @@ -98,7 +105,41 @@ IMPLEMENT_SERVERCLASS_ST(CHLCustomWeaponMelee, DT_HLCustomWeaponMelee) SendPropString(SENDINFO(m_iszWeaponScriptName)), END_SEND_TABLE(); -DEFINE_CUSTOM_WEAPON_FACTORY(hl2_melee, CHLCustomWeaponMelee); +DEFINE_CUSTOM_WEAPON_FACTORY(hl2_melee, CHLCustomWeaponMelee, HL2CustomMeleeData_t); + +bool HL2CustomMeleeData_s::Parse(KeyValues* pKVWeapon) +{ + KeyValues* pkvData = pKVWeapon->FindKey("CustomData"); + if (pkvData) + { + m_flDamage = pkvData->GetFloat("damage"); + m_flNPCDamage = pkvData->GetFloat("damage_npc", m_flDamage); + m_flMeleeRange = pkvData->GetFloat("range", 70.f); + m_flRefireRate = pkvData->GetFloat("rate", 0.7f); + + const char* pszDamageClass = pkvData->GetString("damage_type", nullptr); + if (pszDamageClass) + { + for (byte i = 0; i < ARRAYSIZE(g_ppszDamageClasses); i++) + { + if (V_stricmp(pszDamageClass, g_ppszDamageClasses[i]) == 0) + { + m_nDamageClass = i; + break; + } + } + } + return true; + } + + return false; +} + +void CHLCustomWeaponMelee::InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript) +{ + Q_FileBase(pszWeaponScript, m_iszWeaponScriptName.GetForModify(), 128); + V_memcpy(&m_CustomData, pData, sizeof(HL2CustomMeleeData_t)); +} acttable_t CHLCustomWeaponMelee::m_acttable[] = { @@ -165,7 +206,6 @@ IMPLEMENT_ACTTABLE(CHLCustomWeaponMelee); CHLCustomWeaponMelee::CHLCustomWeaponMelee() { - m_nDamageClass = 0; } //----------------------------------------------------------------------------- @@ -176,9 +216,9 @@ CHLCustomWeaponMelee::CHLCustomWeaponMelee() float CHLCustomWeaponMelee::GetDamageForActivity(Activity hitActivity) { if ((GetOwner() != NULL) && (GetOwner()->IsPlayer())) - return m_flDamage; + return m_CustomData.m_flDamage; - return m_flNPCDamage; + return m_CustomData.m_flNPCDamage; } //----------------------------------------------------------------------------- @@ -280,7 +320,7 @@ void CHLCustomWeaponMelee::HandleAnimEventMeleeHit(animevent_t* pEvent, CBaseCom Vector vecEnd; VectorMA(pOperator->Weapon_ShootPosition(), 50, vecDirection, vecEnd); CBaseEntity* pHurt = pOperator->CheckTraceHullAttack(pOperator->Weapon_ShootPosition(), vecEnd, - Vector(-16, -16, -16), Vector(36, 36, 36), m_flNPCDamage, GetDamageType(), 0.75); + Vector(-16, -16, -16), Vector(36, 36, 36), m_CustomData.m_flNPCDamage, GetDamageType(), 0.75); // did I hit someone? if (pHurt) @@ -317,36 +357,6 @@ void CHLCustomWeaponMelee::Operator_HandleAnimEvent(animevent_t* pEvent, CBaseCo } } -void CHLCustomWeaponMelee::ParseCustomFromWeaponFile(const char* pFileName) -{ - Q_FileBase(pFileName, m_iszWeaponScriptName.GetForModify(), 128); - KeyValuesAD pKVWeapon("WeaponData"); - if (pKVWeapon->LoadFromFile(filesystem, pFileName, "GAME")) - { - KeyValues* pkvData = pKVWeapon->FindKey("CustomData"); - if (pkvData) - { - m_flDamage = pkvData->GetFloat("damage"); - m_flNPCDamage = pkvData->GetFloat("damage_npc", m_flDamage); - m_flMeleeRange = pkvData->GetFloat("range", 70.f); - m_flRefireRate = pkvData->GetFloat("rate", 0.7f); - - const char* pszDamageClass = pkvData->GetString("damage_type", nullptr); - if (pszDamageClass) - { - for (byte i = 0; i < ARRAYSIZE(g_ppszDamageClasses); i++) - { - if (V_stricmp(pszDamageClass, g_ppszDamageClasses[i]) == 0) - { - m_nDamageClass = i; - break; - } - } - } - } - } -} - //-------------------------------------------------------------------------- // // Custom ranged weapon @@ -361,7 +371,7 @@ public: DECLARE_DATADESC(); CHLCustomWeaponGun(); - virtual void ParseCustomFromWeaponFile(const char* pFileName); + virtual void InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript); const char* GetWeaponScriptName() { return m_iszWeaponScriptName.Get(); } // Weapon behaviour @@ -371,15 +381,15 @@ public: // Bullet launch information virtual const Vector& GetBulletSpread(void); - virtual float GetFireRate(void) { return m_flFireRate; } - virtual int GetMinBurst() { return m_nMinBurst; } - virtual int GetMaxBurst() { return m_nMaxBurst; } - virtual float GetMinRestTime() { return m_RestInterval.start; } - virtual float GetMaxRestTime() { return m_RestInterval.start + m_RestInterval.range; } + virtual float GetFireRate(void) { return m_CustomData.m_flFireRate; } + virtual int GetMinBurst() { return m_CustomData.m_nMinBurst; } + virtual int GetMaxBurst() { return m_CustomData.m_nMaxBurst; } + virtual float GetMinRestTime() { return m_CustomData.m_RestInterval.start; } + virtual float GetMaxRestTime() { return m_CustomData.m_RestInterval.start + m_CustomData.m_RestInterval.range; } // Autoaim virtual float GetMaxAutoAimDeflection() { return 0.99f; } - virtual float WeaponAutoAimScale() { return m_flAutoAimScale; } // allows a weapon to influence the perceived size of the target's autoaim radius. + virtual float WeaponAutoAimScale() { return m_CustomData.m_flAutoAimScale; } // allows a weapon to influence the perceived size of the target's autoaim radius. virtual void AddViewKick(void); int WeaponSoundRealtime(WeaponSound_t shoot_type); @@ -409,35 +419,54 @@ private: void CheckZoomToggle(void); void ToggleZoom(void); +public: + typedef struct Data_s + { + float m_flFireRate; + int m_nMinBurst; + int m_nMaxBurst; + interval_t m_RestInterval; + + float m_flAutoAimScale; + + Vector m_vPlayerSpread; + Vector m_vAllySpread; + Vector m_vNPCSpread; + int m_nBulletsPerShot; // For shotguns + + // Viewkick + float m_flMaxVerticalKick; + float m_flSlideLimit; + interval_t m_VerticalPunchRange; + + int m_nActTableIndex; + + bool m_bUseRecoilAnims; + bool m_bFullAuto; // True for machine gun, false for semi-auto + bool m_bNextAttackFromSequence; + bool m_bUsePumpAnimation; + bool m_bHasSecondaryFire; + bool m_bHasZoom; + bool m_bZoomDuringReload; + } Data_t; + + struct Cache_s : public Data_s + { + bool m_bFiresUnderwater; // true if this weapon can fire underwater + bool m_bAltFiresUnderwater; // true if this weapon can fire underwater + float m_fMinRange1; // What's the closest this weapon can be used? + float m_fMinRange2; // What's the closest this weapon can be used? + float m_fMaxRange1; // What's the furthest this weapon can be used? + float m_fMaxRange2; // What's the furthest this weapon can be used? + bool m_bReloadsSingly; // True if this weapon reloads 1 round at a time + + bool Parse(KeyValues*); + }; + private: CNetworkString(m_iszWeaponScriptName, 128); - float m_flFireRate; - int m_nMinBurst; - int m_nMaxBurst; - interval_t m_RestInterval; - - float m_flAutoAimScale; - - Vector m_vPlayerSpread; - Vector m_vAllySpread; - Vector m_vNPCSpread; - int m_nBulletsPerShot; // For shotguns - - // Viewkick - float m_flMaxVerticalKick; - float m_flSlideLimit; - interval_t m_VerticalPunchRange; - - int m_nActTableIndex; - - bool m_bUseRecoilAnims; - bool m_bFullAuto; // True for machine gun, false for semi-auto - bool m_bNextAttackFromSequence; - bool m_bUsePumpAnimation; - bool m_bHasSecondaryFire; - bool m_bHasZoom; - bool m_bZoomDuringReload; + Data_t m_CustomData; bool m_bNeedPump; // When emptied completely bool m_bDelayedFire1; // Fire primary when finished reloading @@ -476,28 +505,10 @@ DEFINE_FIELD(m_bInZoom, FIELD_BOOLEAN), DEFINE_FIELD(m_bMustReload, FIELD_BOOLEAN), END_DATADESC(); -DEFINE_CUSTOM_WEAPON_FACTORY(hl2_gun, CHLCustomWeaponGun); +DEFINE_CUSTOM_WEAPON_FACTORY(hl2_gun, CHLCustomWeaponGun, CHLCustomWeaponGun::Cache_s); CHLCustomWeaponGun::CHLCustomWeaponGun() { - m_flFireRate = 0.5f; - m_nMinBurst = 1; - m_nMaxBurst = 1; - m_RestInterval.start = .3f; - m_RestInterval.range = .3f; - - m_flAutoAimScale = 1.f; - m_nBulletsPerShot = 1; - - m_bUseRecoilAnims = false; - m_bFullAuto = false; - m_bNextAttackFromSequence = false; - m_bUsePumpAnimation = false; - m_bHasSecondaryFire = false; - m_bHasZoom = false; - m_bZoomDuringReload = false; - m_bFiresUnderwater = false; - m_bNeedPump = false; m_bDelayedFire1 = false; m_bDelayedFire2 = false; @@ -508,7 +519,7 @@ CHLCustomWeaponGun::CHLCustomWeaponGun() acttable_t* CHLCustomWeaponGun::ActivityList(void) { - switch (m_nActTableIndex) + switch (m_CustomData.m_nActTableIndex) { default: case ACTTABLE_SMG1: @@ -537,7 +548,7 @@ acttable_t* CHLCustomWeaponGun::ActivityList(void) int CHLCustomWeaponGun::ActivityListCount(void) { - switch (m_nActTableIndex) + switch (m_CustomData.m_nActTableIndex) { default: case ACTTABLE_SMG1: @@ -566,7 +577,7 @@ int CHLCustomWeaponGun::ActivityListCount(void) acttable_t* CHLCustomWeaponGun::GetBackupActivityList(void) { - switch (m_nActTableIndex) + switch (m_CustomData.m_nActTableIndex) { default: case ACTTABLE_SMG1: @@ -587,7 +598,7 @@ acttable_t* CHLCustomWeaponGun::GetBackupActivityList(void) int CHLCustomWeaponGun::GetBackupActivityListCount(void) { - switch (m_nActTableIndex) + switch (m_CustomData.m_nActTableIndex) { default: case ACTTABLE_SMG1: @@ -627,7 +638,7 @@ void ReadIntervalInt(const char* pString, int &iMin, int &iMax) } } -void CHLCustomWeaponGun::ParseCustomFromWeaponFile(const char* pFileName) +bool CHLCustomWeaponGun::Cache_s::Parse(KeyValues* pKVWeapon) { static const char* ppszCustomGunAnimTypes[NUM_GUN_ACT_TABLES] = { "smg", @@ -639,80 +650,93 @@ void CHLCustomWeaponGun::ParseCustomFromWeaponFile(const char* pFileName) "annabelle", }; - Q_FileBase(pFileName, m_iszWeaponScriptName.GetForModify(), 128); - KeyValuesAD pKVWeapon("WeaponData"); - if (pKVWeapon->LoadFromFile(filesystem, pFileName, "GAME")) + KeyValues* pkvData = pKVWeapon->FindKey("CustomData"); + if (pkvData) { - KeyValues* pkvData = pKVWeapon->FindKey("CustomData"); - if (pkvData) + m_flFireRate = pkvData->GetFloat("fire_rate", 0.5f); + ReadIntervalInt(pkvData->GetString("npc_burst", "1"), m_nMinBurst, m_nMaxBurst); + m_RestInterval = ReadInterval(pkvData->GetString("npc_rest_time", "0.3,0.6")); + m_flAutoAimScale = pkvData->GetFloat("autoaim_scale", 1.f); + m_bFullAuto = pkvData->GetBool("auto_fire"); + m_nBulletsPerShot = pkvData->GetInt("bullets", 1); + m_bUseRecoilAnims = pkvData->GetBool("recoil_anims", true); + m_bReloadsSingly = pkvData->GetBool("reload_singly"); + m_bFiresUnderwater = pkvData->GetBool("fires_underwater"); + m_bHasZoom = pkvData->GetBool("zoom_enable"); + m_bZoomDuringReload = m_bHasZoom && pkvData->GetBool("zoom_in_reload"); + + m_fMinRange1 = pkvData->GetFloat("range1_min", 65.f); + m_fMinRange2 = pkvData->GetFloat("range2_min", 65.f); + m_fMaxRange1 = pkvData->GetFloat("range1_max", 1024.f); + m_fMaxRange2 = pkvData->GetFloat("range2_max", 1024.f); + + if (m_bFullAuto) { - m_flFireRate = pkvData->GetFloat("fire_rate", 0.5f); - ReadIntervalInt(pkvData->GetString("npc_burst", "1"), m_nMinBurst, m_nMaxBurst); - m_RestInterval = ReadInterval(pkvData->GetString("npc_rest_time", "0.3,0.6")); - m_flAutoAimScale = pkvData->GetFloat("autoaim_scale", 1.f); - m_bFullAuto = pkvData->GetBool("auto_fire"); - m_nBulletsPerShot = pkvData->GetInt("bullets", 1); - m_bUseRecoilAnims = pkvData->GetBool("recoil_anims", true); - m_bReloadsSingly = pkvData->GetBool("reload_singly"); - m_bFiresUnderwater = pkvData->GetBool("fires_underwater"); - m_bHasZoom = pkvData->GetBool("zoom_enable"); - m_bZoomDuringReload = m_bHasZoom && pkvData->GetBool("zoom_in_reload"); + m_flMaxVerticalKick = pkvData->GetFloat("viewkick_vertical_max", 1.f); + m_flSlideLimit = pkvData->GetFloat("viewkick_slide_limit", 2.f); + } + else + { + m_flSlideLimit = pkvData->GetFloat("viewpunch_side_max", .6f); + m_VerticalPunchRange = ReadInterval(pkvData->GetString("viewpunch_vertical", "0.25,0.5")); - m_fMinRange1 = pkvData->GetFloat("range1_min", 65.f); - m_fMinRange2 = pkvData->GetFloat("range2_min", 65.f); - m_fMaxRange1 = pkvData->GetFloat("range1_max", 1024.f); - m_fMaxRange2 = pkvData->GetFloat("range2_max", 1024.f); + m_bNextAttackFromSequence = pkvData->GetBool("next_attack_time_from_sequence"); + m_bUsePumpAnimation = pkvData->GetBool("use_pump_anim"); + } - if (m_bFullAuto) + // NOTE: The way these are calculated is that each component == sin (degrees/2) + float flSpread = pkvData->GetFloat("spread", 5.f); + float flNPCSpread = pkvData->GetFloat("spread_npc", flSpread); + float flAllySperad = pkvData->GetFloat("spread_ally", flNPCSpread); + m_vPlayerSpread = Vector(sin(DEG2RAD(flSpread * 0.5f))); + m_vNPCSpread = Vector(sin(DEG2RAD(flNPCSpread * 0.5f))); + m_vAllySpread = Vector(sin(DEG2RAD(flAllySperad * 0.5f))); + + const char* pszAnimType = pkvData->GetString("anim_type", nullptr); + if (pszAnimType) + { + for (int i = 0; i < NUM_GUN_ACT_TABLES; i++) { - m_flMaxVerticalKick = pkvData->GetFloat("viewkick_vertical_max", 1.f); - m_flSlideLimit = pkvData->GetFloat("viewkick_slide_limit", 2.f); - } - else - { - m_flSlideLimit = pkvData->GetFloat("viewpunch_side_max", .6f); - m_VerticalPunchRange = ReadInterval(pkvData->GetString("viewpunch_vertical", "0.25,0.5")); - - m_bNextAttackFromSequence = pkvData->GetBool("next_attack_time_from_sequence"); - m_bUsePumpAnimation = pkvData->GetBool("use_pump_anim"); - } - - // NOTE: The way these are calculated is that each component == sin (degrees/2) - float flSpread = pkvData->GetFloat("spread", 5.f); - float flNPCSpread = pkvData->GetFloat("spread_npc", flSpread); - float flAllySperad = pkvData->GetFloat("spread_ally", flNPCSpread); - m_vPlayerSpread = Vector(sin(DEG2RAD(flSpread * 0.5f))); - m_vNPCSpread = Vector(sin(DEG2RAD(flNPCSpread * 0.5f))); - m_vAllySpread = Vector(sin(DEG2RAD(flAllySperad * 0.5f))); - - const char* pszAnimType = pkvData->GetString("anim_type", nullptr); - if (pszAnimType) - { - for (int i = 0; i < NUM_GUN_ACT_TABLES; i++) + if (V_stricmp(pszAnimType, ppszCustomGunAnimTypes[i]) == 0) { - if (V_stricmp(pszAnimType, ppszCustomGunAnimTypes[i]) == 0) - { - m_nActTableIndex = i; - break; - } + m_nActTableIndex = i; + break; } } } + + return true; } + + return false; +} + +void CHLCustomWeaponGun::InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript) +{ + Q_FileBase(pszWeaponScript, m_iszWeaponScriptName.GetForModify(), 128); + const auto* pCache = static_cast (pData); + m_CustomData = *pCache; + m_bFiresUnderwater = pCache->m_bFiresUnderwater; + m_bAltFiresUnderwater = pCache->m_bAltFiresUnderwater; + m_fMinRange1 = pCache->m_fMinRange1; + m_fMinRange2 = pCache->m_fMinRange2; + m_fMaxRange1 = pCache->m_fMaxRange1; + m_fMaxRange2 = pCache->m_fMaxRange2; + m_bReloadsSingly = pCache->m_bReloadsSingly; } const Vector& CHLCustomWeaponGun::GetBulletSpread() { if (!GetOwner() || !GetOwner()->IsNPC()) - return m_vPlayerSpread; + return m_CustomData.m_vPlayerSpread; if (GetOwner()->MyNPCPointer()->IsPlayerAlly()) { // 357 allies should be cooler - return m_vAllySpread; + return m_CustomData.m_vAllySpread; } - return m_vNPCSpread; + return m_CustomData.m_vNPCSpread; } void CHLCustomWeaponGun::AddViewKick(void) @@ -723,7 +747,7 @@ void CHLCustomWeaponGun::AddViewKick(void) if (!pPlayer) return; - if (m_bFullAuto) + if (m_CustomData.m_bFullAuto) { float flDuration = m_fFireDuration; @@ -736,13 +760,13 @@ void CHLCustomWeaponGun::AddViewKick(void) flDuration = MIN(flDuration, 0.75f); } - CHLMachineGun::DoMachineGunKick(pPlayer, 0.5f, m_flMaxVerticalKick, flDuration, m_flSlideLimit); + CHLMachineGun::DoMachineGunKick(pPlayer, 0.5f, m_CustomData.m_flMaxVerticalKick, flDuration, m_CustomData.m_flSlideLimit); } else { QAngle viewPunch; - viewPunch.x = RandomInterval(m_VerticalPunchRange); - viewPunch.y = RandomFloat(-m_flSlideLimit, m_flSlideLimit); + viewPunch.x = RandomInterval(m_CustomData.m_VerticalPunchRange); + viewPunch.y = RandomFloat(-m_CustomData.m_flSlideLimit, m_CustomData.m_flSlideLimit); viewPunch.z = 0.0f; //Add it to the view punch @@ -755,13 +779,13 @@ void CHLCustomWeaponGun::AddViewKick(void) //----------------------------------------------------------------------------- void CHLCustomWeaponGun::CheckZoomToggle(void) { - if (!m_bHasZoom) + if (!m_CustomData.m_bHasZoom) return; CBasePlayer* pPlayer = ToBasePlayer(GetOwner()); int iButtonsTest = IN_ATTACK3; - if (!m_bHasSecondaryFire) + if (!m_CustomData.m_bHasSecondaryFire) iButtonsTest |= IN_ATTACK2; if (pPlayer->m_afButtonPressed & iButtonsTest) @@ -819,7 +843,7 @@ bool CHLCustomWeaponGun::StartReload(void) //NOTENOTE: This is kinda lame because the player doesn't get strong feedback on when the reload has finished, // without the pump. Technically, it's incorrect, but it's good for feedback... - if (m_bUsePumpAnimation && m_iClip1 <= 0) + if (m_CustomData.m_bUsePumpAnimation && m_iClip1 <= 0) { m_bNeedPump = true; } @@ -844,7 +868,7 @@ bool CHLCustomWeaponGun::StartReload(void) } #endif - if (m_bInZoom && !m_bZoomDuringReload) + if (m_bInZoom && !m_CustomData.m_bZoomDuringReload) { ToggleZoom(); } @@ -897,7 +921,7 @@ bool CHLCustomWeaponGun::Reload(void) } else if (BaseClass::Reload()) { - if (m_bInZoom && !m_bZoomDuringReload) + if (m_bInZoom && !m_CustomData.m_bZoomDuringReload) { ToggleZoom(); } @@ -1032,7 +1056,7 @@ void CHLCustomWeaponGun::ItemBusyFrame(void) { BaseClass::ItemBusyFrame(); - if (m_bZoomDuringReload) + if (m_CustomData.m_bZoomDuringReload) CheckZoomToggle(); } @@ -1050,7 +1074,7 @@ void CHLCustomWeaponGun::ItemPostFrame(void) UpdateAutoFire(); - if (m_bZoomDuringReload || !m_bInReload) + if (m_CustomData.m_bZoomDuringReload || !m_bInReload) CheckZoomToggle(); if (m_bReloadsSingly) @@ -1067,7 +1091,7 @@ void CHLCustomWeaponGun::ItemPostFrame(void) m_bDelayedFire1 = true; } // If I'm secondary firing and have one round stop reloading and fire - else if (m_bHasSecondaryFire && (pOwner->m_nButtons & IN_ATTACK2) && (m_iClip1 >= 2)) + else if (m_CustomData.m_bHasSecondaryFire && (pOwner->m_nButtons & IN_ATTACK2) && (m_iClip1 >= 2)) { m_bInReload = false; m_bNeedPump = false; @@ -1106,7 +1130,7 @@ void CHLCustomWeaponGun::ItemPostFrame(void) CheckReload(); } - if (m_bUsePumpAnimation && (m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime)) + if (m_CustomData.m_bUsePumpAnimation && (m_bNeedPump) && (m_flNextPrimaryAttack <= gpGlobals->curtime)) { m_fFireDuration = 0.f; Pump(); @@ -1121,7 +1145,7 @@ void CHLCustomWeaponGun::ItemPostFrame(void) bool bFired = false; // Secondary attack has priority - if (m_bHasSecondaryFire && !m_bMustReload && (m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime)) + if (m_CustomData.m_bHasSecondaryFire && !m_bMustReload && (m_bDelayedFire2 || pOwner->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime)) { m_bDelayedFire2 = false; @@ -1259,7 +1283,7 @@ void CHLCustomWeaponGun::PrimaryAttack() if ((UsesClipsForAmmo1() && m_iClip1 == 0) || (!UsesClipsForAmmo1() && !pPlayer->GetAmmoCount(m_iPrimaryAmmoType))) return; - if (m_bFullAuto) + if (m_CustomData.m_bFullAuto) { m_nShotsFired++; @@ -1288,7 +1312,7 @@ void CHLCustomWeaponGun::PrimaryAttack() // Fire the bullets FireBulletsInfo_t info; - info.m_iShots = iBulletsToFire * m_nBulletsPerShot; + info.m_iShots = iBulletsToFire * m_CustomData.m_nBulletsPerShot; info.m_vecSrc = pPlayer->Weapon_ShootPosition(); info.m_vecDirShooting = pPlayer->GetAutoaimVector(AUTOAIM_SCALE_DEFAULT); info.m_vecSpread = pPlayer->GetAttackSpread(this); @@ -1296,20 +1320,22 @@ void CHLCustomWeaponGun::PrimaryAttack() info.m_iAmmoType = m_iPrimaryAmmoType; info.m_iTracerFreq = 2; FireBullets(info); + + SendWeaponAnim(GetPrimaryAttackActivity()); } else { - if (!m_bNextAttackFromSequence && !m_bUsePumpAnimation && !(pPlayer->m_afButtonPressed & IN_ATTACK)) + if (!m_CustomData.m_bNextAttackFromSequence && !m_CustomData.m_bUsePumpAnimation && !(pPlayer->m_afButtonPressed & IN_ATTACK)) return; m_nShotsFired++; // MUST call sound before removing a round from the clip of a CMachineGun WeaponSound(SINGLE); - pPlayer->DoMuzzleFlash(); + SendWeaponAnim(GetPrimaryAttackActivity()); - m_flNextPrimaryAttack = gpGlobals->curtime + ((m_bNextAttackFromSequence || m_bUsePumpAnimation) ? GetViewModelSequenceDuration() : GetFireRate()); + m_flNextPrimaryAttack = gpGlobals->curtime + ((m_CustomData.m_bNextAttackFromSequence || m_CustomData.m_bUsePumpAnimation) ? GetViewModelSequenceDuration() : GetFireRate()); m_iClip1 -= 1; Vector vecSrc = pPlayer->Weapon_ShootPosition(); @@ -1318,9 +1344,9 @@ void CHLCustomWeaponGun::PrimaryAttack() pPlayer->SetMuzzleFlashTime(gpGlobals->curtime + 1.0); // Fire the bullets, and force the first shot to be perfectly accuracy - pPlayer->FireBullets(m_nBulletsPerShot, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, (m_nBulletsPerShot > 1), true); + pPlayer->FireBullets(m_CustomData.m_nBulletsPerShot, vecSrc, vecAiming, GetBulletSpread(), MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 0, -1, -1, 0, NULL, (m_CustomData.m_nBulletsPerShot > 1), true); - if (m_bUsePumpAnimation && m_iClip1) + if (m_CustomData.m_bUsePumpAnimation && m_iClip1) { // pump so long as some rounds are left. m_bNeedPump = true; @@ -1340,7 +1366,6 @@ void CHLCustomWeaponGun::PrimaryAttack() pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); } - SendWeaponAnim(GetPrimaryAttackActivity()); pPlayer->SetAnimation(PLAYER_ATTACK1); // Register a muzzleflash for the AI @@ -1353,7 +1378,7 @@ void CHLCustomWeaponGun::PrimaryAttack() //----------------------------------------------------------------------------- Activity CHLCustomWeaponGun::GetPrimaryAttackActivity(void) { - if (!m_bUseRecoilAnims || m_nShotsFired < 2) + if (!m_CustomData.m_bUseRecoilAnims || m_nShotsFired < 2) return ACT_VM_PRIMARYATTACK; if (m_nShotsFired < 3) @@ -1423,18 +1448,18 @@ void CHLCustomWeaponGun::FireNPCPrimaryAttack(CBaseCombatCharacter* pOperator, b CSoundEnt::InsertSound(SOUND_COMBAT | SOUND_CONTEXT_GUNFIRE, pOperator->GetAbsOrigin(), SOUNDENT_VOLUME_MACHINEGUN, 0.2f, pOperator, SOUNDENT_CHANNEL_WEAPON, pOperator->GetEnemy()); - const Vector& vecSpread = (bUseWeaponAngles || m_nBulletsPerShot > 1) ? GetBulletSpread() : VECTOR_CONE_PRECALCULATED; - if (m_bFullAuto) + const Vector& vecSpread = (bUseWeaponAngles || m_CustomData.m_nBulletsPerShot > 1) ? GetBulletSpread() : VECTOR_CONE_PRECALCULATED; + if (m_CustomData.m_bFullAuto) { int nShots = WeaponSoundRealtime(SINGLE_NPC); - pOperator->FireBullets(nShots * m_nBulletsPerShot, vecShootOrigin, vecShootDir, vecSpread, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2, entindex(), iMuzzle); + pOperator->FireBullets(nShots * m_CustomData.m_nBulletsPerShot, vecShootOrigin, vecShootDir, vecSpread, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2, entindex(), iMuzzle); pOperator->DoMuzzleFlash(); m_iClip1 = m_iClip1 - nShots; } else { WeaponSound(SINGLE_NPC); - pOperator->FireBullets(m_nBulletsPerShot, vecShootOrigin, vecShootDir, vecSpread, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2, entindex(), iMuzzle); + pOperator->FireBullets(m_CustomData.m_nBulletsPerShot, vecShootOrigin, vecShootDir, vecSpread, MAX_TRACE_LENGTH, m_iPrimaryAmmoType, 2, entindex(), iMuzzle); pOperator->DoMuzzleFlash(); m_iClip1 = m_iClip1 - 1; } diff --git a/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp b/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp index 10553de5..a4337105 100644 --- a/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp +++ b/sp/src/game/shared/mapbase/weapon_custom_scripted.cpp @@ -576,15 +576,22 @@ int CWeaponCustomScripted::WeaponMeleeAttack2Condition( float flDot, float flDis return BaseClass::WeaponMeleeAttack2Condition( flDot, flDist ); } -DEFINE_CUSTOM_WEAPON_FACTORY(vscript, CWeaponCustomScripted); -void CWeaponCustomScripted::ParseCustomFromWeaponFile(const char* pFileName) +struct VScriptWeaponCustomData_s { - Q_FileBase(pFileName, m_iszWeaponScriptName.GetForModify(), 256); - KeyValuesAD pKVWeapon("WeaponData"); - if (pKVWeapon->LoadFromFile(filesystem, pFileName, "GAME")) + char cScripts[256]; + + bool Parse(KeyValues* pKVWeapon) { - Q_strncpy(m_iszClientScripts.GetForModify(), pKVWeapon->GetString("vscript_file"), 256); + Q_strncpy(cScripts, pKVWeapon->GetString("vscript_file"), 256); + return true; } +}; + +DEFINE_CUSTOM_WEAPON_FACTORY(vscript, CWeaponCustomScripted, VScriptWeaponCustomData_s); +void CWeaponCustomScripted::InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript) +{ + Q_FileBase(pszWeaponScript, m_iszWeaponScriptName.GetForModify(), 256); + Q_strncpy(m_iszClientScripts.GetForModify(), static_cast (pData)->cScripts, 256); } extern ConVar sv_script_think_interval; diff --git a/sp/src/game/shared/mapbase/weapon_custom_scripted.h b/sp/src/game/shared/mapbase/weapon_custom_scripted.h index 8cc05cd3..c227e35c 100644 --- a/sp/src/game/shared/mapbase/weapon_custom_scripted.h +++ b/sp/src/game/shared/mapbase/weapon_custom_scripted.h @@ -115,7 +115,7 @@ public: int WeaponMeleeAttack2Condition( float flDot, float flDist ); // Inherited via ICustomWeapon - virtual void ParseCustomFromWeaponFile(const char* pFileName) override; + virtual void InitCustomWeaponFromData(const void* pData, const char* pszWeaponScript); #else void OnDataChanged(DataUpdateType_t type); #endif