From: Mario <zacjardine@y7mail.com>
Date: Mon, 16 Mar 2015 15:29:22 +0000 (+1100)
Subject: Add movetype updates from QC physics branch
X-Git-Tag: xonotic-v0.8.1~38^2~17
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=80034856c349eb74bdbd70f9133b023392cffecc;p=xonotic%2Fxonotic-data.pk3dir.git

Add movetype updates from QC physics branch
---

diff --git a/qcsrc/common/movetypes/include.qc b/qcsrc/common/movetypes/include.qc
index e4d6f39dba..64d92d4a99 100644
--- a/qcsrc/common/movetypes/include.qc
+++ b/qcsrc/common/movetypes/include.qc
@@ -1,4 +1,5 @@
 #include "push.qc"
 #include "toss.qc"
+#include "walk.qc"
 
 #include "movetypes.qc"
diff --git a/qcsrc/common/movetypes/include.qh b/qcsrc/common/movetypes/include.qh
index 126d3b6af6..a96e5957a9 100644
--- a/qcsrc/common/movetypes/include.qh
+++ b/qcsrc/common/movetypes/include.qh
@@ -3,5 +3,6 @@
 
 #include "push.qh"
 #include "toss.qh"
+#include "walk.qh"
 
-#endif
\ No newline at end of file
+#endif
diff --git a/qcsrc/common/movetypes/movetypes.qc b/qcsrc/common/movetypes/movetypes.qc
index 5a45e98662..a7351ac662 100644
--- a/qcsrc/common/movetypes/movetypes.qc
+++ b/qcsrc/common/movetypes/movetypes.qc
@@ -14,21 +14,254 @@
 	#include "../../server/autocvars.qh"
 #endif
 
-void _Movetype_CheckVelocity() // SV_CheckVelocity
+void _Movetype_WallFriction(vector stepnormal)  // SV_WallFriction
 {
+	/*float d, i;
+	vector into, side;
+	makevectors(self.v_angle);
+	d = (stepnormal * v_forward) + 0.5;
+
+	if(d < 0)
+	{
+	    i = (stepnormal * self.move_velocity);
+	    into = i * stepnormal;
+	    side = self.move_velocity - into;
+	    self.move_velocity_x = side.x * (1 * d);
+	    self.move_velocity_y = side.y * (1 * d);
+	}*/
+}
+
+vector planes[MAX_CLIP_PLANES];
+int _Movetype_FlyMove(float dt, bool applygravity, vector stepnormal, float stepheight) // SV_FlyMove
+{
+	int blocked = 0, bumpcount;
+	int i, j, numplanes = 0;
+	float time_left = dt, grav = 0;
+	vector push;
+	vector primal_velocity, original_velocity, new_velocity = '0 0 0', restore_velocity;
+
+	for(i = 0; i <= MAX_CLIP_PLANES; ++i)
+		planes[i] = '0 0 0';
+	
+	grav = 0;
+
+	restore_velocity = self.move_velocity;
+
+	if(applygravity)
+	{
+		self.move_didgravity = 1;
+		grav = dt * (PHYS_ENTGRAVITY(self) ? PHYS_ENTGRAVITY(self) : 1) * PHYS_GRAVITY;
+
+		if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(self.move_flags & FL_ONGROUND))
+		{
+			if(GRAVITY_UNAFFECTED_BY_TICRATE)
+				self.move_velocity_z -= grav * 0.5;
+			else
+				self.move_velocity_z -= grav;
+		}
+	}
+
+	original_velocity = primal_velocity = self.move_velocity;
+
+	for(bumpcount = 0;bumpcount < MAX_CLIP_PLANES;bumpcount++)
+	{
+		if(!self.move_velocity_x && !self.move_velocity_y && !self.move_velocity_z)
+			break;
+
+		push = self.move_velocity * time_left;
+		if(!_Movetype_PushEntity(push, false))
+		{
+			// we got teleported by a touch function
+			// let's abort the move
+			blocked |= 8;
+			break;
+		}
+
+		// this code is used by MOVETYPE_WALK and MOVETYPE_STEP and SV_UnstickEntity
+		// abort move if we're stuck in the world (and didn't make it out)
+		if(trace_startsolid && trace_allsolid)
+		{
+			self.move_velocity = restore_velocity;
+			return 3;
+		}
+
+		if(trace_fraction == 1)
+			break;
+		if(trace_plane_normal_z)
+		{
+			if(trace_plane_normal_z > 0.7)
+			{
+				// floor
+				blocked |= 1;
+
+				if(!trace_ent)
+				{
+					//dprint("_Movetype_FlyMove: !trace_ent\n");
+					trace_ent = world;
+				}
+
+				self.move_flags |= FL_ONGROUND;
+				self.move_groundentity = trace_ent;
+			}
+		}
+		else if(stepheight)
+		{
+			// step - handle it immediately
+			vector org;
+			vector steppush;
+			//Con_Printf("step %f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+			steppush = '0 0 1' * stepheight;
+			org = self.move_origin;
+			if(!_Movetype_PushEntity(steppush, false))
+			{
+				blocked |= 8;
+				break;
+			}
+			//Con_Printf("%f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+			if(!_Movetype_PushEntity(push, false))
+			{
+				blocked |= 8;
+				break;
+			}
+			float trace2_fraction = trace_fraction;
+			//Con_Printf("%f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+			steppush = '0 0 1' * (org_z - self.move_origin_z);
+			if(!_Movetype_PushEntity(steppush, false))
+			{
+				blocked |= 8;
+				break;
+			}
+			//Con_Printf("%f %f %f : ", self.move_origin_x, PRVM_serveredictvector(ent, origin)[1], PRVM_serveredictvector(ent, origin)[2]);
+			// accept the new position if it made some progress...
+			if(fabs(self.move_origin_x - org_x) >= 0.03125 || fabs(self.move_origin_y - org_y) >= 0.03125)
+			{
+				//Con_Printf("accepted (delta %f %f %f)\n", self.move_origin_x - org_x, PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
+				trace_endpos = self.move_origin;
+				time_left *= 1 - trace2_fraction;
+				numplanes = 0;
+				continue;
+			}
+			else
+			{
+				//Con_Printf("REJECTED (delta %f %f %f)\n", self.move_origin_x - org_x, PRVM_serveredictvector(ent, origin)[1] - org[1], PRVM_serveredictvector(ent, origin)[2] - org[2]);
+				self.move_origin = org;
+			}
+		}
+		else
+		{
+			// step - return it to caller
+			blocked |= 2;
+			// save the trace for player extrafriction
+			if(stepnormal)
+				stepnormal = trace_plane_normal;
+		}
+		if(trace_fraction >= 0.001)
+		{
+			// actually covered some distance
+			original_velocity = self.move_velocity;
+			numplanes = 0;
+		}
+
+		time_left *= 1 - trace_fraction;
+
+		// clipped to another plane
+		if(numplanes >= MAX_CLIP_PLANES)
+		{
+			// this shouldn't really happen
+			self.move_velocity = '0 0 0';
+			blocked = 3;
+			break;
+		}
+
+		planes[numplanes] = trace_plane_normal;
+		numplanes++;
+
+		// modify original_velocity so it parallels all of the clip planes
+		for (i = 0;i < numplanes;i++)
+		{
+			new_velocity = _Movetype_ClipVelocity(original_velocity, planes[i], 1);
+			for (j = 0;j < numplanes;j++)
+			{
+				if(j != i)
+				{
+					// not ok
+					if((new_velocity * planes[j]) < 0)
+						break;
+				}
+			}
+			if(j == numplanes)
+				break;
+		}
+
+		if(i != numplanes)
+		{
+			// go along this plane
+			self.move_velocity = new_velocity;
+		}
+		else
+		{
+			// go along the crease
+			if(numplanes != 2)
+			{
+				self.move_velocity = '0 0 0';
+				blocked = 7;
+				break;
+			}
+			vector dir;
+			dir.x = planes[0].y * planes[1].z - planes[0].z * planes[1].y;
+			dir.y = planes[0].z * planes[1].x - planes[0].x * planes[1].z;
+			dir.z = planes[0].x * planes[1].y - planes[0].y * planes[1].x;
+			// LordHavoc: thanks to taniwha of QuakeForge for pointing out this fix for slowed falling in corners
+			float ilength = sqrt((dir * dir));
+			if(ilength)
+				ilength = 1.0 / ilength;
+			dir.x *= ilength;
+			dir.y *= ilength;
+			dir.z *= ilength;
+			float d = (dir * self.move_velocity);
+			self.move_velocity = dir * d;
+		}
+
+		// if current velocity is against the original velocity,
+		// stop dead to avoid tiny occilations in sloping corners
+		if((self.move_velocity * primal_velocity) <= 0)
+		{
+			self.move_velocity = '0 0 0';
+			break;
+		}
+	}
+
+	// LordHavoc: this came from QW and allows you to get out of water more easily
+	if(GAMEPLAYFIX_EASIERWATERJUMP && (self.move_flags & FL_WATERJUMP) && !(blocked & 8))
+		self.move_velocity = primal_velocity;
+
+	if(applygravity)
+	{
+		if(!GAMEPLAYFIX_NOGRAVITYONGROUND || !(self.move_flags & FL_ONGROUND))
+		{
+			if(GRAVITY_UNAFFECTED_BY_TICRATE)
+				self.move_velocity_z -= grav * 0.5f;
+		}
+	}
+
+	return blocked;
 }
 
