//========= Copyright © 1996-2001, Valve LLC, 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 _LINUX
#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 "ispatialpartition.h"
#include "tier0/vprof.h"
#include "movevars_shared.h"
#include "hierarchy.h"
#include "trains.h"
#include "tier0/vcrmode.h"

extern ConVar think_limit;

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) )
	{
		// don't collide with monsters
		mask &= ~CONTENTS_MONSTER;
	}

	Physics_TraceEntity( pEntity, vecAbsStart, vecAbsEnd, mask, pTrace );
}


//-----------------------------------------------------------------------------
// Purpose: Keeps track of original positions of any entities that are being possibly pushed
//  and handles restoring positions for those objects if the push is aborted
//-----------------------------------------------------------------------------
class CPhysicsPushedEntities
{
public:
	CPhysicsPushedEntities( void );

	// Purpose: Tries to rotate an entity hierarchy, returns the blocker if any
	CBaseEntity *PerformRotatePush( CBaseEntity *pRoot, float movetime );

	// Purpose: Tries to linearly push an entity hierarchy, returns the blocker if any
	CBaseEntity *PerformLinearPush( CBaseEntity *pRoot, float movetime );

private:
	// describes the per-frame incremental motion of a rotating MOVETYPE_PUSH
	struct RotatingPushMove_t
	{
		Vector		origin;
		matrix3x4_t	startLocalToWorld;
		matrix3x4_t	endLocalToWorld;
		QAngle		amove;		// delta orientation
	};

	// Pushers + their original positions also (for touching triggers)
	struct PhysicsPusherInfo_t
	{
		CBaseEntity			*m_pEntity;
		Vector				m_vecStartAbsOrigin;
	};

	// Pushed entities + various state related to them being pushed
	struct PhysicsPushedInfo_t
	{
		CBaseEntity			*m_pEntity;
		Vector				m_vecStartAbsOrigin;
		trace_t				m_Trace;
		bool				m_bBlocked;
	};

	// Adds the specified entity to the list
	void	AddEntity( CBaseEntity *ent );

	// If a move fails, restores all entities to their original positions
	void	RestoreEntities( );

	// Compute the direction to move the rotation blocker
	void	ComputeRotationalPushDirection( CBaseEntity *pBlocker, const RotatingPushMove_t &rotPushMove, Vector *pMove, CBaseEntity *pRoot );

	// Speculatively checks to see if all entities in this list can be pushed
	bool	SpeculativelyCheckPush( PhysicsPushedInfo_t &info, const Vector &vecAbsPush, bool bRotationalPush );

	// Speculatively checks to see if all entities in this list can be pushed
	bool	SpeculativelyCheckRotPush( const RotatingPushMove_t &rotPushMove, CBaseEntity *pRoot );

	// Speculatively checks to see if all entities in this list can be pushed
	bool	SpeculativelyCheckLinearPush( const Vector &vecAbsPush );

	// Registers a blockage
	CBaseEntity *RegisterBlockage();

	// Some fixup for objects pushed by rotating objects
	void	FinishRotPushedEntity( CBaseEntity *pPushedEntity, const RotatingPushMove_t &rotPushMove );

	// Commits the speculative movement
	void	FinishPush( bool bIsRotPush = false, const RotatingPushMove_t *pRotPushMove = NULL );

	// Generates a list of all entities potentially blocking all pushers
	void	GenerateBlockingEntityList( );

	// Purpose: Gets a list of all entities hierarchically attached to the root 
	void	SetupAllInHierarchy( CBaseEntity *pParent );

	// Unlink + relink the pusher list so we can actually do the push
	void	UnlinkPusherList( int *pPusherHandles );
	void	RelinkPusherList( int *pPusherHandles );

	// Causes all entities in the list to touch triggers from their prev position
	void	FinishPushers();

	// Purpose: Rotates the root entity, fills in the pushmove structure
	void	RotateRootEntity( CBaseEntity *pRoot, float movetime, RotatingPushMove_t &rotation );

