Added option to vischeck/multipoint all hitboxes instead of one (#1697)

Added option to vischeck all hitboxes
This commit is contained in:
Stephen Martin 2022-07-13 18:49:46 -04:00 committed by GitHub
parent 4e09888306
commit 6530e72b2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 209 additions and 57 deletions

View File

@ -26,8 +26,8 @@
<List width="150"> <List width="150">
<AutoVariable width="fill" target="aimbot.projectile.enable" label="Enable projectile aimbot"/> <AutoVariable width="fill" target="aimbot.projectile.enable" label="Enable projectile aimbot"/>
<AutoVariable width="fill" target="aimbot.debug.engine-pp" label="Engine prediction"/> <AutoVariable width="fill" target="aimbot.debug.engine-pp" label="Engine prediction"/>
<AutoVariable width="fill" target="misc.auto-flip-viewmodel" label="Flip viewmodel" tooltip="Automatically flip the viewmodel for projectile weapons."/>
<AutoVariable width="fill" target="debug.pp-steps" label="Prediction steps" min="1" max="300"/> <AutoVariable width="fill" target="debug.pp-steps" label="Prediction steps" min="1" max="300"/>
<AutoVariable width="fill" target="misc.auto-flip-viewmodel" label="Flip viewmodel" tooltip="Automatically flip the viewmodel for projectile weapons."/>
<AutoVariable width="fill" target="aimbot.projectile.gravity" label="Gravity override"/> <AutoVariable width="fill" target="aimbot.projectile.gravity" label="Gravity override"/>
<AutoVariable width="fill" target="aimbot.projectile.initial-velocity" label="Initial velocity"/> <AutoVariable width="fill" target="aimbot.projectile.initial-velocity" label="Initial velocity"/>
<AutoVariable width="fill" target="aimbot.projectile.speed" label="Velocity override"/> <AutoVariable width="fill" target="aimbot.projectile.speed" label="Velocity override"/>
@ -86,6 +86,13 @@
</LabeledObject> </LabeledObject>
<AutoVariable width="fill" target="aimbot.target.max-range" label="Max range" tooltip="Entities further than this distance will not be targeted. Measured in Hammer units."/> <AutoVariable width="fill" target="aimbot.target.max-range" label="Max range" tooltip="Entities further than this distance will not be targeted. Measured in Hammer units."/>
<AutoVariable width="fill" target="aimbot.multipoint" label="Multipoint"/> <AutoVariable width="fill" target="aimbot.multipoint" label="Multipoint"/>
<LabeledObject width="fill" label="All Hiitboxes" tooltip="This will vischeck as many hitboxes as it can on the target to see if it can shoot. This will reduce your FPS.">
<Select target="aimbot.vischeck-hitboxes">
<Option name="Disable" value="0"/>
<Option name="Rage Only" value="1"/>
<Option name="All" value="2"/>
</Select>
</LabeledObject>
<AutoVariable width="fill" target="aimbot.assistance.only" label="Assistance only" tooltip="Aimbot will only activate if your mouse has moved in the last half second."/> <AutoVariable width="fill" target="aimbot.assistance.only" label="Assistance only" tooltip="Aimbot will only activate if your mouse has moved in the last half second."/>
<AutoVariable width="fill" target="aimbot.lock-target" label="Lock target" tooltip="Lock onto a target until they die or leave your FOV."/> <AutoVariable width="fill" target="aimbot.lock-target" label="Lock target" tooltip="Lock onto a target until they die or leave your FOV."/>
<AutoVariable width="fill" target="aimbot.target.ignore-non-rage" label="Rage only" tooltip="Only target players set to RAGE."/> <AutoVariable width="fill" target="aimbot.target.ignore-non-rage" label="Rage only" tooltip="Only target players set to RAGE."/>

View File

@ -43,9 +43,11 @@ bool IsTargetStateGood(CachedEntity *entity);
bool Aim(CachedEntity *entity); bool Aim(CachedEntity *entity);
void DoAutoshoot(CachedEntity *target = nullptr); void DoAutoshoot(CachedEntity *target = nullptr);
int notVisibleHitbox(CachedEntity *target, int preferred); int notVisibleHitbox(CachedEntity *target, int preferred);
int autoHitbox(CachedEntity* target); std::vector<Vector> getHitpointsVischeck(CachedEntity *ent, int hitbox);
bool hitscanSpecialCases(CachedEntity* target_entity, int weapon_case); float projectileHitboxSize(int projectile_size);
bool projectileSpecialCases(CachedEntity* target_entity, int weapon_case); int autoHitbox(CachedEntity *target);
bool hitscanSpecialCases(CachedEntity *target_entity, int weapon_case);
bool projectileSpecialCases(CachedEntity *target_entity, int weapon_case);
int BestHitbox(CachedEntity *target); int BestHitbox(CachedEntity *target);
bool isHitboxMedium(int hitbox); bool isHitboxMedium(int hitbox);
int ClosestHitbox(CachedEntity *target); int ClosestHitbox(CachedEntity *target);

View File

@ -118,6 +118,7 @@ bool GetProjectileData(CachedEntity *weapon, float &speed, float &gravity, float
bool IsVectorVisible(Vector a, Vector b, bool enviroment_only = false, CachedEntity *self = LOCAL_E, unsigned int mask = MASK_SHOT_HULL); bool IsVectorVisible(Vector a, Vector b, bool enviroment_only = false, CachedEntity *self = LOCAL_E, unsigned int mask = MASK_SHOT_HULL);
// A Special function for navparser to check if a Vector is visible. // A Special function for navparser to check if a Vector is visible.
bool IsVectorVisibleNavigation(Vector a, Vector b, unsigned int mask = MASK_SHOT_HULL); bool IsVectorVisibleNavigation(Vector a, Vector b, unsigned int mask = MASK_SHOT_HULL);
bool didProjectileHit(Vector start_point, Vector end_point, CachedEntity *entity, int projectile_size);
Vector getShootPos(Vector angle); Vector getShootPos(Vector angle);
Vector GetForwardVector(Vector origin, Vector viewangles, float distance, CachedEntity *punch_entity = nullptr); Vector GetForwardVector(Vector origin, Vector viewangles, float distance, CachedEntity *punch_entity = nullptr);
Vector GetForwardVector(float distance, CachedEntity *punch_entity = nullptr); Vector GetForwardVector(float distance, CachedEntity *punch_entity = nullptr);

View File

@ -24,10 +24,9 @@ Vector SimpleLatencyPrediction(CachedEntity *ent, int hb);
// The first entry ignores initial velocity, the second one does not. // The first entry ignores initial velocity, the second one does not.
// Used for vischeck things. // Used for vischeck things.
std::pair<Vector, Vector> BuildingPrediction(CachedEntity *building, Vector vec, float speed, float gravity, float proj_startvelocity = 0.0f);
std::pair<Vector, Vector> ProjectilePrediction(CachedEntity *ent, int hb, float speed, float gravitymod, float entgmod, float proj_startvelocity = 0.0f); std::pair<Vector, Vector> ProjectilePrediction(CachedEntity *ent, int hb, float speed, float gravitymod, float entgmod, float proj_startvelocity = 0.0f);
std::pair<Vector, Vector> ProjectilePrediction_Engine(CachedEntity *ent, int hb, float speed, float gravitymod, float entgmod, float proj_startvelocity = 0.0f); std::pair<Vector, Vector> ProjectilePrediction_Engine(CachedEntity *ent, int hb, float speed, float gravitymod, float entgmod, float proj_startvelocity = 0.0f);
std::pair<Vector, Vector> BuildingPrediction(CachedEntity *building, Vector vec, float speed, float gravity, float proj_startvelocity);
std::vector<Vector> Predict(CachedEntity *player, Vector pos, float offset, Vector vel, Vector acceleration, std::pair<Vector, Vector> minmax, int count, bool vischeck = true); std::vector<Vector> Predict(CachedEntity *player, Vector pos, float offset, Vector vel, Vector acceleration, std::pair<Vector, Vector> minmax, int count, bool vischeck = true);
Vector PredictStep(Vector pos, Vector &vel, const Vector &acceleration, std::pair<Vector, Vector> *minmax, float steplength = g_GlobalVars->interval_per_tick, StrafePredictionData *strafepred = nullptr, bool vischeck = true, std::optional<float> grounddistance = std::nullopt); Vector PredictStep(Vector pos, Vector &vel, const Vector &acceleration, std::pair<Vector, Vector> *minmax, float steplength = g_GlobalVars->interval_per_tick, StrafePredictionData *strafepred = nullptr, bool vischeck = true, std::optional<float> grounddistance = std::nullopt);
float PlayerGravityMod(CachedEntity *player); float PlayerGravityMod(CachedEntity *player);

View File

@ -29,6 +29,7 @@ static settings::Boolean autoshoot{ "aimbot.autoshoot", "1" };
static settings::Boolean autoreload{ "aimbot.autoshoot.activate-heatmaker", "false" }; static settings::Boolean autoreload{ "aimbot.autoshoot.activate-heatmaker", "false" };
static settings::Boolean autoshoot_disguised{ "aimbot.autoshoot-disguised", "1" }; static settings::Boolean autoshoot_disguised{ "aimbot.autoshoot-disguised", "1" };
static settings::Boolean multipoint{ "aimbot.multipoint", "0" }; static settings::Boolean multipoint{ "aimbot.multipoint", "0" };
static settings::Int vischeck_hitboxes{ "aimbot.vischeck-hitboxes", "0" };
static settings::Int hitbox_mode{ "aimbot.hitbox-mode", "0" }; static settings::Int hitbox_mode{ "aimbot.hitbox-mode", "0" };
static settings::Float normal_fov{ "aimbot.fov", "0" }; static settings::Float normal_fov{ "aimbot.fov", "0" };
static settings::Int priority_mode{ "aimbot.priority-mode", "0" }; static settings::Int priority_mode{ "aimbot.priority-mode", "0" };
@ -147,7 +148,7 @@ std::vector<Vector> getValidHitpoints(CachedEntity *ent, int hitbox)
hitpoints.push_back(hb->center); hitpoints.push_back(hb->center);
} }
if (!multipoint) if (!*multipoint)
return hitpoints; return hitpoints;
// Multipoint // Multipoint
@ -186,6 +187,77 @@ std::vector<Vector> getValidHitpoints(CachedEntity *ent, int hitbox)
positions.insert(positions.end(), corners, &corners[8]); positions.insert(positions.end(), corners, &corners[8]);
positions.insert(positions.end(), line_positions, &line_positions[12]); positions.insert(positions.end(), line_positions, &line_positions[12]);
for (int i = 0; i < 20; ++i)
{
trace_t trace;
if (IsEntityVectorVisible(ent, positions[i], true, MASK_SHOT_HULL, &trace))
{
if (trace.hitbox == hitbox)
hitpoints.push_back(positions[i]);
}
}
if (*vischeck_hitboxes)
{
if (*vischeck_hitboxes == 1 && playerlist::AccessData(ent).state != playerlist::k_EState::RAGE)
{
return hitpoints;
}
int i = 0;
while (hitpoints.empty() && i <= 17) // Prevents returning empty at all costs. Loops through every hitbox
{
if (hitbox == i)
i++;
hitpoints = getHitpointsVischeck(ent, i);
i++;
}
}
return hitpoints;
}
std::vector<Vector> getHitpointsVischeck(CachedEntity *ent, int hitbox)
{
std::vector<Vector> hitpoints;
auto hb = ent->hitboxes.GetHitbox(hitbox);
if (!*multipoint)
{
hitpoints.push_back(hb->center);
return hitpoints;
}
auto bboxmin = hb->bbox->bbmin;
auto bboxmax = hb->bbox->bbmax;
auto transform = ent->hitboxes.GetBones()[hb->bbox->bone];
QAngle rotation;
Vector origin;
MatrixAngles(transform, rotation, origin);
Vector corners[8];
GenerateBoxVertices(origin, rotation, bboxmin, bboxmax, corners);
float shrink_size = 1;
if (!isHitboxMedium(hitbox)) // hitbox should be chosen based on size.
shrink_size = 3;
else
shrink_size = 6;
// Shrink positions by moving towards opposing corner
for (int i = 0; i < 8; i++)
corners[i] += (corners[7 - i] - corners[i]) / shrink_size;
// Generate middle points on line segments
// Define cleans up code
const Vector line_positions[12] = { GET_MIDDLE(0, 1), GET_MIDDLE(0, 2), GET_MIDDLE(1, 3), GET_MIDDLE(2, 3), GET_MIDDLE(7, 6), GET_MIDDLE(7, 5), GET_MIDDLE(6, 4), GET_MIDDLE(5, 4), GET_MIDDLE(0, 4), GET_MIDDLE(1, 5), GET_MIDDLE(2, 6), GET_MIDDLE(3, 7) };
// Create combined vector
std::vector<Vector> positions;
positions.reserve(sizeof(Vector) * 20);
positions.insert(positions.end(), corners, &corners[8]);
positions.insert(positions.end(), line_positions, &line_positions[12]);
for (int i = 0; i < 20; ++i) for (int i = 0; i < 20; ++i)
{ {
trace_t trace; trace_t trace;
@ -845,6 +917,36 @@ bool IsTargetStateGood(CachedEntity *entity)
AimbotCalculatedData_s &cd = calculated_data_array[entity->m_IDX]; AimbotCalculatedData_s &cd = calculated_data_array[entity->m_IDX];
cd.hitbox = BestHitbox(entity); cd.hitbox = BestHitbox(entity);
if (*vischeck_hitboxes && !*multipoint)
{
if (*vischeck_hitboxes == 1 && playerlist::AccessData(entity).state != playerlist::k_EState::RAGE)
{
return true;
}
else
{
int i = 0;
trace_t first_tracer;
if (IsEntityVectorVisible(entity, entity->hitboxes.GetHitbox(cd.hitbox)->center, true, MASK_SHOT_HULL, &first_tracer))
return true;
while (i <= 17) // Prevents returning empty at all costs. Loops through every hitbox
{
if (i == cd.hitbox)
i++;
trace_t test_trace;
std::vector<Vector> centered_hitbox = getHitpointsVischeck(entity, i);
if (IsEntityVectorVisible(entity, centered_hitbox[0], true, MASK_SHOT_HULL, &test_trace))
{
cd.hitbox = i;
return true;
}
i++;
}
return false; // It looped through every hitbox and found nothing. It isn't visible.
}
}
return true; return true;
break; break;
} }
@ -960,7 +1062,34 @@ bool IsTargetStateGood(CachedEntity *entity)
return false; return false;
} }
float projectileHitboxSize(int projectile_size)
{
float projectile_hitbox_size = 6.3f;
switch (projectile_size)
{
case CL_CLASS(CTFRocketLauncher):
case CL_CLASS(CTFRocketLauncher_Mortar):
case CL_CLASS(CTFRocketLauncher_AirStrike):
case CL_CLASS(CTFRocketLauncher_DirectHit):
case CL_CLASS(CTFPipebombLauncher):
case CL_CLASS(CTFGrenadeLauncher):
case CL_CLASS(CTFCannon):
break;
case CL_CLASS(CTFFlareGun):
case CL_CLASS(CTFFlareGun_Revenge):
case CL_CLASS(CTFDRGPomson):
projectile_hitbox_size = 3;
break;
case CL_CLASS(CTFSyringeGun):
case CL_CLASS(CTFCompoundBow):
projectile_hitbox_size = 1;
break;
default:
break;
}
return projectile_hitbox_size;
}
// A function to aim at a specific entitiy // A function to aim at a specific entitiy
bool Aim(CachedEntity *entity) bool Aim(CachedEntity *entity)
{ {
@ -969,22 +1098,24 @@ bool Aim(CachedEntity *entity)
// Get angles from eye to target // Get angles from eye to target
Vector is_it_good = PredictEntity(entity); Vector is_it_good = PredictEntity(entity);
bool should_aim; if (!projectileAimbotRequired)
if (extrapolate || projectileAimbotRequired || entity->m_Type() != ENTITY_PLAYER)
{ {
should_aim = IsEntityVectorVisible(entity, is_it_good, true); if (!IsEntityVectorVisible(entity, is_it_good, false))
return false;
} }
else
Vector angles = GetAimAtAngles(g_pLocalPlayer->v_Eye, is_it_good, LOCAL_E);
if (projectileAimbotRequired) // unfortunately you have to check this twice, otherwise you'd have to run GetAimAtAngles far too early
{ {
should_aim = IsEntityVectorVisible(entity, is_it_good, false);
if (!didProjectileHit(getShootPos(angles), is_it_good, entity, projectileHitboxSize(LOCAL_W->m_iClassID())))
return false;
} }
if (!should_aim)
return false;
AimbotCalculatedData_s &cd = calculated_data_array[entity->m_IDX]; AimbotCalculatedData_s &cd = calculated_data_array[entity->m_IDX];
if (fov > 0 && cd.fov > fov) if (fov > 0 && cd.fov > fov)
return false; return false;
Vector angles = GetAimAtAngles(g_pLocalPlayer->v_Eye, is_it_good, LOCAL_E);
// Slow aim // Slow aim
if (slow_aim) if (slow_aim)
DoSlowAim(angles); DoSlowAim(angles);
@ -1156,16 +1287,13 @@ Vector PredictEntity(CachedEntity *entity)
// Buildings // Buildings
case ENTITY_BUILDING: case ENTITY_BUILDING:
{ {
if (projectileAimbotRequired) if (cur_proj_grav != 0)
{ {
std::pair<Vector, Vector> tmp_result; std::pair<Vector, Vector> temp_result = BuildingPrediction(entity, GetBuildingPosition(entity), cur_proj_speed, cur_proj_grav, cur_proj_start_vel);
tmp_result = BuildingPrediction(entity, GetBuildingPosition(entity), cur_proj_speed, cur_proj_grav, cur_proj_start_vel); result = temp_result.second;
result = tmp_result.second; // Buildings don't have velocity but I'll keep it in nonetheless
} }
else else
{
result = GetBuildingPosition(entity); result = GetBuildingPosition(entity);
}
break; break;
} }
// NPCs (Skeletons, merasmus, etc) // NPCs (Skeletons, merasmus, etc)
@ -1308,6 +1436,7 @@ int BestHitbox(CachedEntity *target)
// Hitbox machine :b:roke // Hitbox machine :b:roke
return -1; return -1;
} }
// Function to find the closesnt hitbox to the crosshair for a given ent // Function to find the closesnt hitbox to the crosshair for a given ent
int ClosestHitbox(CachedEntity *target) int ClosestHitbox(CachedEntity *target)
{ {

View File

@ -651,6 +651,18 @@ powerup_type GetPowerupOnPlayer(CachedEntity *player)
return powerup_type::supernova; return powerup_type::supernova;
return powerup_type::not_powerup; return powerup_type::not_powerup;
} }
bool didProjectileHit(Vector start_point, Vector end_point, CachedEntity *entity, int projectile_size)
{
trace::filter_default.SetSelf(RAW_ENT(g_pLocalPlayer->entity));
Ray_t ray;
trace_t trace_obj;
trace_t *tracer = &trace_obj;
ray.Init(start_point, end_point, Vector(0, -projectile_size, -projectile_size), Vector(0, projectile_size, projectile_size));
g_ITrace->TraceRay(ray, MASK_SHOT_HULL, &trace::filter_default, tracer);
return (((IClientEntity *) tracer->m_pEnt) == RAW_ENT(entity) || !tracer->DidHit());
}
// A function to find a weapon by WeaponID // A function to find a weapon by WeaponID
int getWeaponByID(CachedEntity *player, int weaponid) int getWeaponByID(CachedEntity *player, int weaponid)
{ {
@ -1017,7 +1029,7 @@ std::mutex trace_lock;
bool IsEntityVectorVisible(CachedEntity *entity, Vector endpos, bool use_weapon_offset, unsigned int mask, trace_t *trace) bool IsEntityVectorVisible(CachedEntity *entity, Vector endpos, bool use_weapon_offset, unsigned int mask, trace_t *trace)
{ {
trace_t trace_object; trace_t trace_object;
if (!trace) if (!trace)
trace = &trace_object; trace = &trace_object;
Ray_t ray; Ray_t ray;
@ -1035,6 +1047,7 @@ bool IsEntityVectorVisible(CachedEntity *entity, Vector endpos, bool use_weapon_
if (!tcm || g_Settings.is_create_move) if (!tcm || g_Settings.is_create_move)
g_ITrace->TraceRay(ray, mask, &trace::filter_default, trace); g_ITrace->TraceRay(ray, mask, &trace::filter_default, trace);
} }
return (((IClientEntity *) trace->m_pEnt) == RAW_ENT(entity) || !trace->DidHit()); return (((IClientEntity *) trace->m_pEnt) == RAW_ENT(entity) || !trace->DidHit());
} }

View File

@ -501,7 +501,6 @@ Vector EnginePrediction(CachedEntity *entity, float time, Vector *vecVelocity)
return result; return result;
} }
std::pair<Vector, Vector> ProjectilePrediction_Engine(CachedEntity *ent, int hb, float speed, float gravity, float entgmod, float proj_startvelocity) std::pair<Vector, Vector> ProjectilePrediction_Engine(CachedEntity *ent, int hb, float speed, float gravity, float entgmod, float proj_startvelocity)
{ {
Vector origin = ent->m_vecOrigin(); Vector origin = ent->m_vecOrigin();
@ -514,24 +513,22 @@ std::pair<Vector, Vector> ProjectilePrediction_Engine(CachedEntity *ent, int hb,
if (!sv_gravity) if (!sv_gravity)
sv_gravity = g_ICvar->FindVar("sv_gravity"); sv_gravity = g_ICvar->FindVar("sv_gravity");
if (speed == 0.0f || !sv_gravity) if (speed == 0.0f || !sv_gravity)
return { Vector(), Vector() }; return { Vector(), Vector() };
float currenttime = g_pLocalPlayer->v_Eye.DistTo(hitbox) / speed - 1.5f; float currenttime = g_pLocalPlayer->v_Eye.DistTo(hitbox) / speed - 1.5f;
if (currenttime <= 0.0f) if (currenttime <= 0.0f)
currenttime = 0.01f; currenttime = 0.01f;
float besttime = currenttime; float besttime = currenttime;
float mindelta = 65536.0f; float mindelta = 65536.0f;
float no_regression = 66534.0f;
Vector bestpos = origin; Vector bestpos = origin;
Vector current = origin; Vector current = origin;
Vector current_velocity = velocity; Vector current_velocity = velocity;
int maxsteps = (int) debug_pp_steps; int maxsteps = (int) debug_pp_steps;
float steplength = g_GlobalVars->interval_per_tick; float steplength = g_GlobalVars->interval_per_tick;
bool has_run_before = false;
Vector ent_mins = RAW_ENT(ent)->GetCollideable()->OBBMins();
Vector ent_maxs = RAW_ENT(ent)->GetCollideable()->OBBMaxs();
for (int steps = 0; steps < maxsteps; steps++, currenttime += steplength) for (int steps = 0; steps < maxsteps; steps++, currenttime += steplength)
{ {
ent->m_vecOrigin() = current; ent->m_vecOrigin() = current;
@ -553,6 +550,10 @@ std::pair<Vector, Vector> ProjectilePrediction_Engine(CachedEntity *ent, int hb,
bestpos = current; bestpos = current;
mindelta = timedelta; mindelta = timedelta;
} }
else if (mindelta < no_regression)
{
break;
}
} }
// logging::Info("besttime: %f, currenttime: %f, old currenttime: %f", besttime, currenttime, currenttime - steplength * maxsteps); // logging::Info("besttime: %f, currenttime: %f, old currenttime: %f", besttime, currenttime, currenttime - steplength * maxsteps);
const_cast<Vector &>(RAW_ENT(ent)->GetAbsOrigin()) = origin; const_cast<Vector &>(RAW_ENT(ent)->GetAbsOrigin()) = origin;
@ -568,32 +569,6 @@ std::pair<Vector, Vector> ProjectilePrediction_Engine(CachedEntity *ent, int hb,
result.y - origin.y, result.z - origin.z);*/ result.y - origin.y, result.z - origin.z);*/
return { result, result_initialvel }; return { result, result_initialvel };
} }
std::pair<Vector, Vector> BuildingPrediction(CachedEntity *building, Vector vec, float speed, float gravity, float proj_startvelocity)
{
if (!vec.z || CE_BAD(building))
return { Vector(), Vector() };
Vector result = vec;
if (!sv_gravity)
sv_gravity = g_ICvar->FindVar("sv_gravity");
if (speed == 0.0f || !sv_gravity)
return { Vector(), Vector() };
trace::filter_no_player.SetSelf(RAW_ENT(building));
// Buildings do not move. We don't need to do any steps here
float time = g_pLocalPlayer->v_Eye.DistTo(result) / speed;
// Compensate for ping
time += g_IEngine->GetNetChannelInfo()->GetLatency(FLOW_OUTGOING) + cl_interp->GetFloat();
result.z += (sv_gravity->GetFloat() / 2.0f * time * time * gravity);
Vector result_initialvel = result;
result_initialvel.z -= proj_startvelocity * time;
// S = at^2/2 ; t = sqrt(2S/a)*/
return { result, result_initialvel };
}
std::pair<Vector, Vector> ProjectilePrediction(CachedEntity *ent, int hb, float speed, float gravitymod, float entgmod, float proj_startvelocity) std::pair<Vector, Vector> ProjectilePrediction(CachedEntity *ent, int hb, float speed, float gravitymod, float entgmod, float proj_startvelocity)
{ {
Vector origin = ent->m_vecOrigin(); Vector origin = ent->m_vecOrigin();
@ -677,6 +652,32 @@ float DistanceToGround(CachedEntity *ent)
return DistanceToGround(origin, mins, maxs); return DistanceToGround(origin, mins, maxs);
} }
std::pair<Vector, Vector> BuildingPrediction(CachedEntity *building, Vector vec, float speed, float gravity, float proj_startvelocity)
{
if (!vec.z || CE_BAD(building))
return { Vector(), Vector() };
Vector result = vec;
if (!sv_gravity)
sv_gravity = g_ICvar->FindVar("sv_gravity");
if (speed == 0.0f || !sv_gravity)
return { Vector(), Vector() };
trace::filter_no_player.SetSelf(RAW_ENT(building));
// Buildings do not move. We don't need to do any steps here
float time = g_pLocalPlayer->v_Eye.DistTo(result) / speed;
// Compensate for ping
time += g_IEngine->GetNetChannelInfo()->GetLatency(FLOW_OUTGOING) + cl_interp->GetFloat();
result.z += (sv_gravity->GetFloat() / 2.0f * time * time * gravity);
Vector result_initialvel = result;
result_initialvel.z -= proj_startvelocity * time;
// S = at^2/2 ; t = sqrt(2S/a)*/
return { result, result_initialvel };
}
float DistanceToGround(Vector origin, Vector mins, Vector maxs) float DistanceToGround(Vector origin, Vector mins, Vector maxs)
{ {
// First, ensure we're not slightly below the floor, up to 18 HU will snap up // First, ensure we're not slightly below the floor, up to 18 HU will snap up