Skip to content

Commit

Permalink
[Z:R] Implement Hitgroup Knockback config, Zombie Class specific knoc…
Browse files Browse the repository at this point in the history
…kback config. (#232)

* update 2 decimal float for weapon knockback and hitgroup knockback config

* update PackageScript, clean up checking hitgroup logic

* add knockbback config for zombie class config

* Simplify config, switch to new zclass storage & smart pointers

---------

Co-authored-by: Vauff <[email protected]>
  • Loading branch information
nuclearsilo583 and Vauff authored Dec 10, 2024
1 parent 153ae27 commit ac5bb90
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 7 deletions.
1 change: 1 addition & 0 deletions PackageScript
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ builder.AddCopy(os.path.join(builder.sourcePath, 'cfg', MMSPlugin.plugin_name, '
builder.AddCopy(os.path.join(builder.sourcePath, 'cfg', MMSPlugin.plugin_name, 'maps', 'de_somemap.cfg'), mapcfg_folder)
builder.AddCopy(os.path.join(builder.sourcePath, 'configs', 'zr', 'playerclass.jsonc.example'), zr_folder)
builder.AddCopy(os.path.join(builder.sourcePath, 'configs', 'zr', 'weapons.cfg.example'), zr_folder)
builder.AddCopy(os.path.join(builder.sourcePath, 'configs', 'zr', 'hitgroups.cfg.example'), zr_folder)
builder.AddCopy(os.path.join('gamedata', 'cs2fixes.games.txt'), gamedata_folder)

# Add CS2Fixes-specific compiled asset files
Expand Down
47 changes: 47 additions & 0 deletions configs/zr/hitgroups.cfg.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Attribute: Values: Description:
// ----------------------------------------------------------------------------
// knockback decimal The knockback multiplier for this hitgroup.

"Hitgroups"
{
"Generic"
{
"knockback" "1.0"
}
"Head"
{
"knockback" "1.0"
}
"Chest"
{
"knockback" "1.0"
}
"Stomach"
{
"knockback" "1.0"
}
"LeftArm"
{
"knockback" "1.0"
}
"RightArm"
{
"knockback" "1.0"
}
"LeftLeg"
{
"knockback" "1.0"
}
"RightLeg"
{
"knockback" "1.0"
}
"Neck"
{
"knockback" "1.0"
}
"Gear"
{
"knockback" "1.0"
}
}
1 change: 1 addition & 0 deletions configs/zr/playerclass.jsonc.example
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
"scale": 1.05,
"speed": 1.0,
"gravity": 1.0,
"knockback": 1.0,
"admin_flag": "",
"health_regen_count": 250,
"health_regen_interval": 5.0
Expand Down
4 changes: 4 additions & 0 deletions src/cs2fixes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ bool CS2Fixes::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool
g_pUserPreferencesSystem = new CUserPreferencesSystem();
g_pUserPreferencesStorage = new CUserPreferencesREST();
g_pZRWeaponConfig = new ZRWeaponConfig();
g_pZRHitgroupConfig = new ZRHitgroupConfig();
g_pEntityListener = new CEntityListener();
g_pIdleSystem = new CIdleSystem();
g_pPanoramaVoteHandler = new CPanoramaVoteHandler();
Expand Down Expand Up @@ -412,6 +413,9 @@ bool CS2Fixes::Unload(char *error, size_t maxlen)

if (g_pZRWeaponConfig)
delete g_pZRWeaponConfig;

if (g_pZRHitgroupConfig)
delete g_pZRHitgroupConfig;

if (g_pUserPreferencesSystem)
delete g_pUserPreferencesSystem;
Expand Down
110 changes: 104 additions & 6 deletions src/zombiereborn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ static CHandle<CTeam> g_hTeamT;

CZRPlayerClassManager* g_pZRPlayerClassManager = nullptr;
ZRWeaponConfig *g_pZRWeaponConfig = nullptr;
ZRHitgroupConfig *g_pZRHitgroupConfig = nullptr;

bool g_bEnableZR = false;
static float g_flMaxZteleDistance = 150.0f;
Expand Down Expand Up @@ -314,7 +315,8 @@ ZRHumanClass::ZRHumanClass(ordered_json jsonKeys, std::string szClassname) : ZRC
ZRZombieClass::ZRZombieClass(ordered_json jsonKeys, std::string szClassname) :
ZRClass(jsonKeys, szClassname, CS_TEAM_T),
iHealthRegenCount(jsonKeys.value("health_regen_count", 0)),
flHealthRegenInterval(jsonKeys.value("health_regen_interval", 0)){};
flHealthRegenInterval(jsonKeys.value("health_regen_interval", 0)),
flKnockback(jsonKeys.value("knockback", 1.0)){};

void ZRZombieClass::Override(ordered_json jsonKeys, std::string szClassname)
{
Expand All @@ -323,6 +325,8 @@ void ZRZombieClass::Override(ordered_json jsonKeys, std::string szClassname)
iHealthRegenCount = jsonKeys["health_regen_count"].get<int>();
if (jsonKeys.contains("health_regen_interval"))
flHealthRegenInterval = jsonKeys["health_regen_interval"].get<float>();
if (jsonKeys.contains("knockback"))
flKnockback = jsonKeys["knockback"].get<float>();
}

bool ZRClass::IsApplicableTo(CCSPlayerController *pController)
Expand Down Expand Up @@ -450,6 +454,11 @@ void CZRPlayerClassManager::LoadPlayerClass()
Panic("%s has unspecified key: gravity\n", szClassName.c_str());
bMissingKey = true;
}
/*if (!jsonClass.contains("knockback"))
{
Warning("%s has unspecified key: knockback\n", szClassName.c_str());
bMissingKey = true;
}*/
if (!jsonClass.contains("admin_flag"))
{
Panic("%s has unspecified key: admin_flag\n", szClassName.c_str());
Expand Down Expand Up @@ -824,6 +833,7 @@ void ZR_OnLevelInit()
});

g_pZRWeaponConfig->LoadWeaponConfig();
g_pZRHitgroupConfig->LoadHitgroupConfig();
SetupCTeams();
}