	// Purpose: Linearly moves the root entity
	void	LinearlyMoveRootEntity( CBaseEntity *pRoot, float movetime, Vector *pAbsPushVector );

	// Relink everything that is in the push hierarchy
	void	RelinkAllPushers();

private:
	CUtlVector<PhysicsPusherInfo_t>	m_rgPusher;
	CUtlVector<PhysicsPushedInfo_t>	m_rgMoved;
	int m_nBlocker;

	friend class CPushBlockerEnum;
};


// Handles saving moved entities list
static CPhysicsPushedEntities s_PushedEntities;


//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
CPhysicsPushedEntities::CPhysicsPushedEntities( void ) : m_rgPusher(8, 8), m_rgMoved(32, 32)
{
}


//-----------------------------------------------------------------------------
// 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();
}


//-----------------------------------------------------------------------------
// Relink everything that is in the push hierarchy
//-----------------------------------------------------------------------------
void CPhysicsPushedEntities::RelinkAllPushers()
{
	for ( int i = m_rgPusher.Count(); --i >=0; )
	{
		engine->RelinkEntity( m_rgPusher[i].m_pEntity->edict(), false );
	}
}


//-----------------------------------------------------------------------------
// 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] = engine->FastUnlink( m_rgPusher[i].m_pEntity->edict() );
	}
}

void CPhysicsPushedEntities::RelinkPusherList( int *pPusherHandles )
{
	for ( int i = m_rgPusher.Count(); --i >= 0; )
	{
		engine->FastRelink( m_rgPusher[i].m_pEntity->edict(), 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->GetAbsOrigin();
	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!!!
		start.x = (pMove->x < 0) ? pBlocker->GetAbsMaxs().x : pBlocker->GetAbsMins().x;
		start.y = (pMove->y < 0) ? pBlocker->GetAbsMaxs().y : pBlocker->GetAbsMins().y;
		start.z = (pMove->z < 0) ? pBlocker->GetAbsMaxs().z : pBlocker->GetAbsMins().z;
	}

	// 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 );
}


//-----------------------------------------------------------------------------
// 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);
	PhysicsCheckSweep( pBlocker, pBlocker->GetAbsOrigin(), vecAbsPush, &info.m_Trace );
	RelinkPusherList(pPusherHandles);

	// Move the blocker into its new position
	if ( info.m_Trace.fraction )
	{
		pBlocker->SetAbsOrigin( info.m_Trace.endpos );
		engine->RelinkEntity( pBlocker->edict(), false );
	}

	if ( (!bRotationalPush) && (info.m_Trace.fraction == 1.0) )
	{
		Assert( pBlocker->PhysicsTestEntityPosition() == false );
		if ( pBlocker->PhysicsTestEntityPosition() != false )
		{
			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: Shouldn't we simply be testing the blocker against the pusher list here??
	// FIXME: If the trace fraction == 0 can we early out also?
	info.m_bBlocked = pBlocker->PhysicsTestEntityPosition();
	if ( !info.m_bBlocked )
		return true;

	// We're not blocked if the blocker is point-sized or non-solid
	if ( pBlocker->IsPointSized() )
		return true;

	if ( !pBlocker->IsSolid() || pBlocker->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) )
		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
		engine->RelinkEntity( info.m_pEntity->edict(), true, &info.m_vecStartAbsOrigin );

		info.m_pEntity->UpdatePhysicsShadowToCurrentPosition( 0 );
	}
}


