-
Автор темы
- #1
Grenade warning for supremacy (2018)
gh.cpp
gh.h
Put inside Visuals.cpp (Visuals::think)
put in menu.h
entity.h (class Entity : public IClientUnknown) public netvars / for example under m_iTeamNum
entoffsets.h
Пожалуйста, авторизуйтесь для просмотра ссылки.
gh.cpp
C++:
#include "includes.h"
#include "gh.h"
void IEngineTrace::TraceLine(const vec3_t& src, const vec3_t& dst, int mask, IHandleEntity* entity, int collision_group, CGameTrace* trace) {
static auto trace_filter_simple = pattern::find(g_csgo.m_client_dll, XOR("55 8B EC 83 E4 F0 83 EC 7C 56 52")) + 0x3D;
std::uintptr_t filter[4] = { *reinterpret_cast<std::uintptr_t*>(trace_filter_simple), reinterpret_cast<std::uintptr_t>(entity), collision_group, 0 };
TraceRay(Ray(src, dst), mask, reinterpret_cast<CTraceFilter*>(&filter), trace);
}
void IEngineTrace::TraceHull(const vec3_t& src, const vec3_t& dst, const vec3_t& mins, const vec3_t& maxs, int mask, IHandleEntity* entity, int collision_group, CGameTrace* trace) {
static auto trace_filter_simple = pattern::find(g_csgo.m_client_dll, XOR("55 8B EC 83 E4 F0 83 EC 7C 56 52")) + 0x3D;
std::uintptr_t filter[4] = { *reinterpret_cast<std::uintptr_t*>(trace_filter_simple), reinterpret_cast<std::uintptr_t>(entity), collision_group, 0 };
TraceRay(Ray(src, dst, mins, maxs), mask, reinterpret_cast<CTraceFilter*>(&filter), trace);
}
void rotate_point(vec2_t& point, vec2_t origin, bool clockwise, float angle) {
vec2_t delta = point - origin;
vec2_t rotated;
if (clockwise) {
rotated = vec2_t(delta.x * cosf(angle) - delta.y * sinf(angle), delta.x * sinf(angle) + delta.y * cosf(angle));
}
else {
rotated = vec2_t(delta.x * sinf(angle) - delta.y * cosf(angle), delta.x * cosf(angle) + delta.y * sinf(angle));
}
point = rotated + origin;
}
float& Player::get_creation_time() {
return *reinterpret_cast<float*>(0x29B0);
}
void c_grenade_prediction::on_create_move(CUserCmd* cmd) {
m_data = {};
if (!g_cl.m_processing || !g_menu.main.visuals.tracers.get())
return;
const auto weapon = reinterpret_cast<Weapon*>(g_csgo.m_entlist->GetClientEntityFromHandle(g_cl.m_local->GetActiveWeapon()));
if (!weapon || !weapon->m_bPinPulled() && weapon->m_fThrowTime() == 0.f)
return;
const auto weapon_data = weapon->GetWpnData();
if (!weapon_data || weapon_data->m_weapon_type != 9)
return;
m_data.m_owner = g_cl.m_local;
m_data.m_index = weapon->m_iItemDefinitionIndex();
auto view_angles = cmd->m_view_angles;
if (view_angles.x < -90.f) {
view_angles.x += 360.f;
}
else if (view_angles.x > 90.f) {
view_angles.x -= 360.f;
}
view_angles.x -= (90.f - std::fabsf(view_angles.x)) * 10.f / 90.f;
auto direction = vec3_t();
math::AngleVectors(view_angles, direction);
const auto throw_strength = std::clamp< float >(weapon->m_flThrowStrength(), 0.f, 1.f);
const auto eye_pos = g_cl.m_shoot_pos;
const auto src = vec3_t(eye_pos.x, eye_pos.y, eye_pos.z + (throw_strength * 12.f - 12.f));
auto trace = CGameTrace();
g_csgo.m_engine_trace->TraceHull(src, src + direction * 22.f, { -2.f, -2.f, -2.f }, { 2.f, 2.f, 2.f }, MASK_SOLID | CONTENTS_CURRENT_90, g_cl.m_local, COLLISION_GROUP_NONE, &trace);
m_data.predict(trace.m_endpos - direction * 6.f, direction * (std::clamp< float >(weapon_data->m_throw_velocity * 0.9f, 15.f, 750.f) * (throw_strength * 0.7f + 0.3f)) + g_cl.m_local->m_vecVelocity() * 1.25f, g_csgo.m_globals->m_curtime, 0);
}
void DrawBeamPaw(vec3_t src, vec3_t end, Color color)
{
BeamInfo_t beamInfo;
beamInfo.m_vecStart = src;
beamInfo.m_vecEnd = end;
beamInfo.m_pszModelName = "sprites/purplelaser1.vmt";//sprites/purplelaser1.vmt
beamInfo.m_pszHaloName = "sprites/purplelaser1.vmt";//sprites/purplelaser1.vmt
beamInfo.m_flHaloScale = 0;//0
beamInfo.m_flWidth = 2;//11
beamInfo.m_flEndWidth = 2;//11
beamInfo.m_flFadeLength = 1.0f;
beamInfo.m_flAmplitude = 2.3;
beamInfo.m_flBrightness = 255.f;
beamInfo.m_flSpeed = 0.2f;
beamInfo.m_nStartFrame = 0.0;
beamInfo.m_flFrameRate = 0.0;
beamInfo.m_flRed = color.r();
beamInfo.m_flGreen = color.g();
beamInfo.m_flBlue = color.b();
beamInfo.m_nSegments = 2;//40
beamInfo.m_bRenderable = true;
beamInfo.m_flLife = 0.03f;
Beam_t* myBeam = g_csgo.m_beams->CreateBeamPoints(beamInfo);
if (myBeam)
g_csgo.m_beams->DrawBeam(myBeam);
}
void draw_arc(int x, int y, int radius, int start_angle, int percent, int thickness, Color color)
{
auto precision = (2 * 3.14159265358979323846) / 30;
auto step = 3.14159265358979323846 / 180;
auto inner = radius - thickness;
auto end_angle = (start_angle + percent) * step;
auto start_angles = (start_angle * 3.14159265358979323846) / 180;
for (; radius > inner; --radius) {
for (auto angle = start_angles; angle < end_angle; angle += precision) {
auto cx = std::round(x + radius * std::cos(angle));
auto cy = std::round(y + radius * std::sin(angle));
auto cx2 = std::round(x + radius * std::cos(angle + precision));
auto cy2 = std::round(y + radius * std::sin(angle + precision));
render::line(cx, cy, cx2, cy2, color);
}
}
}
const char* index_to_grenade_name_icon(int index)
{
switch (index)
{
case SMOKE: return "k"; break;
case HEGRENADE: return "j"; break;
case MOLOTOV:return "l"; break;
case 48:return "n"; break;
}
}
bool c_grenade_prediction::data_t::draw() const
{
if (!g_menu.main.visuals.grenade_warning.get())
return false;
if (m_path.size() <= 1u || g_csgo.m_globals->m_curtime >= m_expire_time)
return false;
int dist = g_cl.m_local->m_vecOrigin().dist_to(m_origin) / 12;
auto prev_screen = vec2_t();
auto prev_on_screen = render::WorldToScreen(std::get< vec3_t >(m_path.front()), prev_screen);
for (auto i = 1u; i < m_path.size(); ++i) {
auto cur_screen = vec2_t();
const auto cur_on_screen = render::WorldToScreen(std::get< vec3_t >(m_path.at(i)), cur_screen);
if (prev_on_screen && cur_on_screen) {
if (g_menu.main.visuals.grenade_tracer_warning.get()) {
DrawBeamPaw(std::get< vec3_t >(m_path.at(i - 1)), std::get< vec3_t >(m_path.at(i)), Color(255, 255, 255, 255)); // beamcolor
}
}
prev_screen = cur_screen;
prev_on_screen = cur_on_screen;
}
float percent = ((m_expire_time - g_csgo.m_globals->m_curtime) / game::TICKS_TO_TIME(m_tick));
int alpha_damage = 0;
if (m_index == HEGRENADE && dist <= 20) {
alpha_damage = 50 - 255 * (dist / 20);
}
if ((m_index == MOLOTOV || m_index == FIREBOMB) && dist <= 15) {
alpha_damage = 50 - 255 * (dist / 15);
}
if (dist < 45) {
render::circle(prev_screen.x, prev_screen.y - 10, 20, 360, Color(26, 26, 30, 200));
draw_arc(prev_screen.x, prev_screen.y - 10, 20, 0, 360 * percent, 2, Color(255, 255, 255, 225));
//render::GW1.string(prev_screen.x + 3, prev_screen.y - 20, { 255,255,255,255 }, XOR("!"), render::ALIGN_RIGHT);
render::cs.string(prev_screen.x - 5, prev_screen.y - 20, { 255,255,255,255 }, index_to_grenade_name_icon(m_index));
}
auto is_on_screen = [](vec3_t origin, vec2_t& screen) -> bool
{
if (!render::WorldToScreen(origin, screen))
return false;
return (screen.x > 0 && screen.x < g_cl.m_width) && (g_cl.m_height > screen.y && screen.y > 0);
};
vec2_t screenPos;
vec3_t vEnemyOrigin = m_origin;
vec3_t vLocalOrigin = g_cl.m_local->GetAbsOrigin();
if (!g_cl.m_local->alive())
vLocalOrigin = g_csgo.m_input->m_camera_offset;
if (!is_on_screen(vEnemyOrigin, screenPos))
{
const float wm = g_cl.m_width / 2, hm = g_cl.m_height / 2;
vec3_t last_pos = std::get< vec3_t >(m_path.at(m_path.size() - 1));
ang_t dir;
g_csgo.m_engine->GetViewAngles(dir);
float view_angle = dir.y;
if (view_angle < 0)
view_angle += 360;
view_angle = DEG2RAD(view_angle);
auto entity_angle = math::CalcAngle(vLocalOrigin, vEnemyOrigin);
entity_angle.normalize();
if (entity_angle.y < 0.f)
entity_angle.y += 360.f;
entity_angle.y = DEG2RAD(entity_angle.y);
entity_angle.y -= view_angle;
auto position = vec2_t(wm, hm);
position.x -= std::clamp(vLocalOrigin.dist_to(vEnemyOrigin), 400.f, hm - 40);
rotate_point(position, vec2_t(wm, hm), false, entity_angle.y);
if (dist < 45) {
render::circle(position.x, position.y - 10, 20, 360, Color(26, 26, 30, 200));
draw_arc(position.x, position.y - 10, 20, 0, 360 * percent, 2, Color(255, 255, 255, 225));
render::cs.string(position.x - 5, position.y - 20, { 255,255,255,255 }, index_to_grenade_name_icon(m_index));
}
}
return true;
}
void c_grenade_prediction::grenade_warning(Player* entity)
{
auto& predicted_nades = g_grenades_pred.get_list();
static auto last_server_tick = g_csgo.m_cl->m_server_tick;
if (last_server_tick != g_csgo.m_cl->m_server_tick) {
predicted_nades.clear();
last_server_tick = g_csgo.m_cl->m_server_tick;
}
if (entity->dormant() || !g_menu.main.visuals.tracers.get())
return;
const auto client_class = entity->GetClientClass();
if (!client_class || client_class->m_ClassID != 114 && client_class->m_ClassID != cbasecsgrenade)
return;
if (client_class->m_ClassID == cbasecsgrenade) {
const auto model = entity->GetModel();
if (!model)
return;
const auto studio_model = g_csgo.m_model_info->GetStudioModel(model);
if (!studio_model || std::string_view(studio_model->m_name).find("fraggrenade") == std::string::npos)
return;
}
const auto handle = entity-> GetRefEHandle ();
if (entity->m_nExplodeEffectTickBegin()) {
predicted_nades.erase(handle);
return;
}
if (predicted_nades.find(handle) == predicted_nades.end()) {
predicted_nades.emplace(std::piecewise_construct, std::forward_as_tuple(handle), std::forward_as_tuple(reinterpret_cast<Weapon*>(entity)->m_hThrower(), client_class->m_ClassID == 114 ? MOLOTOV : HEGRENADE, entity->m_vecOrigin(), reinterpret_cast<Player*>(entity)->m_vecVelocity(), entity->get_creation_time(), game::TIME_TO_TICKS(reinterpret_cast<Player*>(entity)->m_flSimulationTime() - entity->get_creation_time())));
}
if (predicted_nades.at(handle).draw())
return;
predicted_nades.erase(handle);
}
C++:
#pragma once
class c_grenade_prediction {
public:
struct data_t {
__forceinline data_t() = default;
__forceinline data_t(Player* owner, int index, const vec3_t& origin, const vec3_t& velocity, float throw_time, int offset) : data_t() {
m_owner = owner;
m_index = index;
predict(origin, velocity, throw_time, offset);
}
__forceinline bool physics_simulate() {
if (m_detonated)
return true;
static const auto sv_gravity = g_csgo.m_cvar->FindVar(HASH("sv_gravity"));
const auto new_velocity_z = m_velocity.z - (sv_gravity->GetFloat() * 0.4f) * g_csgo.m_globals->m_interval;
const auto move = vec3_t(
m_velocity.x * g_csgo.m_globals->m_interval,
m_velocity.y * g_csgo.m_globals->m_interval,
(m_velocity.z + new_velocity_z) / 2.f * g_csgo.m_globals->m_interval
);
m_velocity.z = new_velocity_z;
auto trace = CGameTrace();
physics_push_entity(move, trace);
if (m_detonated)
return true;
if (trace.m_fraction != 1.f) {
update_path< true >();
perform_fly_collision_resolution(trace);
}
return false;
}
__forceinline void physics_trace_entity(const vec3_t& src, const vec3_t& dst, std::uint32_t mask, CGameTrace& trace) {
g_csgo.m_engine_trace->TraceHull(
src, dst, { -2.f, -2.f, -2.f }, { 2.f, 2.f, 2.f },
mask, m_owner, m_collision_group, &trace
);
if (trace.m_startsolid
&& (trace.m_contents & CONTENTS_CURRENT_90)) {
trace.clear();
g_csgo.m_engine_trace->TraceHull(
src, dst, { -2.f, -2.f, -2.f }, { 2.f, 2.f, 2.f },
mask & ~CONTENTS_CURRENT_90, m_owner, m_collision_group, &trace
);
}
if (!trace.hit()
|| !trace.m_entity
|| !reinterpret_cast<Entity*>(trace.m_entity)->IsPlayer())
return;
trace.clear();
g_csgo.m_engine_trace->TraceLine(src, dst, mask, m_owner, m_collision_group, &trace);
}
__forceinline void physics_push_entity(const vec3_t& push, CGameTrace& trace) {
physics_trace_entity(m_origin, m_origin + push,
m_collision_group == COLLISION_GROUP_DEBRIS
? (MASK_SOLID | CONTENTS_CURRENT_90) & ~CONTENTS_MONSTER
: MASK_SOLID | CONTENTS_OPAQUE | CONTENTS_IGNORE_NODRAW_OPAQUE | CONTENTS_CURRENT_90 | CONTENTS_HITBOX,
trace
);
if (trace.m_startsolid) {
m_collision_group = COLLISION_GROUP_INTERACTIVE_DEBRIS;
g_csgo.m_engine_trace->TraceLine(
m_origin - push, m_origin + push,
(MASK_SOLID | CONTENTS_CURRENT_90) & ~CONTENTS_MONSTER,
m_owner, m_collision_group, &trace
);
}
if (trace.m_fraction) {
m_origin = trace.m_endpos;
}
if (!trace.m_entity)
return;
if (reinterpret_cast<Entity*>(trace.m_entity)->IsPlayer()
|| m_index != 68 && m_index != MOLOTOV && m_index != FIREBOMB) // TAGRENADE = 68
return;
static const auto weapon_molotov_maxdetonateslope = g_csgo.m_cvar->FindVar(HASH("weapon_molotov_maxdetonateslope"));
if (m_index != 68
&& trace.m_plane.m_normal.z < std::cos(math::deg_to_rad(weapon_molotov_maxdetonateslope->GetFloat()))) // TAGRENADE = 68
return;
detonate< true >();
}
__forceinline void perform_fly_collision_resolution(CGameTrace& trace) {
auto surface_elasticity = 1.f;
if (trace.m_entity) {
#if 0 /* ayo reis wtf */
if (const auto v8 = trace.m_surface.m_name) {
if (*(DWORD*)v8 != 'spam' || *((DWORD*)v8 + 1) != '_sc/') {
if (*((DWORD*)v8 + 1) == '_ed/'
&& *((DWORD*)v8 + 2) == 'ekal'
&& *((DWORD*)v8 + 3) == 'alg/'
&& *((DWORD*)v8 + 4) == 'g/ss'
&& *((DWORD*)v8 + 5) == 'ssal') {
goto BREAKTROUGH;
}
}
else if (*((DWORD*)v8 + 2) == 'iffo'
&& *((DWORD*)v8 + 3) == 'g/ec'
&& *((DWORD*)v8 + 4) == 'ssal'
&& *((DWORD*)v8 + 5) == 'bru/'
&& *((DWORD*)v8 + 6) == 'g_na'
&& *((DWORD*)v8 + 7) == 'ssal') {
goto BREAKTROUGH;
}
}
#endif
if (game::IsBreakable(trace.m_entity)) {
BREAKTROUGH:
m_velocity *= 0.4f;
return;
}
const auto is_player = reinterpret_cast<Entity*>(trace.m_entity)->IsPlayer();
if (is_player) {
surface_elasticity = 0.3f;
}
if (trace.m_entity->index()) {
if (is_player
&& m_last_hit_entity == trace.m_entity) {
m_collision_group = COLLISION_GROUP_DEBRIS;
return;
}
m_last_hit_entity = trace.m_entity;
}
}
auto velocity = vec3_t();
const auto back_off = m_velocity.dot(trace.m_plane.m_normal) * 2.f;
for (auto i = 0u; i < 3u; i++) {
const auto change = trace.m_plane.m_normal[i] * back_off;
velocity[i] = m_velocity[i] - change;
if (std::fabs(velocity[i]) >= 1.f)
continue;
velocity[i] = 0.f;
}
velocity *= std::clamp< float >(surface_elasticity * 0.45f, 0.f, 0.9f);
if (trace.m_plane.m_normal.z > 0.7f) {
const auto speed_sqr = velocity.length_sqr();
if (speed_sqr > 96000.f) {
const auto l = velocity.normalized().dot(trace.m_plane.m_normal);
if (l > 0.5f) {
velocity *= 1.f - l + 0.5f;
}
}
if (speed_sqr < 400.f) {
m_velocity = vec3_t(0, 0, 0);
}
else {
m_velocity = velocity;
physics_push_entity(velocity * ((1.f - trace.m_fraction) * g_csgo.m_globals->m_interval), trace);
}
}
else {
m_velocity = velocity;
physics_push_entity(velocity * ((1.f - trace.m_fraction) * g_csgo.m_globals->m_interval), trace);
}
if (m_bounces_count > 20)
return detonate< false >();
++m_bounces_count;
}
__forceinline void think() {
switch (m_index) {
case SMOKE:
if (m_velocity.length_sqr() <= 0.01f) {
detonate< false >();
}
break;
case DECOY:
if (m_velocity.length_sqr() <= 0.04f) {
detonate< false >();
}
break;
case FLASHBANG:
case HEGRENADE:
case MOLOTOV:
case FIREBOMB:
if (game::TICKS_TO_TIME(m_tick) > m_detonate_time) {
detonate< false >();
}
break;
}
m_next_think_tick = m_tick + game::TIME_TO_TICKS(0.2f);
}
template < bool _bounced >
__forceinline void detonate() {
m_detonated = true;
update_path< _bounced >();
}
template < bool _bounced >
__forceinline void update_path() {
m_last_update_tick = m_tick;
m_path.emplace_back(m_origin, _bounced);
}
__forceinline void predict(const vec3_t& origin, const vec3_t& velocity, float throw_time, int offset) {
m_origin = origin;
m_velocity = velocity;
m_collision_group = COLLISION_GROUP_PROJECTILE;
const auto tick = game::TIME_TO_TICKS(1.f / 30.f);
m_last_update_tick = -tick;
switch (m_index) {
case SMOKE: m_next_think_tick = game::TIME_TO_TICKS(1.5f); break;
case DECOY: m_next_think_tick = game::TIME_TO_TICKS(2.f); break;
case FLASHBANG:
case HEGRENADE:
m_detonate_time = 1.5f;
m_next_think_tick = game::TIME_TO_TICKS(0.02f);
break;
case MOLOTOV:
case FIREBOMB:
static const auto molotov_throw_detonate_time = g_csgo.m_cvar->FindVar(HASH("molotov_throw_detonate_time"));
m_detonate_time = molotov_throw_detonate_time->GetFloat();
m_next_think_tick = game::TIME_TO_TICKS(0.02f);
break;
}
for (; m_tick < game::TIME_TO_TICKS(60.f); ++m_tick) {
if (m_next_think_tick <= m_tick) {
think();
}
if (m_tick < offset)
continue;
if (physics_simulate())
break;
if (m_last_update_tick + tick > m_tick)
continue;
update_path< false >();
}
if (m_last_update_tick + tick <= m_tick) {
update_path< false >();
}
m_expire_time = throw_time + game::TICKS_TO_TIME(m_tick);
}
bool draw() const;
bool m_detonated{};
Player* m_owner{};
vec3_t m_origin{}, m_velocity{};
Entity* m_last_hit_entity{};
Collision_Group_t m_collision_group{};
float m_detonate_time{}, m_expire_time{};
int m_index{}, m_tick{}, m_next_think_tick{},
m_last_update_tick{}, m_bounces_count{};
std::vector< std::pair< vec3_t, bool > > m_path{};
} m_data{};
std::unordered_map< unsigned long, data_t > m_list{};
public:
__forceinline c_grenade_prediction() = default;
void on_create_move(CUserCmd* cmd);
__forceinline const data_t& get_local_data() const { return m_data; }
__forceinline std::unordered_map< unsigned long, data_t >& get_list() { return m_list; }
virtual void grenade_warning(Player* entity);
};
inline c_grenade_prediction g_grenades_pred;
Put inside Visuals.cpp (Visuals::think)
C++:
//nade prediction stuff
auto& predicted_nades = g_grenades_pred.get_list();
static auto last_server_tick = g_csgo.m_cl->m_server_tick;
if (g_csgo.m_cl->m_server_tick != last_server_tick) {
predicted_nades.clear();
last_server_tick = g_csgo.m_cl->m_server_tick;
}
// draw esp on ents.
for (int i{ 1 }; i <= g_csgo.m_entlist->GetHighestEntityIndex(); ++i) {
Entity* ent = g_csgo.m_entlist->GetClientEntity(i);
if (!ent)
continue;
if (ent->dormant())
continue;
if (!ent->is(HASH("CMolotovProjectile"))
&& !ent->is(HASH("CBaseCSGrenadeProjectile")))
continue;
if (ent->is(HASH("CBaseCSGrenadeProjectile"))) {
const auto studio_model = ent->GetModel();
if (!studio_model
|| std::string_view(studio_model->m_name).find("fraggrenade") == std::string::npos)
continue;
}
const auto handle = reinterpret_cast<Player*>(ent)->GetRefEHandle();
if (ent->m_fEffects() & EF_NODRAW) {
predicted_nades.erase(handle);
continue;
}
if (predicted_nades.find(handle) == predicted_nades.end()) {
predicted_nades.emplace(
std::piecewise_construct,
std::forward_as_tuple(handle),
std::forward_as_tuple(
reinterpret_cast<Player*>(g_csgo.m_entlist->GetClientEntityFromHandle(ent->m_hThrower())),
ent->is(HASH("CMolotovProjectile")) ? MOLOTOV : HEGRENADE,
ent->m_vecOrigin(), ent->m_vecVelocity(), ent->m_flSpawnTime_Grenade(),
game::TIME_TO_TICKS(reinterpret_cast<Player*>(ent)->m_flSimulationTime() - ent->m_flSpawnTime_Grenade())
)
);
}
if (predicted_nades.at(handle).draw())
continue;
predicted_nades.erase(handle);
}
g_grenades_pred.get_local_data().draw();
C++:
Checkbox grenade_tracer_warning;
Checkbox grenade_warning;
grenade_warning.setup(XOR("grenade proximity warning"), XOR("warning_prox"));
RegisterElement(&grenade_warning, 1);
grenade_tracer_warning.setup(XOR("grenade proximity warning tracer"), XOR("warning_prox_t"));
RegisterElement(&grenade_tracer_warning, 1);
C++:
__forceinline float& m_flSpawnTime_Grenade()
{
return get< float >(g_entoffsets.m_flSpawnTime_Grenade);
}
__forceinline EHANDLE & m_hThrower ()
{
return get< EHANDLE >(g_entoffsets.m_hThrower);
}
C++:
XoredNetvar< GET_XOR_KEYUI32, __COUNTER__ > m_flSpawnTime_Grenade;
XoredNetvar< GET_XOR_KEYUI32, __COUNTER__ > m_hThrower;
INIT_XOREDNETVAR(m_hThrower, HASH("DT_BaseCSGrenade"), HASH("m_hThrower"));
INIT_XOREDNETVAR_SPECIFIC(m_flSpawnTime_Grenade, 0x29b0);
Последнее редактирование: