s->velocity[2] = zspeed;
}
+void CL_ClientMovement_Physics_PM_Accelerate(cl_clientmovement_state_t *s, vec3_t wishdir, vec_t wishspeed, vec_t accel, vec_t accelqw, vec_t sidefric)
+{
+ vec_t vel_straight, vel_z;
+ vec3_t vel_perpend;
+ vec_t addspeed;
+
+ 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 * wishspeed) * accelqw;
+ if(wishspeed > 0)
+ vel_straight = vel_straight + min(wishspeed, accel * s->cmd.frametime * wishspeed) * (1 - accelqw);
+
+ 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 );
+}
+
void CL_ClientMovement_Physics_Walk(cl_clientmovement_state_t *s)
{
vec_t friction;
{
if (s->waterjumptime <= 0)
{
- vec_t f;
- vec_t vel_straight;
- vec_t vel_z;
- vec3_t vel_perpend;
- float wishspeed2, accel;
-
// apply air speed limit
+ vec_t accel, wishspeed2;
wishspeed = min(wishspeed, cl.movevars_maxairspeed);
if (s->crouched)
wishspeed *= 0.5;
-
accel = cl.movevars_airaccelerate;
-
- // CPM: air control
wishspeed2 = wishspeed;
- if(cl.movevars_airstopaccelerate != 0)
- if(DotProduct(s->velocity, wishdir) < 0)
- accel = cl.movevars_airstopaccelerate;
- if(s->cmd.forwardmove == 0 && s->cmd.sidemove != 0)
- {
- if(cl.movevars_maxairstrafespeed)
- if(wishspeed > cl.movevars_maxairstrafespeed)
- wishspeed = cl.movevars_maxairstrafespeed;
- if(cl.movevars_airstrafeaccelerate)
- accel = cl.movevars_airstrafeaccelerate;
- }
- // !CPM
- /*
- addspeed = wishspeed - DotProduct(s->velocity, wishdir);
- if (addspeed > 0)
+ if(cl.movevars_warsowbunny_turnaccel)
{
- accelspeed = min(cl.movevars_accelerate * s->q.frametime * wishspeed, addspeed);
- VectorMA(s->velocity, accelspeed, wishdir, s->velocity);
- }
- */
+ qboolean accelerating, decelerating, aircontrol;
+ accelerating = (DotProduct(s->velocity, wishdir) > 0);
+ decelerating = (DotProduct(s->velocity, wishdir) < 0);
+ aircontrol = false;
- vel_straight = DotProduct(s->velocity, wishdir);
- vel_z = s->velocity[2];
- VectorMA(s->velocity, -vel_straight, wishdir, vel_perpend);
- vel_perpend[2] -= vel_z;
-
- f = wishspeed - vel_straight;
- if(f > 0)
- vel_straight += min(f, accel * s->cmd.frametime * wishspeed) * cl.movevars_airaccel_qw;
- if(wishspeed > 0)
- vel_straight += min(wishspeed, accel * s->cmd.frametime * wishspeed) * (1 - cl.movevars_airaccel_qw);
-
- VectorM(1 - (s->cmd.frametime * (wishspeed / cl.movevars_maxairspeed) * cl.movevars_airaccel_sideways_friction), vel_perpend, vel_perpend);
-
- VectorMA(vel_perpend, vel_straight, wishdir, s->velocity);
- s->velocity[2] += vel_z;
+ if(accelerating && s->cmd.sidemove == 0 && s->cmd.forwardmove != 0)
+ {
+ CL_ClientMovement_Physics_PM_AirAccelerate(s, wishdir, wishspeed2);
+ }
+ else
+ {
+ // CPM: air control
+ if(cl.movevars_airstopaccelerate != 0)
+ if(DotProduct(s->velocity, wishdir) < 0)
+ accel = cl.movevars_airstopaccelerate;
+ if(s->cmd.forwardmove == 0 && s->cmd.sidemove != 0)
+ {
+ if(cl.movevars_maxairstrafespeed)
+ if(wishspeed > cl.movevars_maxairstrafespeed)
+ wishspeed = cl.movevars_maxairstrafespeed;
+ if(cl.movevars_airstrafeaccelerate)
+ accel = cl.movevars_airstrafeaccelerate;
+ if(cl.movevars_aircontrol)
+ aircontrol = true;
+ }
+ // !CPM
+
+ CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, accel, cl.movevars_airaccel_qw, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed);
+ if(aircontrol)
+ CL_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2);
+ }
+ }
+ else
+ {
+ // CPM: air control
+ if(cl.movevars_airstopaccelerate != 0)
+ if(DotProduct(s->velocity, wishdir) < 0)
+ accel = cl.movevars_airstopaccelerate;
+ if(s->cmd.forwardmove == 0 && s->cmd.sidemove != 0)
+ {
+ if(cl.movevars_maxairstrafespeed)
+ if(wishspeed > cl.movevars_maxairstrafespeed)
+ wishspeed = cl.movevars_maxairstrafespeed;
+ if(cl.movevars_airstrafeaccelerate)
+ accel = cl.movevars_airstrafeaccelerate;
+ }
+ // !CPM
- if(cl.movevars_aircontrol)
- CL_ClientMovement_Physics_CPM_PM_Aircontrol(s, wishdir, wishspeed2);
+ CL_ClientMovement_Physics_PM_Accelerate(s, wishdir, wishspeed, accel, cl.movevars_airaccel_qw, cl.movevars_airaccel_sideways_friction / cl.movevars_maxairspeed);
+ 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;
CL_ClientMovement_Move(s);
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_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];
+ cl.movevars_warsowbunny_turnaccel = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL];
+ cl.movevars_warsowbunny_backtosideratio = cl.statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO];
}
else
{
cl.movevars_airstrafeaccelerate = 0;
cl.movevars_maxairstrafespeed = 0;
cl.movevars_aircontrol = 0;
+ cl.movevars_warsowbunny_airforwardaccel = 0;
+ cl.movevars_warsowbunny_accel = 0;
+ cl.movevars_warsowbunny_topspeed = 0;
+ cl.movevars_warsowbunny_turnaccel = 0;
+ cl.movevars_warsowbunny_backtosideratio = 0;
}
}
cvar_t sv_wallfriction = {CVAR_NOTIFY, "sv_wallfriction", "1", "how much you slow down when sliding along a wall"};
cvar_t sv_wateraccelerate = {0, "sv_wateraccelerate", "-1", "rate at which a player accelerates to sv_maxspeed while in the air, if less than 0 the sv_accelerate variable is used instead"};
cvar_t sv_waterfriction = {CVAR_NOTIFY, "sv_waterfriction","-1", "how fast you slow down, if less than 0 the sv_friction variable is used instead"};
+cvar_t sv_warsowbunny_airforwardaccel = {0, "sv_warsowbunny_airforwardaccel", "1.00001", "how fast you accelerate until you reach sv_maxspeed"};
+cvar_t sv_warsowbunny_accel = {0, "sv_warsowbunny_accel", "0.1585", "how fast you accelerate until after reaching sv_maxspeed (it gets harder as you near sv_warsowbunny_topspeed)"};
+cvar_t sv_warsowbunny_topspeed = {0, "sv_warsowbunny_topspeed", "925", "soft speed limit (can get faster with rjs and on ramps)"};
+cvar_t sv_warsowbunny_turnaccel = {0, "sv_warsowbunny_turnaccel", "9", "max sharpness of turns (also master switch for the sv_warsowbunny_* mode)"};
+cvar_t sv_warsowbunny_backtosideratio = {0, "sv_warsowbunny_backtosideratio", "0.8", "lower values make it easier to change direction without losing speed; the drawback is \"understeering\" in sharp turns"};
cvar_t sys_ticrate = {CVAR_SAVE, "sys_ticrate","0.0138889", "how long a server frame is in seconds, 0.05 is 20fps server rate, 0.1 is 10fps (can not be set higher than 0.1), 0 runs as many server frames as possible (makes games against bots a little smoother, overwhelms network players), 0.0138889 matches QuakeWorld physics"};
cvar_t teamplay = {CVAR_NOTIFY, "teamplay","0", "teamplay mode, values depend on mod but typically 0 = no teams, 1 = no team damage no self damage, 2 = team damage and self damage, some mods support 3 = no team damage but can damage self"};
cvar_t timelimit = {CVAR_NOTIFY, "timelimit","0", "ends level at this time (in minutes)"};
Cvar_RegisterVariable (&sv_wallfriction);
Cvar_RegisterVariable (&sv_wateraccelerate);
Cvar_RegisterVariable (&sv_waterfriction);
+ Cvar_RegisterVariable (&sv_warsowbunny_airforwardaccel);
+ Cvar_RegisterVariable (&sv_warsowbunny_accel);
+ Cvar_RegisterVariable (&sv_warsowbunny_topspeed);
+ Cvar_RegisterVariable (&sv_warsowbunny_turnaccel);
+ Cvar_RegisterVariable (&sv_warsowbunny_backtosideratio);
Cvar_RegisterVariable (&sys_ticrate);
Cvar_RegisterVariable (&teamplay);
Cvar_RegisterVariable (&timelimit);
statsf[STAT_MOVEVARS_AIRSTRAFEACCELERATE] = sv_airstrafeaccelerate.value;
statsf[STAT_MOVEVARS_MAXAIRSTRAFESPEED] = sv_maxairstrafespeed.value;
statsf[STAT_MOVEVARS_AIRCONTROL] = sv_aircontrol.value;
+ statsf[STAT_MOVEVARS_WARSOWBUNNY_AIRFORWARDACCEL] = sv_warsowbunny_airforwardaccel.value;
+ statsf[STAT_MOVEVARS_WARSOWBUNNY_ACCEL] = sv_warsowbunny_accel.value;
+ statsf[STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED] = sv_warsowbunny_topspeed.value;
+ statsf[STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL] = sv_warsowbunny_turnaccel.value;
+ statsf[STAT_MOVEVARS_WARSOWBUNNY_BACKTOSIDERATIO] = sv_warsowbunny_backtosideratio.value;
statsf[STAT_FRAGLIMIT] = fraglimit.value;
statsf[STAT_TIMELIMIT] = timelimit.value;