//-----------------------------------------------------------------------------
// 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 = 2;
		// 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.anglechangetotal += rotPushMove.amove[1];
		player->pl.anglechangefinal = rotPushMove.amove[1];
	}
	else
	{
		QAngle angles = pPushedEntity->GetAbsAngles();
		VectorAdd( angles, rotPushMove.amove, angles );
		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
		engine->RelinkEntity( info.m_pEntity->edict(), true, &info.m_vecStartAbsOrigin );
		info.m_pEntity->UpdatePhysicsShadowToCurrentPosition( 0 );

		// Register physics impacts...
		if (info.m_Trace.m_pEnt)
		{
			pPushedEntity->PhysicsImpact( info.m_Trace.m_pEnt, info.m_Trace );
		}

		// remove the onground flag for non-players
		if ( info.m_pEntity->GetMoveType() != MOVETYPE_WALK )
		{
			info.m_pEntity->RemoveFlag( FL_ONGROUND );
		}

		if (bIsRotPush)
		{
			FinishRotPushedEntity( pPushedEntity, *pRotPushMove );
		}
	}
}


//-----------------------------------------------------------------------------
// 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( )
{
	// Relink all of the pusher entities to get them back into place
	RelinkAllPushers();

	// 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 );

		// When moving back, be sure not to touch triggers
		engine->RelinkEntity( m_rgMoved[ i ].m_pEntity->edict(), false );
	}
}


//-----------------------------------------------------------------------------
// 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 = GetHighestParent( m_pPushedEntities->m_rgPusher[0].m_pEntity );
		++s_nEnumCount;
	}

	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:
	bool IsStandingOnPusher( CBaseEntity *pCheck )
	{
		if ( pCheck->GetFlags() & FL_ONGROUND )
		{
			CBaseEntity *pGroundEnt = pCheck->GetGroundEntity();
			for ( int i = m_pPushedEntities->m_rgPusher.Count(); --i >= 0; )
			{
				if (m_pPushedEntities->m_rgPusher[i].m_pEntity == pGroundEnt)
				{
					return true;
				}
			}
		}
		return false;
	}

	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;
		}

		// We're not pushing stuff we're hierarchically attached to
		CBaseEntity *pCheckHighestParent = GetHighestParent(pCheck);
		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) )
		{
			// FIXME: This does a test against the KD tree...
			// It would be a ton faster to directly test against all the pushers
			// in the pusher hierarchy, since we know they are the only ones who changed
			// It also would avoid re-entrant KD tree iteration

			// see if the ent's bbox is inside the pusher's final position
			if ( !pCheck->PhysicsTestEntityPosition() )
				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;
};

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;
		}

		partition->EnumerateElementsInBox( PARTITION_ENGINE_NON_STATIC_EDICTS, 
			pPusher->GetAbsMins(), pPusher->GetAbsMaxs(), false, &blockerEnum );
	}
}


//-----------------------------------------------------------------------------
// 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 
	AngleMatrix( pRoot->GetAbsAngles(), rotation.origin, 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
	AngleMatrix( pRoot->GetAbsAngles(), rotation.origin, rotation.endLocalToWorld );

	// Relink all children without touching triggers) so everything's in the right place...
	RelinkAllPushers();
}


//-----------------------------------------------------------------------------
// Purpose: Tries to rotate an entity hierarchy, returns the blocker if any
//-----------------------------------------------------------------------------
CBaseEntity *CPhysicsPushedEntities::PerformRotatePush( CBaseEntity *pRoot, float movetime )
{
	VPROF("CPhysicsPushedEntities::PerformRotatePush");

	// 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;

	// Relink all children without touching triggers) so everything's in the right place...
	RelinkAllPushers( );
}


//-----------------------------------------------------------------------------
// Purpose: Tries to linearly push an entity hierarchy, returns the blocker if any
//-----------------------------------------------------------------------------
CBaseEntity *CPhysicsPushedEntities::PerformLinearPush( CBaseEntity *pRoot, float movetime )
{
	VPROF("CPhysicsPushedEntities::PerformLinearPush");

	// 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...
	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 (!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("CBaseEntity::PhysicsDispatchThink");

	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 ( g_pVCR->GetMode() != VCR_Disabled )
		thinkLimit = 0;

	float startTime = 0.0;

	if ( IsDormant() )
	{
		Warning( "Dormant entity %s is thinking!!\n", GetClassname() );
		Assert(0);
	}

	if ( thinkLimit )
	{
		startTime = engine->Time();
	}
	
	if ( thinkFunc )
	{
		(this->*thinkFunc)();
	}

	if ( thinkLimit )
	{
		// calculate running time of the AI in milliseconds
		float time = ( engine->Time() - startTime ) * 1000.0f;
		if ( time > thinkLimit )
		{
			// 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 _LINUX
				Msg( "%s(%s) thinking for %.02f ms!!!\n", GetClassname(), typeid(this).name(), time );
#else
#error "typeinfo"
#endif
			}
		}
	}
}

