From 3e8fb4962277a3b5e95e15249eec148e2f4809a1 Mon Sep 17 00:00:00 2001 From: rei-2 <174158077+rei-2@users.noreply.github.com> Date: Mon, 25 Aug 2025 13:01:40 -0400 Subject: [PATCH] fixes --- Amalgam/Amalgam.vcxproj | 1 + Amalgam/Amalgam.vcxproj.filters | 1 + Amalgam/src/Features/CritHack/CritHack.cpp | 24 ++++++++++++++++--- Amalgam/src/Features/CritHack/CritHack.h | 5 ++++ Amalgam/src/Features/Misc/Misc.cpp | 2 +- .../Visuals/SpectatorList/SpectatorList.cpp | 5 ++-- .../CTFWeaponBase_CalcIsAttackCritical.cpp | 1 - ...TFWeaponBase_CanFireRandomCriticalShot.cpp | 20 ++++++++++++++++ .../src/SDK/Definitions/Main/CTFPlayer.cpp | 6 ++--- 9 files changed, 55 insertions(+), 10 deletions(-) create mode 100644 Amalgam/src/Hooks/CTFWeaponBase_CanFireRandomCriticalShot.cpp diff --git a/Amalgam/Amalgam.vcxproj b/Amalgam/Amalgam.vcxproj index 734d6f94..5f746dab 100644 --- a/Amalgam/Amalgam.vcxproj +++ b/Amalgam/Amalgam.vcxproj @@ -990,6 +990,7 @@ + diff --git a/Amalgam/Amalgam.vcxproj.filters b/Amalgam/Amalgam.vcxproj.filters index a19528d6..ef31c983 100644 --- a/Amalgam/Amalgam.vcxproj.filters +++ b/Amalgam/Amalgam.vcxproj.filters @@ -195,6 +195,7 @@ + diff --git a/Amalgam/src/Features/CritHack/CritHack.cpp b/Amalgam/src/Features/CritHack/CritHack.cpp index a0a88397..5eb46ab1 100644 --- a/Amalgam/src/Features/CritHack/CritHack.cpp +++ b/Amalgam/src/Features/CritHack/CritHack.cpp @@ -9,10 +9,12 @@ #define TF_DAMAGE_CRIT_CHANCE_MELEE 0.15f #define TF_DAMAGE_CRIT_DURATION_RAPID 2.0f +#define STATS_SEND_FREQUENCY 1.f + #define SEED_ATTEMPTS 4096 #define BUCKET_ATTEMPTS 1000 -//#define SERVER_CRIT_DATA +#define SERVER_CRIT_DATA int CCritHack::GetCritCommand(CTFWeaponBase* pWeapon, int iCommandNumber, bool bCrit, bool bSafe) { @@ -227,6 +229,16 @@ void CCritHack::UpdateInfo(CTFPlayer* pLocal, CTFWeaponBase* pWeapon) if (auto pResource = H::Entities.GetResource()) { m_iResourceDamage = pResource->m_iDamage(I::EngineClient->GetLocalPlayer()); + /* // more of a proof of concept for resyncing crit damage + if (m_flLastDamageTime < I::GlobalVars->curtime + STATS_SEND_FREQUENCY * 2) + { // attempt to resync damages + m_iRangedDamage = m_iResourceDamage - m_iMeleeDamage; + + float flObservedCritChance = pWeapon->m_flObservedCritChance(); + m_iCritDamage = (TF_DAMAGE_CRIT_MULTIPLIER * flObservedCritChance * m_iResourceDamage) / (1 + 2 * flObservedCritChance); + SDK::Output("Info", std::format("{}, {}", m_iRangedDamage, m_iCritDamage).c_str()); + } + */ m_iDesyncDamage = m_iRangedDamage + m_iMeleeDamage - m_iResourceDamage; } } @@ -278,6 +290,8 @@ void CCritHack::Reset() m_flDamageTilFlip = 0; m_mHealthHistory.clear(); + + //m_flLastDamageTime = 0.f; } @@ -295,11 +309,13 @@ int CCritHack::GetCritRequest(CUserCmd* pCmd, CTFWeaponBase* pWeapon) void CCritHack::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) { - if (!pWeapon || !pLocal->IsAlive() || !I::EngineClient->IsInGame() - || pLocal->IsCritBoosted() || pWeapon->m_flCritTime() > I::GlobalVars->curtime || !WeaponCanCrit(pWeapon)) + if (!pWeapon || !pLocal->IsAlive() || pLocal->IsAGhost() || !I::EngineClient->IsInGame()) return; UpdateInfo(pLocal, pWeapon); + if (pLocal->IsCritBoosted() || pWeapon->m_flCritTime() > I::GlobalVars->curtime || !WeaponCanCrit(pWeapon)) + return; + if (pWeapon->GetWeaponID() == TF_WEAPON_MINIGUN && pCmd->buttons & IN_ATTACK) pCmd->buttons &= ~IN_ATTACK2; @@ -445,6 +461,8 @@ void CCritHack::Event(IGameEvent* pEvent, uint32_t uHash, CTFPlayer* pLocal) } } + //m_flLastDamageTime = I::GlobalVars->curtime; + CTFWeaponBase* pWeapon = nullptr; for (int i = 0; i < MAX_WEAPONS; i++) { diff --git a/Amalgam/src/Features/CritHack/CritHack.h b/Amalgam/src/Features/CritHack/CritHack.h index 9df02984..70403799 100644 --- a/Amalgam/src/Features/CritHack/CritHack.h +++ b/Amalgam/src/Features/CritHack/CritHack.h @@ -52,6 +52,8 @@ private: float m_flCritChance = 0.f; float m_flMultCritChance = 1.f; + //float m_flLastDamageTime = 0.f; + public: void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); void Event(IGameEvent* pEvent, uint32_t uHash, CTFPlayer* pLocal); @@ -60,6 +62,9 @@ public: bool WeaponCanCrit(CTFWeaponBase* pWeapon, bool bWeaponOnly = false); int PredictCmdNum(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); + + float GetCritDamage() { return m_iCritDamage; } + float GetRangedDamage() { return m_iRangedDamage; } }; ADD_FEATURE(CCritHack, CritHack); \ No newline at end of file diff --git a/Amalgam/src/Features/Misc/Misc.cpp b/Amalgam/src/Features/Misc/Misc.cpp index c5ef2fa4..b66dff9f 100644 --- a/Amalgam/src/Features/Misc/Misc.cpp +++ b/Amalgam/src/Features/Misc/Misc.cpp @@ -211,7 +211,7 @@ void CMisc::AntiAFK(CTFPlayer* pLocal, CUserCmd* pCmd) void CMisc::InstantRespawnMVM(CTFPlayer* pLocal) { - if (!Vars::Misc::MannVsMachine::InstantRespawn.Value || !pLocal->IsAlive()) + if (!Vars::Misc::MannVsMachine::InstantRespawn.Value || pLocal->IsAlive()) return; KeyValues* kv = new KeyValues("MVM_Revive_Response"); diff --git a/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.cpp b/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.cpp index d391d40c..4b369591 100644 --- a/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.cpp +++ b/Amalgam/src/Features/Visuals/SpectatorList/SpectatorList.cpp @@ -17,13 +17,14 @@ bool CSpectatorList::GetSpectators(CTFPlayer* pTarget) auto pPlayer = I::ClientEntityList->GetClientEntity(n)->As(); bool bLocal = n == I::EngineClient->GetLocalPlayer(); - if (pResource->m_bValid(n) && pResource->m_iTeam(I::EngineClient->GetLocalPlayer()) != TEAM_SPECTATOR && pResource->m_iTeam(n) == TEAM_SPECTATOR) + if (pResource->m_bValid(n) && !pResource->IsFakePlayer(n) + && pResource->m_iTeam(I::EngineClient->GetLocalPlayer()) != TEAM_SPECTATOR && pResource->m_iTeam(n) == TEAM_SPECTATOR) { m_vSpectators.emplace_back(F::PlayerUtils.GetPlayerName(n, pResource->GetName(n)), "possible", -1.f, false, n); continue; } - if (pTarget->entindex() == n + if (pTarget->entindex() == n || pResource->IsFakePlayer(n) || !pPlayer || !pPlayer->IsPlayer() || pPlayer->IsAlive() || pTarget->IsDormant() != pPlayer->IsDormant() || pResource->m_iTeam(iTarget) != pResource->m_iTeam(n)) diff --git a/Amalgam/src/Hooks/CTFWeaponBase_CalcIsAttackCritical.cpp b/Amalgam/src/Hooks/CTFWeaponBase_CalcIsAttackCritical.cpp index a84a6237..f44b0be2 100644 --- a/Amalgam/src/Hooks/CTFWeaponBase_CalcIsAttackCritical.cpp +++ b/Amalgam/src/Hooks/CTFWeaponBase_CalcIsAttackCritical.cpp @@ -2,7 +2,6 @@ #include "../Features/CritHack/CritHack.h" - MAKE_HOOK(CTFWeaponBase_CalcIsAttackCritical, S::CTFWeaponBase_CalcIsAttackCritical(), void, void* rcx) { diff --git a/Amalgam/src/Hooks/CTFWeaponBase_CanFireRandomCriticalShot.cpp b/Amalgam/src/Hooks/CTFWeaponBase_CanFireRandomCriticalShot.cpp new file mode 100644 index 00000000..cd2b1a8b --- /dev/null +++ b/Amalgam/src/Hooks/CTFWeaponBase_CanFireRandomCriticalShot.cpp @@ -0,0 +1,20 @@ +#include "../SDK/SDK.h" + +#include "../Features/CritHack/CritHack.h" + +MAKE_SIGNATURE(CTFWeaponBase_CanFireRandomCriticalShot, "client.dll", "F3 0F 58 0D ? ? ? ? 0F 2F 89", 0x0); + +MAKE_HOOK(CTFWeaponBase_CanFireRandomCriticalShot, S::CTFWeaponBase_CanFireRandomCriticalShot(), bool, + void* rcx, float flCritChance) +{ // not present on the client so it will always be a crit behind otherwise + int nRandomRangedCritDamage = F::CritHack.GetCritDamage(); + int nTotalDamage = F::CritHack.GetRangedDamage(); + if (!nTotalDamage) + return true; + + auto pWeapon = reinterpret_cast(rcx); + float flNormalizedDamage = nRandomRangedCritDamage / TF_DAMAGE_CRIT_MULTIPLIER; + pWeapon->m_flObservedCritChance() = flNormalizedDamage / (flNormalizedDamage + (nTotalDamage - nRandomRangedCritDamage)); + + return CALL_ORIGINAL(rcx, flCritChance); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/CTFPlayer.cpp b/Amalgam/src/SDK/Definitions/Main/CTFPlayer.cpp index 6cb6cd4e..c0fb3c06 100644 --- a/Amalgam/src/SDK/Definitions/Main/CTFPlayer.cpp +++ b/Amalgam/src/SDK/Definitions/Main/CTFPlayer.cpp @@ -45,7 +45,7 @@ bool CTFPlayer::InCond(ETFCond eCond) switch (eCond / 32) { case 0: - return m_nPlayerCond() & (1 << eCond); + return m_nPlayerCond() & (1 << eCond) || _condition_bits() & (1 << eCond); case 1: return m_nPlayerCondEx() & (1 << (eCond - 32)); case 2: @@ -63,7 +63,7 @@ void CTFPlayer::AddCond(ETFCond eCond) switch (eCond / 32) { case 0: - m_nPlayerCond() |= (1 << eCond); break; + m_nPlayerCond() |= (1 << eCond), _condition_bits() |= (1 << eCond); break; case 1: m_nPlayerCondEx() |= (1 << (eCond - 32)); break; case 2: @@ -80,7 +80,7 @@ void CTFPlayer::RemoveCond(ETFCond eCond) switch (eCond / 32) { case 0: - m_nPlayerCond() &= ~(1 << eCond); break; + m_nPlayerCond() &= ~(1 << eCond), _condition_bits() &= ~(1 << eCond); break; case 1: m_nPlayerCondEx() &= ~(1 << (eCond - 32)); break; case 2: