void c_movement::accelerate(vec3_t& out_velo, float& stamina, float& friction, vec3_t move, float frametime)
{
static float sv_air_max_wishspeed = g_interfaces->m_var->get_by_name("sv_air_max_wishspeed")->get_float();
static float sv_air_accelerate = g_interfaces->m_var->get_by_name("sv_airaccelerate")->get_float();
static float sv_staminarecoveryrate = g_interfaces->m_var->get_by_name("sv_staminarecoveryrate")->get_float();
float max_speed = out_velo.length_2d();
if (stamina > 0)
{
float flSpeedScale = std::clamp(1.0f - (stamina / 100.f), 0.f, 1.f);
max_speed *= flSpeedScale * flSpeedScale;
stamina = fmaxf(stamina - (frametime * sv_staminarecoveryrate), 0.f);
}
vec3_t forward, left, up;
auto wish_angles = g_interfaces->m_csgo_input->get_view_angles();
g_math->angle_vectors(wish_angles, forward, left, up);
forward.normalize_in_place();
left.normalize_in_place();
vec3_t wish_dir{};
wish_dir.x = (((forward.x * move.x) * max_speed) - ((left.x * move.y) * max_speed));
wish_dir.y = ((forward.y * move.x) * max_speed) - ((left.y * move.y) * max_speed);
auto wish_speed = wish_dir.normalize_in_place();
wish_speed = fminf(wish_speed, max_speed);
const float spped_add = fminf(wish_speed, sv_air_max_wishspeed - out_velo.dot(wish_dir));
if (spped_add > 0.f)
{
const float accelspd = fminf(spped_add, ((wish_speed * frametime) * sv_air_accelerate) * friction);
out_velo += wish_dir * accelspd;
}
friction = 1.0f;
if (g_ctx->m_local_pawn->m_flags() & FL_ONGROUND)
{
if (out_velo.z <= 140.0 && out_velo.z > 0.0)
friction = 0.25f;
}
}
void c_movement::auto_strafe(bool subtick, vec3_t player_velo, float frame_time, float stimar, float friction) {
if (!g_interfaces->m_engine->is_connected() || !g_interfaces->m_engine->is_in_game())
return;
if (!g_ctx->m_local_pawn || !g_ctx->m_local_controller->m_pawn_is_alive())
return;
if (g_ctx->m_local_pawn->m_flags() & FL_ONGROUND)
return;
if (g_ctx->m_local_pawn->m_move_type() == 1794 || g_ctx->m_local_pawn->m_move_type() == 2313)
return;
if (!g_cfg->misc.m_auto_strafe)
return;
if (g_ctx->m_user_cmd->m_button_state.m_button_state & (1 << 16))
return;
auto movement_services = g_ctx->m_local_pawn->m_movement_services();
if (!movement_services)
return;
static uint64_t last_pressed = 0;
static uint64_t last_buttons = 0;
const auto current_buttons = g_ctx->m_user_cmd->m_button_state.m_button_state;
const auto check_button = [&](const uint64_t button) {
if (current_buttons & button && (!(last_buttons & button) ||
(button & IN_MOVELEFT && !(last_pressed & IN_MOVERIGHT)) ||
(button & IN_MOVERIGHT && !(last_pressed & IN_MOVELEFT)) ||
(button & IN_FORWARD && !(last_pressed & IN_BACK)) ||
(button & IN_BACK && !(last_pressed & IN_FORWARD)))) {
if (button & IN_MOVELEFT)
last_pressed &= ~IN_MOVERIGHT;
else if (button & IN_MOVERIGHT)
last_pressed &= ~IN_MOVELEFT;
else if (button & IN_FORWARD)
last_pressed &= ~IN_BACK;
else if (button & IN_BACK)
last_pressed &= ~IN_FORWARD;
last_pressed |= button;
}
else if (!(current_buttons & button))
last_pressed &= ~button;
};
check_button(IN_MOVELEFT);
check_button(IN_MOVERIGHT);
check_button(IN_FORWARD);
check_button(IN_BACK);
last_buttons = current_buttons;
float yaw = normalize(g_interfaces->m_csgo_input->get_view_angles().y);
auto offset = 0.f;
if (last_pressed & IN_MOVELEFT)
offset += 90.f;
if (last_pressed & IN_MOVERIGHT)
offset -= 90.f;
if (last_pressed & IN_FORWARD)
offset *= 0.5f;
else if (last_pressed & IN_BACK)
offset = -offset * 0.5f + 180.f;
yaw += offset;
const int32_t tick_interval = g_interfaces->m_global_vars->m_tick_count;
const float ov_frame_time = subtick ? tick_interval / 12.f : frame_time;
const int subtick_count = subtick ? 12 : 1;
vec3_t vel = g_ctx->m_local_pawn->m_vec_abs_velocity();
vec3_t move = movement_services->m_last_movement_impulses();
float fric = movement_services->m_surface_friction();
float stamina = movement_services->m_stamina();
auto rotate_movement = [](float target_yaw) {
const float rot = DEG2RAD * (g_interfaces->m_csgo_input->get_view_angles().y - target_yaw);
const float new_forward = std::cos(rot) * g_ctx->m_user_cmd->pb.mutable_base()->forwardmove() -
std::sin(rot) * g_ctx->m_user_cmd->pb.mutable_base()->leftmove();
const float new_side = std::sin(rot) * g_ctx->m_user_cmd->pb.mutable_base()->forwardmove() +
std::cos(rot) * g_ctx->m_user_cmd->pb.mutable_base()->leftmove();
g_ctx->m_user_cmd->m_button_state.m_button_state &= ~(IN_BACK | IN_FORWARD | IN_MOVELEFT | IN_MOVERIGHT);
g_ctx->m_user_cmd->m_button_state.m_button_state2 &= ~(IN_BACK | IN_FORWARD | IN_MOVELEFT | IN_MOVERIGHT);
g_ctx->m_user_cmd->pb.mutable_base()->set_forwardmove(std::clamp(new_forward, -1.f, 1.f));
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(std::clamp(new_side * -1.f, -1.f, 1.f));
if (g_ctx->m_user_cmd->pb.mutable_base()->forwardmove() > 0.0f)
g_ctx->m_user_cmd->m_button_state.m_button_state |= IN_FORWARD;
else if (g_ctx->m_user_cmd->pb.mutable_base()->forwardmove() < 0.0f)
g_ctx->m_user_cmd->m_button_state.m_button_state |= IN_BACK;
if (g_ctx->m_user_cmd->pb.mutable_base()->leftmove() > 0.0f)
g_ctx->m_user_cmd->m_button_state.m_button_state |= IN_MOVELEFT;
else if (g_ctx->m_user_cmd->pb.mutable_base()->leftmove() < 0.0f)
g_ctx->m_user_cmd->m_button_state.m_button_state |= IN_MOVERIGHT;
};
static bool side_switch = false;
for (int i = 0; i < subtick_count; i++) {
if (subtick) {
auto move_step = g_protobuf->add_subtick_move_step(g_ctx->m_user_cmd);
if (!move_step)
continue;
move_step->set_when((1.f / 12.f) * i);
}
auto velocity_angle = RAD2DEG * std::atan2f(vel.y, vel.x);
if (velocity_angle < 0.0f)
velocity_angle += 360.0f;
velocity_angle -= floorf(velocity_angle / 360.0f + 0.5f) * 360.0f;
const auto speed = vel.length_2d();
auto ideal = speed > 0.f ? std::clamp(RAD2DEG * std::atan2(15.f, speed), 0.0f, 45.0f) : 0.f;
auto correct = (100.f - g_cfg->misc.m_strafe_smooth) * 0.01f * ideal;
g_ctx->m_user_cmd->pb.mutable_base()->set_forwardmove(0.f);
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(0.f);
auto velocity_delta = normalize(yaw - velocity_angle);
if (fabsf(velocity_delta) > 90.f)
velocity_delta = std::copysignf(90.f, velocity_delta);
side_switch = subtick ? !side_switch : g_ctx->m_user_cmd->m_command_number % 2 == 0;
if (speed <= 80.f) {
if (side_switch) {
yaw = yaw - ideal * 0.5f;
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(-1.0f);
}
else {
yaw = yaw + ideal * 0.5f;
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(1.0f);
}
}
else if (velocity_delta > correct) {
yaw = velocity_angle + correct;
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(-1.0f);
}
else if (velocity_delta < -correct) {
yaw = velocity_angle - correct;
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(1.0f);
}
else {
if (side_switch) {
yaw = yaw - ideal;
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(-1.0f);
}
else {
yaw = yaw + ideal;
g_ctx->m_user_cmd->pb.mutable_base()->set_leftmove(1.0f);
}
}
float prev_forward = g_ctx->m_user_cmd->pb.mutable_base()->forwardmove();
float prev_left = g_ctx->m_user_cmd->pb.mutable_base()->leftmove();
rotate_movement(normalize(yaw));
move.x = g_ctx->m_user_cmd->pb.mutable_base()->forwardmove();
move.y = g_ctx->m_user_cmd->pb.mutable_base()->leftmove();
accelerate(vel, stamina, fric, move, ov_frame_time);
if (subtick) {
auto move_step = g_protobuf->add_subtick_move_step(g_ctx->m_user_cmd);
if (move_step) {
move_step->set_analog_forward_delta(move.x - prev_forward);
move_step->set_analog_left_delta(move.y - prev_left);
}
}
}
}