C++ Enrage autowall for LW

Начинающий
Статус
Оффлайн
Регистрация
5 Сен 2021
Сообщения
76
Реакции[?]
5
Поинты[?]
1K
мутини автовол?
во первых что это а во вторых не посоветуете откуда спастить топ АА
 
Начинающий
Статус
Оффлайн
Регистрация
15 Фев 2022
Сообщения
299
Реакции[?]
21
Поинты[?]
0
Начинающий
Статус
Оффлайн
Регистрация
5 Сен 2021
Сообщения
76
Реакции[?]
5
Поинты[?]
1K
Участник
Статус
Оффлайн
Регистрация
15 Янв 2021
Сообщения
500
Реакции[?]
311
Поинты[?]
101K
ну кнш крутой аним фикс в котором нет файла .h
1. Для тебя ну прям настолько сложно будет спастить готовый ( ! ) сурс и добавить ручками хедер ?
2. Слов культурных не найдётся, но дам совет как грится, тут на форуме предусмотрена фича, называется лс блять. Общайтесь там, а не засоряйте тред пж
1663087140211.png
 
Начинающий
Статус
Оффлайн
Регистрация
5 Сен 2021
Сообщения
76
Реакции[?]
5
Поинты[?]
1K
хз кому надо но вот.

TraceToExit перепастил с какого-то сурса, не помню откуда.
От говна по типу TraceLine и ClipTraceToPlayer чистите сами так как делал на скорую руку и перепривязывать не хотел.
Автоволл хороший но фпса с ним как у курицы (скорее всего из-за гипер скана) да и есть некоторые баги по неизвестным причинам.

cpp:
// This is an independent project of an individual developer. Dear PVS-Studio, please check it.
// PVS-Studio Static Code Analyzer for C, C++, C#, and Java: http://www.viva64.com
#include "autowall.h"

bool autowall::is_breakable_entity(IClientEntity* e)
{
    if (!e || !e->EntIndex())
        return false;

    static auto is_breakable = util::FindSignature(crypt_str("client.dll"), crypt_str("55 8B EC 51 56 8B F1 85 F6 74 68"));

    auto take_damage = *(uintptr_t*)((uintptr_t)is_breakable + 0x26);
    auto backup = *(uint8_t*)((uintptr_t)e + take_damage);

    auto client_class = e->GetClientClass();
    auto network_name = client_class->m_pNetworkName;

    if (!strcmp(network_name, "CBreakableSurface"))
        *(uint8_t*)((uintptr_t)e + take_damage) = DAMAGE_YES;
    else if (!strcmp(network_name, "CBaseDoor") || !strcmp(network_name, "CDynamicProp"))
        *(uint8_t*)((uintptr_t)e + take_damage) = DAMAGE_NO;

    using Fn = bool(__thiscall*)(IClientEntity*);
    auto result = ((Fn)is_breakable)(e);

    *(uint8_t*)((uintptr_t)e + take_damage) = backup;
    return result;
}

void autowall::TraceLine(Vector& absStart, const Vector& absEnd, unsigned int mask, player_t* ignore, CGameTrace* ptr)
{

    Ray_t ray;
    ray.Init(absStart, absEnd);
    CTraceFilter filter;
    filter.pSkip = ignore;

    m_trace()->TraceRay(ray, mask, &filter, ptr);
}