//-----------------------------------------------------------------------------
// 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 time, 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 = time;

	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 ))
			{
				AddFlag( FL_ONGROUND );
				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 * sv_gravity.GetFloat() * 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
//-----------------------------------------------------------------------------
trace_t CBaseEntity::PhysicsPushEntity( const Vector& push )
{
	VPROF("CBaseEntity::PhysicsPushEntity");

	if ( GetMoveParent() )
	{
		Warning( "pushing entity (%s) that has m_pMoveParent!\n", GetClassname() );
		Assert(0);
	}

	// NOTE: absorigin and origin must be equal because there is no moveparent
	Vector prevOrigin;
	VectorCopy( GetAbsOrigin(), prevOrigin );

	trace_t		trace;
	::PhysicsCheckSweep( this, prevOrigin, push, &trace );

	if ( trace.fraction )
	{
		SetAbsOrigin( trace.endpos );
	}

	// Passing in the previous abs origin here will cause the relinker
	// to test the swept ray from previous to current location for trigger intersections
	engine->RelinkEntity( pev, true, &prevOrigin );

	if ( trace.m_pEnt )
	{
		PhysicsImpact( trace.m_pEnt, trace );
	}

	return trace;
}

//-----------------------------------------------------------------------------
// 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");
//	MEASURECODE( "PhysicsPushMove" );

	// If this entity isn't moving, just update the time.
	if ( GetLocalVelocity() == vec3_origin )
	{
		IncrementLocalTime( movetime );
		return NULL;
	}

	IncrementLocalTime( movetime );

	// Now check that the entire hierarchy can rotate into the new location
	CBaseEntity *pBlocker = s_PushedEntities.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");
	// Not rotating
	if ( GetLocalAngularVelocity() == vec3_angle )
	{
		IncrementLocalTime( movetime );
		return NULL;
	}

	IncrementLocalTime( movetime );

	// Now check that the entire hierarchy can rotate into the new location
	CBaseEntity *pBlocker = s_PushedEntities.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;
	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() )
	{
		if ( m_flMoveDoneTime <= m_flLocalTime && m_flMoveDoneTime > 0 )
		{
			m_flMoveDoneTime = 0;
			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( GetAbsOrigin(), gpGlobals->frametime, GetAbsVelocity(), origin );
	SetAbsOrigin( origin );

	engine->RelinkEntity( pev, false );
}


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() )
	{
		RemoveFlag( FL_ONGROUND );
	}

	// 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;
	trace = PhysicsPushEntity( move );

	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();
}


//-----------------------------------------------------------------------------
// 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()
{
	// Run all but the base think function
	PhysicsRunThink( THINK_FIRE_ALL_BUT_BASE );

	int thinktick = GetNextThinkTick();
	float thinktime = thinktick * TICK_RATE;

	// 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 );
		return;
	}

	// not going to think, don't run physics either
	if ( thinktick > gpGlobals->tickcount )
	{
		return;
	}
	
	Vector oldOrigin = GetAbsOrigin();

	// HACKHACK: As an experiment, feed the position delta back
	if ( npc_vphysics.GetBool() && 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 );
			if ( tr.startsolid )
			{
				SetAbsOrigin( position );
				engine->RelinkEntity( pev, true );
			}
		}
		else
		{
			SetAbsOrigin( position );
			engine->RelinkEntity( pev, true );
		}
		//NDebugOverlay::Box( position, WorldAlignMins(), WorldAlignMaxs(), 255, 255, 0, 0, 0.1 );
	}

