diff --git a/Amalgam/Amalgam.vcxproj b/Amalgam/Amalgam.vcxproj index 2eac861c..a531a26d 100644 --- a/Amalgam/Amalgam.vcxproj +++ b/Amalgam/Amalgam.vcxproj @@ -968,6 +968,7 @@ + @@ -1321,6 +1322,7 @@ + diff --git a/Amalgam/Amalgam.vcxproj.filters b/Amalgam/Amalgam.vcxproj.filters index 64cdebac..c103b6eb 100644 --- a/Amalgam/Amalgam.vcxproj.filters +++ b/Amalgam/Amalgam.vcxproj.filters @@ -205,6 +205,7 @@ + @@ -608,6 +609,7 @@ + diff --git a/Amalgam/src/Core/Core.cpp b/Amalgam/src/Core/Core.cpp index 2c29b98d..11c52648 100644 --- a/Amalgam/src/Core/Core.cpp +++ b/Amalgam/src/Core/Core.cpp @@ -7,6 +7,7 @@ #include "../Features/EnginePrediction/EnginePrediction.h" #include "../Features/Visuals/Materials/Materials.h" #include "../Features/Visuals/Visuals.h" +#include "../Features/Spectate/Spectate.h" #include "../SDK/Events/Events.h" #include @@ -145,17 +146,22 @@ void CCore::Unload() if (F::Menu.m_bIsOpen) I::MatSystemSurface->SetCursorAlwaysVisible(false); - if (I::Input->CAM_IsThirdPerson()) + H::ConVars.FindVar("cl_wpn_sway_interp")->SetValue(0.f); + H::ConVars.FindVar("cl_wpn_sway_scale")->SetValue(0.f); + F::Visuals.RestoreWorldModulation(); + if (auto pLocal = H::Entities.GetLocal()) { - if (auto pLocal = H::Entities.GetLocal()) + if (F::Spectate.HasTarget()) + { + F::Spectate.NetUpdateStart(pLocal); + I::EngineClient->SetViewAngles(F::Spectate.m_vOldView); + } + if (I::Input->CAM_IsThirdPerson()) { I::Input->CAM_ToFirstPerson(); pLocal->ThirdPersonSwitch(); } } - F::Visuals.RestoreWorldModulation(); - H::ConVars.FindVar("cl_wpn_sway_interp")->SetValue(0.f); - H::ConVars.FindVar("cl_wpn_sway_scale")->SetValue(0.f); Sleep(250); F::EnginePrediction.Unload(); diff --git a/Amalgam/src/Features/Aimbot/Aimbot.cpp b/Amalgam/src/Features/Aimbot/Aimbot.cpp index b437695b..d5ff38f8 100644 --- a/Amalgam/src/Features/Aimbot/Aimbot.cpp +++ b/Amalgam/src/Features/Aimbot/Aimbot.cpp @@ -90,7 +90,7 @@ void CAimbot::Draw(CTFPlayer* pLocal) if (Vars::Aimbot::General::AimFOV.Value >= 90.f) return; - float flRadius = tanf(DEG2RAD(Vars::Aimbot::General::AimFOV.Value)) / tanf(DEG2RAD(G::FOV) / 2) * float(H::Draw.m_nScreenW) * (4.f / 6.f) / (16.f / 9.f); + float flRadius = tanf(Math::Deg2Rad(Vars::Aimbot::General::AimFOV.Value)) / tanf(Math::Deg2Rad(G::FOV) / 2) * float(H::Draw.m_nScreenW) * (4.f / 6.f) / (16.f / 9.f); H::Draw.LineCircle(H::Draw.m_nScreenW / 2, H::Draw.m_nScreenH / 2, flRadius, 68, Vars::Colors::FOVCircle.Value); } diff --git a/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp b/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp index 06c8a833..c4943b8b 100644 --- a/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp +++ b/Amalgam/src/Features/Aimbot/AimbotHitscan/AimbotHitscan.cpp @@ -283,7 +283,7 @@ int CAimbotHitscan::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBase* std::sort(vRecords.begin(), vRecords.end(), [&](const TickRecord* a, const TickRecord* b) -> bool { Vec3 vPosA = { a->m_aBones[iTargetBone][0][3], a->m_aBones[iTargetBone][1][3], a->m_aBones[iTargetBone][2][3] }; - Vec3 vPosB = { a->m_aBones[iTargetBone][0][3], a->m_aBones[iTargetBone][1][3], a->m_aBones[iTargetBone][2][3] }; + Vec3 vPosB = { b->m_aBones[iTargetBone][0][3], b->m_aBones[iTargetBone][1][3], b->m_aBones[iTargetBone][2][3] }; Vec3 vAnglesA = Math::CalcAngle(m_vEyePos, vPosA); Vec3 vAnglesB = Math::CalcAngle(m_vEyePos, vPosB); return pDoubletapAngle->DeltaAngle(vAnglesA).Length2D() < pDoubletapAngle->DeltaAngle(vAnglesB).Length2D(); @@ -650,7 +650,8 @@ bool CAimbotHitscan::Aim(Vec3 vCurAngle, Vec3 vToAngle, Vec3& vOut, int iMethod) break; } - Math::ClampAngles(vOut); + //if (iMethod != Vars::Aimbot::General::AimTypeEnum::Silent || Vars::Misc::Game::AntiCheatCompatibility.Value) + Math::ClampAngles(vOut); return bReturn; } diff --git a/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp index 56de90a4..af4a45bd 100644 --- a/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp +++ b/Amalgam/src/Features/Aimbot/AimbotMelee/AimbotMelee.cpp @@ -450,7 +450,8 @@ bool CAimbotMelee::Aim(Vec3 vCurAngle, Vec3 vToAngle, Vec3& vOut, int iMethod) break; } - Math::ClampAngles(vOut); + if (iMethod != Vars::Aimbot::General::AimTypeEnum::Silent || Vars::Misc::Game::AntiCheatCompatibility.Value) + Math::ClampAngles(vOut); return bReturn; } diff --git a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp index 9c959754..7823f827 100644 --- a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp +++ b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.cpp @@ -178,7 +178,7 @@ static inline std::vector GetTargets(CTFPlayer* pLocal, CTFWeaponBase* -float CAimbotProjectile::GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pPlayer) +float CAimbotProjectile::GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pPlayer, float flScale) { float flRadius = 0.f; switch (pWeapon->GetWeaponID()) @@ -193,6 +193,11 @@ float CAimbotProjectile::GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pPla case TF_WEAPON_FLAREGUN_REVENGE: if (pWeapon->As()->GetFlareGunType() == FLAREGUN_SCORCHSHOT) flRadius = TF_FLARE_DET_RADIUS; + break; + case TF_WEAPON_JAR: + case TF_WEAPON_JAR_MILK: + case TF_WEAPON_JAR_GAS: + return JAR_EXPLODE_RADIUS * flScale; } if (!flRadius) return 0.f; @@ -206,7 +211,7 @@ float CAimbotProjectile::GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pPla if (pPlayer->InCond(TF_COND_BLASTJUMPING) && SDK::AttribHookValue(1.f, "rocketjump_attackrate_bonus", pWeapon) != 1.f) flRadius *= 0.8f; } - return flRadius * Vars::Aimbot::Projectile::SplashRadius.Value / 100; + return flRadius * flScale; } float CAimbotProjectile::GetSplashRadius(CBaseEntity* pProjectile, CTFWeaponBase* pWeapon, CTFPlayer* pPlayer, float flScale, CTFWeaponBase* pAirblast) @@ -233,6 +238,11 @@ float CAimbotProjectile::GetSplashRadius(CBaseEntity* pProjectile, CTFWeaponBase case ETFClassID::CTFProjectile_Flare: if (pWeapon && pWeapon->As()->GetFlareGunType() == FLAREGUN_SCORCHSHOT) flRadius = TF_FLARE_DET_RADIUS; + break; + case ETFClassID::CTFProjectile_Jar: + case ETFClassID::CTFProjectile_JarMilk: + case ETFClassID::CTFProjectile_JarGas: + return JAR_EXPLODE_RADIUS * flScale; } if (pPlayer && pWeapon) { @@ -315,11 +325,17 @@ static inline int GetHitboxPriority(int nHitbox, Target_t& tTarget, Info_t& tInf return -1; }; -std::unordered_map CAimbotProjectile::GetDirectPoints() +Directs_t CAimbotProjectile::GetDirects() { - std::unordered_map mPoints = {}; + Directs_t mDirects = {}; + + if (Vars::Aimbot::Projectile::SplashPrediction.Value == Vars::Aimbot::Projectile::SplashPredictionEnum::Only && m_tInfo.m_flRadius) + return mDirects; auto& tTarget = *m_tInfo.m_pTarget; + byte iFlags = PointFlagsEnum::Regular; + if (Vars::Aimbot::Projectile::Modifiers.Value & Vars::Aimbot::Projectile::ModifiersEnum::AlternateAngles) + iFlags |= PointFlagsEnum::Alternate; const Vec3 vMins = tTarget.m_pEntity->m_vecMins(), vMaxs = tTarget.m_pEntity->m_vecMaxs(); for (int i = 0; i < 3; i++) @@ -362,17 +378,35 @@ std::unordered_map CAimbotProjectile::GetDirectPoints() vOff.x = std::clamp(vOff.x, vMins.x + Vars::Aimbot::Projectile::HuntsmanClamp.Value, vMaxs.x - Vars::Aimbot::Projectile::HuntsmanClamp.Value); vOff.y = std::clamp(vOff.y, vMins.y + Vars::Aimbot::Projectile::HuntsmanClamp.Value, vMaxs.y - Vars::Aimbot::Projectile::HuntsmanClamp.Value); vOff.z = std::clamp(vOff.z, vMins.z + Vars::Aimbot::Projectile::HuntsmanClamp.Value, vMaxs.z - Vars::Aimbot::Projectile::HuntsmanClamp.Value); - mPoints[iPriority] = vOff; + mDirects[iPriority] = { vOff, iFlags }; } else - mPoints[iPriority] = Vec3(0, 0, vMaxs.z - Vars::Aimbot::Projectile::VerticalShift.Value); + mDirects[iPriority] = { Vec3(0, 0, vMaxs.z - Vars::Aimbot::Projectile::VerticalShift.Value), iFlags }; + break; + case BOUNDS_BODY: + mDirects[iPriority] = { Vec3(0, 0, (vMaxs.z - vMins.z) / 2), iFlags }; + break; + case BOUNDS_FEET: + mDirects[iPriority] = { Vec3(0, 0, vMins.z + Vars::Aimbot::Projectile::VerticalShift.Value), iFlags }; break; - case BOUNDS_BODY: mPoints[iPriority] = Vec3(0, 0, (vMaxs.z - vMins.z) / 2); break; - case BOUNDS_FEET: mPoints[iPriority] = Vec3(0, 0, vMins.z + Vars::Aimbot::Projectile::VerticalShift.Value); break; } } - return mPoints; + return mDirects; +} + +Splashes_t CAimbotProjectile::GetSplashes() +{ + Splashes_t vSplashes = {}; + + if (Vars::Aimbot::Projectile::SplashPrediction.Value == Vars::Aimbot::Projectile::SplashPredictionEnum::Off || !m_tInfo.m_flRadius) + return vSplashes; + + vSplashes.push_back(PointFlagsEnum::Regular); + if (Vars::Aimbot::Projectile::Modifiers.Value & Vars::Aimbot::Projectile::ModifiersEnum::AlternateAngles) + vSplashes.push_back(PointFlagsEnum::Alternate); + + return vSplashes; } static inline std::vector ComputeSphere(float flRadius, int iSamples) @@ -386,7 +420,7 @@ static inline std::vector ComputeSphere(float flRadius, int iSamples) float flRotateX = Vars::Aimbot::Projectile::SplashRotateX.Value < 0.f ? SDK::RandomFloat(0.f, 360.f) : Vars::Aimbot::Projectile::SplashRotateX.Value; float flRotateY = Vars::Aimbot::Projectile::SplashRotateY.Value < 0.f ? SDK::RandomFloat(0.f, 360.f) : Vars::Aimbot::Projectile::SplashRotateY.Value; - float a = PI * (3.f - sqrtf(5.f)); + float a = Math::PI * (3.f - sqrtf(5.f)); for (int n = 0; n < iSamples; n++) { float t = a * n; @@ -514,7 +548,7 @@ static inline void HandleFace(const Face_t& tFace, std::vector& vPoints, f } // possibly add air splash for autodet weapons -void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector& vSplashPoints) +void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector& vSplashPoints, byte iFlags) { vSplashPoints.clear(); @@ -558,10 +592,10 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector& vSpl else { Point_t tPoint = { vPoint, {} }; - CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, 0, tPoint.m_tSolution, CalculateFlagsEnum::None); + CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, 0, tPoint.m_tSolution, iFlags); if (tPoint.m_tSolution.m_iCalculated == CalculateResultEnum::Bad) return false; - vPoint -= Vec3(0, 0, (m_tInfo.m_flGravity * 800.f * pow(tPoint.m_tSolution.m_flTime, 2)) / 2); + vPoint -= Vec3(0, 0, (m_tInfo.m_flGravity * 800.f * powf(tPoint.m_tSolution.m_flTime, 2)) / 2); vAngle = Vec3(tPoint.m_tSolution.m_flPitch, tPoint.m_tSolution.m_flYaw); } return fCheckNormal(trace.plane.normal, vPoint, &vAngle); @@ -571,7 +605,7 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector& vSpl { Vec3 vPoint = vSpherePoints[i] + vTargetCenter; - Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, vPoint, 0, tSolution, false); + Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, vPoint, 0, tSolution, iFlags); if (tSolution.m_iCalculated == CalculateResultEnum::Bad) continue; @@ -593,10 +627,10 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector& vSpl else { Point_t tPoint = { vPoint, {} }; - CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, 0, tPoint.m_tSolution, CalculateFlagsEnum::None); + CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, 0, tPoint.m_tSolution, iFlags); if (tPoint.m_tSolution.m_iCalculated == CalculateResultEnum::Bad) return false; - vPoint -= Vec3(0, 0, (m_tInfo.m_flGravity * 800.f * pow(tPoint.m_tSolution.m_flTime, 2)) / 2); + vPoint -= Vec3(0, 0, (m_tInfo.m_flGravity * 800.f * powf(tPoint.m_tSolution.m_flTime, 2)) / 2); vAngle = Vec3(tPoint.m_tSolution.m_flPitch, tPoint.m_tSolution.m_flYaw); } return fCheckNormal(vNormal, vPoint, &vAngle); @@ -624,7 +658,7 @@ void CAimbotProjectile::SetupSplashPoints(Vec3& vOrigin, std::vector& vSpl #endif } -std::vector CAimbotProjectile::GetSplashPoints(Vec3 vOrigin, std::vector& vSplashPoints, int iSimTime) +std::vector CAimbotProjectile::GetSplashPoints(Vec3 vOrigin, std::vector& vSplashPoints, int iSimTime, byte iFlags) { std::vector> vPointDistances = {}; @@ -634,7 +668,7 @@ std::vector CAimbotProjectile::GetSplashPoints(Vec3 vOrigin, std::vecto for (auto it = vSplashPoints.begin(); it != vSplashPoints.end();) { Point_t tPoint = { *it, {} }; - CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, iSimTime, tPoint.m_tSolution, CalculateFlagsEnum::Accuracy, !m_tInfo.m_iArmTime ? 0 : -1); + CalculateAngle(m_tInfo.m_vLocalEye, tPoint.m_vPoint, iSimTime, tPoint.m_tSolution, iFlags, !m_tInfo.m_iArmTime ? 0 : -1); if (tPoint.m_tSolution.m_iCalculated != CalculateResultEnum::Good) { ++it; @@ -710,13 +744,13 @@ static inline Vec3 PullPoint(const Vec3& vPoint, Vec3 vLocalPos, Info_t& tInfo, const Vec3 vDelta = vTargetPos - vLocalPos; const float flDist = vDelta.Length2D(); - const float flRoot = pow(tInfo.m_flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(tInfo.m_flVelocity, 2)); + const float flRoot = powf(tInfo.m_flVelocity, 4) - flGrav * (flGrav * powf(flDist, 2) + 2.f * vDelta.z * powf(tInfo.m_flVelocity, 2)); if (flRoot < 0.f) return vPoint; - float flPitch = atan((pow(tInfo.m_flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); + float flPitch = atan((powf(tInfo.m_flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); float flTime = flDist / (cos(flPitch) * tInfo.m_flVelocity) - tInfo.m_flOffsetTime; - return vLocalPos + Vec3(0, 0, (flGrav * pow(flTime, 2)) / 2); + return vLocalPos + Vec3(0, 0, (flGrav * powf(flTime, 2)) / 2); }; vLocalPos = fHeightenLocalPos(); @@ -727,97 +761,145 @@ static inline Vec3 PullPoint(const Vec3& vPoint, Vec3 vLocalPos, Info_t& tInfo, -static inline void SolveProjectileSpeed(CTFWeaponBase* pWeapon, const Vec3& vLocalPos, const Vec3& vTargetPos, float& flVelocity, float& flDragTime, const float flGravity) -{ - if (!F::ProjSim.m_pObj->IsDragEnabled() || F::ProjSim.m_pObj->m_dragBasis.IsZero()) - return; +static inline float GetDrag(float flVelocity, ProjectileInfo* pInfo, int iFlags) +{ // stupid, would like not to hardcode magic values + if (!(iFlags & CalculateFlagsEnum::AccountDrag) || !F::ProjSim.m_pObj->m_dragCoefficient || !F::ProjSim.m_pObj->m_dragBasis) + return 0.f; - const float flGrav = flGravity * 800.0f; - const Vec3 vDelta = vTargetPos - vLocalPos; - const float flDist = vDelta.Length2D(); - - const float flRoot = pow(flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(flVelocity, 2)); - if (flRoot < 0.f) - return; - - const float flPitch = atan((pow(flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); - const float flTime = flDist / (cos(flPitch) * flVelocity); - - float flDrag = 0.f; if (Vars::Aimbot::Projectile::DragOverride.Value) - flDrag = Vars::Aimbot::Projectile::DragOverride.Value; + return Vars::Aimbot::Projectile::DragOverride.Value; + + if (!(iFlags & CalculateFlagsEnum::AlternateAngle)) + { + switch (pInfo->m_uType) + { + case FNV1A::Hash32Const("models/weapons/w_models/w_grenade_grenadelauncher.mdl"): + if (!SDK::AttribHookValue(0, "grenade_no_spin", pInfo->m_pWeapon)) + return Math::RemapVal(flVelocity, 1217.f, k_flMaxVelocity, 0.120f, 0.200f); // 0.120 normal, 0.200 capped, 0.300 v3000 + else + return Math::RemapVal(flVelocity, 1217.f, k_flMaxVelocity, 0.060f, 0.085f); // 0.060 normal, 0.085 capped, 0.120 v3000 + case FNV1A::Hash32Const("models/weapons/w_models/w_cannonball.mdl"): + return Math::RemapVal(flVelocity, 1454.f, k_flMaxVelocity, 0.385f, 0.530f); // 0.385 normal, 0.530 capped, 0.790 v3000 + case FNV1A::Hash32Const("models/weapons/w_models/w_stickybomb.mdl"): + return Math::RemapVal(flVelocity, 922.f, k_flMaxVelocity, 0.085f, 0.190f); // 0.085 low, 0.190 capped, 0.230 v2400 + case FNV1A::Hash32Const("models/workshop_partner/weapons/c_models/c_sd_cleaver/c_sd_cleaver.mdl"): + return 0.310f; + case FNV1A::Hash32Const("models/weapons/w_models/w_baseball.mdl"): + return 0.180f; + case FNV1A::Hash32Const("models/weapons/c_models/c_xms_festive_ornament.mdl"): + return 0.285f; + case FNV1A::Hash32Const("models/weapons/c_models/urinejar.mdl"): + case FNV1A::Hash32Const("models/workshop/weapons/c_models/c_madmilk/c_madmilk.mdl"): + case FNV1A::Hash32Const("models/weapons/c_models/c_breadmonster/c_breadmonster.mdl"): + case FNV1A::Hash32Const("models/weapons/c_models/c_breadmonster/c_breadmonster_milk.mdl"): + return 0.057f; + case FNV1A::Hash32Const("models/weapons/c_models/c_gascan/c_gascan.mdl"): + return 0.530f; + } + } else { - switch (pWeapon->m_iItemDefinitionIndex()) // the remaps are dumb but they work so /shrug + switch (pInfo->m_uType) { - case Demoman_m_GrenadeLauncher: - case Demoman_m_GrenadeLauncherR: - case Demoman_m_FestiveGrenadeLauncher: - case Demoman_m_Autumn: - case Demoman_m_MacabreWeb: - case Demoman_m_Rainbow: - case Demoman_m_SweetDreams: - case Demoman_m_CoffinNail: - case Demoman_m_TopShelf: - case Demoman_m_Warhawk: - case Demoman_m_ButcherBird: - case Demoman_m_TheIronBomber: flDrag = Math::RemapVal(flVelocity, 1217.f, k_flMaxVelocity, 0.120f, 0.200f); break; // 0.120 normal, 0.200 capped, 0.300 v3000 - case Demoman_m_TheLochnLoad: flDrag = Math::RemapVal(flVelocity, 1504.f, k_flMaxVelocity, 0.070f, 0.085f); break; // 0.070 normal, 0.085 capped, 0.120 v3000 - case Demoman_m_TheLooseCannon: flDrag = Math::RemapVal(flVelocity, 1454.f, k_flMaxVelocity, 0.385f, 0.530f); break; // 0.385 normal, 0.530 capped, 0.790 v3000 - case Demoman_s_StickybombLauncher: - case Demoman_s_StickybombLauncherR: - case Demoman_s_FestiveStickybombLauncher: - case Demoman_s_TheQuickiebombLauncher: - case Demoman_s_TheScottishResistance: flDrag = Math::RemapVal(flVelocity, 922.f, k_flMaxVelocity, 0.085f, 0.190f); break; // 0.085 low, 0.190 capped, 0.230 v2400 - case Scout_s_TheFlyingGuillotine: - case Scout_s_TheFlyingGuillotineG: flDrag = 0.310f; break; - case Scout_t_TheSandman: flDrag = 0.180f; break; - case Scout_t_TheWrapAssassin: flDrag = 0.285f; break; - case Scout_s_MadMilk: - case Scout_s_MutatedMilk: - case Sniper_s_Jarate: - case Sniper_s_FestiveJarate: - case Sniper_s_TheSelfAwareBeautyMark: flDrag = 0.057f; break; + case FNV1A::Hash32Const("models/weapons/w_models/w_grenade_grenadelauncher.mdl"): + if (!SDK::AttribHookValue(0, "grenade_no_spin", pInfo->m_pWeapon)) + return Math::RemapVal(flVelocity, 1217.f, k_flMaxVelocity, 0.056f, 0.062f); + else + return Math::RemapVal(flVelocity, 1217.f, k_flMaxVelocity, 0.030f, 0.033f); + case FNV1A::Hash32Const("models/weapons/w_models/w_cannonball.mdl"): + return Math::RemapVal(flVelocity, 1454.f, k_flMaxVelocity, 0.099f, 0.092f); + case FNV1A::Hash32Const("models/weapons/w_models/w_stickybomb.mdl"): + return Math::RemapVal(flVelocity, 922.f, k_flMaxVelocity, 0.048f, 0.060f); + case FNV1A::Hash32Const("models/workshop_partner/weapons/c_models/c_sd_cleaver/c_sd_cleaver.mdl"): + return 0.075f; + case FNV1A::Hash32Const("models/weapons/w_models/w_baseball.mdl"): + return 0.057f; + case FNV1A::Hash32Const("models/weapons/c_models/c_xms_festive_ornament.mdl"): + return 0.072f; + case FNV1A::Hash32Const("models/weapons/c_models/urinejar.mdl"): + case FNV1A::Hash32Const("models/workshop/weapons/c_models/c_madmilk/c_madmilk.mdl"): + case FNV1A::Hash32Const("models/weapons/c_models/c_breadmonster/c_breadmonster.mdl"): + case FNV1A::Hash32Const("models/weapons/c_models/c_breadmonster/c_breadmonster_milk.mdl"): + return 0.030f; + case FNV1A::Hash32Const("models/weapons/c_models/c_gascan/c_gascan.mdl"): + return 0.089f; } } - float flOverride = Vars::Aimbot::Projectile::TimeOverride.Value; - flDragTime = powf(flTime, 2) * flDrag / (flOverride ? flOverride : 1.5f); // rough estimate to prevent m_flTime being too low - flVelocity = flVelocity - flVelocity * flTime * flDrag; + return 0.f; } -void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, int iSimTime, Solution_t& tOut, int iFlags, int iTolerance) + +static inline bool GetAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, int iFlags, Info_t& tInfo, float& flPitch, float& flYaw, float& flTime) +{ + float flVelocity = tInfo.m_flVelocity; + float flGrav = tInfo.m_flGravity * 800.f; + Vec3 vDelta = vTargetPos - vLocalPos; + float flDist = vDelta.Length2D(); + float flDrag = GetDrag(flVelocity, F::ProjSim.m_pCurrent, iFlags); + + Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vTargetPos); + + flYaw = vAngleTo.y; + + if (!flGrav) + flPitch = -Math::Deg2Rad(vAngleTo.x); + else + { + float flRoot = powf(flVelocity, 4) - flGrav * (flGrav * powf(flDist, 2) + 2.f * vDelta.z * powf(flVelocity, 2)); + if (flRoot < 0.f) + return false; + + if (!(iFlags & CalculateFlagsEnum::AlternateAngle)) + flPitch = atan((powf(flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); + else + flPitch = atan((powf(flVelocity, 2) + sqrt(flRoot)) / (flGrav * flDist)); + + if (flDrag) + { // drag is handled in a stupid manner, would like something better than this + float flTime = flDist / (flVelocity * cos(flPitch)); + flVelocity *= 1 - flDrag * flTime; + + flRoot = powf(flVelocity, 4) - flGrav * (flGrav * powf(flDist, 2) + 2.f * vDelta.z * powf(flVelocity, 2)); + if (flRoot < 0.f) + return false; + + if (!(iFlags & CalculateFlagsEnum::AlternateAngle)) + flPitch = atan((powf(flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); + else + flPitch = atan((powf(flVelocity, 2) + sqrt(flRoot)) / (flGrav * flDist)); + + //flVelocity = flVelocity / (flDrag * flTime) * (1.f - powf(Math::E, -flDrag * flTime)); + flVelocity = flVelocity / (1 + 0.5f * (1 - powf(Math::E, -flDrag * flTime))); + flVelocity *= 1 + vDelta.z / flVelocity * TICK_INTERVAL * flTime; + } + } + + flTime = flDist / (flVelocity * cos(flPitch)); + + if (Vars::Aimbot::Projectile::TimeOverride.Value) + flTime *= Vars::Aimbot::Projectile::TimeOverride.Value; + + return true; +} + +void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, int iSimTime, Solution_t& tOut, byte iFlags, int iTolerance) { if (tOut.m_iCalculated != CalculateResultEnum::Pending) return; - const float flGrav = m_tInfo.m_flGravity * 800.f; - float flPitch, flYaw; { // basic trajectory pass - float flVelocity = m_tInfo.m_flVelocity, flDragTime = 0.f; - if (iFlags & CalculateFlagsEnum::AccountDrag && m_tInfo.m_pWeapon && F::ProjSim.m_pObj->IsDragEnabled() && !F::ProjSim.m_pObj->m_dragBasis.IsZero()) + //Vec3 vForward, vRight, vUp; Math::AngleVectors(Math::CalcAngle(vLocalPos, vTargetPos), &vForward, &vRight, &vUp); + //Vec3 vShootPos = vLocalPos + (vForward * m_tInfo.m_vOffset.x) + (vRight * m_tInfo.m_vOffset.y) + (vUp * m_tInfo.m_vOffset.z); + if (!GetAngle(vLocalPos, vTargetPos, iFlags, m_tInfo, flPitch, flYaw, tOut.m_flTime)) { - Vec3 vForward, vRight, vUp; Math::AngleVectors(Math::CalcAngle(vLocalPos, vTargetPos), &vForward, &vRight, &vUp); - Vec3 vShootPos = vLocalPos + (vForward * m_tInfo.m_vOffset.x) + (vRight * m_tInfo.m_vOffset.y) + (vUp * m_tInfo.m_vOffset.z); - SolveProjectileSpeed(m_tInfo.m_pWeapon, vShootPos, vTargetPos, flVelocity, flDragTime, m_tInfo.m_flGravity); + tOut.m_iCalculated = CalculateResultEnum::Bad; + return; } - Vec3 vDelta = vTargetPos - vLocalPos; - float flDist = vDelta.Length2D(); - - Vec3 vAngleTo = Math::CalcAngle(vLocalPos, vTargetPos); - if (!flGrav) - flPitch = -DEG2RAD(vAngleTo.x); - else - { // arch - float flRoot = pow(flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(flVelocity, 2)); - if (tOut.m_iCalculated = flRoot < 0.f ? CalculateResultEnum::Bad : CalculateResultEnum::Pending) - return; - flPitch = atan((pow(flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); - } - tOut.m_flTime = flDist / (cos(flPitch) * flVelocity) - m_tInfo.m_flOffsetTime + flDragTime; - tOut.m_flPitch = flPitch = -RAD2DEG(flPitch) - m_tInfo.m_vAngFix.x; - tOut.m_flYaw = flYaw = vAngleTo.y - m_tInfo.m_vAngFix.y; + tOut.m_flTime -= m_tInfo.m_flOffsetTime; + tOut.m_flPitch = flPitch = -Math::Rad2Deg(flPitch) - m_tInfo.m_vAngFix.x; + tOut.m_flYaw = flYaw -= m_tInfo.m_vAngFix.y; } int iTimeTo = ceilf(tOut.m_flTime / TICK_INTERVAL); @@ -827,8 +909,11 @@ void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTarge tOut.m_iCalculated = bGood ? CalculateResultEnum::Good : CalculateResultEnum::Time; return; } - else if (tOut.m_iCalculated = bGood ? CalculateResultEnum::Pending : CalculateResultEnum::Time) + else if (!bGood) + { + tOut.m_iCalculated = CalculateResultEnum::Time; return; + } int iSimFlags = (iFlags & CalculateFlagsEnum::SetupClip ? ProjSimEnum::Redirect : ProjSimEnum::None) | ProjSimEnum::NoRandomAngles | ProjSimEnum::PredictCmdNum; #ifdef SPLASH_DEBUG5 @@ -836,7 +921,7 @@ void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTarge { if (Vars::Visuals::Trajectory::Override.Value) { - if (!Vars::Visuals::Trajectory::Pipes.Value) + if (!Vars::Visuals::Trajectory::ForwardRedirect.Value) s_mTraceCount[__FUNCTION__": setup trace"]++; } else @@ -861,63 +946,53 @@ void CAimbotProjectile::CalculateAngle(const Vec3& vLocalPos, const Vec3& vTarge } #endif m_tProjInfo = {}; - if (tOut.m_iCalculated = !F::ProjSim.GetInfo(m_tInfo.m_pLocal, m_tInfo.m_pWeapon, { flPitch, flYaw, 0 }, m_tProjInfo, iSimFlags) ? CalculateResultEnum::Bad : CalculateResultEnum::Pending) + if (!F::ProjSim.GetInfo(m_tInfo.m_pLocal, m_tInfo.m_pWeapon, { flPitch, flYaw, 0 }, m_tProjInfo, iSimFlags)) + { + tOut.m_iCalculated = CalculateResultEnum::Bad; return; + } { // calculate trajectory from projectile origin - float flVelocity = m_tInfo.m_flVelocity, flDragTime = 0.f; - if (iFlags & CalculateFlagsEnum::AccountDrag && F::ProjSim.m_pObj->IsDragEnabled() && !F::ProjSim.m_pObj->m_dragBasis.IsZero()) - SolveProjectileSpeed(m_tInfo.m_pWeapon, m_tProjInfo.m_vPos, vTargetPos, flVelocity, flDragTime, m_tInfo.m_flGravity); - - Vec3 vDelta = vTargetPos - m_tProjInfo.m_vPos; - float flDist = vDelta.Length2D(); - - Vec3 vAngleTo = Math::CalcAngle(m_tProjInfo.m_vPos, vTargetPos); - if (!flGrav) - tOut.m_flPitch = -DEG2RAD(vAngleTo.x); - else - { // arch - float flRoot = pow(flVelocity, 4) - flGrav * (flGrav * pow(flDist, 2) + 2.f * vDelta.z * pow(flVelocity, 2)); - if (tOut.m_iCalculated = flRoot < 0.f ? CalculateResultEnum::Bad : CalculateResultEnum::Pending) - return; - tOut.m_flPitch = atan((pow(flVelocity, 2) - sqrt(flRoot)) / (flGrav * flDist)); - } - tOut.m_flTime = flDist / (cos(tOut.m_flPitch) * flVelocity) + flDragTime; - } - - { // correct yaw - Vec3 vShootPos = (m_tProjInfo.m_vPos - vLocalPos).To2D(); - Vec3 vTarget = vTargetPos - vLocalPos; - Vec3 vForward; Math::AngleVectors(m_tProjInfo.m_vAng, &vForward); vForward.Normalize2D(); - float flB = 2 * (vShootPos.x * vForward.x + vShootPos.y * vForward.y); - float flC = vShootPos.Length2DSqr() - vTarget.Length2DSqr(); - auto vSolutions = Math::SolveQuadratic(1.f, flB, flC); - if (!vSolutions.empty()) + if (!GetAngle(m_tProjInfo.m_vPos, vTargetPos, iFlags, m_tInfo, tOut.m_flPitch, tOut.m_flYaw, tOut.m_flTime)) { - vShootPos += vForward * vSolutions.front(); - tOut.m_flYaw = flYaw - (RAD2DEG(atan2(vShootPos.y, vShootPos.x)) - flYaw); - flYaw = RAD2DEG(atan2(vShootPos.y, vShootPos.x)); + tOut.m_iCalculated = CalculateResultEnum::Bad; + return; } - } - { // correct pitch - if (flGrav) - { - flPitch -= m_tProjInfo.m_vAng.x; - tOut.m_flPitch = -RAD2DEG(tOut.m_flPitch) + flPitch - m_tInfo.m_vAngFix.x; - } - else - { - Vec3 vShootPos = Math::RotatePoint(m_tProjInfo.m_vPos - vLocalPos, {}, { 0, -flYaw, 0 }); vShootPos.y = 0; - Vec3 vTarget = Math::RotatePoint(vTargetPos - vLocalPos, {}, { 0, -flYaw, 0 }); - Vec3 vForward; Math::AngleVectors(m_tProjInfo.m_vAng - Vec3(0, flYaw, 0), &vForward); vForward.y = 0; vForward.Normalize(); - float flB = 2 * (vShootPos.x * vForward.x + vShootPos.z * vForward.z); - float flC = (powf(vShootPos.x, 2) + powf(vShootPos.z, 2)) - (powf(vTarget.x, 2) + powf(vTarget.z, 2)); + { // correct yaw + Vec3 vShootPos = (m_tProjInfo.m_vPos - vLocalPos).To2D(); + Vec3 vTarget = vTargetPos - vLocalPos; + Vec3 vForward; Math::AngleVectors(m_tProjInfo.m_vAng, &vForward); vForward.Normalize2D(); + float flB = 2 * (vShootPos.x * vForward.x + vShootPos.y * vForward.y); + float flC = vShootPos.Length2DSqr() - vTarget.Length2DSqr(); auto vSolutions = Math::SolveQuadratic(1.f, flB, flC); if (!vSolutions.empty()) { vShootPos += vForward * vSolutions.front(); - tOut.m_flPitch = flPitch - (RAD2DEG(atan2(-vShootPos.z, vShootPos.x)) - flPitch); + tOut.m_flYaw = flYaw - (Math::Rad2Deg(atan2(vShootPos.y, vShootPos.x)) - flYaw); + flYaw = Math::Rad2Deg(atan2(vShootPos.y, vShootPos.x)); + } + } + + { // correct pitch + if (m_tInfo.m_flGravity) + { + flPitch -= m_tProjInfo.m_vAng.x; + tOut.m_flPitch = -Math::Rad2Deg(tOut.m_flPitch) + flPitch - m_tInfo.m_vAngFix.x; + } + else + { + Vec3 vShootPos = Math::RotatePoint(m_tProjInfo.m_vPos - vLocalPos, {}, { 0, -flYaw, 0 }); vShootPos.y = 0; + Vec3 vTarget = Math::RotatePoint(vTargetPos - vLocalPos, {}, { 0, -flYaw, 0 }); + Vec3 vForward; Math::AngleVectors(m_tProjInfo.m_vAng - Vec3(0, flYaw, 0), &vForward); vForward.y = 0; vForward.Normalize(); + float flB = 2 * (vShootPos.x * vForward.x + vShootPos.z * vForward.z); + float flC = (powf(vShootPos.x, 2) + powf(vShootPos.z, 2)) - (powf(vTarget.x, 2) + powf(vTarget.z, 2)); + auto vSolutions = Math::SolveQuadratic(1.f, flB, flC); + if (!vSolutions.empty()) + { + vShootPos += vForward * vSolutions.front(); + tOut.m_flPitch = flPitch - (Math::Rad2Deg(atan2(-vShootPos.z, vShootPos.x)) - flPitch); + } } } } @@ -934,12 +1009,13 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i auto pLocal = m_tInfo.m_pLocal; auto pWeapon = m_tInfo.m_pWeapon; auto& tTarget = *m_tInfo.m_pTarget; + int iTimingTolerance = TIME_TO_TICKS(m_tInfo.m_flBoundingTime); int iSimFlags = ProjSimEnum::Redirect | ProjSimEnum::InitCheck | ProjSimEnum::NoRandomAngles | ProjSimEnum::PredictCmdNum; #ifdef SPLASH_DEBUG5 if (Vars::Visuals::Trajectory::Override.Value) { - if (!Vars::Visuals::Trajectory::Pipes.Value) + if (!Vars::Visuals::Trajectory::ForwardRedirect.Value) s_mTraceCount[__FUNCTION__": setup trace"]++; } else @@ -1059,7 +1135,7 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i { bool bTime = bSplash ? trace.endpos.DistTo(vPoint) < m_tProjInfo.m_flVelocity * TICK_INTERVAL + m_tProjInfo.m_vHull.z - : iSimTime - n < 5 || pWeapon->GetWeaponID() == TF_WEAPON_LUNCHBOX; // projectile so slow it causes problems if we don't waive this check + : iSimTime - n < iTimingTolerance; bool bTarget = trace.m_pEnt == tTarget.m_pEntity || bSplash; bool bValid = bTarget && bTime; if (bValid && bSplash) @@ -1143,8 +1219,9 @@ bool CAimbotProjectile::TestAngle(const Vec3& vPoint, const Vec3& vAngles, int i } else if (!bSplash && bTarget && pWeapon->GetWeaponID() == TF_WEAPON_PIPEBOMBLAUNCHER) { // run for more ticks to check for splash - iSimTime = n + 5; + iSimTime = n + iTimingTolerance; bSplash = bArmTime = true; + filter.pSkip = tTarget.m_pEntity; } else break; @@ -1211,60 +1288,73 @@ bool CAimbotProjectile::HandlePoint(const Vec3& vOrigin, int iSimTime, float flP return bReturn; } -bool CAimbotProjectile::HandleDirect(std::vector& vDirectHistory) +bool CAimbotProjectile::HandleDirect(DirectHistory_t& mDirectHistory) { - if (vDirectHistory.empty()) + if (mDirectHistory.empty()) return false; - std::sort(vDirectHistory.begin(), vDirectHistory.end(), [&](const Direct_t& a, const Direct_t& b) -> bool - { - return a.m_iPriority < b.m_iPriority; - }); - m_flTimeTo = vDirectHistory.front().m_flTime + m_tInfo.m_flLatency; - - for (auto& tHistory : vDirectHistory) + for (auto& vDirectHistory : mDirectHistory | std::views::values) { - if (HandlePoint(tHistory.m_vOrigin, tHistory.m_iSimtime, tHistory.m_flPitch, tHistory.m_flYaw, tHistory.m_flTime, tHistory.m_vPoint)) - return true; + std::sort(vDirectHistory.begin(), vDirectHistory.end(), [&](const Direct_t& a, const Direct_t& b) -> bool + { + return a.m_iPriority < b.m_iPriority; + }); + m_flTimeTo = vDirectHistory.front().m_flTime + m_tInfo.m_flLatency; + + for (auto& tHistory : vDirectHistory) + { + if (HandlePoint(tHistory.m_vOrigin, tHistory.m_iSimtime, tHistory.m_flPitch, tHistory.m_flYaw, tHistory.m_flTime, tHistory.m_vPoint)) + return true; + } } return false; } -bool CAimbotProjectile::HandleSplash(std::vector& vSplashHistory) +bool CAimbotProjectile::HandleSplash(SplashHistory_t& mSplashHistory) { - if (vSplashHistory.empty()) + if (mSplashHistory.empty()) return false; - std::sort(vSplashHistory.begin(), vSplashHistory.end(), [&](const Splash_t& a, const Splash_t& b) -> bool - { - return a.m_flTimeTo < b.m_flTimeTo; - }); - SetupSplashPoints(vSplashHistory.front().m_vOrigin, m_vSplashPoints); - if (m_vSplashPoints.empty()) - return false; - - float flLowestDistance = std::numeric_limits::max(); - for (auto& tHistory : vSplashHistory) + for (auto& [iType, vSplashHistory] : mSplashHistory) { - if (m_tInfo.m_iArmTime && tHistory.m_iSimtime < m_tInfo.m_iArmTime) - continue; + std::sort(vSplashHistory.begin(), vSplashHistory.end(), [&](const Splash_t& a, const Splash_t& b) -> bool + { + return a.m_flTimeTo < b.m_flTimeTo; + }); + byte iFlags = CalculateFlagsEnum::None; + if (iType == PointFlagsEnum::Alternate) + iFlags |= CalculateFlagsEnum::AlternateAngle; + SetupSplashPoints(vSplashHistory.front().m_vOrigin, m_vSplashPoints, iFlags); + if (m_vSplashPoints.empty()) + return false; - std::vector vSplashPoints = {}; - vSplashPoints = GetSplashPoints(tHistory.m_vOrigin, m_vSplashPoints, tHistory.m_iSimtime); - - for (auto& tPoint : vSplashPoints) + iFlags |= CalculateFlagsEnum::Accuracy; + float flLowestDistance = std::numeric_limits::max(); + for (auto& tHistory : vSplashHistory) { - float flDistance = tHistory.m_vOrigin.DistTo(tPoint.m_vPoint); - if (flDistance > flLowestDistance) + if (m_tInfo.m_iArmTime && tHistory.m_iSimtime < m_tInfo.m_iArmTime) continue; - if (HandlePoint(tHistory.m_vOrigin, tHistory.m_iSimtime, tPoint.m_tSolution.m_flPitch, tPoint.m_tSolution.m_flYaw, tPoint.m_tSolution.m_flTime, tPoint.m_vPoint, true)) - flLowestDistance = flDistance; + std::vector vSplashPoints = {}; + vSplashPoints = GetSplashPoints(tHistory.m_vOrigin, m_vSplashPoints, tHistory.m_iSimtime, iFlags); + + for (auto& tPoint : vSplashPoints) + { + float flDistance = tHistory.m_vOrigin.DistTo(tPoint.m_vPoint); + if (flDistance > flLowestDistance) + continue; + + if (HandlePoint(tHistory.m_vOrigin, tHistory.m_iSimtime, tPoint.m_tSolution.m_flPitch, tPoint.m_tSolution.m_flYaw, tPoint.m_tSolution.m_flTime, tPoint.m_vPoint, true)) + flLowestDistance = flDistance; + } } + + if (flLowestDistance != std::numeric_limits::max()) + return true; } - return flLowestDistance != std::numeric_limits::max(); + return false; } int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bVisuals) @@ -1296,7 +1386,7 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas m_tInfo.m_flGravity = m_tProjInfo.m_flGravity; m_tInfo.m_iSplashCount = !m_tInfo.m_flGravity ? Vars::Aimbot::Projectile::SplashCountDirect.Value : Vars::Aimbot::Projectile::SplashCountArc.Value; - m_tInfo.m_flRadius = GetSplashRadius(pWeapon, pLocal); + m_tInfo.m_flRadius = GetSplashRadius(pWeapon, pLocal, Vars::Aimbot::Projectile::SplashRadius.Value / 100); m_tInfo.m_flRadiusTime = m_tInfo.m_flRadius / m_tInfo.m_flVelocity; m_tInfo.m_flBoundingTime = m_tInfo.m_flRadiusTime + tTarget.m_pEntity->GetSize().Length() / m_tInfo.m_flVelocity; m_tInfo.m_iArmTime = TIME_TO_TICKS(ArmTime(pWeapon)); @@ -1310,14 +1400,13 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas + Directs_t mDirects = GetDirects(); + Splashes_t vSplashes = GetSplashes(); + + DirectHistory_t mDirectHistory = {}; + SplashHistory_t mSplashHistory = {}; + int iMaxTime = TIME_TO_TICKS(std::min(m_tProjInfo.m_flLifetime, Vars::Aimbot::Projectile::MaxSimulationTime.Value)); - int iSplash = Vars::Aimbot::Projectile::SplashPrediction.Value && m_tInfo.m_flRadius ? Vars::Aimbot::Projectile::SplashPrediction.Value : Vars::Aimbot::Projectile::SplashPredictionEnum::Off; - - auto mDirectPoints = iSplash == Vars::Aimbot::Projectile::SplashPredictionEnum::Only ? std::unordered_map() : GetDirectPoints(); - - std::vector vDirectHistory = {}; - std::vector vSplashHistory = {}; - for (int i = 1 - TIME_TO_TICKS(m_tInfo.m_flLatency); i <= iMaxTime; i++) { if (!m_tMoveStorage.m_bFailed) @@ -1328,26 +1417,11 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas if (i < 0) continue; - bool bDirectBreaks = true; - if (iSplash) + for (auto& [iIndex, tOffset] : mDirects) { - Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, tTarget.m_vPos, i, tSolution, CalculateFlagsEnum::None); - if (tSolution.m_iCalculated != CalculateResultEnum::Bad) - { - const float flTimeTo = tSolution.m_flTime - TICKS_TO_TIME(i); + Vec3& vOffset = tOffset.m_vOffset; + byte iType = tOffset.m_iFlags & -tOffset.m_iFlags; - bDirectBreaks = false; - if (flTimeTo < m_tInfo.m_flBoundingTime) - { - bDirectBreaks = flTimeTo < -m_tInfo.m_flBoundingTime && (!m_tInfo.m_iArmTime || m_tInfo.m_iArmTime < i); - if (!bDirectBreaks) - vSplashHistory.emplace_back(History_t(tTarget.m_vPos, i), fabsf(flTimeTo)); - } - } - } - - for (auto& [iIndex, vOffset] : mDirectPoints) - { Vec3 vPoint = tTarget.m_vPos + vOffset; if (Vars::Aimbot::Projectile::HuntsmanPullPoint.Value && tTarget.m_nAimedHitbox == HITBOX_HEAD) { @@ -1362,32 +1436,64 @@ int CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBas case CalculateResultEnum::Good: if (m_tInfo.m_iArmTime && m_tInfo.m_iArmTime > i && !m_tMoveStorage.m_MoveData.m_vecVelocity.IsZero()) break; - vDirectHistory.emplace_back(History_t(tTarget.m_vPos, i), tSolution.m_flPitch, tSolution.m_flYaw, tSolution.m_flTime, vPoint, iIndex); + mDirectHistory[iType].emplace_back(History_t(tTarget.m_vPos, i), tSolution.m_flPitch, tSolution.m_flYaw, tSolution.m_flTime, vPoint, iIndex); [[fallthrough]]; case CalculateResultEnum::Bad: - mDirectPoints.erase(iIndex); + tOffset.m_iFlags &= ~iType; + if (!(tOffset.m_iFlags /*& (PointFlagsEnum::Regular | PointFlagsEnum::Alternate)*/)) + mDirects.erase(iIndex); } } - if (bDirectBreaks && mDirectPoints.empty()) + + for (auto it = vSplashes.begin(); it != vSplashes.end();) + { + byte iFlags = CalculateFlagsEnum::AccountDrag; + if (*it == PointFlagsEnum::Alternate) + iFlags |= CalculateFlagsEnum::AlternateAngle; + + Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, tTarget.m_vPos, i, tSolution, iFlags); + if (tSolution.m_iCalculated == CalculateResultEnum::Bad && mDirects.empty()) + { + it = vSplashes.erase(it); + continue; + } + + const float flTimeTo = tSolution.m_flTime - TICKS_TO_TIME(i); + if (flTimeTo > m_tInfo.m_flBoundingTime) + { + ++it; + continue; + } + if (flTimeTo < -m_tInfo.m_flBoundingTime && (!m_tInfo.m_iArmTime || m_tInfo.m_iArmTime < i)) + { + it = vSplashes.erase(it); + continue; + } + + mSplashHistory[*it].emplace_back(History_t(tTarget.m_vPos, i), fabsf(flTimeTo)); + ++it; + } + + if (mDirects.empty() && vSplashes.empty()) break; } m_iResult = false; - switch (iSplash) + switch (m_tInfo.m_flRadius ? Vars::Aimbot::Projectile::SplashPrediction.Value : Vars::Aimbot::Projectile::SplashPredictionEnum::Off) { case Vars::Aimbot::Projectile::SplashPredictionEnum::Off: - HandleDirect(vDirectHistory); + HandleDirect(mDirectHistory); break; case Vars::Aimbot::Projectile::SplashPredictionEnum::Include: - if (!HandleDirect(vDirectHistory)) - HandleSplash(vSplashHistory); + if (!HandleDirect(mDirectHistory)) + HandleSplash(mSplashHistory); break; case Vars::Aimbot::Projectile::SplashPredictionEnum::Prefer: - if (!HandleSplash(vSplashHistory)) - HandleDirect(vDirectHistory); + if (!HandleSplash(mSplashHistory)) + HandleDirect(mDirectHistory); break; case Vars::Aimbot::Projectile::SplashPredictionEnum::Only: - HandleSplash(vSplashHistory); + HandleSplash(mSplashHistory); } F::MoveSim.Restore(m_tMoveStorage); @@ -1459,7 +1565,8 @@ bool CAimbotProjectile::Aim(const Vec3& vCurAngle, const Vec3& vToAngle, Vec3& v break; } - Math::ClampAngles(vOut); + if (iMethod != Vars::Aimbot::General::AimTypeEnum::Silent || Vars::Misc::Game::AntiCheatCompatibility.Value) + Math::ClampAngles(vOut); return bReturn; } @@ -1960,14 +2067,13 @@ bool CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBa + Directs_t mDirects = GetDirects(); + Splashes_t vSplashes = GetSplashes(); + + DirectHistory_t mDirectHistory = {}; + SplashHistory_t mSplashHistory = {}; + int iMaxTime = TIME_TO_TICKS(Vars::Aimbot::Projectile::MaxSimulationTime.Value); - int iSplash = Vars::Aimbot::Projectile::SplashPrediction.Value && m_tInfo.m_flRadius ? Vars::Aimbot::Projectile::SplashPrediction.Value : Vars::Aimbot::Projectile::SplashPredictionEnum::Off; - - auto mDirectPoints = iSplash == Vars::Aimbot::Projectile::SplashPredictionEnum::Only ? std::unordered_map() : GetDirectPoints(); - - std::vector vDirectHistory = {}; - std::vector vSplashHistory = {}; - for (int i = 1 - TIME_TO_TICKS(m_tInfo.m_flLatency); i <= iMaxTime; i++) { if (!m_tMoveStorage.m_bFailed) @@ -1978,26 +2084,11 @@ bool CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBa if (i < 0) continue; - bool bDirectBreaks = true; - if (iSplash) + for (auto& [iIndex, tOffset] : mDirects) { - Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, tTarget.m_vPos, i, tSolution, CalculateFlagsEnum::None); - if (tSolution.m_iCalculated != CalculateResultEnum::Bad) - { - const float flTimeTo = tSolution.m_flTime - TICKS_TO_TIME(i); + Vec3& vOffset = tOffset.m_vOffset; + byte iType = tOffset.m_iFlags & -tOffset.m_iFlags; - bDirectBreaks = false; - if (flTimeTo < m_tInfo.m_flBoundingTime) - { - bDirectBreaks = flTimeTo < -m_tInfo.m_flBoundingTime; - if (!bDirectBreaks) - vSplashHistory.emplace_back(History_t(tTarget.m_vPos, i), fabsf(flTimeTo)); - } - } - } - - for (auto& [iIndex, vOffset] : mDirectPoints) - { Vec3 vPoint = tTarget.m_vPos + vOffset; if (Vars::Aimbot::Projectile::HuntsmanPullPoint.Value && tTarget.m_nAimedHitbox == HITBOX_HEAD) { @@ -2010,32 +2101,64 @@ bool CAimbotProjectile::CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBa switch (tSolution.m_iCalculated) { case CalculateResultEnum::Good: - vDirectHistory.emplace_back(History_t(tTarget.m_vPos, i), tSolution.m_flPitch, tSolution.m_flYaw, tSolution.m_flTime, vPoint, iIndex); + mDirectHistory[iType].emplace_back(History_t(tTarget.m_vPos, i), tSolution.m_flPitch, tSolution.m_flYaw, tSolution.m_flTime, vPoint, iIndex); [[fallthrough]]; case CalculateResultEnum::Bad: - mDirectPoints.erase(iIndex); + tOffset.m_iFlags &= ~iType; + if (!(tOffset.m_iFlags /*& (PointFlagsEnum::Regular | PointFlagsEnum::Alternate)*/)) + mDirects.erase(iIndex); } } - if (bDirectBreaks && mDirectPoints.empty()) + + for (auto it = vSplashes.begin(); it != vSplashes.end();) + { + byte iFlags = CalculateFlagsEnum::AccountDrag; + if (*it == PointFlagsEnum::Alternate) + iFlags |= CalculateFlagsEnum::AlternateAngle; + + Solution_t tSolution; CalculateAngle(m_tInfo.m_vLocalEye, tTarget.m_vPos, i, tSolution, CalculateFlagsEnum::None); + if (tSolution.m_iCalculated == CalculateResultEnum::Bad && mDirects.empty()) + { + it = vSplashes.erase(it); + continue; + } + + const float flTimeTo = tSolution.m_flTime - TICKS_TO_TIME(i); + if (flTimeTo > m_tInfo.m_flBoundingTime) + { + ++it; + continue; + } + if (flTimeTo < -m_tInfo.m_flBoundingTime) + { + it = vSplashes.erase(it); + continue; + } + + mSplashHistory[*it].emplace_back(History_t(tTarget.m_vPos, i), fabsf(flTimeTo)); + ++it; + } + + if (mDirects.empty() && vSplashes.empty()) break; } m_iResult = false; - switch (iSplash) + switch (m_tInfo.m_flRadius ? Vars::Aimbot::Projectile::SplashPrediction.Value : Vars::Aimbot::Projectile::SplashPredictionEnum::Off) { case Vars::Aimbot::Projectile::SplashPredictionEnum::Off: - HandleDirect(vDirectHistory); + HandleDirect(mDirectHistory); break; case Vars::Aimbot::Projectile::SplashPredictionEnum::Include: - if (!HandleDirect(vDirectHistory)) - HandleSplash(vSplashHistory); + if (!HandleDirect(mDirectHistory)) + HandleSplash(mSplashHistory); break; case Vars::Aimbot::Projectile::SplashPredictionEnum::Prefer: - if (!HandleSplash(vSplashHistory)) - HandleDirect(vDirectHistory); + if (!HandleSplash(mSplashHistory)) + HandleDirect(mDirectHistory); break; case Vars::Aimbot::Projectile::SplashPredictionEnum::Only: - HandleSplash(vSplashHistory); + HandleSplash(mSplashHistory); } F::MoveSim.Restore(m_tMoveStorage); diff --git a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.h b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.h index 8985a447..4e99c689 100644 --- a/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.h +++ b/Amalgam/src/Features/Aimbot/AimbotProjectile/AimbotProjectile.h @@ -5,7 +5,8 @@ #include "../../Simulation/MovementSimulation/MovementSimulation.h" #include "../../Simulation/ProjectileSimulation/ProjectileSimulation.h" -Enum(CalculateFlags, None = 0, TwoPass = 1 << 0, SetupClip = 1 << 1, AccountDrag = 1 << 2, Accuracy = TwoPass | SetupClip | AccountDrag) +Enum(PointFlags, None = 0, Regular = 1 << 0, Alternate = 1 << 1) +Enum(CalculateFlags, None = 0, TwoPass = 1 << 0, SetupClip = 1 << 1, AccountDrag = 1 << 2, AlternateAngle = 1 << 3, Accuracy = TwoPass | SetupClip | AccountDrag) Enum(CalculateResult, Pending, Good, Time, Bad) struct Info_t @@ -46,6 +47,14 @@ struct Point_t Solution_t m_tSolution = {}; }; +struct Offset_t +{ + Vec3 m_vOffset; + byte m_iFlags; +}; +using Directs_t = std::unordered_map; +using Splashes_t = std::vector; + struct History_t { Vec3 m_vOrigin; @@ -63,20 +72,23 @@ struct Splash_t : History_t { float m_flTimeTo; }; +using DirectHistory_t = std::unordered_map>; +using SplashHistory_t = std::unordered_map>; class CAimbotProjectile { private: - std::unordered_map GetDirectPoints(); - void SetupSplashPoints(Vec3& vOrigin, std::vector& vSplashPoints); - std::vector GetSplashPoints(Vec3 vOrigin, std::vector& vSplashPoints, int iSimTime); + Directs_t GetDirects(); + Splashes_t GetSplashes(); + void SetupSplashPoints(Vec3& vOrigin, std::vector& vSplashPoints, byte iFlags = CalculateFlagsEnum::None); + std::vector GetSplashPoints(Vec3 vOrigin, std::vector& vSplashPoints, int iSimTime, byte iFlags = CalculateFlagsEnum::Accuracy); - void CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, int iSimTime, Solution_t& tOut, int iFlags = CalculateFlagsEnum::Accuracy, int iTolerance = -1); + void CalculateAngle(const Vec3& vLocalPos, const Vec3& vTargetPos, int iSimTime, Solution_t& tOut, byte iFlags = CalculateFlagsEnum::Accuracy, int iTolerance = -1); bool TestAngle(const Vec3& vPoint, const Vec3& vAngles, int iSimTime, bool bSplash, bool bSecondTest = false); bool HandlePoint(const Vec3& vOrigin, int iSimTime, float flPitch, float flYaw, float flTime, const Vec3& vPoint, bool bSplash = false); - bool HandleDirect(std::vector& vDirectHistory); - bool HandleSplash(std::vector& vSplashHistory); + bool HandleDirect(DirectHistory_t& vDirectHistory); + bool HandleSplash(SplashHistory_t& vSplashHistory); int CanHit(Target_t& tTarget, CTFPlayer* pLocal, CTFWeaponBase* pWeapon, bool bVisuals = true); bool RunMain(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); @@ -108,7 +120,7 @@ private: public: void Run(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd); - float GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pPlayer); + float GetSplashRadius(CTFWeaponBase* pWeapon, CTFPlayer* pPlayer, float flScale = 1.f); bool AutoAirblast(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUserCmd* pCmd, CBaseEntity* pProjectile); float GetSplashRadius(CBaseEntity* pProjectile, CTFWeaponBase* pWeapon = nullptr, CTFPlayer* pPlayer = nullptr, float flScale = 1.f, CTFWeaponBase* pAirblast = nullptr); diff --git a/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.cpp b/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.cpp index b1c3be5d..04dee66e 100644 --- a/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.cpp +++ b/Amalgam/src/Features/Aimbot/AutoDetonate/AutoDetonate.cpp @@ -154,7 +154,7 @@ bool CAutoDetonate::CheckTargets(CTFPlayer* pLocal, EntityEnum::EntityEnum iGrou bool CAutoDetonate::CheckSelf(CTFPlayer* pLocal, EntityEnum::EntityEnum iGroup) { - if (!(Vars::Aimbot::Projectile::AutoDetonate.Value & Vars::Aimbot::Projectile::AutoDetonateEnum::PreventSelfDamage) || !pLocal->IsAlive() || pLocal->IsAGhost()) + if (!(Vars::Aimbot::Projectile::AutoDetonate.Value & Vars::Aimbot::Projectile::AutoDetonateEnum::PreventSelfDamage) || !pLocal->IsAlive() || pLocal->IsAGhost() || pLocal->IsInvulnerable()) return false; auto& vProjectiles = H::Entities.GetGroup(iGroup); diff --git a/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.cpp b/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.cpp index 899f3e8b..c44723ca 100644 --- a/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.cpp +++ b/Amalgam/src/Features/Aimbot/AutoRocketJump/AutoRocketJump.cpp @@ -78,8 +78,8 @@ bool CAutoRocketJump::SetAngles(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUser if (!vSolutions.empty()) { vShootPos += vForward * vSolutions.front(); - m_vAngles.y = flYaw - (RAD2DEG(atan2(vShootPos.y, vShootPos.x)) - flYaw); - flYaw = RAD2DEG(atan2(vShootPos.y, vShootPos.x)); + m_vAngles.y = flYaw - (Math::Rad2Deg(atan2(vShootPos.y, vShootPos.x)) - flYaw); + flYaw = Math::Rad2Deg(atan2(vShootPos.y, vShootPos.x)); } } @@ -93,7 +93,7 @@ bool CAutoRocketJump::SetAngles(CTFPlayer* pLocal, CTFWeaponBase* pWeapon, CUser if (!vSolutions.empty()) { vShootPos += vForward * vSolutions.front(); - m_vAngles.x = flPitch - (RAD2DEG(atan2(-vShootPos.z, vShootPos.x)) - flPitch); + m_vAngles.x = flPitch - (Math::Rad2Deg(atan2(-vShootPos.z, vShootPos.x)) - flPitch); } } diff --git a/Amalgam/src/Features/ImGui/Menu/Components.h b/Amalgam/src/Features/ImGui/Menu/Components.h index fd84739d..b28e8bd1 100644 --- a/Amalgam/src/Features/ImGui/Menu/Components.h +++ b/Amalgam/src/Features/ImGui/Menu/Components.h @@ -254,21 +254,29 @@ namespace ImGui if (bVertical) { - pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x - flInset + vSize.x, vDrawPos.y + flSize }, uTitle, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight); - pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flSize }, { vDrawPos.x - flInset + vSize.x, vDrawPos.y - flInset + vSize.y }, uBackground, H::Draw.Scale(3), ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight); - if (bTwoToneBorder) - pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flSize - H::Draw.Scale() }, {vDrawPos.x - flInset + vSize.x, vDrawPos.y + flSize }, uBorder); + if (!bTwoToneBorder) + pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x + vSize.x - flInset, vDrawPos.y + flSize }, uTitle, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight); + else + { + pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x + vSize.x - flInset, vDrawPos.y + flSize - H::Draw.Scale() }, uTitle, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersTopRight); + pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flSize - H::Draw.Scale() }, { vDrawPos.x + vSize.x - flInset, vDrawPos.y + flSize }, uBorder); + } + pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flSize }, { vDrawPos.x + vSize.x - flInset, vDrawPos.y + vSize.y - flInset }, uBackground, H::Draw.Scale(3), ImDrawFlags_RoundCornersBottomLeft | ImDrawFlags_RoundCornersBottomRight); } else { - pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x + flSize, vDrawPos.y - flInset + vSize.y }, uTitle, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomLeft); - pDrawList->AddRectFilled({ vDrawPos.x + flSize, vDrawPos.y + flInset }, { vDrawPos.x - flInset + vSize.x, vDrawPos.y - flInset + vSize.y }, uBackground, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomRight); - if (bTwoToneBorder) - pDrawList->AddRectFilled({ vDrawPos.x + flSize - H::Draw.Scale(), vDrawPos.y + flInset }, { vDrawPos.x + flSize, vDrawPos.y - flInset + vSize.y }, uBorder); + if (!bTwoToneBorder) + pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x + flSize, vDrawPos.y + vSize.y - flInset }, uTitle, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomLeft); + else + { + pDrawList->AddRectFilled({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x + flSize - H::Draw.Scale(), vDrawPos.y + vSize.y - flInset }, uTitle, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomLeft); + pDrawList->AddRectFilled({ vDrawPos.x + flSize - H::Draw.Scale(), vDrawPos.y + flInset }, { vDrawPos.x + flSize, vDrawPos.y + vSize.y - flInset }, uBorder); + } + pDrawList->AddRectFilled({ vDrawPos.x + flSize, vDrawPos.y + flInset }, { vDrawPos.x + vSize.x - flInset, vDrawPos.y + vSize.y - flInset }, uBackground, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopRight | ImDrawFlags_RoundCornersBottomRight); } flInset += H::Draw.Scale(0.5f) - 0.5f - H::Draw.Scale(); - pDrawList->AddRect({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x - flInset + vSize.x, vDrawPos.y - flInset + vSize.y }, uBorder, H::Draw.Scale(4), ImDrawFlags_None, H::Draw.Scale()); + pDrawList->AddRect({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x + vSize.x - flInset, vDrawPos.y + vSize.y - flInset }, uBorder, H::Draw.Scale(4), ImDrawFlags_None, H::Draw.Scale()); } inline void Divider(float flPrePadding = H::Draw.Scale(8), float flPostPadding = H::Draw.Scale(7), float flInset = H::Draw.Scale(), ImU32 uBorder = F::Render.Background2) { diff --git a/Amalgam/src/Features/ImGui/Menu/Menu.cpp b/Amalgam/src/Features/ImGui/Menu/Menu.cpp index 43048e48..a74eb1b8 100644 --- a/Amalgam/src/Features/ImGui/Menu/Menu.cpp +++ b/Amalgam/src/Features/ImGui/Menu/Menu.cpp @@ -27,18 +27,13 @@ void CMenu::DrawMenu() PushStyleVar(ImGuiStyleVar_WindowMinSize, { H::Draw.Scale(750), H::Draw.Scale(500) }); if (Begin("Main", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoBackground)) { - ImVec2 vWindowPos = GetWindowPos(); ImVec2 vWindowSize = GetWindowSize(); - float flSideSize = 140.f; - - PushClipRect({ 0, 0 }, { ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y }, false); - RenderTwoToneBackground(H::Draw.Scale(flSideSize), F::Render.Background0, F::Render.Background1, F::Render.Background2, 0.f, false); - PopClipRect(); - ImVec2 vDrawPos = GetDrawPos(); auto pDrawList = GetWindowDrawList(); - + float flSize = H::Draw.Scale(140); + float flInset = H::Draw.Scale(); float flOffset = 0.f; + Bind_t tBind; if (!F::Binds.GetBind(CurrentBind, &tBind)) CurrentBind = DEFAULT_BIND; @@ -46,29 +41,39 @@ void CMenu::DrawMenu() if (CurrentBind != DEFAULT_BIND) // bind { flOffset = H::Draw.Scale(60); - pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y + H::Draw.Scale(59) }, { vDrawPos.x + H::Draw.Scale(flSideSize - 1), vDrawPos.y + H::Draw.Scale(60) }, F::Render.Background2); + pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y }, { vDrawPos.x + flSize - flInset, vDrawPos.y + flOffset - flInset }, F::Render.Background0, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft); + pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y + flOffset - flInset }, { vDrawPos.x + flSize - flInset, vDrawPos.y + flOffset }, F::Render.Background2); + pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y + flOffset }, { vDrawPos.x + flSize - flInset, vDrawPos.y + vWindowSize.y }, F::Render.Background0, H::Draw.Scale(3), ImDrawFlags_RoundCornersBottomLeft); SetCursorPos({ H::Draw.Scale(12), H::Draw.Scale(11) }); FText("Editing bind", 0, F::Render.FontRegular); SetCursorPos({ H::Draw.Scale(12), H::Draw.Scale(35) }); PushStyleColor(ImGuiCol_Text, F::Render.Accent.Value); - FText(TruncateText(tBind.m_sName, H::Draw.Scale(flSideSize - 28)).c_str(), 0, F::Render.FontRegular); + FText(TruncateText(tBind.m_sName, flSize - H::Draw.Scale(28)).c_str(), 0, F::Render.FontRegular); PopStyleColor(); - SetCursorPos({ H::Draw.Scale(flSideSize - 31), H::Draw.Scale(6) }); + SetCursorPos({ flSize - H::Draw.Scale(31), H::Draw.Scale(6) }); if (IconButton(ICON_MD_CANCEL)) CurrentBind = DEFAULT_BIND; } else if (!Vars::Menu::CheatTitle.Value.empty()) // title { flOffset = H::Draw.Scale(36); - pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y + H::Draw.Scale(35) }, { vDrawPos.x + H::Draw.Scale(flSideSize - 1), vDrawPos.y + H::Draw.Scale(36) }, F::Render.Background2); - + pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y }, { vDrawPos.x + flSize - flInset, vDrawPos.y + flOffset - flInset }, F::Render.Background0, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft); + pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y + flOffset - flInset }, { vDrawPos.x + flSize - flInset, vDrawPos.y + flOffset }, F::Render.Background2); + pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y + flOffset }, { vDrawPos.x + flSize - flInset, vDrawPos.y + vWindowSize.y }, F::Render.Background0, H::Draw.Scale(3), ImDrawFlags_RoundCornersBottomLeft); + SetCursorPos({ H::Draw.Scale(12), H::Draw.Scale(11) }); PushStyleColor(ImGuiCol_Text, F::Render.Accent.Value); - FText(TruncateText(Vars::Menu::CheatTitle.Value, H::Draw.Scale(flSideSize - 28), F::Render.FontBold).c_str(), 0, F::Render.FontBold); + FText(TruncateText(Vars::Menu::CheatTitle.Value, flSize - H::Draw.Scale(28), F::Render.FontBold).c_str(), 0, F::Render.FontBold); PopStyleColor(); } + else + pDrawList->AddRectFilled({ vDrawPos.x, vDrawPos.y }, { vDrawPos.x + flSize - flInset, vDrawPos.y + vWindowSize.y }, F::Render.Background0, H::Draw.Scale(3), ImDrawFlags_RoundCornersTopLeft | ImDrawFlags_RoundCornersBottomLeft); + + PushClipRect({ 0, 0 }, { ImGui::GetIO().DisplaySize.x, ImGui::GetIO().DisplaySize.y }, false); + RenderTwoToneBackground(flSize, {}, F::Render.Background1, F::Render.Background2, 0.f, false); + PopClipRect(); static int iTab = 0, iAimbotTab = 0, iVisualsTab = 0, iMiscTab = 0, iLogsTab = 0, iSettingsTab = 0; PushFont(F::Render.FontBold); @@ -81,7 +86,7 @@ void CMenu::DrawMenu() { "SETTINGS", "CONFIG", "BINDS", "MATERIALS", "EXTRA" } }, { &iTab, &iAimbotTab, &iVisualsTab, &iMiscTab, &iLogsTab, &iSettingsTab }, - { H::Draw.Scale(flSideSize - 16), H::Draw.Scale(36) }, + { flSize - H::Draw.Scale(16), H::Draw.Scale(36) }, { H::Draw.Scale(8), H::Draw.Scale(8) + flOffset }, FTabsEnum::Vertical | FTabsEnum::HorizontalIcons | FTabsEnum::AlignLeft | FTabsEnum::BarLeft, { { ICON_MD_PERSON }, { ICON_MD_VISIBILITY }, { ICON_MD_ARTICLE }, { ICON_MD_IMPORT_CONTACTS }, { ICON_MD_SETTINGS } }, @@ -102,10 +107,10 @@ void CMenu::DrawMenu() if (bSearch && IsMouseReleased(ImGuiMouseButton_Left) && IsMouseWithin(vDrawPos.x, vDrawPos.y, H::Draw.Scale(140), vWindowSize.y - H::Draw.Scale(45))) sSearch = ""; - SetCursorPos({ H::Draw.Scale(flSideSize), 0 }); + SetCursorPos({ flSize, 0 }); PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0); PushStyleVar(ImGuiStyleVar_WindowPadding, { H::Draw.Scale(8), H::Draw.Scale(8) }); - if (BeginChild("Page", { vWindowSize.x - H::Draw.Scale(flSideSize), vWindowSize.y }, ImGuiChildFlags_AlwaysUseWindowPadding)) + if (BeginChild("Page", { vWindowSize.x - flSize, vWindowSize.y }, ImGuiChildFlags_AlwaysUseWindowPadding)) { if (!bSearch) { @@ -135,7 +140,7 @@ void CMenu::MenuAimbot(int iTab) switch (iTab) { - // General + // General case 0: { if (BeginTable("AimbotTable", 2)) @@ -474,7 +479,7 @@ void CMenu::MenuVisuals(int iTab) switch (iTab) { - // ESP + // ESP case 0: { // fake angle/viewmodel visuals, pickup timers? @@ -511,12 +516,12 @@ void CMenu::MenuVisuals(int iTab) PopStyleColor(); auto fPositionToIndex = [](ImVec2 vPos) - { - int iIndex = floorf((vPos.y - GetCursorPosY() - H::Draw.Scale(4)) / H::Draw.Scale(36)) * 2 - + (vPos.x > GetWindowWidth() / 2 ? 1 : 0); - iIndex = std::clamp(iIndex, 0, int(F::Groups.m_vGroups.size() - 1)); - return iIndex; - }; + { + int iIndex = floorf((vPos.y - GetCursorPosY() - H::Draw.Scale(4)) / H::Draw.Scale(36)) * 2 + + (vPos.x > GetWindowWidth() / 2 ? 1 : 0); + iIndex = std::clamp(iIndex, 0, int(F::Groups.m_vGroups.size() - 1)); + return iIndex; + }; static int iDragging = -1; if (!IsMouseDown(ImGuiMouseButton_Left)) @@ -698,7 +703,7 @@ void CMenu::MenuVisuals(int iTab) vValues.insert(vValues.end(), { ESPEnum::IntelReturnTime }); } - PushTransparent(tGroup.m_iTargets && !(tGroup.m_iTargets& TargetsEnum::ESP)); + PushTransparent(tGroup.m_iTargets && !(tGroup.m_iTargets & TargetsEnum::ESP)); { FDropdown("Draw", &tGroup.m_iESP, vEntries, vValues, FDropdownEnum::Multi); } @@ -1015,7 +1020,7 @@ void CMenu::MenuMisc(int iTab) switch (iTab) { - // Main + // Main case 0: { if (BeginTable("MiscTable", 2)) @@ -1279,7 +1284,7 @@ void CMenu::MenuLogs(int iTab) switch (iTab) { - // PlayerList + // PlayerList case 0: { if (Section("Players")) @@ -1301,309 +1306,309 @@ void CMenu::MenuLogs(int iTab) } auto fGetTeamColor = [&](int iTeam, bool bAlive) - { - switch (iTeam) { - case 3: return Color_t(100, 150, 200, bAlive ? 255 : 127).Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha); - case 2: return Color_t(255, 100, 100, bAlive ? 255 : 127).Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha); - } - return Color_t(127, 127, 127, 255).Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha); - }; + switch (iTeam) + { + case 3: return Color_t(100, 150, 200, bAlive ? 255 : 127).Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha); + case 2: return Color_t(255, 100, 100, bAlive ? 255 : 127).Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha); + } + return Color_t(127, 127, 127, 255).Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha); + }; auto fDrawPlayer = [&](const ListPlayer& tPlayer, int x, int y) - { - ImVec2 vOriginalPos = { !x ? GetStyle().WindowPadding.x : GetWindowWidth() / 2 + GetStyle().WindowPadding.x / 2, H::Draw.Scale(35 + 36 * y) }; - - // background - float flWidth = GetWindowWidth() / 2 - GetStyle().WindowPadding.x * 1.5f; - float flHeight = H::Draw.Scale(28); - ImColor tColor = ColorToVec(fGetTeamColor(tPlayer.m_iTeam, tPlayer.m_bAlive)); - ImVec2 vDrawPos = GetDrawPos() + vOriginalPos; - GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor, H::Draw.Scale(4)); - - // text + icons - int lOffset = H::Draw.Scale(10); - if (tPlayer.m_bLocal || F::Spectate.GetTarget(true) == tPlayer.m_iUserID || tPlayer.m_bFriend || tPlayer.m_bParty) { - lOffset += H::Draw.Scale(19); - SetCursorPos({ vOriginalPos.x + H::Draw.Scale(7), vOriginalPos.y + H::Draw.Scale(6) }); - if (tPlayer.m_bLocal) - IconImage(ICON_MD_PERSON); - else if (F::Spectate.GetTarget(true) == tPlayer.m_iUserID) - IconImage(ICON_MD_VISIBILITY); - else if (tPlayer.m_bFriend) - IconImage(ICON_MD_GROUP); - else if (tPlayer.m_bParty) - IconImage(ICON_MD_GROUPS); - } - SetCursorPos({ vOriginalPos.x + lOffset, vOriginalPos.y + H::Draw.Scale(7) }); - auto sName = TruncateText(tPlayer.m_sName, flWidth / 2 - lOffset); - FText(sName.c_str()); - lOffset += FCalcTextSize(sName.c_str()).x + H::Draw.Scale(8); + ImVec2 vOriginalPos = { !x ? GetStyle().WindowPadding.x : GetWindowWidth() / 2 + GetStyle().WindowPadding.x / 2, H::Draw.Scale(35 + 36 * y) }; - // buttons - bool bPopup = false; + // background + float flWidth = GetWindowWidth() / 2 - GetStyle().WindowPadding.x * 1.5f; + float flHeight = H::Draw.Scale(28); + ImColor tColor = ColorToVec(fGetTeamColor(tPlayer.m_iTeam, tPlayer.m_bAlive)); + ImVec2 vDrawPos = GetDrawPos() + vOriginalPos; + GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor, H::Draw.Scale(4)); - if (!tPlayer.m_bFake) - { - // tag bar - SetCursorPos({ vOriginalPos.x + lOffset, vOriginalPos.y }); - if (BeginChild(std::format("TagBar{}", tPlayer.m_iUserID).c_str(), { flWidth - lOffset - H::Draw.Scale(4), flHeight }, ImGuiWindowFlags_None, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoBackground)) + // text + icons + int lOffset = H::Draw.Scale(10); + if (tPlayer.m_bLocal || F::Spectate.GetTarget(true) == tPlayer.m_iUserID || tPlayer.m_bFriend || tPlayer.m_bParty) { - std::vector vLabels = {}; - std::vector> vTags = {}; - if (int iParty = tPlayer.m_iParty) + lOffset += H::Draw.Scale(19); + SetCursorPos({ vOriginalPos.x + H::Draw.Scale(7), vOriginalPos.y + H::Draw.Scale(6) }); + if (tPlayer.m_bLocal) + IconImage(ICON_MD_PERSON); + else if (F::Spectate.GetTarget(true) == tPlayer.m_iUserID) + IconImage(ICON_MD_VISIBILITY); + else if (tPlayer.m_bFriend) + IconImage(ICON_MD_GROUP); + else if (tPlayer.m_bParty) + IconImage(ICON_MD_GROUPS); + } + SetCursorPos({ vOriginalPos.x + lOffset, vOriginalPos.y + H::Draw.Scale(7) }); + auto sName = TruncateText(tPlayer.m_sName, flWidth / 2 - lOffset); + FText(sName.c_str()); + lOffset += FCalcTextSize(sName.c_str()).x + H::Draw.Scale(8); + + // buttons + bool bPopup = false; + + if (!tPlayer.m_bFake) + { + // tag bar + SetCursorPos({ vOriginalPos.x + lOffset, vOriginalPos.y }); + if (BeginChild(std::format("TagBar{}", tPlayer.m_iUserID).c_str(), { flWidth - lOffset - H::Draw.Scale(4), flHeight }, ImGuiWindowFlags_None, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoBackground)) { - auto pTag = &F::PlayerUtils.m_vTags[F::PlayerUtils.TagToIndex(PARTY_TAG)]; - if (!--iParty) + std::vector vLabels = {}; + std::vector> vTags = {}; + if (int iParty = tPlayer.m_iParty) + { + auto pTag = &F::PlayerUtils.m_vTags[F::PlayerUtils.TagToIndex(PARTY_TAG)]; + if (!--iParty) + vTags.emplace_back(pTag, 0); + else + vLabels.emplace_back(std::format("{}: {}", pTag->m_sName, iParty), pTag->m_tColor.HueShift(iParty * 360.f / iPartyCount)); + } + if (tPlayer.m_bF2P) + { + auto pTag = &F::PlayerUtils.m_vTags[F::PlayerUtils.TagToIndex(F2P_TAG)]; vTags.emplace_back(pTag, 0); - else - vLabels.emplace_back(std::format("{}: {}", pTag->m_sName, iParty), pTag->m_tColor.HueShift(iParty * 360.f / iPartyCount)); - } - if (tPlayer.m_bF2P) - { - auto pTag = &F::PlayerUtils.m_vTags[F::PlayerUtils.TagToIndex(F2P_TAG)]; - vTags.emplace_back(pTag, 0); - } - for (auto& iID : F::PlayerUtils.GetPlayerTags(tPlayer.m_uAccountID)) - { - if (auto pTag = F::PlayerUtils.GetTag(iID)) - vTags.emplace_back(pTag, iID); - } - - PushFont(F::Render.FontSmall); - const auto vDrawPos = GetDrawPos(); - float flTagOffset = 0; - auto fDrawTag = [&](PriorityLabel_t& tTag, int iID) - { - ImColor tTagColor = ColorToVec(tTag.m_tColor); - float flTagWidth = FCalcTextSize(tTag.m_sName.c_str()).x + H::Draw.Scale(!iID ? 10 : 25); - float flTagHeight = H::Draw.Scale(20); - ImVec2 vTagPos = { flTagOffset, H::Draw.Scale(4) }; - - GetWindowDrawList()->AddRectFilled(vDrawPos + vTagPos, { vDrawPos.x + vTagPos.x + flTagWidth, vDrawPos.y + vTagPos.y + flTagHeight }, tTagColor, H::Draw.Scale(4)); - SetCursorPos({ vTagPos.x + H::Draw.Scale(5), vTagPos.y + H::Draw.Scale(3) }); - TextColored(VecToColor(tColor).Blend(tTag.m_tColor).IsColorBright() ? ImVec4(0, 0, 0, 1) : ImVec4(1, 1, 1, 1), tTag.m_sName.c_str()); - if (iID) + } + for (auto& iID : F::PlayerUtils.GetPlayerTags(tPlayer.m_uAccountID)) { - SetCursorPos({ vTagPos.x + flTagWidth - H::Draw.Scale(22), vTagPos.y - H::Draw.Scale(2) }); - if (IconButton(ICON_MD_CANCEL)) - F::PlayerUtils.RemoveTag(tPlayer.m_uAccountID, iID, true, tPlayer.m_sName.c_str()); + if (auto pTag = F::PlayerUtils.GetTag(iID)) + vTags.emplace_back(pTag, iID); } - flTagOffset += flTagWidth + H::Draw.Scale(4); - }; - - for (auto& tTag : vLabels) - fDrawTag(tTag, 0); - for (auto& [pTag, iID] : vTags) - fDrawTag(*pTag, iID); - PopFont(); - } EndChild(); - - bPopup = IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right); - } - SetCursorPos(vOriginalPos); - Button(std::format("##{}", tPlayer.m_iUserID).c_str(), { flWidth, flHeight }); - bPopup |= IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right); - - // popups - if (bPopup) - OpenPopup(std::format("RightClicked{}", tPlayer.m_iUserID).c_str()); - - if (FBeginPopup(std::format("RightClicked{}", tPlayer.m_iUserID).c_str())) - { - PushStyleVar(ImGuiStyleVar_ItemSpacing, { H::Draw.Scale(8), H::Draw.Scale(8) }); - - if (!tPlayer.m_bFake) - { - if (FSelectable("Profile")) - I::SteamFriends->ActivateGameOverlayToUser("steamid", CSteamID(tPlayer.m_uAccountID, k_EUniversePublic, k_EAccountTypeIndividual)); - if (FSelectable("History")) - I::SteamFriends->ActivateGameOverlayToWebPage(std::format("https://steamhistory.net/id/{}", CSteamID(tPlayer.m_uAccountID, k_EUniversePublic, k_EAccountTypeIndividual).ConvertToUint64()).c_str()); - } - - if (FSelectable(F::Spectate.GetTarget(true) == tPlayer.m_iUserID ? "Unspectate" : "Spectate")) - F::Spectate.SetTarget(tPlayer.m_iUserID); - - if (!I::EngineClient->IsPlayingDemo() && FBeginMenu("Votekick")) - { - if (FSelectable("No reason")) - I::ClientState->SendStringCmd(std::format("callvote Kick \"{} other\"", tPlayer.m_iUserID).c_str()); - if (FSelectable("Cheating")) - I::ClientState->SendStringCmd(std::format("callvote Kick \"{} cheating\"", tPlayer.m_iUserID).c_str()); - if (FSelectable("Idle")) - I::ClientState->SendStringCmd(std::format("callvote Kick \"{} idle\"", tPlayer.m_iUserID).c_str()); - if (FSelectable("Scamming")) - I::ClientState->SendStringCmd(std::format("callvote Kick \"{} scamming\"", tPlayer.m_iUserID).c_str()); - - ImGui::EndMenu(); - } - - if (!tPlayer.m_bFake) - { - if (FBeginMenu("Add tag")) - { - for (auto it = F::PlayerUtils.m_vTags.begin(); it != F::PlayerUtils.m_vTags.end(); it++) - { - int iID = std::distance(F::PlayerUtils.m_vTags.begin(), it); - auto& tTag = *it; - if (!tTag.m_bAssignable || F::PlayerUtils.HasTag(tPlayer.m_uAccountID, iID)) - continue; - - auto imColor = ColorToVec(tTag.m_tColor); - PushStyleColor(ImGuiCol_Text, imColor); - imColor.x /= 3; imColor.y /= 3; imColor.z /= 3; - if (FSelectable(tTag.m_sName.c_str(), imColor)) - F::PlayerUtils.AddTag(tPlayer.m_uAccountID, iID, true, tPlayer.m_sName.c_str()); - PopStyleColor(); - } - - ImGui::EndMenu(); - } - if (FBeginMenu("Alias")) - { - bool bHasAlias = F::PlayerUtils.m_mPlayerAliases.contains(tPlayer.m_uAccountID); - static std::string sInput = ""; - - bool bEnter = FInputText("Alias...", sInput, H::Draw.Scale(150), ImGuiInputTextFlags_EnterReturnsTrue); - if (!IsItemFocused()) - sInput = bHasAlias ? F::PlayerUtils.m_mPlayerAliases[tPlayer.m_uAccountID] : ""; - if (bEnter) - { - if (sInput.empty() && bHasAlias) + PushFont(F::Render.FontSmall); + const auto vDrawPos = GetDrawPos(); + float flTagOffset = 0; + auto fDrawTag = [&](PriorityLabel_t& tTag, int iID) { - F::Output.AliasChanged(tPlayer.m_sName.c_str(), "Removed", F::PlayerUtils.m_mPlayerAliases[tPlayer.m_uAccountID].c_str()); + ImColor tTagColor = ColorToVec(tTag.m_tColor); + float flTagWidth = FCalcTextSize(tTag.m_sName.c_str()).x + H::Draw.Scale(!iID ? 10 : 25); + float flTagHeight = H::Draw.Scale(20); + ImVec2 vTagPos = { flTagOffset, H::Draw.Scale(4) }; - F::PlayerUtils.m_mPlayerAliases.erase(tPlayer.m_uAccountID); - F::PlayerUtils.m_bSave = true; - } - else if (!sInput.empty()) - { - F::PlayerUtils.m_mPlayerAliases[tPlayer.m_uAccountID] = sInput; - F::PlayerUtils.m_bSave = true; - - F::Output.AliasChanged(tPlayer.m_sName.c_str(), bHasAlias ? "Changed" : "Added", sInput.c_str()); - } - } - - ImGui::EndMenu(); - } - } - - if (Vars::Resolver::Enabled.Value && !tPlayer.m_bLocal && !I::EngineClient->IsPlayingDemo()) - { - if (FBeginMenu("Set yaw")) - { - static std::vector> vYaws = { - { "Auto", 0.f }, - { "Forward", 0.f }, - { "Left", 90.f }, - { "Right", -90.f }, - { "Backwards", 180.f } - }; - for (auto& [sYaw, flValue] : vYaws) - { - if (FSelectable(sYaw)) - { - switch (FNV1A::Hash32(sYaw)) + GetWindowDrawList()->AddRectFilled(vDrawPos + vTagPos, { vDrawPos.x + vTagPos.x + flTagWidth, vDrawPos.y + vTagPos.y + flTagHeight }, tTagColor, H::Draw.Scale(4)); + SetCursorPos({ vTagPos.x + H::Draw.Scale(5), vTagPos.y + H::Draw.Scale(3) }); + TextColored(VecToColor(tColor).Blend(tTag.m_tColor).IsColorBright() ? ImVec4(0, 0, 0, 1) : ImVec4(1, 1, 1, 1), tTag.m_sName.c_str()); + if (iID) { - case FNV1A::Hash32Const("Auto"): - F::Resolver.SetYaw(tPlayer.m_iUserID, 0.f, true); - break; - default: - F::Resolver.SetYaw(tPlayer.m_iUserID, flValue); + SetCursorPos({ vTagPos.x + flTagWidth - H::Draw.Scale(22), vTagPos.y - H::Draw.Scale(2) }); + if (IconButton(ICON_MD_CANCEL)) + F::PlayerUtils.RemoveTag(tPlayer.m_uAccountID, iID, true, tPlayer.m_sName.c_str()); + } + + flTagOffset += flTagWidth + H::Draw.Scale(4); + }; + + for (auto& tTag : vLabels) + fDrawTag(tTag, 0); + for (auto& [pTag, iID] : vTags) + fDrawTag(*pTag, iID); + PopFont(); + } EndChild(); + + bPopup = IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right); + } + SetCursorPos(vOriginalPos); + Button(std::format("##{}", tPlayer.m_iUserID).c_str(), { flWidth, flHeight }); + bPopup |= IsItemHovered() && IsMouseReleased(ImGuiMouseButton_Right); + + // popups + if (bPopup) + OpenPopup(std::format("RightClicked{}", tPlayer.m_iUserID).c_str()); + + if (FBeginPopup(std::format("RightClicked{}", tPlayer.m_iUserID).c_str())) + { + PushStyleVar(ImGuiStyleVar_ItemSpacing, { H::Draw.Scale(8), H::Draw.Scale(8) }); + + if (!tPlayer.m_bFake) + { + if (FSelectable("Profile")) + I::SteamFriends->ActivateGameOverlayToUser("steamid", CSteamID(tPlayer.m_uAccountID, k_EUniversePublic, k_EAccountTypeIndividual)); + if (FSelectable("History")) + I::SteamFriends->ActivateGameOverlayToWebPage(std::format("https://steamhistory.net/id/{}", CSteamID(tPlayer.m_uAccountID, k_EUniversePublic, k_EAccountTypeIndividual).ConvertToUint64()).c_str()); + } + + if (FSelectable(F::Spectate.GetTarget(true) == tPlayer.m_iUserID ? "Unspectate" : "Spectate")) + F::Spectate.SetTarget(tPlayer.m_iUserID); + + if (!I::EngineClient->IsPlayingDemo() && FBeginMenu("Votekick")) + { + if (FSelectable("No reason")) + I::ClientState->SendStringCmd(std::format("callvote Kick \"{} other\"", tPlayer.m_iUserID).c_str()); + if (FSelectable("Cheating")) + I::ClientState->SendStringCmd(std::format("callvote Kick \"{} cheating\"", tPlayer.m_iUserID).c_str()); + if (FSelectable("Idle")) + I::ClientState->SendStringCmd(std::format("callvote Kick \"{} idle\"", tPlayer.m_iUserID).c_str()); + if (FSelectable("Scamming")) + I::ClientState->SendStringCmd(std::format("callvote Kick \"{} scamming\"", tPlayer.m_iUserID).c_str()); + + ImGui::EndMenu(); + } + + if (!tPlayer.m_bFake) + { + if (FBeginMenu("Add tag")) + { + for (auto it = F::PlayerUtils.m_vTags.begin(); it != F::PlayerUtils.m_vTags.end(); it++) + { + int iID = std::distance(F::PlayerUtils.m_vTags.begin(), it); + auto& tTag = *it; + if (!tTag.m_bAssignable || F::PlayerUtils.HasTag(tPlayer.m_uAccountID, iID)) + continue; + + auto imColor = ColorToVec(tTag.m_tColor); + PushStyleColor(ImGuiCol_Text, imColor); + imColor.x /= 3; imColor.y /= 3; imColor.z /= 3; + if (FSelectable(tTag.m_sName.c_str(), imColor)) + F::PlayerUtils.AddTag(tPlayer.m_uAccountID, iID, true, tPlayer.m_sName.c_str()); + PopStyleColor(); + } + + ImGui::EndMenu(); + } + if (FBeginMenu("Alias")) + { + bool bHasAlias = F::PlayerUtils.m_mPlayerAliases.contains(tPlayer.m_uAccountID); + static std::string sInput = ""; + + bool bEnter = FInputText("Alias...", sInput, H::Draw.Scale(150), ImGuiInputTextFlags_EnterReturnsTrue); + if (!IsItemFocused()) + sInput = bHasAlias ? F::PlayerUtils.m_mPlayerAliases[tPlayer.m_uAccountID] : ""; + if (bEnter) + { + if (sInput.empty() && bHasAlias) + { + F::Output.AliasChanged(tPlayer.m_sName.c_str(), "Removed", F::PlayerUtils.m_mPlayerAliases[tPlayer.m_uAccountID].c_str()); + + F::PlayerUtils.m_mPlayerAliases.erase(tPlayer.m_uAccountID); + F::PlayerUtils.m_bSave = true; + } + else if (!sInput.empty()) + { + F::PlayerUtils.m_mPlayerAliases[tPlayer.m_uAccountID] = sInput; + F::PlayerUtils.m_bSave = true; + + F::Output.AliasChanged(tPlayer.m_sName.c_str(), bHasAlias ? "Changed" : "Added", sInput.c_str()); } } - } - ImGui::EndMenu(); + ImGui::EndMenu(); + } } - if (FBeginMenu("Set pitch")) + + if (Vars::Resolver::Enabled.Value && !tPlayer.m_bLocal && !I::EngineClient->IsPlayingDemo()) { - static std::vector> vPitches = { - { "Auto", 0.f }, - { "Up", -90.f }, - { "Down", 90.f }, - { "Zero", 0.f }, - { "Inverse", 0.f } - }; - for (auto& [sPitch, flValue] : vPitches) + if (FBeginMenu("Set yaw")) { - if (FSelectable(sPitch)) + static std::vector> vYaws = { + { "Auto", 0.f }, + { "Forward", 0.f }, + { "Left", 90.f }, + { "Right", -90.f }, + { "Backwards", 180.f } + }; + for (auto& [sYaw, flValue] : vYaws) { - switch (FNV1A::Hash32(sPitch)) + if (FSelectable(sYaw)) { - case FNV1A::Hash32Const("Auto"): - F::Resolver.SetPitch(tPlayer.m_iUserID, 0.f, false, true); - break; - case FNV1A::Hash32Const("Inverse"): - F::Resolver.SetPitch(tPlayer.m_iUserID, 0.f, true); - break; - default: - F::Resolver.SetPitch(tPlayer.m_iUserID, flValue); + switch (FNV1A::Hash32(sYaw)) + { + case FNV1A::Hash32Const("Auto"): + F::Resolver.SetYaw(tPlayer.m_iUserID, 0.f, true); + break; + default: + F::Resolver.SetYaw(tPlayer.m_iUserID, flValue); + } } } - } - ImGui::EndMenu(); - } - if (FBeginMenu("Set view")) - { - static std::vector> vPitches = { - { "Offset from static view", true }, - { "Offset from view to local", false } - }; - for (auto& [sPitch, bValue] : vPitches) + ImGui::EndMenu(); + } + if (FBeginMenu("Set pitch")) { - if (FSelectable(sPitch)) - F::Resolver.SetView(tPlayer.m_iUserID, bValue); - } + static std::vector> vPitches = { + { "Auto", 0.f }, + { "Up", -90.f }, + { "Down", 90.f }, + { "Zero", 0.f }, + { "Inverse", 0.f } + }; + for (auto& [sPitch, flValue] : vPitches) + { + if (FSelectable(sPitch)) + { + switch (FNV1A::Hash32(sPitch)) + { + case FNV1A::Hash32Const("Auto"): + F::Resolver.SetPitch(tPlayer.m_iUserID, 0.f, false, true); + break; + case FNV1A::Hash32Const("Inverse"): + F::Resolver.SetPitch(tPlayer.m_iUserID, 0.f, true); + break; + default: + F::Resolver.SetPitch(tPlayer.m_iUserID, flValue); + } + } + } - ImGui::EndMenu(); - } - if (FBeginMenu("Set minwalk")) - { - static std::vector> vPitches = { - { "Minwalk on", true }, - { "Minwalk off", false } - }; - for (auto& [sPitch, bValue] : vPitches) + ImGui::EndMenu(); + } + if (FBeginMenu("Set view")) { - if (FSelectable(sPitch)) - F::Resolver.SetMinwalk(tPlayer.m_iUserID, bValue); + static std::vector> vPitches = { + { "Offset from static view", true }, + { "Offset from view to local", false } + }; + for (auto& [sPitch, bValue] : vPitches) + { + if (FSelectable(sPitch)) + F::Resolver.SetView(tPlayer.m_iUserID, bValue); + } + + ImGui::EndMenu(); } + if (FBeginMenu("Set minwalk")) + { + static std::vector> vPitches = { + { "Minwalk on", true }, + { "Minwalk off", false } + }; + for (auto& [sPitch, bValue] : vPitches) + { + if (FSelectable(sPitch)) + F::Resolver.SetMinwalk(tPlayer.m_iUserID, bValue); + } - ImGui::EndMenu(); + ImGui::EndMenu(); + } } - } - if (mParties.contains(tPlayer.m_iParty)) - { - Divider(H::Draw.Scale(1), 0); - - TextColored(F::Render.Inactive.Value, "Partied:"); - for (auto& pPlayer2 : mParties[tPlayer.m_iParty]) - TextColored(F::Render.Inactive.Value, pPlayer2->m_sName.c_str()); - } - - if (tPlayer.m_iLevel != -2) - { - Divider(H::Draw.Scale(1), 0); - - std::string sLevel = "T? L?"; - if (tPlayer.m_iLevel != -1) + if (mParties.contains(tPlayer.m_iParty)) { - int iTier = std::max(ceilf(tPlayer.m_iLevel / 150.f), 1.f); - int iLevel = ((tPlayer.m_iLevel - 1) % 150) + 1; - sLevel = std::format("T{} L{}", iTier, iLevel); - } - TextColored(F::Render.Inactive.Value, sLevel.c_str()); - } + Divider(H::Draw.Scale(1), 0); - PopStyleVar(); - EndPopup(); - } - }; + TextColored(F::Render.Inactive.Value, "Partied:"); + for (auto& pPlayer2 : mParties[tPlayer.m_iParty]) + TextColored(F::Render.Inactive.Value, pPlayer2->m_sName.c_str()); + } + + if (tPlayer.m_iLevel != -2) + { + Divider(H::Draw.Scale(1), 0); + + std::string sLevel = "T? L?"; + if (tPlayer.m_iLevel != -1) + { + int iTier = std::max(ceilf(tPlayer.m_iLevel / 150.f), 1.f); + int iLevel = ((tPlayer.m_iLevel - 1) % 150) + 1; + sLevel = std::format("T{} L{}", iTier, iLevel); + } + TextColored(F::Render.Inactive.Value, sLevel.c_str()); + } + + PopStyleVar(); + EndPopup(); + } + }; // display players std::vector vBlu, vRed, vOther; @@ -1716,155 +1721,155 @@ void CMenu::MenuLogs(int iTab) } EndChild(); auto fDrawTag = [](std::vector::iterator it, PriorityLabel_t& _tTag, int y) - { - int _iID = std::distance(F::PlayerUtils.m_vTags.begin(), it); - - ImVec2 vOriginalPos = { !_tTag.m_bLabel ? GetStyle().WindowPadding.x : GetWindowWidth() * 2 / 3 + GetStyle().WindowPadding.x / 2, H::Draw.Scale(96 + 36 * y) }; - - // background - float flWidth = GetWindowWidth() * (_tTag.m_bLabel ? 1.f / 3 : 2.f / 3) - GetStyle().WindowPadding.x * 1.5f; - float flHeight = H::Draw.Scale(28); - ImColor tColor = ColorToVec(_tTag.m_tColor.Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha)); - ImVec2 vDrawPos = GetDrawPos() + vOriginalPos; - if (iID != _iID) - GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor, H::Draw.Scale(4)); - else { - ImColor tColor2 = { tColor.Value.x * 1.1f, tColor.Value.y * 1.1f, tColor.Value.z * 1.1f, tColor.Value.w }; - GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor2, H::Draw.Scale(4)); + int _iID = std::distance(F::PlayerUtils.m_vTags.begin(), it); - tColor2 = ColorToVec(_tTag.m_tColor.Lerp(Vars::Menu::Theme::Background.Value, 0.25f, LerpEnum::NoAlpha)); - float flInset = H::Draw.Scale(0.5f) - 0.5f; - GetWindowDrawList()->AddRect({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x - flInset + flWidth, vDrawPos.y - flInset + flHeight }, tColor2, H::Draw.Scale(4), ImDrawFlags_None, H::Draw.Scale()); - } + ImVec2 vOriginalPos = { !_tTag.m_bLabel ? GetStyle().WindowPadding.x : GetWindowWidth() * 2 / 3 + GetStyle().WindowPadding.x / 2, H::Draw.Scale(96 + 36 * y) }; - // text - SetCursorPos({ vOriginalPos.x + H::Draw.Scale(9), vOriginalPos.y + H::Draw.Scale(7) }); - FText(TruncateText(_tTag.m_sName, _tTag.m_bLabel ? flWidth - H::Draw.Scale(38) : flWidth / 2 - H::Draw.Scale(20)).c_str()); - - if (!_tTag.m_bLabel) - { - SetCursorPos({ vOriginalPos.x + flWidth / 2, vOriginalPos.y + H::Draw.Scale(7) }); - FText(std::format("{}", _tTag.m_iPriority).c_str()); - } - - // buttons / icons - bool bDelete = false; - if (!_tTag.m_bLocked) - { - SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(26), vOriginalPos.y + H::Draw.Scale(2) }); - bDelete = IconButton(ICON_MD_DELETE); - } - else - { - SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(22), vOriginalPos.y + H::Draw.Scale(6) }); - switch (F::PlayerUtils.IndexToTag(_iID)) + // background + float flWidth = GetWindowWidth() * (_tTag.m_bLabel ? 1.f / 3 : 2.f / 3) - GetStyle().WindowPadding.x * 1.5f; + float flHeight = H::Draw.Scale(28); + ImColor tColor = ColorToVec(_tTag.m_tColor.Lerp(Vars::Menu::Theme::Background.Value, 0.5f, LerpEnum::NoAlpha)); + ImVec2 vDrawPos = GetDrawPos() + vOriginalPos; + if (iID != _iID) + GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor, H::Draw.Scale(4)); + else { - //case DEFAULT_TAG: // no image - case IGNORED_TAG: IconImage(ICON_MD_DO_NOT_DISTURB); break; - case CHEATER_TAG: IconImage(ICON_MD_FLAG); break; - case FRIEND_TAG: IconImage(ICON_MD_GROUP); break; - case PARTY_TAG: IconImage(ICON_MD_GROUPS); break; - case F2P_TAG: IconImage(ICON_MD_MONEY_OFF); break; + ImColor tColor2 = { tColor.Value.x * 1.1f, tColor.Value.y * 1.1f, tColor.Value.z * 1.1f, tColor.Value.w }; + GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor2, H::Draw.Scale(4)); + + tColor2 = ColorToVec(_tTag.m_tColor.Lerp(Vars::Menu::Theme::Background.Value, 0.25f, LerpEnum::NoAlpha)); + float flInset = H::Draw.Scale(0.5f) - 0.5f; + GetWindowDrawList()->AddRect({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x - flInset + flWidth, vDrawPos.y - flInset + flHeight }, tColor2, H::Draw.Scale(4), ImDrawFlags_None, H::Draw.Scale()); } - } - SetCursorPos(vOriginalPos); - bool bClicked = Button(std::format("##{}", _tTag.m_sName).c_str(), { flWidth, flHeight }); - bool bPopup = IsItemClicked(ImGuiMouseButton_Right); - - if (bClicked) - { - iID = _iID; - tTag.m_sName = _tTag.m_sName; - tTag.m_tColor = _tTag.m_tColor; - tTag.m_iPriority = _tTag.m_iPriority; - tTag.m_bLabel = _tTag.m_bLabel; - } - else if (bPopup) - OpenPopup(std::format("RightClicked{}", _iID).c_str()); - else if (bDelete) - OpenPopup(std::format("DeleteTag{}", _iID).c_str()); - - if (FBeginPopup(std::format("RightClicked{}", _iID).c_str())) - { - PushStyleVar(ImGuiStyleVar_ItemSpacing, { H::Draw.Scale(8), 0 }); - - auto& _tTag2 = *it; - bool bSave = false; + // text + SetCursorPos({ vOriginalPos.x + H::Draw.Scale(9), vOriginalPos.y + H::Draw.Scale(7) }); + FText(TruncateText(_tTag.m_sName, _tTag.m_bLabel ? flWidth - H::Draw.Scale(38) : flWidth / 2 - H::Draw.Scale(20)).c_str()); + if (!_tTag.m_bLabel) { - static std::string sInput = ""; + SetCursorPos({ vOriginalPos.x + flWidth / 2, vOriginalPos.y + H::Draw.Scale(7) }); + FText(std::format("{}", _tTag.m_iPriority).c_str()); + } - bool bEnter = FInputText("Name...", sInput, H::Draw.Scale(284), ImGuiInputTextFlags_EnterReturnsTrue); - if (!IsItemFocused()) - sInput = _tTag2.m_sName; - if (bEnter) + // buttons / icons + bool bDelete = false; + if (!_tTag.m_bLocked) + { + SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(26), vOriginalPos.y + H::Draw.Scale(2) }); + bDelete = IconButton(ICON_MD_DELETE); + } + else + { + SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(22), vOriginalPos.y + H::Draw.Scale(6) }); + switch (F::PlayerUtils.IndexToTag(_iID)) { - _tTag2.m_sName = sInput; - bSave = true; + //case DEFAULT_TAG: // no image + case IGNORED_TAG: IconImage(ICON_MD_DO_NOT_DISTURB); break; + case CHEATER_TAG: IconImage(ICON_MD_FLAG); break; + case FRIEND_TAG: IconImage(ICON_MD_GROUP); break; + case PARTY_TAG: IconImage(ICON_MD_GROUPS); break; + case F2P_TAG: IconImage(ICON_MD_MONEY_OFF); break; } } - PushDisabled(_iID == DEFAULT_TAG || _iID == IGNORED_TAG); + SetCursorPos(vOriginalPos); + bool bClicked = Button(std::format("##{}", _tTag.m_sName).c_str(), { flWidth, flHeight }); + bool bPopup = IsItemClicked(ImGuiMouseButton_Right); + + if (bClicked) { - int iLabel = Disabled ? 0 : _tTag2.m_bLabel; - if (FDropdown("Type##", &iLabel, { "Priority", "Label" })) - bSave = true; - _tTag2.m_bLabel = iLabel; - if (Disabled) - _tTag2.m_bLabel = false; + iID = _iID; + tTag.m_sName = _tTag.m_sName; + tTag.m_tColor = _tTag.m_tColor; + tTag.m_iPriority = _tTag.m_iPriority; + tTag.m_bLabel = _tTag.m_bLabel; } - PopDisabled(); - if (FSlider("Priority##", &_tTag2.m_iPriority, -10, 10)) - bSave = true; + else if (bPopup) + OpenPopup(std::format("RightClicked{}", _iID).c_str()); + else if (bDelete) + OpenPopup(std::format("DeleteTag{}", _iID).c_str()); - if (bSave) - F::PlayerUtils.m_bSave = true; - - PopStyleVar(); - EndPopup(); - } - else if (FBeginPopupModal(std::format("DeleteTag{}", _iID).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) - { - FText(std::format("Do you really want to delete '{}'?", _tTag.m_sName).c_str()); - - if (FButton("Yes", FButtonEnum::Left)) + if (FBeginPopup(std::format("RightClicked{}", _iID).c_str())) { - F::PlayerUtils.m_vTags.erase(it); - F::PlayerUtils.m_bSave = F::PlayerUtils.m_bSave = true; + PushStyleVar(ImGuiStyleVar_ItemSpacing, { H::Draw.Scale(8), 0 }); + + auto& _tTag2 = *it; + bool bSave = false; - for (auto& vTags : F::PlayerUtils.m_mPlayerTags | std::views::values) { - for (auto it = vTags.begin(); it != vTags.end();) + static std::string sInput = ""; + + bool bEnter = FInputText("Name...", sInput, H::Draw.Scale(284), ImGuiInputTextFlags_EnterReturnsTrue); + if (!IsItemFocused()) + sInput = _tTag2.m_sName; + if (bEnter) { - if (_iID == *it) - vTags.erase(it); - else - { - if (_iID < *it) - (*it)--; - it++; - } + _tTag2.m_sName = sInput; + bSave = true; } } - if (iID == _iID) + PushDisabled(_iID == DEFAULT_TAG || _iID == IGNORED_TAG); { - iID = -1; - tTag = {}; + int iLabel = Disabled ? 0 : _tTag2.m_bLabel; + if (FDropdown("Type##", &iLabel, { "Priority", "Label" })) + bSave = true; + _tTag2.m_bLabel = iLabel; + if (Disabled) + _tTag2.m_bLabel = false; } - else if (iID > _iID) - iID--; + PopDisabled(); + if (FSlider("Priority##", &_tTag2.m_iPriority, -10, 10)) + bSave = true; - CloseCurrentPopup(); + if (bSave) + F::PlayerUtils.m_bSave = true; + + PopStyleVar(); + EndPopup(); } - if (FButton("No", FButtonEnum::Right | FButtonEnum::SameLine)) - CloseCurrentPopup(); + else if (FBeginPopupModal(std::format("DeleteTag{}", _iID).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + FText(std::format("Do you really want to delete '{}'?", _tTag.m_sName).c_str()); - EndPopup(); - } - }; + if (FButton("Yes", FButtonEnum::Left)) + { + F::PlayerUtils.m_vTags.erase(it); + F::PlayerUtils.m_bSave = F::PlayerUtils.m_bSave = true; + + for (auto& vTags : F::PlayerUtils.m_mPlayerTags | std::views::values) + { + for (auto it = vTags.begin(); it != vTags.end();) + { + if (_iID == *it) + vTags.erase(it); + else + { + if (_iID < *it) + (*it)--; + it++; + } + } + } + + if (iID == _iID) + { + iID = -1; + tTag = {}; + } + else if (iID > _iID) + iID--; + + CloseCurrentPopup(); + } + if (FButton("No", FButtonEnum::Right | FButtonEnum::SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + }; PushStyleColor(ImGuiCol_Text, F::Render.Inactive.Value); SetCursorPos({ H::Draw.Scale(13), H::Draw.Scale(80) }); FText("Priorities"); @@ -1883,27 +1888,27 @@ void CMenu::MenuLogs(int iTab) } std::sort(vPriorities.begin(), vPriorities.end(), [&](const auto& a, const auto& b) -> bool - { - // override for default tag - if (std::distance(F::PlayerUtils.m_vTags.begin(), a.first) == DEFAULT_TAG) - return true; - if (std::distance(F::PlayerUtils.m_vTags.begin(), b.first) == DEFAULT_TAG) - return false; + { + // override for default tag + if (std::distance(F::PlayerUtils.m_vTags.begin(), a.first) == DEFAULT_TAG) + return true; + if (std::distance(F::PlayerUtils.m_vTags.begin(), b.first) == DEFAULT_TAG) + return false; - // sort by priority if unequal - if (a.second.m_iPriority != b.second.m_iPriority) - return a.second.m_iPriority > b.second.m_iPriority; + // sort by priority if unequal + if (a.second.m_iPriority != b.second.m_iPriority) + return a.second.m_iPriority > b.second.m_iPriority; - return a.second.m_sName < b.second.m_sName; - }); + return a.second.m_sName < b.second.m_sName; + }); std::sort(vLabels.begin(), vLabels.end(), [&](const auto& a, const auto& b) -> bool - { - // sort by priority if unequal - if (a.second.m_iPriority != b.second.m_iPriority) - return a.second.m_iPriority > b.second.m_iPriority; + { + // sort by priority if unequal + if (a.second.m_iPriority != b.second.m_iPriority) + return a.second.m_iPriority > b.second.m_iPriority; - return a.second.m_sName < b.second.m_sName; - }); + return a.second.m_sName < b.second.m_sName; + }); // display tags int iPriorities = 0, iLabels = 0; @@ -2331,7 +2336,7 @@ void CMenu::MenuSettings(int iTab) switch (iTab) { - // Settings + // Settings case 0: { if (BeginTable("ConfigSettingsTable", 2)) @@ -2349,152 +2354,152 @@ void CMenu::MenuSettings(int iTab) */ auto fDrawConfigs = [](std::string& sStaticName, bool bVisual = false) - { - auto& sPath = !bVisual ? F::Configs.m_sConfigPath : F::Configs.m_sVisualsPath; - auto& sConfig = !bVisual ? F::Configs.m_sCurrentConfig : F::Configs.m_sCurrentVisuals; - auto sType = !bVisual ? "Config" : "Visual"; - bool bNoSave = GetAsyncKeyState(VK_SHIFT) & 0x8000; - - FSDropdown("Name", &sStaticName, {}, FSDropdownEnum::AutoUpdate, -H::Draw.Unscale(FCalcTextSize("CREATE").x + FCalcTextSize("FOLDER").x) - 72); - PushDisabled(sStaticName.empty()); { - if (FButton("Create", FButtonEnum::Fit | FButtonEnum::SameLine, { 0, 40 })) + auto& sPath = !bVisual ? F::Configs.m_sConfigPath : F::Configs.m_sVisualsPath; + auto& sConfig = !bVisual ? F::Configs.m_sCurrentConfig : F::Configs.m_sCurrentVisuals; + auto sType = !bVisual ? "Config" : "Visual"; + bool bNoSave = GetAsyncKeyState(VK_SHIFT) & 0x8000; + + FSDropdown("Name", &sStaticName, {}, FSDropdownEnum::AutoUpdate, -H::Draw.Unscale(FCalcTextSize("CREATE").x + FCalcTextSize("FOLDER").x) - 72); + PushDisabled(sStaticName.empty()); { - if (!std::filesystem::exists(sPath + sStaticName)) + if (FButton("Create", FButtonEnum::Fit | FButtonEnum::SameLine, { 0, 40 })) { - if (!bVisual) - F::Configs.SaveConfig(sStaticName); - else - F::Configs.SaveVisual(sStaticName); + if (!std::filesystem::exists(sPath + sStaticName)) + { + if (!bVisual) + F::Configs.SaveConfig(sStaticName); + else + F::Configs.SaveVisual(sStaticName); + } + sStaticName.clear(); } - sStaticName.clear(); } - } - PopDisabled(); - if (FButton("Folder", FButtonEnum::Fit | FButtonEnum::SameLine, { 0, 40 })) - ShellExecuteA(NULL, NULL, sPath.c_str(), NULL, NULL, SW_SHOWNORMAL); - vRowSizes.clear(); + PopDisabled(); + if (FButton("Folder", FButtonEnum::Fit | FButtonEnum::SameLine, { 0, 40 })) + ShellExecuteA(NULL, NULL, sPath.c_str(), NULL, NULL, SW_SHOWNORMAL); + vRowSizes.clear(); - std::vector> vConfigs = {}; - bool bDefaultFound = false; - for (auto& tEntry : std::filesystem::directory_iterator(sPath)) - { - if (!tEntry.is_regular_file() || tEntry.path().extension() != F::Configs.m_sConfigExtension) - continue; - - std::string sName = tEntry.path().filename().string(); - sName.erase(sName.end() - F::Configs.m_sConfigExtension.size(), sName.end()); - if (FNV1A::Hash32(sName.c_str()) == FNV1A::Hash32Const("default")) - bDefaultFound = true; - - vConfigs.emplace_back(tEntry, sName); - } - if (!bVisual) - { - if (!bDefaultFound) - F::Configs.SaveConfig("default"); - std::sort(vConfigs.begin(), vConfigs.end(), [&](const auto& a, const auto& b) -> bool + std::vector> vConfigs = {}; + bool bDefaultFound = false; + for (auto& tEntry : std::filesystem::directory_iterator(sPath)) { - // override for default config - if (FNV1A::Hash32(a.second.c_str()) == FNV1A::Hash32Const("default")) - return true; - if (FNV1A::Hash32(b.second.c_str()) == FNV1A::Hash32Const("default")) - return false; + if (!tEntry.is_regular_file() || tEntry.path().extension() != F::Configs.m_sConfigExtension) + continue; - return a.second < b.second; - }); - } + std::string sName = tEntry.path().filename().string(); + sName.erase(sName.end() - F::Configs.m_sConfigExtension.size(), sName.end()); + if (FNV1A::Hash32(sName.c_str()) == FNV1A::Hash32Const("default")) + bDefaultFound = true; - for (auto& [entry, sConfigName] : vConfigs) - { - bool bCurrentConfig = FNV1A::Hash32(sConfigName.c_str()) == FNV1A::Hash32(sConfig.c_str()); - ImVec2 vOriginalPos = GetCursorPos(); - - SetCursorPos({ vOriginalPos.x + H::Draw.Scale(2), vOriginalPos.y + H::Draw.Scale(9) }); - bool bLoad = IconButton(bCurrentConfig ? ICON_MD_REFRESH : ICON_MD_DOWNLOAD); - FTooltip(ICON_MD_ADD ICON_MD_FILE_UPLOAD_OFF, bNoSave && IsItemHovered(), 300.f, F::Render.IconFont); - - SetCursorPos({ H::Draw.Scale(43), vOriginalPos.y + H::Draw.Scale(14) }); - TextColored(bCurrentConfig ? F::Render.Active.Value : F::Render.Inactive.Value, TruncateText(sConfigName, GetWindowWidth() - GetStyle().WindowPadding.x * 2 - H::Draw.Scale(80)).c_str()); - - int iOffset = 9; - SetCursorPos({ GetWindowWidth() - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(9) }); - bool bDelete = IconButton(ICON_MD_DELETE); - - SetCursorPos({ GetWindowWidth() - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(9) }); - bool bSave = IconButton(ICON_MD_SAVE); - FTooltip(ICON_MD_ADD ICON_MD_FILE_DOWNLOAD_OFF, bNoSave && IsItemHovered(), 300.f, F::Render.IconFont); - - if (bLoad) - { - if (!bVisual) - F::Configs.LoadConfig(sConfigName); - else - F::Configs.LoadVisual(sConfigName); + vConfigs.emplace_back(tEntry, sName); } - else if (bSave) + if (!bVisual) { - if (!bCurrentConfig || !bVisual && !F::Configs.m_sCurrentVisuals.empty()) - OpenPopup(std::format("Save{}{}", sType, sConfigName).c_str()); - else if (!bVisual) - F::Configs.SaveConfig(sConfigName); - else - F::Configs.SaveVisual(sConfigName); + if (!bDefaultFound) + F::Configs.SaveConfig("default"); + std::sort(vConfigs.begin(), vConfigs.end(), [&](const auto& a, const auto& b) -> bool + { + // override for default config + if (FNV1A::Hash32(a.second.c_str()) == FNV1A::Hash32Const("default")) + return true; + if (FNV1A::Hash32(b.second.c_str()) == FNV1A::Hash32Const("default")) + return false; + + return a.second < b.second; + }); } - else if (bDelete) - OpenPopup(std::format("Remove{}{}", sType, sConfigName).c_str()); - if (FBeginPopupModal(std::format("Save{}{}", sType, sConfigName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + for (auto& [entry, sConfigName] : vConfigs) { - FText(std::format("Do you really want to override '{}'?", sConfigName).c_str()); + bool bCurrentConfig = FNV1A::Hash32(sConfigName.c_str()) == FNV1A::Hash32(sConfig.c_str()); + ImVec2 vOriginalPos = GetCursorPos(); - if (FButton("Yes, override", FButtonEnum::Left)) + SetCursorPos({ vOriginalPos.x + H::Draw.Scale(2), vOriginalPos.y + H::Draw.Scale(9) }); + bool bLoad = IconButton(bCurrentConfig ? ICON_MD_REFRESH : ICON_MD_DOWNLOAD); + FTooltip(ICON_MD_ADD ICON_MD_FILE_UPLOAD_OFF, bNoSave && IsItemHovered(), 300.f, F::Render.IconFont); + + SetCursorPos({ H::Draw.Scale(43), vOriginalPos.y + H::Draw.Scale(14) }); + TextColored(bCurrentConfig ? F::Render.Active.Value : F::Render.Inactive.Value, TruncateText(sConfigName, GetWindowWidth() - GetStyle().WindowPadding.x * 2 - H::Draw.Scale(80)).c_str()); + + int iOffset = 9; + SetCursorPos({ GetWindowWidth() - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(9) }); + bool bDelete = IconButton(ICON_MD_DELETE); + + SetCursorPos({ GetWindowWidth() - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(9) }); + bool bSave = IconButton(ICON_MD_SAVE); + FTooltip(ICON_MD_ADD ICON_MD_FILE_DOWNLOAD_OFF, bNoSave && IsItemHovered(), 300.f, F::Render.IconFont); + + if (bLoad) { if (!bVisual) + F::Configs.LoadConfig(sConfigName); + else + F::Configs.LoadVisual(sConfigName); + } + else if (bSave) + { + if (!bCurrentConfig || !bVisual && !F::Configs.m_sCurrentVisuals.empty()) + OpenPopup(std::format("Save{}{}", sType, sConfigName).c_str()); + else if (!bVisual) F::Configs.SaveConfig(sConfigName); else F::Configs.SaveVisual(sConfigName); - CloseCurrentPopup(); } - if (FButton("No", FButtonEnum::Right | FButtonEnum::SameLine)) - CloseCurrentPopup(); + else if (bDelete) + OpenPopup(std::format("Remove{}{}", sType, sConfigName).c_str()); - EndPopup(); - } - else if (FBeginPopupModal(std::format("Remove{}{}", sType, sConfigName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) - { - FText(std::format("Do you really want to remove '{}'?", sConfigName).c_str()); - - PushDisabled(!bVisual && FNV1A::Hash32(sConfigName.c_str()) == FNV1A::Hash32Const("default")); + if (FBeginPopupModal(std::format("Save{}{}", sType, sConfigName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { - if (FButton("Yes, delete", FButtonEnum::Fit)) + FText(std::format("Do you really want to override '{}'?", sConfigName).c_str()); + + if (FButton("Yes, override", FButtonEnum::Left)) { if (!bVisual) - F::Configs.DeleteConfig(sConfigName); + F::Configs.SaveConfig(sConfigName); else - F::Configs.DeleteVisual(sConfigName); + F::Configs.SaveVisual(sConfigName); CloseCurrentPopup(); } + if (FButton("No", FButtonEnum::Right | FButtonEnum::SameLine)) + CloseCurrentPopup(); + + EndPopup(); } - PopDisabled(); - if (FButton("Yes, reset", FButtonEnum::Fit | FButtonEnum::SameLine)) + else if (FBeginPopupModal(std::format("Remove{}{}", sType, sConfigName).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) { - if (!bVisual) - F::Configs.ResetConfig(sConfigName); - else - F::Configs.ResetVisual(sConfigName); - CloseCurrentPopup(); + FText(std::format("Do you really want to remove '{}'?", sConfigName).c_str()); + + PushDisabled(!bVisual && FNV1A::Hash32(sConfigName.c_str()) == FNV1A::Hash32Const("default")); + { + if (FButton("Yes, delete", FButtonEnum::Fit)) + { + if (!bVisual) + F::Configs.DeleteConfig(sConfigName); + else + F::Configs.DeleteVisual(sConfigName); + CloseCurrentPopup(); + } + } + PopDisabled(); + if (FButton("Yes, reset", FButtonEnum::Fit | FButtonEnum::SameLine)) + { + if (!bVisual) + F::Configs.ResetConfig(sConfigName); + else + F::Configs.ResetVisual(sConfigName); + CloseCurrentPopup(); + } + if (FButton("No", FButtonEnum::Fit | FButtonEnum::SameLine)) + CloseCurrentPopup(); + + EndPopup(); } - if (FButton("No", FButtonEnum::Fit | FButtonEnum::SameLine)) - CloseCurrentPopup(); - EndPopup(); + SetCursorPos(vOriginalPos); DebugDummy({ 0, H::Draw.Scale(28) }); } - - SetCursorPos(vOriginalPos); DebugDummy({ 0, H::Draw.Scale(28) }); - } - DebugDummy({ 0, H::Draw.Scale(7) }); - }; + DebugDummy({ 0, H::Draw.Scale(7) }); + }; /* Column 1 */ TableNextColumn(); @@ -2618,38 +2623,38 @@ void CMenu::MenuSettings(int iTab) PopStyleColor(); auto fNumberToIndex = [](int iNumber, int iLayer) - { - int iIndex = -1, i = -1; - - std::unordered_map mBinds = {}; - std::function fGetBinds = [&](int iParent) { - for (int _iBind = 0; _iBind < F::Binds.m_vBinds.size(); _iBind++) - { - auto& _tBind = F::Binds.m_vBinds[_iBind]; - if (iParent != _tBind.m_iParent || mBinds.contains(_iBind)) - continue; + int iIndex = -1, i = -1; - mBinds[_iBind]; + std::unordered_map mBinds = {}; + std::function fGetBinds = [&](int iParent) + { + for (int _iBind = 0; _iBind < F::Binds.m_vBinds.size(); _iBind++) + { + auto& _tBind = F::Binds.m_vBinds[_iBind]; + if (iParent != _tBind.m_iParent || mBinds.contains(_iBind)) + continue; - i++; - //if (iParent == iLayer && iNumber >= i) - if (iIndex == -1 && iParent == iLayer && iNumber <= i) - iIndex = _iBind; - fGetBinds(_iBind); - } + mBinds[_iBind]; + + i++; + //if (iParent == iLayer && iNumber >= i) + if (iIndex == -1 && iParent == iLayer && iNumber <= i) + iIndex = _iBind; + fGetBinds(_iBind); + } + }; + fGetBinds(DEFAULT_BIND); + + return iIndex; }; - fGetBinds(DEFAULT_BIND); - - return iIndex; - }; auto fPositionToIndex = [&](ImVec2 vPos, int iLayer = DEFAULT_BIND) - { - int iIndex = floorf((vPos.y - GetCursorPosY() - H::Draw.Scale(4)) / H::Draw.Scale(36)); - iIndex = std::clamp(iIndex, 0, int(F::Binds.m_vBinds.size() - 1)); - iIndex = fNumberToIndex(iIndex, iLayer); - return iIndex; - }; + { + int iIndex = floorf((vPos.y - GetCursorPosY() - H::Draw.Scale(4)) / H::Draw.Scale(36)); + iIndex = std::clamp(iIndex, 0, int(F::Binds.m_vBinds.size() - 1)); + iIndex = fNumberToIndex(iIndex, iLayer); + return iIndex; + }; static int iDragging = -1, iLayer = DEFAULT_BIND; if (!IsMouseDown(ImGuiMouseButton_Left)) @@ -2666,239 +2671,239 @@ void CMenu::MenuSettings(int iTab) std::unordered_map mBinds = {}; std::function fGetBinds = [&](int iParent, int x) - { - for (int _iBind = 0; _iBind < F::Binds.m_vBinds.size(); _iBind++) { - auto& _tBind = F::Binds.m_vBinds[_iBind]; - if (iParent != DEFAULT_BIND - 1 && iParent != _tBind.m_iParent || mBinds.contains(_iBind)) - continue; - - mBinds[_iBind]; - - std::string sType; std::string sInfo; - switch (_tBind.m_iType) + for (int _iBind = 0; _iBind < F::Binds.m_vBinds.size(); _iBind++) { - case BindEnum::Key: - switch (_tBind.m_iInfo) - { - case BindEnum::KeyEnum::Hold: { sType = "hold"; break; } - case BindEnum::KeyEnum::Toggle: { sType = "toggle"; break; } - case BindEnum::KeyEnum::DoubleClick: { sType = "double"; break; } - } - sInfo = VK2STR(_tBind.m_iKey); - break; - case BindEnum::Class: - sType = "class"; - switch (_tBind.m_iInfo) - { - case BindEnum::ClassEnum::Scout: { sInfo = "scout"; break; } - case BindEnum::ClassEnum::Soldier: { sInfo = "soldier"; break; } - case BindEnum::ClassEnum::Pyro: { sInfo = "pyro"; break; } - case BindEnum::ClassEnum::Demoman: { sInfo = "demoman"; break; } - case BindEnum::ClassEnum::Heavy: { sInfo = "heavy"; break; } - case BindEnum::ClassEnum::Engineer: { sInfo = "engineer"; break; } - case BindEnum::ClassEnum::Medic: { sInfo = "medic"; break; } - case BindEnum::ClassEnum::Sniper: { sInfo = "sniper"; break; } - case BindEnum::ClassEnum::Spy: { sInfo = "spy"; break; } - } - break; - case BindEnum::WeaponType: - sType = "weapon"; - switch (_tBind.m_iInfo) - { - case BindEnum::WeaponTypeEnum::Hitscan: { sInfo = "hitscan"; break; } - case BindEnum::WeaponTypeEnum::Projectile: { sInfo = "projectile"; break; } - case BindEnum::WeaponTypeEnum::Melee: { sInfo = "melee"; break; } - case BindEnum::WeaponTypeEnum::Throwable: { sInfo = "throwable"; break; } - } - break; - case BindEnum::ItemSlot: - sType = "slot"; - sInfo = std::format("{}", _tBind.m_iInfo + 1); - break; - case BindEnum::Misc: - switch (_tBind.m_iInfo) - { - case BindEnum::MiscEnum::Spectated: - case BindEnum::MiscEnum::SpectatedFirst: - case BindEnum::MiscEnum::SpectatedThird: - sType = "spectated"; - switch (_tBind.m_iInfo) - { - case BindEnum::MiscEnum::Spectated: { sInfo = "any"; break; } - case BindEnum::MiscEnum::SpectatedFirst: { sInfo = "1st"; break; } - case BindEnum::MiscEnum::SpectatedThird: { sInfo = "3rd"; break; } - } - break; - case BindEnum::MiscEnum::Zoomed: - case BindEnum::MiscEnum::Aiming: - sType = "cond"; - switch (_tBind.m_iInfo) - { - case BindEnum::MiscEnum::Zoomed: { sInfo = "zoomed"; break; } - case BindEnum::MiscEnum::Aiming: { sInfo = "aiming"; break; } - } - break; - } - break; - } - if (_tBind.m_bNot && (_tBind.m_iType != BindEnum::Key || _tBind.m_iInfo == BindEnum::KeyEnum::Hold)) - sType = std::format("not {}", sType); + auto& _tBind = F::Binds.m_vBinds[_iBind]; + if (iParent != DEFAULT_BIND - 1 && iParent != _tBind.m_iParent || mBinds.contains(_iBind)) + continue; - ImVec2 vOriginalPos = { H::Draw.Scale(8) + H::Draw.Scale(28) * std::min(x, 3), GetCursorPosY() + H::Draw.Scale(8) }; + mBinds[_iBind]; - // background - float flWidth = GetWindowWidth() - GetStyle().WindowPadding.x * 2 - H::Draw.Scale(28) * std::min(x, 3); - float flHeight = H::Draw.Scale(28); - ImVec2 vDrawPos = GetDrawPos() + vOriginalPos; - if (iBind != _iBind) - GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, F::Render.Background1p5, H::Draw.Scale(4)); - else - { - ImColor tColor = F::Render.Background1p5L; - GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor, H::Draw.Scale(4)); - - tColor = ColorToVec((VecToColor(F::Render.Background1p5)).Lerp({ 127, 127, 127 }, 1.f / 9, LerpEnum::NoAlpha)); - float flInset = H::Draw.Scale(0.5f) - 0.5f; - GetWindowDrawList()->AddRect({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x - flInset + flWidth, vDrawPos.y - flInset + flHeight }, tColor, H::Draw.Scale(4), ImDrawFlags_None, H::Draw.Scale()); - } - - // text - if (x > 3) - { // don't indent too much - auto sText = std::format("-> {}", x); - SetCursorPos({ vOriginalPos.x - FCalcTextSize(sText.c_str()).x - H::Draw.Scale(10), vOriginalPos.y + H::Draw.Scale(7) }); - FText(sText.c_str()); - } - - float flTextWidth = flWidth - H::Draw.Scale(127); - PushTransparent(!F::Binds.WillBeEnabled(_iBind), true); - - SetCursorPos({ vOriginalPos.x + H::Draw.Scale(9), vOriginalPos.y + H::Draw.Scale(7) }); - FText(TruncateText(_tBind.m_sName, flTextWidth * (1.f / 3) - H::Draw.Scale(20)).c_str()); - - SetCursorPos({ vOriginalPos.x + flTextWidth * (1.f / 3), vOriginalPos.y + H::Draw.Scale(7) }); - FText(sType.c_str()); - - SetCursorPos({ vOriginalPos.x + flTextWidth * (2.f / 3), vOriginalPos.y + H::Draw.Scale(7) }); - FText(sInfo.c_str()); - - // buttons - int iOffset = 1; - - SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); - bool bDelete = IconButton(ICON_MD_DELETE); - - SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); - if (IconButton(ICON_MD_EDIT)) - CurrentBind = CurrentBind != _iBind ? _iBind : DEFAULT_BIND; - - SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); - if (IconButton(!_tBind.m_bNot ? ICON_MD_CODE : ICON_MD_CODE_OFF)) - _tBind.m_bNot = !_tBind.m_bNot; - - PushTransparent(Transparent || _tBind.m_iVisibility == BindVisibilityEnum::Hidden, true); - SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); - if (IconButton(_tBind.m_iVisibility == BindVisibilityEnum::Always ? ICON_MD_VISIBILITY : ICON_MD_VISIBILITY_OFF)) - _tBind.m_iVisibility = (_tBind.m_iVisibility + 1) % 3; - PopTransparent(1, 1); - - SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); - if (IconButton(_tBind.m_bEnabled ? ICON_MD_TOGGLE_ON : ICON_MD_TOGGLE_OFF)) - _tBind.m_bEnabled = !_tBind.m_bEnabled; - - SetCursorPos(vOriginalPos); - bool bClicked = Button(std::format("##{}", _iBind).c_str(), { flWidth, flHeight }); - bool bPopup = IsItemClicked(ImGuiMouseButton_Right); - - PopTransparent(1, 1); - - if (bClicked) - { - if (!bParent) - { - iBind = _iBind; - tBind = _tBind; - } - else - { - bParent = false; - tBind.m_iParent = _iBind; - - // make sure bind can't be parented to itself or any of its children - int _iBind2 = _iBind; - Bind_t _tBind2; - while (F::Binds.GetBind(_iBind2, &_tBind2)) - { - if (_iBind2 == iBind) - tBind.m_iParent = DEFAULT_BIND; - _iBind2 = _tBind2.m_iParent; - } - } - } - else if (bPopup) - OpenPopup(std::format("RightClicked{}", _iBind).c_str()); - else if (iDragging == -1 && IsItemHovered() && IsMouseDown(ImGuiMouseButton_Left)) - iDragging = _iBind, iLayer = iParent; - else if (bDelete) - { - if (U::KeyHandler.Down(VK_SHIFT)) // allow user to quickly remove binds - F::Binds.RemoveBind(_iBind); - else - OpenPopup(std::format("DeleteBind{}", _iBind).c_str()); - } - - if (FBeginPopup(std::format("RightClicked{}", _iBind).c_str())) - { - PushStyleVar(ImGuiStyleVar_ItemSpacing, { H::Draw.Scale(8), 0 }); - - { - static std::string sInput = ""; - - bool bEnter = FInputText("Name...", sInput, H::Draw.Scale(284), ImGuiInputTextFlags_EnterReturnsTrue); - if (!IsItemFocused()) - sInput = _tBind.m_sName; - if (bEnter) - _tBind.m_sName = sInput; - } - - FDropdown("Type", &_tBind.m_iType, { "Key", "Class", "Weapon type", "Item slot", "Misc" }, {}, FDropdownEnum::Left); + std::string sType; std::string sInfo; switch (_tBind.m_iType) { - case BindEnum::Key: FDropdown("Behavior", &_tBind.m_iInfo, { "Hold", "Toggle", "Double click" }, {}, FDropdownEnum::Right); break; - case BindEnum::Class: FDropdown("Class", &_tBind.m_iInfo, { "Scout", "Soldier", "Pyro", "Demoman", "Heavy", "Engineer", "Medic", "Sniper", "Spy" }, {}, FDropdownEnum::Right); break; - case BindEnum::WeaponType: FDropdown("Weapon type", &_tBind.m_iInfo, { "Hitscan", "Projectile", "Melee", "Throwable" }, {}, FDropdownEnum::Right); break; - case BindEnum::ItemSlot: FDropdown("Item slot", &_tBind.m_iInfo, { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, {}, FDropdownEnum::Right); break; - case BindEnum::Misc: FDropdown("Misc", &_tBind.m_iInfo, { "Spectated", "Spectated 1st", "Spectated 3rd", "##Divider", "Zoomed", "Aiming" }, {}, FDropdownEnum::Right); break; + case BindEnum::Key: + switch (_tBind.m_iInfo) + { + case BindEnum::KeyEnum::Hold: { sType = "hold"; break; } + case BindEnum::KeyEnum::Toggle: { sType = "toggle"; break; } + case BindEnum::KeyEnum::DoubleClick: { sType = "double"; break; } + } + sInfo = VK2STR(_tBind.m_iKey); + break; + case BindEnum::Class: + sType = "class"; + switch (_tBind.m_iInfo) + { + case BindEnum::ClassEnum::Scout: { sInfo = "scout"; break; } + case BindEnum::ClassEnum::Soldier: { sInfo = "soldier"; break; } + case BindEnum::ClassEnum::Pyro: { sInfo = "pyro"; break; } + case BindEnum::ClassEnum::Demoman: { sInfo = "demoman"; break; } + case BindEnum::ClassEnum::Heavy: { sInfo = "heavy"; break; } + case BindEnum::ClassEnum::Engineer: { sInfo = "engineer"; break; } + case BindEnum::ClassEnum::Medic: { sInfo = "medic"; break; } + case BindEnum::ClassEnum::Sniper: { sInfo = "sniper"; break; } + case BindEnum::ClassEnum::Spy: { sInfo = "spy"; break; } + } + break; + case BindEnum::WeaponType: + sType = "weapon"; + switch (_tBind.m_iInfo) + { + case BindEnum::WeaponTypeEnum::Hitscan: { sInfo = "hitscan"; break; } + case BindEnum::WeaponTypeEnum::Projectile: { sInfo = "projectile"; break; } + case BindEnum::WeaponTypeEnum::Melee: { sInfo = "melee"; break; } + case BindEnum::WeaponTypeEnum::Throwable: { sInfo = "throwable"; break; } + } + break; + case BindEnum::ItemSlot: + sType = "slot"; + sInfo = std::format("{}", _tBind.m_iInfo + 1); + break; + case BindEnum::Misc: + switch (_tBind.m_iInfo) + { + case BindEnum::MiscEnum::Spectated: + case BindEnum::MiscEnum::SpectatedFirst: + case BindEnum::MiscEnum::SpectatedThird: + sType = "spectated"; + switch (_tBind.m_iInfo) + { + case BindEnum::MiscEnum::Spectated: { sInfo = "any"; break; } + case BindEnum::MiscEnum::SpectatedFirst: { sInfo = "1st"; break; } + case BindEnum::MiscEnum::SpectatedThird: { sInfo = "3rd"; break; } + } + break; + case BindEnum::MiscEnum::Zoomed: + case BindEnum::MiscEnum::Aiming: + sType = "cond"; + switch (_tBind.m_iInfo) + { + case BindEnum::MiscEnum::Zoomed: { sInfo = "zoomed"; break; } + case BindEnum::MiscEnum::Aiming: { sInfo = "aiming"; break; } + } + break; + } + break; } - if (_tBind.m_iType == BindEnum::Key) - FKeybind("Key", _tBind.m_iKey); + if (_tBind.m_bNot && (_tBind.m_iType != BindEnum::Key || _tBind.m_iInfo == BindEnum::KeyEnum::Hold)) + sType = std::format("not {}", sType); - PopStyleVar(); - EndPopup(); - } - else if (FBeginPopupModal(std::format("DeleteBind{}", _iBind).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) - { - FText(std::format("Do you really want to delete '{}'{}?", _tBind.m_sName, F::Binds.HasChildren(_iBind) ? " and all of its children" : "").c_str()); + ImVec2 vOriginalPos = { H::Draw.Scale(8) + H::Draw.Scale(28) * std::min(x, 3), GetCursorPosY() + H::Draw.Scale(8) }; - if (FButton("Yes", FButtonEnum::Left)) + // background + float flWidth = GetWindowWidth() - GetStyle().WindowPadding.x * 2 - H::Draw.Scale(28) * std::min(x, 3); + float flHeight = H::Draw.Scale(28); + ImVec2 vDrawPos = GetDrawPos() + vOriginalPos; + if (iBind != _iBind) + GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, F::Render.Background1p5, H::Draw.Scale(4)); + else { - F::Binds.RemoveBind(_iBind); - CloseCurrentPopup(); + ImColor tColor = F::Render.Background1p5L; + GetWindowDrawList()->AddRectFilled(vDrawPos, { vDrawPos.x + flWidth, vDrawPos.y + flHeight }, tColor, H::Draw.Scale(4)); - iBind = DEFAULT_BIND; - tBind = {}; + tColor = ColorToVec((VecToColor(F::Render.Background1p5)).Lerp({ 127, 127, 127 }, 1.f / 9, LerpEnum::NoAlpha)); + float flInset = H::Draw.Scale(0.5f) - 0.5f; + GetWindowDrawList()->AddRect({ vDrawPos.x + flInset, vDrawPos.y + flInset }, { vDrawPos.x - flInset + flWidth, vDrawPos.y - flInset + flHeight }, tColor, H::Draw.Scale(4), ImDrawFlags_None, H::Draw.Scale()); } - if (FButton("No", FButtonEnum::Right | FButtonEnum::SameLine)) - CloseCurrentPopup(); - EndPopup(); + // text + if (x > 3) + { // don't indent too much + auto sText = std::format("-> {}", x); + SetCursorPos({ vOriginalPos.x - FCalcTextSize(sText.c_str()).x - H::Draw.Scale(10), vOriginalPos.y + H::Draw.Scale(7) }); + FText(sText.c_str()); + } + + float flTextWidth = flWidth - H::Draw.Scale(127); + PushTransparent(!F::Binds.WillBeEnabled(_iBind), true); + + SetCursorPos({ vOriginalPos.x + H::Draw.Scale(9), vOriginalPos.y + H::Draw.Scale(7) }); + FText(TruncateText(_tBind.m_sName, flTextWidth * (1.f / 3) - H::Draw.Scale(20)).c_str()); + + SetCursorPos({ vOriginalPos.x + flTextWidth * (1.f / 3), vOriginalPos.y + H::Draw.Scale(7) }); + FText(sType.c_str()); + + SetCursorPos({ vOriginalPos.x + flTextWidth * (2.f / 3), vOriginalPos.y + H::Draw.Scale(7) }); + FText(sInfo.c_str()); + + // buttons + int iOffset = 1; + + SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); + bool bDelete = IconButton(ICON_MD_DELETE); + + SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); + if (IconButton(ICON_MD_EDIT)) + CurrentBind = CurrentBind != _iBind ? _iBind : DEFAULT_BIND; + + SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); + if (IconButton(!_tBind.m_bNot ? ICON_MD_CODE : ICON_MD_CODE_OFF)) + _tBind.m_bNot = !_tBind.m_bNot; + + PushTransparent(Transparent || _tBind.m_iVisibility == BindVisibilityEnum::Hidden, true); + SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); + if (IconButton(_tBind.m_iVisibility == BindVisibilityEnum::Always ? ICON_MD_VISIBILITY : ICON_MD_VISIBILITY_OFF)) + _tBind.m_iVisibility = (_tBind.m_iVisibility + 1) % 3; + PopTransparent(1, 1); + + SetCursorPos({ vOriginalPos.x + flWidth - H::Draw.Scale(iOffset += 25), vOriginalPos.y + H::Draw.Scale(2) }); + if (IconButton(_tBind.m_bEnabled ? ICON_MD_TOGGLE_ON : ICON_MD_TOGGLE_OFF)) + _tBind.m_bEnabled = !_tBind.m_bEnabled; + + SetCursorPos(vOriginalPos); + bool bClicked = Button(std::format("##{}", _iBind).c_str(), { flWidth, flHeight }); + bool bPopup = IsItemClicked(ImGuiMouseButton_Right); + + PopTransparent(1, 1); + + if (bClicked) + { + if (!bParent) + { + iBind = _iBind; + tBind = _tBind; + } + else + { + bParent = false; + tBind.m_iParent = _iBind; + + // make sure bind can't be parented to itself or any of its children + int _iBind2 = _iBind; + Bind_t _tBind2; + while (F::Binds.GetBind(_iBind2, &_tBind2)) + { + if (_iBind2 == iBind) + tBind.m_iParent = DEFAULT_BIND; + _iBind2 = _tBind2.m_iParent; + } + } + } + else if (bPopup) + OpenPopup(std::format("RightClicked{}", _iBind).c_str()); + else if (iDragging == -1 && IsItemHovered() && IsMouseDown(ImGuiMouseButton_Left)) + iDragging = _iBind, iLayer = iParent; + else if (bDelete) + { + if (U::KeyHandler.Down(VK_SHIFT)) // allow user to quickly remove binds + F::Binds.RemoveBind(_iBind); + else + OpenPopup(std::format("DeleteBind{}", _iBind).c_str()); + } + + if (FBeginPopup(std::format("RightClicked{}", _iBind).c_str())) + { + PushStyleVar(ImGuiStyleVar_ItemSpacing, { H::Draw.Scale(8), 0 }); + + { + static std::string sInput = ""; + + bool bEnter = FInputText("Name...", sInput, H::Draw.Scale(284), ImGuiInputTextFlags_EnterReturnsTrue); + if (!IsItemFocused()) + sInput = _tBind.m_sName; + if (bEnter) + _tBind.m_sName = sInput; + } + + FDropdown("Type", &_tBind.m_iType, { "Key", "Class", "Weapon type", "Item slot", "Misc" }, {}, FDropdownEnum::Left); + switch (_tBind.m_iType) + { + case BindEnum::Key: FDropdown("Behavior", &_tBind.m_iInfo, { "Hold", "Toggle", "Double click" }, {}, FDropdownEnum::Right); break; + case BindEnum::Class: FDropdown("Class", &_tBind.m_iInfo, { "Scout", "Soldier", "Pyro", "Demoman", "Heavy", "Engineer", "Medic", "Sniper", "Spy" }, {}, FDropdownEnum::Right); break; + case BindEnum::WeaponType: FDropdown("Weapon type", &_tBind.m_iInfo, { "Hitscan", "Projectile", "Melee", "Throwable" }, {}, FDropdownEnum::Right); break; + case BindEnum::ItemSlot: FDropdown("Item slot", &_tBind.m_iInfo, { "1", "2", "3", "4", "5", "6", "7", "8", "9" }, {}, FDropdownEnum::Right); break; + case BindEnum::Misc: FDropdown("Misc", &_tBind.m_iInfo, { "Spectated", "Spectated 1st", "Spectated 3rd", "##Divider", "Zoomed", "Aiming" }, {}, FDropdownEnum::Right); break; + } + if (_tBind.m_iType == BindEnum::Key) + FKeybind("Key", _tBind.m_iKey); + + PopStyleVar(); + EndPopup(); + } + else if (FBeginPopupModal(std::format("DeleteBind{}", _iBind).c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_AlwaysUseWindowPadding)) + { + FText(std::format("Do you really want to delete '{}'{}?", _tBind.m_sName, F::Binds.HasChildren(_iBind) ? " and all of its children" : "").c_str()); + + if (FButton("Yes", FButtonEnum::Left)) + { + F::Binds.RemoveBind(_iBind); + CloseCurrentPopup(); + + iBind = DEFAULT_BIND; + tBind = {}; + } + if (FButton("No", FButtonEnum::Right | FButtonEnum::SameLine)) + CloseCurrentPopup(); + + EndPopup(); + } + + if (iParent != DEFAULT_BIND - 1) + fGetBinds(_iBind, x + 1); } - - if (iParent != DEFAULT_BIND - 1) - fGetBinds(_iBind, x + 1); - } - }; + }; fGetBinds(DEFAULT_BIND, 0); // this should ideally never happen, but failsafe @@ -2965,21 +2970,21 @@ void CMenu::MenuSettings(int iTab) vMaterials.push_back(tMaterial); std::sort(vMaterials.begin(), vMaterials.end(), [&](const auto& a, const auto& b) -> bool - { - // override for none material - if (FNV1A::Hash32(a.m_sName.c_str()) == FNV1A::Hash32Const("None")) - return true; - if (FNV1A::Hash32(b.m_sName.c_str()) == FNV1A::Hash32Const("None")) - return false; + { + // override for none material + if (FNV1A::Hash32(a.m_sName.c_str()) == FNV1A::Hash32Const("None")) + return true; + if (FNV1A::Hash32(b.m_sName.c_str()) == FNV1A::Hash32Const("None")) + return false; - // keep locked materials higher - if (a.m_bLocked && !b.m_bLocked) - return true; - if (!a.m_bLocked && b.m_bLocked) - return false; + // keep locked materials higher + if (a.m_bLocked && !b.m_bLocked) + return true; + if (!a.m_bLocked && b.m_bLocked) + return false; - return a.m_sName < b.m_sName; - }); + return a.m_sName < b.m_sName; + }); for (auto& tMaterial : vMaterials) { @@ -3068,7 +3073,7 @@ void CMenu::MenuSettings(int iTab) TextEditor.SetPaletteIndex(TextEditor::PaletteIndex::Punctuation, F::Render.Inactive); TextEditor.SetPaletteIndex(TextEditor::PaletteIndex::ControlCharacter, ImColor(F::Render.Inactive.Value.x, F::Render.Inactive.Value.y, F::Render.Inactive.Value.z, 0.1f)); TextEditor.SetPaletteIndex(TextEditor::PaletteIndex::String, F::Render.Accent); - + PushFont(F::Render.FontMono); ImVec2 vDrawPos = GetDrawPos() + GetCursorPos(); TextEditor.Render("TextEditor"); @@ -3603,92 +3608,92 @@ void CMenu::DrawBinds() std::vector vInfo; std::function fGetBinds = [&](int iParent) - { - for (int iBind = 0; iBind < F::Binds.m_vBinds.size(); iBind++) { - auto& tBind = F::Binds.m_vBinds[iBind]; - if (iParent != tBind.m_iParent || !tBind.m_bEnabled && !m_bIsOpen) - continue; - - if (tBind.m_iVisibility == BindVisibilityEnum::Always || tBind.m_iVisibility == BindVisibilityEnum::WhileActive && tBind.m_bActive || m_bIsOpen) + for (int iBind = 0; iBind < F::Binds.m_vBinds.size(); iBind++) { - std::string sType; std::string sInfo; - switch (tBind.m_iType) + auto& tBind = F::Binds.m_vBinds[iBind]; + if (iParent != tBind.m_iParent || !tBind.m_bEnabled && !m_bIsOpen) + continue; + + if (tBind.m_iVisibility == BindVisibilityEnum::Always || tBind.m_iVisibility == BindVisibilityEnum::WhileActive && tBind.m_bActive || m_bIsOpen) { - case BindEnum::Key: - switch (tBind.m_iInfo) + std::string sType; std::string sInfo; + switch (tBind.m_iType) { - case BindEnum::KeyEnum::Hold: { sType = "hold"; break; } - case BindEnum::KeyEnum::Toggle: { sType = "toggle"; break; } - case BindEnum::KeyEnum::DoubleClick: { sType = "double"; break; } - } - sInfo = VK2STR(tBind.m_iKey); - break; - case BindEnum::Class: - sType = "class"; - switch (tBind.m_iInfo) - { - case BindEnum::ClassEnum::Scout: { sInfo = "scout"; break; } - case BindEnum::ClassEnum::Soldier: { sInfo = "soldier"; break; } - case BindEnum::ClassEnum::Pyro: { sInfo = "pyro"; break; } - case BindEnum::ClassEnum::Demoman: { sInfo = "demoman"; break; } - case BindEnum::ClassEnum::Heavy: { sInfo = "heavy"; break; } - case BindEnum::ClassEnum::Engineer: { sInfo = "engineer"; break; } - case BindEnum::ClassEnum::Medic: { sInfo = "medic"; break; } - case BindEnum::ClassEnum::Sniper: { sInfo = "sniper"; break; } - case BindEnum::ClassEnum::Spy: { sInfo = "spy"; break; } - } - break; - case BindEnum::WeaponType: - sType = "weapon"; - switch (tBind.m_iInfo) - { - case BindEnum::WeaponTypeEnum::Hitscan: { sInfo = "hitscan"; break; } - case BindEnum::WeaponTypeEnum::Projectile: { sInfo = "projectile"; break; } - case BindEnum::WeaponTypeEnum::Melee: { sInfo = "melee"; break; } - case BindEnum::WeaponTypeEnum::Throwable: { sInfo = "throwable"; break; } - } - break; - case BindEnum::ItemSlot: - sType = "slot"; - sInfo = std::format("{}", tBind.m_iInfo + 1); - break; - case BindEnum::Misc: - switch (tBind.m_iInfo) - { - case BindEnum::MiscEnum::Spectated: - case BindEnum::MiscEnum::SpectatedFirst: - case BindEnum::MiscEnum::SpectatedThird: - sType = "spectated"; + case BindEnum::Key: switch (tBind.m_iInfo) { - case BindEnum::MiscEnum::Spectated: { sInfo = "any"; break; } - case BindEnum::MiscEnum::SpectatedFirst: { sInfo = "1st"; break; } - case BindEnum::MiscEnum::SpectatedThird: { sInfo = "3rd"; break; } + case BindEnum::KeyEnum::Hold: { sType = "hold"; break; } + case BindEnum::KeyEnum::Toggle: { sType = "toggle"; break; } + case BindEnum::KeyEnum::DoubleClick: { sType = "double"; break; } + } + sInfo = VK2STR(tBind.m_iKey); + break; + case BindEnum::Class: + sType = "class"; + switch (tBind.m_iInfo) + { + case BindEnum::ClassEnum::Scout: { sInfo = "scout"; break; } + case BindEnum::ClassEnum::Soldier: { sInfo = "soldier"; break; } + case BindEnum::ClassEnum::Pyro: { sInfo = "pyro"; break; } + case BindEnum::ClassEnum::Demoman: { sInfo = "demoman"; break; } + case BindEnum::ClassEnum::Heavy: { sInfo = "heavy"; break; } + case BindEnum::ClassEnum::Engineer: { sInfo = "engineer"; break; } + case BindEnum::ClassEnum::Medic: { sInfo = "medic"; break; } + case BindEnum::ClassEnum::Sniper: { sInfo = "sniper"; break; } + case BindEnum::ClassEnum::Spy: { sInfo = "spy"; break; } } break; - case BindEnum::MiscEnum::Zoomed: - case BindEnum::MiscEnum::Aiming: - sType = "cond"; + case BindEnum::WeaponType: + sType = "weapon"; switch (tBind.m_iInfo) { - case BindEnum::MiscEnum::Zoomed: { sInfo = "zoomed"; break; } - case BindEnum::MiscEnum::Aiming: { sInfo = "aiming"; break; } + case BindEnum::WeaponTypeEnum::Hitscan: { sInfo = "hitscan"; break; } + case BindEnum::WeaponTypeEnum::Projectile: { sInfo = "projectile"; break; } + case BindEnum::WeaponTypeEnum::Melee: { sInfo = "melee"; break; } + case BindEnum::WeaponTypeEnum::Throwable: { sInfo = "throwable"; break; } + } + break; + case BindEnum::ItemSlot: + sType = "slot"; + sInfo = std::format("{}", tBind.m_iInfo + 1); + break; + case BindEnum::Misc: + switch (tBind.m_iInfo) + { + case BindEnum::MiscEnum::Spectated: + case BindEnum::MiscEnum::SpectatedFirst: + case BindEnum::MiscEnum::SpectatedThird: + sType = "spectated"; + switch (tBind.m_iInfo) + { + case BindEnum::MiscEnum::Spectated: { sInfo = "any"; break; } + case BindEnum::MiscEnum::SpectatedFirst: { sInfo = "1st"; break; } + case BindEnum::MiscEnum::SpectatedThird: { sInfo = "3rd"; break; } + } + break; + case BindEnum::MiscEnum::Zoomed: + case BindEnum::MiscEnum::Aiming: + sType = "cond"; + switch (tBind.m_iInfo) + { + case BindEnum::MiscEnum::Zoomed: { sInfo = "zoomed"; break; } + case BindEnum::MiscEnum::Aiming: { sInfo = "aiming"; break; } + } + break; } break; } - break; + if (tBind.m_bNot && (tBind.m_iType != BindEnum::Key || tBind.m_iInfo == BindEnum::KeyEnum::Hold)) + sInfo = std::format("not {}", sInfo); + + vInfo.emplace_back(tBind.m_sName.c_str(), sType, sInfo, iBind, tBind); } - if (tBind.m_bNot && (tBind.m_iType != BindEnum::Key || tBind.m_iInfo == BindEnum::KeyEnum::Hold)) - sInfo = std::format("not {}", sInfo); - vInfo.emplace_back(tBind.m_sName.c_str(), sType, sInfo, iBind, tBind); + if (tBind.m_bActive || m_bIsOpen) + fGetBinds(iBind); } - - if (tBind.m_bActive || m_bIsOpen) - fGetBinds(iBind); - } - }; + }; fGetBinds(DEFAULT_BIND); if (vInfo.empty()) return; @@ -3730,7 +3735,7 @@ void CMenu::DrawBinds() if (Vars::Menu::BindWindowTitle.Value) { SetCursorPos({ H::Draw.Scale(8), H::Draw.Scale(6) }); - IconImage(ICON_MD_KEYBOARD); + IconImage(ICON_MD_KEYBOARD, F::Render.Accent); PushFont(F::Render.FontLarge); SetCursorPos({ H::Draw.Scale(30), H::Draw.Scale(7) }); FText("Binds"); diff --git a/Amalgam/src/Features/Misc/Misc.cpp b/Amalgam/src/Features/Misc/Misc.cpp index 0bcc7cc9..de57cd75 100644 --- a/Amalgam/src/Features/Misc/Misc.cpp +++ b/Amalgam/src/Features/Misc/Misc.cpp @@ -140,7 +140,7 @@ void CMisc::AutoStrafe(CTFPlayer* pLocal, CUserCmd* pCmd) break; float flTurnScale = Math::RemapVal(Vars::Misc::Movement::AutoStrafeTurnScale.Value, 0.f, 1.f, 0.9f, 1.f); - float flRotation = DEG2RAD((flDirDelta > 0.f ? -90.f : 90.f) + flDirDelta * flTurnScale); + float flRotation = Math::Deg2Rad((flDirDelta > 0.f ? -90.f : 90.f) + flDirDelta * flTurnScale); float flCosRot = cosf(flRotation), flSinRot = sinf(flRotation); pCmd->forwardmove = flCosRot * flForward - flSinRot * flSide; diff --git a/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.cpp b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.cpp index 0ff8e22a..62738f65 100644 --- a/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.cpp +++ b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.cpp @@ -23,7 +23,7 @@ bool CProjectileSimulation::GetInfoMain(CTFPlayer* pPlayer, CTFWeaponBase* pWeap if (Vars::Visuals::Trajectory::Override.Value) { - SDK::GetProjectileFireSetup(pPlayer, vAngles, { Vars::Visuals::Trajectory::OffsetX.Value, Vars::Visuals::Trajectory::OffsetY.Value, Vars::Visuals::Trajectory::OffsetZ.Value }, vPos, vAngle, Vars::Visuals::Trajectory::ForwardRedirect.Value, !bRedirect ? 1.f : Vars::Visuals::Trajectory::ForwardCutoff.Value, bInterp); + SDK::GetProjectileFireSetup(pPlayer, vAngles, { Vars::Visuals::Trajectory::OffsetX.Value, Vars::Visuals::Trajectory::OffsetY.Value, Vars::Visuals::Trajectory::OffsetZ.Value }, vPos, vAngle, bRedirect ? Vars::Visuals::Trajectory::ForwardRedirect.Value : 0.f, Vars::Visuals::Trajectory::ForwardCutoff.Value, bInterp); tProjInfo = { pPlayer, pWeapon, FNV1A::Hash32Const("custom"), vPos, vAngle, { Vars::Visuals::Trajectory::Hull.Value, Vars::Visuals::Trajectory::Hull.Value, Vars::Visuals::Trajectory::Hull.Value }, Vars::Visuals::Trajectory::Speed.Value, Vars::Visuals::Trajectory::Gravity.Value, Vars::Visuals::Trajectory::LifeTime.Value }; return true; @@ -360,7 +360,9 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate if (!m_pEnv || !m_pObj) return false; - //set drag + m_pCurrent = &tProjInfo; + + // set drag { float flDrag = 0.f; Vec3 vDragBasis = {}; @@ -403,7 +405,7 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate break; case FNV1A::Hash32Const("models/weapons/w_models/w_baseball.mdl"): flDrag = 1.f; - vDragBasis = { 0.009000f /*0.006645f*/, 0.006581f, 0.006710f}; + vDragBasis = { 0.009000f /*0.006645f*/, 0.006581f, 0.006710f }; vAngDragBasis = { 0.002233f, 0.002246f, 0.002206f }; break; case FNV1A::Hash32Const("models/weapons/c_models/c_xms_festive_ornament.mdl"): @@ -443,7 +445,7 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate m_pObj->m_angDragBasis = vAngDragBasis; } - //set position and velocity + // set position and velocity { Vec3 vVelocity, vAngularVelocity; if (!bWorld) @@ -478,7 +480,8 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate vAngularVelocity = { 600.f, float(SDK::RandomInt(-1200, 1200)), 0.f }; break; } - vAngularVelocity = { 600.f, -1200.f, 0.f }; + if (!tProjInfo.m_pWeapon || !SDK::AttribHookValue(0, "grenade_no_spin", tProjInfo.m_pWeapon)) + vAngularVelocity = { 600.f, -1200.f, 0.f }; break; case FNV1A::Hash32Const("models/workshop_partner/weapons/c_models/c_sd_cleaver/c_sd_cleaver.mdl"): vVelocity = vForward * 10 + vUp; @@ -554,12 +557,11 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate m_pObj->SetVelocity(&vVelocity, &vAngularVelocity); } - //set m_pEnv params + // set m_pEnv params { float flMaxVelocity = 1000000.f; float vMaxAngularVelocity = 1000000.f; - //only pipes need k_flMaxVelocity and k_flMaxAngularVelocity switch (tProjInfo.m_uType) { case FNV1A::Hash32Const("custom"): @@ -585,7 +587,7 @@ bool CProjectileSimulation::Initialize(ProjectileInfo& tProjInfo, bool bSimulate params.maxAngularVelocity = vMaxAngularVelocity; m_pEnv->SetPerformanceSettings(¶ms); - m_pEnv->SetAirDensity(2.f); + m_pEnv->SetAirDensity(AIR_DENSITY); m_pEnv->SetGravity({ 0.f, 0.f, -(800.f * tProjInfo.m_flGravity) }); m_pEnv->ResetSimulationClock(); @@ -678,6 +680,9 @@ void CProjectileSimulation::SetupTrace(CTraceFilterCollideable& filter, int& nMa } } } + + if (m_pObj->m_dragCoefficient && m_pObj->m_angDragBasis) + nMask |= CONTENTS_DISPSOLID; } void CProjectileSimulation::SetupTrace(CTraceFilterCollideable& filter, int& nMask, CBaseEntity* pProjectile) diff --git a/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.h b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.h index 2020e6cb..42846b17 100644 --- a/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.h +++ b/Amalgam/src/Features/Simulation/ProjectileSimulation/ProjectileSimulation.h @@ -209,6 +209,7 @@ public: IPhysicsEnvironment* m_pEnv = nullptr; IPhysicsObject* m_pObj = nullptr; + ProjectileInfo* m_pCurrent = nullptr; }; ADD_FEATURE(CProjectileSimulation, ProjSim); \ No newline at end of file diff --git a/Amalgam/src/Features/Visuals/OffscreenArrows/OffscreenArrows.cpp b/Amalgam/src/Features/Visuals/OffscreenArrows/OffscreenArrows.cpp index d2aaabc9..1d589b88 100644 --- a/Amalgam/src/Features/Visuals/OffscreenArrows/OffscreenArrows.cpp +++ b/Amalgam/src/Features/Visuals/OffscreenArrows/OffscreenArrows.cpp @@ -21,7 +21,7 @@ void COffscreenArrows::DrawArrowTo(const Vec3& vFromPos, const Vec3& vToPos, Col } Vec3 vAngle = Math::VectorAngles({ vCenter.x - vScreen.x, vCenter.y - vScreen.y, 0 }); - const float flDeg = DEG2RAD(vAngle.y); + const float flDeg = Math::Deg2Rad(vAngle.y); const float flCos = cos(flDeg); const float flSin = sin(flDeg); diff --git a/Amalgam/src/Features/Visuals/Visuals.cpp b/Amalgam/src/Features/Visuals/Visuals.cpp index 8e99aba1..dfe54213 100644 --- a/Amalgam/src/Features/Visuals/Visuals.cpp +++ b/Amalgam/src/Features/Visuals/Visuals.cpp @@ -28,7 +28,7 @@ static std::vector SplashTrace(Vec3 vOrigin, float flRadius, Vec3 vNormal std::vector vPoints = {}; for (float i = 0.f; i < iSegments; i++) { - Vec3 vPoint = vOrigin + (vRight * cos(2 * PI * i / iSegments) + vUp * sin(2 * PI * i / iSegments)) * flRadius; + Vec3 vPoint = vOrigin + (vRight * cos(2 * Math::PI * i / iSegments) + vUp * sin(2 * Math::PI * i / iSegments)) * flRadius; if (bTrace) { CGameTrace trace = {}; diff --git a/Amalgam/src/Hooks/CM_TraceToDispTree.cpp b/Amalgam/src/Hooks/CM_TraceToDispTree.cpp new file mode 100644 index 00000000..a830990c --- /dev/null +++ b/Amalgam/src/Hooks/CM_TraceToDispTree.cpp @@ -0,0 +1,73 @@ +#include "../SDK/SDK.h" + +#include "../SDK/Definitions/Misc/TraceInfo.h" +#include + +MAKE_SIGNATURE(CM_TraceToDispTree_True, "engine.dll", "48 8B C4 48 89 58 ? 48 89 70 ? 57 48 81 EC ? ? ? ? F3 0F 10 01", 0x0); +MAKE_SIGNATURE(CM_TraceToDispTree_False, "engine.dll", "48 8B C4 48 89 58 ? 48 89 70 ? 57 48 83 EC ? F3 0F 10 01", 0x0); +MAKE_SIGNATURE(IntersectRayWithTriangle, "engine.dll", "48 8B C4 48 81 EC ? ? ? ? 80 BC 24", 0x0); +MAKE_SIGNATURE(CDispCollTree_SweepAABBTriIntersect, "engine.dll", "48 8B C4 48 89 70 ? 48 89 78 ? 55 41 56 41 57 48 8D 68", 0x0); +MAKE_SIGNATURE(CDispCollTree_EdgeCrossAxis_0, "engine.dll", "48 83 EC ? B8 ? ? ? ? 66 44 3B C0 75 ? B0 ? 48 83 C4 ? C3 48 8B 89 ? ? ? ? F3 0F 10 05 ? ? ? ? 0F 29 74 24 ? 0F 29 7C 24 ? 44 0F 29 04 24 41 0F B7 C0 66 45 85 C0 79 ? 25 ? ? ? ? 48 8D 04 40 F3 44 0F 10 04 81", 0x0); + +#define DISPCOLL_DIST_EPSILON 0.03125f + +static int s_iMask = 0; +static std::optional s_vOriginal = {}; +static CDispCollTri* s_pTri = nullptr; + +MAKE_HOOK(CM_TraceToDispTree_True, S::CM_TraceToDispTree_True(), float, + TraceInfo_t* pTraceInfo, CDispCollTree* pDispTree, float startFrac, float endFrac) +{ + DEBUG_RETURN(CM_TraceToDispTree_True, pTraceInfo, pDispTree, startFrac, endFrac); + + s_iMask = pTraceInfo->m_contents; + + return CALL_ORIGINAL(pTraceInfo, pDispTree, startFrac, endFrac); +} + +MAKE_HOOK(CM_TraceToDispTree_False, S::CM_TraceToDispTree_False(), float, + TraceInfo_t* pTraceInfo, CDispCollTree* pDispTree, float startFrac, float endFrac) +{ + DEBUG_RETURN(CM_TraceToDispTree_False, pTraceInfo, pDispTree, startFrac, endFrac); + + s_iMask = pTraceInfo->m_contents; + + return CALL_ORIGINAL(pTraceInfo, pDispTree, startFrac, endFrac); +} + +MAKE_HOOK(IntersectRayWithTriangle, S::IntersectRayWithTriangle(), float, + const Ray_t& ray, const Vector& v1, const Vector& v2, const Vector& v3, bool oneSided) +{ + if (s_iMask & CONTENTS_DISPSOLID) + oneSided = false; + + return CALL_ORIGINAL(ray, v1, v2, v3, oneSided); +} + +MAKE_HOOK(CDispCollTree_SweepAABBTriIntersect, S::CDispCollTree_SweepAABBTriIntersect(), void, + void* rcx, const Ray_t& ray, const Vector& rayDir, int iTri, CDispCollTri* pTri, CBaseTrace* pTrace) +{ + DEBUG_RETURN(CDispCollTree_SweepAABBTriIntersect, rcx, ray, rayDir, iTri, pTri, pTrace); + + if (s_iMask & CONTENTS_DISPSOLID && pTri->m_vecNormal.Dot(ray.m_Delta) > DISPCOLL_DIST_EPSILON) + { + s_vOriginal = pTri->m_vecNormal, s_pTri = pTri; + pTri->m_vecNormal = -pTri->m_vecNormal; + } + + CALL_ORIGINAL(rcx, ray, rayDir, iTri, pTri, pTrace); + + if (s_vOriginal) + pTri->m_vecNormal = s_vOriginal.value(), s_vOriginal = std::nullopt; +} + +MAKE_HOOK(CDispCollTree_EdgeCrossAxis_0, S::CDispCollTree_EdgeCrossAxis_0(), void, + void* rcx, const Ray_t& ray, unsigned short iPlane, CDispCollHelper* pHelper) +{ + DEBUG_RETURN(CDispCollTree_EdgeCrossAxis_0, rcx, ray, iPlane, pHelper); + + if (s_vOriginal) + s_pTri->m_vecNormal = s_vOriginal.value(), s_vOriginal = std::nullopt; + + CALL_ORIGINAL(rcx, ray, iPlane, pHelper); +} \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Definitions.h b/Amalgam/src/SDK/Definitions/Definitions.h index f9cee149..4ec127c5 100644 --- a/Amalgam/src/SDK/Definitions/Definitions.h +++ b/Amalgam/src/SDK/Definitions/Definitions.h @@ -198,6 +198,7 @@ #define TF_ROCKET_RADIUS (146.f) #define TF_FLARE_DET_RADIUS (110.f) #define TF_FLARE_RADIUS_FOR_FJS (100.f) +#define JAR_EXPLODE_RADIUS (200.f) #define TF_PLAYER_VIEW_OFFSET Vector( 0, 0, 64.0 ) #define TF_BURNING_FREQUENCY 0.5f diff --git a/Amalgam/src/SDK/Definitions/Interfaces/VPhysics.h b/Amalgam/src/SDK/Definitions/Interfaces/VPhysics.h index 87f2b5af..0b20ed24 100644 --- a/Amalgam/src/SDK/Definitions/Interfaces/VPhysics.h +++ b/Amalgam/src/SDK/Definitions/Interfaces/VPhysics.h @@ -2,6 +2,7 @@ #include "../Misc/IAppSystem.h" #include "../Types.h" +#define AIR_DENSITY 2 #define k_flMaxVelocity 2000.0f #define k_flMaxAngularVelocity 360.0f * 10.0f #define DEFAULT_MIN_FRICTION_MASS 10.0f diff --git a/Amalgam/src/SDK/Definitions/Misc/BSPFlags.h b/Amalgam/src/SDK/Definitions/Misc/BSPFlags.h index afaaedd1..01ed6619 100644 --- a/Amalgam/src/SDK/Definitions/Misc/BSPFlags.h +++ b/Amalgam/src/SDK/Definitions/Misc/BSPFlags.h @@ -55,6 +55,7 @@ #define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans #define CONTENTS_LADDER 0x20000000 #define CONTENTS_HITBOX 0x40000000 // use accurate hitboxes on trace +#define CONTENTS_DISPSOLID 0x80000000 // no normal checks when tracing against displacements // NOTE: These are stored in a short in the engine now. Don't use more than 16 bits #define SURF_LIGHT 0x0001 // value will hold the light strength diff --git a/Amalgam/src/SDK/Definitions/Misc/TraceInfo.h b/Amalgam/src/SDK/Definitions/Misc/TraceInfo.h new file mode 100644 index 00000000..310fbdac --- /dev/null +++ b/Amalgam/src/SDK/Definitions/Misc/TraceInfo.h @@ -0,0 +1,33 @@ +#pragma once +#include "CUtlVector.h" +#include "BaseTypes.h" +#include "../Main/CGameTrace.h" +#include "../Types.h" + +#define MAX_CHECK_COUNT_DEPTH 2 +typedef uint32 TraceCounter_t; +typedef CUtlVector CTraceCounterVec; + +struct TraceInfo_t +{ + Vector m_start; + Vector m_end; + Vector m_mins; + Vector m_maxs; + Vector m_extents; + Vector m_delta; + Vector m_invDelta; + trace_t m_trace; + trace_t m_stabTrace; + int m_contents; + bool m_ispoint; + bool m_isswept; + void* m_pBSPData; + Vector m_DispStabDir; + int m_bDispHit; + bool m_bCheckPrimary; + int m_nCheckDepth; + TraceCounter_t m_Count[MAX_CHECK_COUNT_DEPTH]; + CTraceCounterVec m_BrushCounters[MAX_CHECK_COUNT_DEPTH]; + CTraceCounterVec m_DispCounters[MAX_CHECK_COUNT_DEPTH]; +}; \ No newline at end of file diff --git a/Amalgam/src/SDK/Definitions/Types.h b/Amalgam/src/SDK/Definitions/Types.h index 1483571d..5ba83ab3 100644 --- a/Amalgam/src/SDK/Definitions/Types.h +++ b/Amalgam/src/SDK/Definitions/Types.h @@ -1,5 +1,6 @@ #pragma once #include +#include #include #include #include @@ -9,15 +10,34 @@ #include #include -#define PI 3.14159265358979323846 -#define M_RADPI 57.295779513082 -#define DEG2RAD(x) ((float)(x) * (float)((float)(PI) / 180.f)) -#define RAD2DEG(x) ((float)(x) * (float)(180.f / (float)(PI))) - #pragma warning (disable : 26495) namespace Math { + template + constexpr T PI_V = static_cast(3.141592653589793); + constexpr float PI = PI_V<>; + + template + constexpr T RAD_V = static_cast(57.29577951308232); + constexpr float RAD = RAD_V<>; + + template + constexpr T E_V = static_cast(2.718281828459045); + constexpr float E = E_V<>; + + template + inline T Deg2Rad(T v) + { + return v * PI_V / T(180); + } + + template + inline T Rad2Deg(T v) + { + return v * T(180) / PI_V; + } + inline float DeltaAngle(const float flAngleA, const float flAngleB) { float flOut = fmodf((flAngleA - flAngleB) + 180.f, 360.f); @@ -698,15 +718,15 @@ public: inline Vec3 ToAngle() const noexcept { - return { RAD2DEG(atan2(-z, hypot(x, y))), - RAD2DEG(atan2(y, x)), + return { Math::Rad2Deg(atan2(-z, hypot(x, y))), + Math::Rad2Deg(atan2(y, x)), 0.f }; } inline Vec3 FromAngle() const noexcept { - return { cos(DEG2RAD(x)) * cos(DEG2RAD(y)), - cos(DEG2RAD(x)) * sin(DEG2RAD(y)), - -sin(DEG2RAD(x)) }; + return { cos(Math::Deg2Rad(x)) * cos(Math::Deg2Rad(y)), + cos(Math::Deg2Rad(x)) * sin(Math::Deg2Rad(y)), + -sin(Math::Deg2Rad(x)) }; } }; using Vector = Vec3; @@ -749,9 +769,9 @@ private: { float sr, sp, sy, cr, cp, cy; - SinCos(DEG2RAD(vAngles[1]), &sy, &cy); - SinCos(DEG2RAD(vAngles[0]), &sp, &cp); - SinCos(DEG2RAD(vAngles[2]), &sr, &cr); + SinCos(Math::Deg2Rad(vAngles[1]), &sy, &cy); + SinCos(Math::Deg2Rad(vAngles[0]), &sp, &cp); + SinCos(Math::Deg2Rad(vAngles[2]), &sr, &cr); // matrix = (YAW * PITCH) * ROLL m2[0][0] = cp * cy; diff --git a/Amalgam/src/SDK/Helpers/Draw/Draw.cpp b/Amalgam/src/SDK/Helpers/Draw/Draw.cpp index 395d3f54..06375304 100644 --- a/Amalgam/src/SDK/Helpers/Draw/Draw.cpp +++ b/Amalgam/src/SDK/Helpers/Draw/Draw.cpp @@ -292,7 +292,7 @@ void CDraw::FillRoundRect(int x, int y, int w, int h, int iRadius, Color_t tColo const float a = 90.f * i; for (int j = 0; j < _iCount; j++) { - const float _a = DEG2RAD(a + j * flDelta); + const float _a = Math::Deg2Rad(a + j * flDelta); vVertices.emplace_back(Vertex_t({ { _x + iRadius * sinf(_a), _y - iRadius * cosf(_a) } })); } } @@ -314,7 +314,7 @@ void CDraw::LineRoundRect(int x, int y, int w, int h, int iRadius, Color_t tColo const float a = 90.f * i; for (int j = 0; j < _iCount; j++) { - const float _a = DEG2RAD(a + j * flDelta); + const float _a = Math::Deg2Rad(a + j * flDelta); vVertices.emplace_back(Vertex_t({ { _x + iRadius * sinf(_a), _y - iRadius * cosf(_a) } })); } } @@ -326,8 +326,8 @@ void CDraw::FillCircle(int x, int y, float iRadius, int iSegments, Color_t tColo { std::vector vVertices = {}; - const float step = static_cast(PI) * 2.0f / iSegments; - for (float a = 0; a < PI * 2.0f; a += step) + const float flStep = Math::PI * 2.f / iSegments; + for (float a = 0; a < Math::PI * 2.f; a += flStep) vVertices.emplace_back(Vector2D{ iRadius * cosf(a) + x, iRadius * sinf(a) + y }); FillPolygon(vVertices, tColor); diff --git a/Amalgam/src/SDK/SDK.cpp b/Amalgam/src/SDK/SDK.cpp index 186687ca..4caa6109 100644 --- a/Amalgam/src/SDK/SDK.cpp +++ b/Amalgam/src/SDK/SDK.cpp @@ -720,7 +720,7 @@ void SDK::FixMovement(CUserCmd* pCmd, const Vec3& vCurAngle, const Vec3& vTarget float flCurYaw = vCurAngle.y + (bCurOOB ? 180.f : 0.f); float flTargetYaw = vTargetAngle.y + (bTargetOOB ? 180.f : 0.f); - float flYaw = DEG2RAD(flTargetYaw - flCurYaw + vMoveAng.y); + float flYaw = Math::Deg2Rad(flTargetYaw - flCurYaw + vMoveAng.y); pCmd->forwardmove = cos(flYaw) * flSpeed; pCmd->sidemove = sin(flYaw) * flSpeed * (bTargetOOB ? -1 : 1); @@ -766,8 +766,8 @@ Vec3 SDK::ComputeMove(const CUserCmd* pCmd, CTFPlayer* pLocal, const Vec3& vFrom Vec3 vSilent = vDiff.To2D(); Vec3 vAngle = Math::VectorAngles(vSilent); - const float flYaw = DEG2RAD(vAngle.y - pCmd->viewangles.y); - const float flPitch = DEG2RAD(vAngle.x - pCmd->viewangles.x); + const float flYaw = Math::Deg2Rad(vAngle.y - pCmd->viewangles.y); + const float flPitch = Math::Deg2Rad(vAngle.x - pCmd->viewangles.x); Vec3 vMove = { cos(flYaw) * 450.f, -sin(flYaw) * 450.f, -cos(flPitch) * 450.f }; if (!(I::EngineTrace->GetPointContents(pLocal->GetShootPos()) & CONTENTS_WATER)) // only apply upmove in water diff --git a/Amalgam/src/SDK/Vars.h b/Amalgam/src/SDK/Vars.h index 26e9499d..48e48732 100644 --- a/Amalgam/src/SDK/Vars.h +++ b/Amalgam/src/SDK/Vars.h @@ -319,9 +319,9 @@ NAMESPACE_BEGIN(Vars) CVarEnum(Hitboxes, VA_LIST("Hitboxes", "Projectile hitboxes"), 0b001111, DROPDOWN_MULTI, nullptr, VA_LIST("Auto", "##Divider", "Head", "Body", "Feet", "##Divider", "Bodyaim if lethal", "Prioritize feet"), Auto = 1 << 0, Head = 1 << 1, Body = 1 << 2, Feet = 1 << 3, BodyaimIfLethal = 1 << 4, PrioritizeFeet = 1 << 5); - CVarEnum(Modifiers, VA_LIST("Modifiers", "Projectile modifiers"), 0b1010, DROPDOWN_MULTI, nullptr, - VA_LIST("Charge weapon", "Cancel charge", "Use arm time"), - ChargeWeapon = 1 << 0, CancelCharge = 1 << 1, UseArmTime = 1 << 2); + CVarEnum(Modifiers, VA_LIST("Modifiers", "Projectile modifiers"), 0b0010, DROPDOWN_MULTI, nullptr, + VA_LIST("Charge weapon", "Cancel charge", "Use arm time", "Alternate angles"), + ChargeWeapon = 1 << 0, CancelCharge = 1 << 1, UseArmTime = 1 << 2, AlternateAngles = 1 << 3); CVar(MaxSimulationTime, "Max simulation time", 2.f, SLIDER_MIN | SLIDER_PRECISION, 0.1f, 2.5f, 0.25f, "%gs"); CVar(HitChance, "Hit chance", 0.f, SLIDER_CLAMP | SLIDER_PRECISION, 0.f, 100.f, 10.f, "%g%%"); CVar(AutodetRadius, "Autodet radius", 90.f, SLIDER_CLAMP | SLIDER_PRECISION, 0.f, 100.f, 10.f, "%g%%"); @@ -670,8 +670,8 @@ NAMESPACE_BEGIN(Vars) CVar(OffsetX, "Offset X", 16.f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, -25.f, 25.f, 0.5f); CVar(OffsetY, "Offset Y", 8.f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, -25.f, 25.f, 0.5f); CVar(OffsetZ, "Offset Z", -6.f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, -25.f, 25.f, 0.5f); - CVar(ForwardRedirect, "Forward redirect", 2000.f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, 0.f, 2000.f, 100.f); - CVar(ForwardCutoff, "Forward cutoff", 0.1f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, 0.f, 1.f, 0.1f); + CVar(ForwardRedirect, "Forward redirect", 0.f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, 0.f, 2000.f, 100.f); + CVar(ForwardCutoff, "Forward cutoff", 0.f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, 0.f, 1.f, 0.1f); CVar(Hull, "Hull", 5.f, NOSAVE | DEBUGVAR | SLIDER_MIN | SLIDER_PRECISION, 0.f, 10.f, 0.5f); CVar(Speed, "Speed", 1200.f, NOSAVE | DEBUGVAR | SLIDER_MIN | SLIDER_PRECISION, 0.f, 5000.f, 50.f); CVar(Gravity, "Gravity", 1.f, NOSAVE | DEBUGVAR | SLIDER_PRECISION, 0.f, 1.f, 0.1f); diff --git a/Amalgam/src/Utils/Math/Math.h b/Amalgam/src/Utils/Math/Math.h index ca052bdc..3b8921b2 100644 --- a/Amalgam/src/Utils/Math/Math.h +++ b/Amalgam/src/Utils/Math/Math.h @@ -105,11 +105,11 @@ namespace Math } else { - flYaw = RAD2DEG(atan2f(vForward.y, vForward.x)); + flYaw = Rad2Deg(atan2f(vForward.y, vForward.x)); if (flYaw < 0) flYaw += 360; - flPitch = RAD2DEG(atan2f(-vForward.z, vForward.Length2D())); + flPitch = Rad2Deg(atan2f(-vForward.z, vForward.Length2D())); if (flPitch < 0) flPitch += 360; } @@ -129,8 +129,8 @@ namespace Math inline void AngleVectors(const Vec3& vAngles, Vec3* pForward = nullptr, Vec3* pRight = nullptr, Vec3* pUp = nullptr) { float sp, sy, sr, cp, cy, cr; - SinCos(DEG2RAD(vAngles.x), &sp, &cp); - SinCos(DEG2RAD(vAngles.y), &sy, &cy); + SinCos(Deg2Rad(vAngles.x), &sp, &cp); + SinCos(Deg2Rad(vAngles.y), &sy, &cy); if (pForward) { @@ -141,7 +141,7 @@ namespace Math if (pRight || pUp) { - SinCos(DEG2RAD(vAngles.z), &sr, &cr); + SinCos(Deg2Rad(vAngles.z), &sr, &cr); if (pRight) { @@ -165,8 +165,8 @@ namespace Math float flHyp = std::sqrtf((vDelta.x * vDelta.x) + (vDelta.y * vDelta.y)); Vec3 vAngles = { - atanf(vDelta.z / flHyp) * float(M_RADPI), - atanf(vDelta.y / vDelta.x) * float(M_RADPI), + atanf(vDelta.z / flHyp) * RAD, + atanf(vDelta.y / vDelta.x) * RAD, 0.f }; @@ -187,7 +187,7 @@ namespace Math Vec3 vToForward = Vec3(); AngleVectors(vToAng, &vToForward); - float flResult = RAD2DEG(acos(vFromForward.Dot(vToForward))); + float flResult = Rad2Deg(acos(vFromForward.Dot(vToForward))); if (!isfinite(flResult) || isinf(flResult) || isnan(flResult)) flResult = 0.f; @@ -199,9 +199,9 @@ namespace Math Vec3 vOffset = vPoint - vOrigin; float sp, sy, sr, cp, cy, cr; - SinCos(DEG2RAD(vAngles.x), &sp, &cp); - SinCos(DEG2RAD(vAngles.y), &sy, &cy); - SinCos(DEG2RAD(vAngles.z), &sr, &cr); + SinCos(Deg2Rad(vAngles.x), &sp, &cp); + SinCos(Deg2Rad(vAngles.y), &sy, &cy); + SinCos(Deg2Rad(vAngles.z), &sr, &cr); Vec3 vX = { cy * cp, @@ -277,9 +277,9 @@ namespace Math inline void AngleMatrix(const Vec3& vAngles, matrix3x4& mMatrix, bool bClearOrigin = true) { float sp, sy, sr, cp, cy, cr; - SinCos(DEG2RAD(vAngles.x), &sp, &cp); - SinCos(DEG2RAD(vAngles.y), &sy, &cy); - SinCos(DEG2RAD(vAngles.z), &sr, &cr); + SinCos(Deg2Rad(vAngles.x), &sp, &cp); + SinCos(Deg2Rad(vAngles.y), &sy, &cy); + SinCos(Deg2Rad(vAngles.z), &sr, &cr); mMatrix[0][0] = cp * cy; mMatrix[1][0] = cp * sy; @@ -315,14 +315,14 @@ namespace Math float flLen = vForward.Length2D(); if (flLen > 0.001f) { - vAngles.x = RAD2DEG(std::atan2(-vForward.z, flLen)); - vAngles.y = RAD2DEG(std::atan2(vForward.y, vForward.x)); - vAngles.z = RAD2DEG(std::atan2(vLeft.z, vUp.z)); + vAngles.x = Rad2Deg(std::atan2(-vForward.z, flLen)); + vAngles.y = Rad2Deg(std::atan2(vForward.y, vForward.x)); + vAngles.z = Rad2Deg(std::atan2(vLeft.z, vUp.z)); } else { - vAngles.x = RAD2DEG(std::atan2(-vForward.z, flLen)); - vAngles.y = RAD2DEG(std::atan2(-vLeft.x, vLeft.y)); + vAngles.x = Rad2Deg(std::atan2(-vForward.z, flLen)); + vAngles.y = Rad2Deg(std::atan2(-vLeft.x, vLeft.y)); vAngles.z = 0; } } @@ -411,7 +411,7 @@ namespace Math GetMatrixOrigin(mMatrix, vOut); return vOut; } - + inline void ConcatTransforms(const matrix3x4& mIn1, const matrix3x4& mIn2, matrix3x4& mOut) { if (&mIn1 == &mOut) @@ -461,7 +461,7 @@ namespace Math float q = 2 * powf(b, 3) / 27 - b * c / 3 + d; if (p == 0.f) - return pow(q, 1.f / 3); + return powf(q, 1.f / 3); if (q == 0.f) return 0.f; @@ -476,7 +476,7 @@ namespace Math return -2 * t * cosh(acosh(-g) / 3) - b / 3; return 2 * t * cosh(acosh(g) / 3) - b / 3; } - + inline std::vector SolveQuartic(float a, float b, float c, float d, float e) { std::vector vRoots = {};