]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/cl_physics.qc
always perform the trace before speedcap, independent of sv_doublejump :-P (untested...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / cl_physics.qc
index 4c2280099dc2f0b08e5e86de9466c898c733913b..d3425451c15c94419b1b16fd3c3821e9c441e97d 100644 (file)
@@ -13,7 +13,9 @@ float sv_airaccel_qw;
 float sv_airstopaccelerate;
 float sv_airstrafeaccelerate;
 float sv_maxairstrafespeed;
+float sv_airstrafeaccel_qw;
 float sv_aircontrol;
+float sv_aircontrol_power;
 float sv_warsowbunny_airforwardaccel;
 float sv_warsowbunny_accel;
 float sv_warsowbunny_topspeed;
@@ -86,6 +88,7 @@ void PlayerJump (void)
        if(cvar_string("sv_jumpspeedcap_min") != "")
                self.velocity_z = max(cvar("sv_jumpvelocity") * cvar("sv_jumpspeedcap_min"), self.velocity_z);
        if(cvar_string("sv_jumpspeedcap_max") != "") {
+               tracebox(self.origin + '0 0 0.01', self.mins, self.maxs, self.origin - '0 0 0.01', MOVE_NORMAL, self);
                if(trace_fraction < 1 && trace_plane_normal_z < 0.98 && cvar("sv_jumpspeedcap_max_disable_on_ramps")) {
                        // don't do jump speedcaps on ramps to preserve old xonotic ramjump style
                        //print("Trace plane normal z: ", ftos(trace_plane_normal_z), ", disabling speed cap!\n");
@@ -385,7 +388,7 @@ float IsMoveInDirection(vector mv, float angle) // key mix factor
 {
        if(mv_x == 0 && mv_y == 0)
                return 0; // avoid division by zero
-       angle = RAD2DEG * atan2(mv_y, mv_x);
+       angle -= RAD2DEG * atan2(mv_y, mv_x);
        angle = remainder(angle, 360) / 45;
        if(angle >  1)
                return 0;
@@ -394,6 +397,25 @@ float IsMoveInDirection(vector mv, float angle) // key mix factor
        return 1 - fabs(angle);
 }
 
+float GeomLerp(float a, float lerp, float b)
+{
+       if(a == 0)
+       {
+               if(lerp < 1)
+                       return 0;
+               else
+                       return b;
+       }
+       if(b == 0)
+       {
+               if(lerp > 0)
+                       return 0;
+               else
+                       return a;
+       }
+       return a * pow(fabs(b / a), lerp);
+}
+
 void CPM_PM_Aircontrol(vector wishdir, float wishspeed)
 {
        float zspeed, xyspeed, dot, k;
@@ -416,10 +438,10 @@ void CPM_PM_Aircontrol(vector wishdir, float wishspeed)
        xyspeed = vlen(self.velocity); self.velocity = normalize(self.velocity);
 
        dot = self.velocity * wishdir;
-       k *= sv_aircontrol*dot*dot*frametime;
 
        if(dot > 0) // we can't change direction while slowing down
        {
+               k *= fabs(sv_aircontrol)*pow(dot, sv_aircontrol_power)*frametime;
                self.velocity = normalize(self.velocity * xyspeed + wishdir * k);
        }
 
@@ -584,6 +606,7 @@ string GetMapname(void);
 float speedaward_lastupdate;
 float speedaward_lastsent;
 .float jumppadusetime;
+var float autocvar_g_movement_highspeed = 1;
 void SV_PlayerPhysics()
 {
        local vector wishvel, wishdir, v;
@@ -593,6 +616,13 @@ void SV_PlayerPhysics()
        float not_allowed_to_move;
        string c;
 
+       // fix physics stats for g_movement_highspeed
+       self.stat_sv_airaccel_qw = copysign(bound(0, 1-(1-fabs(sv_airaccel_qw))*autocvar_g_movement_highspeed, 1), sv_airaccel_qw);
+       if(sv_airstrafeaccel_qw)
+               self.stat_sv_airstrafeaccel_qw = copysign(bound(0.001, 1-(1-fabs(sv_airstrafeaccel_qw))*autocvar_g_movement_highspeed, 1), sv_airstrafeaccel_qw);
+       else
+               self.stat_sv_airstrafeaccel_qw = 0;
+
     if(self.PlayerPhysplug)
         if(self.PlayerPhysplug())
             return;
@@ -688,6 +718,8 @@ void SV_PlayerPhysics()
                bot_think();
        }
        
+       MUTATOR_CALLHOOK(PlayerPhysics);
+
        self.items &~= IT_USING_JETPACK;
 
        if(self.classname == "player")
@@ -1135,8 +1167,9 @@ void SV_PlayerPhysics()
                        float accelerating;
                        float wishspeed2;
                        float airaccelqw;
+                       float strafity;
 
-                       airaccelqw = sv_airaccel_qw;
+                       airaccelqw = self.stat_sv_airaccel_qw;
                        accelerating = (self.velocity * wishdir > 0);
                        wishspeed2 = wishspeed;
 
@@ -1144,24 +1177,21 @@ void SV_PlayerPhysics()
                        if(sv_airstopaccelerate)
                                if(self.velocity * wishdir < 0)
                                        airaccel = sv_airstopaccelerate*maxspd_mod;
-                       // this doesn't play well with analog input, but can't r
-                       // fixed like the AirControl can. So, don't set the maxa
-                       // cvars when you want to support analog input.
-                       if(self.movement_x == 0 && self.movement_y != 0)
-                       {
-                               if(sv_maxairstrafespeed)
-                               {
-                                       wishspeed = min(wishspeed, sv_maxairstrafespeed*maxspd_mod);
-                                       if(sv_maxairstrafespeed < sv_maxairspeed)
-                                               airaccelqw = 1;
-                               }
-                               if(sv_airstrafeaccelerate)
-                               {
-                                       airaccel = sv_airstrafeaccelerate*maxspd_mod;
-                                       if(sv_airstrafeaccelerate > sv_airaccelerate)
-                                               airaccelqw = 1;
-                               }
-                       }
+                       // note that for straight forward jumping:
+                       // step = accel * frametime * wishspeed0;
+                       // accel  = bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
+                       // -->
+                       // dv/dt = accel * maxspeed (when slow)
+                       // dv/dt = accel * maxspeed * (1 - accelqw) (when fast)
+                       // log dv/dt = logaccel + logmaxspeed (when slow)
+                       // log dv/dt = logaccel + logmaxspeed + log(1 - accelqw) (when fast)
+                       strafity = IsMoveInDirection(self.movement, -90) + IsMoveInDirection(self.movement, +90); // if one is nonzero, other is always zero
+                       if(sv_maxairstrafespeed)
+                               wishspeed = min(wishspeed, GeomLerp(sv_maxairspeed*maxspd_mod, strafity, sv_maxairstrafespeed*maxspd_mod));
+                       if(sv_airstrafeaccelerate)
+                               airaccel = GeomLerp(airaccel, strafity, sv_airstrafeaccelerate*maxspd_mod);
+                       if(self.stat_sv_airstrafeaccel_qw)
+                               airaccelqw = copysign(1-GeomLerp(1-fabs(self.stat_sv_airaccel_qw), strafity, 1-fabs(self.stat_sv_airstrafeaccel_qw)), ((strafity > 0.5) ? self.stat_sv_airstrafeaccel_qw : self.stat_sv_airaccel_qw));
                        // !CPM
 
                        if(sv_warsowbunny_turnaccel && accelerating && self.movement_y == 0 && self.movement_x != 0)