text: //========= Copyright Valve Corporation, All rights reserved. ============//
  //
  // Purpose: Physics simulation for non-havok/ipion objects
  //
  // $NoKeywords: $
  //=============================================================================//
  
  
  #include "cbase.h"
  #ifdef _WIN32
  #include "typeinfo.h"
  // BUGBUG: typeinfo stomps some of the warning settings (in yvals.h)
  #pragma warning(disable:4244)
  #elif POSIX
  #include <typeinfo>
  #else
  #error "need typeinfo defined"
  #endif
  
  #include "player.h"
  #include "ai_basenpc.h"
  #include "gamerules.h"
  #include "vphysics_interface.h"
  #include "mempool.h"
  #include "entitylist.h"
  #include "engine/IEngineSound.h"
  #include "datacache/imdlcache.h"
  #include "ispatialpartition.h"
  #include "tier0/vprof.h"
  #include "movevars_shared.h"
  #include "hierarchy.h"
  #include "trains.h"
  #include "vphysicsupdateai.h"
  #include "tier0/vcrmode.h"
  #include "pushentity.h"
  
  // memdbgon must be the last include file in a .cpp file!!!
  #include "tier0/memdbgon.h"
  
  extern ConVar think_limit;
  #ifdef _XBOX
  ConVar vprof_think_limit( "vprof_think_limit", "0" );
  #endif
  
  ConVar vprof_scope_entity_thinks( "vprof_scope_entity_thinks", "0" );
  ConVar vprof_scope_entity_gamephys( "vprof_scope_entity_gamephys", "0" );
  
  ConVar	npc_vphysics	( "npc_vphysics","0");
  //-----------------------------------------------------------------------------
  // helper method for trace hull as used by physics...
  //-----------------------------------------------------------------------------
  static void Physics_TraceEntity( CBaseEntity* pBaseEntity, const Vector &vecAbsStart,
  	const Vector &vecAbsEnd, unsigned int mask, trace_t *ptr )
  {
  	// FIXME: I really am not sure the best way of doing this
  	// The TraceHull code below for shots will make sure the object passes
  	// through shields which do not block that damage type. It will also 
  	// send messages to the shields that they've been hit.
  	if (pBaseEntity->GetDamageType() != DMG_GENERIC)
  	{
  		GameRules()->WeaponTraceEntity( pBaseEntity, vecAbsStart, vecAbsEnd, mask, ptr );
  	}
  	else
  	{
  		UTIL_TraceEntity( pBaseEntity, vecAbsStart, vecAbsEnd, mask, ptr );
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Does not change the entities velocity at all
  // Input  : push - 
  // Output : trace_t
  //-----------------------------------------------------------------------------
  static void PhysicsCheckSweep( CBaseEntity *pEntity, const Vector& vecAbsStart, const Vector &vecAbsDelta, trace_t *pTrace )
  {
  	unsigned int mask = pEntity->PhysicsSolidMaskForEntity();
  
  	Vector vecAbsEnd;
  	VectorAdd( vecAbsStart, vecAbsDelta, vecAbsEnd );
  
  	// Set collision type
  	if ( !pEntity->IsSolid() || pEntity->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS) )
  	{
  		if ( pEntity->GetMoveParent() )
  		{
  			UTIL_ClearTrace( *pTrace );
  			return;
  		}
  
  		// don't collide with monsters
  		mask &= ~CONTENTS_MONSTER;
  	}
  
  	Physics_TraceEntity( pEntity, vecAbsStart, vecAbsEnd, mask, pTrace );
  }
  
  CPhysicsPushedEntities s_PushedEntities;
  #ifndef TF_DLL
  CPhysicsPushedEntities *g_pPushedEntities = &s_PushedEntities;
  #endif
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  CPhysicsPushedEntities::CPhysicsPushedEntities( void ) : m_rgPusher(8, 8), m_rgMoved(32, 32)
  {
  	m_flMoveTime = -1.0f;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Store off entity and copy original origin to temporary array
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::AddEntity( CBaseEntity *ent )
  {
  	int i = m_rgMoved.AddToTail();
  	m_rgMoved[i].m_pEntity = ent;
  	m_rgMoved[i].m_vecStartAbsOrigin = ent->GetAbsOrigin();
  }
  
  
  //-----------------------------------------------------------------------------
  // Unlink + relink the pusher list so we can actually do the push
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::UnlinkPusherList( int *pPusherHandles )
  {
  	for ( int i = m_rgPusher.Count(); --i >= 0; )
  	{
  		pPusherHandles[i] = partition->HideElement( m_rgPusher[i].m_pEntity->CollisionProp()->GetPartitionHandle() );
  	}
  }
  
  void CPhysicsPushedEntities::RelinkPusherList( int *pPusherHandles )
  {
  	for ( int i = m_rgPusher.Count(); --i >= 0; )
  	{
  		partition->UnhideElement( m_rgPusher[i].m_pEntity->CollisionProp()->GetPartitionHandle(), pPusherHandles[i] );
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Compute the direction to move the rotation blocker
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::ComputeRotationalPushDirection( CBaseEntity *pBlocker, const RotatingPushMove_t &rotPushMove, Vector *pMove, CBaseEntity *pRoot )
  {
  	// calculate destination position
  	// "start" is relative to the *root* pusher, world orientation
  	Vector start = pBlocker->CollisionProp()->GetCollisionOrigin();
  	if ( pRoot->GetSolid() == SOLID_VPHYSICS )
  	{
  		// HACKHACK: Use move dir to guess which corner of the box determines contact and rotate the box so
  		// that corner remains in the same local position.
  		// BUGBUG: This will break, but not as badly as the previous solution!!!
  		Vector vecAbsMins, vecAbsMaxs;
  		pBlocker->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
  		start.x = (pMove->x < 0) ? vecAbsMaxs.x : vecAbsMins.x;
  		start.y = (pMove->y < 0) ? vecAbsMaxs.y : vecAbsMins.y;
  		start.z = (pMove->z < 0) ? vecAbsMaxs.z : vecAbsMins.z;
  		
  		CBasePlayer *pPlayer = ToBasePlayer(pBlocker);
  		if ( pPlayer )
  		{
  			// notify the player physics code so it can use vphysics to keep players from getting stuck
  			pPlayer->SetPhysicsFlag( PFLAG_GAMEPHYSICS_ROTPUSH, true );
  		}
  	}
  
  	// org is pusher local coordinate of start
  	Vector local;
  	// transform starting point into local space
  	VectorITransform( start, rotPushMove.startLocalToWorld, local );
  	// rotate local org into world space at end of rotation
  	Vector end;
  	VectorTransform( local, rotPushMove.endLocalToWorld, end );
  
  	// move is the difference (in world space) that the move will push this object
  	VectorSubtract( end, start, *pMove );
  }
  
  class CTraceFilterPushFinal : public CTraceFilterSimple
  {
  	DECLARE_CLASS( CTraceFilterPushFinal, CTraceFilterSimple );
  
  public:
  	CTraceFilterPushFinal( CBaseEntity *pEntity, int nCollisionGroup ) 
  		: CTraceFilterSimple( pEntity, nCollisionGroup )
  	{
  	
  	}
  
  	bool ShouldHitEntity( IHandleEntity *pHandleEntity, int contentsMask )
  	{
  		Assert( dynamic_cast<CBaseEntity*>(pHandleEntity) );
  		CBaseEntity *pTestEntity = static_cast<CBaseEntity*>(pHandleEntity);
  
  		// UNDONE: This should really filter to just the pushing entities
  		if ( pTestEntity->GetMoveType() == MOVETYPE_VPHYSICS && 
  			pTestEntity->VPhysicsGetObject() && pTestEntity->VPhysicsGetObject()->IsMoveable() )
  			return false;
  
  		return BaseClass::ShouldHitEntity( pHandleEntity, contentsMask );
  	}
  
  };
  
  bool CPhysicsPushedEntities::IsPushedPositionValid( CBaseEntity *pBlocker )
  {
  	CTraceFilterPushFinal pushFilter(pBlocker, pBlocker->GetCollisionGroup() );
  
  	trace_t trace;
  	UTIL_TraceEntity( pBlocker, pBlocker->GetAbsOrigin(), pBlocker->GetAbsOrigin(), pBlocker->PhysicsSolidMaskForEntity(), &pushFilter, &trace );
  
  	return !trace.startsolid;
  }
  
  //-----------------------------------------------------------------------------
  // Speculatively checks to see if all entities in this list can be pushed
  //-----------------------------------------------------------------------------
  bool CPhysicsPushedEntities::SpeculativelyCheckPush( PhysicsPushedInfo_t &info, const Vector &vecAbsPush, bool bRotationalPush )
  {
  	CBaseEntity *pBlocker = info.m_pEntity;
  
  	// See if it's possible to move the entity, but disable all pushers in the hierarchy first
  	int *pPusherHandles = (int*)stackalloc( m_rgPusher.Count() * sizeof(int) );
  	UnlinkPusherList( pPusherHandles );
  	CTraceFilterPushMove pushFilter(pBlocker, pBlocker->GetCollisionGroup() );
  
  	Vector pushDestPosition = pBlocker->GetAbsOrigin() + vecAbsPush;
  	UTIL_TraceEntity( pBlocker, pBlocker->GetAbsOrigin(), pushDestPosition, 
  		pBlocker->PhysicsSolidMaskForEntity(), &pushFilter, &info.m_Trace );
  
  	RelinkPusherList(pPusherHandles);
  	info.m_bPusherIsGround = false;
  	if ( pBlocker->GetGroundEntity() && pBlocker->GetGroundEntity()->GetRootMoveParent() == m_rgPusher[0].m_pEntity )
  	{
  		info.m_bPusherIsGround = true;
  	}
  
  	bool bIsUnblockable = (m_bIsUnblockableByPlayer && (pBlocker->IsPlayer() || pBlocker->MyNPCPointer())) ? true : false;
  	if ( bIsUnblockable )
  	{
  		pBlocker->SetAbsOrigin( pushDestPosition );
  	}
  	else
  	{
  		// Move the blocker into its new position
  		if ( info.m_Trace.fraction )
  		{
  			pBlocker->SetAbsOrigin( info.m_Trace.endpos );
  		}
  
  		// We're not blocked if the blocker is point-sized or non-solid
  		if ( pBlocker->IsPointSized() || !pBlocker->IsSolid() || 
  			pBlocker->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) )
  		{
  			return true;
  		}
  
  		if ( (!bRotationalPush) && (info.m_Trace.fraction == 1.0) )
  		{
  			//Assert( pBlocker->PhysicsTestEntityPosition() == false );
  			if ( !IsPushedPositionValid(pBlocker) )
  			{
  				Warning("Interpenetrating entities! (%s and %s)\n",
  					pBlocker->GetClassname(), m_rgPusher[0].m_pEntity->GetClassname() );
  			}
  
  			return true;
  		}
  	}
  
  	// Check to see if we're still blocked by the pushers
  	// FIXME: If the trace fraction == 0 can we early out also?
  	info.m_bBlocked = !IsPushedPositionValid(pBlocker);
  
  	if ( !info.m_bBlocked )
  		return true;
  
  	// if the player is blocking the train try nudging him around to fix accumulated error
  	if ( bIsUnblockable )
  	{
  		Vector org = pBlocker->GetAbsOrigin();
  		for ( int checkCount = 0; checkCount < 4; checkCount++ )
  		{
  			Vector move;
  			MatrixGetColumn( m_rgPusher[0].m_pEntity->EntityToWorldTransform(), checkCount>>1, move );
  			
  			// alternate movements 1/2" in each direction
  			float factor = ( checkCount & 1 ) ? -0.5f : 0.5f;
  			pBlocker->SetAbsOrigin( org + move * factor );
  			info.m_bBlocked = !IsPushedPositionValid(pBlocker);
  			if ( !info.m_bBlocked )
  				return true;
  		}
  		pBlocker->SetAbsOrigin( pushDestPosition );
  
  #ifndef TF_DLL
  		DevMsg(1, "Ignoring player blocking train!\n");
  #endif
  		return true;
  	}
  	return false;
  }
  
  
  //-----------------------------------------------------------------------------
  // Speculatively checks to see if all entities in this list can be pushed
  //-----------------------------------------------------------------------------
  bool CPhysicsPushedEntities::SpeculativelyCheckRotPush( const RotatingPushMove_t &rotPushMove, CBaseEntity *pRoot )
  {
  	Vector vecAbsPush;
  	m_nBlocker = -1;
  	for (int i = m_rgMoved.Count(); --i >= 0; )
  	{
  		ComputeRotationalPushDirection( m_rgMoved[i].m_pEntity, rotPushMove, &vecAbsPush, pRoot );
  		if (!SpeculativelyCheckPush( m_rgMoved[i], vecAbsPush, true ))
  		{
  			m_nBlocker = i;
  			return false;
  		}
  	}
  
  	return true;
  }
  
  
  //-----------------------------------------------------------------------------
  // Speculatively checks to see if all entities in this list can be pushed
  //-----------------------------------------------------------------------------
  bool CPhysicsPushedEntities::SpeculativelyCheckLinearPush( const Vector &vecAbsPush )
  {
  	m_nBlocker = -1;
  	for (int i = m_rgMoved.Count(); --i >= 0; )
  	{
  		if (!SpeculativelyCheckPush( m_rgMoved[i], vecAbsPush, false ))
  		{
  			m_nBlocker = i;
  			return false;
  		}
  	}
  
  	return true;
  }
  
  
  //-----------------------------------------------------------------------------
  // Causes all entities in the list to touch triggers from their prev position
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::FinishPushers()
  {
  	// We succeeded! Now that we know the final location of all entities,
  	// touch triggers + update physics objects + do other fixup
  	for ( int i = m_rgPusher.Count(); --i >= 0; )
  	{
  		PhysicsPusherInfo_t &info = m_rgPusher[i];
  
  		// Cause touch functions to be called
  		// FIXME: Need to make moved entities not touch triggers until we know we're ok
  		// FIXME: it'd be better for the engine to just have a touch method
  		info.m_pEntity->PhysicsTouchTriggers( &info.m_vecStartAbsOrigin );
  
  		info.m_pEntity->UpdatePhysicsShadowToCurrentPosition( gpGlobals->frametime );
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Causes all entities in the list to touch triggers from their prev position
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::FinishRotPushedEntity( CBaseEntity *pPushedEntity, const RotatingPushMove_t &rotPushMove )
  {
  	// Impart angular velocity of push onto pushed objects
  	if ( pPushedEntity->IsPlayer() )
  	{
  		QAngle angVel = pPushedEntity->GetLocalAngularVelocity();
  		angVel[1] = rotPushMove.amove[1];
  		pPushedEntity->SetLocalAngularVelocity(angVel);
  
  		// Look up associated client
  		CBasePlayer *player = ( CBasePlayer * )pPushedEntity;
  		player->pl.fixangle = FIXANGLE_RELATIVE;
  		// Because we can run multiple ticks per server frame, accumulate a total offset here instead of straight
  		//  setting it.  The engine will reset anglechange to 0 when the message is actually sent to the client
  		player->pl.anglechange += rotPushMove.amove;
  	}
  	else
  	{
  		QAngle angles = pPushedEntity->GetAbsAngles();
  		
  		// only rotate YAW with pushing.  Freely rotateable entities should either use VPHYSICS
  		// or be set up as children
  		angles.y += rotPushMove.amove.y;
  		pPushedEntity->SetAbsAngles( angles );
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Causes all entities in the list to touch triggers from their prev position
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::FinishPush( bool bIsRotPush, const RotatingPushMove_t *pRotPushMove )
  {
  	FinishPushers();
  
  	for ( int i = m_rgMoved.Count(); --i >= 0; )
  	{
  		PhysicsPushedInfo_t &info = m_rgMoved[i];
  		CBaseEntity *pPushedEntity = info.m_pEntity;
  
  		// Cause touch functions to be called
  		// FIXME: it'd be better for the engine to just have a touch method
  		info.m_pEntity->PhysicsTouchTriggers( &info.m_vecStartAbsOrigin );
  		info.m_pEntity->UpdatePhysicsShadowToCurrentPosition( gpGlobals->frametime );
  		CAI_BaseNPC *pNPC = info.m_pEntity->MyNPCPointer();
  		if ( info.m_bPusherIsGround && pNPC )
  		{
  			pNPC->NotifyPushMove();
  		}
  
  
  		// Register physics impacts...
  		if (info.m_Trace.m_pEnt)
  		{
  			pPushedEntity->PhysicsImpact( info.m_Trace.m_pEnt, info.m_Trace );
  		}
  
  		if (bIsRotPush)
  		{
  			FinishRotPushedEntity( pPushedEntity, *pRotPushMove );
  		}
  	}
  }
  
  // save initial state when beginning a push sequence
  void CPhysicsPushedEntities::BeginPush( CBaseEntity *pRoot )
  {
  	m_rgMoved.RemoveAll();
  	m_rgPusher.RemoveAll();
  
  	m_rootPusherStartLocalOrigin = pRoot->GetLocalOrigin();
  	m_rootPusherStartLocalAngles = pRoot->GetLocalAngles();
  	m_rootPusherStartLocaltime = pRoot->GetLocalTime();
  }
  
  // store off a list of what has changed - so vphysicsUpdate can undo this if the object gets blocked
  void CPhysicsPushedEntities::StoreMovedEntities( physicspushlist_t &list )
  {
  	list.localMoveTime = m_rootPusherStartLocaltime;
  	list.localOrigin = m_rootPusherStartLocalOrigin;
  	list.localAngles = m_rootPusherStartLocalAngles;
  	list.pushedCount = CountMovedEntities();
  	Assert(list.pushedCount < ARRAYSIZE(list.pushedEnts));
  	if ( list.pushedCount > ARRAYSIZE(list.pushedEnts) )
  	{
  		list.pushedCount = ARRAYSIZE(list.pushedEnts);
  	}
  	for ( int i = 0; i < list.pushedCount; i++ )
  	{
  		list.pushedEnts[i] = m_rgMoved[i].m_pEntity;
  		list.pushVec[i] = m_rgMoved[i].m_pEntity->GetAbsOrigin() - m_rgMoved[i].m_vecStartAbsOrigin;
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Registers a blockage
  //-----------------------------------------------------------------------------
  CBaseEntity *CPhysicsPushedEntities::RegisterBlockage()
  {
  	Assert(	m_nBlocker >= 0 );
  
  	// Generate a PhysicsImpact against the blocker...
  	PhysicsPushedInfo_t &info = m_rgMoved[m_nBlocker];
  	if ( info.m_Trace.m_pEnt )
  	{
  		info.m_pEntity->PhysicsImpact( info.m_Trace.m_pEnt, info.m_Trace );
  	}
  
  	// This is the dude 
  	return info.m_pEntity;
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Restore entities that might have been moved
  // Input  : fromrotation - if the move is from a rotation, then angular move must also be reverted
  //			*amove - 
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::RestoreEntities( )
  {
  	// Reset all of the pushed entities to get them back into place also
  	for ( int i = m_rgMoved.Count(); --i >= 0; )
  	{
  		m_rgMoved[ i ].m_pEntity->SetAbsOrigin( m_rgMoved[ i ].m_vecStartAbsOrigin );
  	}
  }
  
  
  
  
  //-----------------------------------------------------------------------------
  // Purpose: This is a trace filter that only hits an exclusive list of entities
  //-----------------------------------------------------------------------------
  class CTraceFilterAgainstEntityList : public ITraceFilter
  {
  public:
  	virtual bool ShouldHitEntity( IHandleEntity *pEntity, int contentsMask )
  	{
  		for ( int i = m_entityList.Count()-1; i >= 0; --i )
  		{
  			if ( m_entityList[i] == pEntity )
  				return true;
  		}
  
  		return false;
  	}
  
  	virtual TraceType_t	GetTraceType() const
  	{
  		return TRACE_ENTITIES_ONLY;
  	}
  
  	void AddEntityToHit( IHandleEntity *pEntity )
  	{
  		m_entityList.AddToTail(pEntity);
  	}
  
  	CUtlVector<IHandleEntity *>	m_entityList;
  };
  
  //-----------------------------------------------------------------------------
  // Generates a list of potential blocking entities
  //-----------------------------------------------------------------------------
  class CPushBlockerEnum : public IPartitionEnumerator
  {
  public:
  	CPushBlockerEnum( CPhysicsPushedEntities *pPushedEntities ) : m_pPushedEntities(pPushedEntities)
  	{
  		// All elements are part of the same hierarchy, so they all have
  		// the same root, so it doesn't matter which one we grab
  		m_pRootHighestParent = m_pPushedEntities->m_rgPusher[0].m_pEntity->GetRootMoveParent();
  		++s_nEnumCount;
  
  		m_collisionGroupCount = 0;
  		for ( int i = m_pPushedEntities->m_rgPusher.Count(); --i >= 0; )
  		{
  			if ( !m_pPushedEntities->m_rgPusher[i].m_pEntity->IsSolid() )
  				continue;
  
  			m_pushersOnly.AddEntityToHit( m_pPushedEntities->m_rgPusher[i].m_pEntity );
  			int collisionGroup = m_pPushedEntities->m_rgPusher[i].m_pEntity->GetCollisionGroup();
  			AddCollisionGroup(collisionGroup);
  		}
  
  	}
  
  	virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity )
  	{
  		CBaseEntity *pCheck = GetPushableEntity( pHandleEntity );
  		if ( !pCheck )
  			return ITERATION_CONTINUE;
  
  		// Mark it as seen
  		pCheck->m_nPushEnumCount = s_nEnumCount;
  		m_pPushedEntities->AddEntity( pCheck );
  
  		return ITERATION_CONTINUE;
  	}
  
  private:
  
  	inline void AddCollisionGroup(int collisionGroup)
  	{
  		for ( int i = 0; i < m_collisionGroupCount; i++ )
  		{
  			if ( m_collisionGroups[i] == collisionGroup )
  				return;
  		}
  		if ( m_collisionGroupCount < ARRAYSIZE(m_collisionGroups) )
  		{
  			m_collisionGroups[m_collisionGroupCount] = collisionGroup;
  			m_collisionGroupCount++;
  		}
  	}
  
  	bool IsStandingOnPusher( CBaseEntity *pCheck )
  	{
  		CBaseEntity *pGroundEnt = pCheck->GetGroundEntity();
  		if ( pCheck->GetFlags() & FL_ONGROUND || pGroundEnt )
  		{
  			for ( int i = m_pPushedEntities->m_rgPusher.Count(); --i >= 0; )
  			{
  				if (m_pPushedEntities->m_rgPusher[i].m_pEntity == pGroundEnt)
  				{
  					return true;
  				}
  			}
  		}
  		return false;
  	}
  
  	bool IntersectsPushers( CBaseEntity *pTest )
  	{
  		trace_t tr;
  
  		ICollideable *pCollision = pTest->GetCollideable();
  		enginetrace->SweepCollideable( pCollision, pTest->GetAbsOrigin(), pTest->GetAbsOrigin(), pCollision->GetCollisionAngles(), 
  			pTest->PhysicsSolidMaskForEntity(), &m_pushersOnly, &tr );
  
  		return tr.startsolid;
  	}
  
  	CBaseEntity *GetPushableEntity( IHandleEntity *pHandleEntity )
  	{
  		CBaseEntity *pCheck = gEntList.GetBaseEntity( pHandleEntity->GetRefEHandle() );
  		if ( !pCheck )
  			return NULL;
  
  		// Don't bother if we've already seen this one...
  		if (pCheck->m_nPushEnumCount == s_nEnumCount)
  			return NULL;
  
  		if ( !pCheck->IsSolid() )
  			return NULL;
  
  		if ( pCheck->GetMoveType() == MOVETYPE_PUSH || 
  			 pCheck->GetMoveType() == MOVETYPE_NONE || 
  			 pCheck->GetMoveType() == MOVETYPE_VPHYSICS ||
  			 pCheck->GetMoveType() == MOVETYPE_NOCLIP )
  		{
  			return NULL;
  		}
  
  		bool bCollide = false;
  		for ( int i = 0; i < m_collisionGroupCount; i++ )
  		{
  			if ( g_pGameRules->ShouldCollide( pCheck->GetCollisionGroup(), m_collisionGroups[i] ) )
  			{
  				bCollide = true;
  				break;
  			}
  		}
  		if ( !bCollide )
  			return NULL;
  		// We're not pushing stuff we're hierarchically attached to
  		CBaseEntity *pCheckHighestParent = pCheck->GetRootMoveParent();
  		if (pCheckHighestParent == m_pRootHighestParent)
  			return NULL;
  
  		// If we're standing on the pusher or any rigidly attached child
  		// of the pusher, we don't need to bother checking for interpenetration
  		if ( !IsStandingOnPusher(pCheck) )
  		{
  			// Our surrounding boxes are touching. But we may well not be colliding....
  			// see if the ent's bbox is inside the pusher's final position
  			if ( !IntersectsPushers( pCheck ) )
  				return NULL;
  		}
  
  		// NOTE: This is pretty tricky here. If a rigidly attached child comes into
  		// contact with a pusher, we *cannot* push the child. Instead, we must push
  		// the highest parent of that child.
  		return pCheckHighestParent;
  	}
  
  private:
  	static int s_nEnumCount;
  	CPhysicsPushedEntities *m_pPushedEntities;
  	CBaseEntity *m_pRootHighestParent;
  	CTraceFilterAgainstEntityList	m_pushersOnly;
  	int m_collisionGroups[8];
  	int m_collisionGroupCount;
  };
  
  int CPushBlockerEnum::s_nEnumCount = 0;
  
  //-----------------------------------------------------------------------------
  // Generates a list of potential blocking entities
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::GenerateBlockingEntityList()
  {
  	VPROF("CPhysicsPushedEntities::GenerateBlockingEntityList");
  
  	m_rgMoved.RemoveAll();
  	CPushBlockerEnum blockerEnum( this );
  
  	for ( int i = m_rgPusher.Count(); --i >= 0;  )
  	{
  		CBaseEntity *pPusher = m_rgPusher[i].m_pEntity;
  
  		// Don't bother if the pusher isn't solid
  		if ( !pPusher->IsSolid() || pPusher->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) )
  		{
  			continue;
  		}
  
  		Vector vecAbsMins, vecAbsMaxs;
  		pPusher->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
  		partition->EnumerateElementsInBox( PARTITION_ENGINE_NON_STATIC_EDICTS, vecAbsMins, vecAbsMaxs, false, &blockerEnum );
  
  		//Go back throught the generated list.
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Generates a list of potential blocking entities
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::GenerateBlockingEntityListAddBox( const Vector &vecMoved )
  {
  	VPROF("CPhysicsPushedEntities::GenerateBlockingEntityListAddBox");
  
  	m_rgMoved.RemoveAll();
  	CPushBlockerEnum blockerEnum( this );
  
  	for ( int i = m_rgPusher.Count(); --i >= 0;  )
  	{
  		CBaseEntity *pPusher = m_rgPusher[i].m_pEntity;
  
  		// Don't bother if the pusher isn't solid
  		if ( !pPusher->IsSolid() || pPusher->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) )
  		{
  			continue;
  		}
  
  		Vector vecAbsMins, vecAbsMaxs;
  		pPusher->CollisionProp()->WorldSpaceAABB( &vecAbsMins, &vecAbsMaxs );
  		for ( int iAxis = 0; iAxis < 3; ++iAxis )
  		{
  			if ( vecMoved[iAxis] >= 0.0f )
  			{
  				vecAbsMins[iAxis] -= vecMoved[iAxis];
  			}
  			else
  			{
  				vecAbsMaxs[iAxis] -= vecMoved[iAxis];
  			}
  		}
  
  		partition->EnumerateElementsInBox( PARTITION_ENGINE_NON_STATIC_EDICTS, vecAbsMins, vecAbsMaxs, false, &blockerEnum );
  
  		//Go back throught the generated list.
  	}
  }
  
  #ifdef TF_DLL
  #include "tf_logic_robot_destruction.h"
  #endif
  //-----------------------------------------------------------------------------
  // Purpose: Gets a list of all entities hierarchically attached to the root 
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::SetupAllInHierarchy( CBaseEntity *pParent )
  {
  	if (!pParent)
  		return;
  
  	VPROF("CPhysicsPushedEntities::SetupAllInHierarchy");
  
  	// Make sure to snack the position +before+ relink because applying the
  	// rotation (which occurs in relink) will put it at the final location
  	// NOTE: The root object at this point is actually at its final position.
  	// We'll fix that up later
  	int i = m_rgPusher.AddToTail();
  	m_rgPusher[i].m_pEntity = pParent;
  	m_rgPusher[i].m_vecStartAbsOrigin = pParent->GetAbsOrigin();
  
  	CBaseEntity *pChild;
  	for ( pChild = pParent->FirstMoveChild(); pChild != NULL; pChild = pChild->NextMovePeer() )
  	{
  		SetupAllInHierarchy( pChild );
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Rotates the root entity, fills in the pushmove structure
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::RotateRootEntity( CBaseEntity *pRoot, float movetime, RotatingPushMove_t &rotation )
  {
  	VPROF("CPhysicsPushedEntities::RotateRootEntity");
  
  	rotation.amove = pRoot->GetLocalAngularVelocity() * movetime;
  	rotation.origin = pRoot->GetAbsOrigin();
  
  	// Knowing the initial + ending basis is needed for determining
  	// which corner we're pushing 
  	MatrixCopy( pRoot->EntityToWorldTransform(), rotation.startLocalToWorld );
  
  	// rotate the pusher to it's final position
  	QAngle angles = pRoot->GetLocalAngles();
  	angles += pRoot->GetLocalAngularVelocity() * movetime;
  
  	pRoot->SetLocalAngles( angles );
  	
  	// Compute the change in absangles
  	MatrixCopy( pRoot->EntityToWorldTransform(), rotation.endLocalToWorld );
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Tries to rotate an entity hierarchy, returns the blocker if any
  //-----------------------------------------------------------------------------
  CBaseEntity *CPhysicsPushedEntities::PerformRotatePush( CBaseEntity *pRoot, float movetime )
  {
  	VPROF("CPhysicsPushedEntities::PerformRotatePush");
  
  	m_bIsUnblockableByPlayer = (pRoot->GetFlags() & FL_UNBLOCKABLE_BY_PLAYER) ? true : false;
  	// Build a list of this entity + all its children because we're going to try to move them all
  	// This will also make sure each entity is linked in the appropriate place
  	// with correct absboxes
  	m_rgPusher.RemoveAll();
  	SetupAllInHierarchy( pRoot );
  
  	// save where we rotated from, in case we're blocked
  	QAngle angPrevAngles = pRoot->GetLocalAngles();
  
  	// Apply the rotation
  	RotatingPushMove_t	rotPushMove;
  	RotateRootEntity( pRoot, movetime, rotPushMove );
  
  	// Next generate a list of all entities that could potentially be intersecting with
  	// any of the children in their new locations...
  	GenerateBlockingEntityList( );
  
  	// Now we have a unique list of things that could potentially block our push
  	// and need to be pushed out of the way. Lets try to push them all out of the way.
  	// If we fail, undo it all
  	if (!SpeculativelyCheckRotPush( rotPushMove, pRoot ))
  	{
  		CBaseEntity *pBlocker = RegisterBlockage();
  		pRoot->SetLocalAngles( angPrevAngles );
  		RestoreEntities( );
  		return pBlocker;
  	}
  
  	FinishPush( true, &rotPushMove );
  	return NULL;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Linearly moves the root entity
  //-----------------------------------------------------------------------------
  void CPhysicsPushedEntities::LinearlyMoveRootEntity( CBaseEntity *pRoot, float movetime, Vector *pAbsPushVector )
  {
  	VPROF("CPhysicsPushedEntities::LinearlyMoveRootEntity");
  
  	// move the pusher to it's final position
  	Vector move = pRoot->GetLocalVelocity() * movetime;
  	Vector origin = pRoot->GetLocalOrigin();
  	origin += move;		
  	pRoot->SetLocalOrigin( origin );
  
  	// Store off the abs push vector
  	*pAbsPushVector = pRoot->GetAbsVelocity() * movetime;
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Tries to linearly push an entity hierarchy, returns the blocker if any
  //-----------------------------------------------------------------------------
  CBaseEntity *CPhysicsPushedEntities::PerformLinearPush( CBaseEntity *pRoot, float movetime )
  {
  	VPROF("CPhysicsPushedEntities::PerformLinearPush");
  
  	m_flMoveTime = movetime;
  
  	m_bIsUnblockableByPlayer = (pRoot->GetFlags() & FL_UNBLOCKABLE_BY_PLAYER) ? true : false;
  	// Build a list of this entity + all its children because we're going to try to move them all
  	// This will also make sure each entity is linked in the appropriate place
  	// with correct absboxes
  	m_rgPusher.RemoveAll();
  	SetupAllInHierarchy( pRoot );
  
  	// save where we started from, in case we're blocked
  	Vector vecPrevOrigin = pRoot->GetLocalOrigin();
  
  	// Move the root (and all children) into its new position
  	Vector vecAbsPush;
  	LinearlyMoveRootEntity( pRoot, movetime, &vecAbsPush );
  
  	// Next generate a list of all entities that could potentially be intersecting with
  	// any of the children in their new locations...
  	GenerateBlockingEntityListAddBox( vecAbsPush );
  
  	// Now we have a unique list of things that could potentially block our push
  	// and need to be pushed out of the way. Lets try to push them all out of the way.
  	// If we fail, undo it all
  	if (!SpeculativelyCheckLinearPush( vecAbsPush ))
  	{
  		CBaseEntity *pBlocker = RegisterBlockage();
  		pRoot->SetLocalOrigin( vecPrevOrigin );
  		RestoreEntities();
  		return pBlocker;
  	}
  
  	FinishPush( );
  	return NULL;
  }
  
  
  
  //-----------------------------------------------------------------------------
  //
  // CBaseEntity methods
  //
  //-----------------------------------------------------------------------------
  
  //-----------------------------------------------------------------------------
  // Purpose: Called when it's time for a physically moved objects (plats, doors, etc)
  //			to run it's game code.
  //			All other entity thinking is done during worldspawn's think
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsDispatchThink( BASEPTR thinkFunc )
  {
  	VPROF_ENTER_SCOPE( ( !vprof_scope_entity_thinks.GetBool() ) ? 
  						"CBaseEntity::PhysicsDispatchThink" : 
  						EntityFactoryDictionary()->GetCannonicalName( GetClassname() ) );
  
  	float thinkLimit = think_limit.GetFloat();
  	
  	// The thinkLimit stuff makes a LOT of calls to Sys_FloatTime, which winds up calling into
  	// VCR mode so much that the framerate becomes unusable.
  	if ( VCRGetMode() != VCR_Disabled )
  		thinkLimit = 0;
  
  	float startTime = 0.0;
  
  	if ( IsDormant() )
  	{
  		Warning( "Dormant entity %s (%s) is thinking!!\n", GetClassname(), GetDebugName() );
  		Assert(0);
  	}
  
  	if ( thinkLimit )
  	{
  		startTime = engine->Time();
  	}
  	
  	if ( thinkFunc )
  	{
  		MDLCACHE_CRITICAL_SECTION();
  		(this->*thinkFunc)();
  	}
  
  	if ( thinkLimit )
  	{
  		// calculate running time of the AI in milliseconds
  		float time = ( engine->Time() - startTime ) * 1000.0f;
  		if ( time > thinkLimit )
  		{
  #if defined( _XBOX ) && !defined( _RETAIL )
  			if ( vprof_think_limit.GetBool() )
  			{
  				extern bool g_VProfSignalSpike;
  				g_VProfSignalSpike = true;
  			}
  #endif
  			// If its an NPC print out the shedule/task that took so long
  			CAI_BaseNPC *pNPC = MyNPCPointer();
  			if (pNPC && pNPC->GetCurSchedule())
  			{
  				pNPC->ReportOverThinkLimit( time );
  			}
  			else
  			{
  #ifdef _WIN32
  				Msg( "%s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).raw_name(), time );
  #elif POSIX
  				Msg( "%s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).name(), time );
  #else
  #error "typeinfo"
  #endif
  			}
  		}
  	}
  
  	VPROF_EXIT_SCOPE();
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Does not change the entities velocity at all
  // Input  : push - 
  // Output : trace_t
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsCheckSweep( const Vector& vecAbsStart, const Vector &vecAbsDelta, trace_t *pTrace )
  {
  	::PhysicsCheckSweep( this, vecAbsStart, vecAbsDelta, pTrace );
  }
  
  
  
  #define	MAX_CLIP_PLANES	5
  //-----------------------------------------------------------------------------
  // Purpose: The basic solid body movement attempt/clip that slides along multiple planes
  // Input  : time - Amount of time to try moving for
  //			*steptrace - if not NULL, the trace results of any vertical wall hit will be stored
  // Output : int - the clipflags if the velocity was modified (hit something solid)
  //   1 = floor
  //   2 = wall / step
  //   4 = dead stop
  //-----------------------------------------------------------------------------
  int CBaseEntity::PhysicsTryMove( float flTime, trace_t *steptrace )
  {
  	VPROF("CBaseEntity::PhysicsTryMove");
  
  	int			bumpcount, numbumps;
  	Vector		dir;
  	float		d;
  	int			numplanes;
  	Vector		planes[MAX_CLIP_PLANES];
  	Vector		primal_velocity, original_velocity, new_velocity;
  	int			i, j;
  	trace_t		trace;
  	Vector		end;
  	float		time_left;
  	int			blocked;
  	
  	unsigned int mask = PhysicsSolidMaskForEntity();
  
  	new_velocity.Init();
  
  	numbumps = 4;
  
  	Vector vecAbsVelocity = GetAbsVelocity();
  
  	blocked = 0;
  	VectorCopy (vecAbsVelocity, original_velocity);
  	VectorCopy (vecAbsVelocity, primal_velocity);
  	numplanes = 0;
  	
  	time_left = flTime;
  
  	for (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)
  	{
  		if (vecAbsVelocity == vec3_origin)
  			break;
  
  		VectorMA( GetAbsOrigin(), time_left, vecAbsVelocity, end );
  
  		Physics_TraceEntity( this, GetAbsOrigin(), end, mask, &trace );
  
  		if (trace.startsolid)
  		{	// entity is trapped in another solid
  			SetAbsVelocity(vec3_origin);
  			return 4;
  		}
  
  		if (trace.fraction > 0)
  		{	// actually covered some distance
  			SetAbsOrigin( trace.endpos );
  			VectorCopy (vecAbsVelocity, original_velocity);
  			numplanes = 0;
  		}
  
  		if (trace.fraction == 1)
  			 break;		// moved the entire distance
  
  		if (!trace.m_pEnt)
  		{
  			SetAbsVelocity( vecAbsVelocity );
  			Warning( "PhysicsTryMove: !trace.u.ent" );
  			Assert(0);
  			return 4;
  		}
  
  		if (trace.plane.normal[2] > 0.7)
  		{
  			blocked |= 1;		// floor
  			if (CanStandOn( trace.m_pEnt ))
  			{
  				// keep track of time when changing ground entity
  				if (GetGroundEntity() != trace.m_pEnt)
  				{
  					SetGroundChangeTime( gpGlobals->curtime + (flTime - (1 - trace.fraction) * time_left) );
  				}
  
  				SetGroundEntity( trace.m_pEnt );
  			}
  		}
  		if (!trace.plane.normal[2])
  		{
  			blocked |= 2;		// step
  			if (steptrace)
  				*steptrace = trace;	// save for player extrafriction
  		}
  
  		// run the impact function
  		PhysicsImpact( trace.m_pEnt, trace );
  		// Removed by the impact function
  		if ( IsMarkedForDeletion() || IsEdictFree() )
  			break;		
  	
  		time_left -= time_left * trace.fraction;
  		
  		// clipped to another plane
  		if (numplanes >= MAX_CLIP_PLANES)
  		{	// this shouldn't really happen
  			SetAbsVelocity(vec3_origin);
  			return blocked;
  		}
  
  		VectorCopy (trace.plane.normal, planes[numplanes]);
  		numplanes++;
  
  		// modify original_velocity so it parallels all of the clip planes
  		if ( GetMoveType() == MOVETYPE_WALK && (!(GetFlags() & FL_ONGROUND) || GetFriction()!=1) )	// relfect player velocity
  		{
  			for ( i = 0; i < numplanes; i++ )
  			{
  				if ( planes[i][2] > 0.7  )
  				{// floor or slope
  					PhysicsClipVelocity( original_velocity, planes[i], new_velocity, 1 );
  					VectorCopy( new_velocity, original_velocity );
  				}
  				else
  				{
  					PhysicsClipVelocity( original_velocity, planes[i], new_velocity, 1.0 + sv_bounce.GetFloat() * (1-GetFriction()) );
  				}
  			}
  
  			VectorCopy( new_velocity, vecAbsVelocity );
  			VectorCopy( new_velocity, original_velocity );
  		}
  		else
  		{
  			for (i=0 ; i<numplanes ; i++)
  			{
  				PhysicsClipVelocity (original_velocity, planes[i], new_velocity, 1);
  				for (j=0 ; j<numplanes ; j++)
  					if (j != i)
  					{
  						if (DotProduct (new_velocity, planes[j]) < 0)
  							break;	// not ok
  					}
  				if (j == numplanes)
  					break;
  			}
  			
  			if (i != numplanes)
  			{	
  				// go along this plane
  				VectorCopy (new_velocity, vecAbsVelocity);
  			}
  			else
  			{	
  				// go along the crease
  				if (numplanes != 2)
  				{
  	//				Msg( "clip velocity, numplanes == %i\n",numplanes);
  					SetAbsVelocity( vecAbsVelocity );
  					return blocked;
  				}
  				CrossProduct (planes[0], planes[1], dir);
  				d = DotProduct (dir, vecAbsVelocity);
  				VectorScale (dir, d, vecAbsVelocity);
  			}
  
  			//
  			// if original velocity is against the original velocity, stop dead
  			// to avoid tiny oscillations in sloping corners
  			//
  			if (DotProduct (vecAbsVelocity, primal_velocity) <= 0)
  			{
  				SetAbsVelocity(vec3_origin);
  				return blocked;
  			}
  		}
  	}
  
  	SetAbsVelocity( vecAbsVelocity );
  	return blocked;
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Applies 1/2 gravity to falling movetype step objects
  //			Simulation should be done assuming average velocity over the time 
  //			interval.  Since that would effect a lot of code, and since most of 
  //			that code is going away, it's easier to just add in the average effect 
  //			of gravity on the velocity over the interval at the beginning of similation, 
  //			then add it in again at the end of simulation so that the final velocity is
  //			correct for the entire interval.
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsAddHalfGravity( float timestep )
  {
  	VPROF("CBaseEntity::PhysicsAddHalfGravity");
  	float	ent_gravity;
  
  	if ( GetGravity() )
  	{
  		ent_gravity = GetGravity();
  	}
  	else
  	{
  		ent_gravity = 1.0;
  	}
  
  	// Add 1/2 of the total gravitational effects over this timestep
  	Vector vecAbsVelocity = GetAbsVelocity();
  	vecAbsVelocity[2] -= ( 0.5 * ent_gravity * GetCurrentGravity() * timestep );
  	vecAbsVelocity[2] += GetBaseVelocity()[2] * gpGlobals->frametime;
  	SetAbsVelocity( vecAbsVelocity );
  
  	Vector vecNewBaseVelocity = GetBaseVelocity();
  	vecNewBaseVelocity[2] = 0;
  	SetBaseVelocity( vecNewBaseVelocity );
  	
  	// Bound velocity
  	PhysicsCheckVelocity();
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Does not change the entities velocity at all
  // Input  : push - 
  // Output : trace_t
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsPushEntity( const Vector& push, trace_t *pTrace )
  {
  	VPROF("CBaseEntity::PhysicsPushEntity");
  
  	if ( GetMoveParent() )
  	{
  		Warning( "pushing entity (%s) that has parent (%s)!\n", GetDebugName(), GetMoveParent()->GetDebugName() );
  		Assert(0);
  	}
  
  	// NOTE: absorigin and origin must be equal because there is no moveparent
  	Vector prevOrigin;
  	VectorCopy( GetAbsOrigin(), prevOrigin );
  
  	::PhysicsCheckSweep( this, prevOrigin, push, pTrace );
  
  	if ( pTrace->fraction )
  	{
  		SetAbsOrigin( pTrace->endpos );
  
  		// FIXME(ywb):  Should we try to enable this here
  		// WakeRestingObjects();
  	}
  
  	// Passing in the previous abs origin here will cause the relinker
  	// to test the swept ray from previous to current location for trigger intersections
  	PhysicsTouchTriggers( &prevOrigin );
  
  	if ( pTrace->m_pEnt )
  	{
  		PhysicsImpact( pTrace->m_pEnt, *pTrace );
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose:  See if entity is inside another entity, if so, returns true if so, fills in *ppEntity if ppEntity is not NULL
  // Input  : **ppEntity - optional return pointer to entity we are inside of
  // Output : Returns true on success, false on failure.
  //-----------------------------------------------------------------------------
  bool CBaseEntity::PhysicsTestEntityPosition( CBaseEntity **ppEntity /*=NULL*/ )
  {
  	VPROF("CBaseEntity::PhysicsTestEntityPosition");
  
  	trace_t	trace;
  	
  	unsigned int mask = PhysicsSolidMaskForEntity();
  
  	Physics_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), mask, &trace );
  	
  	if ( trace.startsolid )
  	{
  		if ( ppEntity )
  		{
  			*ppEntity = trace.m_pEnt;
  		}
  		return true;
  	}
  		
  	return false;
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  //-----------------------------------------------------------------------------
  CBaseEntity *CBaseEntity::PhysicsPushMove( float movetime )
  {
  	VPROF("CBaseEntity::PhysicsPushMove");
  
  	// If this entity isn't moving, just update the time.
  	IncrementLocalTime( movetime );
  
  	if ( GetLocalVelocity() == vec3_origin )
  	{
  		return NULL;
  	}
  
  	// Now check that the entire hierarchy can rotate into the new location
  	CBaseEntity *pBlocker = g_pPushedEntities->PerformLinearPush( this, movetime );
  	if ( pBlocker )
  	{
  		IncrementLocalTime( -movetime );
  	}
  	return pBlocker;
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Tries to rotate, returns success or failure
  // Input  : movetime - 
  // Output : bool
  //-----------------------------------------------------------------------------
  CBaseEntity *CBaseEntity::PhysicsPushRotate( float movetime )
  {
  	VPROF("CBaseEntity::PhysicsPushRotate");
  
  	IncrementLocalTime( movetime );
  
  	// Not rotating
  	if ( GetLocalAngularVelocity() == vec3_angle )
  	{
  		return NULL;
  	}
  
  	// Now check that the entire hierarchy can rotate into the new location
  	CBaseEntity *pBlocker = g_pPushedEntities->PerformRotatePush( this, movetime );
  	if ( pBlocker )
  	{
  		IncrementLocalTime( -movetime );
  	}
  
  	return pBlocker;
  }
  
  
  //-----------------------------------------------------------------------------
  // Block of icky shared code from PhysicsParent + PhysicsPusher
  //-----------------------------------------------------------------------------
  void CBaseEntity::PerformPush( float movetime )
  {
  	VPROF("CBaseEntity::PerformPush");
  	// NOTE: Use handle index because the previous blocker could have been deleted
  	int hPrevBlocker = m_pBlocker.ToInt();
  	CBaseEntity *pBlocker;
  	g_pPushedEntities->BeginPush( this );
  	if (movetime > 0)
  	{
  		if ( GetLocalAngularVelocity() != vec3_angle )
  		{
  			if ( GetLocalVelocity() != vec3_origin )
  			{
  				// NOTE: Both PhysicsPushRotate + PhysicsPushMove
  				// will attempt to advance local time. Choose the one that's
  				// the greater of the two from push + move
  
  				// FIXME: Should we really be doing them both simultaneously??
  				// FIXME: Choose the *greater* of the two?!? That's strange...
  				float flInitialLocalTime = m_flLocalTime;
  
  				// moving and rotating, so rotate first, then move
  				pBlocker = PhysicsPushRotate( movetime );
  				if ( !pBlocker )
  				{
  					float flRotateLocalTime = m_flLocalTime;
  
  					// Reset the local time to what it was before we rotated
  					m_flLocalTime = flInitialLocalTime;
  					pBlocker = PhysicsPushMove( movetime );
  					if ( m_flLocalTime < flRotateLocalTime )
  					{
  						m_flLocalTime = flRotateLocalTime;
  					}
  				}
  			}
  			else
  			{
  				// only rotating
  				pBlocker = PhysicsPushRotate( movetime );
  			}
  		}
  		else
  		{
  			// only moving
  			pBlocker = PhysicsPushMove( movetime );
  		}
  
  		m_pBlocker = pBlocker;
  		if (m_pBlocker.ToInt() != hPrevBlocker)
  		{
  			if (hPrevBlocker != INVALID_EHANDLE_INDEX)
  			{
  				EndBlocked();
  			}
  			if (m_pBlocker)
  			{
  				StartBlocked( pBlocker );
  			}
  		}
  		if (m_pBlocker)
  		{
  			Blocked( m_pBlocker );
  		}
  
  		// NOTE NOTE: This is here for brutal reasons.
  		// For MOVETYPE_PUSH objects with VPhysics shadow objects, the move done time
  		// is handled by CBaseEntity::VPhyicsUpdatePusher, which only gets called if
  		// the physics system thinks the entity is awake. That will happen if the
  		// shadow gets updated, but the push code above doesn't update unless the
  		// move is successful or non-zero. So we must make sure it's awake
  		if ( VPhysicsGetObject() )
  		{
  			VPhysicsGetObject()->Wake();
  		}
  	}
  
  	// move done is handled by physics if it has any
  	if ( VPhysicsGetObject() )
  	{
  		// store the list of moved entities for later
  		// if you actually did an unblocked push that moved entities, and you're using physics (which may block later)
  		if ( movetime > 0 && !m_pBlocker && GetSolid() == SOLID_VPHYSICS && g_pPushedEntities->CountMovedEntities() > 0 )
  		{
  			// UNDONE: Any reason to want to call this twice before physics runs?
  			// If so, maybe just append to the list?
  			Assert( !GetDataObject( PHYSICSPUSHLIST ) );
  			physicspushlist_t *pList = (physicspushlist_t *)CreateDataObject( PHYSICSPUSHLIST );
  			if ( pList )
  			{
  				g_pPushedEntities->StoreMovedEntities( *pList );
  			}
  		}
  	}
  	else
  	{
  		if ( m_flMoveDoneTime <= m_flLocalTime && m_flMoveDoneTime > 0 )
  		{
  			SetMoveDoneTime( -1 );
  			MoveDone();
  		}
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: UNDONE: This is only different from PhysicsParent because of the callback to PhysicsVelocity()
  // Can we support that callback in push objects as well?
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsPusher( void )
  {
  	VPROF("CBaseEntity::PhysicsPusher");
  
  	// regular thinking
  	if ( !PhysicsRunThink() )
  		return;
  
  	m_flVPhysicsUpdateLocalTime = m_flLocalTime;
  
  	float movetime = GetMoveDoneTime();
  	if (movetime > gpGlobals->frametime)
  	{
  		movetime = gpGlobals->frametime;
  	}
  
  	PerformPush( movetime );
  }
  
  
  
  //-----------------------------------------------------------------------------
  // Purpose: Non moving objects can only think
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsNone( void )
  {
  	VPROF("CBaseEntity::PhysicsNone");
  
  	// regular thinking
  	PhysicsRunThink();
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: A moving object that doesn't obey physics
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsNoclip( void )
  {
  	VPROF("CBaseEntity::PhysicsNoclip");
  
  	// regular thinking
  	if ( !PhysicsRunThink() )
  	{
  		return;
  	}
  	
  	// Apply angular velocity
  	SimulateAngles( gpGlobals->frametime );
  
  	Vector origin;
  	VectorMA( GetLocalOrigin(), gpGlobals->frametime, GetLocalVelocity(), origin );
  	SetLocalOrigin( origin );
  }
  
  
  void CBaseEntity::PerformCustomPhysics( Vector *pNewPosition, Vector *pNewVelocity, QAngle *pNewAngles, QAngle *pNewAngVelocity )
  {
  	// If you're going to use custom physics, you need to implement this!
  	Assert(0);
  }
  
  
  //-----------------------------------------------------------------------------
  // Allows entities to describe their own physics
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsCustom()
  {
  	VPROF("CBaseEntity::PhysicsCustom");
  	PhysicsCheckWater();
  
  	// regular thinking
  	if ( !PhysicsRunThink() )
  		return;
  
  	// Moving upward, off the ground, or  resting on a client/monster, remove FL_ONGROUND
  	if ( m_vecVelocity[2] > 0 || !GetGroundEntity() || !GetGroundEntity()->IsStandable() )
  	{
  		SetGroundEntity( NULL );
  	}
  
  	// NOTE: The entity must set the position, angles, velocity in its custom movement
  	Vector vecNewPosition = GetAbsOrigin();
  	Vector vecNewVelocity = GetAbsVelocity();
  	QAngle angNewAngles = GetAbsAngles();
  	QAngle angNewAngVelocity = GetLocalAngularVelocity();
  
  	PerformCustomPhysics( &vecNewPosition, &vecNewVelocity, &angNewAngles, &angNewAngVelocity );
  
  	// Store off all of the new state information...
  	SetAbsVelocity( vecNewVelocity );
  	SetAbsAngles( angNewAngles );
  	SetLocalAngularVelocity( angNewAngVelocity );
  
  	Vector move;
  	VectorSubtract( vecNewPosition, GetAbsOrigin(), move );
  
  	// move origin
  	trace_t trace;
  	PhysicsPushEntity( move, &trace );
  
  	PhysicsCheckVelocity();
  
  	if (trace.allsolid)
  	{	
  		// entity is trapped in another solid
  		// UNDONE: does this entity needs to be removed?
  		SetAbsVelocity(vec3_origin);
  		SetLocalAngularVelocity(vec3_angle);
  		return;
  	}
  	
  	if (IsEdictFree())
  		return;
  
  	// check for in water
  	PhysicsCheckWaterTransition();
  }
  
  bool g_bTestMoveTypeStepSimulation = true;
  ConVar sv_teststepsimulation( "sv_teststepsimulation", "1", 0 );
  
  //-----------------------------------------------------------------------------
  // Purpose: Until we remove the above cvar, we need to have the entities able
  //  to dynamically deal with changing their simulation stuff here.
  //-----------------------------------------------------------------------------
  void CBaseEntity::CheckStepSimulationChanged()
  {
  	if ( g_bTestMoveTypeStepSimulation != IsSimulatedEveryTick() )
  	{
  		SetSimulatedEveryTick( g_bTestMoveTypeStepSimulation );
  	}
  
  	bool hadobject = HasDataObjectType( STEPSIMULATION );
  
  	if ( g_bTestMoveTypeStepSimulation )
  	{
  		if ( !hadobject )
  		{
  			CreateDataObject( STEPSIMULATION );
  		}
  	}
  	else
  	{
  		if ( hadobject )
  		{
  			DestroyDataObject( STEPSIMULATION );
  		}
  	}
  }
  
  
  #define STEP_TELPORTATION_VEL_SQ	( 4096.0f * 4096.0f )
  //-----------------------------------------------------------------------------
  // Purpose: Run regular think and latch off angle/origin changes so we can interpolate them on the server to fake simulation
  // Input  : *step - 
  //-----------------------------------------------------------------------------
  void CBaseEntity::StepSimulationThink( float dt )
  {
  	// See if we need to allocate, deallocate step simulation object
  	CheckStepSimulationChanged();
  
  	StepSimulationData *step = ( StepSimulationData * )GetDataObject( STEPSIMULATION );
  	if ( !step )
  	{
  		PhysicsStepRunTimestep( dt );
  
  		// Just call the think function directly
  		PhysicsRunThink( THINK_FIRE_BASE_ONLY );
  	}
  	else
  	{
  		// Assume that it's in use
  		step->m_bOriginActive = true;
  		step->m_bAnglesActive = true;
  
  		// Reset networked versions of origin and angles
  		step->m_nLastProcessTickCount = -1;
  		step->m_vecNetworkOrigin.Init();
  		step->m_angNetworkAngles.Init();
  
  		// Remember old old values
  		step->m_Previous2 = step->m_Previous;
  
  		// Remember old values
  		step->m_Previous.nTickCount = gpGlobals->tickcount;
  		step->m_Previous.vecOrigin = GetStepOrigin();
  		QAngle stepAngles = GetStepAngles();
  		AngleQuaternion( stepAngles, step->m_Previous.qRotation );
  
  		// Run simulation
  		PhysicsStepRunTimestep( dt );
  
  		// Call the actual think function...
  		PhysicsRunThink( THINK_FIRE_BASE_ONLY );
  
  		// do any local processing that's needed
  		if (GetBaseAnimating() != NULL)
  		{
  			GetBaseAnimating()->UpdateStepOrigin();
  		}
  
  		// Latch new values to see if external code modifies our position/orientation
  		step->m_Next.vecOrigin = GetStepOrigin();
  		stepAngles = GetStepAngles();
  		AngleQuaternion( stepAngles, step->m_Next.qRotation );
  		// Also store of non-Quaternion version for simple comparisons
  		step->m_angNextRotation = GetStepAngles();
  		step->m_Next.nTickCount = GetNextThinkTick();
  
  		// Hack:  Add a tick if we are simulating every other tick
  		if ( CBaseEntity::IsSimulatingOnAlternateTicks() )
  		{
  			++step->m_Next.nTickCount;
  		}
  
  		// Check for teleportation/snapping of the origin
  		if ( dt > 0.0f )
  		{
  			Vector deltaorigin = step->m_Next.vecOrigin - step->m_Previous.vecOrigin;
  			float velSq = deltaorigin.LengthSqr() / ( dt * dt );
  			if ( velSq >= STEP_TELPORTATION_VEL_SQ )
  			{
  				// Deactivate it due to large origin change
  				step->m_bOriginActive = false;
  				step->m_bAnglesActive = false;
  			}
  		}
  	}
  }
  
  //-----------------------------------------------------------------------------
  // Purpose: Monsters freefall when they don't have a ground entity, otherwise
  //   all movement is done with discrete steps.
  // This is also used for objects that have become still on the ground, but
  //  will fall if the floor is pulled out from under them.
  // JAY: Extended this to synchronize movement and thinking wherever possible.
  // This allows the client-side interpolation to interpolate animation and simulation
  // data at the same time.
  // UNDONE:	Remove all other cases from this loop - only use MOVETYPE_STEP to simulate
  //			entities that are currently animating/thinking.
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsStep()
  {
  	// EVIL HACK: Force these to appear as if they've changed!!!
  	// The underlying values don't actually change, but we need the network sendproxy on origin/angles
  	//  to get triggered, and that only happens if NetworkStateChanged() appears to have occured.
  	// Getting them for modify marks them as changed automagically.
  	m_vecOrigin.GetForModify();
  	m_angRotation.GetForModify();
  	
  	// HACK:  Make sure that the client latches the networked origin/orientation changes with the current server tick count
  	//  so that we don't get jittery interpolation.  All of this is necessary to mimic actual continuous simulation of the underlying
  	//  variables.
  	SetSimulationTime( gpGlobals->curtime );
  	
  	// Run all but the base think function
  	PhysicsRunThink( THINK_FIRE_ALL_BUT_BASE );
  
  	int thinktick = GetNextThinkTick();
  	float thinktime = thinktick * TICK_INTERVAL;
  
  	// Is the next think too far out, or non-existent?
  	// BUGBUG: Interpolation is going to look bad in here.  But it should only
  	// be for dead things - and those should be ragdolls (client-side sim) anyway.
  	// UNDONE: Remove this and assert?  Force MOVETYPE_STEP objs to become MOVETYPE_TOSS when
  	// they aren't thinking?
  	// UNDONE: this happens as the first frame for a bunch of things like dynamically created ents.
  	// can't remove until initial conditions are resolved
  	float deltaThink = thinktime - gpGlobals->curtime;
  	if ( thinktime <= 0 || deltaThink > 0.5 )
  	{
  		PhysicsStepRunTimestep( gpGlobals->frametime );
  		PhysicsCheckWaterTransition();
  		SetLastThink( -1, gpGlobals->curtime );
  		UpdatePhysicsShadowToCurrentPosition(gpGlobals->frametime);
  		PhysicsRelinkChildren(gpGlobals->frametime);
  		return;
  	}
  
  	Vector oldOrigin = GetAbsOrigin();
  
  	// Feed the position delta back from vphysics if enabled
  	bool updateFromVPhysics = npc_vphysics.GetBool();
  	if ( HasDataObjectType(VPHYSICSUPDATEAI) )
  	{
  		vphysicsupdateai_t *pUpdate = static_cast<vphysicsupdateai_t *>(GetDataObject( VPHYSICSUPDATEAI ));
  		if ( pUpdate->stopUpdateTime > gpGlobals->curtime )
  		{
  			updateFromVPhysics = true;
  		}
  		else
  		{
  			float maxAngular;
  			VPhysicsGetObject()->GetShadowController()->GetMaxSpeed( NULL, &maxAngular );
  			VPhysicsGetObject()->GetShadowController()->MaxSpeed( pUpdate->savedShadowControllerMaxSpeed, maxAngular );
  			DestroyDataObject(VPHYSICSUPDATEAI);
  		}
  	}
  
  	if ( updateFromVPhysics && VPhysicsGetObject() && !GetParent() )
  	{
  		Vector position;
  		VPhysicsGetObject()->GetShadowPosition( &position, NULL );
  		float delta = (GetAbsOrigin() - position).LengthSqr();
  		// for now, use a tolerance of 1 inch for these tests
  		if ( delta < 1 )
  		{
  			// physics is really close, check to see if my current position is valid.
  			// If so, ignore the physics result.
  			trace_t tr;
  			Physics_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), PhysicsSolidMaskForEntity(), &tr );
  			updateFromVPhysics = tr.startsolid;
  		}
  		if ( updateFromVPhysics )
  		{
  			SetAbsOrigin( position );
  			PhysicsTouchTriggers();
  		}
  		//NDebugOverlay::Box( position, WorldAlignMins(), WorldAlignMaxs(), 255, 255, 0, 0, 0.0 );
  	}
  
  	// not going to think, don't run game physics either
  	if ( thinktick > gpGlobals->tickcount )
  		return;
  	
  	// Don't let things stay in the past.
  	//  it is possible to start that way
  	//  by a trigger with a local time.
  	if ( thinktime < gpGlobals->curtime )
  	{
  		thinktime = gpGlobals->curtime;	
  	}
  
  	// simulate over the timestep
  	float dt = thinktime - GetLastThink();
  
  	// Now run step simulator
  	StepSimulationThink( dt );
  
  	PhysicsCheckWaterTransition();
  
  	if ( VPhysicsGetObject() )
  	{
  		if ( !VectorCompare( oldOrigin, GetAbsOrigin() ) )
  		{
  			VPhysicsGetObject()->UpdateShadow( GetAbsOrigin(), vec3_angle, (GetFlags() & FL_FLY) ? true : false, dt );
  		}
  	}
  	PhysicsRelinkChildren(dt);
  }
  
  
  void UTIL_TraceLineFilterEntity( CBaseEntity *pEntity, const Vector &vecAbsStart, const Vector &vecAbsEnd, 
  					   unsigned int mask, const int nCollisionGroup, trace_t *ptr );
  
  // Check to see what (if anything) this MOVETYPE_STEP entity is standing on
  void CBaseEntity::PhysicsStepRecheckGround()
  {
  	unsigned int mask = PhysicsSolidMaskForEntity();
  	// determine if it's on solid ground at all
  	Vector	mins, maxs, point;
  	int		x, y;
  	trace_t trace;
  	
  	VectorAdd (GetAbsOrigin(), WorldAlignMins(), mins);
  	VectorAdd (GetAbsOrigin(), WorldAlignMaxs(), maxs);
  	point[2] = mins[2] - 1;
  	for	(x=0 ; x<=1 ; x++)
  	{
  		for	(y=0 ; y<=1 ; y++)
  		{
  			point[0] = x ? maxs[0] : mins[0];
  			point[1] = y ? maxs[1] : mins[1];
  
  			ICollideable *pCollision = GetCollideable();
  
  			if ( pCollision && IsNPC() )
  			{
  				UTIL_TraceLineFilterEntity( this, point, point, mask, COLLISION_GROUP_NONE, &trace );
  			}
  			else
  			{
  				UTIL_TraceLine( point, point, mask, this, COLLISION_GROUP_NONE, &trace );
  			}
  
  			if ( trace.startsolid )
  			{
  				SetGroundEntity( trace.m_pEnt );
  				return;
  			}
  		}
  	}
  }
  
  
  //-----------------------------------------------------------------------------
  // Purpose: 
  // Input  : timestep - 
  //-----------------------------------------------------------------------------
  void CBaseEntity::PhysicsStepRunTimestep( float timestep )
  {
  	bool	wasonground;
  	bool	inwater;
  #if 0
  	bool	hitsound = false;
  #endif
  	float	speed, newspeed, control;
  	float	friction;
  
  	PhysicsCheckVelocity();
  
  	wasonground = ( GetFlags() & FL_ONGROUND ) ? true : false;
  
  	// add gravity except:
  	//   flying monsters
  	//   swimming monsters who are in the water
  	inwater = PhysicsCheckWater();
  
  	bool isfalling = false;
  
  	if ( !wasonground )
  	{
  		if ( !( GetFlags() & FL_FLY ) )
  		{
  			if ( !( ( GetFlags() & FL_SWIM ) && ( GetWaterLevel() > 0 ) ) )
  			{
  #if 0
  				if ( GetAbsVelocity()[2] < ( GetCurrentGravity() * -0.1 ) )
  				{
  					hitsound = true;
  				}
  #endif
  
  				if ( !inwater )
  				{
  					PhysicsAddHalfGravity( timestep );
  					isfalling = true;
  				}
  			}
  		}
  	}
  
  	if ( !(GetFlags() & FL_STEPMOVEMENT) &&
  		(!VectorCompare(GetAbsVelocity(), vec3_origin) || 
  		 !VectorCompare(GetBaseVelocity(), vec3_origin)))
  	{
  		Vector vecAbsVelocity = GetAbsVelocity();
  
  		SetGroundEntity( NULL );
  		// apply friction
  		// let dead monsters who aren't completely onground slide
  		if ( wasonground )
  		{
  			speed = VectorLength( vecAbsVelocity );
  			if (speed)
  			{
  				friction = sv_friction.GetFloat() * GetFriction();
  
  				control = speed < sv_stopspeed.GetFloat() ? sv_stopspeed.GetFloat() : speed;
  				newspeed = speed - timestep*control*friction;
  
  				if (newspeed < 0)
  					newspeed = 0;
  				newspeed /= speed;
  
  				vecAbsVelocity[0] *= newspeed;
  				vecAbsVelocity[1] *= newspeed;
  			}
  		}
  
  		vecAbsVelocity += GetBaseVelocity();
  		SetAbsVelocity( vecAbsVelocity );
  
  		// Apply angular velocity
  		SimulateAngles( timestep );
  
  		PhysicsCheckVelocity();
  
  		PhysicsTryMove( timestep, NULL );
  
  		PhysicsCheckVelocity();
  
  		vecAbsVelocity = GetAbsVelocity();
  		vecAbsVelocity -= GetBaseVelocity();
  		SetAbsVelocity( vecAbsVelocity );
  
  		PhysicsCheckVelocity();
  
  		if ( !(GetFlags() & FL_ONGROUND) )
  		{
  			PhysicsStepRecheckGround();
  		}
  
  		PhysicsTouchTriggers();
  	}
  
  	if (!( GetFlags() & FL_ONGROUND ) && isfalling)
  	{
  		PhysicsAddHalfGravity( timestep );
  	}
  }
  
  // After this long, if a player isn't updating, then return it's projectiles to server control
  #define PLAYER_PACKETS_STOPPED_SO_RETURN_TO_PHYSICS_TIME 1.0f
  
  void Physics_SimulateEntity( CBaseEntity *pEntity )
  {
  	VPROF( ( !vprof_scope_entity_gamephys.GetBool() ) ? 
  			"Physics_SimulateEntity" : 
  			EntityFactoryDictionary()->GetCannonicalName( pEntity->GetClassname() ) );
  
  	if ( pEntity->edict() )
  	{
  #if !defined( NO_ENTITY_PREDICTION )
  		// Player drives simulation of this entity
  		if ( pEntity->IsPlayerSimulated() )
  		{
  			// If the player is gone, dropped, crashed, then return
  			//  control to the game code.
  			CBasePlayer *simulatingPlayer = pEntity->GetSimulatingPlayer();
  			if ( simulatingPlayer &&
  				( simulatingPlayer->GetTimeBase() > gpGlobals->curtime - PLAYER_PACKETS_STOPPED_SO_RETURN_TO_PHYSICS_TIME ) )
  			{
  				// Okay, the guy is still around
  				return;
  			}
  
  			pEntity->UnsetPlayerSimulated();
  		}
  #endif
  
  		MDLCACHE_CRITICAL_SECTION();
  
  #if !defined( NO_ENTITY_PREDICTION )
  		// If an object was at one point player simulated, but had that status revoked (as just
  		//  above when no packets have arrived in a while ), then we still will assume that the
  		//  owner/player will be predicting the entity locally (even if the game is playing like butt)
  		//  and so we won't spam that player with additional network data such as effects/sounds 
  		//  that are theoretically being predicted by the player anyway.
  		if ( pEntity->m_PredictableID->IsActive() )
  		{
  			CBasePlayer *playerowner = ToBasePlayer( pEntity->GetOwnerEntity() );
  			if ( playerowner )
  			{
  				CBasePlayer *pl = ToBasePlayer( UTIL_PlayerByIndex( pEntity->m_PredictableID->GetPlayer() + 1 ) );
  				// Is the player who created it still the owner?
  				if ( pl == playerowner )
  				{
  					// Set up to suppress sending events to owner player
  					if ( pl->IsPredictingWeapons() )
  					{
  						IPredictionSystem::SuppressHostEvents( playerowner );
  					}
  				}
  			}	
  			{
  				VPROF( ( !vprof_scope_entity_gamephys.GetBool() ) ? 
  						"pEntity->PhysicsSimulate" : 
  						EntityFactoryDictionary()->GetCannonicalName( pEntity->GetClassname() ) );
  
  				// Run entity physics
  				pEntity->PhysicsSimulate();
  			}
  
  			// Restore suppression filter
  			IPredictionSystem::SuppressHostEvents( NULL );
  		}
  		else
  #endif
  		{
  			// Run entity physics
  			pEntity->PhysicsSimulate();
  		}
  	}
  	else
  	{
  		pEntity->PhysicsRunThink();
  	}
  }
  //-----------------------------------------------------------------------------
  // Purpose: Runs the main physics simulation loop against all entities ( except players )
  //-----------------------------------------------------------------------------
  void Physics_RunThinkFunctions( bool simulating )
  {
  	VPROF( "Physics_RunThinkFunctions");
  
  	g_bTestMoveTypeStepSimulation = sv_teststepsimulation.GetBool();
  
  	float starttime = gpGlobals->curtime;
  	// clear all entites freed outside of this loop
  	gEntList.CleanupDeleteList();
  
  	if ( !simulating )
  	{
  		// only simulate players
  		for ( int i = 1; i <= gpGlobals->maxClients; i++ )
  		{
  			CBasePlayer *pPlayer = UTIL_PlayerByIndex( i );
  			if ( pPlayer )
  			{
  				// Always reset clock to real sv.time
  				gpGlobals->curtime = starttime;
  				// Force usercmd processing even though gpGlobals->tickcount isn't incrementing
  				pPlayer->ForceSimulation();
  				Physics_SimulateEntity( pPlayer );
  			}
  		}
  	}
  	else
  	{
  		UTIL_DisableRemoveImmediate();
  		int listMax = SimThink_ListCount();
  		listMax = MAX(listMax,1);
  		CBaseEntity **list = (CBaseEntity **)stackalloc( sizeof(CBaseEntity *) * listMax );
  		// iterate through all entities and have them think or simulate
  		
  		// UNDONE: This has problems with UTIL_RemoveImmediate() (now disabled during this loop).  
  		// Do we really need UTIL_RemoveImmediate()?
  		int count = SimThink_ListCopy( list, listMax );
  
  		//DevMsg(1, "Count: %d\n", count );
  		for ( int i = 0; i < count; i++ )
  		{
  			if ( !list[i] )
  				continue;
  			// Always reset clock to real sv.time
  			gpGlobals->curtime = starttime;
  			Physics_SimulateEntity( list[i] );
  		}
  
  		stackfree( list );
  		UTIL_EnableRemoveImmediate();
  	}
  
  	gpGlobals->curtime = starttime;
  }
  
  