]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - cl_input.c
sv_aircontrol_power - customizing the response curve of CPMA style air control
[xonotic/darkplaces.git] / cl_input.c
index 28339a431a3eaed4268e52093d8838196112e35e..aacdfcc5febea6a8eb01f96a559db26a80b603e3 100644 (file)
@@ -450,7 +450,7 @@ cvar_t m_accelerate_minspeed = {CVAR_SAVE, "m_accelerate_minspeed","5000", "belo
 cvar_t m_accelerate_maxspeed = {CVAR_SAVE, "m_accelerate_maxspeed","10000", "above this speed, full acceleration is done"};
 cvar_t m_accelerate_filter = {CVAR_SAVE, "m_accelerate_filter","0.1", "mouse acceleration factor filtering"};
 
-cvar_t cl_netfps = {CVAR_SAVE, "cl_netfps","20", "how many input packets to send to server each second"};
+cvar_t cl_netfps = {CVAR_SAVE, "cl_netfps","72", "how many input packets to send to server each second"};
 cvar_t cl_netrepeatinput = {CVAR_SAVE, "cl_netrepeatinput", "1", "how many packets in a row can be lost without movement issues when using cl_movement (technically how many input messages to repeat in each packet that have not yet been acknowledged by the server), only affects DP7 and later servers (Quake uses 0, QuakeWorld uses 2, and just for comparison Quake3 uses 1)"};
 cvar_t cl_netimmediatebuttons = {CVAR_SAVE, "cl_netimmediatebuttons", "1", "sends extra packets whenever your buttons change or an impulse is used (basically: whenever you click fire or change weapon)"};
 
@@ -625,7 +625,7 @@ void CL_Input (void)
        if (!key_consoleactive && key_dest == key_game && !cl.csqc_wantsmousemove)
        {
                float modulatedsensitivity = sensitivity.value * cl.sensitivityscale;
-               if (cl_prydoncursor.integer)
+               if (cl_prydoncursor.integer > 0)
                {
                        // mouse interacting with the scene, mostly stationary view
                        V_StopPitchDrift();
@@ -743,7 +743,7 @@ void CL_UpdatePrydonCursor(void)
 {
        vec3_t temp;
 
-       if (!cl_prydoncursor.integer)
+       if (cl_prydoncursor.integer <= 0)
                VectorClear(cl.cmd.cursor_screen);
 
        /*
@@ -778,7 +778,15 @@ void CL_UpdatePrydonCursor(void)
        VectorSet(temp, cl.cmd.cursor_screen[2] * 1000000, (v_flipped.integer ? -1 : 1) * cl.cmd.cursor_screen[0] * -r_refdef.view.frustum_x * 1000000, cl.cmd.cursor_screen[1] * -r_refdef.view.frustum_y * 1000000);
        Matrix4x4_Transform(&r_refdef.view.matrix, temp, cl.cmd.cursor_end);
        // trace from view origin to the cursor
-       cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl.entities[cl.playerentity].render : NULL);
+       if (cl_prydoncursor_notrace.integer)
+       {
+               cl.cmd.cursor_fraction = 1.0f;
+               VectorCopy(cl.cmd.cursor_end, cl.cmd.cursor_impact);
+               VectorClear(cl.cmd.cursor_normal);
+               cl.cmd.cursor_entitynumber = 0;
+       }
+       else
+               cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl.entities[cl.playerentity].render : NULL);
 }
 
 typedef enum waterlevel_e
@@ -1078,22 +1086,44 @@ void CL_ClientMovement_Physics_Swim(cl_clientmovement_state_t *s)
        CL_ClientMovement_Move(s);
 }
 
+static vec_t CL_IsMoveInDirection(vec_t forward, vec_t side, vec_t angle)
+{
+       if(forward == 0 && side == 0)
+               return 0; // avoid division by zero
+       angle -= RAD2DEG(atan2(side, forward));
+       angle = (ANGLEMOD(angle + 180) - 180) / 45;
+       if(angle >  1)
+               return 0;
+       if(angle < -1)
+               return 0;
+       return 1 - fabs(angle);
+}
+
 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 0
+       // this doesn't play well with analog input
        if(s->cmd.forwardmove == 0 || s->cmd.sidemove != 0)
                return;
-       
+       k = 32;
+#else
+       k = 32 * (2 * CL_IsMoveInDirection(s->cmd.forwardmove, s->cmd.sidemove, 0) - 1);
+       if(k <= 0)
+               return;
+#endif
+
+       k *= bound(0, wishspeed / cl.movevars_maxairspeed, 1);
+
        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
+               k *= cl.movevars_aircontrol*pow(dot, cl.movevars_aircontrol_power)*s->cmd.frametime;
                VectorMAM(speed, s->velocity, k, wishdir, s->velocity);
                VectorNormalize(s->velocity);
        }
@@ -1130,6 +1160,8 @@ void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_
        vel_xy_current  = VectorLength(vel_xy);
        vel_xy_forward  = vel_xy_current + bound(0, wishspeed - vel_xy_current, step) * accelqw + step * (1 - accelqw);
        vel_xy_backward = vel_xy_current - bound(0, wishspeed + vel_xy_current, step) * accelqw - step * (1 - accelqw);
+       if(vel_xy_backward < 0)
+               vel_xy_backward = 0; // not that it REALLY occurs that this would cause wrong behaviour afterwards
 
        vel_straight    = vel_straight   + bound(0, wishspeed - vel_straight,   step) * accelqw + step * (1 - accelqw);
 
@@ -1137,15 +1169,23 @@ void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_
                // negative: only apply so much sideways friction to stay below the speed you could get by "braking"
        {
                vec_t f, fmin;
-               f = 1 - s->cmd.frametime * wishspeed * sidefric;
+               f = max(0, 1 + s->cmd.frametime * wishspeed * sidefric);
                fmin = (vel_xy_backward*vel_xy_backward - vel_straight*vel_straight) / VectorLength2(vel_perpend);
+               // assume: fmin > 1
+               // vel_xy_backward*vel_xy_backward - vel_straight*vel_straight > vel_perpend*vel_perpend
+               // vel_xy_backward*vel_xy_backward > vel_straight*vel_straight + vel_perpend*vel_perpend
+               // vel_xy_backward*vel_xy_backward > vel_xy * vel_xy
+               // obviously, this cannot be
                if(fmin <= 0)
                        VectorScale(vel_perpend, f, vel_perpend);
                else
-                       VectorScale(vel_perpend, min(1.0f, max(fmin, f)), vel_perpend);
+               {
+                       fmin = sqrt(fmin);
+                       VectorScale(vel_perpend, max(fmin, f), vel_perpend);
+               }
        }
        else
-               VectorScale(vel_perpend, 1 - s->cmd.frametime * wishspeed * sidefric, vel_perpend);
+               VectorScale(vel_perpend, max(0, 1 - s->cmd.frametime * wishspeed * sidefric), vel_perpend);
 
        VectorMA(vel_perpend, vel_straight, wishdir, s->velocity);
 
@@ -1220,6 +1260,7 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
        vec_t addspeed;
        vec_t accelspeed;
        vec_t f;
+       vec_t gravity;
        vec3_t forward;
        vec3_t right;
        vec3_t up;
@@ -1292,11 +1333,20 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
                        accelspeed = min(cl.movevars_accelerate * s->cmd.frametime * wishspeed, addspeed);
                        VectorMA(s->velocity, accelspeed, wishdir, s->velocity);
                }
-               s->velocity[2] -= cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime;
+               if(cl.moveflags & MOVEFLAG_NOGRAVITYONGROUND)
+                       gravity = 0;
+               else
+                       gravity = cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime;
+               if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
+                       s->velocity[2] -= gravity * 0.5f;
+               else
+                       s->velocity[2] -= gravity;
                if (cls.protocol == PROTOCOL_QUAKEWORLD)
                        s->velocity[2] = 0;
                if (VectorLength2(s->velocity))
                        CL_ClientMovement_Move(s);
+               if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
+                       s->velocity[2] -= gravity * 0.5f;
        }
        else
        {
@@ -1320,6 +1370,9 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
                        if(cl.movevars_airstopaccelerate != 0)
                                if(DotProduct(s->velocity, wishdir) < 0)
                                        accel = cl.movevars_airstopaccelerate;
+                       // this doesn't play well with analog input, but can't really be
+                       // fixed like the AirControl can. So, don't set the maxairstrafe*
+                       // cvars when you want to support analog input.
                        if(s->cmd.forwardmove == 0 && s->cmd.sidemove != 0)
                        {
                                if(cl.movevars_maxairstrafespeed)
@@ -1352,8 +1405,14 @@ void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
                        if(cl.movevars_aircontrol)
                                CL_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2);
                }
-               s->velocity[2] -= cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime;
+               gravity = cl.movevars_gravity * cl.movevars_entgravity * s->cmd.frametime;
+               if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
+                       s->velocity[2] -= gravity * 0.5f;
+               else
+                       s->velocity[2] -= gravity;
                CL_ClientMovement_Move(s);
+               if(cl.moveflags & MOVEFLAG_GRAVITYUNAFFECTEDBYTICRATE)
+                       s->velocity[2] -= gravity * 0.5f;
        }
 }
 
@@ -1403,6 +1462,7 @@ void CL_UpdateMoveVars(void)
                cl.movevars_airstrafeaccelerate = cl.statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE];
                cl.movevars_maxairstrafespeed = cl.statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED];
                cl.movevars_aircontrol = cl.statsf[STAT_MOVEVARS_AIRCONTROL];
+               cl.movevars_aircontrol_power = cl.statsf[STAT_MOVEVARS_AIRCONTROL_POWER];
                cl.movevars_warsowbunny_airforwardaccel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL];
                cl.movevars_warsowbunny_accel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL];
                cl.movevars_warsowbunny_topspeed = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED];
@@ -1435,6 +1495,7 @@ void CL_UpdateMoveVars(void)
                cl.movevars_airstrafeaccelerate = 0;
                cl.movevars_maxairstrafespeed = 0;
                cl.movevars_aircontrol = 0;
+               cl.movevars_aircontrol_power = 2;
                cl.movevars_warsowbunny_airforwardaccel = 0;
                cl.movevars_warsowbunny_accel = 0;
                cl.movevars_warsowbunny_topspeed = 0;
@@ -1447,6 +1508,9 @@ void CL_UpdateMoveVars(void)
                if(gamemode == GAME_NEXUIZ)
                        cl.moveflags = MOVEFLAG_Q2AIRACCELERATE;
        }
+
+       if(cl.movevars_aircontrol_power <= 0)
+               cl.movevars_aircontrol = 2; // CPMA default
 }
 
 void CL_ClientMovement_Replay(void)
@@ -1648,7 +1712,7 @@ void CL_SendMove(void)
        if (in_button8.state  & 3) bits |= 128;
        if (in_use.state      & 3) bits |= 256;
        if (key_dest != key_game || key_consoleactive) bits |= 512;
-       if (cl_prydoncursor.integer) bits |= 1024;
+       if (cl_prydoncursor.integer > 0) bits |= 1024;
        if (in_button9.state  & 3)  bits |=   2048;
        if (in_button10.state  & 3) bits |=   4096;
        if (in_button11.state  & 3) bits |=   8192;