+void CL_ClientMovement_Physics_CPM_PM_Aircontrol(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
+{
+ vec_t zspeed, speed, dot, k;
+
+ if(s->cmd.forwardmove == 0 || s->cmd.sidemove != 0)
+ return;
+
+ zspeed = s->velocity[2];
+ s->velocity[2] = 0;
+ speed = VectorNormalizeLength(s->velocity);
+
+ dot = DotProduct(s->velocity, wishdir);
+ k = 32;
+ k *= cl.movevars_aircontrol*dot*dot*s->cmd.frametime;
+
+ if(dot > 0) { // we can't change direction while slowing down
+ VectorMAM(speed, s->velocity, k, wishdir, s->velocity);
+ VectorNormalize(s->velocity);
+ }
+
+ VectorScale(s->velocity, speed, s->velocity);
+ s->velocity[2] = zspeed;
+}
+
+void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed, vec_t wishspeed0, vec_t accel, vec_t accelqw, vec_t sidefric)
+{
+ vec_t vel_straight, vel_z;
+ vec3_t vel_perpend;
+ vec_t addspeed;
+ vec_t savespeed;
+
+ if(cl.moveflags & MOVEFLAG_Q2AIRACCELERATE)
+ wishspeed0 = wishspeed; // don't need to emulate this Q1 bug
+
+ savespeed = VectorLength2(s->velocity);
+
+ vel_straight = DotProduct(s->velocity, wishdir);
+ vel_z = s->velocity[2];
+ VectorMA(s->velocity, -vel_straight, wishdir, vel_perpend); vel_perpend[2] -= vel_z;
+
+ addspeed = wishspeed - vel_straight;
+ if(addspeed > 0)
+ vel_straight = vel_straight + min(addspeed, accel * s->cmd.frametime * wishspeed0) * accelqw;
+ if(wishspeed > 0)
+ vel_straight = vel_straight + min(wishspeed, accel * s->cmd.frametime * wishspeed0) * (1 - accelqw);
+
+ if(sidefric < 0 && VectorLength2(vel_perpend))
+ {
+ vec_t f, fmin;
+ f = 1 + s->cmd.frametime * wishspeed * sidefric;
+ fmin = (savespeed - vel_straight*vel_straight) / VectorLength2(vel_perpend);
+ if(fmin <= 0)
+ VectorScale(vel_perpend, f, vel_perpend);
+ else
+ VectorScale(vel_perpend, min(1.0f, max(fmin, f)), vel_perpend);
+ }
+ else
+ VectorScale(vel_perpend, 1 - s->cmd.frametime * wishspeed * sidefric, vel_perpend);
+
+ VectorMA(vel_perpend, vel_straight, wishdir, s->velocity);
+ s->velocity[2] += vel_z;
+}
+
+void CL_ClientMovement_Physics_PM_AirAccelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed)
+{
+ vec3_t curvel, wishvel, acceldir, curdir;
+ float addspeed, accelspeed, curspeed;
+ float dot;
+
+ float airforwardaccel = cl.movevars_warsowbunny_airforwardaccel;
+ float bunnyaccel = cl.movevars_warsowbunny_accel;
+ float bunnytopspeed = cl.movevars_warsowbunny_topspeed;
+ float turnaccel = cl.movevars_warsowbunny_turnaccel;
+ float backtosideratio = cl.movevars_warsowbunny_backtosideratio;
+
+ if( !wishspeed )
+ return;
+
+ VectorCopy( s->velocity, curvel );
+ curvel[2] = 0;
+ curspeed = VectorLength( curvel );
+
+ if( wishspeed > curspeed * 1.01f )
+ {
+ float accelspeed = curspeed + airforwardaccel * cl.movevars_maxairspeed * s->cmd.frametime;
+ if( accelspeed < wishspeed )
+ wishspeed = accelspeed;
+ }
+ else
+ {
+ float f = ( bunnytopspeed - curspeed ) / ( bunnytopspeed - cl.movevars_maxairspeed );
+ if( f < 0 )
+ f = 0;
+ wishspeed = max( curspeed, cl.movevars_maxairspeed ) + bunnyaccel * f * cl.movevars_maxairspeed * s->cmd.frametime;
+ }
+ VectorScale( wishdir, wishspeed, wishvel );
+ VectorSubtract( wishvel, curvel, acceldir );
+ addspeed = VectorNormalizeLength( acceldir );
+
+ accelspeed = turnaccel * cl.movevars_maxairspeed /* wishspeed */ * s->cmd.frametime;
+ if( accelspeed > addspeed )
+ accelspeed = addspeed;
+
+ if( backtosideratio < 1.0f )
+ {
+ VectorNormalize2( curvel, curdir );
+ dot = DotProduct( acceldir, curdir );
+ if( dot < 0 )
+ VectorMA( acceldir, -( 1.0f - backtosideratio ) * dot, curdir, acceldir );
+ }
+
+ VectorMA( s->velocity, accelspeed, acceldir, s->velocity );
+}
+