/* * 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); } } } } } } }