How to fix sliding/surfing from slope surface in Quake

2023-07-13 QuakeC tutorials kleskby 0 222
Author: kleskby


As you could notice while playing quake, if you stand on a slope you slowly move down the slope. This is very annoying player physics bug in Quake 1.

 

Solution 1.
Open client.qc, at the bottom of PlayerPreThink add the following code:



 if(self.movetype != MOVETYPE_NOCLIP && clienttype(self) != CLIENTTYPE_BOT) //SLIDING (SURFING) FIX
 {
 if(self.flags & FL_ONGROUND && vlen(self.velocity) < 30)
 {
 traceline (self.origin, self.origin - '0 0 42', TRUE, self); //detecting slope angle
 if(trace_fraction > 0.65) self.movetype = MOVETYPE_BOUNCE;
 else self.movetype = MOVETYPE_WALK;
 }
 else self.movetype = MOVETYPE_WALK;
 }

The function checks if the player is not in noclip mode and is not a bot, then it checks if the player is on the ground (FL_ONGROUND flag is set) and has a velocity less than 30. If both conditions are met, the code checks the angle of the ground the player is standing on by performing a traceline from the player's current position to a point just below them. The TRUE parameter indicates that the trace should stop when it hits a solid surface.
If the trace_fraction (which is the fraction of the trace line that was traveled before hitting a solid surface) is greater than 0.65, the player's movement type is set to MOVETYPE_BOUNCE (can be other movetype). Otherwise, returning player movement type to a normal state.

 

Solution 2.
If you use modern source port such as DarkPlaces or FTEQW you can recode player movement function by defining SV_PlayerPhysics. Here is an example how to do this:
 



float lastclientthink;
float sv_accelerate;
float sv_maxairspeed;
float sv_friction;
float sv_maxspeed;
float sv_stopspeed;
float sv_gravity;
.float ladder_time;
.entity ladder_entity;
.float gravity;