Expand All @@ -844,7 +854,7 @@ void ZRWeaponConfig::LoadWeaponConfig()
{
const char *pszWeaponName = pKey->GetName();
bool bEnabled = pKey->GetBool("enabled", false);
float flKnockback= pKey->GetFloat("knockback", 0.0f);
float flKnockback = pKey->GetFloat("knockback", 1.0f);
Message("%s knockback: %f\n", pszWeaponName, flKnockback);
ZRWeapon *weapon = new ZRWeapon;
if (!bEnabled)
Expand All @@ -867,6 +877,76 @@ ZRWeapon* ZRWeaponConfig::FindWeapon(const char *pszWeaponName)
return nullptr;
}

void ZRHitgroupConfig::LoadHitgroupConfig()
{
m_HitgroupMap.Purge();
KeyValues* pKV = new KeyValues("Hitgroups");
KeyValues::AutoDelete autoDelete(pKV);

const char *pszPath = "addons/cs2fixes/configs/zr/hitgroups.cfg";

if (!pKV->LoadFromFile(g_pFullFileSystem, pszPath))
{
Warning("Failed to load %s\n", pszPath);
return;
}
for (KeyValues* pKey = pKV->GetFirstSubKey(); pKey; pKey = pKey->GetNextKey())
{
const char *pszHitgroupName = pKey->GetName();
float flKnockback= pKey->GetFloat("knockback", 1.0f);
int iIndex = -1;

if (!V_strcasecmp(pszHitgroupName, "Generic"))
iIndex = 0;
else if (!V_strcasecmp(pszHitgroupName, "Head"))
iIndex = 1;
else if (!V_strcasecmp(pszHitgroupName, "Chest"))
iIndex = 2;
else if (!V_strcasecmp(pszHitgroupName, "Stomach"))
iIndex = 3;
else if (!V_strcasecmp(pszHitgroupName, "LeftArm"))
iIndex = 4;
else if (!V_strcasecmp(pszHitgroupName, "RightArm"))
iIndex = 5;
else if (!V_strcasecmp(pszHitgroupName, "LeftLeg"))
iIndex = 6;
else if (!V_strcasecmp(pszHitgroupName, "RightLeg"))
iIndex = 7;
else if (!V_strcasecmp(pszHitgroupName, "Neck"))
iIndex = 8;
else if (!V_strcasecmp(pszHitgroupName, "Gear"))
iIndex = 10;

if (iIndex == -1)
{
Panic("Failed to load hitgroup %s, invalid name!", pszHitgroupName);
continue;
}

std::shared_ptr<ZRHitgroup> hitGroup = std::make_shared<ZRHitgroup>();

hitGroup->flKnockback = flKnockback;
m_HitgroupMap.Insert(iIndex, hitGroup);
Message("Loaded hitgroup %s at index %d with %f knockback\n", pszHitgroupName, iIndex, hitGroup->flKnockback);
}

return;
}

std::shared_ptr<ZRHitgroup> ZRHitgroupConfig::FindHitgroupIndex(int iIndex)
{
uint16 index = m_HitgroupMap.Find(iIndex);
//Message("We are finding hitgroup index with index: %d and index is: %d\n", iIndex, index);

if (m_HitgroupMap.IsValidIndex(index))
{
//Message("We found valid index with (m_HitgroupMap[index]): %d\n", m_HitgroupMap[index]);
return m_HitgroupMap[index];
}

return nullptr;
}

void ZR_RespawnAll()
{
for (int i = 0; i < gpGlobals->maxClients; i++)
Expand Down Expand Up @@ -997,17 +1077,22 @@ void ZR_OnPlayerSpawn(CCSPlayerController* pController)
});
}

