-
Автор темы
- #1
Всем привет.
Включаю функцию рейджа и происходит следующие.
База: Csgosimple
Включая функцию рейджа вижу, что он не стреляет, а так же все модельки игроков стоят на месте, но ESP продолжает показывать куда перемещается игрок.
Прикладывают код рейджа, но может быть не достаточно, что ещё вам кинуть?
Включаю функцию рейджа и происходит следующие.
База: Csgosimple
Включая функцию рейджа вижу, что он не стреляет, а так же все модельки игроков стоят на месте, но ESP продолжает показывать куда перемещается игрок.
Прикладывают код рейджа, но может быть не достаточно, что ещё вам кинуть?
Код:
#include "Ragebot.h"
#define fuck_my_ass g_LocalPlayer->GetEyePos()
void aim::run(CUserCmd* cmd)
{
backup.clear();
targets.clear();
scanned_targets.clear();
final_target.reset();
should_stop = false;
if (!g_Options.ragebot.enable)
return;
//automatic_revolver(cmd);
prepare_targets();
if (sunshine::weapon->is_non_aim())
return;
if (sunshine::current_weapon == -1)
return;
scan_targets();
if (!should_stop && g_Options.ragebot.weapon[sunshine::current_weapon].autostop_modifiers[AUTOSTOP_PREDICTIVE])
{
for (auto& target : targets)
{
if (!target.last_record->valid())
continue;
scan_data last_data;
scan(target.last_record, last_data, g_LocalPlayer->GetEyePos());
if (!last_data.valid())
continue;
should_stop = true;
break;
}
}
if (!automatic_stop(cmd))
return;
if (scanned_targets.empty())
return;
find_best_target();
if (!final_target.data.valid())
return;
fire(cmd);
}
bool aim::automatic_stop(CUserCmd* cmd)
{
if (!should_stop)
return true;
if (!g_Options.ragebot.weapon[sunshine::current_weapon].autostop)
return true;
//if (g_ctx.globals.slowwalking)
// return true;
if (!(g_LocalPlayer->m_fFlags() & FL_ONGROUND))
return true;
if (sunshine::weapon->is_empty())
return true;
if (!g_Options.ragebot.weapon[sunshine::current_weapon].autostop_modifiers[AUTOSTOP_BETWEEN_SHOTS] && !sunshine::weapon->CanFire(false))
return true;
auto animlayer = g_LocalPlayer->GetAnimOverlays()[1];
if (animlayer.m_nSequence)
{
auto activity = g_LocalPlayer->GetSequenceActivity(animlayer.m_nSequence);
if (activity == ACT_CSGO_RELOAD && animlayer.m_flWeight > 0.0f)
return true;
}
auto weapon_info = sunshine::weapon->get_csweapon_info();
if (!weapon_info)
return true;
auto max_speed = 0.33f * (sunshine::scoped ? weapon_info->flMaxPlayerSpeedAlt : weapon_info->flMaxPlayerSpeed);
//if (engine_prediction::.Length2D() < max_speed)
// slowwalk::get().create_move(cmd);
//else
//{
// Vector direction;
// Vector real_view;
// math::vector_angles(engineprediction::get().backup_data.velocity, direction);
// m_engine()->GetViewAngles(real_view);
// direction.y = real_view.y - direction.y;
// Vector forward;
// math::angle_vectors(direction, forward);
// static auto cl_forwardspeed = m_cvar()->FindVar(crypt_str("cl_forwardspeed"));
// static auto cl_sidespeed = m_cvar()->FindVar(crypt_str("cl_sidespeed"));
// auto negative_forward_speed = -cl_forwardspeed->GetFloat();
// auto negative_side_speed = -cl_sidespeed->GetFloat();
// auto negative_forward_direction = forward * negative_forward_speed;
// auto negative_side_direction = forward * negative_side_speed;
// cmd->m_forwardmove = negative_forward_direction.x;
// cmd->m_sidemove = negative_side_direction.y;
// if (g_cfg.ragebot.weapon[g_ctx.globals.current_weapon].autostop_modifiers[AUTOSTOP_FORCE_ACCURACY])
// return false;
//}
return true;
}
void aim::prepare_targets()
{
for (auto i = 1; i < g_GlobalVars->maxClients; i++)
{
auto e = (C_BasePlayer*)g_EntityList->GetClientEntity(i);
if (!e->valid(true, false))
continue;
auto records = &player_records[i];
if (records->empty())
continue;
targets.emplace_back(target(e, get_record(records, false), get_record(records, true)));
}
for (auto& target : targets)
backup.emplace_back(adjust_data(target.e));
}
static bool compare_records(const optimized_adjust_data& first, const optimized_adjust_data& second)
{
if (first.shot != second.shot)
return first.shot;
else if (first.speed != second.speed)
return first.speed > second.speed;
return first.simulation_time < second.simulation_time;
}
adjust_data* aim::get_record(std::deque <adjust_data>* records, bool history)
{
if (history)
{
std::deque <optimized_adjust_data> optimized_records;
for (auto i = 0; i < records->size(); ++i)
{
auto record = &records->at(i);
optimized_adjust_data optimized_record;
optimized_record.i = i;
optimized_record.player = record->player;
optimized_record.simulation_time = record->simulation_time;
optimized_record.speed = record->velocity.Length();
optimized_record.shot = record->shot;
optimized_records.emplace_back(optimized_record);
}
if (optimized_records.size() < 2)
return nullptr;
std::sort(optimized_records.begin(), optimized_records.end(), compare_records);
for (auto& optimized_record : optimized_records)
{
auto record = &records->at(optimized_record.i);
if (!record->valid())
continue;
return record;
}
}
else
{
for (auto i = 0; i < records->size(); ++i)
{
auto record = &records->at(i);
if (!record->valid())
continue;
return record;
}
}
return nullptr;
}
int aim::get_minimum_damage(bool visible, int health)
{
auto minimum_damage = 0;
auto weaponData = sunshine::weapon->get_csweapon_info();
if (visible)
{
if (g_Options.ragebot.weapon[sunshine::current_weapon].minimum_visible_damage == 0)
minimum_damage = min(weaponData->iDamage / 3, health / 4);
else if (g_Options.ragebot.weapon[sunshine::current_weapon].minimum_visible_damage > 100)
minimum_damage = health + g_Options.ragebot.weapon[sunshine::current_weapon].minimum_visible_damage - 100;
else
minimum_damage = Math::clamp(g_Options.ragebot.weapon[sunshine::current_weapon].minimum_visible_damage, 1, health);
}
else
{
if (g_Options.ragebot.weapon[sunshine::current_weapon].minimum_damage == 0)
minimum_damage = min(weaponData->iDamage / 3, health / 4);
else if (g_Options.ragebot.weapon[sunshine::current_weapon].minimum_damage > 100)
minimum_damage = health + g_Options.ragebot.weapon[sunshine::current_weapon].minimum_damage - 100;
else
minimum_damage = Math::clamp(g_Options.ragebot.weapon[sunshine::current_weapon].minimum_damage, 1, health);
}
//if (key_binds::get().get_key_bind_state(4 + g_ctx.globals.current_weapon))
//{
// if (g_cfg.ragebot.weapon[g_ctx.globals.current_weapon].minimum_override_damage > 100)
// minimum_damage = health + g_cfg.ragebot.weapon[g_ctx.globals.current_weapon].minimum_override_damage - 100;
// else
// minimum_damage = Math::clamp(g_cfg.ragebot.weapon[g_ctx.globals.current_weapon].minimum_override_damage, 1, health);
//}
return minimum_damage;
}
void aim::scan_targets()
{
if (targets.empty())
return;
for (auto& target : targets)
{
if (target.history_record->valid())
{
scan_data last_data;
if (target.last_record->valid())
{
target.last_record->adjust_player();
scan(target.last_record, last_data);
}
scan_data history_data;
scan(target.history_record, history_data);
if (last_data.valid() && last_data.damage > history_data.damage)
scanned_targets.emplace_back(scanned_target(target.last_record, last_data));
else if (history_data.valid())
scanned_targets.emplace_back(scanned_target(target.history_record, history_data));
}
else
{
if (!target.last_record->valid())
continue;
scan_data last_data;
target.last_record->adjust_player();
scan(target.last_record, last_data);
if (!last_data.valid())
continue;
scanned_targets.emplace_back(scanned_target(target.last_record, last_data));
}
}
}
#include "autowall.hpp"
void aim::scan(adjust_data* record, scan_data& data, const Vector& shoot_position)
{
if (!sunshine::weapon)
return;
auto weapon_info = sunshine::weapon->get_csweapon_info();
if (!weapon_info)
return;
auto hitboxes = get_hitboxes(record);
if (hitboxes.empty())
return;
//auto force_safe_points = key_binds::get().get_key_bind_state(3) || g_cfg.ragebot.weapon[g_ctx.globals.current_weapon].max_misses && g_ctx.globals.missed_shots[record->i] >= g_cfg.ragebot.weapon[g_ctx.globals.current_weapon].max_misses_amount;
auto best_damage = 0;
auto minimum_damage = get_minimum_damage(false, record->player->m_iHealth());
auto minimum_visible_damage = get_minimum_damage(true, record->player->m_iHealth());
auto get_hitgroup = [](const int& hitbox)
{
if (hitbox == HITBOX_HEAD)
return 0;
else if (hitbox == HITBOX_PELVIS)
return 1;
else if (hitbox == HITBOX_STOMACH)
return 2;
else if (hitbox >= HITBOX_LOWER_CHEST && hitbox <= HITBOX_UPPER_CHEST)
return 3;
else if (hitbox >= HITBOX_RIGHT_THIGH && hitbox <= HITBOX_LEFT_FOOT)
return 4;
else if (hitbox >= HITBOX_RIGHT_HAND && hitbox <= HITBOX_LEFT_FOREARM)
return 5;
return -1;
};
std::vector <scan_point> points;
for (auto& hitbox : hitboxes)
{
auto current_points = get_points(record, hitbox);
for (auto& point : current_points)
{
point.safe = record->bot || (hitbox_intersection(record->player, record->matrixes_data.zero, hitbox, shoot_position, point.point) && hitbox_intersection(record->player, record->matrixes_data.first, hitbox, shoot_position, point.point) && hitbox_intersection(record->player, record->matrixes_data.second, hitbox, shoot_position, point.point));
//if (!force_safe_points || point.safe)
points.emplace_back(point);
}
}
if (points.empty())
return;
auto body_hitboxes = true;
for (auto& point : points)
{
if (body_hitboxes && (point.hitbox < HITBOX_PELVIS || point.hitbox > HITBOX_UPPER_CHEST))
{
body_hitboxes = false;
//if (g_cfg.player_list.force_body_aim[record->i])
//break;
//if (key_binds::get().get_key_bind_state(22))
// break;
if (best_damage >= record->player->m_iHealth())
break;
if (g_Options.ragebot.weapon[sunshine::current_weapon].prefer_body_aim && best_damage >= 1 && record->flags & FL_ONGROUND && !record->shot)
break;
}
auto fire_data = autowall::Get().wall_penetration(shoot_position, point.point, record->player);
auto is_visible = false;
Ray_t ray;
ray.Init(g_LocalPlayer->m_vecOrigin() + g_LocalPlayer->m_vecViewOffset(), point.point);
CTraceFilter filter;
filter.pSkip = g_LocalPlayer;
trace_t tr;
g_EngineTrace->TraceRay(ray, MASK_SHOT | CONTENTS_GRATE, &filter, &tr);
if (tr.fraction > 0.9699f)
is_visible = true;
if (fire_data.damage < 1)
continue;
if (!is_visible && !g_Options.ragebot.autowall)
continue;
if (get_hitgroup(fire_data.hitbox) != get_hitgroup(point.hitbox))
continue;
auto current_minimum_damage = is_visible ? minimum_visible_damage : minimum_damage;
if (fire_data.damage >= current_minimum_damage && fire_data.damage >= best_damage)
{
if (!should_stop)
{
should_stop = true;
if (g_Options.ragebot.weapon[sunshine::current_weapon].autostop_modifiers[AUTOSTOP_LETHAL] && fire_data.damage < record->player->m_iHealth())
should_stop = false;
else if (g_Options.ragebot.weapon[sunshine::current_weapon].autostop_modifiers[AUTOSTOP_VISIBLE] && !is_visible)
should_stop = false;
else if (g_Options.ragebot.weapon[sunshine::current_weapon].autostop_modifiers[AUTOSTOP_CENTER] && !point.center)
should_stop = false;
}
//if (force_safe_points && !point.safe)
// continue;
best_damage = fire_data.damage;
data.point = point;
data.visible = fire_data.visible;
data.damage = fire_data.damage;
data.hitbox = fire_data.hitbox;
if (data.damage > record->player->m_iHealth() + 3 && data.hitbox >= 2 && data.hitbox <= 6)
return;
}
}
}
std::vector <int> aim::get_hitboxes(adjust_data* record)
{
std::vector <int> hitboxes;
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(4))
hitboxes.emplace_back(HITBOX_STOMACH);
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(5))
hitboxes.emplace_back(HITBOX_PELVIS);
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(2))
hitboxes.emplace_back(HITBOX_CHEST);
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(1))
hitboxes.emplace_back(HITBOX_UPPER_CHEST);
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(3))
hitboxes.emplace_back(HITBOX_LOWER_CHEST);
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(0))
hitboxes.emplace_back(HITBOX_HEAD);
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(6))
{
hitboxes.emplace_back(HITBOX_RIGHT_UPPER_ARM);
hitboxes.emplace_back(HITBOX_LEFT_UPPER_ARM);
}
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(7))
{
hitboxes.emplace_back(HITBOX_RIGHT_THIGH);
hitboxes.emplace_back(HITBOX_LEFT_THIGH);
hitboxes.emplace_back(HITBOX_RIGHT_CALF);
hitboxes.emplace_back(HITBOX_LEFT_CALF);
}
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitboxes.at(8))
{
hitboxes.emplace_back(HITBOX_RIGHT_FOOT);
hitboxes.emplace_back(HITBOX_LEFT_FOOT);
}
return hitboxes;
}
#include "prediction.hpp"
std::vector <scan_point> aim::get_points(adjust_data* record, int hitbox, bool from_aim)
{
std::vector <scan_point> points;
auto model = record->player->GetModel();
if (!model)
return points;
auto hdr = g_MdlInfo->GetStudioModel(model);
if (!hdr)
return points;
auto set = hdr->GetHitboxSet(record->player->m_nHitboxSet());
if (!set)
return points;
auto bbox = set->pHitbox(hitbox);
if (!bbox)
return points;
const auto is_zeus = sunshine::weapon->m_iItemDefinitionIndex() == WEAPON_TASER;
const auto is_knife = sunshine::weapon->IsKnife();
const auto mod = bbox->m_flRadius != -1.0f ? bbox->m_flRadius : 0.0f;
Vector max;
Vector min;
Math::VectorTransform(bbox->bbmax + mod, record->matrixes_data.main[bbox->bone], max);
Math::VectorTransform(bbox->bbmin - mod, record->matrixes_data.main[bbox->bone], min);
const auto center = (min + max) * 0.5f;
points.emplace_back(scan_point(center, hitbox, true));
if (!bbox->m_flRadius || is_zeus && !is_knife)
return points;
if (hitbox == HITBOX_NECK || hitbox == HITBOX_RIGHT_THIGH || hitbox == HITBOX_LEFT_THIGH || hitbox == HITBOX_RIGHT_CALF || hitbox == HITBOX_LEFT_CALF || hitbox == HITBOX_RIGHT_FOOT || hitbox == HITBOX_LEFT_FOOT || hitbox == HITBOX_RIGHT_HAND || hitbox == HITBOX_LEFT_HAND || hitbox == HITBOX_RIGHT_UPPER_ARM || hitbox == HITBOX_LEFT_UPPER_ARM || hitbox == HITBOX_RIGHT_FOREARM || hitbox == HITBOX_LEFT_FOREARM)
return points;
const auto cur_angles = Math::calculate_angle(center, fuck_my_ass);
Vector forward;
Math::AngleVectors(cur_angles, forward);
auto rs = 0.0f;
auto scale = hitbox == HITBOX_HEAD ? g_Options.ragebot.weapon[sunshine::current_weapon].head_scale * 0.01f : g_Options.ragebot.weapon[sunshine::current_weapon].body_scale * 0.01f;
if (g_Options.ragebot.weapon[sunshine::current_weapon].static_point_scale)
{
rs = bbox->m_flRadius * scale;
if (hitbox == HITBOX_HEAD)
rs = bbox->m_flRadius * scale;
}
else
{
auto transformed_center = center;
Math::VectorTransform(transformed_center, record->matrixes_data.main[bbox->bone], transformed_center);
auto spread = engine_prediction::spread + engine_prediction::inaccuracy;
auto distance = transformed_center.DistTo(fuck_my_ass);
distance /= Math::fast_sin(DEG2RAD(90.0f - RAD2DEG(spread)));
spread = Math::fast_sin(spread);
auto radius = max(bbox->m_flRadius - distance * spread, 0.0f);
rs = bbox->m_flRadius * Math::clamp(radius / bbox->m_flRadius, 0.0f, 1.0f);
}
if (scale <= 0.05f || scale > 1.f)
return points;
if (rs < 0.2f)
return points;
const auto top = Vector(0, 0, 1) * rs;
const auto right = forward.Cross(Vector(0, 0, 1)) * rs;
const auto left = Vector(-right.x, -right.y, right.z);
const auto delta = (max - min).Normalized();
Vector angle;
Math::VectorAngles(delta, angle);
angle -= cur_angles;
Math::normalize_angles(angle);
const auto is_horizontal = angle.x < 45.f && angle.x > -45.f;
const auto is_flipped = angle.y < 0.f;
if (hitbox == HITBOX_HEAD || (hitbox != HITBOX_LEFT_FOOT && hitbox != HITBOX_RIGHT_FOOT))
{
points.emplace_back(scan_point(max + top, hitbox, false));
points.emplace_back(scan_point(min - top, hitbox, false));
}
points.emplace_back(scan_point(max - (is_horizontal ? Vector() - top : left), hitbox, false));
points.emplace_back(scan_point(max - (is_horizontal ? is_flipped ? left : right : right), hitbox, false));
if (hitbox != HITBOX_LEFT_FOOT && hitbox != HITBOX_RIGHT_FOOT)
{
points.emplace_back(scan_point(min - (is_horizontal ? top : left), hitbox, false));
points.emplace_back(scan_point(min + (is_horizontal ? is_flipped ? left : right : left), hitbox, false));
}
return points;
}
static bool compare_targets(const scanned_target& first, const scanned_target& second)
{
switch (g_Options.ragebot.weapon[sunshine::current_weapon].selection_type)
{
case 1:
return first.fov < second.fov;
case 2:
return first.distance < second.distance;
case 3:
return first.health < second.health;
case 4:
return first.data.damage > second.data.damage;
}
return false;
}
void aim::find_best_target()
{
if (g_Options.ragebot.weapon[sunshine::current_weapon].selection_type)
std::sort(scanned_targets.begin(), scanned_targets.end(), compare_targets);
for (auto& target : scanned_targets)
{
if (target.fov > (float)g_Options.ragebot.field_of_view)
continue;
final_target = target;
final_target.record->adjust_player();
break;
}
}
void aim::fire(CUserCmd* cmd)
{
if (!sunshine::weapon->CanFire(true))
return;
auto aim_angle = Math::calculate_angle(fuck_my_ass, final_target.data.point.point).Clamp();
if (!g_Options.ragebot.silent_aim)
g_EngineClient->SetViewAngles(aim_angle);
if (!g_Options.ragebot.autoshoot && !(cmd->buttons & IN_ATTACK))
return;
auto final_hitchance = 0;
if (g_Options.ragebot.weapon[sunshine::current_weapon].hitchance)
{
auto is_valid_hitchance = calculate_hitchance(final_hitchance);
if (!is_valid_hitchance)
{
auto is_zoomable_weapon = sunshine::weapon->m_iItemDefinitionIndex() == WEAPON_SCAR20 || sunshine::weapon->m_iItemDefinitionIndex() == WEAPON_G3SG1 || sunshine::weapon->m_iItemDefinitionIndex() == WEAPON_SSG08 || sunshine::weapon->m_iItemDefinitionIndex() == WEAPON_AWP || sunshine::weapon->m_iItemDefinitionIndex() == WEAPON_AUG || sunshine::weapon->m_iItemDefinitionIndex() == WEAPON_SG556;
if ((int)fuck_my_ass.DistTo(final_target.record->origin) < g_Options.ragebot.weapon[sunshine::current_weapon].autoscope_distance_float && g_Options.ragebot.weapon[sunshine::current_weapon].autoscope_distance) {
if (g_Options.ragebot.weapon[sunshine::current_weapon].autoscope && is_zoomable_weapon && !sunshine::weapon->m_zoomLevel())
cmd->buttons |= IN_ATTACK2;
}
else {
if (g_Options.ragebot.weapon[sunshine::current_weapon].autoscope && is_zoomable_weapon && !sunshine::weapon->m_zoomLevel())
cmd->buttons |= IN_ATTACK2;
}
return;
}
}
cmd->viewangles = aim_angle;
cmd->buttons |= IN_ATTACK;
cmd->tick_count = TIME_TO_TICKS(final_target.record->simulation_time + Utils::get_interpolation());
sunshine::aimbot_working = true;
}
static std::vector<std::tuple<float, float, float>> precomputed_seeds = {};
float random_float(float min, float max) {
typedef float(*RandomFloat_t)(float, float);
static RandomFloat_t m_RandomFloat = (RandomFloat_t)GetProcAddress(GetModuleHandle((L"vstdlib.dll")), ("RandomFloat"));
return m_RandomFloat(min, max);
}
//--------------------------------------------------------------------------------
int random_int(int min, int max) {
typedef int(*RandomInt_t)(int, int);
static RandomInt_t m_RandomInt = (RandomInt_t)GetProcAddress(GetModuleHandle((L"vstdlib.dll")), ("RandomInt"));
return m_RandomInt(min, max);
}
//--------------------------------------------------------------------------------
void random_seed(int seed) {
typedef void(*RandomSeed_t)(int);
static RandomSeed_t m_RandomSeed = (RandomSeed_t)GetProcAddress(GetModuleHandle((L"vstdlib.dll")), ("RandomSeed"));
return m_RandomSeed(seed);
}
__forceinline void aim::build_seed_table()
{
if (!precomputed_seeds.empty())
return;
for (auto i = 0; i < 255; i++) {
random_seed(i + 1);
const auto pi_seed = random_float(0.f, M_PI * 2);
precomputed_seeds.emplace_back(random_float(0.f, 1.f),
sin(pi_seed), cos(pi_seed));
}
}
void fast_rsqrt(float a, float* out)
{
const auto xx = _mm_load_ss(&a);
auto xr = _mm_rsqrt_ss(xx);
auto xt = _mm_mul_ss(xr, xr);
xt = _mm_mul_ss(xt, xx);
xt = _mm_sub_ss(_mm_set_ss(3.f), xt);
xt = _mm_mul_ss(xt, _mm_set_ss(0.5f));
xr = _mm_mul_ss(xr, xt);
_mm_store_ss(out, xr);
}
//--------------------------------------------------------------------------------
float fast_vec_normalize(Vector& vec)
{
const auto sqrlen = vec.LengthSqr() + 1.0e-10f;
float invlen;
fast_rsqrt(sqrlen, &invlen);
vec.x *= invlen;
vec.y *= invlen;
vec.z *= invlen;
return sqrlen * invlen;
}
bool aim::calculate_hitchance(int& final_hitchance)
{
// generate look-up-table to enhance performance.
build_seed_table();
const auto info = sunshine::weapon->get_csweapon_info();
if (!info)
{
final_hitchance = 0;
return true;
}
const auto hitchance_cfg = g_Options.ragebot.weapon[sunshine::current_weapon].hitchance_amount;
if ((fuck_my_ass - final_target.data.point.point).Length() > info->flRange)
{
final_hitchance = 0;
return true;
}
static auto nospread = g_CVar->FindVar(("weapon_accuracy_nospread"));
if (nospread->GetBool())
{
final_hitchance = INT_MAX;
return true;
}
// calculate inaccuracy.
const auto weapon_inaccuracy = engine_prediction::inaccuracy;
// calculate start and angle.
static auto weapon_recoil_scale = g_CVar->FindVar(("weapon_recoil_scale"));
const auto aim_angle = Math::calculate_angle(fuck_my_ass, final_target.data.point.point) - (g_LocalPlayer->m_aimPunchAngle() * weapon_recoil_scale->GetFloat());
auto forward = Vector(0, 0, 0);
auto right = Vector(0, 0, 0);
auto up = Vector(0, 0, 0);
Math::angle_vectors(aim_angle, &forward, &right, &up);
fast_vec_normalize(forward);
fast_vec_normalize(right);
fast_vec_normalize(up);
// keep track of all traces that hit the enemy.
auto current = 0;
// setup calculation parameters.
Vector total_spread, spread_angle, end;
float inaccuracy, spread_x, spread_y;
std::tuple<float, float, float>* seed;
// use look-up-table to find average hit probability.
for (auto i = 0u; i < 255; 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);
Math::VectorAngles(total_spread.Normalized(), spread_angle);
Math::AngleVectors(spread_angle, end);
end = fuck_my_ass + end.Normalized() * info->flRange;
CGameTrace tr;
g_EngineTrace->ClipRayToEntity(Ray_t(fuck_my_ass, end), MASK_SHOT, final_target.record->player, &tr);
if (tr.hit_entity == final_target.record->player)
current++;
// abort if hitchance is already sufficent.
if ((static_cast<float>(current) / 255.f) * 100.f >= hitchance_cfg)
{
final_hitchance = (static_cast<float>(current) / 255.f) * 100.f;
return true;
}
// abort if we can no longer reach hitchance.
if ((static_cast<float>(current + 255 - i) / 255.f) * 100.f < hitchance_cfg)
{
final_hitchance = (static_cast<float>(current + 255 - i) / 255.f) * 100.f;
return false;
}
}
final_hitchance = (static_cast<float>(current) / 255.f) * 100.f;
return (static_cast<float>(current) / 255.f) * 100.f >= hitchance_cfg;
}
Vector vector_rotate(const Vector& in1, const matrix3x4_t& in2)
{
return Vector(in1.Dot(in2[0]), in1.Dot(in2[1]), in1.Dot(in2[2]));
}
//--------------------------------------------------------------------------------
Vector vector_rotate(const Vector& in1, const Vector& in2)
{
matrix3x4_t dora_dura;
Math::AngleMatrix(in2, dora_dura);
return vector_rotate(in1, dora_dura);
}
float segment_to_segment(const Vector& s1, const Vector& s2, const Vector& k1, const Vector& k2)
{
static auto constexpr epsilon = 0.00000001f;
auto u = s2 - s1;
auto v = k2 - k1;
auto w = s1 - k1;
auto a = u.Dot(u); //-V525
auto b = u.Dot(v);
auto c = v.Dot(v);
auto d = u.Dot(w);
auto e = v.Dot(w);
auto D = a * c - b * b;
auto sn = 0.0f, sd = D;
auto tn = 0.0f, td = D;
if (D < epsilon)
{
sn = 0.0f;
sd = 1.0f;
tn = e;
td = c;
}
else
{
sn = b * e - c * d;
tn = a * e - b * d;
if (sn < 0.0f)
{
sn = 0.0f;
tn = e;
td = c;
}
else if (sn > sd)
{
sn = sd;
tn = e + b;
td = c;
}
}
if (tn < 0.0f)
{
tn = 0.0f;
if (-d < 0.0f)
sn = 0.0f;
else if (-d > a)
sn = sd;
else
{
sn = -d;
sd = a;
}
}
else if (tn > td)
{
tn = td;
if (-d + b < 0.0f)
sn = 0.0f;
else if (-d + b > a)
sn = sd;
else
{
sn = -d + b;
sd = a;
}
}
auto sc = fabs(sn) < epsilon ? 0.0f : sn / sd;
auto tc = fabs(tn) < epsilon ? 0.0f : tn / td;
auto dp = w + u * sc - v * tc;
return dp.Length();
}
bool intersect_line_with_bb(Vector& start, Vector& end, Vector& min, Vector& max)
{
char quadrant[3];
int i;
Vector candidatePlane;
for (i = 0; i < 3; i++) {
if (start[i] < min[i]) {
quadrant[i] = 1;
candidatePlane[i] = min[i];
}
else if (start[i] > max[i]) {
quadrant[i] = 0;
candidatePlane[i] = max[i];
}
else {
quadrant[i] = 2;
}
}
// Calculate T distances to candidate planes
Vector maxT;
for (i = 0; i < 3; i++) {
if (quadrant[i] != 2 && end[i] != 0.f)
maxT[i] = (candidatePlane[i] - start[i]) / end[i];
else
maxT[i] = -1.f;
}
// Get largest of the maxT's for final choice of intersection
int whichPlane = 0;
for (i = 1; i < 3; i++) {
if (maxT[whichPlane] < maxT[i])
whichPlane = i;
}
if (maxT[whichPlane] < 0.0f)
return false;
for (i = 0; i < 3; i++) {
if (whichPlane != i) {
float temp = start[i] + maxT[whichPlane] * end[i];
if (temp < min[i] || temp > max[i]) {
return false;
}
}
}
return true;
}
bool aim::hitbox_intersection(C_BasePlayer* e, matrix3x4_t* matrix, int hitbox, const Vector& start, const Vector& end)
{
auto model = e->GetModel();
if (!model)
return false;
auto studio_model = g_MdlInfo->GetStudioModel(model);
if (!studio_model)
return false;
auto studio_set = studio_model->GetHitboxSet(e->m_nHitboxSet());
if (!studio_set)
return false;
auto studio_hitbox = studio_set->pHitbox(hitbox);
if (!studio_hitbox)
return false;
Vector min, max;
const auto is_capsule = studio_hitbox->m_flRadius != -1.f;
if (is_capsule)
{
Math::VectorTransform(studio_hitbox->bbmin, matrix[studio_hitbox->bone], min);
Math::VectorTransform(studio_hitbox->bbmax, matrix[studio_hitbox->bone], max);
const auto dist = segment_to_segment(start, end, min, max);
if (dist < studio_hitbox->m_flRadius)
return true;
}
else
{
Math::VectorTransform(vector_rotate(studio_hitbox->bbmin, studio_hitbox->rotation), matrix[studio_hitbox->bone], min);
Math::VectorTransform(vector_rotate(studio_hitbox->bbmax, studio_hitbox->rotation), matrix[studio_hitbox->bone], max);
Math::VectorTransform(start, matrix[studio_hitbox->bone], min);
max = vector_rotate(end, matrix[studio_hitbox->bone]);
if (intersect_line_with_bb(min, max, studio_hitbox->bbmin, studio_hitbox->bbmax))
return true;
}
return false;
}