2007 lines
64 KiB
C++
2007 lines
64 KiB
C++
#include "rage.h"
|
||
#include "../../core/config.h"
|
||
#include "../../core/variables.h"
|
||
#include "../../sdk/datatypes/usercmd.h"
|
||
#include "../../core/sdk.h"
|
||
#include "../../sdk/entity.h"
|
||
#include "../../sdk/interfaces/iengineclient.h"
|
||
#include "../../sdk/interfaces/iglobalvars.h"
|
||
#include "../../sdk/interfaces/cgameentitysystem.h"
|
||
#include "../../sdk/datatypes/qangle.h"
|
||
#include "../../sdk/datatypes/vector.h"
|
||
#include "../misc/movement.h"
|
||
#include "../cstrike/sdk/interfaces/ccsgoinput.h"
|
||
#include "../cstrike/sdk/interfaces/ienginecvar.h"
|
||
#include "../lagcomp/lagcomp.h"
|
||
#include "../cstrike/sdk/interfaces/events.h"
|
||
#include "../penetration/penetration.h"
|
||
#include "../cstrike/sdk/interfaces/itrace.h"
|
||
#include "../cstrike/core/spoofcall/syscall.h"
|
||
#include <iostream>
|
||
#include <memoryapi.h>
|
||
#include <mutex>
|
||
#include <array>
|
||
#include "../../core/spoofcall/virtualization/VirtualizerSDK64.h"
|
||
#include "../../utilities/inputsystem.h"
|
||
#ifndef M_PI
|
||
#define M_PI 3.14159265358979323846
|
||
#endif
|
||
#include "../../core/hooks.h"
|
||
#define M_PI_F ((float)(M_PI))
|
||
#ifndef RAD2DEG
|
||
#define RAD2DEG(x) ((float)(x) * (float)(180.f / M_PI_F))
|
||
#endif
|
||
|
||
#ifndef DEG2RAD
|
||
#define DEG2RAD(x) ((float)(x) * (float)(M_PI_F / 180.f))
|
||
#endif
|
||
static std::vector <std::uint32_t> e_hitboxes;
|
||
static bool m_stop = false;
|
||
static bool early_stopped = false;
|
||
|
||
#include <mutex>
|
||
#define MAX_STUDIO_BONES 1024
|
||
|
||
|
||
enum class HitscanMode : int {
|
||
NORMAL = 0,
|
||
LETHAL = 1,
|
||
LETHAL2 = 3,
|
||
PREFER = 4
|
||
};
|
||
|
||
struct HitscanBox_t {
|
||
int m_index;
|
||
HitscanMode m_mode;
|
||
|
||
__forceinline bool operator==(const HitscanBox_t& c) const {
|
||
return m_index == c.m_index && m_mode == c.m_mode;
|
||
}
|
||
};
|
||
|
||
class target
|
||
{
|
||
public:
|
||
C_CSPlayerPawn* handle;
|
||
C_BaseEntity* entHandle;
|
||
target()
|
||
{
|
||
handle = nullptr;
|
||
entHandle = nullptr;
|
||
}
|
||
|
||
target(C_CSPlayerPawn* handle, C_BaseEntity* entHandle)
|
||
{
|
||
this->handle = handle;
|
||
this->entHandle = entHandle;
|
||
}
|
||
};
|
||
|
||
class temp_point
|
||
{
|
||
public:
|
||
Vector_t point;
|
||
QAngle_t pointangle;
|
||
QAngle_t angle;
|
||
|
||
int hitbox;
|
||
bool center;
|
||
float safe;
|
||
float damage;
|
||
bool canHit;
|
||
|
||
temp_point()
|
||
{
|
||
point = Vector_t(0, 0, 0);
|
||
pointangle = QAngle_t(0, 0, 0);
|
||
angle = QAngle_t(0, 0, 0);
|
||
hitbox = -1;
|
||
center = false;
|
||
safe = 0.0f;
|
||
damage = 0.f;
|
||
canHit = false;
|
||
}
|
||
|
||
temp_point(const Vector_t& point, const QAngle_t& pointangle, const QAngle_t& angle, const int& hitbox, const bool& center, const float& damage, const bool& canHit) //-V818 //-V730
|
||
{
|
||
this->point = point;
|
||
this->pointangle = pointangle;
|
||
this->angle = angle;
|
||
this->hitbox = hitbox;
|
||
this->center = center;
|
||
this->damage = damage;
|
||
this->canHit = canHit;
|
||
}
|
||
|
||
void reset()
|
||
{
|
||
point = Vector_t(0, 0, 0);
|
||
pointangle = QAngle_t(0, 0, 0);
|
||
angle = QAngle_t(0, 0, 0);
|
||
hitbox = -1;
|
||
center = false;
|
||
safe = 0.0f;
|
||
damage = 0.f;
|
||
canHit = false;
|
||
}
|
||
};
|
||
class scan_point
|
||
{
|
||
public:
|
||
Vector_t point;
|
||
QAngle_t pointangle;
|
||
QAngle_t angle;
|
||
|
||
int hitbox;
|
||
bool center;
|
||
float safe;
|
||
float damage;
|
||
bool canHit;
|
||
|
||
scan_point()
|
||
{
|
||
point = Vector_t(0, 0, 0);
|
||
pointangle = QAngle_t(0, 0, 0);
|
||
angle = QAngle_t(0, 0, 0);
|
||
hitbox = -1;
|
||
center = false;
|
||
safe = 0.0f;
|
||
damage = 0.f;
|
||
canHit = false;
|
||
}
|
||
|
||
scan_point(const Vector_t& point, const QAngle_t& pointangle, const QAngle_t& angle, const int& hitbox, const bool& center, const float& damage, const bool& canHit) //-V818 //-V730
|
||
{
|
||
this->point = point;
|
||
this->pointangle = pointangle;
|
||
this->angle = angle;
|
||
this->hitbox = hitbox;
|
||
this->center = center;
|
||
this->damage = damage;
|
||
this->canHit = canHit;
|
||
}
|
||
|
||
void reset()
|
||
{
|
||
point = Vector_t(0, 0, 0);
|
||
pointangle = QAngle_t(0, 0, 0);
|
||
angle = QAngle_t(0, 0, 0);
|
||
hitbox = -1;
|
||
center = false;
|
||
safe = 0.0f;
|
||
damage = 0.f;
|
||
canHit = false;
|
||
}
|
||
};
|
||
class scan_data
|
||
{
|
||
public:
|
||
scan_point point;
|
||
temp_point temp_point;
|
||
|
||
bool visible;
|
||
int damage;
|
||
int hitbox;
|
||
|
||
scan_data()
|
||
{
|
||
reset();
|
||
}
|
||
|
||
void reset()
|
||
{
|
||
temp_point.reset();
|
||
point.reset();
|
||
visible = false;
|
||
damage = -1;
|
||
hitbox = -1;
|
||
}
|
||
|
||
bool valid()
|
||
{
|
||
return damage >= 1 && point.angle.IsValid();
|
||
}
|
||
};
|
||
|
||
class scanned_target
|
||
{
|
||
public:
|
||
C_CSPlayerPawn* record;
|
||
C_BaseEntity* ent;
|
||
scan_data data;
|
||
|
||
float fov;
|
||
float distance;
|
||
int health;
|
||
float damage;
|
||
scanned_target()
|
||
{
|
||
reset();
|
||
}
|
||
|
||
scanned_target(const scanned_target& data) //-V688
|
||
{
|
||
this->record = data.record;
|
||
this->data = data.data;
|
||
this->fov = data.fov;
|
||
this->distance = data.distance;
|
||
this->health = data.health;
|
||
this->damage = data.damage;
|
||
this->ent = data.ent;
|
||
|
||
}
|
||
|
||
scanned_target& operator=(const scanned_target& data) //-V688
|
||
{
|
||
this->ent = data.ent;
|
||
this->record = data.record;
|
||
this->data = data.data;
|
||
this->fov = data.fov;
|
||
this->distance = data.distance;
|
||
this->health = data.health;
|
||
this->damage = data.damage;
|
||
|
||
return *this;
|
||
}
|
||
|
||
scanned_target(C_BaseEntity* ent, float damage, float health, Vector_t eyepos, Vector_t end_pos, C_CSPlayerPawn* record, const scan_data& data) //-V688 //-V818
|
||
{
|
||
this->ent = ent;
|
||
this->record = record;
|
||
this->data = data;
|
||
this->distance = eyepos.DistTo(end_pos);
|
||
this->fov = 0;
|
||
this->health = health;
|
||
this->damage = damage;
|
||
}
|
||
|
||
void reset()
|
||
{
|
||
ent = nullptr;
|
||
record = nullptr;
|
||
data.reset();
|
||
fov = 0.0f;
|
||
distance = 0.0f;
|
||
health = 0;
|
||
damage = 0;
|
||
}
|
||
};
|
||
|
||
|
||
Vector_t last_shoot_position;
|
||
std::vector <scanned_target> scanned_targets;
|
||
scanned_target final_target;
|
||
C_CSPlayerPawn* last_target;
|
||
|
||
std::vector <target> targets;
|
||
// TODO: not sure if this is correct
|
||
float calc_lerp() noexcept {
|
||
|
||
const float cl_interp = I::Cvar->Find(FNV1A::Hash("cl_interp"))->value.fl;
|
||
auto lerp = cl_interp / 64.f;
|
||
|
||
if (lerp <= cl_interp)
|
||
lerp = cl_interp;
|
||
|
||
return lerp;
|
||
}
|
||
|
||
float get_las_valid_sim_time() noexcept {
|
||
auto sv_maxunlag = I::Cvar->Find(FNV1A::Hash("sv_maxunlag"))->value.fl;
|
||
|
||
const auto nci = I::Engine->GetNetChannelInfo(0);
|
||
if (!nci)
|
||
return std::numeric_limits<float>::max();
|
||
|
||
const auto latency = nci->get_latency(flow::FLOW_OUTGOING) + nci->get_latency(FLOW_INCOMING);
|
||
const float correct = std::clamp(latency, 0.0f, sv_maxunlag);
|
||
const float max_delta = std::min((sv_maxunlag - correct), 0.2f) / 1000.f;
|
||
|
||
return I::GlobalVars->flCurtime - max_delta;
|
||
}
|
||
|
||
struct record {
|
||
public:
|
||
bool valid = { };
|
||
float simulation_time = { };
|
||
std::array<bone_data, MAX_STUDIO_BONES> bone_data = { };
|
||
Vector_t head_pos = { };
|
||
};
|
||
|
||
struct record_set {
|
||
public:
|
||
record* record1;
|
||
record* record2;
|
||
float fraction;
|
||
};
|
||
|
||
class backtrack_entity {
|
||
public:
|
||
CBaseHandle handle = {};
|
||
std::vector<record> records = {};
|
||
bool last_valid = { };
|
||
CStrongHandle<CModel> model = { };
|
||
uint32_t num_bones = { };
|
||
CSkeletonInstance* skeleton;
|
||
backtrack_entity(CBaseHandle handle) noexcept : handle(handle) {
|
||
CS_ASSERT(I::GlobalVars);
|
||
auto unlag = I::Cvar->Find(FNV1A::Hash(CS_XOR("sv_maxunlag")))->value.fl;
|
||
auto max_ticks = static_cast<int>(unlag / I::GlobalVars->flIntervalPerTick);
|
||
|
||
if (max_ticks < 0)
|
||
max_ticks = 0;
|
||
|
||
records.resize(max_ticks);
|
||
records.resize(records.capacity()); // basically free, so why not
|
||
}
|
||
|
||
// TODO: not sure if this is correct
|
||
float calc_lerp() noexcept {
|
||
|
||
auto cl_interp = I::Cvar->Find(FNV1A::Hash("cl_interp"))->value.fl;
|
||
auto lerp = cl_interp / 64.f;
|
||
|
||
if (lerp <= cl_interp)
|
||
lerp = cl_interp;
|
||
|
||
return lerp;
|
||
}
|
||
|
||
float get_las_valid_sim_time() noexcept {
|
||
auto sv_maxunlag = I::Cvar->Find(FNV1A::Hash("sv_maxunlag"))->value.fl;
|
||
|
||
const auto nci = I::Engine->GetNetChannelInfo(0);
|
||
if (!nci)
|
||
return std::numeric_limits<float>::max();
|
||
|
||
const auto latency = nci->get_latency(flow::FLOW_OUTGOING) + nci->get_latency(FLOW_INCOMING);
|
||
const float correct = std::clamp(latency , 0.0f, sv_maxunlag);
|
||
const float max_delta = std::min((sv_maxunlag - correct), 0.2f) / 1000.f;
|
||
|
||
return I::GlobalVars->flCurtime - max_delta;
|
||
}
|
||
|
||
void save_data(unsigned int index) noexcept {
|
||
if (records.size() <= 0)
|
||
return;
|
||
|
||
auto& rec = records[index % records.size()];
|
||
|
||
if (!SDK::LocalPawn)
|
||
return;
|
||
|
||
C_CSPlayerPawn* player = final_target.record;
|
||
if (!player || player->GetHealth() <= 0 || player->GetGameSceneNode()->IsDormant()) {
|
||
invalidate();
|
||
return;
|
||
}
|
||
|
||
if (!SDK::LocalPawn->IsOtherEnemy(player)) {
|
||
invalidate();
|
||
return;
|
||
}
|
||
|
||
rec.simulation_time = player->m_flSimulationTime();
|
||
rec.head_pos = player->GetEyePosition();
|
||
|
||
const auto game_scene_node = player->GetGameSceneNode();
|
||
if (!game_scene_node) {
|
||
invalidate();
|
||
return;
|
||
}
|
||
|
||
skeleton = game_scene_node->GetSkeletonInstance();
|
||
if (!skeleton) {
|
||
invalidate();
|
||
return;
|
||
}
|
||
|
||
skeleton->calc_world_space_bones(0, bone_flags::FLAG_HITBOX);
|
||
|
||
auto& model_state = skeleton->GetModel();
|
||
model = model_state.m_hModel();
|
||
if (!model.is_valid()) {
|
||
invalidate();
|
||
return;
|
||
}
|
||
|
||
num_bones = model->GetHitboxesNum();
|
||
if (num_bones == 0) {
|
||
invalidate();
|
||
return;
|
||
}
|
||
|
||
auto bone_data = model_state.GetHitboxData();
|
||
|
||
if (num_bones > MAX_STUDIO_BONES)
|
||
num_bones = MAX_STUDIO_BONES;
|
||
|
||
memcpy(rec.bone_data.data(), bone_data, sizeof(bone_data) * num_bones);
|
||
rec.valid = true;
|
||
last_valid = true;
|
||
}
|
||
|
||
float closest_record(Vector_t start, Vector_t end, float las_valid_sim_time) {
|
||
float closest = std::numeric_limits<float>::max();
|
||
|
||
for (auto& rec : records) {
|
||
if (!rec.valid)
|
||
continue;
|
||
|
||
if (rec.simulation_time <= las_valid_sim_time)
|
||
continue;
|
||
|
||
float dist = get_distance(rec.head_pos, start, end);
|
||
if (dist < closest)
|
||
closest = dist;
|
||
}
|
||
|
||
return closest;
|
||
}
|
||
|
||
record_set find_best_records(Vector_t start, Vector_t end, float las_valid_sim_time) {
|
||
|
||
int best_bone = -1;
|
||
int best_record = -1;
|
||
float best_bone_dist = std::numeric_limits<float>::max();
|
||
|
||
for (int bone_index = 0; bone_index < (int)num_bones; bone_index++) {
|
||
if (!(model->GetHitboxFlags(bone_index) & bone_flags::FLAG_HITBOX)) {
|
||
continue;
|
||
}
|
||
|
||
auto parent_bone_index = model->GetHitboxParent(bone_index);
|
||
if (parent_bone_index == -1)
|
||
continue;
|
||
|
||
for (int record_index = 0; record_index < std::size(records); record_index++) {
|
||
const auto& rec = records[record_index];
|
||
if (!rec.valid)
|
||
continue;
|
||
|
||
if (rec.simulation_time <= las_valid_sim_time)
|
||
continue;
|
||
|
||
const float bone_dist = MATH::segment_dist(start, end, rec.bone_data[bone_index].pos, rec.bone_data[parent_bone_index].pos);
|
||
if (bone_dist < best_bone_dist) {
|
||
best_bone_dist = bone_dist;
|
||
best_bone = bone_index;
|
||
best_record = record_index;
|
||
}
|
||
}
|
||
}
|
||
|
||
CS_ASSERT(best_bone != -1 && best_record != -1);
|
||
|
||
int prev_record = best_record - 1;
|
||
if (prev_record < 0)
|
||
prev_record += records.size();
|
||
if (!records[prev_record].valid)
|
||
prev_record = best_record;
|
||
|
||
int next_record = (best_record + 1) % records.size();
|
||
if (!records[next_record].valid)
|
||
next_record = best_record;
|
||
|
||
const auto& best_rec = records[best_record];
|
||
uint32_t best_bone_parent = model->GetHitboxParent(best_bone);
|
||
|
||
|
||
float prev_dist = MATH::segment_dist(
|
||
start, end,
|
||
records[prev_record].bone_data[best_bone].pos,
|
||
records[prev_record].bone_data[best_bone_parent].pos
|
||
);
|
||
float next_dist = MATH::segment_dist(
|
||
start, end,
|
||
records[next_record].bone_data[best_bone].pos,
|
||
records[next_record].bone_data[best_bone_parent].pos
|
||
);
|
||
|
||
bool prev_is_best = prev_dist < next_dist;
|
||
int rec1_index = prev_is_best ? prev_record : best_record;
|
||
int rec2_index = prev_is_best ? best_record : next_record;
|
||
|
||
// records are the same
|
||
if (rec1_index == rec2_index)
|
||
return { &records[rec1_index], &records[rec2_index], 0.0f };
|
||
|
||
const float best_full_dist = (prev_is_best ? prev_dist : next_dist) + best_bone_dist;
|
||
const float fraction = prev_is_best ? prev_dist / best_full_dist : best_bone_dist / best_full_dist;
|
||
|
||
return { &records[rec1_index], &records[rec2_index], fraction };
|
||
}
|
||
|
||
private:
|
||
|
||
void invalidate() noexcept {
|
||
if (last_valid) {
|
||
for (auto& rec : records)
|
||
rec.valid = false;
|
||
|
||
last_valid = false;
|
||
}
|
||
}
|
||
|
||
float get_distance(Vector_t p, Vector_t a, Vector_t b) {
|
||
Vector_t ap = p - a;
|
||
Vector_t ab = b - a;
|
||
|
||
float ab2 = ab.DotProduct(ab);
|
||
float ap_ab = ap.DotProduct(ab);
|
||
float t = ap_ab / ab2;
|
||
|
||
// ignore if player is behind ur or too far away
|
||
if (t < 0.0f || t > 1.0f)
|
||
return std::numeric_limits<float>::max();
|
||
|
||
Vector_t nearest = a + ab * t;
|
||
return (p - nearest).Length();
|
||
}
|
||
};
|
||
|
||
std::unordered_map<int, std::unique_ptr<backtrack_entity>> records{ };
|
||
void F::LAGCOMP::impl::Initialize() {
|
||
EntCache::RegisterCallback(
|
||
CachedEntity_t::Type::PLAYER_CONTROLLER,
|
||
[](int index, const CBaseHandle handle) noexcept {
|
||
records.insert_or_assign(index, std::make_unique<backtrack_entity>(handle));
|
||
},
|
||
[](int index, const CBaseHandle handle) noexcept {
|
||
records.erase(index);
|
||
}
|
||
);
|
||
}
|
||
void F::LAGCOMP::impl::Render() noexcept {
|
||
|
||
const float las_valid_sim_time = get_las_valid_sim_time();
|
||
for (const auto& [index, entity] : records) {
|
||
if (!entity->last_valid)
|
||
continue;
|
||
|
||
record const* last_record = nullptr;
|
||
float last_record_time = std::numeric_limits<float>::max();
|
||
|
||
for (const auto& rec : entity->records) {
|
||
if (!rec.valid || rec.simulation_time <= las_valid_sim_time)
|
||
continue;
|
||
|
||
if (rec.simulation_time < last_record_time) {
|
||
last_record_time = rec.simulation_time;
|
||
last_record = &rec;
|
||
}
|
||
}
|
||
|
||
if (!last_record)
|
||
continue;
|
||
|
||
L_PRINT(LOG_INFO) << CS_XOR("[record] info | simulation_time: ") << last_record->simulation_time;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[record] info | bone_data: ") << last_record->bone_data[HEAD].pos;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[record] info | head_pos: ") << last_record->head_pos;
|
||
|
||
entity->skeleton->calc_world_space_bones(0, bone_flags::FLAG_HITBOX);
|
||
|
||
for (uint32_t i = 0; i < entity->num_bones; i++) {
|
||
if (!(entity->model->GetHitboxFlags(i) & bone_flags::FLAG_HITBOX)) {
|
||
continue;
|
||
}
|
||
|
||
auto parent_index = entity->model->GetHitboxParent(i);
|
||
if (parent_index == -1)
|
||
continue;
|
||
|
||
ImVec2 screen_pos, screen_parent_pos;
|
||
if (!MATH::WorldToScreen(last_record->bone_data[i].pos, screen_pos))
|
||
continue;
|
||
if (!MATH::WorldToScreen(last_record->bone_data[parent_index].pos, screen_parent_pos))
|
||
continue;
|
||
|
||
C_GET(ColorPickerVar_t, Vars.colSkeletonOutline).colValue.a = C_GET(ColorPickerVar_t, Vars.colSkeleton).colValue.a;
|
||
D::pDrawListActive->AddLine(ImVec2(screen_pos.x, screen_pos.y), ImVec2(screen_parent_pos.x, screen_parent_pos.y), C_GET(ColorPickerVar_t, Vars.colSkeletonOutline).colValue.GetU32(), 2.f);
|
||
D::pDrawListActive->AddLine(ImVec2(screen_pos.x, screen_pos.y), ImVec2(screen_parent_pos.x, screen_parent_pos.y), C_GET(ColorPickerVar_t, Vars.colSkeleton).colValue.GetU32(), 1.f);
|
||
|
||
}
|
||
}
|
||
}
|
||
void F::LAGCOMP::impl::Start(CUserCmd* cmd) noexcept {
|
||
|
||
if (!I::Engine->IsConnected() || !I::Engine->IsInGame())
|
||
return;
|
||
|
||
if (!SDK::LocalController || !SDK::LocalPawn)
|
||
return;
|
||
|
||
auto pLocal = SDK::LocalPawn;
|
||
if (!pLocal || pLocal->GetHealth() <= 0)
|
||
return;
|
||
|
||
for (auto& [index, entity] : records) {
|
||
entity->save_data(cmd->m_csgoUserCmd.m_pBaseCmd->m_nCommandNumber);
|
||
}
|
||
|
||
CPlayer_WeaponServices* WeaponServices = pLocal->GetWeaponServices();
|
||
if (!WeaponServices)
|
||
return;
|
||
|
||
auto active_weapon = I::GameResourceService->pGameEntitySystem->Get<C_CSWeaponBase>(WeaponServices->m_hActiveWeapon());
|
||
if (!active_weapon)
|
||
return;
|
||
|
||
auto v_data = active_weapon->datawep();
|
||
if (!v_data || v_data->m_WeaponType() == WEAPONTYPE_MELEE)
|
||
return;
|
||
|
||
if (!cmd)
|
||
return;
|
||
|
||
if (cmd->m_csgoUserCmd.m_nAttack1StartHhistoryIndex == -1)
|
||
return;
|
||
|
||
const auto sub_tick = cmd->GetInputHistoryEntry(cmd->m_csgoUserCmd.m_nAttack1StartHhistoryIndex);
|
||
|
||
if (!sub_tick || !sub_tick->m_sv_interp0 || !sub_tick->m_sv_interp1) {
|
||
L_PRINT(LOG_ERROR) << (CS_XOR("invalid sub tick"));
|
||
return;
|
||
}
|
||
|
||
Vector_t forward = MATH::angle_vector(sub_tick->m_pViewCmd->m_angValue); //sub_tick[1]-->->angValue.x, sub_tick->pViewCmd->angValue.y, sub_tick->pViewCmd->angValue.z);
|
||
Vector_t start_pos = pLocal->GetEyePosition();
|
||
Vector_t end_pos = start_pos + (forward * v_data->m_flRange());
|
||
const float las_valid_sim_time = get_las_valid_sim_time();
|
||
|
||
L_PRINT(LOG_INFO) << CS_XOR("[lagcomp] get_las_valid_sim_time: ") << get_las_valid_sim_time();
|
||
|
||
int target_index = -1;
|
||
float target_index_dist = std::numeric_limits<float>::max();
|
||
for (auto& [index, entity] : records) {
|
||
if (!entity->last_valid)
|
||
continue;
|
||
|
||
const float distance = entity->closest_record(start_pos, end_pos, las_valid_sim_time);
|
||
if (distance < target_index_dist) {
|
||
target_index = index;
|
||
target_index_dist = distance;
|
||
L_PRINT(LOG_WARNING) << CS_XOR("[lagcomp] Inserted new best record | idx: ") << target_index << " at distanc:" << target_index_dist;
|
||
|
||
}
|
||
}
|
||
|
||
// no entities or to far away
|
||
if (target_index == -1 || target_index_dist > 100.0f)
|
||
return;
|
||
|
||
|
||
const auto entity = records[target_index].get();
|
||
|
||
const auto records = entity->find_best_records(start_pos, end_pos, las_valid_sim_time);
|
||
|
||
const float time_per_tick = I::GlobalVars->flIntervalPerTick;
|
||
const float best_time = std::lerp(records.record1->simulation_time, records.record2->simulation_time, records.fraction);
|
||
const float best_tick_time = best_time / time_per_tick;
|
||
int best_tick = (int)std::floor(best_tick_time);
|
||
const float best_tick_fraction = best_tick_time - best_tick;
|
||
|
||
best_tick -= 1; // FIXME: engine prediction?
|
||
L_PRINT(LOG_INFO) << CS_XOR("[lagcomp] backtracking info | best tick: ") << best_tick << CS_XOR(" | tick fraction:") << best_tick_fraction << CS_XOR(" ticks:") << (I::GlobalVars->flCurtime - best_time) * 1000.f;
|
||
|
||
|
||
|
||
if (!sub_tick->m_cl_interp || !sub_tick->m_sv_interp0 || !sub_tick->m_sv_interp1) {
|
||
L_PRINT(LOG_INFO) << "Invalid sub tick";
|
||
return;
|
||
}
|
||
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] subtick info: ");
|
||
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] cl_interp info | cl_interp tick: ") << sub_tick->m_cl_interp->m_nDstTick;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] cl_interp info | nSrcTick tick: ") << sub_tick->m_cl_interp->m_nSrcTick;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] cl_interp info | flFraction tick: ") << sub_tick->m_cl_interp->m_flFraction;
|
||
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] sv_interp0 info | cl_interp tick: ") << sub_tick->m_sv_interp0->m_nDstTick;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] sv_interp0 info | nSrcTick tick: ") << sub_tick->m_sv_interp0->m_nSrcTick;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] sv_interp0 info | flFraction tick: ") << sub_tick->m_sv_interp0->m_flFraction;
|
||
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] sv_interp1 info | cl_interp tick: ") << sub_tick->m_sv_interp1->m_nDstTick;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] sv_interp1 info | nSrcTick tick: ") << sub_tick->m_sv_interp1->m_nSrcTick;
|
||
L_PRINT(LOG_INFO) << CS_XOR("[subtick] sv_interp1 info | flFraction tick: ") << sub_tick->m_sv_interp1->m_flFraction;
|
||
|
||
sub_tick->m_cl_interp->m_nSrcTick = best_tick;
|
||
sub_tick->m_cl_interp->m_nDstTick = best_tick + 1;
|
||
sub_tick->m_cl_interp->m_flFraction = best_tick_fraction;
|
||
|
||
sub_tick->m_sv_interp0->m_nSrcTick = best_tick;
|
||
sub_tick->m_sv_interp0->m_nDstTick = best_tick + 1;
|
||
sub_tick->m_sv_interp0->m_flFraction = 0.f;
|
||
|
||
sub_tick->m_sv_interp1->m_nSrcTick = best_tick + 1;
|
||
sub_tick->m_sv_interp1->m_nDstTick = best_tick + 2;
|
||
sub_tick->m_sv_interp1->m_flFraction = 0.f;
|
||
|
||
|
||
}
|
||
|
||
|
||
// setup config hitboxes
|
||
void F::RAGE::impl::Scan() {
|
||
|
||
/* emplace menu hitboxes which will be used for hitscan*/
|
||
|
||
if (rage_data.hitbox_head) {
|
||
e_hitboxes.emplace_back(HEAD);
|
||
}
|
||
|
||
if (rage_data.hitbox_chest) {
|
||
e_hitboxes.emplace_back(CHEST);
|
||
e_hitboxes.emplace_back(RIGHT_CHEST);
|
||
e_hitboxes.emplace_back(LEFT_CHEST);
|
||
}
|
||
|
||
if (rage_data.hitbox_stomach) {
|
||
e_hitboxes.emplace_back(STOMACH);
|
||
e_hitboxes.emplace_back(CENTER);
|
||
e_hitboxes.emplace_back(PELVIS);
|
||
}
|
||
|
||
if (rage_data.hitbox_legs) {
|
||
e_hitboxes.emplace_back(L_LEG);
|
||
e_hitboxes.emplace_back(R_LEG);
|
||
}
|
||
if (rage_data.hitbox_feets) {
|
||
e_hitboxes.emplace_back(L_FEET);
|
||
e_hitboxes.emplace_back(R_FEET);
|
||
}
|
||
|
||
return;
|
||
}
|
||
void F::RAGE::impl::Reset(reset type) {
|
||
switch (type) {
|
||
case reset::entity:
|
||
targets.clear();
|
||
break;
|
||
case reset::aimbot:
|
||
e_hitboxes.clear();
|
||
targets.clear();
|
||
scanned_targets.clear();
|
||
break;
|
||
}
|
||
return;
|
||
}
|
||
|
||
void F::RAGE::impl::SetupTarget(C_CSPlayerPawn* pLocal)
|
||
{
|
||
if (!D::pDrawListActive)
|
||
return;
|
||
|
||
if (!I::Engine->IsInGame()) return;
|
||
|
||
CCSPlayerController* pLocalController = CCSPlayerController::GetLocalPlayerController();
|
||
if (!pLocalController)
|
||
return;
|
||
|
||
pLocal = I::GameResourceService->pGameEntitySystem->Get<C_CSPlayerPawn>(pLocalController->GetPawnHandle());
|
||
if (!pLocal)
|
||
return;
|
||
const std::lock_guard<std::mutex> guard{ g_cachedEntitiesMutex };
|
||
|
||
for (const auto& it : g_cachedEntities) {
|
||
|
||
C_BaseEntity* pEntity = I::GameResourceService->pGameEntitySystem->Get(it.m_handle);
|
||
if (pEntity == nullptr)
|
||
continue;
|
||
|
||
CBaseHandle hEntity = pEntity->GetRefEHandle();
|
||
if (hEntity != it.m_handle) continue;
|
||
|
||
if (it.m_type != CachedEntity_t::PLAYER_CONTROLLER)
|
||
continue;
|
||
|
||
CCSPlayerController* CPlayer = I::GameResourceService->pGameEntitySystem->Get<CCSPlayerController>(hEntity);
|
||
if (CPlayer == nullptr)
|
||
break;
|
||
|
||
C_CSPlayerPawn* player = I::GameResourceService->pGameEntitySystem->Get<C_CSPlayerPawn>(CPlayer->GetPawnHandle());
|
||
if (!player)
|
||
continue;
|
||
|
||
if (player->GetHealth() <= 0 || !pLocal->IsOtherEnemy(player) || player->GetGameSceneNode()->IsDormant() || player->m_bGunGameImmunity())
|
||
continue;
|
||
|
||
targets.push_back(target(player, pEntity));
|
||
continue;
|
||
}
|
||
|
||
|
||
|
||
}
|
||
|
||
bool F::RAGE::impl::valid(C_CSPlayerPawn* player, C_CSPlayerPawn* pLocal, bool check) {
|
||
if (!player)
|
||
return false;
|
||
|
||
bool Invalid = player->GetHealth() <= 0 || player->GetLifeState() == ELifeState::LIFE_DISCARDBODY || player->GetLifeState() == ELifeState::LIFE_DEAD || player->GetLifeState() == ELifeState::LIFE_DYING;
|
||
if (Invalid || !pLocal->IsOtherEnemy(player) || player->GetGameSceneNode()->IsDormant() || player->m_bGunGameImmunity())
|
||
return false;
|
||
|
||
return true;
|
||
}
|
||
|
||
static Vector_t get_target_angle(C_CSPlayerPawn* localplayer, Vector_t position)
|
||
{
|
||
Vector_t eye_position = localplayer->GetEyePosition();
|
||
Vector_t angle = position;
|
||
|
||
angle.x = position.x - eye_position.x;
|
||
angle.y = position.y - eye_position.y;
|
||
angle.z = position.z - eye_position.z;
|
||
|
||
angle.Normalizes();
|
||
MATH::vec_angles(angle, &angle);
|
||
|
||
angle.clamp();
|
||
return angle;
|
||
}
|
||
|
||
|
||
std::vector <scan_point> F::RAGE::impl::get_points(C_CSPlayerPawn* pLocal, C_CSPlayerPawn* record, uint32_t hitbox, bool from_aim)// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><> <20><><EFBFBD>
|
||
{
|
||
// removed
|
||
std::vector <scan_point> points;
|
||
return points;
|
||
}
|
||
|
||
void F::RAGE::impl::ScanPoint(C_CSPlayerPawn* pLocal, CUserCmd* cmd, C_CSPlayerPawn* record, scan_data& data, const Vector_t& shoot_pos, bool optimized) {
|
||
auto weapon = pLocal->ActiveWeapon();
|
||
if (!weapon)
|
||
return;
|
||
|
||
auto weapon_info = weapon->datawep();
|
||
|
||
if (!weapon_info)
|
||
return;
|
||
|
||
if (e_hitboxes.empty())
|
||
return;
|
||
|
||
early_stopped = false;
|
||
|
||
auto best_damage = 0;
|
||
|
||
auto minimum_damage = rage_data.minimum_damage;
|
||
|
||
float damage = 0.f;
|
||
bool can_hit = false;
|
||
|
||
std::vector <scan_point> points;
|
||
std::vector <temp_point> temp_points;
|
||
|
||
for (auto& hitbox : e_hitboxes)
|
||
{
|
||
float hitbox_scale = {}; QAngle_t temp_angle = {}; Vector_t hitbox_pos = {}; Vector4D_t hitbox_rot = {}; QAngle_t point_angle = {}; QAngle_t angle = {};
|
||
|
||
// create our ange based on our current point
|
||
record->CalculateHitboxData(hitbox, hitbox_pos, hitbox_rot, hitbox_scale, true);
|
||
|
||
// shit got in vec convert to a quarention angle
|
||
auto vec = get_target_angle(pLocal, hitbox_pos);
|
||
angle.ToVec(vec);
|
||
|
||
damage = rage->ScaleDamage(record, pLocal, weapon, hitbox_pos, damage, can_hit);
|
||
|
||
|
||
if (damage <= 0) {
|
||
temp_points.emplace_back(temp_point(hitbox_pos, point_angle, angle, hitbox, false, damage, can_hit));
|
||
continue;
|
||
}
|
||
else {
|
||
MATH::VectorAngless(pLocal->GetEyePosition() - hitbox_pos, point_angle);
|
||
points.emplace_back(scan_point(hitbox_pos, point_angle, angle, hitbox, false, damage, can_hit));
|
||
}
|
||
}
|
||
|
||
for (auto& temp_point : temp_points)
|
||
{
|
||
if (temp_point.damage > 0)
|
||
continue;
|
||
|
||
data.temp_point = temp_point;
|
||
}
|
||
|
||
if (points.empty())
|
||
return;
|
||
|
||
auto current_minimum_damage = minimum_damage;
|
||
|
||
for (auto& point : points)
|
||
{
|
||
if (point.damage <= 0)
|
||
continue;
|
||
|
||
if (point.damage >= current_minimum_damage && point.damage >= best_damage) {
|
||
best_damage = point.damage;
|
||
data.point = point;
|
||
data.damage = point.damage;
|
||
data.hitbox = point.hitbox;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void F::RAGE::impl::ScanTarget(C_CSPlayerPawn* pLocal, CUserCmd* cmd, QAngle_t viewangles)
|
||
{
|
||
if (!pLocal)
|
||
return;
|
||
|
||
auto weapon = pLocal->ActiveWeapon();
|
||
if (!weapon)
|
||
return;
|
||
|
||
if (!I::Engine->IsConnected() || !I::Engine->IsInGame())
|
||
return;
|
||
|
||
if (targets.size() <= 0)
|
||
return;
|
||
|
||
final_target.reset();
|
||
|
||
for (auto& target : targets)
|
||
{
|
||
auto player = target.handle;
|
||
|
||
if (!player)
|
||
continue;
|
||
|
||
if (!valid(player, pLocal))
|
||
continue;
|
||
|
||
scan_data last_data;
|
||
|
||
rage->ScanPoint(pLocal, cmd, player, last_data, Vector_t(0, 0, 0), true);
|
||
|
||
if (last_data.damage > 0) {
|
||
m_stop = cheat->onground && cheat->canShot;
|
||
rage->AutomaticStop(pLocal, weapon, cmd, early);
|
||
}
|
||
scanned_targets.emplace_back(scanned_target(target.entHandle, last_data.damage, player->GetHealth(), pLocal->GetEyePosition(), player->GetEyePosition(), player, last_data));
|
||
}
|
||
}
|
||
|
||
bool F::RAGE::impl::Ready(C_CSPlayerPawn* pLocal) {
|
||
if (!pLocal)
|
||
return false;
|
||
|
||
auto ActiveWeapon = pLocal->ActiveWeapon();
|
||
|
||
if (!ActiveWeapon)
|
||
return false;
|
||
|
||
auto data = ActiveWeapon->datawep();
|
||
if (!data)
|
||
return false;
|
||
|
||
if (ActiveWeapon->clip1() <= 0)
|
||
return false;
|
||
|
||
|
||
return true;
|
||
}
|
||
|
||
void F::RAGE::impl::Events(IGameEvent* ev, events type) {
|
||
if (!C_GET(bool, Vars.rage_enable))
|
||
return;
|
||
|
||
if (!I::Engine->IsConnected() || !I::Engine->IsInGame())
|
||
return;
|
||
|
||
if (!SDK::LocalController)
|
||
return;
|
||
|
||
switch (type) {
|
||
case player_death: {
|
||
auto controller = SDK::LocalController;
|
||
if (!controller)
|
||
break;
|
||
|
||
const auto event_controller = ev->get_player_controller(CS_XOR("attacker"));
|
||
if (!event_controller)
|
||
return;
|
||
|
||
|
||
if (event_controller->GetIdentity()->GetIndex() == controller->GetIdentity()->GetIndex()) {
|
||
const std::int64_t value{ ev->get_int(CS_XOR("dmg_health")) };
|
||
// reset targets
|
||
scanned_targets.clear();
|
||
targets.clear();
|
||
}
|
||
}
|
||
break;
|
||
case round_start: {
|
||
rage->Reset(reset::entity);
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
inline Vector_t CrossProduct(const Vector_t& a, const Vector_t& b)
|
||
{
|
||
return Vector_t(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x);
|
||
}
|
||
|
||
#define SMALL_NUM 0.00000001 // anything that avoids division overflow
|
||
#define dot(u, v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)
|
||
#define norm(v) sqrt(dot(v, v)) // norm = length of vector
|
||
void VectorAngles(const Vector_t& forward, Vector_t& up, Vector_t& angles)
|
||
{
|
||
Vector_t left = CrossProduct(up, forward);
|
||
left.NormalizeInPlace();
|
||
|
||
float forwardDist = forward.Length2D();
|
||
|
||
if (forwardDist > 0.001f)
|
||
{
|
||
angles.x = atan2f(-forward.z, forwardDist) * 180 / MATH::_PI;
|
||
angles.y = atan2f(forward.y, forward.x) * 180 / MATH::_PI;
|
||
|
||
float upZ = (left.y * forward.x) - (left.x * forward.y);
|
||
angles.z = atan2f(left.z, upZ) * 180 / MATH::_PI;
|
||
}
|
||
else
|
||
{
|
||
angles.x = atan2f(-forward.z, forwardDist) * 180 / MATH::_PI;
|
||
angles.y = atan2f(-left.x, left.y) * 180 / MATH::_PI;
|
||
angles.z = 0;
|
||
}
|
||
}
|
||
|
||
void sin_cos(float radian, float* sin, float* cos)
|
||
{
|
||
*sin = std::sin(radian);
|
||
*cos = std::cos(radian);
|
||
}
|
||
|
||
float GRD_TO_BOG(float GRD)
|
||
{
|
||
return (MATH::_PI / 180) * GRD;
|
||
}
|
||
void AngleVectors(const Vector_t& angles, Vector_t* forward)
|
||
{
|
||
// sry
|
||
//Assert(s_bMathlibInitialized);
|
||
//Assert(forward);
|
||
|
||
float sp, sy, cp, cy;
|
||
|
||
sy = sin(DEG2RAD(angles[1]));
|
||
cy = cos(DEG2RAD(angles[1]));
|
||
|
||
sp = sin(DEG2RAD(angles[0]));
|
||
cp = cos(DEG2RAD(angles[0]));
|
||
|
||
forward->x = cp * cy;
|
||
forward->y = cp * sy;
|
||
forward->z = -sp;
|
||
}
|
||
|
||
void AngleVectors(const Vector_t& angles, Vector_t* forward, Vector_t* right, Vector_t* up)
|
||
{
|
||
float sp, sy, sr, cp, cy, cr;
|
||
|
||
sin_cos(GRD_TO_BOG(angles.x), &sp, &cp);
|
||
sin_cos(GRD_TO_BOG(angles.y), &sy, &cy);
|
||
sin_cos(GRD_TO_BOG(angles.z), &sr, &cr);
|
||
|
||
if (forward != nullptr)
|
||
{
|
||
forward->x = cp * cy;
|
||
forward->y = cp * sy;
|
||
forward->z = -sp;
|
||
}
|
||
|
||
if (right != nullptr)
|
||
{
|
||
right->x = -1 * sr * sp * cy + -1 * cr * -sy;
|
||
right->y = -1 * sr * sp * sy + -1 * cr * cy;
|
||
right->z = -1 * sr * cp;
|
||
}
|
||
|
||
if (up != nullptr)
|
||
{
|
||
up->x = cr * sp * cy + -sr * -sy;
|
||
up->y = cr * sp * sy + -sr * cy;
|
||
up->z = cr * cp;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
float F::RAGE::impl::GetSpread(C_CSWeaponBase* weapon)
|
||
{
|
||
return weapon->get_spread();
|
||
}
|
||
|
||
void F::RAGE::impl::BuildSeed()
|
||
{
|
||
for (auto i = 0; i <= 255; i++) {
|
||
MATH::fnRandomSeed(i + 1);
|
||
|
||
const auto pi_seed = MATH::fnRandomFloat(0.f, 6.283186f);
|
||
|
||
F::RAGE::rage->m_computed_seeds.emplace_back(MATH::fnRandomFloat(0.f, 1.f),
|
||
pi_seed);
|
||
}
|
||
}
|
||
|
||
float F::RAGE::impl::GetInaccuracy(C_CSPlayerPawn* pLocal, C_CSWeaponBase* weapon)
|
||
{
|
||
return weapon->get_inaccuracy();
|
||
}
|
||
|
||
float F::RAGE::impl::HitchanceFast(C_CSPlayerPawn* pLocal, C_CSWeaponBase* weapon)
|
||
{
|
||
if (!weapon)
|
||
return 0.f;
|
||
|
||
if (!weapon->datawep())
|
||
return 0.f;
|
||
|
||
float flInaccuracy = this->GetInaccuracy(pLocal, weapon);
|
||
flInaccuracy = 1 / flInaccuracy;
|
||
|
||
return flInaccuracy;
|
||
}
|
||
void NormalizeAngles(Vector_t& angles)
|
||
{
|
||
for (auto i = 0; i < 3; i++)
|
||
{
|
||
while (angles[i] < -180.0f)
|
||
angles[i] += 360.0f;
|
||
while (angles[i] > 180.0f)
|
||
angles[i] -= 360.0f;
|
||
}
|
||
}
|
||
|
||
|
||
__forceinline Vector_t CalculateSpread(C_CSWeaponBase* weapon, int seed, float inaccuracy, float spread, bool revolver2 = false) {
|
||
const char* item_def_index;
|
||
float recoil_index, r1, r2, r3, r4, s1, c1, s2, c2;
|
||
|
||
if (!weapon)
|
||
return { };
|
||
// if we have no bullets, we have no spread.
|
||
auto wep_info = weapon->datawep();
|
||
if (!wep_info)
|
||
return { };
|
||
|
||
// get some data for later.
|
||
item_def_index = wep_info->m_szName();
|
||
recoil_index = weapon->m_flRecoilIndex();
|
||
|
||
MATH::fnRandomSeed((seed & 0xff) + 1);
|
||
|
||
// generate needed floats.
|
||
r1 = MATH::fnRandomFloat(0.f, 1.f);
|
||
r2 = MATH::fnRandomFloat(0.f, 3.14159265358979323846264338327950288f * 2);
|
||
r3 = MATH::fnRandomFloat(0.f, 1.f);
|
||
r4 = MATH::fnRandomFloat(0.f, 3.14159265358979323846264338327950288f * 2);
|
||
|
||
// revolver secondary spread.
|
||
if (item_def_index == CS_XOR("weapon_revoler") && revolver2) {
|
||
r1 = 1.f - (r1 * r1);
|
||
r3 = 1.f - (r3 * r3);
|
||
}
|
||
|
||
// negev spread.
|
||
else if (item_def_index == CS_XOR("weapon_negev") && recoil_index < 3.f) {
|
||
for (int i{ 3 }; i > recoil_index; --i) {
|
||
r1 *= r1;
|
||
r3 *= r3;
|
||
}
|
||
|
||
r1 = 1.f - r1;
|
||
r3 = 1.f - r3;
|
||
}
|
||
|
||
// get needed sine / cosine values.
|
||
c1 = std::cos(r2);
|
||
c2 = std::cos(r4);
|
||
s1 = std::sin(r2);
|
||
s2 = std::sin(r4);
|
||
|
||
// calculate spread vector.
|
||
return {
|
||
(c1 * (r1 * inaccuracy)) + (c2 * (r3 * spread)),
|
||
(s1 * (r1 * inaccuracy)) + (s2 * (r3 * spread)),
|
||
0.f
|
||
};
|
||
}
|
||
|
||
bool F::RAGE::impl::CanHit(Vector_t start, Vector_t end, C_CSPlayerPawn* pLocal, C_CSPlayerPawn* record, int box)
|
||
{
|
||
if (!pLocal)
|
||
return false;
|
||
|
||
if (!record)
|
||
return false;
|
||
|
||
|
||
return false;
|
||
}
|
||
void F::RAGE::impl::Hitchance(C_CSPlayerPawn* pLocal, C_CSPlayerPawn* ent, C_CSWeaponBase* weapon, QAngle_t vAimpoint)
|
||
{
|
||
if (!pLocal)
|
||
return;
|
||
|
||
|
||
if (!weapon)
|
||
return;
|
||
|
||
auto data = weapon->datawep();
|
||
if (!data)
|
||
return;
|
||
|
||
float HITCHANCE_MAX = 100.f;
|
||
constexpr int SEED_MAX = 255;
|
||
|
||
Vector_t start{ pLocal->GetEyePosition() }, end, fwd, right, up, dir, wep_spread;
|
||
float inaccuracy, spread;
|
||
float hitchance = rage_data.rage_hitchance;
|
||
Vector_t point = Vector_t(vAimpoint.x, vAimpoint.y, vAimpoint.z);
|
||
|
||
if (hitchance <= 0) {
|
||
rage_data.accurate = true;
|
||
return;
|
||
}
|
||
|
||
// we cant reach it anymore too far
|
||
if (pLocal->GetEyePosition().DistTo(point) > data->m_flRange()) {
|
||
rage_data.accurate = false;
|
||
return;
|
||
}
|
||
|
||
size_t total_hits{ }, needed_hits{ (size_t)std::ceil((hitchance * SEED_MAX) / HITCHANCE_MAX) };
|
||
|
||
// get needed directional vectors.
|
||
MATH::anglevectors(vAimpoint, &fwd, &right, &up);
|
||
|
||
// store off inaccuracy / spread ( these functions are quite intensive and we only need them once ).
|
||
inaccuracy = this->GetInaccuracy(pLocal, weapon);
|
||
spread = this->GetSpread(weapon);
|
||
|
||
// iterate all possible seeds.
|
||
for (int i{ }; i <= SEED_MAX; ++i) {
|
||
// get spread.
|
||
wep_spread = CalculateSpread( weapon, i, inaccuracy, spread);
|
||
|
||
// get spread direction.
|
||
dir = (fwd + (right * wep_spread.x) + (up * wep_spread.y)).normalized();
|
||
|
||
// get end of trace.
|
||
end = start - (dir * data->m_flRange());
|
||
|
||
trace_filter_t filter = {};
|
||
I::Trace->Init(filter, pLocal, MASK_SHOT, 3, 7);
|
||
|
||
game_trace_t trace = {};
|
||
ray_t ray = {};
|
||
|
||
I::Trace->TraceShape(ray, &start, &end, filter, trace);
|
||
I::Trace->ClipTraceToPlayers(start, end, &filter, &trace, 0.F, 60.F, (1.F / (start - end).Length()) * (trace.m_end_pos - start).Length());
|
||
|
||
if (trace.HitEntity && trace.HitEntity->GetRefEHandle().GetEntryIndex() == ent->GetRefEHandle().GetEntryIndex())
|
||
++total_hits;
|
||
|
||
// we made it.
|
||
if (total_hits >= needed_hits) {
|
||
rage_data.accurate = true;
|
||
|
||
}
|
||
// we cant make it anymore.
|
||
if ((SEED_MAX - i + total_hits) < needed_hits) {
|
||
rage_data.accurate = false;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
void VectorAngles2(const Vector_t& forward, Vector_t& angles)
|
||
{
|
||
float tmp, yaw, pitch;
|
||
|
||
if (forward[1] == 0 && forward[0] == 0)
|
||
{
|
||
yaw = 0;
|
||
if (forward[2] > 0)
|
||
pitch = 270;
|
||
else
|
||
pitch = 90;
|
||
}
|
||
else
|
||
{
|
||
yaw = (atan2(forward[1], forward[0]) * 180 / M_PI);
|
||
if (yaw < 0)
|
||
yaw += 360;
|
||
|
||
tmp = sqrt(forward[0] * forward[0] + forward[1] * forward[1]);
|
||
pitch = (atan2(-forward[2], tmp) * 180 / M_PI);
|
||
if (pitch < 0)
|
||
pitch += 360;
|
||
}
|
||
|
||
angles[0] = pitch;
|
||
angles[1] = yaw;
|
||
angles[2] = 0;
|
||
}
|
||
// Linear interpolation function
|
||
template <typename T>
|
||
T Lerp(float t, const T& start, const T& end) {
|
||
return start + t * (end - start);
|
||
}
|
||
|
||
const char* GetExtractedWeaponName(C_CSWeaponBase* weapon)
|
||
{
|
||
if (!weapon)
|
||
return "";
|
||
|
||
auto weapon_data = weapon->datawep();
|
||
if (!weapon_data)
|
||
return "";
|
||
|
||
const char* szWeaponName = weapon_data->m_szName();
|
||
const char* weaponPrefix = ("weapon_");
|
||
const char* weaponNameStart = strstr(szWeaponName, weaponPrefix);
|
||
const char* extractedWeaponName = weaponNameStart ? weaponNameStart + strlen(weaponPrefix) : szWeaponName;
|
||
|
||
return extractedWeaponName;
|
||
}
|
||
|
||
|
||
void F::RAGE::impl::AutomaticStop(C_CSPlayerPawn* pLocal, C_CSWeaponBase* weapon, CUserCmd* cmd, stop_mode mode)
|
||
{
|
||
if (!pLocal || !weapon)
|
||
return;
|
||
|
||
if (!pLocal->IsValidMoveType() || !cheat->onground)
|
||
return;
|
||
|
||
if (rage_data.rage_hitchance <= 0.f)
|
||
return;
|
||
|
||
auto movesys = pLocal->m_pMovementServices();
|
||
if (!movesys) {
|
||
return;
|
||
}
|
||
auto weapon_data = weapon->datawep();
|
||
|
||
if (!weapon_data)
|
||
return;
|
||
|
||
if ((weapon->m_zoomLevel() == 0 && weapon_data->m_WeaponType() == WEAPONTYPE_SNIPER_RIFLE))
|
||
return;
|
||
|
||
if (!m_stop)
|
||
return;
|
||
|
||
if (!rage_data.auto_stop)
|
||
return;
|
||
|
||
float m_max_speed = weapon->get_max_speed();
|
||
Vector_t velocity = pLocal->m_vecVelocity();
|
||
|
||
|
||
const char* extractedWeaponName = GetExtractedWeaponName(weapon);
|
||
|
||
bool has_autos = strcmp(extractedWeaponName, CS_XOR("scar20")) == 0 || strcmp(extractedWeaponName, CS_XOR("g3sg1")) == 0;
|
||
if (!cheat->canShot && !has_autos && weapon_data->m_WeaponType() == WEAPONTYPE_SNIPER_RIFLE)
|
||
return;
|
||
|
||
// set z to 0
|
||
velocity.z = 0.f;
|
||
|
||
float speed = velocity.Length2D();
|
||
|
||
// we are pressing move keys
|
||
bool pressing_move_keys = (cmd->m_nButtons.m_nValue & IN_FORWARD || cmd->m_nButtons.m_nValue & IN_MOVELEFT ||
|
||
cmd->m_nButtons.m_nValue & IN_BACK || cmd->m_nButtons.m_nValue & IN_MOVERIGHT);
|
||
|
||
cmd->m_nButtons.m_nValue &= ~(IN_MOVERIGHT | IN_MOVELEFT | IN_FORWARD | IN_BACK | IN_SPEED);
|
||
|
||
bool fullstop = true;
|
||
float addspeed, accelspeed;
|
||
auto accel = I::Cvar->Find(FNV1A::Hash(CS_XOR("sv_accelerate")))->value.fl;
|
||
float max_accurate_speed = (m_max_speed * 0.33000001);
|
||
bool inaccurate_speed = speed > max_accurate_speed;
|
||
float surfaceFriction = pLocal->m_pMovementServices()->m_flSurfaceFriction();
|
||
float wish_speed = sqrt(cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove * cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove + cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove * cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove);
|
||
|
||
|
||
Vector_t angle;
|
||
MATH::vec_angles(velocity, &angle);
|
||
angle.y = cmd->m_csgoUserCmd.m_pBaseCmd->m_pViewangles->m_angValue.y - angle.y;
|
||
|
||
Vector_t direction;
|
||
AngleVectors(angle, &direction);
|
||
|
||
Vector_t stop = direction * -speed;
|
||
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove = 0;
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove = 0;
|
||
if (speed > max_accurate_speed) {
|
||
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove = 0;
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove = 0;
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove = stop.x;
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove = stop.y;
|
||
}
|
||
else {
|
||
float sidemove = cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove;
|
||
float forwardmove = cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove;
|
||
float upmove = cmd->m_csgoUserCmd.m_pBaseCmd->m_flUpMove;
|
||
|
||
float move_speed = std::sqrt(std::pow(sidemove, 2) + std::pow(forwardmove, 2) + std::pow(upmove, 2));
|
||
|
||
if (move_speed > max_accurate_speed) {
|
||
float desaccel = max_accurate_speed / move_speed;
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove *= desaccel;
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove *= desaccel;
|
||
}
|
||
else
|
||
{
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flForwardMove = 0;
|
||
cmd->m_csgoUserCmd.m_pBaseCmd->m_flSideMove = 0;
|
||
}
|
||
}
|
||
|
||
}/*
|
||
void F::RAGE::impl::AutomaticStop(C_CSPlayerPawn* pLocal, C_CSWeaponBase* weapon, CUserCmd* cmd, stop_mode mode)
|
||
{
|
||
if (!pLocal || !weapon)
|
||
return;
|
||
|
||
if (!pLocal->IsValidMoveType() || !cheat->onground) {
|
||
return;
|
||
}
|
||
|
||
if (rage_data.rage_hitchance <= 0.f)
|
||
return;
|
||
|
||
auto movesys = pLocal->m_pMovementServices();
|
||
if (!movesys) {
|
||
return;
|
||
}
|
||
auto weapon_data = weapon->datawep();
|
||
|
||
if (!weapon_data)
|
||
return;
|
||
|
||
if ((weapon->m_zoomLevel() == 0 && weapon_data->m_WeaponType() == WEAPONTYPE_SNIPER_RIFLE))
|
||
return;
|
||
|
||
const char* extractedWeaponName = GetExtractedWeaponName(weapon);
|
||
|
||
bool has_autos = strcmp(extractedWeaponName, CS_XOR("scar20")) == 0 || strcmp(extractedWeaponName, CS_XOR("g3sg1")) == 0;
|
||
bool has_snipers = strcmp(extractedWeaponName, CS_XOR("awp")) == 0 || strcmp(extractedWeaponName, CS_XOR("ssg08")) == 0;
|
||
|
||
auto m_max_cycle = weapon->m_weaponMode() == CSWeaponMode::Primary_Mode ? weapon_data->m_flCycleTime().flValue[0] : weapon_data->m_flCycleTime().flValue[1];
|
||
|
||
const float max_speed = weapon->m_weaponMode() == CSWeaponMode::Primary_Mode ? weapon_data->m_flMaxSpeed().flValue[0] : weapon_data->m_flMaxSpeed().flValue[1];
|
||
const float max_accurate_speed_percentage = 0.34f; // Adjust the percentage as needed
|
||
const float max_accurate_speed = max_speed * max_accurate_speed_percentage;
|
||
const float cur_speed = pLocal->m_vecVelocity().Length2D();
|
||
|
||
if (mode == slow) {
|
||
if (has_autos) {
|
||
if (pLocal->m_vecVelocity().Length2D() < 5.f)
|
||
return;
|
||
}
|
||
else {
|
||
if (!cheat->canShot)
|
||
return;
|
||
|
||
if (has_snipers) {
|
||
if (pLocal->m_vecVelocity().Length2D() < 5.f)
|
||
return;
|
||
}
|
||
else {
|
||
if (pLocal->m_vecVelocity().Length2D() < 15.f)
|
||
return;
|
||
}
|
||
|
||
}
|
||
if (m_stop) {
|
||
cmd->nButtons.nValue &= ~(IN_MOVERIGHT | IN_MOVELEFT | IN_FORWARD | IN_BACK | IN_SPEED);
|
||
|
||
// get velocity data
|
||
static float vel = pLocal->m_vecVelocity().length();
|
||
|
||
bool vel_accurate = (cur_speed <= max_accurate_speed);
|
||
// if we're inside limit accurate speed maintain velocity
|
||
if (vel_accurate) {
|
||
int a = MATH::fnRandomInt(0, 1);
|
||
|
||
// randomly switch mode
|
||
if (a == 0) {
|
||
QAngle_t resist_angle;
|
||
MATH::VectorAngless((pLocal->m_vecVelocity() * -1), resist_angle);
|
||
resist_angle.y = cmd->pBaseCmd->pCmdView->angValue.y - resist_angle.y;
|
||
|
||
Vector_t resistance = Vector_t(0, 0, 0);
|
||
MATH::anglevectors(resist_angle, &resistance);
|
||
|
||
// set movement
|
||
cmd->pBaseCmd->flForwardMove = std::clamp(resist_angle.x, -450.f, 450.f);
|
||
cmd->pBaseCmd->flSideMove = std::clamp(resist_angle.y, -450.f, 450.f);
|
||
}
|
||
else {
|
||
// force movement
|
||
cmd->pBaseCmd->flSideMove = 0.f;
|
||
cmd->pBaseCmd->flForwardMove = 0.f;
|
||
|
||
// clamp movement
|
||
cmd->pBaseCmd->flSideMove = std::clamp(cmd->pBaseCmd->flSideMove, -450.f, 450.f);
|
||
cmd->pBaseCmd->flForwardMove = std::clamp(cmd->pBaseCmd->flForwardMove, -450.f, 450.f);
|
||
}
|
||
|
||
// prevent we autostopping but unable to shoot due to wrong accurate speed
|
||
// full stop imediatly otherwise we delayshooting rn
|
||
if (pLocal->GetShotsFired() <= 0 && !has_autos) {
|
||
cmd->nButtons.nValue &= ~(IN_MOVERIGHT | IN_MOVELEFT | IN_FORWARD | IN_BACK | IN_SPEED);
|
||
// force movement
|
||
cmd->pBaseCmd->flSideMove = 0.f;
|
||
cmd->pBaseCmd->flForwardMove = 0.f;
|
||
cmd->nButtons.nValue &= ~(IN_MOVERIGHT | IN_MOVELEFT | IN_FORWARD | IN_BACK | IN_SPEED);
|
||
|
||
// clamp movement
|
||
cmd->pBaseCmd->flSideMove = std::clamp(cmd->pBaseCmd->flSideMove, -450.f, 450.f);
|
||
cmd->pBaseCmd->flForwardMove = std::clamp(cmd->pBaseCmd->flForwardMove, -450.f, 450.f);
|
||
return;
|
||
}
|
||
} // just slowly resist angle at high velocity then maintain the speed
|
||
else {
|
||
cmd->pBaseCmd->flSideMove = 0.f;
|
||
cmd->pBaseCmd->flForwardMove = 0.f;
|
||
QAngle_t resist_angle;
|
||
MATH::VectorAngless((pLocal->m_vecVelocity() * -1), resist_angle);
|
||
resist_angle.y = cmd->pBaseCmd->pCmdView->angValue.y - resist_angle.y;
|
||
Vector_t resistance = Vector_t(0, 0, 0);
|
||
MATH::anglevectors(resist_angle, &resistance);
|
||
// set movement
|
||
cmd->pBaseCmd->flForwardMove = std::clamp(resist_angle.x, -450.f, 450.f);
|
||
cmd->pBaseCmd->flSideMove = std::clamp(resist_angle.y, -450.f, 450.f);
|
||
}
|
||
m_stop = false;
|
||
}
|
||
}
|
||
// just full stop
|
||
else if (mode == early && m_stop) {
|
||
if (!weapon_data->m_bIsFullAuto() && !cheat->canShot)
|
||
return;
|
||
|
||
if (!weapon_data->m_bIsFullAuto()) {
|
||
|
||
cmd->pBaseCmd->flForwardMove = 0.f;
|
||
cmd->pBaseCmd->flSideMove = 0.f;
|
||
QAngle_t resist_angle;
|
||
MATH::VectorAngless((pLocal->m_vecVelocity() * -1), resist_angle);
|
||
resist_angle.y = cmd->pBaseCmd->pCmdView->angValue.y - resist_angle.y;
|
||
|
||
Vector_t resistance = Vector_t(0, 0, 0);
|
||
MATH::anglevectors(resist_angle, &resistance);
|
||
|
||
// set movement
|
||
cmd->pBaseCmd->flForwardMove = std::clamp(resist_angle.x, -450.f, 450.f);
|
||
cmd->pBaseCmd->flSideMove = std::clamp(resist_angle.y, -450.f, 450.f);
|
||
}
|
||
|
||
cmd->pBaseCmd->flForwardMove = 0.f;
|
||
cmd->pBaseCmd->flSideMove = 0.f;
|
||
m_stop = false;
|
||
}
|
||
|
||
}*/
|
||
static bool compare_targets(const scanned_target& first, const scanned_target& second)
|
||
{
|
||
// higher damage is preferred
|
||
if (first.damage > second.damage)
|
||
return true;
|
||
else if (first.damage < second.damage)
|
||
return false;
|
||
|
||
// lower distance is preferred if damages are equal
|
||
return first.distance < second.distance;
|
||
}
|
||
|
||
void F::RAGE::impl::SortTarget()
|
||
{
|
||
auto validate_target = [&](scanned_target* a, scanned_target* b) -> bool {
|
||
if (!a || !b)
|
||
goto fuck_yeah;
|
||
|
||
|
||
if (last_target != nullptr && last_target->GetHealth() <= 0 && a->record->GetIdentity()->GetIndex() != last_target->GetIdentity()->GetIndex() && last_target->GetIdentity()->GetIndex() <= 64) {
|
||
return true;
|
||
}
|
||
|
||
if (a->damage == b->damage)
|
||
return a->distance < b->distance;
|
||
|
||
return a->damage > b->damage;
|
||
|
||
fuck_yeah:
|
||
// this might not make sense to you, but it actually does.
|
||
return (a != nullptr || (a != nullptr && b != nullptr && a == b)) ? true : false;
|
||
};
|
||
|
||
for (auto& data : scanned_targets) {
|
||
|
||
if (data.damage < 1.f)
|
||
continue;
|
||
|
||
if (!final_target.record) {
|
||
final_target = data;
|
||
|
||
// we only have one entry (target)? let's skip target selection..
|
||
if (scanned_targets.size() == 1)
|
||
break;
|
||
else
|
||
continue;
|
||
}
|
||
|
||
if (last_target != nullptr && last_target->GetHealth() <= 0 && data.record->GetIdentity()->GetIndex() != last_target->GetIdentity()->GetIndex()) {
|
||
continue;
|
||
}
|
||
|
||
// sort our target based on our conditions
|
||
if (validate_target(&data, &final_target)) {
|
||
final_target = data;
|
||
continue;
|
||
}
|
||
}
|
||
|
||
}
|
||
float F::RAGE::impl::ScaleDamage(C_CSPlayerPawn* target, C_CSPlayerPawn* pLocal, C_CSWeaponBase* weapon, Vector_t aim_point, float& dmg, bool& canHit)
|
||
{
|
||
if (!pLocal || !weapon || !target)
|
||
return 0.f;
|
||
|
||
if (pLocal->GetHealth() <= 0)
|
||
return 0.f;
|
||
|
||
auto vdata = weapon->datawep();
|
||
if (!vdata)
|
||
return 0.f;
|
||
|
||
auto entity = I::GameResourceService->pGameEntitySystem->Get(target->GetRefEHandle());
|
||
if (!entity)
|
||
return 0.f;
|
||
|
||
auto localent = I::GameResourceService->pGameEntitySystem->Get(pLocal->GetRefEHandle());
|
||
if (!localent)
|
||
return 0.f;
|
||
|
||
float damage = 0.f;
|
||
F::AUTOWALL::c_auto_wall::data_t data;
|
||
F::AUTOWALL::g_auto_wall->pen(data, pLocal->GetEyePosition(), aim_point, entity, localent, pLocal, target, vdata, damage, canHit);
|
||
return data.m_can_hit ? data.m_dmg : 0.f;
|
||
}
|
||
|
||
void F::RAGE::impl::AjustRecoil(C_CSPlayerPawn* player, CUserCmd* pCmd) {
|
||
if (!player || !pCmd) return;
|
||
|
||
}
|
||
|
||
void F::RAGE::impl::Run(C_CSPlayerPawn* pLocal, CCSGOInput* pInput, CUserCmd* cmd) {
|
||
|
||
|
||
if (!C_GET(bool, Vars.rage_enable))
|
||
return;
|
||
|
||
if (!I::Engine->IsConnected() || !I::Engine->IsInGame())
|
||
return;
|
||
|
||
if (!SDK::LocalController || !SDK::LocalPawn)
|
||
return;
|
||
|
||
// sanity check
|
||
if (!pLocal || pLocal->GetHealth() <= 0) {
|
||
last_target = nullptr;
|
||
return;
|
||
}
|
||
|
||
if (!pInput || !cmd)
|
||
return;
|
||
|
||
auto pCmd = cmd->m_csgoUserCmd.m_pBaseCmd;
|
||
if (!pCmd)
|
||
return;
|
||
|
||
rage->Reset(reset::aimbot);
|
||
|
||
// setup menu adaptive weapon with rage data
|
||
rage->SetupAdaptiveWeapon(pLocal);
|
||
|
||
// reset subtick data
|
||
sub_tick_data.reset();
|
||
|
||
// reset hitchance data
|
||
rage_data.accurate = false;
|
||
|
||
// no ammo or not valid weapon
|
||
if (!rage->Ready(pLocal))
|
||
return;
|
||
|
||
VIRTUALIZER_TIGER_WHITE_START
|
||
|
||
// hitbox menu selection
|
||
rage->Scan();
|
||
|
||
// store targets in server
|
||
rage->SetupTarget(pLocal);
|
||
|
||
// keep scanned targets getting updated
|
||
scanned_targets.clear();
|
||
|
||
// scan & select them based on our conditions
|
||
rage->ScanTarget(pLocal, cmd, pCmd->m_pViewangles->m_angValue);
|
||
|
||
if (scanned_targets.empty())
|
||
return;
|
||
|
||
auto weapon_data = pLocal->ActiveWeapon();
|
||
if (!weapon_data)
|
||
return;
|
||
|
||
auto vdata = weapon_data->datawep();
|
||
if (!vdata)
|
||
return;
|
||
|
||
if (last_target != nullptr && last_target->GetHealth() <= 0) {
|
||
last_target = nullptr;
|
||
}
|
||
|
||
// select best target
|
||
rage->SortTarget();
|
||
|
||
if (!(final_target.data.valid()))
|
||
return;
|
||
|
||
auto best_target = final_target;
|
||
|
||
Hitchance(pLocal, best_target.record, weapon_data, best_target.data.point.pointangle);
|
||
m_stop = cheat->onground && !rage_data.accurate;
|
||
|
||
bool can_scope = weapon_data->m_zoomLevel() == 0 && weapon_data->datawep()->m_WeaponType() == WEAPONTYPE_SNIPER_RIFLE;
|
||
if (can_scope && !rage_data.rapid_fire) {
|
||
cmd->m_nButtons.m_nValue |= IN_SECOND_ATTACK;
|
||
}
|
||
|
||
rage->AutomaticStop(pLocal, weapon_data, cmd, slow);
|
||
|
||
// calculate aimpunch & compensate it
|
||
static auto prev = QAngle_t(0.f, 0.f, 0.f);
|
||
auto cache = pLocal->m_aimPunchCache();
|
||
auto pred_punch = cache.m_Data[cache.m_Size - 1];
|
||
auto delta = prev - pred_punch * 2.f;
|
||
if (cache.m_Size > 0 && cache.m_Size <= 0xFFFF) {
|
||
pred_punch = cache.m_Data[cache.m_Size - 1];
|
||
prev = pred_punch;
|
||
}
|
||
|
||
const float time_per_tick = I::GlobalVars->flIntervalPerTick;
|
||
const float best_time = final_target.record->m_flSimulationTime();
|
||
const float best_tick_time = best_time / time_per_tick;
|
||
int best_tick = (int)std::floor(best_tick_time);
|
||
const float best_tick_fraction = best_tick_time - best_tick;
|
||
|
||
best_tick -= 1; // FIXME: engine prediction?
|
||
// store best_point with compensated aimpunch
|
||
auto best_point = final_target.data.point.angle + delta * 2.f;
|
||
|
||
/* for (int i = 0; i < cmd->m_csgoUserCmd.m_inputHistoryField.m_pRep->m_nAllocatedSize; i++)
|
||
{
|
||
CCSGOInputHistoryEntryPB* pInputEntry = cmd->GetInputHistoryEntry(i);
|
||
if (pInputEntry == nullptr)
|
||
continue;
|
||
|
||
if (pInputEntry->m_pViewCmd == nullptr)
|
||
continue;
|
||
|
||
pInputEntry->m_pViewCmd->m_angValue = best_point;
|
||
}
|
||
*/
|
||
|
||
cmd->SetSubTickAngle(best_point);
|
||
if (cheat->canShot) {
|
||
if (rage_data.rapid_fire && rage_data.accurate) {
|
||
sub_tick_data.command = command_msg::rapid_fire;
|
||
sub_tick_data.best_point = best_point;
|
||
}
|
||
else
|
||
{
|
||
if (rage_data.accurate) {
|
||
sub_tick_data.command = command_msg::silent;
|
||
sub_tick_data.best_point = best_point;
|
||
|
||
// our InputMessage set our predicted subtick viewangles to best point we ready to shoot
|
||
cmd->AdjustAttackStartIndex(pCmd->m_nTickCount - 1);
|
||
cmd->m_nButtons.m_nValue |= IN_ATTACK;
|
||
}
|
||
/* else if (rage_data.rapid_fire && cheat->canShot) {
|
||
cmd->m_csgoUserCmd.m_nAttack1StartHhistoryIndex = pCmd->m_nTickCount - 1;
|
||
|
||
if (!(cmd->m_nButtons.m_nValue & IN_ATTACK)) {
|
||
L_PRINT(LOG_INFO) << "shooting";
|
||
cmd->m_nButtons.m_nValue |= IN_ATTACK;
|
||
}
|
||
L_PRINT(LOG_INFO) << "on rapid fire";
|
||
|
||
for (int i = 0; i < cmd->m_csgoUserCmd.m_inputHistoryField.m_pRep->m_nAllocatedSize; i++)
|
||
{
|
||
CCSGOInputHistoryEntryPB* pInputEntry = cmd->GetInputHistoryEntry(i);
|
||
if (pInputEntry == nullptr)
|
||
continue;
|
||
if (pInputEntry->m_pViewCmd == nullptr)
|
||
continue;
|
||
|
||
|
||
pInputEntry->m_nPlayerTickCount = 0;
|
||
L_PRINT(LOG_INFO) << "tick:" << pInputEntry->m_nPlayerTickCount;
|
||
|
||
}
|
||
*/
|
||
}
|
||
} // run rapid fire on ( awp, scout, scar ) regeardless if we can shoot or not to avoid delays and shit.
|
||
else if (rage_data.accurate && rage_data.rapid_fire && weapon_data->datawep()->m_WeaponType() == WEAPONTYPE_SNIPER_RIFLE) {
|
||
sub_tick_data.command = command_msg::rapid_fire;
|
||
sub_tick_data.best_point = best_point;
|
||
}
|
||
else
|
||
sub_tick_data.command = command_msg::none;
|
||
|
||
|
||
last_target = final_target.record;
|
||
|
||
VIRTUALIZER_MUTATE_ONLY_END;
|
||
}
|
||
|
||
void F::RAGE::impl::SetupAdaptiveWeapon(C_CSPlayerPawn* pLocal) {
|
||
if (!C_GET(bool, Vars.rage_enable))
|
||
return;
|
||
|
||
if (!pLocal)
|
||
return;
|
||
|
||
if (pLocal->GetHealth() <= 0)
|
||
return;
|
||
|
||
|
||
auto ActiveWeapon = pLocal->ActiveWeapon();
|
||
if (!ActiveWeapon)
|
||
return;
|
||
|
||
auto data = ActiveWeapon->datawep();
|
||
if (!data)
|
||
return;
|
||
|
||
if (!ActiveWeapon->IsWeapon())
|
||
return;
|
||
|
||
const char* extractedWeaponName = GetExtractedWeaponName(ActiveWeapon);
|
||
|
||
bool has_awp = strcmp(extractedWeaponName, CS_XOR("awp")) == 0;
|
||
bool has_heavy_pistols = strcmp(extractedWeaponName, CS_XOR("revolver")) == 0 || strcmp(extractedWeaponName, CS_XOR("deagle")) == 0;
|
||
bool has_scout = strcmp(extractedWeaponName, CS_XOR("ssg08")) == 0;
|
||
rage_data.rage_enable = C_GET(bool, Vars.rage_enable);
|
||
|
||
if (has_awp) {
|
||
rage_data.minimum_damage = C_GET_ARRAY(int, 7, Vars.rage_minimum_damage, 6);
|
||
rage_data.rage_hitchance = C_GET_ARRAY(int, 7, Vars.rage_minimum_hitchance, 6);
|
||
rage_data.auto_stop = C_GET_ARRAY(bool, 7, Vars.rage_auto_stop, 6);
|
||
rage_data.penetration = C_GET_ARRAY(bool, 7, Vars.rage_penetration, 6);
|
||
rage_data.rage_target_select = C_GET_ARRAY(int, 7, Vars.rage_target_select, 6);
|
||
rage_data.hitbox_head = C_GET_ARRAY(bool, 7, Vars.hitbox_head, 6);
|
||
rage_data.hitbox_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_chest, 6);
|
||
rage_data.hitbox_stomach = C_GET_ARRAY(bool, 7, Vars.hitbox_stomach, 6);
|
||
rage_data.hitbox_legs = C_GET_ARRAY(bool, 7, Vars.hitbox_legs, 6);
|
||
rage_data.hitbox_feets = C_GET_ARRAY(bool, 7, Vars.hitbox_feet, 6);
|
||
rage_data.rapid_fire = C_GET_ARRAY(bool, 7, Vars.rapid_fire, 6);
|
||
}
|
||
else if (has_scout) {
|
||
rage_data.minimum_damage = C_GET_ARRAY(int, 7, Vars.rage_minimum_damage, 5);
|
||
rage_data.rage_hitchance = C_GET_ARRAY(int, 7, Vars.rage_minimum_hitchance, 5);
|
||
rage_data.auto_stop = C_GET_ARRAY(bool, 7, Vars.rage_auto_stop, 5);
|
||
rage_data.penetration = C_GET_ARRAY(bool, 7, Vars.rage_penetration, 5);
|
||
rage_data.rage_target_select = C_GET_ARRAY(int, 7, Vars.rage_target_select, 5);
|
||
rage_data.remove_weapon_accuracy_spread = C_GET_ARRAY(bool, 7, Vars.remove_weapon_accuracy_spread, 5);
|
||
rage_data.hitbox_head = C_GET_ARRAY(bool, 7, Vars.hitbox_head, 5);
|
||
rage_data.hitbox_neck = C_GET_ARRAY(bool, 7, Vars.hitbox_neck, 5);
|
||
rage_data.hitbox_uppeer_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_uppeer_chest, 5);
|
||
rage_data.hitbox_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_chest, 5);
|
||
rage_data.hitbox_stomach = C_GET_ARRAY(bool, 7, Vars.hitbox_stomach, 5);
|
||
rage_data.hitbox_legs = C_GET_ARRAY(bool, 7, Vars.hitbox_legs, 5);
|
||
rage_data.hitbox_feets = C_GET_ARRAY(bool, 7, Vars.hitbox_feet, 5);
|
||
rage_data.rapid_fire = C_GET_ARRAY(bool, 7, Vars.rapid_fire, 5);
|
||
|
||
}
|
||
else if (has_heavy_pistols) {
|
||
rage_data.minimum_damage = C_GET_ARRAY(int, 7, Vars.rage_minimum_damage, 2);
|
||
rage_data.rage_hitchance = C_GET_ARRAY(int, 7, Vars.rage_minimum_hitchance, 2);
|
||
rage_data.auto_stop = C_GET_ARRAY(bool, 7, Vars.rage_auto_stop, 2);
|
||
rage_data.penetration = C_GET_ARRAY(bool, 7, Vars.rage_penetration, 2);
|
||
rage_data.rage_target_select = C_GET_ARRAY(int, 7, Vars.rage_target_select, 2);
|
||
rage_data.remove_weapon_accuracy_spread = C_GET_ARRAY(bool, 7, Vars.remove_weapon_accuracy_spread, 2);
|
||
rage_data.hitbox_head = C_GET_ARRAY(bool, 7, Vars.hitbox_head, 2);
|
||
rage_data.hitbox_neck = C_GET_ARRAY(bool, 7, Vars.hitbox_neck, 2);
|
||
rage_data.hitbox_uppeer_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_uppeer_chest, 2);
|
||
rage_data.hitbox_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_chest, 2);
|
||
rage_data.hitbox_stomach = C_GET_ARRAY(bool, 7, Vars.hitbox_stomach, 2);
|
||
rage_data.hitbox_legs = C_GET_ARRAY(bool, 7, Vars.hitbox_legs, 2);
|
||
rage_data.hitbox_feets = C_GET_ARRAY(bool, 7, Vars.hitbox_feet, 2);
|
||
rage_data.rapid_fire = C_GET_ARRAY(bool, 7, Vars.rapid_fire, 2);
|
||
|
||
}
|
||
else if (data->m_WeaponType() == WEAPONTYPE_PISTOL && !has_heavy_pistols) {
|
||
rage_data.minimum_damage = C_GET_ARRAY(int, 7, Vars.rage_minimum_damage, 1);
|
||
rage_data.rage_hitchance = C_GET_ARRAY(int, 7, Vars.rage_minimum_hitchance, 1);
|
||
rage_data.auto_stop = C_GET_ARRAY(bool, 7, Vars.rage_auto_stop, 1);
|
||
rage_data.penetration = C_GET_ARRAY(bool, 7, Vars.rage_penetration, 1);
|
||
rage_data.rage_target_select = C_GET_ARRAY(int, 7, Vars.rage_target_select, 1);
|
||
rage_data.hitbox_head = C_GET(bool, 7, Vars.hitbox_head, 1);
|
||
rage_data.hitbox_neck = C_GET(bool, 7, Vars.hitbox_neck, 1);
|
||
rage_data.hitbox_uppeer_chest = C_GET(bool, 7, Vars.hitbox_uppeer_chest, 1);
|
||
rage_data.hitbox_chest = C_GET(bool, 7, Vars.hitbox_chest, 1);
|
||
rage_data.hitbox_stomach = C_GET(bool, 7, Vars.hitbox_stomach, 1);
|
||
rage_data.hitbox_legs = C_GET(bool, 7, Vars.hitbox_legs, 1);
|
||
rage_data.hitbox_feets = C_GET(bool, 7, Vars.hitbox_feet, 1);
|
||
rage_data.rapid_fire = C_GET(bool, 7, Vars.rapid_fire, 1);
|
||
}
|
||
else if (data->m_WeaponType() == WEAPONTYPE_MACHINEGUN) {
|
||
rage_data.minimum_damage = C_GET_ARRAY(int, 7, Vars.rage_minimum_damage, 3);
|
||
rage_data.rage_hitchance = C_GET_ARRAY(int, 7, Vars.rage_minimum_hitchance, 3);
|
||
rage_data.auto_stop = C_GET_ARRAY(bool, 7, Vars.rage_auto_stop, 3);
|
||
rage_data.penetration = C_GET_ARRAY(bool, 7, Vars.rage_penetration, 3);
|
||
rage_data.rage_target_select = C_GET_ARRAY(int, 7, Vars.rage_target_select, 3);
|
||
rage_data.hitbox_head = C_GET_ARRAY(bool, 7, Vars.hitbox_head, 3);
|
||
rage_data.hitbox_neck = C_GET_ARRAY(bool, 7, Vars.hitbox_neck, 3);
|
||
rage_data.hitbox_uppeer_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_uppeer_chest, 3);
|
||
rage_data.hitbox_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_chest, 3);
|
||
rage_data.hitbox_stomach = C_GET_ARRAY(bool, 7, Vars.hitbox_stomach, 3);
|
||
rage_data.hitbox_legs = C_GET_ARRAY(bool, 7, Vars.hitbox_legs, 3);
|
||
rage_data.hitbox_feets = C_GET_ARRAY(bool, 7, Vars.hitbox_feet, 3);
|
||
rage_data.rapid_fire = C_GET_ARRAY(bool, 7, Vars.rapid_fire, 3);
|
||
|
||
}
|
||
else if (data->m_WeaponType() == WEAPONTYPE_RIFLE) {
|
||
rage_data.minimum_damage = C_GET_ARRAY(int, 7, Vars.rage_minimum_damage, 3);
|
||
rage_data.rage_hitchance = C_GET_ARRAY(int, 7, Vars.rage_minimum_hitchance, 3);
|
||
rage_data.auto_stop = C_GET_ARRAY(bool, 7, Vars.rage_auto_stop, 3);
|
||
rage_data.penetration = C_GET_ARRAY(bool, 7, Vars.rage_penetration, 3);
|
||
rage_data.rage_target_select = C_GET_ARRAY(int, 7, Vars.rage_target_select, 3);
|
||
rage_data.hitbox_head = C_GET_ARRAY(bool, 7, Vars.hitbox_head, 3);
|
||
rage_data.hitbox_neck = C_GET_ARRAY(bool, 7, Vars.hitbox_neck, 3);
|
||
rage_data.hitbox_uppeer_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_uppeer_chest, 3);
|
||
rage_data.hitbox_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_chest, 3);
|
||
rage_data.hitbox_stomach = C_GET_ARRAY(bool, 7, Vars.hitbox_stomach, 3);
|
||
rage_data.hitbox_legs = C_GET_ARRAY(bool, 7, Vars.hitbox_legs, 3);
|
||
rage_data.hitbox_feets = C_GET_ARRAY(bool, 7, Vars.hitbox_feet, 3);
|
||
rage_data.rapid_fire = C_GET_ARRAY(bool, 7, Vars.rapid_fire, 3);
|
||
}
|
||
else if (data->m_WeaponType() == WEAPONTYPE_SNIPER_RIFLE){
|
||
rage_data.minimum_damage = C_GET_ARRAY(int, 7, Vars.rage_minimum_damage, 4);
|
||
rage_data.rage_hitchance = C_GET_ARRAY(int, 7, Vars.rage_minimum_hitchance, 4);
|
||
rage_data.auto_stop = C_GET_ARRAY(bool, 7, Vars.rage_auto_stop, 4);
|
||
rage_data.penetration = C_GET_ARRAY(bool, 7, Vars.rage_penetration, 4);
|
||
rage_data.rage_target_select = C_GET_ARRAY(int, 7, Vars.rage_target_select, 4);
|
||
rage_data.hitbox_head = C_GET_ARRAY(bool, 7, Vars.hitbox_head, 4);
|
||
rage_data.hitbox_neck = C_GET_ARRAY(bool, 7, Vars.hitbox_neck, 4);
|
||
rage_data.hitbox_uppeer_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_uppeer_chest, 4);
|
||
rage_data.hitbox_chest = C_GET_ARRAY(bool, 7, Vars.hitbox_chest, 4);
|
||
rage_data.hitbox_stomach = C_GET_ARRAY(bool, 7, Vars.hitbox_stomach, 4);
|
||
rage_data.hitbox_legs = C_GET_ARRAY(bool, 7, Vars.hitbox_legs, 4);
|
||
rage_data.hitbox_feets = C_GET_ARRAY(bool, 7, Vars.hitbox_feet, 4);
|
||
rage_data.rapid_fire = C_GET_ARRAY(bool, 7, Vars.rapid_fire, 4);
|
||
}
|
||
|
||
}
|