void autowall::ScaleDamage(CGameTrace& enterTrace, weapon_info_t* weaponData, float& currentDamage)
{
    if (!enterTrace.hit_entity || !enterTrace.hit_entity->GetClientClass() || !g_ctx.local()->m_hActiveWeapon() || enterTrace.hit_entity->GetClientClass()->m_ClassID != CCSPlayer)
        return;

    player_t* target = (player_t*)enterTrace.hit_entity;

    auto new_damage = currentDamage;

    const int hitgroup = enterTrace.hitgroup;
    const auto is_zeus = g_ctx.local()->m_hActiveWeapon()->m_iItemDefinitionIndex() == WEAPON_TASER;

    static auto is_armored = [](player_t* player, int armor, int hitgroup) {
        if (player && player->m_ArmorValue() > 0)
        {
            if (player->m_bHasHelmet() && hitgroup == HITGROUP_HEAD || (hitgroup >= HITGROUP_CHEST && hitgroup <= HITGROUP_RIGHTARM))
                return true;
        }
        return false;
    };

    if (!is_zeus) {
        switch (hitgroup)
        {
        case HITGROUP_HEAD:
            new_damage *= 4.f;
            break;
        case HITGROUP_STOMACH:
            new_damage *= 1.25f;
            break;
        case HITGROUP_LEFTLEG:
        case HITGROUP_RIGHTLEG:
            new_damage *= .75f;
            break;
        default:
            break;
            /*4.0; 1
            1.0; 2
            1.25; 3
            1.0; 4
            1.0; 5
            0.75; 6
            0.75; 7
            1.0; 8*/
        }
    }
    else
        new_damage *= 0.92f;

    if (is_armored(target, target->m_ArmorValue(), hitgroup))
    {
        float flHeavyRatio = 1.0f;
        float flBonusRatio = 0.5f;
        float flRatio = weaponData->flArmorRatio * 0.5f;
        float flNewDamage;

        if (!target->m_bHasHeavyArmor())
        {
            flNewDamage = new_damage * flRatio;
        }
        else
        {
            flBonusRatio = 0.33f;
            flRatio = weaponData->flArmorRatio * 0.5f;
            flHeavyRatio = 0.33f;
            flNewDamage = (new_damage * (flRatio * 0.5)) * 0.85f;
        }

        int iArmor = target->m_ArmorValue();

        if (((new_damage - flNewDamage) * (flBonusRatio * flHeavyRatio)) > iArmor)
            flNewDamage = new_damage - (iArmor / flBonusRatio);

        new_damage = flNewDamage;
    }

    currentDamage = new_damage;
}

bool DidHitWorld(IClientEntity* m_pEnt)
{
    return m_pEnt == m_entitylist()->GetClientEntity(0);
}

bool DidHitNonWorldEntity(IClientEntity* m_pEnt)
{
    return m_pEnt != NULL && DidHitWorld(m_pEnt);
}

bool autowall::TraceToExit(Vector& start, Vector dir, Vector& end, CGameTrace& enter_trace, CGameTrace& exit_trace)
{
    float flDistance = 0;
    int nStartContents = 0;

    while (flDistance <= 90.f)
    {
        flDistance += 4.0f;

        end = start + (flDistance * dir);

        Vector vecTrEnd = end - (4.0f * dir);

        if (nStartContents == 0)
            nStartContents = m_trace()->GetPointContents_WorldOnly(end, MASK_SHOT_HULL | CONTENTS_HITBOX);

        int nCurrentContents = m_trace()->GetPointContents_WorldOnly(end, MASK_SHOT_HULL | CONTENTS_HITBOX);

        if ((nCurrentContents & MASK_SHOT_HULL) == 0 || ((nCurrentContents & CONTENTS_HITBOX) && nStartContents != nCurrentContents))
        {
            // this gets a bit more complicated and expensive when we have to deal with displacements
            util::trace_line(end, vecTrEnd, MASK_SHOT_HULL | CONTENTS_HITBOX, nullptr, &exit_trace);

            // we exited the wall into a player's hitbox
            if (exit_trace.startsolid == true && (exit_trace.surface.flags & SURF_HITBOX)/*( nStartContents & CONTENTS_HITBOX ) == 0 && (nCurrentContents & CONTENTS_HITBOX)*/)
            {
                CTraceFilter filter;
                filter.pSkip = exit_trace.hit_entity;

                // do another trace, but skip the player to get the actual exit surface
                util::trace_line(end, start, MASK_SHOT_HULL, &filter, &exit_trace);
                if (exit_trace.DidHit() && exit_trace.startsolid == false)
                {
                    end = exit_trace.endpos;
                    return true;
                }
            }
            else if (exit_trace.DidHit() && exit_trace.startsolid == false)
            {
                bool bStartIsNodraw = !!(enter_trace.surface.flags & (SURF_NODRAW));
                bool bExitIsNodraw = !!(exit_trace.surface.flags & (SURF_NODRAW));
                if (bExitIsNodraw && is_breakable_entity(exit_trace.hit_entity) && is_breakable_entity(enter_trace.hit_entity))
                {
                    // we have a case where we have a breakable object, but the mapper put a nodraw on the backside
                    end = exit_trace.endpos;
                    return true;
                }
                else if (bExitIsNodraw == false || (bStartIsNodraw && bExitIsNodraw)) // exit nodraw is only valid if our entrace is also nodraw
                {
                    Vector vecNormal = exit_trace.plane.normal;
                    float flDot = dir.Dot(vecNormal);
                    if (flDot <= 1.0f)
                    {
                        // get the real end pos
                        end = end - ((4.f * exit_trace.fraction) * dir);
                        return true;
                    }
                }
            }
            else if (DidHitNonWorldEntity(enter_trace.hit_entity) && is_breakable_entity(enter_trace.hit_entity))
            {
                // if we hit a breakable, make the assumption that we broke it if we can't find an exit (hopefully..)
                // fake the end pos
                exit_trace = enter_trace;
                exit_trace.endpos = start + (1.0f * dir);
                return true;
            }
        }
    }

    return false;
}

