improve medigun functionality

This commit is contained in:
rei-2
2025-09-23 11:10:53 -04:00
parent aa8eb672b7
commit 2745a8e984
14 changed files with 133 additions and 54 deletions
+1
View File
@@ -992,6 +992,7 @@
<ClCompile Include="src\Hooks\CMaterial_Uncache.cpp" />
<ClCompile Include="src\Hooks\CTFWeaponBase_CanFireRandomCriticalShot.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_GetMinFOV.cpp" />
<ClCompile Include="src\Hooks\CWeaponMedigun_PrimaryAttack.cpp" />
<ClCompile Include="src\Hooks\IEngineTrace_SetTraceEntity.cpp" />
<ClCompile Include="src\Hooks\CNetChannel_SendDatagram.cpp" />
<ClCompile Include="src\Hooks\CNetChannel_SendNetMsg.cpp" />
+1
View File
@@ -197,6 +197,7 @@
<ClCompile Include="src\Hooks\CInput_ValidateUserCmd.cpp" />
<ClCompile Include="src\Hooks\CTFWeaponBase_CanFireRandomCriticalShot.cpp" />
<ClCompile Include="src\Hooks\CTFPlayer_GetMinFOV.cpp" />
<ClCompile Include="src\Hooks\CWeaponMedigun_PrimaryAttack.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\Utils\UtlVector\UtlVector.h" />
-1
View File
@@ -1,7 +1,6 @@
#include <Windows.h>
#include "Core/Core.h"
#include "Utils/CrashLog/CrashLog.h"
#include <format>
DWORD WINAPI MainThread(LPVOID lpParam)
{
@@ -6,6 +6,34 @@
#include "../../Simulation/ProjectileSimulation/ProjectileSimulation.h"
#include "../AimbotProjectile/AimbotProjectile.h"
void CAutoHeal::AutoHeal(CTFPlayer* pLocal, CWeaponMedigun* pWeapon, CUserCmd* pCmd)
{ // manage lagcomp
if (!Vars::Aimbot::Healing::AutoHeal.Value)
return;
auto pTarget = pWeapon->m_hHealingTarget().Get()->As<CTFPlayer>();
if (!pTarget || pCmd->buttons & IN_ATTACK && !(G::LastUserCmd->buttons & IN_ATTACK))
return;
std::vector<TickRecord*> vRecords = {};
if (!F::Backtrack.GetRecords(pTarget, vRecords))
return;
vRecords = F::Backtrack.GetValidRecords(vRecords, pLocal, true);
if (!vRecords.size())
return;
Vec3 vEyePos = pLocal->GetShootPos();
for (auto pRecord : vRecords)
{
Vec3 vCenter = pRecord->m_vOrigin + (pRecord->m_vMins + pRecord->m_vMaxs) / 2;
if (SDK::VisPosWorld(pLocal, pTarget, vEyePos, vCenter))
{
pCmd->tick_count = TIME_TO_TICKS(pRecord->m_flSimTime) + TIME_TO_TICKS(F::Backtrack.GetFakeInterp());
break;
}
}
}
void CAutoHeal::ActivateOnVoice(CTFPlayer* pLocal, CWeaponMedigun* pWeapon, CUserCmd* pCmd)
{
if (!Vars::Aimbot::Healing::ActivateOnVoice.Value)
@@ -603,6 +631,8 @@ void CAutoHeal::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd)
return;
}
AutoHeal(pLocal, pWeapon->As<CWeaponMedigun>(), pCmd);
ActivateOnVoice(pLocal, pWeapon->As<CWeaponMedigun>(), pCmd);
m_mMedicCallers.clear();
@@ -6,6 +6,7 @@
class CAutoHeal
{
private:
void AutoHeal(CTFPlayer* pLocal, CWeaponMedigun* pWeapon, CUserCmd* pCmd);
void ActivateOnVoice(CTFPlayer* pLocal, CWeaponMedigun* pWeapon, CUserCmd* pCmd);
void AutoVaccinator(CTFPlayer* pLocal, CWeaponMedigun* pWeapon, CUserCmd* pCmd);
void GetDangers(CTFPlayer* pTarget, bool bVaccinator, float& flBulletDanger, float& flBlastDanger, float& flFireDanger);
+6 -8
View File
@@ -139,9 +139,8 @@ void CBinds::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
if (G::Unload)
return;
for (auto it = m_vBinds.begin(); it < m_vBinds.end(); it++)
for (auto& tBind : m_vBinds)
{ // don't delay inputs for binds
auto& tBind = *it;
if (tBind.m_iType != BindEnum::Key)
continue;
@@ -162,9 +161,8 @@ void CBinds::Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon)
SetVars(pLocal, pWeapon);
for (auto it = m_vBinds.begin(); it < m_vBinds.end(); it++)
for (auto& tBind : m_vBinds)
{ // clear inputs for binds
auto& tBind = *it;
if (tBind.m_iType != BindEnum::Key)
continue;
@@ -247,11 +245,11 @@ void CBinds::RemoveBind(int iBind, bool bForce)
std::vector<int> vErases = {};
std::function<void(int)> searchBinds = [&](int iIndex)
{
for (auto it = m_vBinds.begin(); it < m_vBinds.end(); it++)
for (int iBind = 0; iBind < m_vBinds.size(); iBind++)
{
int iIndex2 = std::distance(m_vBinds.begin(), it);
if (iIndex == it->m_iParent && iIndex != iIndex2)
searchBinds(iIndex2);
auto& tBind = m_vBinds[iBind];
if (iIndex == tBind.m_iParent && iIndex != iBind)
searchBinds(iBind);
}
vErases.push_back(iIndex);
};
+6 -9
View File
@@ -335,10 +335,9 @@ bool CConfigs::SaveConfig(const std::string& sConfigName, bool bNotify)
{
boost::property_tree::ptree tSub;
for (auto it = F::Binds.m_vBinds.begin(); it != F::Binds.m_vBinds.end(); it++)
for (int iID = 0; iID < F::Binds.m_vBinds.size(); iID++)
{
int iID = std::distance(F::Binds.m_vBinds.begin(), it);
auto& tBind = *it;
auto& tBind = F::Binds.m_vBinds[iID];
boost::property_tree::ptree tChild;
SaveJson(tChild, "Name", tBind.m_sName);
@@ -381,10 +380,9 @@ bool CConfigs::SaveConfig(const std::string& sConfigName, bool bNotify)
{
boost::property_tree::ptree tSub;
for (auto it = F::Groups.m_vGroups.begin(); it != F::Groups.m_vGroups.end(); it++)
for (int iID = 0; iID < F::Groups.m_vGroups.size(); iID++)
{
int iID = std::distance(F::Groups.m_vGroups.begin(), it);
auto& tGroup = *it;
auto& tGroup = F::Groups.m_vGroups[iID];
boost::property_tree::ptree tChild;
SaveJson(tChild, "Name", tGroup.m_sName);
@@ -588,10 +586,9 @@ bool CConfigs::SaveVisual(const std::string& sConfigName, bool bNotify)
{
boost::property_tree::ptree tSub;
for (auto it = F::Groups.m_vGroups.begin(); it != F::Groups.m_vGroups.end(); it++)
for (int iID = 0; iID < F::Groups.m_vGroups.size(); iID++)
{
int iID = std::distance(F::Groups.m_vGroups.begin(), it);
auto& tGroup = *it;
auto& tGroup = F::Groups.m_vGroups[iID];
boost::property_tree::ptree tChild;
SaveJson(tChild, "Name", tGroup.m_sName);
+4 -4
View File
@@ -544,11 +544,11 @@ void CCritHack::StoreHealthHistory(int iIndex, int iHealth, bool bDamage)
MAKE_SIGNATURE(CTFGameStats_FindPlayerStats, "server.dll", "4C 8B C1 48 85 D2 75", 0x0);
MAKE_SIGNATURE(UTIL_PlayerByIndex, "server.dll", "48 83 EC ? 8B D1 85 C9 7E ? 48 8B 05", 0x0);
static void* pCTFGameStats = nullptr;
static void* s_pCTFGameStats = nullptr;
MAKE_HOOK(CTFGameStats_FindPlayerStats, S::CTFGameStats_FindPlayerStats(), void*,
void* rcx, CBasePlayer* pPlayer)
{
pCTFGameStats = rcx;
s_pCTFGameStats = rcx;
return CALL_ORIGINAL(rcx, pPlayer);
}
#endif
@@ -659,11 +659,11 @@ void CCritHack::Draw(CTFPlayer* pLocal)
#ifdef SERVER_CRIT_DATA
H::Draw.StringOutlined(fFont, x, y += nTall, Vars::Menu::Theme::Active.Value, Vars::Menu::Theme::Background.Value, align, std::format("AllDamage: {} ({})", m_iRangedDamage + m_iMeleeDamage, m_iMeleeDamage).c_str());
if (pCTFGameStats)
if (s_pCTFGameStats)
{
if (auto pPlayer2 = S::UTIL_PlayerByIndex.Call<void*>(I::EngineClient->GetLocalPlayer()))
{
if (auto pPlayerStats = S::CTFGameStats_FindPlayerStats.Call<PlayerStats_t*>(pCTFGameStats, pPlayer2))
if (auto pPlayerStats = S::CTFGameStats_FindPlayerStats.Call<PlayerStats_t*>(s_pCTFGameStats, pPlayer2))
{
int iRangedDamage = pPlayerStats->statsCurrentRound.m_iStat[TFSTAT_DAMAGE_RANGED] /*= m_iRangedDamage*/;
int iCritDamage = pPlayerStats->statsCurrentRound.m_iStat[TFSTAT_DAMAGE_RANGED_CRIT_RANDOM] /*= m_iCritDamage = 0*/;
+18 -21
View File
@@ -2520,10 +2520,9 @@ void CMenu::MenuSettings(int iTab)
std::unordered_map<int, bool> mBinds = {};
std::function<void(int)> getBinds = [&](int iParent)
{
for (auto it = F::Binds.m_vBinds.begin(); it < F::Binds.m_vBinds.end(); it++)
for (int _iBind = 0; _iBind < F::Binds.m_vBinds.size(); _iBind++)
{
int _iBind = std::distance(F::Binds.m_vBinds.begin(), it);
auto& _tBind = *it;
auto& _tBind = F::Binds.m_vBinds[_iBind];
if (iParent != _tBind.m_iParent || mBinds.contains(_iBind))
continue;
@@ -2565,10 +2564,9 @@ void CMenu::MenuSettings(int iTab)
std::unordered_map<int, bool> mBinds = {};
std::function<void(int, int)> getBinds = [&](int iParent, int x)
{
for (auto it = F::Binds.m_vBinds.begin(); it < F::Binds.m_vBinds.end(); it++)
for (int _iBind = 0; _iBind < F::Binds.m_vBinds.size(); _iBind++)
{
int _iBind = std::distance(F::Binds.m_vBinds.begin(), it);
auto& _tBind = *it;
auto& _tBind = F::Binds.m_vBinds[_iBind];
if (iParent != DEFAULT_BIND - 1 && iParent != _tBind.m_iParent || mBinds.contains(_iBind))
continue;
@@ -3325,7 +3323,7 @@ struct DragBoxStorage_t
DragBox_t m_tDragBox;
float m_flScale;
};
static std::unordered_map<uint32_t, DragBoxStorage_t> mDragBoxStorage = {};
static std::unordered_map<uint32_t, DragBoxStorage_t> s_mDragBoxStorage = {};
void CMenu::AddDraggable(const char* sLabel, ConfigVar<DragBox_t>& var, bool bShouldDraw, ImVec2 vSize)
{
using namespace ImGui;
@@ -3336,8 +3334,8 @@ void CMenu::AddDraggable(const char* sLabel, ConfigVar<DragBox_t>& var, bool bSh
auto tDragBox = FGet(var, true);
auto uHash = FNV1A::Hash32(sLabel);
bool bContains = mDragBoxStorage.contains(uHash);
auto& tStorage = mDragBoxStorage[uHash];
bool bContains = s_mDragBoxStorage.contains(uHash);
auto& tStorage = s_mDragBoxStorage[uHash];
SetNextWindowSize(vSize, ImGuiCond_Always);
if (!bContains || tDragBox != tStorage.m_tDragBox || H::Draw.Scale() != tStorage.m_flScale)
@@ -3373,7 +3371,7 @@ struct WindowBoxStorage_t
WindowBox_t m_tWindowBox;
float m_flScale;
};
static std::unordered_map<uint32_t, WindowBoxStorage_t> mWindowBoxStorage = {};
static std::unordered_map<uint32_t, WindowBoxStorage_t> s_mWindowBoxStorage = {};
void CMenu::AddResizableDraggable(const char* sLabel, ConfigVar<WindowBox_t>& var, bool bShouldDraw, ImVec2 vMinSize, ImVec2 vMaxSize, ImGuiSizeCallback fCustomCallback)
{
using namespace ImGui;
@@ -3384,8 +3382,8 @@ void CMenu::AddResizableDraggable(const char* sLabel, ConfigVar<WindowBox_t>& va
auto tWindowBox = FGet(var, true);
auto uHash = FNV1A::Hash32(sLabel);
bool bContains = mWindowBoxStorage.contains(uHash);
auto& tStorage = mWindowBoxStorage[uHash];
bool bContains = s_mWindowBoxStorage.contains(uHash);
auto& tStorage = s_mWindowBoxStorage[uHash];
SetNextWindowSizeConstraints(vMinSize, vMaxSize, fCustomCallback);
if (!bContains || tWindowBox != tStorage.m_tWindowBox || H::Draw.Scale() != tStorage.m_flScale)
@@ -3439,10 +3437,9 @@ void CMenu::DrawBinds()
std::vector<BindInfo_t> vInfo;
std::function<void(int)> getBinds = [&](int iParent)
{
for (auto it = F::Binds.m_vBinds.begin(); it < F::Binds.m_vBinds.end(); it++)
for (int iBind = 0; iBind < F::Binds.m_vBinds.size(); iBind++)
{
int iBind = std::distance(F::Binds.m_vBinds.begin(), it);
auto& tBind = *it;
auto& tBind = F::Binds.m_vBinds[iBind];
if (iParent != tBind.m_iParent || !tBind.m_bEnabled && !m_bIsOpen)
continue;
@@ -3504,10 +3501,10 @@ void CMenu::DrawBinds()
if (vInfo.empty())
return;
static DragBox_t old = { -2147483648, -2147483648 };
DragBox_t info = m_bIsOpen ? FGet(Vars::Menu::BindsDisplay, true) : Vars::Menu::BindsDisplay.Value;
if (info != old)
SetNextWindowPos({ float(info.x), float(info.y) }, ImGuiCond_Always);
static DragBox_t tOld = { -2147483648, -2147483648 };
DragBox_t tDragBox = m_bIsOpen ? FGet(Vars::Menu::BindsDisplay, true) : Vars::Menu::BindsDisplay.Value;
if (tDragBox != tOld)
SetNextWindowPos({ float(tDragBox.x), float(tDragBox.y) }, ImGuiCond_Always);
float flNameWidth = 0, flInfoWidth = 0, flStateWidth = 0;
PushFont(F::Render.FontSmall);
@@ -3533,9 +3530,9 @@ void CMenu::DrawBinds()
else
RenderBackground(F::Render.Background0p5, F::Render.Background2);
info.x = vWindowPos.x; info.y = vWindowPos.y; old = info;
tDragBox.x = vWindowPos.x; tDragBox.y = vWindowPos.y; tOld = tDragBox;
if (m_bIsOpen)
FSet(Vars::Menu::BindsDisplay, info);
FSet(Vars::Menu::BindsDisplay, tDragBox);
int iListStart = 8;
if (Vars::Menu::BindWindowTitle.Value)
@@ -64,9 +64,8 @@ MAKE_HOOK(CHLClient_FrameStageNotify, U::Memory.GetVirtual(I::Client, 35), void,
break;
}
case FRAME_RENDER_START:
for (auto it = F::Binds.m_vBinds.begin(); it < F::Binds.m_vBinds.end(); it++)
for (auto& tBind : F::Binds.m_vBinds)
{ // don't drop inputs for binds
auto& tBind = *it;
if (tBind.m_iType != BindEnum::Key)
continue;
@@ -94,7 +94,7 @@ const static std::vector<const char*> s_vNoisemaker = { "items\\halloween", "ite
const static std::vector<const char*> s_vFryingPan = { "pan_" };
const static std::vector<const char*> s_vWater = { "ambient_mp3\\water\\water_splash", "slosh", "wade" };
static bool ShouldBlockSound(const char* pSound)
static inline bool ShouldBlockSound(const char* pSound)
{
if (!Vars::Misc::Sound::Block.Value || !pSound)
return false;
@@ -10,7 +10,7 @@ MAKE_HOOK(CTFRocketLauncher_CheckReloadMisfire, S::CTFRocketLauncher_CheckReload
if (!SDK::AttribHookValue(0, "can_overload", pWeapon))
return false;
auto pPlayer = pWeapon->m_hOwner()->As<CTFPlayer>();
auto pOwner = pWeapon->m_hOwner()->As<CTFPlayer>();
int iClip1 = pWeapon->m_iClip1();
if (pWeapon->m_bRemoveable()) // just using this var since it's in the datamap and doesn't seem to be used on the client
{
@@ -22,7 +22,7 @@ MAKE_HOOK(CTFRocketLauncher_CheckReloadMisfire, S::CTFRocketLauncher_CheckReload
else
pWeapon->m_bRemoveable() = false;
}
else if (iClip1 >= pWeapon->GetMaxClip1() || iClip1 > 0 && pPlayer && pPlayer->GetAmmoCount(pWeapon->m_iPrimaryAmmoType()) == 0)
else if (iClip1 >= pWeapon->GetMaxClip1() || iClip1 > 0 && pOwner && pOwner->GetAmmoCount(pWeapon->m_iPrimaryAmmoType()) == 0)
{
pWeapon->CalcIsAttackCritical();
pWeapon->m_bRemoveable() = true;
@@ -0,0 +1,62 @@
#include "../SDK/SDK.h"
#include "../Features/Backtrack/Backtrack.h"
MAKE_SIGNATURE(CWeaponMedigun_PrimaryAttack, "client.dll", "40 53 48 83 EC ? 8B 91 ? ? ? ? 48 8B D9 85 D2 0F 84 ? ? ? ? 48 89 7C 24 ? B8 ? ? ? ? 83 FA ? 74 ? 0F B7 C2 48 8B 3D ? ? ? ? 8B C8 48 83 C7 ? 48 C1 E1 ? 48 03 F9 0F 84 ? ? ? ? C1 EA ? 39 57 ? 0F 85 ? ? ? ? 48 8B 3F 48 85 FF 74", 0x0);
struct Restore_t
{
Vec3 m_vOrigin;
Vec3 m_vMins;
Vec3 m_vMaxs;
};
MAKE_HOOK(CWeaponMedigun_PrimaryAttack, S::CWeaponMedigun_PrimaryAttack(), void,
void* rcx)
{
auto pWeapon = reinterpret_cast<CWeaponMedigun*>(rcx);
auto pOwner = pWeapon->m_hOwner()->As<CTFPlayer>();
if (!pOwner || !pOwner->m_pCurrentCommand())
return CALL_ORIGINAL(rcx);
// do pseudo lagcomp for the client
std::unordered_map<CBaseEntity*, Restore_t> mRestore = {};
auto pCmd = pOwner->m_pCurrentCommand();
float flTargetTime = TICKS_TO_TIME(pCmd->tick_count - TIME_TO_TICKS(F::Backtrack.GetFakeInterp()));
for (auto pEntity : H::Entities.GetGroup(EGroupType::PLAYERS_TEAMMATES))
{
auto pPlayer = pEntity->As<CTFPlayer>();
if (pPlayer == pOwner || !pPlayer->IsAlive() || pPlayer->IsAGhost())
continue;
std::vector<TickRecord*> vRecords = {};
if (!F::Backtrack.GetRecords(pEntity, vRecords))
continue;
vRecords = F::Backtrack.GetValidRecords(vRecords);
if (!vRecords.size())
continue;
for (auto pRecord : vRecords)
{
if (pRecord->m_flSimTime <= flTargetTime)
{
mRestore[pEntity] = { pEntity->GetAbsOrigin(), pEntity->m_vecMins(), pEntity->m_vecMaxs() };
pEntity->SetAbsOrigin(pRecord->m_vOrigin);
pEntity->m_vecMins() = pRecord->m_vMins;
pEntity->m_vecMaxs() = pRecord->m_vMaxs;
break;
}
}
}
CALL_ORIGINAL(rcx);
for (auto& [pEntity, tRestore] : mRestore)
{
pEntity->SetAbsOrigin(tRestore.m_vOrigin);
pEntity->m_vecMins() = tRestore.m_vMins;
pEntity->m_vecMaxs() = tRestore.m_vMaxs;
}
mRestore.clear();
}
@@ -154,12 +154,6 @@ float CTFWeaponBase::GetSmackDelay()
float CTFWeaponBase::GetRange()
{
switch (GetWeaponID())
{
case TF_WEAPON_MEDIGUN: return 450.f;
case TF_WEAPON_MECHANICAL_ARM: return 256.f;
}
if (auto pWeaponInfo = GetWeaponInfo())
#ifdef WEAPONDATA_USES_WEAPONMODE
return pWeaponInfo->GetWeaponData(m_iWeaponMode()).m_flRange;