aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/server/physics_npc_solver.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /sp/src/game/server/physics_npc_solver.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'sp/src/game/server/physics_npc_solver.cpp')
-rw-r--r--sp/src/game/server/physics_npc_solver.cpp936
1 files changed, 468 insertions, 468 deletions
diff --git a/sp/src/game/server/physics_npc_solver.cpp b/sp/src/game/server/physics_npc_solver.cpp
index 9284c5f7..ce7f8434 100644
--- a/sp/src/game/server/physics_npc_solver.cpp
+++ b/sp/src/game/server/physics_npc_solver.cpp
@@ -1,468 +1,468 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-//=============================================================================//
-
-#include "cbase.h"
-#include "physics_saverestore.h"
-#include "vphysics/friction.h"
-#include "ai_basenpc.h"
-#include "movevars_shared.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-
-class CPhysicsNPCSolver : public CLogicalEntity, public IMotionEvent
-{
- DECLARE_CLASS( CPhysicsNPCSolver, CLogicalEntity );
-public:
- CPhysicsNPCSolver();
- ~CPhysicsNPCSolver();
- DECLARE_DATADESC();
- void Init( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime );
- static CPhysicsNPCSolver *Create( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime );
-
- // CBaseEntity
- virtual void Spawn();
- virtual void UpdateOnRemove();
- virtual void Think();
- virtual void OnRestore()
- {
- BaseClass::OnRestore();
- if ( m_allowIntersection )
- {
- PhysDisableEntityCollisions( m_hNPC, m_hEntity );
- }
- }
-
- // IMotionEvent
- virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
-
-public:
- CPhysicsNPCSolver *m_pNext;
-private:
- // locals
- void ResetCancelTime();
- void BecomePenetrationSolver();
- bool IsIntersecting();
- bool IsContactOnNPCHead( IPhysicsFrictionSnapshot *pSnapshot, IPhysicsObject *pPhysics, CAI_BaseNPC *pNPC );
- bool CheckTouching();
- friend bool NPCPhysics_SolverExists( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject );
-
- CHandle<CAI_BaseNPC> m_hNPC;
- EHANDLE m_hEntity;
- IPhysicsMotionController *m_pController;
- float m_separationDuration;
- float m_cancelTime;
- bool m_allowIntersection;
-};
-
-LINK_ENTITY_TO_CLASS( physics_npc_solver, CPhysicsNPCSolver );
-
-BEGIN_DATADESC( CPhysicsNPCSolver )
-
- DEFINE_FIELD( m_hNPC, FIELD_EHANDLE ),
- DEFINE_FIELD( m_hEntity, FIELD_EHANDLE ),
- DEFINE_FIELD( m_separationDuration, FIELD_FLOAT ),
- DEFINE_FIELD( m_cancelTime, FIELD_TIME ),
- DEFINE_FIELD( m_allowIntersection, FIELD_BOOLEAN ),
- DEFINE_PHYSPTR( m_pController ),
- //DEFINE_FIELD( m_pNext, FIELD_CLASSPTR ),
-
-END_DATADESC()
-
-CEntityClassList<CPhysicsNPCSolver> g_SolverList;
-template <> CPhysicsNPCSolver *CEntityClassList<CPhysicsNPCSolver>::m_pClassList = NULL;
-
-bool NPCPhysics_SolverExists( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject )
-{
- CPhysicsNPCSolver *pSolver = g_SolverList.m_pClassList;
- while ( pSolver )
- {
- if ( pSolver->m_hEntity == pPhysicsObject && pSolver->m_hNPC == pNPC )
- return true;
- pSolver = pSolver->m_pNext;
- }
-
- return false;
-}
-
-CPhysicsNPCSolver *CPhysicsNPCSolver::Create( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime )
-{
- CPhysicsNPCSolver *pSolver = (CPhysicsNPCSolver *)CBaseEntity::CreateNoSpawn( "physics_npc_solver", vec3_origin, vec3_angle, NULL );
- pSolver->Init( pNPC, pPhysicsObject, disableCollisions, separationTime );
- pSolver->Spawn();
- //NDebugOverlay::EntityBounds(pNPC, 255, 255, 0, 64, 0.5f );
- return pSolver;
-}
-
-CPhysicsNPCSolver::CPhysicsNPCSolver()
-{
- g_SolverList.Insert( this );
-}
-
-CPhysicsNPCSolver::~CPhysicsNPCSolver()
-{
- g_SolverList.Remove( this );
-}
-
-void CPhysicsNPCSolver::Init( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime )
-{
- m_hNPC = pNPC;
- m_hEntity = pPhysicsObject;
- m_pController = NULL;
- m_separationDuration = separationTime;
- m_allowIntersection = disableCollisions;
-
-}
-
-void CPhysicsNPCSolver::ResetCancelTime()
-{
- m_cancelTime = gpGlobals->curtime + m_separationDuration;
- SetNextThink( m_cancelTime );
-}
-
-void CPhysicsNPCSolver::BecomePenetrationSolver()
-{
- CBaseEntity *pEntity = m_hEntity.Get();
- if ( pEntity )
- {
- m_allowIntersection = true;
- IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
- int listCount = pEntity->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
- PhysDisableEntityCollisions( m_hNPC, pEntity );
- m_pController = physenv->CreateMotionController( this );
- for ( int i = 0; i < listCount; i++ )
- {
- m_pController->AttachObject( pList[i], false );
- pList[i]->Wake();
- }
- m_pController->SetPriority( IPhysicsMotionController::HIGH_PRIORITY );
- }
-}
-
-void CPhysicsNPCSolver::Spawn()
-{
- if ( m_allowIntersection )
- {
- BecomePenetrationSolver();
- }
- else
- {
- m_hEntity->SetNavIgnore();
- }
- ResetCancelTime();
-}
-
-void CPhysicsNPCSolver::UpdateOnRemove()
-{
- if ( m_allowIntersection )
- {
- physenv->DestroyMotionController( m_pController );
- m_pController = NULL;
- PhysEnableEntityCollisions( m_hNPC, m_hEntity );
- }
- else
- {
- if ( m_hEntity.Get() )
- {
- m_hEntity->ClearNavIgnore();
- }
- }
- //NDebugOverlay::EntityBounds(m_hNPC, 0, 255, 0, 64, 0.5f );
- BaseClass::UpdateOnRemove();
-}
-
-bool CPhysicsNPCSolver::IsIntersecting()
-{
- CAI_BaseNPC *pNPC = m_hNPC.Get();
- CBaseEntity *pPhysics = m_hEntity.Get();
- if ( pNPC && pPhysics )
- {
- Ray_t ray;
- // bloated bounds to force slight separation
- Vector mins = pNPC->WorldAlignMins() - Vector(1,1,1);
- Vector maxs = pNPC->WorldAlignMaxs() + Vector(1,1,1);
-
- ray.Init( pNPC->GetAbsOrigin(), pNPC->GetAbsOrigin(), mins, maxs );
- trace_t tr;
- enginetrace->ClipRayToEntity( ray, pNPC->PhysicsSolidMaskForEntity(), pPhysics, &tr );
- if ( tr.startsolid )
- return true;
- }
- return false;
-}
-
-bool CPhysicsNPCSolver::IsContactOnNPCHead( IPhysicsFrictionSnapshot *pSnapshot, IPhysicsObject *pPhysics, CAI_BaseNPC *pNPC )
-{
- float heightCheck = pNPC->GetAbsOrigin().z + pNPC->GetHullMaxs().z;
- Vector vel, point;
- pPhysics->GetVelocity( &vel, NULL );
- pSnapshot->GetContactPoint( point );
- // don't care if the object is already moving away
- if ( vel.LengthSqr() < 10.0f*10.0f )
- {
- float topdist = fabs(point.z-heightCheck);
- if ( topdist < 2.0f )
- {
- return true;
- }
- }
- return false;
-}
-
-bool CPhysicsNPCSolver::CheckTouching()
-{
- CAI_BaseNPC *pNPC = m_hNPC.Get();
- if ( !pNPC )
- return false;
-
- CBaseEntity *pPhysicsEnt = m_hEntity.Get();
- if ( !pPhysicsEnt )
- return false;
-
- IPhysicsObject *pPhysics = pPhysicsEnt->VPhysicsGetObject();
- IPhysicsObject *pNPCPhysics = pNPC->VPhysicsGetObject();
- if ( !pNPCPhysics || !pPhysics )
- return false;
-
- IPhysicsFrictionSnapshot *pSnapshot = pPhysics->CreateFrictionSnapshot();
- bool found = false;
- bool penetrate = false;
-
- while ( pSnapshot->IsValid() )
- {
- IPhysicsObject *pOther = pSnapshot->GetObject(1);
- if ( pOther == pNPCPhysics )
- {
- found = true;
- if ( IsContactOnNPCHead(pSnapshot, pPhysics, pNPC ) )
- {
- penetrate = true;
- pSnapshot->MarkContactForDelete();
- }
- break;
- }
- pSnapshot->NextFrictionData();
- }
- pSnapshot->DeleteAllMarkedContacts( true );
- pPhysics->DestroyFrictionSnapshot( pSnapshot );
-
- // if the object is penetrating something, check to see if it's intersecting this NPC
- // if so, go ahead and switch over to penetration solver mode
- if ( !penetrate && (pPhysics->GetGameFlags() & FVPHYSICS_PENETRATING) )
- {
- penetrate = IsIntersecting();
- }
-
- if ( penetrate )
- {
- pPhysicsEnt->ClearNavIgnore();
- BecomePenetrationSolver();
- }
-
- return found;
-}
-
-void CPhysicsNPCSolver::Think()
-{
- bool finished = m_allowIntersection ? !IsIntersecting() : !CheckTouching();
-
- if ( finished )
- {
- UTIL_Remove(this);
- return;
- }
- if ( m_allowIntersection )
- {
- IPhysicsObject *pObject = m_hEntity->VPhysicsGetObject();
- if ( !pObject )
- {
- UTIL_Remove(this);
- return;
- }
- pObject->Wake();
- }
- ResetCancelTime();
-}
-
-IMotionEvent::simresult_e CPhysicsNPCSolver::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject,
- float deltaTime, Vector &linear, AngularImpulse &angular )
-{
- if ( IsIntersecting() )
- {
- const float PUSH_SPEED = 150.0f;
-
- if ( pObject->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
- {
- CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
- if ( pPlayer )
- {
- pPlayer->ForceDropOfCarriedPhysObjects( m_hEntity );
- }
- }
-
- ResetCancelTime();
- angular.Init();
- linear.Init();
-
- // Don't push on vehicles because they won't move
- if ( pObject->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY )
- {
- if ( m_hEntity->GetServerVehicle() )
- return SIM_NOTHING;
- }
-
- Vector origin, vel;
- pObject->GetPosition( &origin, NULL );
- pObject->GetVelocity( &vel, NULL );
- Vector dir = origin - m_hNPC->GetAbsOrigin();
- dir.z = dir.z > 0 ? 0.1f : -0.1f;
- VectorNormalize(dir);
- AngularImpulse angVel;
- angVel.Init();
-
- // NOTE: Iterate this object's contact points
- // if it can't move in this direction, try sliding along the plane/crease
- Vector pushImpulse;
- PhysComputeSlideDirection( pObject, dir * PUSH_SPEED, angVel, &pushImpulse, NULL, 0 );
-
- dir = pushImpulse;
- VectorNormalize(dir);
-
- if ( DotProduct( vel, dir ) < PUSH_SPEED * 0.5f )
- {
- linear = pushImpulse;
- if ( pObject->GetContactPoint(NULL,NULL) )
- {
- linear.z += GetCurrentGravity();
- }
- }
- return SIM_GLOBAL_ACCELERATION;
- }
- return SIM_NOTHING;
-}
-
-
-CBaseEntity *NPCPhysics_CreateSolver( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationDuration )
-{
- if ( disableCollisions )
- {
- if ( PhysEntityCollisionsAreDisabled( pNPC, pPhysicsObject ) )
- return NULL;
- }
- else
- {
- if ( pPhysicsObject->IsNavIgnored() )
- return NULL;
- }
- return CPhysicsNPCSolver::Create( pNPC, pPhysicsObject, disableCollisions, separationDuration );
-}
-
-
-class CPhysicsEntitySolver : public CLogicalEntity//, public IMotionEvent
-{
- DECLARE_CLASS( CPhysicsEntitySolver, CLogicalEntity );
-public:
- DECLARE_DATADESC();
- void Init( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime );
- static CPhysicsEntitySolver *Create( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime );
-
- // CBaseEntity
- virtual void Spawn();
- virtual void UpdateOnRemove();
- virtual void Think();
-
- // IMotionEvent
- //virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
-
-private:
- // locals
- void ResetCancelTime();
- void BecomePenetrationSolver();
- //bool IsIntersecting();
- //bool IsTouching();
-
- EHANDLE m_hMovingEntity;
- EHANDLE m_hPhysicsBlocker;
- //IPhysicsMotionController *m_pController;
- float m_separationDuration;
- float m_cancelTime;
- int m_savedCollisionGroup;
-};
-
-LINK_ENTITY_TO_CLASS( physics_entity_solver, CPhysicsEntitySolver );
-
-BEGIN_DATADESC( CPhysicsEntitySolver )
-
- DEFINE_FIELD( m_hMovingEntity, FIELD_EHANDLE ),
- DEFINE_FIELD( m_hPhysicsBlocker, FIELD_EHANDLE ),
- DEFINE_FIELD( m_separationDuration, FIELD_FLOAT ),
- DEFINE_FIELD( m_cancelTime, FIELD_TIME ),
- DEFINE_FIELD( m_savedCollisionGroup, FIELD_INTEGER ),
- //DEFINE_PHYSPTR( m_pController ),
-
-END_DATADESC()
-
-CPhysicsEntitySolver *CPhysicsEntitySolver::Create( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime )
-{
- CPhysicsEntitySolver *pSolver = (CPhysicsEntitySolver *)CBaseEntity::CreateNoSpawn( "physics_entity_solver", vec3_origin, vec3_angle, NULL );
- pSolver->Init( pMovingEntity, pPhysicsBlocker, separationTime );
- pSolver->Spawn();
- //NDebugOverlay::EntityBounds(pNPC, 255, 255, 0, 64, 0.5f );
- return pSolver;
-}
-
-void CPhysicsEntitySolver::Init( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime )
-{
- m_hMovingEntity = pMovingEntity;
- m_hPhysicsBlocker = pPhysicsBlocker;
- //m_pController = NULL;
- m_separationDuration = separationTime;
-}
-
-void CPhysicsEntitySolver::Spawn()
-{
- SetNextThink( gpGlobals->curtime + m_separationDuration );
- PhysDisableEntityCollisions( m_hMovingEntity, m_hPhysicsBlocker );
- m_savedCollisionGroup = m_hPhysicsBlocker->GetCollisionGroup();
- m_hPhysicsBlocker->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
- if ( m_hPhysicsBlocker->VPhysicsGetObject() )
- {
- m_hPhysicsBlocker->VPhysicsGetObject()->RecheckContactPoints();
- }
-}
-
-void CPhysicsEntitySolver::Think()
-{
- UTIL_Remove(this);
-}
-
-void CPhysicsEntitySolver::UpdateOnRemove()
-{
- //physenv->DestroyMotionController( m_pController );
- //m_pController = NULL;
- CBaseEntity *pEntity = m_hMovingEntity.Get();
- CBaseEntity *pPhysics = m_hPhysicsBlocker.Get();
- if ( pEntity && pPhysics )
- {
- PhysEnableEntityCollisions( pEntity, pPhysics );
- }
- if ( pPhysics )
- {
- pPhysics->SetCollisionGroup( m_savedCollisionGroup );
- }
- BaseClass::UpdateOnRemove();
-}
-
-
-CBaseEntity *EntityPhysics_CreateSolver( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationDuration )
-{
- if ( PhysEntityCollisionsAreDisabled( pMovingEntity, pPhysicsObject ) )
- return NULL;
-
- return CPhysicsEntitySolver::Create( pMovingEntity, pPhysicsObject, separationDuration );
-}
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "physics_saverestore.h"
+#include "vphysics/friction.h"
+#include "ai_basenpc.h"
+#include "movevars_shared.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+
+class CPhysicsNPCSolver : public CLogicalEntity, public IMotionEvent
+{
+ DECLARE_CLASS( CPhysicsNPCSolver, CLogicalEntity );
+public:
+ CPhysicsNPCSolver();
+ ~CPhysicsNPCSolver();
+ DECLARE_DATADESC();
+ void Init( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime );
+ static CPhysicsNPCSolver *Create( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime );
+
+ // CBaseEntity
+ virtual void Spawn();
+ virtual void UpdateOnRemove();
+ virtual void Think();
+ virtual void OnRestore()
+ {
+ BaseClass::OnRestore();
+ if ( m_allowIntersection )
+ {
+ PhysDisableEntityCollisions( m_hNPC, m_hEntity );
+ }
+ }
+
+ // IMotionEvent
+ virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
+
+public:
+ CPhysicsNPCSolver *m_pNext;
+private:
+ // locals
+ void ResetCancelTime();
+ void BecomePenetrationSolver();
+ bool IsIntersecting();
+ bool IsContactOnNPCHead( IPhysicsFrictionSnapshot *pSnapshot, IPhysicsObject *pPhysics, CAI_BaseNPC *pNPC );
+ bool CheckTouching();
+ friend bool NPCPhysics_SolverExists( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject );
+
+ CHandle<CAI_BaseNPC> m_hNPC;
+ EHANDLE m_hEntity;
+ IPhysicsMotionController *m_pController;
+ float m_separationDuration;
+ float m_cancelTime;
+ bool m_allowIntersection;
+};
+
+LINK_ENTITY_TO_CLASS( physics_npc_solver, CPhysicsNPCSolver );
+
+BEGIN_DATADESC( CPhysicsNPCSolver )
+
+ DEFINE_FIELD( m_hNPC, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hEntity, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_separationDuration, FIELD_FLOAT ),
+ DEFINE_FIELD( m_cancelTime, FIELD_TIME ),
+ DEFINE_FIELD( m_allowIntersection, FIELD_BOOLEAN ),
+ DEFINE_PHYSPTR( m_pController ),
+ //DEFINE_FIELD( m_pNext, FIELD_CLASSPTR ),
+
+END_DATADESC()
+
+CEntityClassList<CPhysicsNPCSolver> g_SolverList;
+template <> CPhysicsNPCSolver *CEntityClassList<CPhysicsNPCSolver>::m_pClassList = NULL;
+
+bool NPCPhysics_SolverExists( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject )
+{
+ CPhysicsNPCSolver *pSolver = g_SolverList.m_pClassList;
+ while ( pSolver )
+ {
+ if ( pSolver->m_hEntity == pPhysicsObject && pSolver->m_hNPC == pNPC )
+ return true;
+ pSolver = pSolver->m_pNext;
+ }
+
+ return false;
+}
+
+CPhysicsNPCSolver *CPhysicsNPCSolver::Create( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime )
+{
+ CPhysicsNPCSolver *pSolver = (CPhysicsNPCSolver *)CBaseEntity::CreateNoSpawn( "physics_npc_solver", vec3_origin, vec3_angle, NULL );
+ pSolver->Init( pNPC, pPhysicsObject, disableCollisions, separationTime );
+ pSolver->Spawn();
+ //NDebugOverlay::EntityBounds(pNPC, 255, 255, 0, 64, 0.5f );
+ return pSolver;
+}
+
+CPhysicsNPCSolver::CPhysicsNPCSolver()
+{
+ g_SolverList.Insert( this );
+}
+
+CPhysicsNPCSolver::~CPhysicsNPCSolver()
+{
+ g_SolverList.Remove( this );
+}
+
+void CPhysicsNPCSolver::Init( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationTime )
+{
+ m_hNPC = pNPC;
+ m_hEntity = pPhysicsObject;
+ m_pController = NULL;
+ m_separationDuration = separationTime;
+ m_allowIntersection = disableCollisions;
+
+}
+
+void CPhysicsNPCSolver::ResetCancelTime()
+{
+ m_cancelTime = gpGlobals->curtime + m_separationDuration;
+ SetNextThink( m_cancelTime );
+}
+
+void CPhysicsNPCSolver::BecomePenetrationSolver()
+{
+ CBaseEntity *pEntity = m_hEntity.Get();
+ if ( pEntity )
+ {
+ m_allowIntersection = true;
+ IPhysicsObject *pList[VPHYSICS_MAX_OBJECT_LIST_COUNT];
+ int listCount = pEntity->VPhysicsGetObjectList( pList, ARRAYSIZE(pList) );
+ PhysDisableEntityCollisions( m_hNPC, pEntity );
+ m_pController = physenv->CreateMotionController( this );
+ for ( int i = 0; i < listCount; i++ )
+ {
+ m_pController->AttachObject( pList[i], false );
+ pList[i]->Wake();
+ }
+ m_pController->SetPriority( IPhysicsMotionController::HIGH_PRIORITY );
+ }
+}
+
+void CPhysicsNPCSolver::Spawn()
+{
+ if ( m_allowIntersection )
+ {
+ BecomePenetrationSolver();
+ }
+ else
+ {
+ m_hEntity->SetNavIgnore();
+ }
+ ResetCancelTime();
+}
+
+void CPhysicsNPCSolver::UpdateOnRemove()
+{
+ if ( m_allowIntersection )
+ {
+ physenv->DestroyMotionController( m_pController );
+ m_pController = NULL;
+ PhysEnableEntityCollisions( m_hNPC, m_hEntity );
+ }
+ else
+ {
+ if ( m_hEntity.Get() )
+ {
+ m_hEntity->ClearNavIgnore();
+ }
+ }
+ //NDebugOverlay::EntityBounds(m_hNPC, 0, 255, 0, 64, 0.5f );
+ BaseClass::UpdateOnRemove();
+}
+
+bool CPhysicsNPCSolver::IsIntersecting()
+{
+ CAI_BaseNPC *pNPC = m_hNPC.Get();
+ CBaseEntity *pPhysics = m_hEntity.Get();
+ if ( pNPC && pPhysics )
+ {
+ Ray_t ray;
+ // bloated bounds to force slight separation
+ Vector mins = pNPC->WorldAlignMins() - Vector(1,1,1);
+ Vector maxs = pNPC->WorldAlignMaxs() + Vector(1,1,1);
+
+ ray.Init( pNPC->GetAbsOrigin(), pNPC->GetAbsOrigin(), mins, maxs );
+ trace_t tr;
+ enginetrace->ClipRayToEntity( ray, pNPC->PhysicsSolidMaskForEntity(), pPhysics, &tr );
+ if ( tr.startsolid )
+ return true;
+ }
+ return false;
+}
+
+bool CPhysicsNPCSolver::IsContactOnNPCHead( IPhysicsFrictionSnapshot *pSnapshot, IPhysicsObject *pPhysics, CAI_BaseNPC *pNPC )
+{
+ float heightCheck = pNPC->GetAbsOrigin().z + pNPC->GetHullMaxs().z;
+ Vector vel, point;
+ pPhysics->GetVelocity( &vel, NULL );
+ pSnapshot->GetContactPoint( point );
+ // don't care if the object is already moving away
+ if ( vel.LengthSqr() < 10.0f*10.0f )
+ {
+ float topdist = fabs(point.z-heightCheck);
+ if ( topdist < 2.0f )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CPhysicsNPCSolver::CheckTouching()
+{
+ CAI_BaseNPC *pNPC = m_hNPC.Get();
+ if ( !pNPC )
+ return false;
+
+ CBaseEntity *pPhysicsEnt = m_hEntity.Get();
+ if ( !pPhysicsEnt )
+ return false;
+
+ IPhysicsObject *pPhysics = pPhysicsEnt->VPhysicsGetObject();
+ IPhysicsObject *pNPCPhysics = pNPC->VPhysicsGetObject();
+ if ( !pNPCPhysics || !pPhysics )
+ return false;
+
+ IPhysicsFrictionSnapshot *pSnapshot = pPhysics->CreateFrictionSnapshot();
+ bool found = false;
+ bool penetrate = false;
+
+ while ( pSnapshot->IsValid() )
+ {
+ IPhysicsObject *pOther = pSnapshot->GetObject(1);
+ if ( pOther == pNPCPhysics )
+ {
+ found = true;
+ if ( IsContactOnNPCHead(pSnapshot, pPhysics, pNPC ) )
+ {
+ penetrate = true;
+ pSnapshot->MarkContactForDelete();
+ }
+ break;
+ }
+ pSnapshot->NextFrictionData();
+ }
+ pSnapshot->DeleteAllMarkedContacts( true );
+ pPhysics->DestroyFrictionSnapshot( pSnapshot );
+
+ // if the object is penetrating something, check to see if it's intersecting this NPC
+ // if so, go ahead and switch over to penetration solver mode
+ if ( !penetrate && (pPhysics->GetGameFlags() & FVPHYSICS_PENETRATING) )
+ {
+ penetrate = IsIntersecting();
+ }
+
+ if ( penetrate )
+ {
+ pPhysicsEnt->ClearNavIgnore();
+ BecomePenetrationSolver();
+ }
+
+ return found;
+}
+
+void CPhysicsNPCSolver::Think()
+{
+ bool finished = m_allowIntersection ? !IsIntersecting() : !CheckTouching();
+
+ if ( finished )
+ {
+ UTIL_Remove(this);
+ return;
+ }
+ if ( m_allowIntersection )
+ {
+ IPhysicsObject *pObject = m_hEntity->VPhysicsGetObject();
+ if ( !pObject )
+ {
+ UTIL_Remove(this);
+ return;
+ }
+ pObject->Wake();
+ }
+ ResetCancelTime();
+}
+
+IMotionEvent::simresult_e CPhysicsNPCSolver::Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject,
+ float deltaTime, Vector &linear, AngularImpulse &angular )
+{
+ if ( IsIntersecting() )
+ {
+ const float PUSH_SPEED = 150.0f;
+
+ if ( pObject->GetGameFlags() & FVPHYSICS_PLAYER_HELD )
+ {
+ CBasePlayer *pPlayer = UTIL_GetLocalPlayer();
+ if ( pPlayer )
+ {
+ pPlayer->ForceDropOfCarriedPhysObjects( m_hEntity );
+ }
+ }
+
+ ResetCancelTime();
+ angular.Init();
+ linear.Init();
+
+ // Don't push on vehicles because they won't move
+ if ( pObject->GetGameFlags() & FVPHYSICS_MULTIOBJECT_ENTITY )
+ {
+ if ( m_hEntity->GetServerVehicle() )
+ return SIM_NOTHING;
+ }
+
+ Vector origin, vel;
+ pObject->GetPosition( &origin, NULL );
+ pObject->GetVelocity( &vel, NULL );
+ Vector dir = origin - m_hNPC->GetAbsOrigin();
+ dir.z = dir.z > 0 ? 0.1f : -0.1f;
+ VectorNormalize(dir);
+ AngularImpulse angVel;
+ angVel.Init();
+
+ // NOTE: Iterate this object's contact points
+ // if it can't move in this direction, try sliding along the plane/crease
+ Vector pushImpulse;
+ PhysComputeSlideDirection( pObject, dir * PUSH_SPEED, angVel, &pushImpulse, NULL, 0 );
+
+ dir = pushImpulse;
+ VectorNormalize(dir);
+
+ if ( DotProduct( vel, dir ) < PUSH_SPEED * 0.5f )
+ {
+ linear = pushImpulse;
+ if ( pObject->GetContactPoint(NULL,NULL) )
+ {
+ linear.z += GetCurrentGravity();
+ }
+ }
+ return SIM_GLOBAL_ACCELERATION;
+ }
+ return SIM_NOTHING;
+}
+
+
+CBaseEntity *NPCPhysics_CreateSolver( CAI_BaseNPC *pNPC, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationDuration )
+{
+ if ( disableCollisions )
+ {
+ if ( PhysEntityCollisionsAreDisabled( pNPC, pPhysicsObject ) )
+ return NULL;
+ }
+ else
+ {
+ if ( pPhysicsObject->IsNavIgnored() )
+ return NULL;
+ }
+ return CPhysicsNPCSolver::Create( pNPC, pPhysicsObject, disableCollisions, separationDuration );
+}
+
+
+class CPhysicsEntitySolver : public CLogicalEntity//, public IMotionEvent
+{
+ DECLARE_CLASS( CPhysicsEntitySolver, CLogicalEntity );
+public:
+ DECLARE_DATADESC();
+ void Init( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime );
+ static CPhysicsEntitySolver *Create( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime );
+
+ // CBaseEntity
+ virtual void Spawn();
+ virtual void UpdateOnRemove();
+ virtual void Think();
+
+ // IMotionEvent
+ //virtual simresult_e Simulate( IPhysicsMotionController *pController, IPhysicsObject *pObject, float deltaTime, Vector &linear, AngularImpulse &angular );
+
+private:
+ // locals
+ void ResetCancelTime();
+ void BecomePenetrationSolver();
+ //bool IsIntersecting();
+ //bool IsTouching();
+
+ EHANDLE m_hMovingEntity;
+ EHANDLE m_hPhysicsBlocker;
+ //IPhysicsMotionController *m_pController;
+ float m_separationDuration;
+ float m_cancelTime;
+ int m_savedCollisionGroup;
+};
+
+LINK_ENTITY_TO_CLASS( physics_entity_solver, CPhysicsEntitySolver );
+
+BEGIN_DATADESC( CPhysicsEntitySolver )
+
+ DEFINE_FIELD( m_hMovingEntity, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_hPhysicsBlocker, FIELD_EHANDLE ),
+ DEFINE_FIELD( m_separationDuration, FIELD_FLOAT ),
+ DEFINE_FIELD( m_cancelTime, FIELD_TIME ),
+ DEFINE_FIELD( m_savedCollisionGroup, FIELD_INTEGER ),
+ //DEFINE_PHYSPTR( m_pController ),
+
+END_DATADESC()
+
+CPhysicsEntitySolver *CPhysicsEntitySolver::Create( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime )
+{
+ CPhysicsEntitySolver *pSolver = (CPhysicsEntitySolver *)CBaseEntity::CreateNoSpawn( "physics_entity_solver", vec3_origin, vec3_angle, NULL );
+ pSolver->Init( pMovingEntity, pPhysicsBlocker, separationTime );
+ pSolver->Spawn();
+ //NDebugOverlay::EntityBounds(pNPC, 255, 255, 0, 64, 0.5f );
+ return pSolver;
+}
+
+void CPhysicsEntitySolver::Init( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsBlocker, float separationTime )
+{
+ m_hMovingEntity = pMovingEntity;
+ m_hPhysicsBlocker = pPhysicsBlocker;
+ //m_pController = NULL;
+ m_separationDuration = separationTime;
+}
+
+void CPhysicsEntitySolver::Spawn()
+{
+ SetNextThink( gpGlobals->curtime + m_separationDuration );
+ PhysDisableEntityCollisions( m_hMovingEntity, m_hPhysicsBlocker );
+ m_savedCollisionGroup = m_hPhysicsBlocker->GetCollisionGroup();
+ m_hPhysicsBlocker->SetCollisionGroup( COLLISION_GROUP_DEBRIS );
+ if ( m_hPhysicsBlocker->VPhysicsGetObject() )
+ {
+ m_hPhysicsBlocker->VPhysicsGetObject()->RecheckContactPoints();
+ }
+}
+
+void CPhysicsEntitySolver::Think()
+{
+ UTIL_Remove(this);
+}
+
+void CPhysicsEntitySolver::UpdateOnRemove()
+{
+ //physenv->DestroyMotionController( m_pController );
+ //m_pController = NULL;
+ CBaseEntity *pEntity = m_hMovingEntity.Get();
+ CBaseEntity *pPhysics = m_hPhysicsBlocker.Get();
+ if ( pEntity && pPhysics )
+ {
+ PhysEnableEntityCollisions( pEntity, pPhysics );
+ }
+ if ( pPhysics )
+ {
+ pPhysics->SetCollisionGroup( m_savedCollisionGroup );
+ }
+ BaseClass::UpdateOnRemove();
+}
+
+
+CBaseEntity *EntityPhysics_CreateSolver( CBaseEntity *pMovingEntity, CBaseEntity *pPhysicsObject, bool disableCollisions, float separationDuration )
+{
+ if ( PhysEntityCollisionsAreDisabled( pMovingEntity, pPhysicsObject ) )
+ return NULL;
+
+ return CPhysicsEntitySolver::Create( pMovingEntity, pPhysicsObject, separationDuration );
+}
+