Skip to content

Commit d0d5cd8

Browse files
coffeegrind123claude
andcommitted
Implement advanced smooth aimbot with curves and humanization
- Replace simple linear interpolation with MutinyFixed-style smooth aim - Add 3 curve types with unique pitch/yaw interaction patterns - Implement time-based smoothing with frame time accumulation - Add FOV-based smooth time calculation for dynamic response - Add velocity-based randomization when target is reached - Add mouse input detection to reduce smoothing during user input - Add target change detection with automatic state reset - Port all features to hitscan, projectile, and melee aimbots 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 8432dc3 commit d0d5cd8

File tree

6 files changed

+723
-4
lines changed

6 files changed

+723
-4
lines changed

Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp

Lines changed: 235 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,32 @@ bool CAimbotHitscan::ShouldFire(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUser
595595
return true;
596596
}
597597

598+
void CAimbotHitscan::ClearLegitAimStepVars()
599+
{
600+
m_bReachedLegitAimStepTarget = false;
601+
m_flLegitAimStepIncTimeOverShoot = 0.0f;
602+
m_flCurAimTime = 0.0f;
603+
m_bInitializedLegitAimStepDirection = false;
604+
int nRandom = rand() % 3;
605+
m_nLegitAimCurveType = nRandom != m_nLegitAimCurveType ? nRandom : rand() % 3;
606+
}
607+
608+
static void SmoothAngle(const Vec3& vFrom, Vec3& vTo, float flPercent)
609+
{
610+
Vec3 vDelta = vFrom - vTo;
611+
Math::NormalizeAngle(vDelta.x);
612+
Math::NormalizeAngle(vDelta.y);
613+
vDelta.x *= flPercent;
614+
vDelta.y *= flPercent;
615+
vTo = vFrom - vDelta;
616+
Math::ClampAngles(vTo);
617+
}
618+
619+
static inline float RandFloatRange(float flMin, float flMax)
620+
{
621+
return ((float)rand() / (float)RAND_MAX) * (flMax - flMin) + flMin;
622+
}
623+
598624
bool CAimbotHitscan::Aim(Vec3 vCurAngle, Vec3 vToAngle, Vec3& vOut, int iMethod)
599625
{
600626
auto pLocal = H::Entities.GetLocal();
@@ -616,9 +642,217 @@ bool CAimbotHitscan::Aim(Vec3 vCurAngle, Vec3 vToAngle, Vec3& vOut, int iMethod)
616642
vOut = vToAngle;
617643
break;
618644
case Vars::Aimbot::General::AimTypeEnum::Smooth:
619-
vOut = vCurAngle.LerpAngle(vToAngle, Vars::Aimbot::General::AssistStrength.Value / 100.f);
645+
{
646+
// MutinyFixed-style smooth aimbot with curves and humanization
647+
Vec3 vOldAngles = vCurAngle;
648+
649+
// Calculate delta for initialization
650+
Vec3 vDelta = vToAngle - vCurAngle;
651+
Math::NormalizeAngle(vDelta.x);
652+
Math::NormalizeAngle(vDelta.y);
653+
Math::ClampAngles(vDelta);
654+
655+
// Initialize direction if not set
656+
if (!m_bInitializedLegitAimStepDirection)
657+
{
658+
m_LegitAimStartDirection = vDelta.y > 0 ? LEFT : RIGHT;
659+
m_vLegitAimStepInitialDelta = vDelta;
660+
m_bInitializedLegitAimStepDirection = true;
661+
}
662+
663+
// Check if we've reached the target
664+
if (m_bReachedLegitAimStepTarget)
665+
{
666+
if (fabsf(vDelta.y) > 15.0f || fabsf(vDelta.x) > 15.0f)
667+
{
668+
ClearLegitAimStepVars();
669+
}
670+
}
671+
672+
// Calculate frame time
673+
static float flLastAimStepTime = 0.0f;
674+
if (flLastAimStepTime == 0.0f)
675+
flLastAimStepTime = I::GlobalVars->curtime;
676+
677+
float flFrameTime = std::min(I::GlobalVars->curtime - flLastAimStepTime, 0.1f);
678+
flLastAimStepTime = I::GlobalVars->curtime;
679+
680+
m_flCurAimTime += flFrameTime;
681+
682+
// Calculate FOV to target
683+
float flFOV = std::max(0.001f, Math::CalcFov(vOldAngles, vToAngle));
684+
685+
// Calculate smooth time based on speed setting
686+
float flSmoothScale = std::max(0.1f, Vars::Aimbot::General::AssistStrength.Value);
687+
float flSmoothTime = m_flCurAimTime * flSmoothScale + (m_bReachedLegitAimStepTarget ? 0.1f / flFOV : 0.33f / flFOV);
688+
689+
// Apply velocity-based randomization when target reached
690+
if (m_bReachedLegitAimStepTarget)
691+
{
692+
auto pLocal = H::Entities.GetLocal();
693+
if (pLocal)
694+
{
695+
float flLocalVel = pLocal->m_vecVelocity().Length();
696+
if (flLocalVel > 0.0f)
697+
{
698+
flSmoothTime *= RandFloatRange(0.35f, 0.45f);
699+
}
700+
}
701+
}
702+
703+
// Clamp smooth time
704+
if (flSmoothTime > 0.92f)
705+
flSmoothTime = 1.0f;
706+
707+
// Detect mouse input and reduce smoothing
708+
if (G::CurrentUserCmd && (abs(G::CurrentUserCmd->mousedx) > 2 || abs(G::CurrentUserCmd->mousedy) > 2))
709+
{
710+
flSmoothTime *= 0.25f;
711+
m_flCurAimTime = std::max(0.0f, m_flCurAimTime - (flFrameTime * 2.0f));
712+
}
713+
714+
// Apply smoothing
715+
vOut = vToAngle;
716+
SmoothAngle(vOldAngles, vOut, flSmoothTime);
717+
718+
// Apply curve-specific pitch adjustments
719+
Vec3 vDeltaAngle = (vOut - vOldAngles);
720+
Math::NormalizeAngle(vDeltaAngle.x);
721+
Math::NormalizeAngle(vDeltaAngle.y);
722+
723+
switch (m_nLegitAimCurveType)
724+
{
725+
case 0:
726+
if (vDeltaAngle.y > 0.4f)
727+
{
728+
float flInc = RandFloatRange(0.265f, 0.291f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
729+
if (m_vLegitAimStepInitialDelta.x < 0)
730+
vOut.x -= flInc;
731+
else
732+
vOut.x += flInc;
733+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
734+
}
735+
else if (vDeltaAngle.y < -0.4f)
736+
{
737+
float flInc = RandFloatRange(0.252f, 0.294f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
738+
if (m_vLegitAimStepInitialDelta.x < 0)
739+
vOut.x -= flInc;
740+
else
741+
vOut.x += flInc;
742+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
743+
}
744+
else if (vDeltaAngle.y > 0.2f)
745+
{
746+
float flInc = RandFloatRange(-0.002f, 0.0385f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
747+
if (m_vLegitAimStepInitialDelta.x < 0)
748+
vOut.x -= flInc;
749+
else
750+
vOut.x += flInc;
751+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
752+
}
753+
else if (vDeltaAngle.y < -0.2f)
754+
{
755+
float flInc = RandFloatRange(-0.00212f, 0.032f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
756+
if (m_vLegitAimStepInitialDelta.x < 0)
757+
vOut.x -= flInc;
758+
else
759+
vOut.x += flInc;
760+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
761+
}
762+
else
763+
{
764+
m_bReachedLegitAimStepTarget = true;
765+
}
766+
break;
767+
case 1:
768+
if (vDeltaAngle.y > 0.4f)
769+
{
770+
float flInc = RandFloatRange(0.265f, 0.331f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
771+
if (m_vLegitAimStepInitialDelta.x < 0)
772+
vOut.x -= flInc;
773+
else
774+
vOut.x += flInc;
775+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
776+
}
777+
else if (vDeltaAngle.y < -0.4f)
778+
{
779+
float flInc = RandFloatRange(0.252f, 0.324f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
780+
if (m_vLegitAimStepInitialDelta.x < 0)
781+
vOut.x -= flInc;
782+
else
783+
vOut.x += flInc;
784+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
785+
}
786+
else if (vDeltaAngle.y > 0.2f)
787+
{
788+
float flInc = RandFloatRange(-0.002f, 0.0385f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
789+
if (m_vLegitAimStepInitialDelta.x < 0)
790+
vOut.x -= flInc;
791+
else
792+
vOut.x += flInc;
793+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
794+
}
795+
else if (vDeltaAngle.y < -0.2f)
796+
{
797+
float flInc = RandFloatRange(-0.00212f, 0.032f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
798+
if (m_vLegitAimStepInitialDelta.x < 0)
799+
vOut.x -= flInc;
800+
else
801+
vOut.x += flInc;
802+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
803+
}
804+
else
805+
{
806+
m_bReachedLegitAimStepTarget = true;
807+
}
808+
break;
809+
case 2:
810+
if (vDeltaAngle.y > 0.4f)
811+
{
812+
float flInc = RandFloatRange(0.2f, 0.25f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
813+
if (m_vLegitAimStepInitialDelta.x < 0)
814+
vOut.x -= flInc;
815+
else
816+
vOut.x += flInc;
817+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
818+
}
819+
else if (vDeltaAngle.y < -0.4f)
820+
{
821+
float flInc = RandFloatRange(0.15f, 0.20f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
822+
if (m_vLegitAimStepInitialDelta.x < 0)
823+
vOut.x -= flInc;
824+
else
825+
vOut.x += flInc;
826+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
827+
}
828+
else if (vDeltaAngle.y > 0.2f)
829+
{
830+
float flInc = RandFloatRange(-0.005f, 0.018f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
831+
if (m_vLegitAimStepInitialDelta.x < 0)
832+
vOut.x -= flInc;
833+
else
834+
vOut.x += flInc;
835+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
836+
}
837+
else if (vDeltaAngle.y < -0.2f)
838+
{
839+
float flInc = RandFloatRange(-0.001f, 0.04f) - std::min(0.0f, (1.0f / flFOV)) - flSmoothTime;
840+
if (m_vLegitAimStepInitialDelta.x < 0)
841+
vOut.x -= flInc;
842+
else
843+
vOut.x += flInc;
844+
vOut.x = std::clamp(Math::NormalizeAngle(vOut.x), -89.f, 89.f);
845+
}
846+
else
847+
{
848+
m_bReachedLegitAimStepTarget = true;
849+
}
850+
break;
851+
}
852+
620853
bReturn = true;
621854
break;
855+
}
622856
case Vars::Aimbot::General::AimTypeEnum::Assistive:
623857
Vec3 vMouseDelta = G::CurrentUserCmd->viewangles.DeltaAngle(G::LastUserCmd->viewangles);
624858
Vec3 vTargetDelta = vToAngle.DeltaAngle(G::LastUserCmd->viewangles);

Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
class CAimbotHitscan
77
{
88
private:
9+
enum AimDirection { LEFT = 0, RIGHT };
10+
911
std::vector<Target_t> GetTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
1012
std::vector<Target_t> SortTargets(CTFPlayer* pLocal, CTFWeaponBase* pWeapon);
1113

@@ -21,6 +23,17 @@ class CAimbotHitscan
2123

2224
Vec3 m_vEyePos = {};
2325

26+
void ClearLegitAimStepVars();
27+
28+
// Smooth aim state variables
29+
float m_flCurAimTime = 0.0f;
30+
float m_flLegitAimStepIncTimeOverShoot = 0.0f;
31+
bool m_bReachedLegitAimStepTarget = false;
32+
bool m_bInitializedLegitAimStepDirection = false;
33+
AimDirection m_LegitAimStartDirection = LEFT;
34+
Vec3 m_vLegitAimStepInitialDelta = {};
35+
int m_nLegitAimCurveType = 0;
36+
2437
public:
2538
void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd);
2639
};

0 commit comments

Comments
 (0)