- Status
- Offline
- Joined
- Apr 18, 2019
- Messages
- 147
- Reaction score
- 249
.cpp:
.h:
C++:
void GrenadePrediction::Tick(int buttons)
{
bool in_attack = buttons & IN_ATTACK, in_attack2 = buttons & IN_ATTACK2;
if (g_ctx.m_local && g_ctx.m_local->m_iHealth() > 0)
{
act = (in_attack && in_attack2) ? ACT_LOB :
(in_attack2) ? ACT_DROP :
(in_attack) ? ACT_THROW :
ACT_NONE;
}
}
bool IsGrenade(weapon_t* weapon)
{
auto WeaponIDz = weapon->m_iItemDefinitionIndex();
if (WeaponIDz == WEAPON_HEGRENADE || WeaponIDz == WEAPON_INCGRENADE ||
WeaponIDz == WEAPON_MOLOTOV || WeaponIDz == WEAPON_FLASHBANG ||
WeaponIDz == WEAPON_DECOY || WeaponIDz == WEAPON_SMOKEGRENADE)
return true;
return false;
}
void GrenadePrediction::View(CViewSetup* setup)
{
if (g_ctx.m_local && g_ctx.m_local->m_iHealth() > 0)
{
auto weapon = reinterpret_cast<weapon_t*>(g_csgo.m_entitylist()->GetClientEntity(g_ctx.m_local->GetActiveWeaponIndex()));
if (!weapon) return;
if (IsGrenade(weapon))
{
type = weapon->m_iItemDefinitionIndex();
Simulate(setup);
}
else
type = 0;
}
}
inline float CSGO_Armor(float flDamage, int ArmorValue) {
float flArmorRatio = 0.5f;
float flArmorBonus = 0.5f;
if (ArmorValue > 0) {
float flNew = flDamage * flArmorRatio;
float flArmor = (flDamage - flNew) * flArmorBonus;
if (flArmor > static_cast<float>(ArmorValue)) {
flArmor = static_cast<float>(ArmorValue) * (1.f / flArmorBonus);
flNew = flDamage - flArmor;
}
flDamage = flNew;
}
return flDamage;
}
void DrawLine(int x1, int y1, int x2, int y2, Color color)
{
g_csgo.m_surface()->DrawSetColor(color);
g_csgo.m_surface()->DrawLine(x1, y1, x2, y2);
}
void DrawFilled3DBox(Vector origin, int width, int height, Color outline, Color filling)
{
float difw = float(width / 2);
float difh = float(height / 2);
Vector boxVectors[8] =
{
Vector(origin.x - difw, origin.y - difh, origin.z - difw),
Vector(origin.x - difw, origin.y - difh, origin.z + difw),
Vector(origin.x + difw, origin.y - difh, origin.z + difw),
Vector(origin.x + difw, origin.y - difh, origin.z - difw),
Vector(origin.x - difw, origin.y + difh, origin.z - difw),
Vector(origin.x - difw, origin.y + difh, origin.z + difw),
Vector(origin.x + difw, origin.y + difh, origin.z + difw),
Vector(origin.x + difw, origin.y + difh, origin.z - difw),
};
static Vector vec0, vec1, vec2, vec3,
vec4, vec5, vec6, vec7;
if (math::world_to_screen(boxVectors[0], vec0) &&
math::world_to_screen(boxVectors[1], vec1) &&
math::world_to_screen(boxVectors[2], vec2) &&
math::world_to_screen(boxVectors[3], vec3) &&
math::world_to_screen(boxVectors[4], vec4) &&
math::world_to_screen(boxVectors[5], vec5) &&
math::world_to_screen(boxVectors[6], vec6) &&
math::world_to_screen(boxVectors[7], vec7))
{
Vector lines[12][2];
lines[0][0] = vec0;
lines[0][1] = vec1;
lines[1][0] = vec1;
lines[1][1] = vec2;
lines[2][0] = vec2;
lines[2][1] = vec3;
lines[3][0] = vec3;
lines[3][1] = vec0;
// top of box
lines[4][0] = vec4;
lines[4][1] = vec5;
lines[5][0] = vec5;
lines[5][1] = vec6;
lines[6][0] = vec6;
lines[6][1] = vec7;
lines[7][0] = vec7;
lines[7][1] = vec4;
lines[8][0] = vec0;
lines[8][1] = vec4;
lines[9][0] = vec1;
lines[9][1] = vec5;
lines[10][0] = vec2;
lines[10][1] = vec6;
lines[11][0] = vec3;
lines[11][1] = vec7;
for (int i = 0; i < 12; i++)
DrawLine(lines[i][0].x, lines[i][0].y, lines[i][1].x, lines[i][1].y, outline);
}
}
void DrawF(int X, int Y, unsigned int Font, bool center_width, bool center_height, Color Color, std::string Input)
{
/* char -> wchar */
size_t size = Input.size() + 1;
auto wide_buffer = std::make_unique<wchar_t[]>(size);
mbstowcs_s(0, wide_buffer.get(), size, Input.c_str(), size - 1);
/* check center */
int width = 0, height = 0;
g_csgo.m_surface()->GetTextSize(Font, wide_buffer.get(), width, height);
if (!center_width)
width = 0;
if (!center_height)
height = 0;
/* call and draw*/
g_csgo.m_surface()->DrawSetTextColor(Color);
g_csgo.m_surface()->DrawSetTextFont(Font);
g_csgo.m_surface()->DrawSetTextPos(X - (width * .5), Y - (height * .5));
g_csgo.m_surface()->DrawPrintText(wide_buffer.get(), wcslen(wide_buffer.get()));
}
Vector2D GetTextSize(unsigned int Font, std::string Input)
{
/* char -> wchar */
size_t size = Input.size() + 1;
auto wide_buffer = std::make_unique<wchar_t[]>(size);
mbstowcs_s(0, wide_buffer.get(), size, Input.c_str(), size - 1);
int width, height;
g_csgo.m_surface()->GetTextSize(Font, wide_buffer.get(), width, height);
return Vector2D(width, height);
}
void GrenadePrediction::Paint()
{
if (!g_ctx.m_local) return;
if (g_ctx.m_local->m_iHealth() > 0)
{
if ((type) && path.size() > 1)
{
Vector nadeStart, nadeEnd;
Vector prev = path[0];
auto weapon = reinterpret_cast<weapon_t*>(g_csgo.m_entitylist()->GetClientEntity(g_ctx.m_local->GetActiveWeaponIndex()));
if (!weapon) return;
auto WeaponIDz = weapon->m_iItemDefinitionIndex();
for (auto it = path.begin(), end = path.end(); it != end; ++it)
{
if (math::world_to_screen(prev, nadeStart) && math::world_to_screen(*it, nadeEnd))
DrawLine((int)nadeStart.x, (int)nadeStart.y, (int)nadeEnd.x, (int)nadeEnd.y, Color(255, 0, 0));
prev = *it;
}
for (auto it = others.begin(), end = others.end(); it != end; ++it)
DrawFilled3DBox(it->first, 5, 5, Color(0, 135, 255, 200), Color(0, 135, 255, 200));
//RENDER::DrawFilled3DBox(others.rbegin()->first, 4, 4, CColor(255, 0, 0, 200), CColor(0, 135, 255, 200));
if (math::world_to_screen(prev, nadeEnd))
{
if (WeaponIDz == WEAPON_FLASHBANG)
DrawF((int)nadeEnd.x - 5, (int)nadeEnd.y, fonts[iconslol], true, true, Color(255, 255, 255, 255), "i");
else if (WeaponIDz == WEAPON_HEGRENADE)
DrawF((int)nadeEnd.x - 5, (int)nadeEnd.y, fonts[iconslol], true, true, Color(255, 255, 255, 255), "j");
else if (WeaponIDz == WEAPON_INCGRENADE)
DrawF((int)nadeEnd.x - 5, (int)nadeEnd.y, fonts[iconslol], true, true, Color(255, 255, 255, 255), "n");
else if (WeaponIDz == WEAPON_MOLOTOV)
DrawF((int)nadeEnd.x - 5, (int)nadeEnd.y, fonts[iconslol], true, true, Color(255, 255, 255, 255), "l");
else if (WeaponIDz == WEAPON_DECOY)
DrawF((int)nadeEnd.x - 5, (int)nadeEnd.y, fonts[iconslol], true, true, Color(255, 255, 255, 255), "m");
else if (WeaponIDz == WEAPON_SMOKEGRENADE)
DrawF((int)nadeEnd.x - 5, (int)nadeEnd.y, fonts[iconslol], true, true, Color(255, 255, 255, 255), "k");
}
}
}
}
void GrenadePrediction::Setup(Vector& vecSrc, Vector& vecThrow, Vector viewangles)
{
if (!g_ctx.m_local) return;
Vector angThrow = viewangles;
float pitch = angThrow.x;
if (pitch <= 90.0f)
{
if (pitch < -90.0f)
pitch += 360.0f;
}
else
pitch -= 360.0f;
float a = pitch - (90.0f - fabs(pitch)) * 10.0f / 90.0f;
angThrow.x = a;
float flVel = 750.0f * 0.9f;
static const float power[] = { 1.0f, 1.0f, 0.5f, 0.0f };
float b = power[act];
b = b * 0.7f; b = b + 0.3f;
flVel *= b;
Vector vForward, vRight, vUp;
math::angle_vectors(angThrow, &vForward, &vRight, &vUp);
vecSrc = g_ctx.m_local->get_eye_pos();
float off = (power[act] * 12.0f) - 12.0f;
vecSrc.z += off;
trace_t tr;
Vector vecDest = vecSrc;
vecDest += vForward * 22.0f;
TraceHull(vecSrc, vecDest, tr);
Vector vecBack = vForward; vecBack *= 6.0f;
vecSrc = tr.endpos;
vecSrc -= vecBack;
vecThrow = g_ctx.m_local->m_vecVelocity(); vecThrow *= 1.25f;
vecThrow += vForward * flVel;
}
void GrenadePrediction::Simulate(CViewSetup* setup)
{
Vector vecSrc, vecThrow;
Vector angles; g_csgo.m_engine()->GetViewAngles(angles);
Setup(vecSrc, vecThrow, angles);
float interval = g_csgo.m_globals()->m_interval_per_tick;
int logstep = (int)(0.05f / interval);
int logtimer = 0;
path.clear(); others.clear();
for (unsigned int i = 0; i < path.max_size() - 1; ++i)
{
if (!logtimer) path.push_back(vecSrc);
int s = Step(vecSrc, vecThrow, i, interval);
if ((s & 1)) break;
if ((s & 2) || logtimer >= logstep) logtimer = 0;
else ++logtimer;
}
path.push_back(vecSrc);
}
#define PI 3.14159265358979323846f
int GrenadePrediction::Step(Vector& vecSrc, Vector& vecThrow, int tick, float interval)
{
Vector move; AddGravityMove(move, vecThrow, interval, false);
trace_t tr; PushEntity(vecSrc, move, tr);
int result = 0;
auto weapon = reinterpret_cast<weapon_t*>(g_csgo.m_entitylist()->GetClientEntity(g_ctx.m_local->GetActiveWeaponIndex()));
if (!weapon) return 0;
if (!IsGrenade(weapon)) return 0;
if (CheckDetonate(vecThrow, tr, tick, interval))
result |= 1;
if (tr.fraction != 1.0f)
{
result |= 2;
ResolveFlyCollisionCustom(tr, vecThrow, interval);
QAngle angles;
math::vector_angles((tr.endpos - tr.startpos).Normalized(), angles);
others.push_back(std::make_pair(tr.endpos, angles));
}
vecSrc = tr.endpos;
return result;
}
bool GrenadePrediction::CheckDetonate(const Vector& vecThrow, const trace_t& tr, int tick, float interval)
{
switch (type)
{
case WEAPON_SMOKEGRENADE:
case WEAPON_DECOY:
if (vecThrow.Length2D() < 0.1f)
{
int det_tick_mod = (int)(0.2f / interval);
return !(tick % det_tick_mod);
}
return false;
case WEAPON_MOLOTOV:
case WEAPON_INCGRENADE:
if (tr.fraction != 1.0f && tr.plane.normal.z > 0.7f)
return true;
case WEAPON_FLASHBANG:
case WEAPON_HEGRENADE:
return (float)tick * interval > 1.5f && !(tick % (int)(0.2f / interval));
default:
assert(false);
return false;
}
}
void GrenadePrediction::TraceHull(Vector& src, Vector& end, trace_t& tr)
{
Ray_t ray; CTraceFilterWorldOnly filter;
ray.Init(src, end, Vector(-2.0f, -2.0f, -2.0f), Vector(2.0f, 2.0f, 2.0f));
g_csgo.m_trace()->TraceRay(ray, 0x200400B, &filter, &tr);
}
void GrenadePrediction::AddGravityMove(Vector& move, Vector& vel, float frametime, bool onground)
{
Vector basevel(0.0f, 0.0f, 0.0f);
move.x = (vel.x + basevel.x) * frametime;
move.y = (vel.y + basevel.y) * frametime;
if (onground)
move.z = (vel.z + basevel.z) * frametime;
else
{
float gravity = 800.0f * 0.4f;
float newZ = vel.z - (gravity * frametime);
move.z = ((vel.z + newZ) / 2.0f + basevel.z) * frametime;
vel.z = newZ;
}
}
void GrenadePrediction::PushEntity(Vector& src, const Vector& move, trace_t& tr)
{
Vector vecAbsEnd = src;
vecAbsEnd += move;
TraceHull(src, vecAbsEnd, tr);
}
void GrenadePrediction::ResolveFlyCollisionCustom(trace_t& tr, Vector& vecVelocity, float interval)
{
float flSurfaceElasticity = 1.0, flGrenadeElasticity = 0.45f;
float flTotalElasticity = flGrenadeElasticity * flSurfaceElasticity;
if (flTotalElasticity > 0.9f) flTotalElasticity = 0.9f;
if (flTotalElasticity < 0.0f) flTotalElasticity = 0.0f;
Vector vecAbsVelocity;
PhysicsClipVelocity(vecVelocity, tr.plane.normal, vecAbsVelocity, 2.0f);
vecAbsVelocity *= flTotalElasticity;
float flSpeedSqr = vecAbsVelocity.LengthSqr();
static const float flMinSpeedSqr = 20.0f * 20.0f;
if (flSpeedSqr < flMinSpeedSqr)
{
vecAbsVelocity.x = 0.0f;
vecAbsVelocity.y = 0.0f;
vecAbsVelocity.z = 0.0f;
}
if (tr.plane.normal.z > 0.7f)
{
vecVelocity = vecAbsVelocity;
vecAbsVelocity *= ((1.0f - tr.fraction) * interval);
PushEntity(tr.endpos, vecAbsVelocity, tr);
}
else
vecVelocity = vecAbsVelocity;
}
int GrenadePrediction::PhysicsClipVelocity(const Vector& in, const Vector& normal, Vector& out, float overbounce)
{
static const float STOP_EPSILON = 0.1f;
float backoff, change, angle;
int i, blocked;
blocked = 0;
angle = normal[2];
if (angle > 0) blocked |= 1;
if (!angle) blocked |= 2;
backoff = in.Dot(normal) * overbounce;
for (i = 0; i < 3; i++)
{
change = normal[i] * backoff;
out[i] = in[i] - change;
if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)
out[i] = 0;
}
return blocked;
}
C++:
#pragma once
#include <deque>
enum ACT
{
ACT_NONE,
ACT_THROW,
ACT_LOB,
ACT_DROP,
};
class GrenadePrediction : public singleton<GrenadePrediction>
{
private:
std::vector<Vector> path;
std::vector<std::pair<Vector, QAngle>> others;
//std::vector<Vector> others;
int type = 0;
int act = 0;
void Setup(Vector& vecSrc, Vector& vecThrow, Vector viewangles);
void Simulate(CViewSetup* setup);
int Step(Vector& vecSrc, Vector& vecThrow, int tick, float interval);
bool CheckDetonate(const Vector& vecThrow, const trace_t& tr, int tick, float interval);
void TraceHull(Vector& src, Vector& end, trace_t& tr);
void AddGravityMove(Vector& move, Vector& vel, float frametime, bool onground);
void PushEntity(Vector& src, const Vector& move, trace_t& tr);
void ResolveFlyCollisionCustom(trace_t& tr, Vector& vecVelocity, float interval);
int PhysicsClipVelocity(const Vector& in, const Vector& normal, Vector& out, float overbounce);
public:
void Tick(int buttons);
void View(CViewSetup* setup);
void Paint();
};