void() SV_PlayerPhysics =
{
 local vector wishvel, wishdir, v;
 local float wishspeed, f;

 // this is the first function run each frame, so do bot think here
 if (clienttype(self) == CLIENTTYPE_BOT)

 if (self.movetype == MOVETYPE_NONE)
 return;

 if (time != lastclientthink)
 {
 lastclientthink = time;
 sv_maxairspeed = cvar("sv_maxairspeed");
 sv_maxspeed = cvar("sv_maxspeed");
 sv_friction = cvar("sv_friction");
 sv_accelerate = cvar("sv_accelerate");
 sv_stopspeed = cvar("sv_stopspeed");
 sv_gravity = cvar("sv_gravity");
 }

 if (self.punchangle != '0 0 0')
 {
 f = vlen(self.punchangle) - 10 * frametime;
 if (f > 0)
 self.punchangle = normalize(self.punchangle) * f;
 else
 self.punchangle = '0 0 0';
 }

 if (self.punchvector != '0 0 0')
 {
 f = vlen(self.punchvector) - 30 * frametime;
 if (f > 0)
 self.punchvector = normalize(self.punchvector) * f;
 else
 self.punchvector = '0 0 0';
 }

 // if dead, behave differently
 if (self.deadflag)
 return;

 if (!self.fixangle)
 {
 // show 1/3 the pitch angle and all the roll angle
 // LordHavoc: no real interest in porting V_CalcRoll
 //self.angles_z = V_CalcRoll (self.angles, self.velocity)*4;
 self.angles_x = 0;
 self.angles_y = self.v_angle_y + self.punchangle_y;
 self.angles_z = 0;
 }

 if (self.flags & FL_WATERJUMP )
 {
 self.velocity_x = self.movedir_x;
 self.velocity_y = self.movedir_y;
 if (time > self.teleport_time || self.waterlevel == 0)
 {
 self.flags = self.flags - (self.flags & FL_WATERJUMP);
 self.teleport_time = 0;
 }
 }
 else if (self.movetype == MOVETYPE_NOCLIP || self.movetype == MOVETYPE_FLY)
 {
 // noclipping or flying
 self.velocity = self.velocity * (1 - frametime * sv_friction);
 makevectors(self.v_angle);
 //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
 wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z;
 // acceleration
 wishdir = normalize(wishvel);
 wishspeed = vlen(wishvel);
 if (wishspeed > sv_maxspeed)
 wishspeed = sv_maxspeed;
 if (time >= self.teleport_time)
 {
 f = wishspeed - (self.velocity * wishdir);
 if (f > 0)
 self.velocity = self.velocity + wishdir * min(f, sv_accelerate * frametime * wishspeed);
 }
 }
 else if (self.waterlevel >= 2)
 {
 // swimming
 makevectors(self.v_angle);
 //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
 wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z;
 if (wishvel == '0 0 0')
 wishvel = '0 0 -60'; // drift towards bottom

 wishdir = normalize(wishvel);
 wishspeed = vlen(wishvel);
 if (wishspeed > sv_maxspeed)
 wishspeed = sv_maxspeed;
 wishspeed = wishspeed * 0.7;

 // water friction
 self.velocity = self.velocity * (1 - frametime * sv_friction);

 // water acceleration
 f = wishspeed - (self.velocity * wishdir);
 if (f > 0)
 self.velocity = self.velocity + wishdir * min(f, sv_accelerate * frametime * wishspeed);
 }
 else if (time < self.ladder_time)
 {
 // on a func_ladder or swimming in func_water
 self.velocity = self.velocity * (1 - frametime * sv_friction);
 makevectors(self.v_angle);
 //wishvel = v_forward * self.movement_x + v_right * self.movement_y + v_up * self.movement_z;
 wishvel = v_forward * self.movement_x + v_right * self.movement_y + '0 0 1' * self.movement_z;
 if (self.gravity)
 self.velocity_z = self.velocity_z + self.gravity * sv_gravity * frametime;
 else
 self.velocity_z = self.velocity_z + sv_gravity * frametime;
 if (self.ladder_entity.classname == "func_water")
 {
 f = vlen(wishvel);
 if (f > self.ladder_entity.speed)
 wishvel = wishvel * (self.ladder_entity.speed / f);

 self.watertype = self.ladder_entity.skin;
 f = self.ladder_entity.origin_z + self.ladder_entity.maxs_z;
 if ((self.origin_z + self.view_ofs_z) < f)
 self.waterlevel = 3;
 else if ((self.origin_z + (self.mins_z + self.maxs_z) * 0.5) < f)
 self.waterlevel = 2;
 else if ((self.origin_z + self.mins_z + 1) < f)
 self.waterlevel = 1;
 else
 {
 self.waterlevel = 0;
 self.watertype = CONTENT_EMPTY;
 }
 }
 // acceleration
 wishdir = normalize(wishvel);
 wishspeed = vlen(wishvel);
 if (wishspeed > sv_maxspeed)
 wishspeed = sv_maxspeed;
 if (time >= self.teleport_time)
 {
 f = wishspeed - (self.velocity * wishdir);
 if (f > 0)
 self.velocity = self.velocity + wishdir * min(f, sv_accelerate * frametime * wishspeed);
 }
 }
 else if (self.flags & FL_ONGROUND)
 {
 // walking
 makevectors(self.v_angle_y * '0 1 0');
 wishvel = v_forward * self.movement_x + v_right * self.movement_y;
 // friction
 if (self.velocity_x || self.velocity_y)
 {
 v = self.velocity;
 v_z = 0;
 f = vlen(v);
 if (f < sv_stopspeed)
 f = 1 - frametime * (sv_stopspeed / f) * sv_friction;
 else
 f = 1 - frametime * sv_friction;
 if (f > 0)
 self.velocity = self.velocity * f;
 else
 self.velocity = '0 0 0';
 }
 // acceleration
 wishdir = normalize(wishvel);
 wishspeed = vlen(wishvel);
 if (wishspeed > sv_maxspeed)
 wishspeed = sv_maxspeed;
 if (time >= self.teleport_time)
 {
 f = wishspeed - (self.velocity * wishdir);
 if (f > 0)
 self.velocity = self.velocity + wishdir * min(f, sv_accelerate * frametime * wishspeed);
 }
 }
 else
 {
 // airborn
 makevectors(self.v_angle_y * '0 1 0');
 wishvel = v_forward * self.movement_x + v_right * self.movement_y;
 // acceleration
 wishdir = normalize(wishvel);
 wishspeed = vlen(wishvel);
 if (wishspeed > sv_maxairspeed)
 wishspeed = sv_maxairspeed;
 if (time >= self.teleport_time)
 {
 f = wishspeed - (self.velocity * wishdir);
 if (f > 0)
 self.velocity = self.velocity + wishdir * min(f, sv_accelerate * frametime * wishspeed);
 }
 }
};

preview



Tags:
Owned by kleskby#1837
Telegram
Close

You have no new notifications.


You have no new messages.