-float _Movetype_CheckWater(entity ent) // SV_CheckWater
+void _Movetype_CheckVelocity()  // SV_CheckVelocity
+{
+	// if(vlen(self.move_velocity) < 0.0001)
+	// self.move_velocity = '0 0 0';
+}
+
+bool _Movetype_CheckWater(entity ent)  // SV_CheckWater
 {
 	vector point = ent.move_origin;
-	point_z += (ent.mins_z + 1);
+	point.z += (ent.mins.z + 1);
 
 	int nativecontents = pointcontents(point);
-
-	if(ent.move_watertype)
-	if(ent.move_watertype != nativecontents)
+	if(ent.move_watertype && ent.move_watertype != nativecontents)
 	{
-		//dprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", ent.move_watertype, nativecontents);
+		// dprintf("_Movetype_CheckWater(): Original: '%d', New: '%d'\n", ent.move_watertype, nativecontents);
 		if(ent.contentstransition)
 			ent.contentstransition(ent.move_watertype, nativecontents);
 	}
@@ -41,22 +274,22 @@ float _Movetype_CheckWater(entity ent) // SV_CheckWater
 	{
 		ent.move_watertype = nativecontents;
 		ent.move_waterlevel = 1;
-		point_y = (ent.origin_y + ((ent.mins_z + ent.maxs_y) * 0.5));
+		point.y = (ent.origin.y + ((ent.mins.z + ent.maxs.y) * 0.5));
 		if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
 		{
 			ent.move_waterlevel = 2;
-			point_y = ent.origin_y + ent.view_ofs_y;
+			point.y = ent.origin.y + ent.view_ofs.y;
 			if(Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(point)) & DPCONTENTS_LIQUIDSMASK)
 				ent.move_waterlevel = 3;
 		}
 	}
 
-	return (ent.move_waterlevel > 1);
+	return ent.move_waterlevel > 1;
 }
 
-void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
+void _Movetype_CheckWaterTransition(entity ent)  // SV_CheckWaterTransition
 {
-	float contents = pointcontents(ent.move_origin);
+	int contents = pointcontents(ent.move_origin);
 
 	if(!ent.move_watertype)
 	{
@@ -70,7 +303,7 @@ void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
 	}
 	else if(ent.move_watertype != contents)
 	{
-		//dprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.move_origin), pointcontents(ent.move_origin), ent.move_watertype, contents);
+		// dprintf("_Movetype_CheckWaterTransition(): Origin: %s, Direct: '%d', Original: '%d', New: '%d'\n", vtos(ent.move_origin), pointcontents(ent.move_origin), ent.move_watertype, contents);
 		if(ent.contentstransition)
 			ent.contentstransition(ent.move_watertype, contents);
 	}
@@ -87,12 +320,10 @@ void _Movetype_CheckWaterTransition(entity ent) // SV_CheckWaterTransition
 	}
 }
 
-void _Movetype_Impact(entity oth) // SV_Impact
+void _Movetype_Impact(entity oth)  // SV_Impact
 {
-	entity oldother, oldself;
-
-	oldself = self;
-	oldother = other;
+	entity oldself = self;
+	entity oldother = other;
 
 	if(self.move_touch)
 	{
@@ -115,17 +346,14 @@ void _Movetype_Impact(entity oth) // SV_Impact
 	}
 }
 
