242 lines
7.9 KiB
C++
242 lines
7.9 KiB
C++
/*
|
|
* AutoReflect.cpp
|
|
*
|
|
* Created on: Nov 18, 2016
|
|
* Author: nullifiedcat
|
|
*/
|
|
|
|
#include "common.hpp"
|
|
|
|
namespace hacks
|
|
{
|
|
namespace tf
|
|
{
|
|
namespace autoreflect
|
|
{
|
|
|
|
// Vars for user settings
|
|
CatVar enabled(CV_SWITCH, "reflect_enabled", "0", "Auto Reflect",
|
|
"Master AutoReflect switch");
|
|
CatVar idle_only(CV_SWITCH, "reflect_only_idle", "0", "Only when not shooting",
|
|
"Don't AutoReflect if you're holding M1");
|
|
CatVar legit(CV_SWITCH, "reflect_legit", "0", "Legit Reflect",
|
|
"Only Auto-airblasts projectiles that you can see, doesnt move "
|
|
"your crosshair");
|
|
CatVar dodgeball(CV_SWITCH, "reflect_dodgeball", "0", "Dodgeball Mode",
|
|
"Allows auto-reflect to work in dodgeball servers");
|
|
CatVar blastkey(CV_KEY, "reflect_key", "0", "Reflect Key",
|
|
"Hold this key to activate auto-airblast");
|
|
CatVar stickies(CV_SWITCH, "reflect_stickybombs", "0", "Reflect stickies",
|
|
"Reflect Stickybombs");
|
|
CatVar teammates(CV_SWITCH, "reflect_teammates", "0",
|
|
"Reflect teammates projectiles", "Useful in dodgeball with "
|
|
"free-for-all enabled");
|
|
CatVar fov(CV_FLOAT, "reflect_fov", "85", "Reflect FOV", "Reflect FOV", 180.0f);
|
|
CatVar fov_draw(CV_SWITCH, "reflect_fov_draw", "0", "Draw Fov Ring",
|
|
"Draws a ring to represent your current reflect fov");
|
|
CatVar fovcircle_opacity(CV_FLOAT, "reflect_fov_draw_opacity", "0.7",
|
|
"FOV Circle Opacity", "Defines opacity of FOV circle",
|
|
0.0f, 1.0f);
|
|
// TODO setup proj sorting
|
|
// TODO CatVar big_proj(CV_SWITCH, "reflect_big_projectile", "0", "Reflect big
|
|
// projectiles", "Reflect Rockets");
|
|
// TODO CatVar small_proj(CV_SWITCH, "reflect_small_projectile", "0", "Reflect
|
|
// small projectiles", "Reflect Huntsman arrows, Crusaders bolts");
|
|
// TODO CatVar misc_proj(CV_SWITCH, "reflect_misc_projectile", "0", "Reflect
|
|
// other", "Reflect jarate, milk");
|
|
|
|
// Function called by game for movement
|
|
void CreateMove()
|
|
{
|
|
// Check if user settings allow Auto Reflect
|
|
if (!enabled)
|
|
return;
|
|
if (blastkey && !blastkey.KeyDown())
|
|
return;
|
|
|
|
// Check if player is using a flame thrower
|
|
if (g_pLocalPlayer->weapon()->m_iClassID != CL_CLASS(CTFFlameThrower))
|
|
return;
|
|
|
|
// Check for phlogistinator, which is item 594
|
|
if (HasWeapon(LOCAL_E, 594))
|
|
return;
|
|
|
|
// If user settings allow, return if local player is in attack
|
|
if (idle_only && (g_pUserCmd->buttons & IN_ATTACK))
|
|
return;
|
|
|
|
// Create some book-keeping vars
|
|
float closest_dist = 0.0f;
|
|
Vector closest_vec;
|
|
// Loop to find the closest entity
|
|
for (int i = 0; i < HIGHEST_ENTITY; i++)
|
|
{
|
|
|
|
// Find an ent from the for loops current tick
|
|
CachedEntity *ent = ENTITY(i);
|
|
|
|
// Check if null or dormant
|
|
if (CE_BAD(ent))
|
|
continue;
|
|
|
|
// Check if ent should be reflected
|
|
if (!ShouldReflect(ent))
|
|
continue;
|
|
|
|
// Some extrapolating due to reflect timing being latency based
|
|
// Grab latency
|
|
float latency =
|
|
g_IEngine->GetNetChannelInfo()->GetLatency(FLOW_INCOMING) +
|
|
g_IEngine->GetNetChannelInfo()->GetLatency(FLOW_OUTGOING);
|
|
// Create a vector variable to store our velocity
|
|
Vector velocity;
|
|
// Grab Velocity of projectile
|
|
velocity::EstimateAbsVelocity(RAW_ENT(ent), velocity);
|
|
// Predict a vector for where the projectile will be
|
|
Vector predicted_proj = ent->m_vecOrigin + (velocity * latency);
|
|
;
|
|
|
|
// Dont vischeck if ent is stickybomb or if dodgeball mode is enabled
|
|
if (!IsEntStickyBomb(ent) && !dodgeball)
|
|
{
|
|
// Vis check the predicted vector
|
|
if (!IsVectorVisible(g_pLocalPlayer->v_Origin, predicted_proj))
|
|
continue;
|
|
} /*else {
|
|
// Stickys are weird, we use a different way to vis check them
|
|
// Vis checking stickys are wonky, I quit, just ignore the check >_>
|
|
//if (!VisCheckEntFromEnt(ent, LOCAL_E)) continue;
|
|
}*/
|
|
|
|
// Calculate distance
|
|
float dist = predicted_proj.DistToSqr(g_pLocalPlayer->v_Origin);
|
|
|
|
// If legit mode is on, we check to see if reflecting will work if we
|
|
// dont aim at the projectile
|
|
if (legit)
|
|
{
|
|
if (GetFov(g_pLocalPlayer->v_OrigViewangles, g_pLocalPlayer->v_Eye,
|
|
predicted_proj) > (float) fov)
|
|
continue;
|
|
}
|
|
|
|
// Compare our info to the others and determine if its the best, if we
|
|
// dont have a projectile already, then we save it here
|
|
if (dist < closest_dist || closest_dist == 0.0f)
|
|
{
|
|
closest_dist = dist;
|
|
closest_vec = predicted_proj;
|
|
}
|
|
}
|
|
|
|
// Determine whether the closest projectile is whithin our parameters,
|
|
// preferably 185 units should be our limit, sqr is around the number below
|
|
if (closest_dist == 0 || closest_dist > 34400)
|
|
return;
|
|
|
|
// We dont want to aim if legit is true
|
|
if (!legit)
|
|
{
|
|
// Aim at predicted projectile
|
|
AimAt(g_pLocalPlayer->v_Eye, closest_vec, g_pUserCmd);
|
|
// Use silent angles
|
|
g_pLocalPlayer->bUseSilentAngles = true;
|
|
}
|
|
|
|
// Airblast
|
|
g_pUserCmd->buttons |= IN_ATTACK2;
|
|
|
|
// Function is finished, return
|
|
return;
|
|
}
|
|
|
|
// Function to determine whether an ent is good to reflect
|
|
bool ShouldReflect(CachedEntity *ent)
|
|
{
|
|
// Check if the entity is a projectile
|
|
if (ent->m_Type != ENTITY_PROJECTILE)
|
|
return false;
|
|
|
|
if (!teammates)
|
|
{
|
|
// Check if the projectile is your own teams
|
|
if (!ent->m_bEnemy)
|
|
return false;
|
|
}
|
|
|
|
// We dont want to do these checks in dodgeball, it breakes if we do
|
|
if (!dodgeball)
|
|
{
|
|
// If projectile is already deflected, don't deflect it again.
|
|
if (CE_INT(ent, (ent->m_bGrenadeProjectile
|
|
?
|
|
/* NetVar for grenades */ netvar.Grenade_iDeflected
|
|
:
|
|
/* For rockets */ netvar.Rocket_iDeflected)))
|
|
return false;
|
|
}
|
|
|
|
// Check if the projectile is a sticky bomb and if the user settings allow
|
|
// it to be reflected
|
|
if (IsEntStickyBomb(ent) && !stickies)
|
|
return false;
|
|
|
|
// Target passed the test, return true
|
|
return true;
|
|
}
|
|
|
|
bool IsEntStickyBomb(CachedEntity *ent)
|
|
{
|
|
// Check if the projectile is a sticky bomb
|
|
if (ent->m_iClassID == CL_CLASS(CTFGrenadePipebombProjectile))
|
|
{
|
|
if (CE_INT(ent, netvar.iPipeType) == 1)
|
|
{
|
|
// Ent passed and should be reflected
|
|
return true;
|
|
}
|
|
}
|
|
// Ent didnt pass the test so return false
|
|
return false;
|
|
}
|
|
void Draw()
|
|
{
|
|
// Dont draw to screen when reflect is disabled
|
|
if (!enabled)
|
|
return;
|
|
// Don't draw to screen when legit is disabled
|
|
if (!legit)
|
|
return;
|
|
|
|
// Fov ring to represent when a projectile will be reflected
|
|
if (fov_draw)
|
|
{
|
|
// It cant use fovs greater than 180, so we check for that
|
|
if (float(fov) > 0.0f && float(fov) < 180)
|
|
{
|
|
// Dont show ring while player is dead
|
|
if (LOCAL_E->m_bAlivePlayer)
|
|
{
|
|
rgba_t color = GUIColor();
|
|
color.a = float(fovcircle_opacity);
|
|
|
|
int width, height;
|
|
g_IEngine->GetScreenSize(width, height);
|
|
|
|
// Math
|
|
float mon_fov = (float(width) / float(height) / (4.0f / 3.0f));
|
|
float fov_real =
|
|
RAD2DEG(2 * atanf(mon_fov * tanf(DEG2RAD(draw::fov / 2))));
|
|
float radius = tan(DEG2RAD(float(fov)) / 2) /
|
|
tan(DEG2RAD(fov_real) / 2) * (width);
|
|
|
|
draw_api::draw_circle(width / 2, height / 2, radius, color, 1,
|
|
100);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} |