#include "../../../cs2/entity/C_CSPlayerPawn/C_CSPlayerPawn.h" #include "../../../templeware/interfaces/CGameEntitySystem/CGameEntitySystem.h" #include "../../../templeware/interfaces/interfaces.h" #include "../../../templeware/hooks/hooks.h" #include "../../../templeware/config/config.h" #include "../../utils/memory/patternscan/patternscan.h" #include "../visuals/visuals.h" #include "CUserCmd.h" #include "../../../templeware/utils/schema/schema.h" #include #include #include #include #include #include "../../menu/hud.h" #include "../../menu/menu.h" #include // Адреса из дампа (актуально для 2024-07-18) #define DW_SENSITIVITY 0x1A6A9D8 #define DW_SENSITIVITY_SENS 0x40 float GetGameSensitivity() { static float fallback = 2.0f; HMODULE hClient = GetModuleHandleA("client.dll"); if (!hClient) return fallback; uintptr_t sensBase = reinterpret_cast(hClient) + DW_SENSITIVITY; uintptr_t sensPtr = *reinterpret_cast(sensBase); if (!sensPtr) return fallback; float sens = *reinterpret_cast(sensPtr + DW_SENSITIVITY_SENS); if (sens < 0.01f || sens > 20.0f) return fallback; return sens; } // Индексы костей (актуально для CS2) constexpr int BONE_INDEX_HEAD = 6; // Head constexpr int BONE_INDEX_NECK = 5; // Neck constexpr int BONE_INDEX_BODY = 4;//0; // Pelvis/Root // --- lastBoneIdx теперь глобальный static --- static int lastBoneIdx = -1; inline QAngle_t CalcAngles(Vector_t viewPos, Vector_t aimPos) { QAngle_t angle = { 0, 0, 0 }; Vector_t delta = aimPos - viewPos; angle.x = -asin(delta.z / delta.Length()) * (180.0f / 3.141592654f); angle.y = atan2(delta.y, delta.x) * (180.0f / 3.141592654f); return angle; } inline float GetFov(const QAngle_t& viewAngle, const QAngle_t& aimAngle) { QAngle_t delta = (aimAngle - viewAngle).Normalize(); return sqrtf(powf(delta.x, 2.0f) + powf(delta.y, 2.0f)); } // // Сигнатура функции GetBonePosition (актуально для client.dll): // // 48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 4D 8B F1 // using GetBonePositionFn = int64_t(__fastcall*)(void*, uint32_t, Vector_t*, Vector_t*); // static GetBonePositionFn oGetBonePosition = nullptr; // static void InitGetBonePositionSig() { // if (!oGetBonePosition) { // uintptr_t addr = M::patternScan("client.dll", "48 89 6C 24 ? 48 89 74 24 ? 48 89 7C 24 ? 41 56 48 83 EC ? 4D 8B F1"); // oGetBonePosition = reinterpret_cast(addr); // } // } Vector_t GetBonePosition(const C_CSPlayerPawn* Entity, int boneIdx) { if (!Entity) return {}; // Внешний способ: читаем Vector3 по адресу boneMatrix + boneIdx * 0x20 uintptr_t pGameSceneNode = *reinterpret_cast((uintptr_t)Entity + 0x328); if (!pGameSceneNode) return {}; uintptr_t pBoneMatrix = *reinterpret_cast(pGameSceneNode + 0x1F0); if (!pBoneMatrix) return {}; return *reinterpret_cast(pBoneMatrix + boneIdx * 0x20); } // Получить позицию для аимбота в зависимости от выбора пользователя Vector_t GetAimbotTargetPos(const C_CSPlayerPawn* Entity, const Vector_t& from, const QAngle_t& viewAngles) { switch (Config::aimbot_bone) { case Config::BONE_HEAD: return GetBonePosition(Entity, BONE_INDEX_HEAD); case Config::BONE_NECK: return GetBonePosition(Entity, BONE_INDEX_NECK); case Config::BONE_BODY: return GetBonePosition(Entity, BONE_INDEX_BODY); case Config::BONE_NEAREST: default: { // Каждый раз ищем ближайшую кость по FOV std::array bones = { BONE_INDEX_HEAD, BONE_INDEX_BODY }; float bestFov = FLT_MAX; int bestIdx = BONE_INDEX_HEAD; for (int idx : bones) { Vector_t pos = GetBonePosition(Entity, idx); QAngle_t ang = CalcAngles(from, pos); // <-- Исправлено! float fov = GetFov(viewAngles, ang); if (fov < bestFov && std::isfinite(fov)) { bestFov = fov; bestIdx = idx; } } return GetBonePosition(Entity, bestIdx); } } } Vector_t GetEntityEyePos(const C_CSPlayerPawn* Entity) { if (!Entity) return {}; uintptr_t game_scene_node = *reinterpret_cast((uintptr_t)Entity + SchemaFinder::Get(hash_32_fnv1a_const("C_BaseEntity->m_pGameSceneNode"))); auto Origin = *reinterpret_cast(game_scene_node + SchemaFinder::Get(hash_32_fnv1a_const("CGameSceneNode->m_vecAbsOrigin"))); auto ViewOffset = *reinterpret_cast((uintptr_t)Entity + SchemaFinder::Get(hash_32_fnv1a_const("C_BaseModelEntity->m_vecViewOffset"))); Vector_t Result = Origin + ViewOffset; if (!std::isfinite(Result.x) || !std::isfinite(Result.y) || !std::isfinite(Result.z)) return {}; return Result; } // Удаляем все вспомогательные функции инкапсуляции void Aimbot() { static C_CSPlayerPawn* lockedTarget = nullptr; static bool prevAimbotState = false; static bool targetWasLost = false; static QAngle_t last_punch_angle = { 0,0,0 }; static int shotCount = 0; float sensitivity = GetGameSensitivity(); bool aimbotActive = Config::always_on_aimbot ? true : Config::aimbot; // --- shooterAfterAim + triggerbot_key --- if (Config::shooterAfterAim && (GetAsyncKeyState(Config::triggerbot_key) & 0x8000)) { aimbotActive = true; } C_CSPlayerPawn* lp = H::oGetLocalPlayer(0); if (cached_players.empty() || !lp || !lp->handle().valid() || lp->getHealth() <= 0) return; Vector_t lep = GetEntityEyePos(lp); QAngle_t* viewangles = (QAngle_t*)(modules.getModule("client") + 0x1A78650); bool isShooting = (GetAsyncKeyState(Config::triggerbot_key) & 0x8000) || (GetAsyncKeyState(VK_LBUTTON) & 0x8000); int shotsFired = lp ? lp->getShotsFired() : 0; shotCount = shotsFired; //g_DebugString = "debug: " + std::to_string(shotsFired) + "Sens: " + std::to_string(sensitivity); if (Config::aimbot_on_lmb && !Config::always_on_aimbot) { aimbotActive = isShooting; } // Получаем локального игрока и viewangles всегда, чтобы не дублировать код // C_CSPlayerPawn* lp = H::oGetLocalPlayer(0); // Vector_t lep = GetEntityEyePos(lp); // QAngle_t* viewangles = (QAngle_t*)(modules.getModule("client") + 0x1A78650); // Проверка: стреляет ли игрок (LMB) // bool isShooting = (GetAsyncKeyState(VK_LBUTTON) & 0x8000); // --- Новый режим: always_on_aimbot --- if (Config::always_on_aimbot) { float bestFov = Config::aimbot_fov; PlayerCache* bestTarget = nullptr; QAngle_t bestAngle = { 0, 0, 0 }; for (auto& Player : cached_players) { if (!Player.handle.valid() || Player.health <= 0 || Player.handle.index() == INVALID_EHANDLE_INDEX) continue; if (Config::teamCheck && (Player.team_num == cached_local.team)) continue; Vector_t target_pos = Player.position + Player.viewOffset; QAngle_t angle = CalcAngles(target_pos, lep); angle.x *= -1.f; angle.y += 180.f; const float fov = GetFov(*viewangles, angle); if (!std::isfinite(fov) || fov > bestFov) continue; bestFov = fov; bestTarget = &Player; bestAngle = angle; } if (bestTarget) { Vector_t target_pos = bestTarget->position + bestTarget->viewOffset; QAngle_t angle = CalcAngles(target_pos, lep); angle.x *= -1.f; angle.y += 180.f; QAngle_t cur_punch_angle = *(QAngle_t*)((uintptr_t)lp + SchemaFinder::Get(hash_32_fnv1a_const("C_CSPlayerPawn->m_aimPunchAngle"))); // --- RCS --- bool rcsActive = false; if (Config::shooterAfterAim && (GetAsyncKeyState(Config::triggerbot_key) & 0x8000)) { rcsActive = (Config::rcs || Config::shooterAfterAim) && (shotCount > Config::rcsActivationShots); } else { rcsActive = (Config::rcs || Config::shooterAfterAim) && (shotCount > Config::rcsActivationShots); } if (rcsActive && shotsFired > 1) { // Для прямого изменения viewangles: делить НЕ нужно //QAngle_t punchDelta = cur_punch_angle - last_punch_angle; //g_DebugString = "debug: " + std::to_string(punchDelta.x); angle -= cur_punch_angle * 2.f; last_punch_angle = cur_punch_angle; } else { last_punch_angle = { 0,0,0 }; } angle.z = 0.f; angle = angle.Normalize(); // --- Smooth --- QAngle_t delta = (angle - *viewangles).Normalize(); if (Config::aimbot_smooth > 0.f) { QAngle_t cur = *viewangles; float smooth = Config::aimbot_smooth; if (Config::aimbot_dynamic_smooth) { float fov = sqrtf(delta.x * delta.x + delta.y * delta.y); float maxFov = Config::aimbot_fov; float factor = (maxFov > 0.01f) ? (fov / maxFov) : 0.f; smooth = smooth + (smooth * factor * Config::aimbot_dynamic_smooth_factor); } angle = cur + delta * (1.f / smooth); angle = angle.Normalize(); *viewangles = angle; } else { *viewangles = angle; } } // В этом режиме не используем lockedTarget и не трогаем targetWasLost/prevAimbotState return; } // Если кнопка только что нажата (переход с false на true) — ищем новую цель if (aimbotActive && !prevAimbotState) { lastBoneIdx = -1; // Сброс при новой активации int nMaxHighestEntity = I::GameEntity->Instance->GetHighestEntityIndex(); float bestFov = Config::aimbot_fov; C_CSPlayerPawn* bestTarget = nullptr; QAngle_t bestAngle = { 0, 0, 0 }; for (int i = 1; i <= nMaxHighestEntity; i++) { auto Entity = I::GameEntity->Instance->Get(i); if (!Entity) continue; if (!Entity->handle().valid()) continue; SchemaClassInfoData_t* _class = nullptr; Entity->dump_class_info(&_class); if (!_class) continue; const uint32_t hash = HASH(_class->szName); if (hash == HASH("C_CSPlayerPawn")) { C_CSPlayerPawn* pawn = (C_CSPlayerPawn*)Entity; if (!pawn) continue; if (pawn->get_entity_by_handle() == lp->get_entity_by_handle()) continue; if (pawn->getHealth() <= 0) continue; if (Config::team_check && pawn->getTeam() == lp->getTeam()) continue; Vector_t target_pos = GetEntityEyePos(pawn);//GetAimbotTargetPos(pawn, lep); QAngle_t angle = CalcAngles(target_pos, lep); angle.x *= -1.f; angle.y += 180.f; const float fov = GetFov(*viewangles, angle); if (!std::isfinite(fov) || fov > bestFov) continue; bestFov = fov; bestTarget = pawn; bestAngle = angle; } } lockedTarget = bestTarget; targetWasLost = false; // Сброс punch_angle при смене цели last_punch_angle = { 0,0,0 }; } // Если кнопка отпущена — сбрасываем захват if (!aimbotActive) { lockedTarget = nullptr; targetWasLost = false; last_punch_angle = { 0,0,0 }; // сброс rcs // Сброс lastBoneIdx при отпускании кнопки аимбота (например, в Aimbot()): // if (!aimbotActive) lastBoneIdx = -1; } // Если есть захваченная цель и кнопка удерживается if (aimbotActive && lockedTarget) { // Проверяем, что цель всё ещё валидна if (!lp || !lp->handle().valid() || lp->getHealth() <= 0) { lockedTarget = nullptr; targetWasLost = false; last_punch_angle = { 0,0,0 }; return; } if ( lockedTarget->get_entity_by_handle() == lp->get_entity_by_handle() || lockedTarget->getHealth() <= 0 || !lockedTarget->handle().valid() ) { lockedTarget = nullptr; targetWasLost = true; last_punch_angle = { 0,0,0 }; // сброс rcs } else { Vector_t target_pos = GetAimbotTargetPos(lockedTarget, lep, *viewangles); QAngle_t angle = CalcAngles(target_pos, lep); angle.x *= -1.f; angle.y += 180.f; QAngle_t cur_punch_angle = *(QAngle_t*)((uintptr_t)lp + SchemaFinder::Get(hash_32_fnv1a_const("C_CSPlayerPawn->m_aimPunchAngle"))); // --- RCS --- bool rcsActive = false; if (Config::shooterAfterAim && (GetAsyncKeyState(Config::triggerbot_key) & 0x8000)) { rcsActive = (Config::rcs || Config::shooterAfterAim) && (shotCount > Config::rcsActivationShots); } else { rcsActive = (Config::rcs || Config::shooterAfterAim) && (shotCount > Config::rcsActivationShots); } if (rcsActive && shotCount > 1) { // Для прямого изменения viewangles: делить НЕ нужно //QAngle_t punchDelta = cur_punch_angle - last_punch_angle; //g_DebugString = "debug: " + std::to_string(punchDelta.x); angle -= cur_punch_angle * 2.f; last_punch_angle = cur_punch_angle; } else { last_punch_angle = { 0,0,0 }; } angle.z = 0.f; angle = angle.Normalize(); // --- Smooth --- if (Config::aimbot_smooth > 0.f) { QAngle_t cur = *viewangles; QAngle_t delta = (angle - cur).Normalize(); float smooth = Config::aimbot_smooth; if (Config::aimbot_dynamic_smooth) { float fov = sqrtf(delta.x * delta.x + delta.y * delta.y); float maxFov = Config::aimbot_fov; float factor = (maxFov > 0.01f) ? (fov / maxFov) : 0.f; smooth = smooth + (smooth * factor * Config::aimbot_dynamic_smooth_factor); } angle = cur + delta * (1.f / smooth); angle = angle.Normalize(); *viewangles = angle; } else { *viewangles = angle; } } } //Если кнопка зажата, цели нет, и мы не теряли цель (т.е. только в начале или если цели не было вообще) if (aimbotActive && !lockedTarget && !targetWasLost) { int nMaxHighestEntity = I::GameEntity->Instance->GetHighestEntityIndex(); float bestFov = Config::aimbot_fov; C_CSPlayerPawn* bestTarget = nullptr; QAngle_t bestAngle = { 0, 0, 0 }; for (int i = 1; i <= nMaxHighestEntity; i++) { auto Entity = I::GameEntity->Instance->Get(i); if (!Entity) continue; if (!Entity->handle().valid()) continue; SchemaClassInfoData_t* _class = nullptr; Entity->dump_class_info(&_class); if (!_class) continue; const uint32_t hash = HASH(_class->szName); if (hash == HASH("C_CSPlayerPawn")) { C_CSPlayerPawn* pawn = (C_CSPlayerPawn*)Entity; if (!pawn) continue; if (pawn->get_entity_by_handle() == lp->get_entity_by_handle()) continue; if (pawn->getHealth() <= 0) continue; if (Config::team_check && pawn->getTeam() == lp->getTeam()) continue; Vector_t target_pos = GetEntityEyePos(pawn);//GetAimbotTargetPos(pawn, lep); QAngle_t angle = CalcAngles(target_pos, lep); angle.x *= -1.f; angle.y += 180.f; const float fov = GetFov(*viewangles, angle); if (!std::isfinite(fov) || fov > bestFov) continue; bestFov = fov; bestTarget = pawn; bestAngle = angle; } } lockedTarget = bestTarget; // Сброс punch_angle при смене цели last_punch_angle = { 0,0,0 }; } prevAimbotState = aimbotActive; } void Ver2Aimbot(CUserCmd* pCmd) { //// --- Silent Aim: чистая и безопасная реализация --- //if (!Config::silent_aim || !pCmd) return; //static C_CSPlayerPawn* lockedTarget = nullptr; //static bool prevSilentState = false; //static QAngle_t last_punch_angle = { 0,0,0 }; //static int shotCount = 0; //static bool targetWasLost = false; //static bool targetWasLockedThisPress = false; //C_CSPlayerPawn* lp = H::oGetLocalPlayer(0); //if (!lp || !lp->handle().valid() || lp->getHealth() <= 0) return; //Vector_t lep = GetEntityEyePos(lp); //// Получаем viewangles только из CUserCmd! //QAngle_t* cur = nullptr; //if (pCmd->csgoUserCmd.pBaseCmd && pCmd->csgoUserCmd.pBaseCmd->pViewAngles) { // cur = &pCmd->csgoUserCmd.pBaseCmd->pViewAngles->angValue; //} //if (!cur) return; //// --- Кнопка активации --- //bool silentActive = Config::always_on_silent_aim ? true : (GetAsyncKeyState(Config::silent_aim_key) & 0x8000); //if (Config::silent_shooterAfterAim && (GetAsyncKeyState(Config::triggerbot_key) & 0x8000)) { // silentActive = true; //} //int shotsFired = lp ? lp->getShotsFired() : 0; //shotCount = shotsFired; //// --- Сброс флагов при новом нажатии --- //if (silentActive && !prevSilentState) { // targetWasLost = false; // targetWasLockedThisPress = false; //} //// --- Поиск цели --- //if (silentActive && !lockedTarget) { // if (Config::silent_rage || (!targetWasLost && !targetWasLockedThisPress)) { // int nMaxHighestEntity = I::GameEntity->Instance->GetHighestEntityIndex(); // float bestFov = Config::silent_aim_fov; // C_CSPlayerPawn* bestTarget = nullptr; // QAngle_t bestAngle = { 0, 0, 0 }; // for (int i = 1; i <= nMaxHighestEntity; i++) { // auto Entity = I::GameEntity->Instance->Get(i); // if (!Entity) continue; // if (!Entity->handle().valid()) continue; // SchemaClassInfoData_t* _class = nullptr; // Entity->dump_class_info(&_class); // if (!_class) continue; // const uint32_t hash = HASH(_class->szName); // if (hash == HASH("C_CSPlayerPawn")) { // C_CSPlayerPawn* pawn = (C_CSPlayerPawn*)Entity; // if (!pawn) continue; // if (pawn->get_entity_by_handle() == lp->get_entity_by_handle()) continue; // if (pawn->getHealth() <= 0) continue; // if (Config::team_check && pawn->getTeam() == lp->getTeam()) continue; // // --- Выбор кости для silent aim --- // Vector_t target_pos; // switch (Config::silent_aim_bone) { // case Config::BONE_HEAD: // target_pos = GetBonePosition(pawn, BONE_INDEX_HEAD); break; // case Config::BONE_NECK: // target_pos = GetBonePosition(pawn, BONE_INDEX_NECK); break; // case Config::BONE_BODY: // target_pos = GetBonePosition(pawn, BONE_INDEX_BODY); break; // case Config::BONE_NEAREST: // default: // target_pos = GetAimbotTargetPos(pawn, lep, *cur); break; // } // QAngle_t angle = CalcAngles(target_pos, lep); // angle.x *= -1.f; // angle.y += 180.f; // float fov = GetFov(*cur, angle); // if (!std::isfinite(fov) || fov > bestFov) continue; // bestFov = fov; // bestTarget = pawn; // bestAngle = angle; // } // } // lockedTarget = bestTarget; // last_punch_angle = { 0,0,0 }; // if (!Config::silent_rage && lockedTarget) targetWasLockedThisPress = true; // if (!Config::silent_rage && !lockedTarget) targetWasLost = true; // } //} //// --- Сброс при отпускании кнопки --- //if (!silentActive) { // lockedTarget = nullptr; // last_punch_angle = { 0,0,0 }; // targetWasLost = false; // targetWasLockedThisPress = false; //} //// --- Наведение на цель --- //if (silentActive && lockedTarget) { // // Проверка валидности цели // if (!lp || !lp->handle().valid() || lp->getHealth() <= 0 || // lockedTarget->get_entity_by_handle() == lp->get_entity_by_handle() || // lockedTarget->getHealth() <= 0 || // !lockedTarget->handle().valid() || // (Config::team_check && lockedTarget->getTeam() == lp->getTeam())) { // lockedTarget = nullptr; // last_punch_angle = { 0,0,0 }; // targetWasLost = true; // prevSilentState = silentActive; // return; // } // // --- Выбор кости для silent aim --- // Vector_t target_pos; // switch (Config::silent_aim_bone) { // case Config::BONE_HEAD: // target_pos = GetBonePosition(lockedTarget, BONE_INDEX_HEAD); break; // case Config::BONE_NECK: // target_pos = GetBonePosition(lockedTarget, BONE_INDEX_NECK); break; // case Config::BONE_BODY: // target_pos = GetBonePosition(lockedTarget, BONE_INDEX_BODY); break; // case Config::BONE_NEAREST: // default: // target_pos = GetAimbotTargetPos(lockedTarget, lep, *cur); break; // } // QAngle_t angle = CalcAngles(target_pos, lep); // angle.x *= -1.f; // angle.y += 180.f; // // --- Smooth --- // if (Config::silent_aim_smooth > 0.f) { // QAngle_t delta = (angle - *cur).Normalize(); // float smooth = Config::silent_aim_smooth; // angle = *cur + delta * (1.f / smooth); // angle = angle.Normalize(); // } // *cur = angle; //} //prevSilentState = silentActive; } // --- Функция для вывода отладочной информации через ImGui --- void ShowSilentAimDebugInfo(const CUserCmd* pCmd) { char debugBuf[256]; _snprintf_s(debugBuf, sizeof(debugBuf), "CUserCmd: size=%zu, m_csgoUserCmd@%zu, m_nButtons@%zu, nSubticks=%d, pRep=%p, pBaseCmd=%p", sizeof(CUserCmd), offsetof(CUserCmd, m_csgoUserCmd), offsetof(CUserCmd, m_nButtons), pCmd->m_csgoUserCmd.m_inputHistoryField.m_pRep ? pCmd->m_csgoUserCmd.m_inputHistoryField.m_pRep->m_nAllocatedSize : 0, (void*)pCmd->m_csgoUserCmd.m_inputHistoryField.m_pRep, (void*)pCmd->m_csgoUserCmd.m_pBaseCmd); g_DebugString = debugBuf; } void SilentAimbot(CUserCmd* pCmd) { if (!Config::silent_aim || !pCmd) return; C_CSPlayerPawn* lp = H::oGetLocalPlayer(0); if (!lp || !lp->handle().valid() || lp->getHealth() <= 0) return; // Кнопка активации bool silentActive = Config::always_on_silent_aim ? true : (GetAsyncKeyState(Config::silent_aim_key) & 0x8000); if (Config::silent_shooterAfterAim && (GetAsyncKeyState(Config::triggerbot_key) & 0x8000)) { silentActive = true; } if (!silentActive) return; Vector_t localEye = GetEntityEyePos(lp); // --- Исправленный доступ к углам --- QAngle_t* curAngles = nullptr; if (pCmd && pCmd->csgoUserCmd.pBaseCmd && pCmd->csgoUserCmd.pBaseCmd->pViewAngles) curAngles = &pCmd->csgoUserCmd.pBaseCmd->pViewAngles->angValue; if (!curAngles) return; // Поиск цели float bestFov = Config::silent_aim_fov; C_CSPlayerPawn* bestTarget = nullptr; Vector_t bestTargetPos{}; for (int i = 1; i <= I::GameEntity->Instance->GetHighestEntityIndex(); ++i) { auto Entity = I::GameEntity->Instance->Get(i); if (!Entity || !Entity->handle().valid()) continue; SchemaClassInfoData_t* _class = nullptr; Entity->dump_class_info(&_class); if (!_class || HASH(_class->szName) != HASH("C_CSPlayerPawn")) continue; C_CSPlayerPawn* pawn = (C_CSPlayerPawn*)Entity; if (!pawn || pawn->get_entity_by_handle() == lp->get_entity_by_handle() || pawn->getHealth() <= 0) continue; if (Config::team_check && pawn->getTeam() == lp->getTeam()) continue; Vector_t targetPos = GetBonePosition(pawn, Config::silent_aim_bone == Config::BONE_HEAD ? BONE_INDEX_HEAD : Config::silent_aim_bone == Config::BONE_NECK ? BONE_INDEX_NECK : Config::silent_aim_bone == Config::BONE_BODY ? BONE_INDEX_BODY : BONE_INDEX_HEAD); QAngle_t angle = CalcAngles(targetPos, localEye); angle.x *= -1.f; angle.y += 180.f; float fov = GetFov(*curAngles, angle); if (!std::isfinite(fov) || fov > bestFov) continue; bestFov = fov; bestTarget = pawn; bestTargetPos = targetPos; } if (!bestTarget) return; QAngle_t aimAngle = CalcAngles(bestTargetPos, localEye); aimAngle.x *= -1.f; aimAngle.y += 180.f; // Установить угол для всех сабтиков pCmd->SetSubTickAngle(aimAngle); }