void DoAutostrafe() const
{
if (!c_config::get().misc_autostrafe)
return;
static bool is_bhopping;
static float calculated_direction;
static bool in_transition;
static float true_direction;
static float wish_direction;
static float step;
static float rough_direction;
auto local_player = Globals::LocalPlayer;
if (!local_player) return;
enum directions
{
FORWARDS = 0,
BACKWARDS = 180,
LEFT = 90,
RIGHT = -90
};
// Reset direction when player is not strafing
is_bhopping = pCmd->buttons & IN_JUMP;
if (!is_bhopping && local_player->GetFlags() & FL_ONGROUND)
{
calculated_direction = directions::FORWARDS;
in_transition = false;
return;
}
// Get true view angles
Vector base{ };
g_pEngine->GetViewAngles(base);
// Calculate the rough direction closest to the player's true direction
auto get_rough_direction = [&](float true_direction) -> float
{
// Make array with our four rough directions
std::array< float, 4 > minimum = { directions::FORWARDS, directions::BACKWARDS, directions::LEFT, directions::RIGHT };
float best_angle, best_delta = 181.f;
// Loop through our rough directions and find which one is closest to our true direction
for (size_t i = 0; i < minimum.size(); ++i)
{
float rough_direction = base.y + minimum.at(i);
float delta = fabsf(g_Math.NormalizeYaw(true_direction - rough_direction));
// Only the smallest delta wins out
if (delta < best_delta)
{
best_angle = rough_direction;
best_delta = delta;
}
}
return best_angle;
};
// Get true direction based on player velocity
true_direction = local_player->GetVelocity().Angle().y;
// Detect wish direction based on movement keypresses
if (pCmd->buttons & IN_FORWARD)
{
wish_direction = base.y + directions::FORWARDS;
}
else if (pCmd->buttons & IN_BACK)
{
wish_direction = base.y + directions::BACKWARDS;
}
else if (pCmd->buttons & IN_MOVELEFT)
{
wish_direction = base.y + directions::LEFT;
}
else if (pCmd->buttons & IN_MOVERIGHT)
{
wish_direction = base.y + directions::RIGHT;
}
else
{
// Reset to forward when not pressing a movement key, then fix anti-aim strafing by setting IN_FORWARD
pCmd->buttons |= IN_FORWARD;
wish_direction = base.y + directions::FORWARDS;
}
// Calculate the ideal strafe rotation based on player speed (c) navewindre
float speed_rotation = min(RAD2DEG(std::asinf(30.f / local_player->GetVelocity().Length2D())) * 0.5f, 45.f);
if (in_transition)
{
// Get value to rotate by via calculated speed rotation
float ideal_step = speed_rotation + calculated_direction;
step = fabsf(g_Math.NormalizeYaw(calculated_direction - ideal_step)); // 15.f is a good alternative, but here is where you would do your "speed" slider value for the autostrafer
// Check when the calculated direction arrives close to the wish direction
if (fabsf(g_Math.NormalizeYaw(wish_direction - calculated_direction)) > step)
{
float add = g_Math.NormalizeYaw(calculated_direction + step);
float sub = g_Math.NormalizeYaw(calculated_direction - step);
// Step in direction that gets us closer to our wish direction
if (fabsf(g_Math.NormalizeYaw(wish_direction - add)) >= fabsf(g_Math.NormalizeYaw(wish_direction - sub)))
{
calculated_direction -= step;
}
else
{
calculated_direction += step;
}
}
else
{
// Stop transitioning when we meet our wish direction
in_transition = false;
}
}
else
{
// Get rough direction and setup calculated direction only when not transitioning
rough_direction = get_rough_direction(true_direction);
calculated_direction = rough_direction;
// When we have a difference between our current (rough) direction and our wish direction, then transition
if (rough_direction != wish_direction)
{
in_transition = true;
}
}
// Set movement up to be rotated
pCmd->forwardmove = 0.f;
pCmd->sidemove = pCmd->command_number % 2 ? 450.f : -450.f;
// Calculate ideal rotation based on our newly calculated direction
float direction = (pCmd->command_number % 2 ? speed_rotation : -speed_rotation) + calculated_direction;
// Rotate our direction based on our new, defininite direction
float rotation = DEG2RAD(base.y - direction);
float cos_rot = cos(rotation);
float sin_rot = sin(rotation);
float forwardmove = (cos_rot * pCmd->forwardmove) - (sin_rot * pCmd->sidemove);
float sidemove = (sin_rot * pCmd->forwardmove) + (cos_rot * pCmd->sidemove);
// Apply newly rotated movement
pCmd->forwardmove = forwardmove;
pCmd->sidemove = sidemove;
}