// handy debug code to visualize tolerance / shadow lag
#if 0
	else
	{
		if ( VPhysicsGetObject() && !GetParent() )
		{
			Vector position;
			VPhysicsGetObject()->GetShadowPosition( &position, NULL );
			float delta = (GetAbsOrigin() - position).LengthSqr();
			if ( delta > 8 )
			{
				NDebugOverlay::Box( position, WorldAlignMins(), WorldAlignMaxs(), 255, 0, 0, 0, 0.1 );
			}
			else
			{
				NDebugOverlay::Box( position, WorldAlignMins(), WorldAlignMaxs(), 0, 255, 0, 0, 0.1 );
			}
		}
	}
#endif
	// 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();

	PhysicsStepRunTimestep( dt );

	// now think
	PhysicsRunThink( THINK_FIRE_BASE_ONLY );

	PhysicsCheckWaterTransition();

	if ( VPhysicsGetObject() )
	{
		if ( !VectorCompare( oldOrigin, GetAbsOrigin() ) )
		{
			VPhysicsGetObject()->UpdateShadow( GetAbsOrigin(), vec3_angle, (GetFlags() & FL_FLY) ? true : false, dt );
		}
	}
	PhysicsRelinkChildren();
}

void CBaseEntity::PhysicsStepRunTimestep( float timestep )
{
	bool	wasonground;
	bool	inwater;
	bool	hitsound = false;
	float	speed, newspeed, control;
	float	friction;

	unsigned int mask = PhysicsSolidMaskForEntity();

	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 ( GetAbsVelocity()[2] < ( sv_gravity.GetFloat() * -0.1 ) )
				{
					hitsound = true;
				}

				if ( !inwater )
				{
					PhysicsAddHalfGravity( timestep );
					isfalling = true;
				}
			}
		}
	}

	if ( !(GetFlags() & FL_STEPMOVEMENT) &&
		(!VectorCompare(GetAbsVelocity(), vec3_origin) || 
		 !VectorCompare(GetBaseVelocity(), vec3_origin)))
	{
		Vector vecAbsVelocity = GetAbsVelocity();

		RemoveFlag( FL_ONGROUND );
		// 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();

		// 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++)
		{
			if ( GetFlags() & FL_ONGROUND )
				break;

			for	(y=0 ; y<=1 ; y++)
			{
				point[0] = x ? maxs[0] : mins[0];
				point[1] = y ? maxs[1] : mins[1];
				UTIL_TraceLine( point, point, mask, this, COLLISION_GROUP_NONE, &trace );
				if ( trace.startsolid )
				{
					AddFlag( FL_ONGROUND );
					SetGroundEntity( trace.m_pEnt );
					break;
				}
			}
		}

		engine->RelinkEntity( pev, true );
	}

	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 )
{
	if ( pEntity->GetFlags() & FL_STATICPROP )
		return;

	if ( pEntity->pev )
	{
		// 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();
		}

		// 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( "pEntity->PhysicsSimulate" );
			// Run entity physics
			pEntity->PhysicsSimulate();
		}

		// Restore suppression filter
		IPredictionSystem::SuppressHostEvents( NULL );
	}
	else
	{
		pEntity->PhysicsRunThink();
	}
}
//-----------------------------------------------------------------------------
// Purpose: Runs the main physics simulation loop against all entities ( except players )
//-----------------------------------------------------------------------------
void Physics_RunThinkFunctions( bool simulating )
{
	VPROF( "Physics_RunThinkFunctions");
	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;
				Physics_SimulateEntity( pPlayer );
			}
		}
	}
	else
	{
		// iterate through all entities and have them think or simulate
		CBaseEntity *ent = NULL;
		while ( (ent = gEntList.NextEnt(ent)) != NULL )
		{
			// Always reset clock to real sv.time
			gpGlobals->curtime = starttime;
			Physics_SimulateEntity( ent );
		}
	}

	gpGlobals->curtime = starttime;
}