bool autowall::HandleBulletPenetration(player_t* ignore, weapon_info_t* weaponData, CGameTrace& enterTrace, Vector& eyePosition, Vector direction, int& possibleHitsRemaining, float& currentDamage, float penetrationPower, float ff_damage_bullet_penetration, bool pskip)
{
    static ConVar* ff_damage_reduction_bullets = m_cvar()->FindVar(crypt_str("ff_damage_reduction_bullets"));

    if (possibleHitsRemaining <= 0 || weaponData->flPenetration <= 0 || currentDamage < 1) {
        return false;
    }

    CGameTrace exitTrace;
    auto* pEnemy = (player_t*)enterTrace.hit_entity;
    auto* const enterSurfaceData = m_physsurface()->GetSurfaceData(enterTrace.surface.surfaceProps);
    const int enter_material = enterSurfaceData->game.material;

    if (!enterSurfaceData || enterSurfaceData->game.flPenetrationModifier <= 0)
        return false;

    const auto enter_penetration_modifier = enterSurfaceData->game.flPenetrationModifier;
    //float enterDamageModifier = enterSurfaceData->game.damagemodifier;// , modifier, finalDamageModifier, combinedPenetrationModifier;
    const bool isSolidSurf = (enterTrace.contents & CONTENTS_GRATE);
    const bool isLightSurf = (enterTrace.surface.flags & SURF_NODRAW);

    if ((possibleHitsRemaining <= 0 && !isLightSurf && !isSolidSurf && enter_material != CHAR_TEX_GRATE && enter_material != CHAR_TEX_GLASS)
        || penetrationPower <= 0)
        return false;

    Vector end;
 
    if (!TraceToExit(enterTrace.endpos, direction, end, enterTrace, exitTrace))
    {
        if (!(m_trace()->GetPointContents(end, 0x600400B) & 0x600400B))
            return false;
    }

    auto* const exitSurfaceData = m_physsurface()->GetSurfaceData(exitTrace.surface.surfaceProps);
    const int exitMaterial = exitSurfaceData->game.material;
    const float exitSurfPenetrationModifier = exitSurfaceData->game.flPenetrationModifier;
    //float exitDamageModifier = exitSurfaceData->game.damagemodifier;

    float combined_damage_modifier = 0.16f;
    float combined_penetration_modifier;

    //Are we using the newer penetration system?
    if (enter_material == CHAR_TEX_GLASS || enter_material == CHAR_TEX_GRATE) {
        combined_damage_modifier = 0.05f;
        combined_penetration_modifier = 3;
    }
    else if (isSolidSurf || isLightSurf) {
        combined_damage_modifier = 0.16f;
        combined_penetration_modifier = 1;
    }
    else if (enter_material == CHAR_TEX_FLESH && ff_damage_reduction_bullets->GetFloat() == 0 && pEnemy != nullptr && pEnemy->is_player() && pEnemy->m_iTeamNum() == g_ctx.local()->m_iTeamNum())
    {
        if (ff_damage_bullet_penetration == 0)
        {
            // don't allow penetrating players when FF is off
            combined_penetration_modifier = 0;
            return false;
        }

        combined_penetration_modifier = ff_damage_bullet_penetration;
    }
    else {
        combined_penetration_modifier = (enter_penetration_modifier + exitSurfPenetrationModifier) / 2;
    }

    if (enter_material == exitMaterial) {
        if (exitMaterial == CHAR_TEX_WOOD || exitMaterial == CHAR_TEX_CARDBOARD)
            combined_penetration_modifier = 3;
        else if (exitMaterial == CHAR_TEX_PLASTIC)
            combined_penetration_modifier = 2;
    }

    auto penetration_mod = fmaxf(0.f, (3.f / penetrationPower) * 1.25f);

    float modifier = fmaxf(0, 1.0f / combined_penetration_modifier);

    auto thickness = (exitTrace.endpos - enterTrace.endpos).Length();

    const auto lost_damage = ((modifier * 3.f) * penetration_mod + (currentDamage * combined_damage_modifier)) + (((thickness * thickness) * modifier) / 24.f);

    currentDamage -= std::fmaxf(0.f, lost_damage);

    if (currentDamage < 1.f)
        return false;

    eyePosition = exitTrace.endpos;
    --possibleHitsRemaining;

    return true;
}

