You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
701 lines
20 KiB
701 lines
20 KiB
//========= Copyright © 1996-2003, Valve LLC, All rights reserved. ============ |
|
// |
|
// Purpose: |
|
// |
|
//============================================================================= |
|
|
|
#include "cbase.h" |
|
#include "asw_vphysics_npc.h" |
|
#include "physobj.h" |
|
#include "vphysics/player_controller.h" |
|
#include "vcollide_parse.h" |
|
#include "igamemovement.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
// if this is defined then this npc is given a vphysics shadow, so he can push things, etc. (currently bugged) |
|
//#define USE_VPHYSICS_SHADOW |
|
|
|
//---------------------------------------------------- |
|
// Player Physics Shadow |
|
//---------------------------------------------------- |
|
#define VPHYS_MAX_DISTANCE 2.0 |
|
#define VPHYS_MAX_VEL 10 |
|
#define VPHYS_MAX_DISTSQR (VPHYS_MAX_DISTANCE*VPHYS_MAX_DISTANCE) |
|
#define VPHYS_MAX_VELSQR (VPHYS_MAX_VEL*VPHYS_MAX_VEL) |
|
#define SMOOTHING_FACTOR 0.9 |
|
|
|
static ConVar marinephysicsshadowupdate_render( "marinephysicsshadowupdate_render", "0" ); |
|
|
|
//========================================================= |
|
// Marine activities |
|
//========================================================= |
|
|
|
|
|
LINK_ENTITY_TO_CLASS( asw_vphysics_npc, CASW_VPhysics_NPC ); |
|
|
|
//--------------------------------------------------------- |
|
// |
|
//--------------------------------------------------------- |
|
|
|
IMPLEMENT_SERVERCLASS_ST(CASW_VPhysics_NPC, DT_ASW_VPhysics_NPC) |
|
|
|
END_SEND_TABLE() |
|
|
|
|
|
|
|
//--------------------------------------------------------- |
|
// Save/Restore |
|
//--------------------------------------------------------- |
|
BEGIN_DATADESC( CASW_VPhysics_NPC ) |
|
DEFINE_FIELD( m_vNewVPhysicsPosition, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_vNewVPhysicsVelocity, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_vecLastSafePosition, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_afPhysicsFlags, FIELD_INTEGER ), |
|
DEFINE_FIELD( m_touchedPhysObject, FIELD_BOOLEAN ), |
|
DEFINE_FIELD( m_vecSmoothedVelocity, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_oldOrigin, FIELD_VECTOR ), |
|
DEFINE_FIELD( m_vphysicsCollisionState, FIELD_INTEGER ), |
|
//DEFINE_FIELD( m_pPhysicsController, FIELD_POINTER ), |
|
//DEFINE_FIELD( m_pShadowStand, FIELD_POINTER ), |
|
//DEFINE_FIELD( m_pShadowCrouch, FIELD_POINTER ), |
|
END_DATADESC() |
|
|
|
|
|
CASW_VPhysics_NPC::CASW_VPhysics_NPC() |
|
{ |
|
|
|
} |
|
|
|
|
|
CASW_VPhysics_NPC::~CASW_VPhysics_NPC() |
|
{ |
|
VPhysicsDestroyObject(); |
|
} |
|
|
|
void CASW_VPhysics_NPC::UpdateOnRemove( void ) |
|
{ |
|
VPhysicsDestroyObject(); |
|
|
|
// Chain at end to mimic destructor unwind order |
|
BaseClass::UpdateOnRemove(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_VPhysics_NPC::Spawn( void ) |
|
{ |
|
BaseClass::Spawn(); |
|
|
|
#ifdef USE_VPHYSICS_SHADOW |
|
m_afPhysicsFlags = 0; |
|
m_vecSmoothedVelocity = vec3_origin; |
|
InitVCollision(); |
|
m_vecLastSafePosition = GetAbsOrigin(); |
|
#endif |
|
} |
|
|
|
int CASW_VPhysics_NPC::Restore( IRestore &restore ) |
|
{ |
|
int status = BaseClass::Restore(restore); |
|
if ( !status ) |
|
return 0; |
|
|
|
// clear this - it will get reset by touching the trigger again |
|
m_afPhysicsFlags &= ~PFLAG_VPHYSICS_MOTIONCONTROLLER; |
|
|
|
InitVCollision(); |
|
|
|
// success |
|
return 1; |
|
} |
|
|
|
void CASW_VPhysics_NPC::InhabitedPhysicsSimulate() |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
return; |
|
|
|
// Update our vphysics object. |
|
if ( m_pPhysicsController ) |
|
{ |
|
// If simulating at 2 * TICK_INTERVAL, add an extra TICK_INTERVAL to position arrival computation |
|
//int additionalTick = CBaseEntity::IsSimulatingOnAlternateTicks() ? 1 : 0; |
|
|
|
//float flSecondsToArrival = ( ctx->numcmds + ctx->dropped_packets + additionalTick ) * TICK_INTERVAL; |
|
float flSecondsToArrival = gpGlobals->frametime; |
|
UpdateVPhysicsPosition( m_vNewVPhysicsPosition, m_vNewVPhysicsVelocity, flSecondsToArrival ); |
|
} |
|
#endif |
|
} |
|
|
|
void CASW_VPhysics_NPC::UpdateVPhysicsAfterMove() |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
// Update our vphysics object. |
|
if ( m_pPhysicsController ) |
|
{ |
|
// If simulating at 2 * TICK_INTERVAL, add an extra TICK_INTERVAL to position arrival computation |
|
//int additionalTick = CBaseEntity::IsSimulatingOnAlternateTicks() ? 1 : 0; |
|
|
|
//float flSecondsToArrival = ( ctx->numcmds + ctx->dropped_packets + additionalTick ) * TICK_INTERVAL; |
|
float flSecondsToArrival = gpGlobals->frametime; |
|
UpdateVPhysicsPosition( m_vNewVPhysicsPosition, m_vNewVPhysicsVelocity, flSecondsToArrival ); |
|
} |
|
#endif |
|
} |
|
|
|
void CASW_VPhysics_NPC::PostThink( void ) |
|
{ |
|
m_vecSmoothedVelocity = m_vecSmoothedVelocity * SMOOTHING_FACTOR + GetAbsVelocity() * ( 1 - SMOOTHING_FACTOR ); |
|
|
|
//if ( IsAlive() ) |
|
//{ |
|
//PostThinkVPhysics(); |
|
//} |
|
} |
|
|
|
void CASW_VPhysics_NPC::InitVCollision( void ) |
|
{ |
|
// Cleanup any old vphysics stuff. |
|
VPhysicsDestroyObject(); |
|
|
|
|
|
CPhysCollide *pModel = PhysCreateBbox( WorldAlignMins(), WorldAlignMaxs() ); |
|
CPhysCollide *pCrouchModel = PhysCreateBbox( VEC_DUCK_HULL_MIN, VEC_DUCK_HULL_MAX ); |
|
|
|
SetupVPhysicsShadow( pModel, "player_stand", pCrouchModel, "player_crouch" ); |
|
} |
|
|
|
void CASW_VPhysics_NPC::VPhysicsDestroyObject() |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
// Since CBasePlayer aliases its pointer to the physics object, tell CBaseEntity to |
|
// clear out its physics object pointer so we don't wind up deleting one of |
|
// the aliased objects twice. |
|
VPhysicsSetObject( NULL ); |
|
|
|
PhysRemoveShadow( this ); |
|
|
|
if ( m_pPhysicsController ) |
|
{ |
|
physenv->DestroyPlayerController( m_pPhysicsController ); |
|
m_pPhysicsController = NULL; |
|
} |
|
|
|
if ( m_pShadowStand ) |
|
{ |
|
PhysDestroyObject( m_pShadowStand ); |
|
m_pShadowStand = NULL; |
|
} |
|
if ( m_pShadowCrouch ) |
|
{ |
|
PhysDestroyObject( m_pShadowCrouch ); |
|
m_pShadowCrouch = NULL; |
|
} |
|
#endif |
|
BaseClass::VPhysicsDestroyObject(); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_VPhysics_NPC::SetVCollisionState( int collisionState ) |
|
{ |
|
Vector vel = vec3_origin; |
|
Vector pos = vec3_origin; |
|
vel = GetAbsVelocity(); |
|
pos = GetAbsOrigin(); |
|
|
|
m_vphysicsCollisionState = collisionState; |
|
switch( collisionState ) |
|
{ |
|
case VPHYS_WALK: |
|
m_pShadowStand->SetPosition( pos, vec3_angle, true ); |
|
m_pShadowStand->SetVelocity( &vel, NULL ); |
|
m_pShadowCrouch->EnableCollisions( false ); |
|
m_pShadowStand->EnableCollisions( true ); |
|
m_pPhysicsController->SetObject( m_pShadowStand ); |
|
VPhysicsSwapObject( m_pShadowStand ); |
|
break; |
|
|
|
case VPHYS_CROUCH: |
|
m_pShadowCrouch->SetPosition( pos, vec3_angle, true ); |
|
m_pShadowCrouch->SetVelocity( &vel, NULL ); |
|
m_pShadowStand->EnableCollisions( false ); |
|
m_pShadowCrouch->EnableCollisions( true ); |
|
m_pPhysicsController->SetObject( m_pShadowCrouch ); |
|
VPhysicsSwapObject( m_pShadowCrouch ); |
|
break; |
|
|
|
case VPHYS_NOCLIP: |
|
m_pShadowCrouch->EnableCollisions( false ); |
|
m_pShadowStand->EnableCollisions( false ); |
|
break; |
|
} |
|
} |
|
|
|
void CASW_VPhysics_NPC::VPhysicsShadowUpdate( IPhysicsObject *pPhysics ) |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
Vector newPosition; |
|
|
|
m_touchedPhysObject = false; // asw try to clear |
|
|
|
bool bMarineStuck = false; |
|
|
|
bool physicsUpdated = m_pPhysicsController->GetShadowPosition( &newPosition, NULL ) > 0 ? true : false; |
|
|
|
// UNDONE: If the player is penetrating, but the player's game collisions are not stuck, teleport the physics shadow to the game position |
|
if ( pPhysics->GetGameFlags() & FVPHYSICS_PENETRATING ) |
|
{ |
|
CUtlVector<CBaseEntity *> list; |
|
PhysGetListOfPenetratingEntities( this, list ); |
|
for ( int i = list.Count()-1; i >= 0; --i ) |
|
{ |
|
// filter out anything that isn't simulated by vphysics |
|
// UNDONE: Filter out motion disabled objects? |
|
if ( list[i]->GetMoveType() == MOVETYPE_VPHYSICS ) |
|
{ |
|
// I'm currently stuck inside a moving object, so allow vphysics to |
|
// apply velocity to the player in order to separate these objects |
|
m_touchedPhysObject = true; |
|
} |
|
} |
|
} |
|
|
|
if ( m_pPhysicsController->IsInContact() || (m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER) ) |
|
{ |
|
m_touchedPhysObject = true; |
|
} |
|
|
|
if ( IsFollowingPhysics() ) |
|
{ |
|
m_touchedPhysObject = true; |
|
} |
|
|
|
if ( GetMoveType() == MOVETYPE_NOCLIP ) |
|
{ |
|
m_oldOrigin = GetAbsOrigin(); |
|
return; |
|
} |
|
|
|
if ( phys_timescale.GetFloat() == 0.0f ) |
|
{ |
|
physicsUpdated = false; |
|
} |
|
|
|
if ( !physicsUpdated ) |
|
return; |
|
|
|
IPhysicsObject *pPhysGround = GetGroundVPhysics(); |
|
|
|
Vector newVelocity; |
|
pPhysics->GetPosition( &newPosition, 0 ); |
|
m_pPhysicsController->GetShadowVelocity( &newVelocity ); |
|
|
|
if ( marinephysicsshadowupdate_render.GetBool() ) |
|
{ |
|
//NDebugOverlay::Box( GetAbsOrigin(), WorldAlignMins(), WorldAlignMaxs(), 255, 0, 0, 24, 15.0f ); |
|
NDebugOverlay::Box( newPosition, WorldAlignMins(), WorldAlignMaxs(), 0,0,255, 24, 15.0f); |
|
NDebugOverlay::Box( newPosition, WorldAlignMins(), WorldAlignMaxs(), 0,0,255, 24, .01f); |
|
} |
|
//if (m_touchedPhysObject) |
|
//Msg("touched physics object\n"); |
|
|
|
Vector tmp = GetAbsOrigin() - newPosition; |
|
if ( !m_touchedPhysObject && !(GetFlags() & FL_ONGROUND) ) |
|
{ |
|
tmp.z *= 0.5f; // don't care about z delta as much |
|
} |
|
|
|
float dist = tmp.LengthSqr(); |
|
float deltaV = (newVelocity - GetAbsVelocity()).LengthSqr(); |
|
|
|
float maxDistErrorSqr = VPHYS_MAX_DISTSQR; |
|
float maxVelErrorSqr = VPHYS_MAX_VELSQR; |
|
if ( IsRideablePhysics(pPhysGround) ) |
|
{ |
|
maxDistErrorSqr *= 0.25; |
|
maxVelErrorSqr *= 0.25; |
|
} |
|
|
|
if ( dist >= maxDistErrorSqr || deltaV >= maxVelErrorSqr || (pPhysGround && !m_touchedPhysObject) ) |
|
{ |
|
if ( m_touchedPhysObject || pPhysGround ) |
|
{ |
|
// BUGBUG: Rewrite this code using fixed timestep |
|
if ( deltaV >= maxVelErrorSqr ) |
|
{ |
|
Vector dir = GetAbsVelocity(); |
|
float len = VectorNormalize(dir); |
|
float dot = DotProduct( newVelocity, dir ); |
|
if ( dot > len ) |
|
{ |
|
dot = len; |
|
} |
|
else if ( dot < -len ) |
|
{ |
|
dot = -len; |
|
} |
|
|
|
VectorMA( newVelocity, -dot, dir, newVelocity ); |
|
|
|
if ( m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER ) |
|
{ |
|
float val = Lerp( 0.1f, len, dot ); |
|
VectorMA( newVelocity, val - len, dir, newVelocity ); |
|
} |
|
|
|
if ( !IsRideablePhysics(pPhysGround) ) |
|
{ |
|
if ( !(m_afPhysicsFlags & PFLAG_VPHYSICS_MOTIONCONTROLLER ) && IsSimulatingOnAlternateTicks() ) |
|
{ |
|
newVelocity *= 0.5f; |
|
} |
|
ApplyAbsVelocityImpulse( newVelocity ); |
|
} |
|
} |
|
|
|
trace_t trace; |
|
UTIL_TraceEntity( this, newPosition, newPosition, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); |
|
if ( !trace.allsolid && !trace.startsolid ) |
|
{ |
|
SetAbsOrigin( newPosition ); |
|
} |
|
else |
|
{ |
|
Warning( "Stuck3 on %s!!\n", trace.m_pEnt->GetClassname() ); |
|
bMarineStuck = true; |
|
} |
|
} |
|
else |
|
{ |
|
trace_t trace; |
|
UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); |
|
|
|
// current position is not ok, fixup |
|
if ( trace.allsolid || trace.startsolid ) |
|
{ |
|
// STUCK!?!?! |
|
Warning( "Stuck2 on %s!!\n", trace.m_pEnt->GetClassname() ); |
|
SetAbsOrigin( newPosition ); |
|
bMarineStuck = true; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
if ( m_touchedPhysObject ) |
|
{ |
|
// check my position (physics object could have simulated into my position |
|
// physics is not very far away, check my position |
|
trace_t trace; |
|
UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), |
|
MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); |
|
|
|
// is current position ok? |
|
if ( trace.allsolid || trace.startsolid ) |
|
{ |
|
// stuck????!?!? |
|
Msg("Stuck on %s\n", trace.m_pEnt->GetClassname()); |
|
SetAbsOrigin( newPosition ); |
|
UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), |
|
MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); |
|
if ( trace.allsolid || trace.startsolid ) |
|
{ |
|
Msg("Double Stuck\n"); |
|
SetAbsOrigin( m_oldOrigin ); |
|
bMarineStuck = true; |
|
} |
|
} |
|
} |
|
} |
|
m_oldOrigin = GetAbsOrigin(); |
|
// UNDONE: Force physics object to be at player position when not touching phys??? |
|
|
|
// if we're stuck, move us to our last safe position and check that position is free of phys objects |
|
if (bMarineStuck) |
|
{ |
|
// check if our last safe position is ok |
|
trace_t trace; |
|
UTIL_TraceEntity( this, m_vecLastSafePosition, m_vecLastSafePosition, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); |
|
if ( !trace.allsolid && !trace.startsolid ) |
|
{ |
|
// position is free, so move there |
|
SetAbsOrigin(m_vecLastSafePosition); |
|
Msg("Moving marine to last safe position\n"); |
|
} |
|
else |
|
{ |
|
// safe position now has something in the way |
|
// could try: pushing the thing aside? |
|
// giving it no collision with the marine? (temporarily?) |
|
if (trace.m_pEnt) |
|
{ |
|
CAI_BaseNPC *pAI = dynamic_cast<CAI_BaseNPC*>(trace.m_pEnt); |
|
if (!pAI && trace.m_pEnt->entindex()>gpGlobals->maxClients) // make sure it's not an NPC or the world |
|
{ |
|
//m_BlockingEntities.AddToTail(trace.m_pEnt); |
|
//m_BlockingCollisionGroup.AddToTail(trace.m_pEnt->GetCollisionGroup()); |
|
//trace.m_pEnt->SetCollisionGroup(ASW_COLLISION_GROUP_PASSABLE); |
|
//Msg("Turning off collision on object: %d\n", trace.m_pEnt->entindex()); |
|
} |
|
Msg("Safe position was blocked by %s\n", trace.m_pEnt->GetClassname()); |
|
} |
|
else |
|
{ |
|
Msg("Safe position was blocked by unknown\n"); |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
trace_t trace; |
|
UTIL_TraceEntity( this, GetAbsOrigin(), GetAbsOrigin(), MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); |
|
if ( !trace.allsolid && !trace.startsolid ) |
|
{ |
|
m_vecLastSafePosition = GetAbsOrigin(); |
|
// we're safe and free, so restore collision on any previous blocking entities |
|
//if (m_BlockingEntities.Count() > 0) |
|
//{ |
|
//for (int i=0;i<m_BlockingEntities.Count();i++) |
|
//{ |
|
//CBaseEntity *pEnt = m_BlockingEntities[i].Get(); |
|
//if (pEnt) |
|
//{ |
|
////pEnt->SetCollisionGroup(m_BlockingCollisionGroup[i]); |
|
////Msg("Restoring collision on object: %d\n", pEnt->entindex()); |
|
//} |
|
//} |
|
//m_BlockingEntities.RemoveAll(); |
|
//m_BlockingCollisionGroup.RemoveAll(); |
|
//} |
|
} |
|
} |
|
#endif |
|
} |
|
|
|
// recreate physics on save/load, don't try to save the state! |
|
bool CASW_VPhysics_NPC::ShouldSavePhysics() |
|
{ |
|
return false; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_VPhysics_NPC::PostThinkVPhysics(CMoveData* pMoveData) |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
// Check to see if things are initialized! |
|
if ( !m_pPhysicsController ) |
|
{ |
|
//Msg("not updating physics for marine as he has no physics controller\n"); |
|
return; |
|
} |
|
|
|
Vector newPosition = GetAbsOrigin(); |
|
float frametime = gpGlobals->frametime; |
|
if ( frametime <= 0 || frametime > 0.1f ) |
|
frametime = 0.1f; |
|
|
|
IPhysicsObject *pPhysGround = GetGroundVPhysics(); |
|
|
|
// asw phys fix: |
|
if ( !pPhysGround && m_touchedPhysObject && pMoveData->m_outStepHeight <= 0.f && (GetFlags() & FL_ONGROUND) ) |
|
{ |
|
newPosition = m_oldOrigin + frametime * pMoveData->m_outWishVel; |
|
newPosition = (GetAbsOrigin() * 0.5f) + (newPosition * 0.5f); |
|
} |
|
|
|
int collisionState = VPHYS_WALK; |
|
if ( GetMoveType() == MOVETYPE_NOCLIP || GetMoveType() == MOVETYPE_OBSERVER ) |
|
{ |
|
Msg(" setting vphys_noclip on marine\n"); |
|
collisionState = VPHYS_NOCLIP; |
|
} |
|
//else if ( GetFlags() & FL_DUCKING ) |
|
//{ |
|
//Msg(" setting vphys_crouch on marine\n"); |
|
//collisionState = VPHYS_CROUCH; |
|
//} |
|
|
|
if ( collisionState != m_vphysicsCollisionState ) |
|
{ |
|
SetVCollisionState( collisionState ); |
|
} |
|
|
|
// asw phys fix: |
|
if ( !(TouchedPhysics() || pPhysGround) ) |
|
{ |
|
float maxSpeed = MaxSpeed(); |
|
pMoveData->m_outWishVel.Init( maxSpeed, maxSpeed, maxSpeed ); |
|
} |
|
|
|
// teleport the physics object up by stepheight (game code does this - reflect in the physics) |
|
// asw phys fix: |
|
if ( pMoveData->m_outStepHeight > 0.1f ) |
|
{ |
|
if ( pMoveData->m_outStepHeight > 4.0f ) |
|
{ |
|
VPhysicsGetObject()->SetPosition( GetAbsOrigin(), vec3_angle, true ); |
|
} |
|
else |
|
{ |
|
// don't ever teleport into solid |
|
Vector position, end; |
|
VPhysicsGetObject()->GetPosition( &position, NULL ); |
|
end = position; |
|
end.z += pMoveData->m_outStepHeight; |
|
trace_t trace; |
|
UTIL_TraceEntity( this, position, end, MASK_PLAYERSOLID, this, COLLISION_GROUP_PLAYER_MOVEMENT, &trace ); |
|
if ( trace.DidHit() ) |
|
{ |
|
pMoveData->m_outStepHeight = trace.endpos.z - position.z; |
|
} |
|
m_pPhysicsController->StepUp( pMoveData->m_outStepHeight ); |
|
} |
|
m_pPhysicsController->Jump(); |
|
} |
|
pMoveData->m_outStepHeight = 0.0f; |
|
|
|
|
|
// Store these off because after running the usercmds, it'll pass them |
|
// to UpdateVPhysicsPosition. |
|
m_vNewVPhysicsPosition = newPosition; |
|
m_vNewVPhysicsVelocity = pMoveData->m_outWishVel; |
|
//Msg("updating marine vphys pos to %f %f %f\n", newPosition.x, newPosition.y, newPosition.z); |
|
m_oldOrigin = GetAbsOrigin(); |
|
#endif |
|
} |
|
|
|
void CASW_VPhysics_NPC::UpdateVPhysicsPosition( const Vector &position, const Vector &velocity, float secondsToArrival ) |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
bool onground = (GetFlags() & FL_ONGROUND) ? true : false; |
|
IPhysicsObject *pPhysGround = GetGroundVPhysics(); |
|
|
|
// if the object is much heavier than the player, treat it as a local coordinate system |
|
// the player controller will solve movement differently in this case. |
|
if ( !IsRideablePhysics(pPhysGround) ) |
|
{ |
|
pPhysGround = NULL; |
|
} |
|
|
|
m_pPhysicsController->Update( position, velocity, secondsToArrival, onground, pPhysGround ); |
|
#endif |
|
} |
|
|
|
void CASW_VPhysics_NPC::UpdatePhysicsShadowToCurrentPosition() |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
UpdateVPhysicsPosition( GetAbsOrigin(), vec3_origin, 0 ); |
|
#endif |
|
} |
|
|
|
void CASW_VPhysics_NPC::SetupVPhysicsShadow( CPhysCollide *pStandModel, const char *pStandHullName, CPhysCollide *pCrouchModel, const char *pCrouchHullName ) |
|
{ |
|
solid_t solid; |
|
Q_strncpy( solid.surfaceprop, "player", sizeof(solid.surfaceprop) ); |
|
solid.params = g_PhysDefaultObjectParams; |
|
solid.params.mass = 85.0f; |
|
solid.params.inertia = 1e24f; |
|
solid.params.enableCollisions = false; |
|
//disable drag |
|
solid.params.dragCoefficient = 0; |
|
// create standing hull |
|
m_pShadowStand = PhysModelCreateCustom( this, pStandModel, GetLocalOrigin(), GetLocalAngles(), pStandHullName, false, &solid ); |
|
m_pShadowStand->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION ); |
|
|
|
// create crouchig hull |
|
m_pShadowCrouch = PhysModelCreateCustom( this, pCrouchModel, GetLocalOrigin(), GetLocalAngles(), pCrouchHullName, false, &solid ); |
|
m_pShadowCrouch->SetCallbackFlags( CALLBACK_GLOBAL_COLLISION | CALLBACK_SHADOW_COLLISION ); |
|
|
|
// default to stand |
|
VPhysicsSetObject( m_pShadowStand ); |
|
|
|
// tell physics lists I'm a shadow controller object |
|
PhysAddShadow( this ); |
|
m_pPhysicsController = physenv->CreatePlayerController( m_pShadowStand ); |
|
m_pPhysicsController->SetPushMassLimit( 350.0f ); |
|
m_pPhysicsController->SetPushSpeedLimit( 50.0f ); |
|
|
|
// Give the controller a valid position so it doesn't do anything rash. |
|
UpdatePhysicsShadowToCurrentPosition(); |
|
|
|
// init state |
|
if ( GetFlags() & FL_DUCKING ) |
|
{ |
|
SetVCollisionState( VPHYS_CROUCH ); |
|
} |
|
else |
|
{ |
|
SetVCollisionState( VPHYS_WALK ); |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Empty, just want to keep the baseentity version from being called |
|
// current so we don't kick up dust, etc. |
|
//----------------------------------------------------------------------------- |
|
void CASW_VPhysics_NPC::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) |
|
{ |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void CASW_VPhysics_NPC::VPhysicsUpdate( IPhysicsObject *pPhysics ) |
|
{ |
|
float savedImpact = m_impactEnergyScale; |
|
|
|
// HACKHACK: Reduce player's stress by 1/8th |
|
m_impactEnergyScale *= 0.125f; |
|
ApplyStressDamage( pPhysics, true ); |
|
m_impactEnergyScale = savedImpact; |
|
} |
|
|
|
bool CASW_VPhysics_NPC::IsRideablePhysics( IPhysicsObject *pPhysics ) |
|
{ |
|
if ( pPhysics ) |
|
{ |
|
if ( pPhysics->GetMass() > (VPhysicsGetObject()->GetMass()*2) ) |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
IPhysicsObject *CASW_VPhysics_NPC::GetGroundVPhysics() |
|
{ |
|
CBaseEntity *pGroundEntity = GetGroundEntity(); |
|
if ( pGroundEntity && pGroundEntity->GetMoveType() == MOVETYPE_VPHYSICS ) |
|
{ |
|
IPhysicsObject *pPhysGround = pGroundEntity->VPhysicsGetObject(); |
|
if ( pPhysGround && pPhysGround->IsMoveable() ) |
|
return pPhysGround; |
|
} |
|
return NULL; |
|
} |
|
|
|
void CASW_VPhysics_NPC::Touch( CBaseEntity *pOther ) |
|
{ |
|
#ifdef USE_VPHYSICS_SHADOW |
|
if ( pOther == GetGroundEntity() ) |
|
return; |
|
|
|
if ( pOther->GetMoveType() != MOVETYPE_VPHYSICS || pOther->GetSolid() != SOLID_VPHYSICS || (pOther->GetSolidFlags() & FSOLID_TRIGGER) ) |
|
return; |
|
|
|
IPhysicsObject *pPhys = pOther->VPhysicsGetObject(); |
|
if ( !pPhys || !pPhys->IsMoveable() ) |
|
return; |
|
|
|
SetTouchedPhysics( true ); |
|
#endif |
|
} |
|
|
|
float CASW_VPhysics_NPC::MaxSpeed() { return 300.0f; } |