From 19edc51369a311a899536ffbe5f2495c6427dce3 Mon Sep 17 00:00:00 2001 From: rei-2 <174158077+rei-2@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:55:43 -0400 Subject: [PATCH] grappling hook projectile aim support some reorganization --- Amalgam/Amalgam.vcxproj | 1 + Amalgam/Amalgam.vcxproj.filters | 1 + Amalgam/cpp.hint | 2 + .../Aimbot/AimbotGlobal/AimbotGlobal.cpp | 4 +- .../AimbotProjectile/AimbotProjectile.cpp | 17 +- .../MovementSimulation/MovementSimulation.cpp | 11 +- .../MovementSimulation/MovementSimulation.h | 1 + Amalgam/src/Hooks/CHLClient_CreateMove.cpp | 104 +--------- .../Hooks/CTFGrapplingHook_ItemPostFrame.cpp | 25 +++ Amalgam/src/SDK/Definitions/Main/KeyValues.h | 6 +- Amalgam/src/SDK/SDK.cpp | 180 ++++++++++++++---- Amalgam/src/SDK/SDK.h | 14 +- 12 files changed, 213 insertions(+), 153 deletions(-) create mode 100644 Amalgam/src/Hooks/CTFGrapplingHook_ItemPostFrame.cpp diff --git a/Amalgam/Amalgam.vcxproj b/Amalgam/Amalgam.vcxproj index 6d9e9405..b395297e 100644 --- a/Amalgam/Amalgam.vcxproj +++ b/Amalgam/Amalgam.vcxproj @@ -962,6 +962,7 @@ + diff --git a/Amalgam/Amalgam.vcxproj.filters b/Amalgam/Amalgam.vcxproj.filters index b24f0678..f18e2b6d 100644 --- a/Amalgam/Amalgam.vcxproj.filters +++ b/Amalgam/Amalgam.vcxproj.filters @@ -208,6 +208,7 @@ + diff --git a/Amalgam/cpp.hint b/Amalgam/cpp.hint index f39f9431..0c705a77 100644 --- a/Amalgam/cpp.hint +++ b/Amalgam/cpp.hint @@ -1,3 +1,5 @@ +#define no_inline __declspec(noinline) + #define VA_LIST(...) __VA_ARGS__ #define STRINGIFY(x) STRINGIFY2(x) diff --git a/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.cpp b/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.cpp index c8eea794..22f7ebc9 100644 --- a/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.cpp +++ b/Amalgam/src/Features/Aimbot/AimbotGlobal/AimbotGlobal.cpp @@ -367,7 +367,9 @@ bool CAimbotGlobal::ShouldHoldAttack(CTFWeaponBase* pWeapon) break; [[fallthrough]]; case Vars::Aimbot::General::AimHoldsFireEnum::Always: - if (!F::Aimbot.m_bRunningSecondary && !G::CanPrimaryAttack && G::LastUserCmd->buttons & IN_ATTACK && Vars::Aimbot::General::AimType.Value && !pWeapon->IsInReload()) + if (!(G::LastUserCmd->buttons & IN_ATTACK) || !Vars::Aimbot::General::AimType.Value || F::Aimbot.m_bRunningSecondary) + break; + if (!G::CanPrimaryAttack && !pWeapon->IsInReload() || pWeapon->GetWeaponID() == TF_WEAPON_GRAPPLINGHOOK && pWeapon->As()->m_hProjectile()) return true; } return false; diff --git a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp index 0587e790..0bd84f5b 100644 --- a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp +++ b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp @@ -2035,12 +2035,27 @@ bool CAimbotProjectile::RunMain(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUser pCmd->buttons &= ~IN_ATTACK; } break; + case TF_WEAPON_GRAPPLINGHOOK: + break; default: pCmd->buttons |= IN_ATTACK; } } - F::Aimbot.m_bRan = G::Attacking = SDK::IsAttacking(pLocal, pWeapon, pCmd, true); + if (nWeaponID != TF_WEAPON_GRAPPLINGHOOK) + F::Aimbot.m_bRan = G::Attacking = SDK::IsAttacking(pLocal, pWeapon, pCmd, true); + else + { + Vec3 vOriginalAngles = pCmd->viewangles; int iOriginalButtons = pCmd->buttons; + pCmd->viewangles = tTarget.m_vAngleTo, pCmd->buttons |= IN_ATTACK; + F::Aimbot.m_bRan = G::Attacking = SDK::IsAttacking(pLocal, pWeapon, pCmd, true); + pCmd->viewangles = vOriginalAngles, pCmd->buttons = iOriginalButtons; + if (!G::Attacking) + continue; + + if (Vars::Aimbot::General::AutoShoot.Value) + pCmd->buttons |= IN_ATTACK; + } DrawVisuals(iResult, tTarget, m_vPlayerPath, m_vProjectilePath, m_vBoxes); Aim(pCmd, tTarget.m_vAngleTo); diff --git a/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.cpp b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.cpp index 6010da1b..81e9fc77 100644 --- a/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.cpp +++ b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.cpp @@ -236,7 +236,7 @@ bool CMovementSimulation::Initialize(CBaseEntity* pEntity, MoveStorage& tMoveSto // setup move data SetupMoveData(tMoveStorage); - if (I::GameMovement->player = pPlayer, I::GameMovement->mv = &tMoveStorage.m_MoveData; I::GameMovement->CheckStuck()) + if (CheckStuck(tMoveStorage)) { tMoveStorage.m_bFailed = true; return true; @@ -319,6 +319,15 @@ void CMovementSimulation::SetupMoveData(MoveStorage& tMoveStorage) tMoveStorage.m_bDirectMove = tMoveStorage.m_pPlayer->IsOnGround() || tMoveStorage.m_pPlayer->IsSwimming(); } +bool CMovementSimulation::CheckStuck(MoveStorage& tMoveStorage) +{ + I::GameMovement->player = I::GameMovement->m_pTFPlayer = tMoveStorage.m_pPlayer, I::GameMovement->mv = &tMoveStorage.m_MoveData; + SetBounds(tMoveStorage.m_pPlayer); + bool bReturn = I::GameMovement->CheckStuck(); + RestoreBounds(tMoveStorage.m_pPlayer); + return bReturn; +} + static inline float GetFrictionScale(float flVelocityXY, float flTurn, float flVelocityZ, float flMin = 50.f, float flMax = 150.f) { if (0.f >= flVelocityZ || flVelocityZ > 250.f) diff --git a/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.h b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.h index 5fbde04b..9049eb90 100644 --- a/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.h +++ b/Amalgam/src/Features/Simulation/MovementSimulation/MovementSimulation.h @@ -46,6 +46,7 @@ private: void Reset(MoveStorage& tMoveStorage); void SetupMoveData(MoveStorage& tMoveStorage); + bool CheckStuck(MoveStorage& tMoveStorage); void GetAverageYaw(MoveStorage& tMoveStorage, int iSamples); bool StrafePrediction(MoveStorage& tMoveStorage, bool bHitchance = false); diff --git a/Amalgam/src/Hooks/CHLClient_CreateMove.cpp b/Amalgam/src/Hooks/CHLClient_CreateMove.cpp index 815335f5..a6f2eafb 100644 --- a/Amalgam/src/Hooks/CHLClient_CreateMove.cpp +++ b/Amalgam/src/Hooks/CHLClient_CreateMove.cpp @@ -15,9 +15,7 @@ #include "../Features/Spectate/Spectate.h" #include "../Features/AntiCheatCompatibility/AntiCheatCompatibility.h" -MAKE_SIGNATURE(IHasGenericMeter_GetMeterMultiplier, "client.dll", "F3 0F 10 81 ? ? ? ? C3 CC CC CC CC CC CC CC 48 85 D2", 0x0); - -static inline void UpdateInfo(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) +static no_inline void UpdateInfo(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd) { G::PSilentAngles = G::SilentAngles = G::Attacking = G::Throwing = false; G::LastUserCmd = G::CurrentUserCmd ? G::CurrentUserCmd : pCmd; @@ -27,105 +25,7 @@ static inline void UpdateInfo(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCm if (!pWeapon) return; - G::CanPrimaryAttack = G::CanSecondaryAttack = G::Reloading = false; - - if (pWeapon->GetMaxClip1() != WEAPON_NOCLIP && !pWeapon->m_bReloadsSingly()) - { // dumb fix - float flOldCurtime = I::GlobalVars->curtime; - I::GlobalVars->curtime = TICKS_TO_TIME(pLocal->m_nTickBase()); - pWeapon->CheckReload(); - I::GlobalVars->curtime = flOldCurtime; - } - - bool bCanAttack = pLocal->CanAttack(); - { - static int iStaticItemDefinitionIndex = 0; - int iOldItemDefinitionIndex = iStaticItemDefinitionIndex; - int iNewItemDefinitionIndex = iStaticItemDefinitionIndex = pWeapon->m_iItemDefinitionIndex(); - - if (iNewItemDefinitionIndex != iOldItemDefinitionIndex || !bCanAttack || !pWeapon->m_iClip1()) - F::Ticks.m_iWait = -1; - } - if (bCanAttack) - { - G::CanPrimaryAttack = pWeapon->CanPrimaryAttack(); - G::CanSecondaryAttack = pWeapon->CanSecondaryAttack(); - - switch (pWeapon->GetWeaponID()) - { - case TF_WEAPON_FLAME_BALL: - if (G::CanPrimaryAttack) - { - // do this, otherwise it will be a tick behind - float flFrametime = TICK_INTERVAL * 100; - float flMeterMult = S::IHasGenericMeter_GetMeterMultiplier.Call(pWeapon->m_pMeter()); - float flRate = SDK::AttribHookValue(1.f, "item_meter_charge_rate", pWeapon) - 1; - float flMult = SDK::AttribHookValue(1.f, "mult_item_meter_charge_rate", pWeapon); - float flTankPressure = pLocal->m_flTankPressure() + flFrametime * flMeterMult / (flRate * flMult); - - if (G::CanPrimaryAttack && flTankPressure < 100.f) - G::CanPrimaryAttack = G::CanSecondaryAttack = false; - } - break; - case TF_WEAPON_MINIGUN: - { - int iState = pWeapon->As()->m_iWeaponState(); - if (iState != AC_STATE_FIRING && iState != AC_STATE_SPINNING || !pWeapon->HasPrimaryAmmoForShot()) - G::CanPrimaryAttack = false; - break; - } - case TF_WEAPON_FLAREGUN_REVENGE: - if (pCmd->buttons & IN_ATTACK2) - G::CanPrimaryAttack = false; - break; - case TF_WEAPON_BAT_WOOD: - case TF_WEAPON_BAT_GIFTWRAP: - if (!pWeapon->HasPrimaryAmmoForShot()) - G::CanSecondaryAttack = false; - break; - case TF_WEAPON_MEDIGUN: - case TF_WEAPON_BUILDER: - case TF_WEAPON_LASER_POINTER: - break; - case TF_WEAPON_PARTICLE_CANNON: - { - float flChargeBeginTime = pWeapon->As()->m_flChargeBeginTime(); - if (flChargeBeginTime > 0) - { - float flTotalChargeTime = TICKS_TO_TIME(pLocal->m_nTickBase()) - flChargeBeginTime; - if (flTotalChargeTime < TF_PARTICLE_MAX_CHARGE_TIME) - { - G::CanPrimaryAttack = G::CanSecondaryAttack = false; - break; - } - } - [[fallthrough]]; - } - default: - if (pWeapon->GetSlot() != SLOT_MELEE) - { - bool bAmmo = pWeapon->HasPrimaryAmmoForShot(); - bool bReload = pWeapon->IsInReload(); - if (!bAmmo && pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka) - G::CanPrimaryAttack = G::CanSecondaryAttack = false; - if (bReload && bAmmo && !G::CanPrimaryAttack) - G::Reloading = true; - } - } - if (G::CanPrimaryAttack) - { - switch (pWeapon->GetWeaponID()) - { - case TF_WEAPON_FLAMETHROWER: - case TF_WEAPON_FLAME_BALL: - case TF_WEAPON_FLAREGUN: - case TF_WEAPON_FLAREGUN_REVENGE: - if (pLocal->IsUnderwater()) - G::CanPrimaryAttack = G::CanSecondaryAttack = false; - } - } - } - + SDK::CanAttack(pLocal, pWeapon, pCmd, G::CanPrimaryAttack, G::CanSecondaryAttack, G::Reloading); G::Attacking = SDK::IsAttacking(pLocal, pWeapon, pCmd); G::PrimaryWeaponType = SDK::GetWeaponType(pWeapon, &G::SecondaryWeaponType); G::CanHeadshot = pWeapon->CanHeadshot() || pWeapon->AmbassadorCanHeadshot(TICKS_TO_TIME(pLocal->m_nTickBase())); diff --git a/Amalgam/src/Hooks/CTFGrapplingHook_ItemPostFrame.cpp b/Amalgam/src/Hooks/CTFGrapplingHook_ItemPostFrame.cpp new file mode 100644 index 00000000..8c6abee3 --- /dev/null +++ b/Amalgam/src/Hooks/CTFGrapplingHook_ItemPostFrame.cpp @@ -0,0 +1,25 @@ +#include "../SDK/SDK.h" + +MAKE_SIGNATURE(CTFGrapplingHook_ItemPostFrame, "client.dll", "40 53 57 48 83 EC ? 48 8B D9 E8 ? ? ? ? 48 8B F8 48 85 C0 0F 84 ? ? ? ? 8B 88", 0x0); +MAKE_SIGNATURE(CTFGrapplingHook_PrimaryAttack, "client.dll", "48 89 5C 24 ? 48 89 7C 24 ? 55 48 8D 6C 24 ? 48 81 EC ? ? ? ? 48 8B D9 E8 ? ? ? ? 8B 93", 0x0); +MAKE_SIGNATURE(CTFGrapplingHook_ItemPostFrame_Fired, "client.dll", "40 38 35 ? ? ? ? 75 ? 48 8B 03", 0x0); + +static bool s_bOriginalFired = false; + +MAKE_HOOK(CTFGrapplingHook_ItemPostFrame, S::CTFGrapplingHook_ItemPostFrame(), void, + void* rcx) +{ + static bool& bFired = *reinterpret_cast(U::Memory.RelToAbs(S::CTFGrapplingHook_ItemPostFrame_Fired())); + s_bOriginalFired = bFired; + bFired = false; // this var breaks prediction for this weapon pretty hard otherwise + CALL_ORIGINAL(rcx); +} + +MAKE_HOOK(CTFGrapplingHook_PrimaryAttack, S::CTFGrapplingHook_PrimaryAttack(), void, + void* rcx) +{ + bool bOriginalFirstTimePredicted = I::Prediction->m_bFirstTimePredicted; + I::Prediction->m_bFirstTimePredicted = !s_bOriginalFired; // don't spam deny sound + CALL_ORIGINAL(rcx); + I::Prediction->m_bFirstTimePredicted = bOriginalFirstTimePredicted; +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Main/KeyValues.h b/Amalgam/src/SDK/Definitions/Main/KeyValues.h index 01ee6412..9db05515 100644 --- a/Amalgam/src/SDK/Definitions/Main/KeyValues.h +++ b/Amalgam/src/SDK/Definitions/Main/KeyValues.h @@ -2,6 +2,8 @@ #include "../Types.h" #include +class CKeyValuesGrowableStringTable; + enum types_t { TYPE_NONE = 0, @@ -33,12 +35,12 @@ private: char m_iDataType; char m_bHasEscapeSequences; char m_bEvaluateConditionals; - char unused[1]; + char m_bUnknown; KeyValues* m_pPeer; KeyValues* m_pSub; KeyValues* m_pChain; - void* m_pUnknown; + CKeyValuesGrowableStringTable* m_pGrowableStringTable; public: class AutoDelete diff --git a/Amalgam/src/SDK/SDK.cpp b/Amalgam/src/SDK/SDK.cpp index 2121076f..232c563c 100644 --- a/Amalgam/src/SDK/SDK.cpp +++ b/Amalgam/src/SDK/SDK.cpp @@ -3,10 +3,12 @@ #include "../Features/ImGui/Notifications/Notifications.h" #include "../Features/ImGui/Menu/Menu.h" #include "../Features/EnginePrediction/EnginePrediction.h" +#include "../Features/Ticks/Ticks.h" #pragma warning (disable : 6385) MAKE_SIGNATURE(CAttributeManager_AttribHookValue_Float, "client.dll", "4C 8B DC 49 89 5B ? 49 89 6B ? 56 57 41 54 41 56 41 57 48 83 EC ? 48 8B 3D ? ? ? ? 4C 8D 35", 0x0); +MAKE_SIGNATURE(IHasGenericMeter_GetMeterMultiplier, "client.dll", "F3 0F 10 81 ? ? ? ? C3 CC CC CC CC CC CC CC 48 85 D2", 0x0); static BOOL CALLBACK TeamFortressWindow(HWND hWindow, LPARAM lParam) { @@ -418,6 +420,13 @@ bool SDK::PredictOrigin(Vec3& vOut, const Vec3& vOrigin, const Vec3& vVelocity, return !trace.DidHit(); } +float SDK::GetGravity() +{ + static auto sv_gravity = H::ConVars.FindVar("sv_gravity"); + + return sv_gravity->GetFloat(); +} + bool SDK::IsLoopback() { auto pNetChan = I::EngineClient->GetNetChannelInfo(); @@ -437,6 +446,38 @@ int SDK::GetWinningTeam() return 0; } +const char* SDK::GetClassByIndex(const int nClass, bool bLower) +{ + static const char* szClassesUpper[] = { + "Unknown", "Scout", "Sniper", "Soldier", "Demoman", "Medic", "Heavy", "Pyro", "Spy", "Engineer" + }; + static const char* szClassesLower[] = { + "unknown", "scout", "sniper", "soldier", "demoman", "medic", "heavy", "pyro", "spy", "engineer" + }; + + if (!bLower) + return nClass < 10 && nClass > 0 ? szClassesUpper[nClass] : szClassesUpper[0]; + else + return nClass < 10 && nClass > 0 ? szClassesLower[nClass] : szClassesLower[0]; +} + +float SDK::AttribHookValue(float value, const char* name, void* econent, void* buffer, bool isGlobalConstString) +{ + return S::CAttributeManager_AttribHookValue_Float.Call(value, name, econent, buffer, isGlobalConstString); +} + +float SDK::MaxSpeed(CTFPlayer* pPlayer, bool bIncludeCrouch, bool bIgnoreSpecialAbility) +{ + float flSpeed = pPlayer->CalculateMaxSpeed(bIgnoreSpecialAbility); + + if (pPlayer->InCond(TF_COND_SPEED_BOOST) || pPlayer->InCond(TF_COND_HALLOWEEN_SPEED_BOOST)) + flSpeed *= 1.35f; + if (bIncludeCrouch && pPlayer->IsDucking() && pPlayer->IsOnGround()) + flSpeed /= 3; + + return flSpeed; +} + EWeaponType SDK::GetWeaponType(CTFWeaponBase* pWeapon, EWeaponType* pSecondaryType) { if (pSecondaryType) @@ -478,7 +519,6 @@ EWeaponType SDK::GetWeaponType(CTFWeaponBase* pWeapon, EWeaponType* pSecondaryTy case TF_WEAPON_PDA_SPY_BUILD: case TF_WEAPON_INVIS: case TF_WEAPON_BUFF_ITEM: - case TF_WEAPON_GRAPPLINGHOOK: case TF_WEAPON_ROCKETPACK: return EWeaponType::UNKNOWN; case TF_WEAPON_CLEAVER: @@ -502,25 +542,107 @@ EWeaponType SDK::GetWeaponType(CTFWeaponBase* pWeapon, EWeaponType* pSecondaryTy case TF_WEAPON_JAR_MILK: case TF_WEAPON_JAR_GAS: case TF_WEAPON_LUNCHBOX: + case TF_WEAPON_GRAPPLINGHOOK: return EWeaponType::PROJECTILE; } return EWeaponType::HITSCAN; } -const char* SDK::GetClassByIndex(const int nClass, bool bLower) +void SDK::CanAttack(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* pCmd, bool& bPrimary, bool& bSecondary, bool& bReloading) { - static const char* szClassesUpper[] = { - "Unknown", "Scout", "Sniper", "Soldier", "Demoman", "Medic", "Heavy", "Pyro", "Spy", "Engineer" - }; - static const char* szClassesLower[] = { - "unknown", "scout", "sniper", "soldier", "demoman", "medic", "heavy", "pyro", "spy", "engineer" - }; + bPrimary = bSecondary = bReloading = false; - if (!bLower) - return nClass < 10 && nClass > 0 ? szClassesUpper[nClass] : szClassesUpper[0]; - else - return nClass < 10 && nClass > 0 ? szClassesLower[nClass] : szClassesLower[0]; + if (pWeapon->GetMaxClip1() != WEAPON_NOCLIP && !pWeapon->m_bReloadsSingly()) + { // dumb fix + float flOldCurtime = I::GlobalVars->curtime; + I::GlobalVars->curtime = TICKS_TO_TIME(pLocal->m_nTickBase()); + pWeapon->CheckReload(); + I::GlobalVars->curtime = flOldCurtime; + } + + bool bCanAttack = pLocal->CanAttack(); + { + static int iStaticItemDefinitionIndex = 0; + int iOldItemDefinitionIndex = iStaticItemDefinitionIndex; + int iNewItemDefinitionIndex = iStaticItemDefinitionIndex = pWeapon->m_iItemDefinitionIndex(); + + if (iNewItemDefinitionIndex != iOldItemDefinitionIndex || !bCanAttack || !pWeapon->m_iClip1()) + F::Ticks.m_iWait = -1; + } + if (bCanAttack) + { + bPrimary = pWeapon->CanPrimaryAttack(); + bSecondary = pWeapon->CanSecondaryAttack(); + + switch (pWeapon->GetWeaponID()) + { + case TF_WEAPON_FLAME_BALL: + if (bPrimary) + { + // do this, otherwise it will be a tick behind + float flFrametime = TICK_INTERVAL * 100; + float flMeterMult = S::IHasGenericMeter_GetMeterMultiplier.Call(pWeapon->m_pMeter()); + float flRate = SDK::AttribHookValue(1.f, "item_meter_charge_rate", pWeapon) - 1; + float flMult = SDK::AttribHookValue(1.f, "mult_item_meter_charge_rate", pWeapon); + float flTankPressure = pLocal->m_flTankPressure() + flFrametime * flMeterMult / (flRate * flMult); + + if (bPrimary && flTankPressure < 100.f) + bPrimary = bSecondary = false; + } + break; + case TF_WEAPON_MINIGUN: + if (int iState = pWeapon->As()->m_iWeaponState(); iState != AC_STATE_FIRING && iState != AC_STATE_SPINNING || !pWeapon->HasPrimaryAmmoForShot()) + bPrimary = false; + break; + case TF_WEAPON_FLAREGUN_REVENGE: + if (pCmd->buttons & IN_ATTACK2) + bPrimary = false; + break; + case TF_WEAPON_BAT_WOOD: + case TF_WEAPON_BAT_GIFTWRAP: + if (!pWeapon->HasPrimaryAmmoForShot()) + bSecondary = false; + break; + case TF_WEAPON_MEDIGUN: + case TF_WEAPON_BUILDER: + case TF_WEAPON_LASER_POINTER: + break; + case TF_WEAPON_PARTICLE_CANNON: + if (float flChargeBeginTime = pWeapon->As()->m_flChargeBeginTime(); flChargeBeginTime > 0) + { + float flTotalChargeTime = TICKS_TO_TIME(pLocal->m_nTickBase()) - flChargeBeginTime; + if (flTotalChargeTime < TF_PARTICLE_MAX_CHARGE_TIME) + { + bPrimary = bSecondary = false; + break; + } + } + [[fallthrough]]; + default: + if (pWeapon->GetSlot() != SLOT_MELEE) + { + bool bAmmo = pWeapon->HasPrimaryAmmoForShot(); + bool bReload = pWeapon->IsInReload(); + if (!bAmmo && pWeapon->m_iItemDefinitionIndex() != Soldier_m_TheBeggarsBazooka) + bPrimary = bSecondary = false; + if (bReload && bAmmo && !bPrimary) + bReloading = true; + } + } + if (bPrimary) + { + switch (pWeapon->GetWeaponID()) + { + case TF_WEAPON_FLAMETHROWER: + case TF_WEAPON_FLAME_BALL: + case TF_WEAPON_FLAREGUN: + case TF_WEAPON_FLAREGUN_REVENGE: + if (pLocal->IsUnderwater()) + bPrimary = bSecondary = false; + } + } + } } int SDK::IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* pCmd, bool bTickBase) @@ -621,14 +743,14 @@ int SDK::IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* if (!G::CanPrimaryAttack || !(pCmd->buttons & IN_ATTACK) || pWeapon->As()->m_hProjectile()) return false; - Vec3 vPos, vAngle; GetProjectileFireSetup(pLocal, pCmd->viewangles, { 23.5f, -8.f, -3.f }, vPos, vAngle, false); + static auto tf_grapplinghook_max_distance = H::ConVars.FindVar("tf_grapplinghook_max_distance"); + const float flGrappleDistance = tf_grapplinghook_max_distance->GetFloat(); + + Vec3 vPos, vAngle; GetProjectileFireSetup(pLocal, pCmd->viewangles, { 23.5f, -8.f, -3.f }, vPos, vAngle, 2000.f); Vec3 vForward; Math::AngleVectors(vAngle, &vForward); CGameTrace trace = {}; - CTraceFilterHitscan filter = {}; - filter.pSkip = pLocal; - static auto tf_grapplinghook_max_distance = H::ConVars.FindVar("tf_grapplinghook_max_distance"); - const float flGrappleDistance = tf_grapplinghook_max_distance->GetFloat(); + CTraceFilterWorldAndPropsOnly filter = {}; Trace(vPos, vPos + vForward * flGrappleDistance, MASK_SOLID, &filter, &trace); return trace.DidHit() && !(trace.surface.flags & SURF_SKY); } @@ -694,30 +816,6 @@ int SDK::IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* return G::CanPrimaryAttack && pCmd->buttons & IN_ATTACK ? 1 : G::Reloading && pCmd->buttons & IN_ATTACK ? 2 : 0; } -float SDK::GetGravity() -{ - static auto sv_gravity = H::ConVars.FindVar("sv_gravity"); - - return sv_gravity->GetFloat(); -} - -float SDK::MaxSpeed(CTFPlayer* pPlayer, bool bIncludeCrouch, bool bIgnoreSpecialAbility) -{ - float flSpeed = pPlayer->CalculateMaxSpeed(bIgnoreSpecialAbility); - - if (pPlayer->InCond(TF_COND_SPEED_BOOST) || pPlayer->InCond(TF_COND_HALLOWEEN_SPEED_BOOST)) - flSpeed *= 1.35f; - if (bIncludeCrouch && pPlayer->IsDucking() && pPlayer->IsOnGround()) - flSpeed /= 3; - - return flSpeed; -} - -float SDK::AttribHookValue(float value, const char* name, void* econent, void* buffer, bool isGlobalConstString) -{ - return S::CAttributeManager_AttribHookValue_Float.Call(value, name, econent, buffer, isGlobalConstString); -} - void SDK::FixMovement(CUserCmd* pCmd, const Vec3& vCurAngle, const Vec3& vTargetAngle) { bool bCurOOB = fabsf(Math::NormalizeAngle(vCurAngle.x)) > 90.f; diff --git a/Amalgam/src/SDK/SDK.h b/Amalgam/src/SDK/SDK.h index 4d7e045e..7bfa0c88 100644 --- a/Amalgam/src/SDK/SDK.h +++ b/Amalgam/src/SDK/SDK.h @@ -23,6 +23,8 @@ #include #include +#define no_inline __declspec(noinline) + #define VK_0 0x30 #define VK_1 0x31 #define VK_2 0x32 @@ -122,16 +124,18 @@ namespace SDK Vec3 PredictOrigin(const Vec3& vOrigin, const Vec3& vVelocity, float flLatency, bool bTrace = true, const Vec3& vMins = {}, const Vec3& vMaxs = {}, unsigned int nMask = MASK_SOLID, float flNormal = 0.f); bool PredictOrigin(Vec3& vOut, const Vec3& vOrigin, const Vec3& vVelocity, float flLatency, bool bTrace = true, const Vec3& vMins = {}, const Vec3& vMaxs = {}, unsigned int nMask = MASK_SOLID, float flNormal = 0.f); + float GetGravity(); bool IsLoopback(); int GetRoundState(); int GetWinningTeam(); - EWeaponType GetWeaponType(CTFWeaponBase* pWeapon, EWeaponType* pSecondaryType = nullptr); - const char* GetClassByIndex(const int nClass, bool bLower = true); - int IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* pCmd, bool bTickBase = false); - float GetGravity(); - float MaxSpeed(CTFPlayer* pPlayer, bool bIncludeCrouch = false, bool bIgnoreSpecialAbility = false); + const char* GetClassByIndex(const int nClass, bool bLower = true); float AttribHookValue(float value, const char* name, void* econent, void* buffer = nullptr, bool isGlobalConstString = true); + float MaxSpeed(CTFPlayer* pPlayer, bool bIncludeCrouch = false, bool bIgnoreSpecialAbility = false); + + EWeaponType GetWeaponType(CTFWeaponBase* pWeapon, EWeaponType* pSecondaryType = nullptr); + void CanAttack(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* pCmd, bool& bPrimary, bool& bSecondary, bool& bReloading); + int IsAttacking(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, const CUserCmd* pCmd, bool bTickBase = false); void FixMovement(CUserCmd* pCmd, const Vec3& vCurAngle, const Vec3& vTargetAngle); void FixMovement(CUserCmd* pCmd, const Vec3& vTargetAngle);