static std::vector<std::tuple<float, float, float>> precomputed_seeds = {};
bool aimbot::can_hit_hitbox(const Vector start, const Vector end, animation* log, studiohdr_t* hdr, int box)
{
const auto studio_box = hdr->pHitbox(static_cast<uint32_t>(box), 0);
if (!studio_box)
return false;
Vector min, max;
const auto is_capsule = studio_box->radius != -1.f;
if (is_capsule)
{
math::vector_transform(studio_box->bbmin, log->matrix[studio_box->bone], min);
math::vector_transform(studio_box->bbmax, log->matrix[studio_box->bone], max);
const auto dist = math::segment_to_segment(start, end, min, max);
if (dist < studio_box->radius)
return true;
}
if (!is_capsule)
{
math::vector_transform(math::vector_rotate(studio_box->bbmin, studio_box->rotation), log->matrix[studio_box->bone], min);
math::vector_transform(math::vector_rotate(studio_box->bbmax, studio_box->rotation), log->matrix[studio_box->bone], max);
math::vector_i_transform(start, log->matrix[studio_box->bone], min);
math::vector_i_rotate(end, log->matrix[studio_box->bone], max);
if (math::intersect_line_with_bb(min, max, studio_box->bbmin, studio_box->bbmax))
return true;
}
return false;
}
__forceinline void build_seed_table()
{
if (!precomputed_seeds.empty())
return;
for (auto i = 0; i <= 256; i++) {
random_seed(i + 1);
const auto pi_seed = random_float(0.f, 6.283186f);
precomputed_seeds.emplace_back(random_float(0.f, 1.f),
sin(pi_seed), cos(pi_seed));
}
}
bool aimbot::calc_hc(C_CSPlayer* local, animation& log, const Vector position, QAngle angle, const aimpoint_t& point, float chance, int box) const
{
static constexpr auto total_seeds = 255;
// generate look-up-table to enhance performance.
build_seed_table();
const auto weapon = get_weapon(g_pLocalPlayer->get_active_weapon());
if (!weapon)
return false;
const auto info = weapon->get_wpn_data();
if (!info)
return false;
const auto player = get_entity(log.index);
const auto studio_model = g_pModelInfo->GetStudioModel(player->get_model());
if (!studio_model)
return false;
// setup calculation parameters.
const auto round_acc = [](const float accuracy) { return roundf(accuracy * 1000.f) / 1000.f; };
const auto sniper = weapon->get_weapon_id() == WEAPON_AWP || weapon->get_weapon_id() == WEAPON_G3SG1
|| weapon->get_weapon_id() == WEAPON_SCAR20 || weapon->get_weapon_id() == WEAPON_SSG08;
const auto crouched = local->get_flags() & FL_DUCKING;
// calculate inaccuracy.
const auto weapon_inaccuracy = weapon->get_inaccuracy();
// calculate start and angle.
const auto start = local->get_eye_pos();
const auto aim_angle = math::get().calc_angle(start, position);
Vector forward, right, up;
math::get().angle_vectors(aim_angle, &forward, &right, &up);
// keep track of all traces that hit the enemy.
int current = 0;
int awalls_hit = 0;
// setup calculation parameters.
Vector total_spread, spread_angle, end;
float inaccuracy, spread_x, spread_y;
std::tuple<float, float, float>* seed;
// the calculater.
bool m_bHitchance = false;
// use look-up-table to find average hit probability.
for (auto i = 0u; i <= total_seeds; i++) // NOLINT(modernize-loop-convert)
{
// get seed.
seed = &precomputed_seeds[i];
// calculate spread.
inaccuracy = std::get<0>(*seed) * weapon_inaccuracy;
spread_x = std::get<2>(*seed) * inaccuracy;
spread_y = std::get<1>(*seed) * inaccuracy;
total_spread = (forward + right * spread_x + up * spread_y).Normalize();
// calculate angle with spread applied.
math::get().vector_angles(total_spread, spread_angle);
// calculate end point of trace.
math::get().angle_vectors(spread_angle, end);
end = start + end.Normalize() * info->flWeaponRange;
// did we hit the hitbox?
if (can_hit_hitbox(start, end, &log, studio_model, box))
current++;
// abort if hitchance is already sufficent.
if (static_cast<float>(current) / static_cast<float>(total_seeds) * 100.f >= chance) {
return true;
}
// abort if we can no longer reach hitchance.
if (static_cast<float>(current + total_seeds - i) / static_cast<float>(total_seeds) < chance)
return false;
}
return static_cast<float>(current) / static_cast<float>(total_seeds) * 100.f >= chance;
}