void ZR_ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, const char *szWeapon)
void ZR_ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, const char *szWeapon, int hitgroup, float classknockback)
{
ZRWeapon *pWeapon = g_pZRWeaponConfig->FindWeapon(szWeapon);
std::shared_ptr<ZRHitgroup> pHitgroup = g_pZRHitgroupConfig->FindHitgroupIndex(hitgroup);
// player shouldn't be able to pick up that weapon in the first place, but just in case
if (!pWeapon)
return;
float flWeaponKnockbackScale = pWeapon->flKnockback;

float flHitgroupKnockbackScale = 1.0f;

if (pHitgroup)
flHitgroupKnockbackScale = pHitgroup->flKnockback;

Vector vecKnockback;
AngleVectors(pHuman->m_angEyeAngles(), &vecKnockback);
vecKnockback *= (iDamage * g_flKnockbackScale * flWeaponKnockbackScale);
vecKnockback *= (iDamage * g_flKnockbackScale * flWeaponKnockbackScale * flHitgroupKnockbackScale * classknockback);
pVictim->m_vecAbsVelocity = pVictim->m_vecAbsVelocity() + vecKnockback;
}

Expand Down Expand Up @@ -1496,13 +1581,26 @@ void ZR_OnPlayerHurt(IGameEvent* pEvent)
CCSPlayerController *pVictimController = (CCSPlayerController*)pEvent->GetPlayerController("userid");
const char* szWeapon = pEvent->GetString("weapon");
int iDmgHealth = pEvent->GetInt("dmg_health");
int iHitGroup = pEvent->GetInt("hitgroup");

// grenade and molotov knockbacks are handled by TakeDamage detours
if (!pAttackerController || !pVictimController || !V_strncmp(szWeapon, "inferno", 7) || !V_strncmp(szWeapon, "hegrenade", 9))
return;

if (pAttackerController->m_iTeamNum() == CS_TEAM_CT && pVictimController->m_iTeamNum() == CS_TEAM_T)
ZR_ApplyKnockback((CCSPlayerPawn*)pAttackerController->GetPawn(), (CCSPlayerPawn*)pVictimController->GetPawn(), iDmgHealth, szWeapon);
{
float flClassKnockback = 1.0f;

if (pVictimController->GetZEPlayer())
{
std::shared_ptr<ZRClass> activeClass = pVictimController->GetZEPlayer()->GetActiveZRClass();

if (activeClass && activeClass->iTeam == CS_TEAM_T)
flClassKnockback = static_pointer_cast<ZRZombieClass>(activeClass)->flKnockback;
}

ZR_ApplyKnockback((CCSPlayerPawn*)pAttackerController->GetPawn(), (CCSPlayerPawn*)pVictimController->GetPawn(), iDmgHealth, szWeapon, iHitGroup, flClassKnockback);
}
}

void ZR_OnPlayerDeath(IGameEvent* pEvent)
Expand Down
26 changes: 25 additions & 1 deletion src/zombiereborn.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,12 @@ struct ZRZombieClass : ZRClass
{
int iHealthRegenCount;
float flHealthRegenInterval;
float flKnockback;
ZRZombieClass(std::shared_ptr<ZRZombieClass> pClass) :
ZRClass(pClass, CS_TEAM_T),
iHealthRegenCount(pClass->iHealthRegenCount),
flHealthRegenInterval(pClass->flHealthRegenInterval){};
flHealthRegenInterval(pClass->flHealthRegenInterval),
flKnockback(pClass->flKnockback){};
ZRZombieClass(ordered_json jsonKeys, std::string szClassname);
void PrintInfo()
{
Expand All @@ -173,6 +175,7 @@ struct ZRZombieClass : ZRClass
"\tscale: %f\n"
"\tspeed: %f\n"
"\tgravity: %f\n"
"\tknockback: %f\n"
"\tadmin flag: %d\n"
"\thealth_regen_count: %d\n"
"\thealth_regen_interval: %f\n",
Expand All @@ -183,6 +186,7 @@ struct ZRZombieClass : ZRClass
flScale,
flSpeed,
flGravity,
flKnockback,
iAdminFlag,
iHealthRegenCount,
flHealthRegenInterval);
Expand Down Expand Up @@ -242,6 +246,11 @@ struct ZRWeapon
float flKnockback;
};

struct ZRHitgroup
{
float flKnockback;
};

class ZRWeaponConfig
{
public:
Expand All @@ -255,7 +264,22 @@ class ZRWeaponConfig
CUtlMap<uint32, ZRWeapon*> m_WeaponMap;
};


class ZRHitgroupConfig
{
public:
ZRHitgroupConfig()
{
m_HitgroupMap.SetLessFunc(DefLessFunc(uint32));
};
void LoadHitgroupConfig();
std::shared_ptr<ZRHitgroup> FindHitgroupIndex(int iIndex);
private:
CUtlMap<uint32, std::shared_ptr<ZRHitgroup>> m_HitgroupMap;
};

extern ZRWeaponConfig *g_pZRWeaponConfig;
extern ZRHitgroupConfig *g_pZRHitgroupConfig;
extern CZRPlayerClassManager* g_pZRPlayerClassManager;

extern bool g_bEnableZR;
Expand Down

0 comments on commit ac5bb90

Please sign in to comment.