vector gunorg = '0 0 0';
static float bobmodel_scale = 0;
static float time_ofs = 0; // makes the effect always restart in the same way
+ static float avg_xyspeed = 0; // makes the effect always restart in the same way
if (clonground)
{
if (time - hitgroundtime > 0.05)
else
bobmodel_scale = max(0, bobmodel_scale - frametime * 5);
- float xyspeed = bound(0, vlen(vec2(view.velocity)), 400);
- if (bobmodel_scale && xyspeed)
- {
- float bspeed = xyspeed * 0.01 * bobmodel_scale;
- float s = (time - time_ofs) * autocvar_cl_bobmodel_speed;
- gunorg.y = bspeed * autocvar_cl_bobmodel_side * sin(s);
- gunorg.z = bspeed * autocvar_cl_bobmodel_up * cos(s * 2);
+ if (bobmodel_scale)
+ {
+ float xyspeed = bound(0, vlen(vec2(view.velocity)), 400);
+ // smooth speed changes to get rid of weapon stuttering on direction changes
+ const float avg_time = 0.1;
+ float frac = 1 - exp(-frametime / max(0.001, avg_time));
+ avg_xyspeed = frac * xyspeed + (1 - frac) * avg_xyspeed;
+ // stop bobbing at a very low value of avg_xyspeed instead of 0
+ // since the averaging formula takes a very long time to reach exactly 0
+ if (avg_xyspeed < 1)
+ time_ofs = time;
+ else
+ {
+ if (avg_xyspeed < 400) // reduce bob frequency too when player walks crouching
+ time_ofs += frametime * map_bound_ranges(avg_xyspeed, 150, 400, 0.08, 0);
+
+ float bspeed = avg_xyspeed * 0.01 * bobmodel_scale;
+ float s = (time - time_ofs) * autocvar_cl_bobmodel_speed;
+ gunorg.y = bspeed * autocvar_cl_bobmodel_side * sin(s);
+ gunorg.z = bspeed * autocvar_cl_bobmodel_up * cos(s * 2);
+ }
}
else
time_ofs = time;