void autowall::FixTraceRay(Vector end, Vector start, CGameTrace* oldtrace, player_t* ent)
{
    if (!ent)
        return;

    const auto mins = ent->m_vecMins();
    const auto maxs = ent->m_vecMaxs();

    auto dir(end - start);
    auto len = dir.Normalize();

    const auto center = (mins + maxs) / 2;
    const auto pos(ent->m_vecOrigin() + center);

    auto to = pos - start;
    const float range_along = dir.Dot(to);

    float range;
    if (range_along < 0.f) {
        range = -(to).Length();
    }
    else if (range_along > len) {
        range = -(pos - end).Length();
    }
    else {
        auto ray(pos - (start + (dir * range_along)));
        range = ray.Length();
    }

    if (range <= 60.f) {

        Ray_t ray;
        ray.Init(start, end);

        trace_t trace;
        m_trace()->ClipRayToEntity(ray, 0x4600400B, ent, &trace);

        if (oldtrace->fraction > trace.fraction)
            *oldtrace = trace;
    }
}

void autowall::ClipTraceToPlayers(const Vector& start, const Vector& end, uint32_t mask, ITraceFilter* filter, CGameTrace* tr) {
    Vector     pos, to, dir, on_ray;
    float      len, range_along, range;
    //CGameTrace new_trace;

    float smallestFraction = tr->fraction;
    constexpr float maxRange = 60.0f;

    //Vector delta(vecAbsEnd - vecAbsStart);
    //const float delta_length = delta.Normalize();

    dir = start - end;
    len = dir.Normalize();

    Ray_t ray;
    ray.Init(start, end);

    for (int i = 1; i <= 64; ++i) {
        player_t* ent = (player_t*)m_entitylist()->GetClientEntity(i);
        if (!ent || ent->IsDormant() || ent->is_alive())
            continue;

        if (filter && !filter->ShouldHitEntity(ent, mask))
            continue;

        // set some local vars.
        pos = ent->m_vecOrigin() + ((ent->m_vecMins() + ent->m_vecMaxs()) * 0.5f);
        to = pos - start;
        range_along = dir.Dot(to);

        // off start point.
        if (range_along < 0.f)
            range = -(to).Length();

        // off end point.
        else if (range_along > len)
            range = -(pos - end).Length();

        // within ray bounds.
        else {
            on_ray = start + (dir * range_along);
            range = (pos - on_ray).Length();
        }

        if (/*range > 0.0f && */range <= maxRange) {
            trace_t playerTrace;

            //ray.Init(start, end);

            m_trace()->ClipRayToEntity(ray, 0x4600400B, ent, &playerTrace);

            if (playerTrace.fraction < smallestFraction) {
                // we shortened the ray - save off the trace
                *tr = playerTrace;
                smallestFraction = playerTrace.fraction;
            }
        }
    }
}