-void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
+void _Movetype_LinkEdict_TouchAreaGrid()  // SV_LinkEdict_TouchAreaGrid
 {
-	entity e, oldself, oldother;
-
-	oldself = self;
-	oldother = other;
+	entity oldself = self;
+	entity oldother = other;
 
-	for(e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
+	for (entity e = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); e; e = e.chain)
 	{
-		if(e.move_touch)
-		if(boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
+		if(e.move_touch && boxesoverlap(e.absmin, e.absmax, oldself.absmin, oldself.absmax))
 		{
 			self = e;
 			other = oldself;
@@ -148,7 +376,7 @@ void _Movetype_LinkEdict_TouchAreaGrid() // SV_LinkEdict_TouchAreaGrid
 	self = oldself;
 }
 
-void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
+void _Movetype_LinkEdict(bool touch_triggers)  // SV_LinkEdict
 {
 	vector mi, ma;
 	if(self.solid == SOLID_BSP)
@@ -162,26 +390,26 @@ void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
 		mi = self.mins;
 		ma = self.maxs;
 	}
-	mi = mi + self.origin;
-	ma = ma + self.origin;
+	mi += self.move_origin;
+	ma += self.move_origin;
 
 	if(self.move_flags & FL_ITEM)
 	{
-		mi_x -= 15;
-		mi_y -= 15;
-		mi_z -= 1;
-		ma_x += 15;
-		ma_y += 15;
-		ma_z += 1;
+		mi.x -= 15;
+		mi.y -= 15;
+		mi.z -= 1;
+		ma.x += 15;
+		ma.y += 15;
+		ma.z += 1;
 	}
 	else
 	{
-		mi_x -= 1;
-		mi_y -= 1;
-		mi_z -= 1;
-		ma_x += 1;
-		ma_y += 1;
-		ma_z += 1;
+		mi.x -= 1;
+		mi.y -= 1;
+		mi.z -= 1;
+		ma.x += 1;
+		ma.y += 1;
+		ma.z += 1;
 	}
 
 	self.absmin = mi;
@@ -191,10 +419,9 @@ void _Movetype_LinkEdict(float touch_triggers) // SV_LinkEdict
 		_Movetype_LinkEdict_TouchAreaGrid();
 }
 
-float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
+bool _Movetype_TestEntityPosition(vector ofs)  // SV_TestEntityPosition
 {
-	vector org;
-	org = self.move_origin + ofs;
+//	vector org = self.move_origin + ofs;
 
 	int cont = self.dphitcontentsmask;
 	self.dphitcontentsmask = DPCONTENTS_SOLID;
@@ -209,10 +436,9 @@ float _Movetype_TestEntityPosition(vector ofs) // SV_TestEntityPosition
 	return false;
 }
 
-float _Movetype_UnstickEntity() // SV_UnstickEntity
+bool _Movetype_UnstickEntity()  // SV_UnstickEntity
 {
-	if(!_Movetype_TestEntityPosition('0 0 0'))
-		return true;
+	if(!_Movetype_TestEntityPosition('0 0 0')) return true;
 	if(!_Movetype_TestEntityPosition('-1 0 0')) goto success;
 	if(!_Movetype_TestEntityPosition('1 0 0')) goto success;
 	if(!_Movetype_TestEntityPosition('0 -1 0')) goto success;
@@ -221,38 +447,36 @@ float _Movetype_UnstickEntity() // SV_UnstickEntity
 	if(!_Movetype_TestEntityPosition('1 -1 0')) goto success;
 	if(!_Movetype_TestEntityPosition('-1 1 0')) goto success;
 	if(!_Movetype_TestEntityPosition('1 1 0')) goto success;
-	float i;
-	for(i = 1; i <= 17; ++i)
+	for (int i = 1; i <= 17; ++i)
 	{
 		if(!_Movetype_TestEntityPosition('0 0 -1' * i)) goto success;
 		if(!_Movetype_TestEntityPosition('0 0 1' * i)) goto success;
 	}
-	dprintf("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
+	dprintf("Can't unstick an entity (edict: %d, classname: %s, origin: %s)\n",
+		num_for_edict(self), self.classname, vtos(self.move_origin));
 	return false;
-:success
-	dprintf("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n", num_for_edict(self), self.classname, vtos(self.move_origin));
+	: success;
+	dprintf("Sucessfully unstuck an entity (edict: %d, classname: %s, origin: %s)\n",
+		num_for_edict(self), self.classname, vtos(self.move_origin));
 	_Movetype_LinkEdict(true);
 	return true;
 }
 
-vector _Movetype_ClipVelocity(vector vel, vector norm, float f) // SV_ClipVelocity
+vector _Movetype_ClipVelocity(vector vel, vector norm, float f)  // SV_ClipVelocity
 {
-	vel = vel - ((vel * norm) * norm) * f;
+	vel -= ((vel * norm) * norm) * f;
 
-	if(vel_x > -0.1 && vel_x < 0.1) vel_x = 0;
-	if(vel_y > -0.1 && vel_y < 0.1) vel_y = 0;
-	if(vel_z > -0.1 && vel_z < 0.1) vel_z = 0;
+	if(vel.x > -0.1 && vel.x < 0.1) vel.x = 0;
+	if(vel.y > -0.1 && vel.y < 0.1) vel.y = 0;
+	if(vel.z > -0.1 && vel.z < 0.1) vel.z = 0;
 
 	return vel;
 }
 
 void _Movetype_PushEntityTrace(vector push)
 {
-	vector end;
-	float type;
-
-	end = self.move_origin + push;
-
+	vector end = self.move_origin + push;
+	int type;
 	if(self.move_nomonsters)
 		type = max(0, self.move_nomonsters);
 	else if(self.move_movetype == MOVETYPE_FLYMISSILE)
@@ -265,7 +489,7 @@ void _Movetype_PushEntityTrace(vector push)
 	tracebox(self.move_origin, self.mins, self.maxs, end, type, self);
 }
 
-float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
+float _Movetype_PushEntity(vector push, bool failonstartsolid)  // SV_PushEntity
 {
 	_Movetype_PushEntityTrace(push);
 
@@ -285,57 +509,55 @@ float _Movetype_PushEntity(vector push, float failonstartsolid) // SV_PushEntity
 .float ltime;
 .void() blocked;
 // matrix version of makevectors, sets v_forward, v_right and v_up
-void makevectors_matrix(vector myangles) // AngleVectorsFLU
+void makevectors_matrix(vector myangles)  // AngleVectorsFLU
 {
-	float angle, sr, sp, sy, cr, cp, cy;
-
 	v_forward = v_right = v_up = '0 0 0';
 
-	angle = myangles_y * (M_PI*2 / 360);
-	sy = sin(angle);
-	cy = cos(angle);
-	angle = myangles_x * (M_PI*2 / 360);
-	sp = sin(angle);
-	cp = cos(angle);
+	float y = myangles.y * (M_PI * 2 / 360);
+	float sy = sin(y);
+	float cy = cos(y);
+	float p = myangles.x * (M_PI * 2 / 360);
+	float sp = sin(p);
+	float cp = cos(p);
 	if(v_forward)
 	{
-		v_forward_x = cp*cy;
-		v_forward_y = cp*sy;
-		v_forward_z = -sp;
+		v_forward.x = cp * cy;
+		v_forward.y = cp * sy;
+		v_forward.z = -sp;
 	}
 	if(v_right || v_up)
 	{
-		if(myangles_z)
+		if(myangles.z)
 		{
-			angle = myangles_z * (M_PI*2 / 360);
-			sr = sin(angle);
-			cr = cos(angle);
+			float r = myangles.z * (M_PI * 2 / 360);
+			float sr = sin(r);
+			float cr = cos(r);
 			if(v_right)
 			{
-				v_right_x = sr*sp*cy+cr*-sy;
-				v_right_y = sr*sp*sy+cr*cy;
-				v_right_z = sr*cp;
+				v_right.x = sr * sp * cy + cr * -sy;
+				v_right.y = sr * sp * sy + cr * cy;
+				v_right.z = sr * cp;
 			}
 			if(v_up)
 			{
-				v_up_x = cr*sp*cy+-sr*-sy;
-				v_up_y = cr*sp*sy+-sr*cy;
-				v_up_z = cr*cp;
+				v_up.x = cr * sp * cy + -sr * -sy;
+				v_up.y = cr * sp * sy + -sr * cy;
+				v_up.z = cr * cp;
 			}
 		}
 		else
 		{
 			if(v_right)
 			{
-				v_right_x = -sy;
-				v_right_y = cy;
-				v_right_z = 0;
+				v_right.x = -sy;
+				v_right.y = cy;
+				v_right.z = 0;
 			}
 			if(v_up)
 			{
-				v_up_x = sp*cy;
-				v_up_y = sp*sy;
-				v_up_z = cp;
+				v_up.x = sp * cy;
+				v_up.y = sp * sy;
+				v_up.z = cp;
 			}
 		}
 	}
@@ -344,7 +566,7 @@ void makevectors_matrix(vector myangles) // AngleVectorsFLU
 void _Movetype_Physics_Frame(float movedt)
 {
 	self.move_didgravity = -1;
-	switch(self.move_movetype)
+	switch (self.move_movetype)
 	{
 		case MOVETYPE_PUSH:
 		case MOVETYPE_FAKEPUSH:
@@ -365,7 +587,7 @@ void _Movetype_Physics_Frame(float movedt)
 			error("SV_Physics_Step not implemented");
 			break;
 		case MOVETYPE_WALK:
-			error("SV_Physics_Walk not implemented");
+			_Movetype_Physics_Walk(movedt);
 			break;
 		case MOVETYPE_TOSS:
 		case MOVETYPE_BOUNCE:
@@ -377,11 +599,9 @@ void _Movetype_Physics_Frame(float movedt)
 	}
 }
 
-void Movetype_Physics_NoMatchServer() // optimized
+void Movetype_Physics_NoMatchServer()  // optimized
 {
-	float movedt;
-
-	movedt = time - self.move_time;
+	float movedt = time - self.move_time;
 	self.move_time = time;
 
 	_Movetype_Physics_Frame(movedt);
@@ -399,29 +619,26 @@ void Movetype_Physics_MatchServer(bool sloppy)
 	Movetype_Physics_MatchTicrate(TICRATE, sloppy);
 }
 
-void Movetype_Physics_MatchTicrate(float tr, bool sloppy) // SV_Physics_Entity
+void Movetype_Physics_MatchTicrate(float tr, bool sloppy)  // SV_Physics_Entity
 {
-	float n, i, dt, movedt;
-
 	if(tr <= 0)
 	{
 		Movetype_Physics_NoMatchServer();
 		return;
 	}
 
-	dt = time - self.move_time;
+	float dt = time - self.move_time;
 
-	movedt = tr;
-	n = max(0, floor(dt / tr));
+	int n = max(0, floor(dt / tr));
 	dt -= n * tr;
 	self.move_time += n * tr;
 
 	if(!self.move_didgravity)
 		self.move_didgravity = ((self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS) && !(self.move_flags & FL_ONGROUND));
 
-	for(i = 0; i < n; ++i)
+	for (int i = 0; i < n; ++i)
 	{
-		_Movetype_Physics_Frame(movedt);
+		_Movetype_Physics_Frame(tr);
 		if(wasfreed(self))
 			return;
 	}
@@ -435,25 +652,15 @@ void Movetype_Physics_MatchTicrate(float tr, bool sloppy) // SV_Physics_Entity
 
 		if(self.move_didgravity > 0)
 		{
-			if(GRAVITY_UNAFFECTED_BY_TICRATE)
-			{
-				if(self.gravity)
-					self.velocity_z -= 0.5 * dt * self.gravity * PHYS_GRAVITY;
-				else
-					self.velocity_z -= 0.5 * dt * PHYS_GRAVITY;
-			}
-			else
-			{
-				if(self.gravity)
-					self.velocity_z -= dt * self.gravity * PHYS_GRAVITY;
-				else
-					self.velocity_z -= dt * PHYS_GRAVITY;
-			}
+			self.velocity_z -= (GRAVITY_UNAFFECTED_BY_TICRATE ? 0.5 : 1)
+			    * dt
+			    * (self.gravity ? self.gravity : 1)
+			    * PHYS_GRAVITY;
 		}
 
 		self.angles = self.move_angles + dt * self.avelocity;
 
-		if(sloppy || self.movetype == MOVETYPE_NOCLIP)
+		if(sloppy || self.move_movetype == MOVETYPE_NOCLIP)
 		{
 			setorigin(self, self.move_origin + dt * self.velocity);
 		}
@@ -464,16 +671,8 @@ void Movetype_Physics_MatchTicrate(float tr, bool sloppy) // SV_Physics_Entity
 				setorigin(self, trace_endpos);
 		}
 
-		if(self.move_didgravity > 0)
-		{
-			if(GRAVITY_UNAFFECTED_BY_TICRATE)
-			{
-				if(self.gravity)
-					self.velocity_z -= 0.5 * dt * self.gravity * PHYS_GRAVITY;
-				else
-					self.velocity_z -= 0.5 * dt * PHYS_GRAVITY;
-			}
-		}
+		if(self.move_didgravity > 0 && GRAVITY_UNAFFECTED_BY_TICRATE)
+			self.velocity_z -= 0.5 * dt * (self.gravity ? self.gravity : 1) * PHYS_GRAVITY;
 	}
 	else
 	{
diff --git a/qcsrc/common/movetypes/movetypes.qh b/qcsrc/common/movetypes/movetypes.qh
index 85c07fce64..88b545fe11 100644
--- a/qcsrc/common/movetypes/movetypes.qh
+++ b/qcsrc/common/movetypes/movetypes.qh
@@ -2,9 +2,9 @@
 #define MOVETYPES_H
 
 .float move_ltime;
-.void(void) move_think;
+.void(void)move_think;
 .float move_nextthink;
-.void(void) move_blocked;
+.void(void)move_blocked;
 
 .float move_movetype;
 .float move_time;
@@ -15,11 +15,11 @@
 .int move_flags;
 .int move_watertype;
 .int move_waterlevel;
-.void(void) move_touch;
-.void(float, float) contentstransition;
+.void(void)move_touch;
+.void(float, float)contentstransition;
 .float move_bounce_factor;
 .float move_bounce_stopspeed;
-.float move_nomonsters; // -1 for MOVE_NORMAL, otherwise a MOVE_ constant
+.float move_nomonsters;  // -1 for MOVE_NORMAL, otherwise a MOVE_ constant
 
 // should match sv_gameplayfix_fixedcheckwatertransition
 float autocvar_cl_gameplayfix_fixedcheckwatertransition = 1;
@@ -34,12 +34,15 @@ float autocvar_cl_gameplayfix_fixedcheckwatertransition = 1;
 #define TICRATE ticrate
 #endif
 
-.entity move_groundentity; // FIXME add move_groundnetworkentity?
+.entity move_groundentity;  // FIXME add move_groundnetworkentity?
 .float move_suspendedinair;
 .float move_didgravity;
 
+void _Movetype_WallFriction(vector stepnormal);
+int _Movetype_FlyMove(float dt, bool applygravity, vector stepnormal, float stepheight);
 void _Movetype_CheckVelocity();
 void _Movetype_CheckWaterTransition(entity ent);
+float _Movetype_CheckWater(entity ent);
 void _Movetype_LinkEdict_TouchAreaGrid();
 void _Movetype_LinkEdict(float touch_triggers);
 float _Movetype_TestEntityPosition(vector ofs);
@@ -60,18 +63,18 @@ float _Movetype_UnstickEntity();
 const int MAX_CLIP_PLANES = 5;
 
 #ifdef CSQC
-const int MOVETYPE_NONE				= 0;
-const int MOVETYPE_ANGLENOCLIP	    = 1;
-const int MOVETYPE_ANGLECLIP	    = 2;
-const int MOVETYPE_WALK				= 3;
-const int MOVETYPE_STEP				= 4;
-const int MOVETYPE_FLY				= 5;
-const int MOVETYPE_TOSS				= 6;
-const int MOVETYPE_PUSH				= 7;
-const int MOVETYPE_NOCLIP		    = 8;
-const int MOVETYPE_FLYMISSILE	    = 9;
-const int MOVETYPE_BOUNCE		    = 10;
-const int MOVETYPE_BOUNCEMISSILE	= 11;	// Like bounce but doesn't lose speed on bouncing
+const int MOVETYPE_NONE             = 0;
+const int MOVETYPE_ANGLENOCLIP      = 1;
+const int MOVETYPE_ANGLECLIP        = 2;
+const int MOVETYPE_WALK             = 3;
+const int MOVETYPE_STEP             = 4;
+const int MOVETYPE_FLY              = 5;
+const int MOVETYPE_TOSS             = 6;
+const int MOVETYPE_PUSH             = 7;
+const int MOVETYPE_NOCLIP           = 8;
+const int MOVETYPE_FLYMISSILE       = 9;
+const int MOVETYPE_BOUNCE           = 10;
+const int MOVETYPE_BOUNCEMISSILE    = 11;  // Like bounce but doesn't lose speed on bouncing
 const int MOVETYPE_FOLLOW           = 12;
 const int MOVETYPE_FLY_WORLDONLY    = 33;
 
diff --git a/qcsrc/common/movetypes/push.qc b/qcsrc/common/movetypes/push.qc
index 7ae5e2eb55..1f563f58dd 100644
--- a/qcsrc/common/movetypes/push.qc
+++ b/qcsrc/common/movetypes/push.qc
@@ -1,171 +1,161 @@
-void _Movetype_PushMove(float dt) // SV_PushMove
+void _Movetype_PushMove(float dt)  // SV_PushMove
 {
-	bool rotated;
-	int savesolid;
-	float movetime2, pushltime;
-	vector move, move1, moveangle, pushorig, pushang;
-	vector a;
-	vector pivot;
-	entity oldself;
-	entity check;
-
-	if(self.move_velocity == '0 0 0' && self.move_avelocity == '0 0 0')
+	if (self.move_velocity == '0 0 0' && self.move_avelocity == '0 0 0')
 	{
 		self.move_ltime += dt;
 		return;
 	}
 
-	switch(self.solid)
+	switch (self.solid)
 	{
-	// LordHavoc: valid pusher types
-	case SOLID_BSP:
-	case SOLID_BBOX:
-	case SOLID_SLIDEBOX:
-	case SOLID_CORPSE: // LordHavoc: this would be weird...
-		break;
-	// LordHavoc: no collisions
-	case SOLID_NOT:
-	case SOLID_TRIGGER:
-		self.move_origin = self.move_origin + dt * self.move_velocity;
-		self.move_angles = self.move_angles + dt * self.move_avelocity;
-		self.move_angles_x -= 360.0 * floor(self.move_angles_x * (1.0 / 360.0));
-		self.move_angles_y -= 360.0 * floor(self.move_angles_y * (1.0 / 360.0));
-		self.move_angles_z -= 360.0 * floor(self.move_angles_z * (1.0 / 360.0));
-		self.move_ltime += dt;
-		_Movetype_LinkEdict(true);
-		return;
-	default:
-		dprintf("_Movetype_PushMove: entity %e, unrecognized solid type %d\n", self, self.solid);
-		return;
+		// LordHavoc: valid pusher types
+		case SOLID_BSP:
+		case SOLID_BBOX:
+		case SOLID_SLIDEBOX:
+		case SOLID_CORPSE:  // LordHavoc: this would be weird...
+			break;
+		// LordHavoc: no collisions
+		case SOLID_NOT:
+		case SOLID_TRIGGER:
+			self.move_origin = self.move_origin + dt * self.move_velocity;
+			self.move_angles = self.move_angles + dt * self.move_avelocity;
+			self.move_angles_x -= 360.0 * floor(self.move_angles.x * (1.0 / 360.0));
+			self.move_angles_y -= 360.0 * floor(self.move_angles.y * (1.0 / 360.0));
+			self.move_angles_z -= 360.0 * floor(self.move_angles.z * (1.0 / 360.0));
+			self.move_ltime += dt;
+			_Movetype_LinkEdict(true);
+			return;
+		default:
+			dprintf("_Movetype_PushMove: entity %e, unrecognized solid type %d\n", self, self.solid);
+			return;
 	}
 
-	rotated = (self.move_angles * self.move_angles) + (self.move_avelocity * self.move_avelocity) > 0;
+	bool rotated = (self.move_angles * self.move_angles) + (self.move_avelocity * self.move_avelocity) > 0;
 
-	movetime2 = dt;
+	vector move1 = self.move_velocity * dt;
+	vector moveangle = self.move_avelocity * dt;
 
-	move1 = self.move_velocity * movetime2;
-	moveangle = self.move_avelocity * movetime2;
+	makevectors_matrix(-moveangle);
 
-	a = -moveangle;
-	makevectors_matrix(a);
-
-	pushorig = self.move_origin;
-	pushang = self.move_angles;
-	pushltime = self.move_ltime;
+//	vector pushorig = self.move_origin;
+//	vector pushang = self.move_angles;
+//	float pushltime = self.move_ltime;
 
 // move the pusher to its final position
 
 	self.move_origin = self.move_origin + dt * self.move_velocity;
 	self.move_angles = self.move_angles + dt * self.move_avelocity;
-	
+
 	self.move_ltime += dt;
 	_Movetype_LinkEdict(true);
 
-	savesolid = self.solid;
+	int savesolid = self.solid;
 
-	if(self.move_movetype != MOVETYPE_FAKEPUSH)
-	for(check = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); check; check = check.chain)
+	if (self.move_movetype != MOVETYPE_FAKEPUSH)
 	{
-		switch(check.move_movetype)
+		for (entity check = findradius(0.5 * (self.absmin + self.absmax), 0.5 * vlen(self.absmax - self.absmin)); check; check = check.chain)
 		{
-		case MOVETYPE_NONE:
-		case MOVETYPE_PUSH:
-		case MOVETYPE_FOLLOW:
-		case MOVETYPE_NOCLIP:
-		case MOVETYPE_FLY_WORLDONLY:
-			continue;
-		default:
-			break;
-		}
-
-		if(check.owner == self)
-			continue;
-
-		if(self.owner == check)
-			continue;
-
-		pivot = check.mins + 0.5 * (check.maxs - check.mins);
-
-		if (rotated)
-		{
-			vector org2;
-			vector org = check.move_origin - self.move_origin;
-			org = org + pivot;
-			org2_x = dotproduct(org, v_forward);
-			org2_y = dotproduct(org, v_right);
-			org2_z = dotproduct(org, v_up);
-			move = org2 - org;
-			move = move + move1;
-		}
-		else
-			move = move1;
-
-		// physics objects need better collisions than this code can do
-		if(check.move_movetype == 32) // MOVETYPE_PHYSICS
-		{
-			check.move_origin = check.move_origin + move;
-			oldself = self;
+			switch (check.move_movetype)
+			{
+				case MOVETYPE_NONE:
+				case MOVETYPE_PUSH:
+				case MOVETYPE_FOLLOW:
+				case MOVETYPE_NOCLIP:
+				case MOVETYPE_FLY_WORLDONLY:
+					continue;
+				default:
+					break;
+			}
+
+			if (check.owner == self)
+				continue;
+
+			if (self.owner == check)
+				continue;
+
+			vector pivot = check.mins + 0.5 * (check.maxs - check.mins);
+			vector move;
+			if (rotated)
+			{
+				vector org = (check.move_origin - self.move_origin) + pivot;
+				vector org2;
+				org2.x = org * v_forward;
+				org2.y = org * v_right;
+				org2.z = org * v_up;
+				move = (org2 - org) + move1;
+			}
+			else
+			{
+				move = move1;
+			}
+
+			// physics objects need better collisions than this code can do
+			if (check.move_movetype == 32)  // MOVETYPE_PHYSICS
+			{
+				check.move_origin = check.move_origin + move;
+				entity oldself = self;
+				self = check;
+				_Movetype_LinkEdict(true);
+				self = oldself;
+				continue;
+			}
+
+			// try moving the contacted entity
+			self.solid = SOLID_NOT;
+			entity oldself = self;
 			self = check;
-			_Movetype_LinkEdict(true);
-			self = oldself;
-			continue;
-		}
-
-		// try moving the contacted entity
-		self.solid = SOLID_NOT;
-		oldself = self;
-		self = check;
-		if(!_Movetype_PushEntity(move, true))
-		{
+			if (!_Movetype_PushEntity(move, true))
+			{
+				self = oldself;
+				// entity "check" got teleported
+				check.move_angles_y += trace_fraction * moveangle.y;
+				self.solid = savesolid;
+				continue;  // pushed enough
+			}
 			self = oldself;
-			// entity "check" got teleported
-			check.move_angles_y += trace_fraction * moveangle_y;
+			// FIXME: turn players specially
+			check.move_angles_y += trace_fraction * moveangle.y;
 			self.solid = savesolid;
-			continue; // pushed enough
+
+			// this trace.fraction < 1 check causes items to fall off of pushers
+			// if they pass under or through a wall
+			// the groundentity check causes items to fall off of ledges
+			if (check.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || check.move_groundentity != self))
+				check.move_flags &= ~FL_ONGROUND;
 		}
-		self = oldself;
-		// FIXME: turn players specially
-		check.move_angles_y += trace_fraction * moveangle_y;
-		self.solid = savesolid;
-
-		// this trace.fraction < 1 check causes items to fall off of pushers
-		// if they pass under or through a wall
-		// the groundentity check causes items to fall off of ledges
-		if(check.move_movetype != MOVETYPE_WALK && (trace_fraction < 1 || check.move_groundentity != self))
-			check.move_flags &= ~FL_ONGROUND;
 	}
 
-	self.move_angles_x -= 360.0 * floor(self.move_angles_x * (1.0 / 360.0));
-	self.move_angles_y -= 360.0 * floor(self.move_angles_y * (1.0 / 360.0));
-	self.move_angles_z -= 360.0 * floor(self.move_angles_z * (1.0 / 360.0));
+	self.move_angles_x -= 360.0 * floor(self.move_angles.x * (1.0 / 360.0));
+	self.move_angles_y -= 360.0 * floor(self.move_angles.y * (1.0 / 360.0));
+	self.move_angles_z -= 360.0 * floor(self.move_angles.z * (1.0 / 360.0));
 }
 
-void _Movetype_Physics_Pusher(float dt) // SV_Physics_Pusher
+void _Movetype_Physics_Pusher(float dt)  // SV_Physics_Pusher
 {
-	float thinktime, oldltime, movetime;
-
-	oldltime = self.move_ltime;
-
-	thinktime = self.move_nextthink;
-	if(thinktime < self.move_ltime + dt)
+	float oldltime = self.move_ltime;
+	float thinktime = self.move_nextthink;
+	float movetime;
+	if (thinktime < self.move_ltime + dt)
 	{
 		movetime = thinktime - self.move_ltime;
-		if(movetime < 0)
+		if (movetime < 0)
 			movetime = 0;
 	}
 	else
+	{
 		movetime = dt;
+	}
 
-	if(movetime)
+	if (movetime)
 		// advances self.move_ltime if not blocked
 		_Movetype_PushMove(movetime);
 
-	if(thinktime > oldltime && thinktime <= self.move_ltime)
+	if (thinktime > oldltime && thinktime <= self.move_ltime)
 	{
 		self.move_nextthink = 0;
 		self.move_time = time;
 		other = world;
-		if(self.move_think)
+		if (self.move_think)
 			self.move_think();
 	}
 }
diff --git a/qcsrc/common/movetypes/toss.qc b/qcsrc/common/movetypes/toss.qc
index df9c9b8e30..6ed0407eb3 100644
--- a/qcsrc/common/movetypes/toss.qc
+++ b/qcsrc/common/movetypes/toss.qc
@@ -1,14 +1,18 @@
 #include "../physics.qh"
 
-void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
+void _Movetype_Physics_Toss(float dt)  // SV_Physics_Toss
 {
-	if(self.move_flags & FL_ONGROUND)
+	if (self.move_flags & FL_ONGROUND)
 	{
-		if(self.move_velocity_z >= 1/32)
+		if (self.move_velocity.z >= 1 / 32)
+		{
 			self.move_flags &= ~FL_ONGROUND;
-		else if(!self.move_groundentity)
+		}
+		else if (!self.move_groundentity)
+		{
 			return;
-		else if(self.move_suspendedinair && wasfreed(self.move_groundentity))
+		}
+		else if (self.move_suspendedinair && wasfreed(self.move_groundentity))
 		{
 			self.move_groundentity = world;
 			return;
@@ -19,70 +23,53 @@ void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
 
 	_Movetype_CheckVelocity();
 
-	if(self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
+	if (self.move_movetype == MOVETYPE_BOUNCE || self.move_movetype == MOVETYPE_TOSS)
 	{
 		self.move_didgravity = 1;
-		if(GRAVITY_UNAFFECTED_BY_TICRATE)
-		{
-			if(self.gravity)
-				self.move_velocity_z -= 0.5 * dt * self.gravity * PHYS_GRAVITY;
-			else
-				self.move_velocity_z -= 0.5 * dt * PHYS_GRAVITY;
-		}
-		else
-		{
-			if(self.gravity)
-				self.move_velocity_z -= dt * self.gravity * PHYS_GRAVITY;
-			else
-				self.move_velocity_z -= dt * PHYS_GRAVITY;
-		}
+		self.move_velocity_z -= (GRAVITY_UNAFFECTED_BY_TICRATE ? 0.5 : 1)
+		    * dt
+		    * (self.gravity ? self.gravity : 1)
+		    * PHYS_GRAVITY;
 	}
 
 	self.move_angles = self.move_angles + self.move_avelocity * dt;
 
-	float movetime, bump;
-	movetime = dt;
-	for(bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
+	float movetime = dt;
+	for (int bump = 0; bump < MAX_CLIP_PLANES && movetime > 0; ++bump)
 	{
-		vector move;
-		move = self.move_velocity * movetime;
+		vector move = self.move_velocity * movetime;
 		_Movetype_PushEntity(move, true);
-		if(wasfreed(self))
+		if (wasfreed(self))
 			return;
 
-		if(trace_startsolid)
+		if (trace_startsolid)
 		{
 			_Movetype_UnstickEntity();
 			_Movetype_PushEntity(move, false);
-			if(wasfreed(self))
+			if (wasfreed(self))
 				return;
 		}
 
-		if(trace_fraction == 1)
+		if (trace_fraction == 1)
 			break;
 
 		movetime *= 1 - min(1, trace_fraction);
 
-		if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
+		if (self.move_movetype == MOVETYPE_BOUNCEMISSILE)
 		{
 			self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 2.0);
 			self.move_flags &= ~FL_ONGROUND;
 		}
-		else if(self.move_movetype == MOVETYPE_BOUNCE)
+		else if (self.move_movetype == MOVETYPE_BOUNCE)
 		{
-			float d, bouncefac, bouncestop;
-
-			bouncefac = self.move_bounce_factor;     if(!bouncefac)  bouncefac = 0.5;
-			bouncestop = self.move_bounce_stopspeed; if(!bouncestop) bouncestop = 60 / 800;
-			if(self.gravity)
-				bouncestop *= self.gravity * PHYS_GRAVITY;
-			else
-				bouncestop *= PHYS_GRAVITY;
+			float bouncefac = self.move_bounce_factor;     if (!bouncefac)  bouncefac = 0.5;
+			float bouncestop = self.move_bounce_stopspeed; if (!bouncestop) bouncestop = 60 / 800;
+			bouncestop *= (self.gravity ? self.gravity : 1) * PHYS_GRAVITY;
 
 			self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1 + bouncefac);
 
-			d = trace_plane_normal * self.move_velocity;
-			if(trace_plane_normal_z > 0.7 && d < bouncestop && d > -bouncestop)
+			float d = trace_plane_normal * self.move_velocity;
+			if (trace_plane_normal.z > 0.7 && d < bouncestop && d > -bouncestop)
 			{
 				self.move_flags |= FL_ONGROUND;
 				self.move_groundentity = trace_ent;
@@ -90,42 +77,39 @@ void _Movetype_Physics_Toss(float dt) // SV_Physics_Toss
 				self.move_avelocity = '0 0 0';
 			}
 			else
+			{
 				self.move_flags &= ~FL_ONGROUND;
+			}
 		}
 		else
 		{
 			self.move_velocity = _Movetype_ClipVelocity(self.move_velocity, trace_plane_normal, 1.0);
-			if(trace_plane_normal_z > 0.7)
+			if (trace_plane_normal.z > 0.7)
 			{
 				self.move_flags |= FL_ONGROUND;
 				self.move_groundentity = trace_ent;
-				if(trace_ent.solid == SOLID_BSP)
+				if (trace_ent.solid == SOLID_BSP)
 					self.move_suspendedinair = true;
 				self.move_velocity = '0 0 0';
 				self.move_avelocity = '0 0 0';
 			}
 			else
+			{
 				self.move_flags &= ~FL_ONGROUND;
+			}
 		}
 
 		// DP revision 8905 (just, WHY...)
-		if(self.move_movetype == MOVETYPE_BOUNCEMISSILE)
+		if (self.move_movetype == MOVETYPE_BOUNCEMISSILE)
 			break;
 
 		// DP revision 8918 (WHY...)
-		if(self.move_flags & FL_ONGROUND)
+		if (self.move_flags & FL_ONGROUND)
 			break;
 	}
 
-	if(GRAVITY_UNAFFECTED_BY_TICRATE)
-	if(self.move_didgravity > 0)
-	if(!(self.move_flags & FL_ONGROUND))
-	{
-		if(self.gravity)
-			self.move_velocity_z -= 0.5 * dt * self.gravity * PHYS_GRAVITY;
-		else
-			self.move_velocity_z -= 0.5 * dt * PHYS_GRAVITY;
-	}
+	if (GRAVITY_UNAFFECTED_BY_TICRATE && self.move_didgravity > 0 && !(self.move_flags & FL_ONGROUND))
+		self.move_velocity_z -= 0.5 * dt * (self.gravity ? self.gravity : 1) * PHYS_GRAVITY;
 
 	_Movetype_CheckWaterTransition(self);
 }
diff --git a/qcsrc/common/movetypes/walk.qc b/qcsrc/common/movetypes/walk.qc
new file mode 100644
index 0000000000..cbcfc5b392
--- /dev/null
+++ b/qcsrc/common/movetypes/walk.qc
@@ -0,0 +1,167 @@
+void _Movetype_Physics_Walk(float dt)  // SV_WalkMove
+{
+	vector stepnormal = '0 0 0';
+
+	// if frametime is 0 (due to client sending the same timestamp twice), don't move
+	if (dt <= 0)
+		return;
+
+	if (GAMEPLAYFIX_UNSTICKPLAYERS)
+		_Movetype_UnstickEntity();
+
+	bool applygravity = (!_Movetype_CheckWater(self) && self.move_movetype == MOVETYPE_WALK && !(self.move_flags & FL_WATERJUMP));
+
+	_Movetype_CheckVelocity();
+
+	// do a regular slide move unless it looks like you ran into a step
+	bool oldonground = (self.move_flags & FL_ONGROUND);
+
+	vector start_origin = self.move_origin;
+	vector start_velocity = self.move_velocity;
+
+	int clip = _Movetype_FlyMove(dt, applygravity, stepnormal, GAMEPLAYFIX_STEPMULTIPLETIMES ? PHYS_STEPHEIGHT : 0);
+
+	if (GAMEPLAYFIX_DOWNTRACEONGROUND && !(clip & 1))
+	{
+		// only try this if there was no floor in the way in the trace (no,
+		// this check seems to be not REALLY necessary, because if clip & 1,
+		// our trace will hit that thing too)
+		vector upmove = self.move_origin + '0 0 1';
+		vector downmove = self.move_origin - '0 0 1';
+		int type;
+		if (self.move_movetype == MOVETYPE_FLYMISSILE) type = MOVE_MISSILE; else if (self.move_movetype == MOVETYPE_FLY_WORLDONLY)
+			type = MOVE_WORLDONLY;
+		else if (self.solid == SOLID_TRIGGER || self.solid == SOLID_NOT)
+			type = MOVE_NOMONSTERS;
+		else   type = MOVE_NORMAL;
+		tracebox(upmove, self.mins, self.maxs, downmove, type, self);
+		if (trace_fraction < 1 && trace_plane_normal.z > 0.7)
+			clip |= 1;  // but we HAVE found a floor
+	}
+
+	// if the move did not hit the ground at any point, we're not on ground
+	if (!(clip & 1))
+		self.move_flags &= ~FL_ONGROUND;
+
+	_Movetype_CheckVelocity();
+	_Movetype_LinkEdict(true);
+
+	if (clip & 8)  // teleport
+		return;
+
+	if (self.move_flags & FL_WATERJUMP)
+		return;
+
+	if (PHYS_NOSTEP)
+		return;
+
+	vector originalmove_origin = self.move_origin;
+	vector originalmove_velocity = self.move_velocity;
+	// originalmove_clip = clip;
+	int originalmove_flags = self.move_flags;
+	entity originalmove_groundentity = self.move_groundentity;
+
+	// if move didn't block on a step, return
+	if (clip & 2)
+	{
+		// if move was not trying to move into the step, return
+		if (fabs(start_velocity.x) < 0.03125 && fabs(start_velocity.y) < 0.03125)
+			return;
+
+		if (self.move_movetype != MOVETYPE_FLY)
+		{
+			// return if gibbed by a trigger
+			if (self.move_movetype != MOVETYPE_WALK)
+				return;
+
+			// return if attempting to jump while airborn (unless sv_jumpstep)
+			if (!PHYS_JUMPSTEP)
+				if (!oldonground && self.move_waterlevel == 0)
+					return;
+		}
+
+		// try moving up and forward to go up a step
+		// back to start pos
+		self.move_origin = start_origin;
+		self.move_velocity = start_velocity;
+
+		// move up
+		vector upmove = '0 0 1' * PHYS_STEPHEIGHT;
+		if (!_Movetype_PushEntity(upmove, true))
+		{
+			// we got teleported when upstepping... must abort the move
+			return;
+		}
+
+		// move forward
+		self.move_velocity_z = 0;
+		clip = _Movetype_FlyMove(dt, applygravity, stepnormal, 0);
+		self.move_velocity_z += start_velocity.z;
+		if (clip & 8)
+		{
+			// we got teleported when upstepping... must abort the move
+			// note that z velocity handling may not be what QC expects here, but we cannot help it
+			return;
+		}
+
+		_Movetype_CheckVelocity();
+		_Movetype_LinkEdict(true);
+
+		// check for stuckness, possibly due to the limited precision of floats
+		// in the clipping hulls
+		if (clip
+		    && fabs(originalmove_origin.y - self.move_origin.y) < 0.03125
+		    && fabs(originalmove_origin.x - self.move_origin.x) < 0.03125)
+		{
+			// Con_Printf("wall\n");
+			// stepping up didn't make any progress, revert to original move
+			self.move_origin = originalmove_origin;
+			self.move_velocity = originalmove_velocity;
+			// clip = originalmove_clip;
+			self.move_flags = originalmove_flags;
+			self.move_groundentity = originalmove_groundentity;
+			// now try to unstick if needed
+			// clip = SV_TryUnstick (ent, oldvel);
+			return;
+		}
+
+		// Con_Printf("step - ");
+
+		// extra friction based on view angle
+		if (clip & 2 && PHYS_WALLFRICTION)
+			_Movetype_WallFriction(stepnormal);
+	}
+	// don't do the down move if stepdown is disabled, moving upward, not in water, or the move started offground or ended onground
+	else if (!GAMEPLAYFIX_STEPDOWN || self.move_waterlevel >= 3 || start_velocity.z >= (1.0 / 32.0) || !oldonground || (self.move_flags & FL_ONGROUND))
+	{
+		return;
+	}
+
+	// move down
+	vector downmove = '0 0 1' * (-PHYS_STEPHEIGHT + start_velocity.z * dt);
+	if (!_Movetype_PushEntity(downmove, true))
+	{
+		// we got teleported when downstepping... must abort the move
+		return;
+	}
+
+	if (trace_fraction < 1 && trace_plane_normal.z > 0.7)
+	{
+		// this has been disabled so that you can't jump when you are stepping
+		// up while already jumping (also known as the Quake2 double jump bug)
+	}
+	else
+	{
+		// Con_Printf("slope\n");
+		// if the push down didn't end up on good ground, use the move without
+		// the step up.  This happens near wall / slope combinations, and can
+		// cause the player to hop up higher on a slope too steep to climb
+		self.move_origin = originalmove_origin;
+		self.move_velocity = originalmove_velocity;
+		self.move_flags = originalmove_flags;
+		self.move_groundentity = originalmove_groundentity;
+	}
+
+	_Movetype_CheckVelocity();
+	_Movetype_LinkEdict(true);
+}
diff --git a/qcsrc/common/movetypes/walk.qh b/qcsrc/common/movetypes/walk.qh
new file mode 100644
index 0000000000..10493c96f4
--- /dev/null
+++ b/qcsrc/common/movetypes/walk.qh
@@ -0,0 +1,6 @@
+#ifndef MOVETYPE_WALK_H
+#define MOVETYPE_WALK_H
+
+void _Movetype_Physics_Walk(float dt);
+
+#endif
diff --git a/qcsrc/common/physics.qc b/qcsrc/common/physics.qc
index 728863ad44..01b9755b1b 100644
--- a/qcsrc/common/physics.qc
+++ b/qcsrc/common/physics.qc
@@ -1751,6 +1751,9 @@ void CSQC_ClientMovement_PlayerMove_Frame(void)
 	PM_Main();
 
 #ifdef CSQC
-	self.pmove_flags = self.flags; // TODO
+	self.pmove_flags = 
+			((self.flags & FL_DUCKED) ? PMF_DUCKED : 0) |
+			(!(self.flags & FL_JUMPRELEASED) ? 0 : PMF_JUMP_HELD) |
+			((self.flags & FL_ONGROUND) ? PMF_ONGROUND : 0);
 #endif
 }
diff --git a/qcsrc/common/physics.qh b/qcsrc/common/physics.qh
index 52a8e9a569..d5b8f14acc 100644
--- a/qcsrc/common/physics.qh
+++ b/qcsrc/common/physics.qh
@@ -72,6 +72,10 @@ bool IsFlying(entity a);
 	#define GAMEPLAYFIX_NOGRAVITYONGROUND			cvar("sv_gameplayfix_nogravityonground")
 	#define GAMEPLAYFIX_Q2AIRACCELERATE				cvar("sv_gameplayfix_q2airaccelerate")
 	#define GAMEPLAYFIX_EASIERWATERJUMP 			getstati(STAT_GAMEPLAYFIX_EASIERWATERJUMP)
+	#define GAMEPLAYFIX_DOWNTRACEONGROUND			getstati(STAT_GAMEPLAYFIX_DOWNTRACEONGROUND)
+	#define GAMEPLAYFIX_STEPMULTIPLETIMES			getstati(STAT_GAMEPLAYFIX_STEPMULTIPLETIMES)
+	#define GAMEPLAYFIX_UNSTICKPLAYERS				getstati(STAT_GAMEPLAYFIX_UNSTICKPLAYERS)
+	#define GAMEPLAYFIX_STEPDOWN					getstati(STAT_GAMEPLAYFIX_STEPDOWN)
 
 	#define IS_DUCKED(s)    					!!(s.flags & FL_DUCKED)
 	#define SET_DUCKED(s)   					s.flags |= FL_DUCKED
@@ -95,6 +99,22 @@ bool IsFlying(entity a);
 
 	#define PHYS_DOUBLEJUMP						getstati(STAT_DOUBLEJUMP)
 
+	#define PHYS_BUGRIGS						getstati(STAT_BUGRIGS)
+	#define PHYS_BUGRIGS_ANGLE_SMOOTHING 		getstati(STAT_BUGRIGS_ANGLE_SMOOTHING)
+	#define PHYS_BUGRIGS_PLANAR_MOVEMENT 		getstati(STAT_BUGRIGS_PLANAR_MOVEMENT)
+	#define PHYS_BUGRIGS_REVERSE_SPEEDING 		getstati(STAT_BUGRIGS_REVERSE_SPEEDING)
+	#define PHYS_BUGRIGS_FRICTION_FLOOR 		getstatf(STAT_BUGRIGS_FRICTION_FLOOR)
+	#define PHYS_BUGRIGS_AIR_STEERING 			getstati(STAT_BUGRIGS_AIR_STEERING)
+	#define PHYS_BUGRIGS_FRICTION_BRAKE 		getstatf(STAT_BUGRIGS_FRICTION_BRAKE)
+	#define PHYS_BUGRIGS_ACCEL 					getstatf(STAT_BUGRIGS_ACCEL)
+	#define PHYS_BUGRIGS_SPEED_REF 				getstatf(STAT_BUGRIGS_SPEED_REF)
+	#define PHYS_BUGRIGS_SPEED_POW 				getstatf(STAT_BUGRIGS_SPEED_POW)
+	#define PHYS_BUGRIGS_STEER 					getstatf(STAT_BUGRIGS_STEER)
+	#define PHYS_BUGRIGS_FRICTION_AIR 			getstatf(STAT_BUGRIGS_FRICTION_AIR)
+	#define PHYS_BUGRIGS_CAR_JUMPING 			getstatf(STAT_BUGRIGS_CAR_JUMPING)
+	#define PHYS_BUGRIGS_REVERSE_SPINNING 		getstatf(STAT_BUGRIGS_REVERSE_SPINNING)
+	#define PHYS_BUGRIGS_REVERSE_STOPPING 		getstatf(STAT_BUGRIGS_REVERSE_STOPPING)
+
 	#define PHYS_JUMPSPEEDCAP_MIN				getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MIN)
 	#define PHYS_JUMPSPEEDCAP_MAX				getstatf(STAT_MOVEVARS_JUMPSPEEDCAP_MAX)
 	#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS	getstati(STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS)
@@ -130,6 +150,8 @@ bool IsFlying(entity a);
 	#define PHYS_WARSOWBUNNY_TOPSPEED			getstatf(STAT_MOVEVARS_WARSOWBUNNY_TOPSPEED)
 	#define PHYS_WARSOWBUNNY_TURNACCEL			getstatf(STAT_MOVEVARS_WARSOWBUNNY_TURNACCEL)
 
+	#define PHYS_WALLFRICTION					getstati(STAT_MOVEVARS_WALLFRICTION)
+
 	#define PHYS_JETPACK_ACCEL_UP 				getstatf(STAT_JETPACK_ACCEL_UP)
 	#define PHYS_JETPACK_ACCEL_SIDE 			getstatf(STAT_JETPACK_ACCEL_SIDE)
 	#define PHYS_JETPACK_ANTIGRAVITY 			getstatf(STAT_JETPACK_ANTIGRAVITY)
@@ -139,6 +161,9 @@ bool IsFlying(entity a);
 
 	#define PHYS_DODGING_FROZEN					getstati(STAT_DODGING_FROZEN)
 
+	#define PHYS_NOSTEP							getstati(STAT_NOSTEP)
+	#define PHYS_JUMPSTEP						getstati(STAT_MOVEVARS_JUMPSTEP)
+
 #elif defined(SVQC)
 
 	.float stat_sv_airaccel_qw;
@@ -163,6 +188,29 @@ bool IsFlying(entity a);
 	.float stat_jetpack_maxspeed_up;
 	.float stat_jetpack_maxspeed_side;
 	.float stat_gameplayfix_easierwaterjump;
+	.float stat_gameplayfix_downtracesupportsongroundflag;
+	.float stat_gameplayfix_stepmultipletimes;
+	.float stat_gameplayfix_unstickplayers;
+	.float stat_gameplayfix_stepdown;
+
+	.float stat_bugrigs;
+	.float stat_bugrigs_angle_smoothing;
+	.float stat_bugrigs_planar_movement;
+	.float stat_bugrigs_reverse_speeding;
+	.float stat_bugrigs_friction_floor;
+	.float stat_bugrigs_air_steering;
+	.float stat_bugrigs_friction_brake;
+	.float stat_bugrigs_accel;
+	.float stat_bugrigs_speed_ref;
+	.float stat_bugrigs_speed_pow;
+	.float stat_bugrigs_steer;
+	.float stat_bugrigs_friction_air;
+	.float stat_bugrigs_car_jumping;
+	.float stat_bugrigs_reverse_spinning;
+	.float stat_bugrigs_reverse_stopping;
+
+	.float stat_nostep;
+	.float stat_jumpstep;
 
 	#define PHYS_INPUT_ANGLES(s)				s.v_angle
 	#define PHYS_WORLD_ANGLES(s)				s.angles
@@ -192,6 +240,10 @@ bool IsFlying(entity a);
 	#define GAMEPLAYFIX_NOGRAVITYONGROUND			cvar("sv_gameplayfix_nogravityonground")
 	#define GAMEPLAYFIX_Q2AIRACCELERATE				autocvar_sv_gameplayfix_q2airaccelerate
 	#define GAMEPLAYFIX_EASIERWATERJUMP				cvar("sv_gameplayfix_easierwaterjump")
+	#define GAMEPLAYFIX_DOWNTRACEONGROUND 			cvar("sv_gameplayfix_downtracesupportsongroundflag")
+	#define GAMEPLAYFIX_STEPMULTIPLETIMES 			cvar("sv_gameplayfix_stepmultipletimes")
+	#define GAMEPLAYFIX_UNSTICKPLAYERS 				cvar("sv_gameplayfix_unstickplayers")
+	#define GAMEPLAYFIX_STEPDOWN 					cvar("sv_gameplayfix_stepdown")
 
 	#define IS_DUCKED(s)    					s.crouch
 	#define SET_DUCKED(s)   					s.crouch = true
@@ -215,6 +267,22 @@ bool IsFlying(entity a);
 
 	#define PHYS_DOUBLEJUMP						autocvar_sv_doublejump
 
+	#define PHYS_BUGRIGS						g_bugrigs
+	#define PHYS_BUGRIGS_ANGLE_SMOOTHING		g_bugrigs_angle_smoothing
+	#define PHYS_BUGRIGS_PLANAR_MOVEMENT		g_bugrigs_planar_movement
+	#define PHYS_BUGRIGS_REVERSE_SPEEDING		g_bugrigs_reverse_speeding
+	#define PHYS_BUGRIGS_FRICTION_FLOOR			g_bugrigs_friction_floor
+	#define PHYS_BUGRIGS_AIR_STEERING			g_bugrigs_air_steering
+	#define PHYS_BUGRIGS_FRICTION_BRAKE			g_bugrigs_friction_brake
+	#define PHYS_BUGRIGS_ACCEL					g_bugrigs_accel
+	#define PHYS_BUGRIGS_SPEED_REF				g_bugrigs_speed_ref
+	#define PHYS_BUGRIGS_SPEED_POW				g_bugrigs_speed_pow
+	#define PHYS_BUGRIGS_STEER					g_bugrigs_steer
+	#define PHYS_BUGRIGS_FRICTION_AIR			g_bugrigs_friction_air
+	#define PHYS_BUGRIGS_CAR_JUMPING			g_bugrigs_planar_movement_car_jumping
+	#define PHYS_BUGRIGS_REVERSE_SPINNING		g_bugrigs_reverse_spinning
+	#define PHYS_BUGRIGS_REVERSE_STOPPING		g_bugrigs_reverse_stopping
+
 	#define PHYS_JUMPSPEEDCAP_MIN				autocvar_sv_jumpspeedcap_min
 	#define PHYS_JUMPSPEEDCAP_MAX				autocvar_sv_jumpspeedcap_max
 	#define PHYS_JUMPSPEEDCAP_DISABLE_ONRAMPS	autocvar_sv_jumpspeedcap_max_disable_on_ramps
@@ -250,6 +318,8 @@ bool IsFlying(entity a);
 	#define PHYS_WARSOWBUNNY_TOPSPEED			autocvar_sv_warsowbunny_topspeed
 	#define PHYS_WARSOWBUNNY_TURNACCEL			autocvar_sv_warsowbunny_turnaccel
 
+	#define PHYS_WALLFRICTION					cvar("sv_wallfriction")
+
 	#define PHYS_JETPACK_ACCEL_UP 				autocvar_g_jetpack_acceleration_up
 	#define PHYS_JETPACK_ACCEL_SIDE 			autocvar_g_jetpack_acceleration_side
 	#define PHYS_JETPACK_ANTIGRAVITY 			autocvar_g_jetpack_antigravity
@@ -259,5 +329,8 @@ bool IsFlying(entity a);
 
 	#define PHYS_DODGING_FROZEN					autocvar_sv_dodging_frozen
 
+	#define PHYS_NOSTEP							cvar("sv_nostep")
+	#define PHYS_JUMPSTEP						cvar("sv_jumpstep")
+
 #endif
 #endif
diff --git a/qcsrc/common/stats.qh b/qcsrc/common/stats.qh
index 0095c60a31..c3d67ca1a7 100644
--- a/qcsrc/common/stats.qh
+++ b/qcsrc/common/stats.qh
@@ -204,28 +204,28 @@ const int STAT_REVIVE_PROGRESS        = 106;
 // 166 empty?
 // 167 empty?
 // 168 empty?
-// 169 empty?
-// 170 empty?
-// 171 empty?
-// 172 empty?
-// 173 empty?
-// 174 empty?
-// 175 empty?
-// 176 empty?
-// 177 empty?
-// 178 empty?
-// 179 empty?
-// 180 empty?
-// 181 empty?
-// 182 empty?
-// 183 empty?
-// 184 empty?
-// 185 empty?
-// 186 empty?
-// 187 empty?
-// 188 empty?
-// 189 empty?
-const int STAT_GAMEPLAYFIX_EASIERWATERJUMP			  = 190;
+const int STAT_BUGRIGS_REVERSE_STOPPING               = 169;
+const int STAT_BUGRIGS_REVERSE_SPINNING               = 170;
+const int STAT_BUGRIGS_CAR_JUMPING                    = 171;
+const int STAT_BUGRIGS_FRICTION_AIR                   = 172;
+const int STAT_BUGRIGS_STEER                          = 173;
+const int STAT_BUGRIGS_SPEED_POW                      = 174;
+const int STAT_BUGRIGS_SPEED_REF                      = 175;
+const int STAT_BUGRIGS_ACCEL                          = 176;
+const int STAT_BUGRIGS_FRICTION_BRAKE                 = 177;
+const int STAT_BUGRIGS_AIR_STEERING                   = 178;
+const int STAT_BUGRIGS_FRICTION_FLOOR                 = 179;
+const int STAT_BUGRIGS_REVERSE_SPEEDING               = 180;
+const int STAT_BUGRIGS_PLANAR_MOVEMENT                = 181;
+const int STAT_BUGRIGS_ANGLE_SMOOTHING                = 182;
+const int STAT_BUGRIGS                                = 183;
+const int STAT_GAMEPLAYFIX_STEPDOWN                   = 184;
+const int STAT_MOVEVARS_JUMPSTEP                      = 185;
+const int STAT_NOSTEP                                 = 186;
+const int STAT_GAMEPLAYFIX_UNSTICKPLAYERS             = 187;
+const int STAT_GAMEPLAYFIX_STEPMULTIPLETIMES          = 188;
+const int STAT_GAMEPLAYFIX_DOWNTRACEONGROUND          = 189;
+const int STAT_GAMEPLAYFIX_EASIERWATERJUMP            = 190;
 const int STAT_MOVEVARS_FRICTION_SLICK                = 191;
 const int STAT_MOVEVARS_FRICTION_ONLAND               = 192;
 const int STAT_MOVEVARS_JUMPSPEEDCAP_DISABLE_ONRAMPS  = 193;
diff --git a/qcsrc/common/triggers/trigger/impulse.qc b/qcsrc/common/triggers/trigger/impulse.qc
index 6019885391..89ca2e03d6 100644
--- a/qcsrc/common/triggers/trigger/impulse.qc
+++ b/qcsrc/common/triggers/trigger/impulse.qc
@@ -35,10 +35,6 @@ void trigger_impulse_touch1()
 	other.lastpushtime = time;
 	if(!pushdeltatime) return;
 
-#ifdef CSQC
-	print("Touchie!\n");
-#endif
-
 	other.velocity = other.velocity + normalize(targ.origin - self.origin) * str * pushdeltatime;
 	other.flags &= ~FL_ONGROUND;
 #ifdef SVQC