Index: game/physics/Physics_Player.cpp
===================================================================
--- game/physics/Physics_Player.cpp	(Revision 6945)
+++ game/physics/Physics_Player.cpp	(Arbeitskopie)
@@ -283,6 +283,63 @@
 	planes[numplanes].Normalize();
 	numplanes++;
 
+	// BluePill : Push test tweaked for low frametimes (Proof of Concept, relies on hardcoded values)
+	// needs further testing for various framerates (including < 60fps) and whether it can negatively affect mission gameplay
+	if ( push && current.velocity.LengthSqr() > 0.0F )
+	{
+		// calculate the "real time" velocity as if the framerate was constantly 60fps
+		// idPhysics_RigidBody::Evaluate (-> idODE_*::Evaluate) already takes account of the frametime
+		// just applying current.velocity would cause the actual movement to be velocity*frametime˛ per frame, while it should be velocity*frametime.
+		idVec3 realtimeVelocity = current.velocity;
+		// prevent potential division by zero (minimum frametime should be 1ms)
+		if (frametime > 0.0001F)
+			realtimeVelocity *= (0.0166667f / frametime);
+
+		// BluePill : Hardcoded trace range of 15, need to test for different crouch/walk speeds
+		// calculate the end of the reachable range to push entities
+		end = current.origin + current.velocity * ( 15.0F / current.velocity.LengthFast() );
+
+		// see if we can make it there
+		gameLocal.clip.Translation( trace, current.origin, end, clipModel, clipModel->GetAxis(), clipMask, self );
+
+		// if we are not blocked by the world
+		if ( trace.c.entityNum != ENTITYNUM_WORLD ) {
+
+			clipModel->SetPosition( current.origin, clipModel->GetAxis() );
+
+			// clip movement, only push idMoveables, don't push entities the player is standing on
+			// apply impact to pushed objects
+			pushFlags = PUSHFL_CLIP | PUSHFL_ONLYMOVEABLE | PUSHFL_NOGROUNDENTITIES | PUSHFL_APPLYIMPULSE;
+
+			// clip & push
+
+			// greebo: Don't use the idPusher
+			//totalMass = gameLocal.push.ClipTranslationalPush( trace, self, pushFlags, end, end - current.origin, cv_pm_pushmod.GetFloat() );
+
+			// Set the trace result to zero, we're pushing into things here
+			// trace.fraction = 0.0f;
+			trace.endpos = current.origin;
+
+			// greebo: Check the entity in front of us
+			idEntity* pushedEnt = gameLocal.entities[trace.c.entityNum];
+			if (pushedEnt != NULL)
+			{
+				// Register the blocking physics object with our push force
+				m_PushForce->SetPushEntity(pushedEnt, 0);
+				m_PushForce->SetContactInfo(trace, realtimeVelocity);
+
+				totalMass = pushedEnt->GetPhysics()->GetMass();
+			}
+
+			if (totalMass > 0.0f) {
+				// decrease velocity based on the total mass of the objects being pushed ?
+				current.velocity *= 1.0f - idMath::ClampFloat(0.0f, 1000.0f, totalMass - 20.0f) * (1.0f / 950.0f);
+
+				pushed = true;
+			}
+		}
+	}
+
 	for ( bumpcount = 0; bumpcount < numbumps; bumpcount++ )
 	{
 		// calculate position we are trying to move to
@@ -391,7 +448,8 @@
 			}
 		}
 
-		// if we can push other entities and not blocked by the world
+		// original push test code; the new push test is located above this loop
+		/*// if we can push other entities and not blocked by the world
 		if ( push && trace.c.entityNum != ENTITYNUM_WORLD ) {
 
 			clipModel->SetPosition( current.origin, clipModel->GetAxis() );
@@ -401,7 +459,7 @@
 			pushFlags = PUSHFL_CLIP | PUSHFL_ONLYMOVEABLE | PUSHFL_NOGROUNDENTITIES | PUSHFL_APPLYIMPULSE;
 
 			// clip & push
-			
+
 			// greebo: Don't use the idPusher
 			//totalMass = gameLocal.push.ClipTranslationalPush( trace, self, pushFlags, end, end - current.origin, cv_pm_pushmod.GetFloat() );
 
@@ -425,7 +483,7 @@
 				current.velocity *= 1.0f - idMath::ClampFloat( 0.0f, 1000.0f, totalMass - 20.0f ) * ( 1.0f / 950.0f );
 				pushed = true;
 			}
-	
+
 			current.origin = trace.endpos;
 			time_left -= time_left * trace.fraction;
 
@@ -433,7 +491,7 @@
 			if ( trace.fraction >= 1.0f ) {
 				break;
 			}
-		}
+		}*/
 
 		if ( !stepped ) {
 			// let the entity know about the collision