bool autowall::FireBullet(Vector eyepos, weapon_t* pWeapon, Vector& direction, float& currentDamage, player_t* ignore, player_t* to_who, int hitbox, bool* was_viable, std::vector<float>* power)
{
    if (!pWeapon || !ignore)
        return false;

    //      Current bullet travel Power to penetrate Distance to penetrate Range               Player bullet reduction convars              Amount to extend ray by
    float currentDistance = 0;

    static ConVar* damageBulletPenetration = m_cvar()->FindVar(crypt_str("ff_damage_bullet_penetration"));

    const float ff_damage_bullet_penetration = damageBulletPenetration->GetFloat();

    weapon_info_t* weaponData = g_ctx.globals.weapon->get_csweapon_info();
    CGameTrace enterTrace;

    CTraceFilter filter;
    filter.pSkip = ignore;

    if (!weaponData)
        return false;

    //Set our current damage to what our gun's initial damage reports it will do
    currentDamage = float(weaponData->iDamage);
    auto maxRange = weaponData->flRange;
    auto penetrationDistance = weaponData->flRange;
    auto penetrationPower = weaponData->flPenetration;
    auto RangeModifier = weaponData->flRangeModifier;
    auto possibleHitsRemaining = 4;

    //This gets set in FX_Firebullets to 4 as a pass-through value.
    //CS:GO has a maximum of 4 surfaces a bullet can pass-through before it 100% stops.
    //Excerpt from Valve: https://steamcommunity.com/sharedfiles/filedetails/?id=275573090
    //"The total number of surfaces any bullet can penetrate in a single flight is capped at 4." -CS:GO Official

    if (power)
    {
        maxRange = power->at(0);
        penetrationDistance = power->at(1);
        penetrationPower = power->at(2);
        currentDamage = power->at(3);
        RangeModifier = power->at(4);
    }

    int penetrated = 0;

    //If our damage is greater than (or equal to) 1, and we can shoot, let's shoot.
    while (/*ctx.last_penetrated_count >= 0 &&*/currentDamage > 0)
    {
        //Calculate max bullet range

        //Create endpoint of bullet
        Vector end = eyepos + direction * (maxRange - currentDistance);

        util::trace_line(eyepos, end, MASK_SHOT_HULL | CONTENTS_HITBOX, &filter, &enterTrace);
        //utilTraceLine(eyepos, end, 0x4600400B/*_HULL | CONTENTS_HITBOX*/, ignore, &enterTrace);

        if (to_who || enterTrace.contents & CONTENTS_HITBOX && enterTrace.hit_entity) {
            FixTraceRay(eyepos + (direction * 40.f), eyepos, &enterTrace, (to_who != nullptr ? to_who : (player_t*)enterTrace.hit_entity));
        }
        else
            ClipTraceToPlayers(eyepos, eyepos + (direction * 40.f), 0x4600400B, &filter, &enterTrace);

        if (enterTrace.fraction == 1.0f)
            return false;

        //We have to do this *after* tracing to the player.
        //int enterMaterial = enterSurfaceData->game.material;

        //calculate the damage based on the distance the bullet traveled.
        currentDistance += enterTrace.fraction * (maxRange - currentDistance);

        //Let's make our damage drops off the further away the bullet is.
        currentDamage *= powf(RangeModifier, (currentDistance / 500));

        if (!(enterTrace.contents & CONTENTS_HITBOX))
            enterTrace.hitgroup = 1;

        //This looks gay as fuck if we put it into 1 long line of code.
        const bool canDoDamage = enterTrace.hitgroup > 0 && enterTrace.hitgroup <= 8 || enterTrace.hitgroup == HITGROUP_GEAR;
        const bool isPlayer = enterTrace.hit_entity != nullptr
            && enterTrace.hit_entity->GetClientClass()
            && enterTrace.hit_entity->GetClientClass()->m_ClassID == CCSPlayer
            && (!g_ctx.local() || g_ctx.local()->is_alive() || ((player_t*)enterTrace.hit_entity)->m_iTeamNum() != g_ctx.local()->m_iTeamNum());

        if (to_who)
        {
            if (enterTrace.hit_entity && to_who == enterTrace.hit_entity && canDoDamage && isPlayer) {

                ScaleDamage(enterTrace, weaponData, currentDamage);

                if (was_viable != nullptr)
                    *was_viable = (penetrated == 0);

                return true;
            }
        }
        else
        {
            if (enterTrace.hit_entity && canDoDamage && isPlayer) {

                ScaleDamage(enterTrace, weaponData, currentDamage);

                if (was_viable != nullptr)
                    *was_viable = (penetrated == 0);

                return true;
            }
        }

        //Sanity checking / Can we actually shoot through?
        if (currentDistance > maxRange && penetrationPower
            || m_physsurface()->GetSurfaceData(enterTrace.surface.surfaceProps)->game.flPenetrationModifier < 0.1f) {
            return false;//ctx.last_penetrated_count = 0;
        }

        const auto prev = possibleHitsRemaining;

        //Calling HandleBulletPenetration here reduces our penetrationCounter, and if it returns true, we can't shoot through it.
        if (!HandleBulletPenetration(ignore, weaponData, enterTrace, eyepos, direction, possibleHitsRemaining, currentDamage, penetrationPower, ff_damage_bullet_penetration)) {
            break;
        }
        if (prev != possibleHitsRemaining)
            penetrated++;
    }

    return false;
}

////////////////////////////////////// Usage Calls //////////////////////////////////////
float autowall::CanHit(Vector& vecEyePos, Vector& point)
{
    g_ctx.globals.autowalling = true;

    Vector angles, direction;
    Vector tmp = point - vecEyePos;
    float currentDamage = 0;

    math::vector_angles(tmp, angles);
    math::angle_vectors(angles, direction);
    direction.Normalize();

    auto weapon = g_ctx.local()->m_hActiveWeapon().Get();

    if (weapon != nullptr && !weapon->is_non_aim() && FireBullet(vecEyePos, weapon, direction, currentDamage, g_ctx.local()))
    {
        g_ctx.globals.autowalling = false;
        return currentDamage;
    }

    return -1; //That wall is just a bit too thick buddy
}

float autowall::CanHit(const Vector& vecEyePos, Vector& point, player_t* ignore_ent, player_t* to_who, int hitbox, bool* was_viable)
{
    if (ignore_ent == nullptr || to_who == nullptr)
        return 0;

    g_ctx.globals.autowalling = true;

    Vector direction;
    Vector tmp = point - vecEyePos;
    float currentDamage = 0;

    direction = tmp.Normalized();

    auto weapon = g_ctx.local()->m_hActiveWeapon().Get();

    if (weapon != nullptr)
    {
        if (!weapon->is_non_aim() && FireBullet(vecEyePos, weapon, direction, currentDamage, ignore_ent, to_who, hitbox, was_viable))
        {
            g_ctx.globals.autowalling = false;
            return currentDamage;
        }
        else
        {
            g_ctx.globals.autowalling = false;
            return -1;
        }
    }

    return -1;
}

float autowall::SimulateShot(Vector& vecEyePos, Vector& point, player_t* ignore_ent, player_t* to_who, bool* was_viable)
{
    if (ignore_ent == nullptr || to_who == nullptr)
        return 0;

    g_ctx.globals.autowalling = true;

    Vector angles, direction;
    const Vector tmp(point - vecEyePos);
    float currentDamage = 0.f;

    math::vector_angles(tmp, angles);
    math::angle_vectors(angles, direction);
    direction.Normalize();

    auto weapon = g_ctx.local()->m_hActiveWeapon().Get();

    static std::vector<float> power = { 4000.f, 4000.f, 2.50f, 80.f, 1.f };

    if (weapon != nullptr)
    {
        if (FireBullet(vecEyePos, weapon, direction, currentDamage, ignore_ent, to_who, -1, was_viable, &power))
        {
            g_ctx.globals.autowalling = false;
            return currentDamage;
        }
        else
        {
            g_ctx.globals.autowalling = false;
            return -1;
        }
    }

    return -1;
}
hpp:
#pragma once
#include "..\..\includes.hpp"

class weapon_info_t;
class weapon_t;

class autowall : public singleton <autowall>
{
public:

    bool is_breakable_entity(IClientEntity* e);
    void TraceLine(Vector& absStart, const Vector& absEnd, unsigned int mask, player_t* ignore, CGameTrace* ptr);
    void ScaleDamage(CGameTrace& enterTrace, weapon_info_t* weaponData, float& currentDamage);
    bool TraceToExit(Vector& start, Vector dir, Vector& end, CGameTrace& enter_trace, CGameTrace& exit_trace);
    bool HandleBulletPenetration(player_t* ignore, weapon_info_t* weaponData, CGameTrace& enterTrace, Vector& eyePosition, Vector direction, int& possibleHitsRemaining, float& currentDamage, float penetrationPower, float ff_damage_bullet_penetration, bool pskip = false);
    void FixTraceRay(Vector end, Vector start, CGameTrace* oldtrace, player_t* ent);
    void ClipTraceToPlayers(const Vector& vecAbsStart, const Vector& vecAbsEnd, uint32_t mask, ITraceFilter* filter, CGameTrace* tr);
    bool FireBullet(Vector eyepos, weapon_t* pWeapon, Vector& direction, float& currentDamage, player_t* ignore, player_t* to_who = nullptr, int hitbox = -1, bool* was_viable = nullptr, std::vector<float>* = nullptr);
    float CanHit(Vector& vecEyePos, Vector& point);
    float CanHit(const Vector& vecEyePos, Vector& point, player_t* ignore_ent, player_t* start_ent, int hitbox, bool* was_viable = nullptr);
    float SimulateShot(Vector& vecEyePos, Vector& point, player_t* ignore_ent, player_t* to_who, bool* was_viable = nullptr);

};
if (auto fire_data = autowall::get().CanHit(shoot_position, point.point, g_ctx.local(), record->player, point.hitbox, &was_viable); fire_data > 0)

bool was_viable вместо fire_data.visible
помогите исправить
 

Вложения

Сверху Снизу