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.
649 lines
19 KiB
649 lines
19 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "c_basehlplayer.h" |
|
#include "playerandobjectenumerator.h" |
|
#include "engine/ivdebugoverlay.h" |
|
#include "c_ai_basenpc.h" |
|
#include "in_buttons.h" |
|
#include "collisionutils.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
// How fast to avoid collisions with center of other object, in units per second |
|
#define AVOID_SPEED 2000.0f |
|
extern ConVar cl_forwardspeed; |
|
extern ConVar cl_backspeed; |
|
extern ConVar cl_sidespeed; |
|
|
|
extern ConVar zoom_sensitivity_ratio; |
|
extern ConVar default_fov; |
|
extern ConVar sensitivity; |
|
|
|
ConVar cl_npc_speedmod_intime( "cl_npc_speedmod_intime", "0.25", FCVAR_CLIENTDLL | FCVAR_ARCHIVE ); |
|
ConVar cl_npc_speedmod_outtime( "cl_npc_speedmod_outtime", "1.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE ); |
|
|
|
IMPLEMENT_CLIENTCLASS_DT(C_BaseHLPlayer, DT_HL2_Player, CHL2_Player) |
|
RecvPropDataTable( RECVINFO_DT(m_HL2Local),0, &REFERENCE_RECV_TABLE(DT_HL2Local) ), |
|
RecvPropBool( RECVINFO( m_fIsSprinting ) ), |
|
END_RECV_TABLE() |
|
|
|
BEGIN_PREDICTION_DATA( C_BaseHLPlayer ) |
|
DEFINE_PRED_TYPEDESCRIPTION( m_HL2Local, C_HL2PlayerLocalData ), |
|
DEFINE_PRED_FIELD( m_fIsSprinting, FIELD_BOOLEAN, FTYPEDESC_INSENDTABLE ), |
|
END_PREDICTION_DATA() |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Drops player's primary weapon |
|
//----------------------------------------------------------------------------- |
|
void CC_DropPrimary( void ) |
|
{ |
|
C_BasePlayer *pPlayer = (C_BasePlayer *) C_BasePlayer::GetLocalPlayer(); |
|
|
|
if ( pPlayer == NULL ) |
|
return; |
|
|
|
pPlayer->Weapon_DropPrimary(); |
|
} |
|
|
|
static ConCommand dropprimary("dropprimary", CC_DropPrimary, "dropprimary: Drops the primary weapon of the player."); |
|
|
|
//----------------------------------------------------------------------------- |
|
// Constructor |
|
//----------------------------------------------------------------------------- |
|
C_BaseHLPlayer::C_BaseHLPlayer() |
|
{ |
|
AddVar( &m_Local.m_vecPunchAngle, &m_Local.m_iv_vecPunchAngle, LATCH_SIMULATION_VAR ); |
|
AddVar( &m_Local.m_vecPunchAngleVel, &m_Local.m_iv_vecPunchAngleVel, LATCH_SIMULATION_VAR ); |
|
|
|
m_flZoomStart = 0.0f; |
|
m_flZoomEnd = 0.0f; |
|
m_flZoomRate = 0.0f; |
|
m_flZoomStartTime = 0.0f; |
|
m_flSpeedMod = cl_forwardspeed.GetFloat(); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : updateType - |
|
//----------------------------------------------------------------------------- |
|
void C_BaseHLPlayer::OnDataChanged( DataUpdateType_t updateType ) |
|
{ |
|
// Make sure we're thinking |
|
if ( updateType == DATA_UPDATE_CREATED ) |
|
{ |
|
SetNextClientThink( CLIENT_THINK_ALWAYS ); |
|
} |
|
|
|
BaseClass::OnDataChanged( updateType ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
void C_BaseHLPlayer::Weapon_DropPrimary( void ) |
|
{ |
|
engine->ServerCmd( "DropPrimary" ); |
|
} |
|
|
|
float C_BaseHLPlayer::GetFOV() |
|
{ |
|
//Find our FOV with offset zoom value |
|
float flFOVOffset = BaseClass::GetFOV() + GetZoom(); |
|
|
|
// Clamp FOV in MP |
|
int min_fov = ( gpGlobals->maxClients == 1 ) ? 5 : default_fov.GetInt(); |
|
|
|
// Don't let it go too low |
|
flFOVOffset = MAX( min_fov, flFOVOffset ); |
|
|
|
return flFOVOffset; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Output : float |
|
//----------------------------------------------------------------------------- |
|
float C_BaseHLPlayer::GetZoom( void ) |
|
{ |
|
float fFOV = m_flZoomEnd; |
|
|
|
//See if we need to lerp the values |
|
if ( ( m_flZoomStart != m_flZoomEnd ) && ( m_flZoomRate > 0.0f ) ) |
|
{ |
|
float deltaTime = (float)( gpGlobals->curtime - m_flZoomStartTime ) / m_flZoomRate; |
|
|
|
if ( deltaTime >= 1.0f ) |
|
{ |
|
//If we're past the zoom time, just take the new value and stop lerping |
|
fFOV = m_flZoomStart = m_flZoomEnd; |
|
} |
|
else |
|
{ |
|
fFOV = SimpleSplineRemapVal( deltaTime, 0.0f, 1.0f, m_flZoomStart, m_flZoomEnd ); |
|
} |
|
} |
|
|
|
return fFOV; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : FOVOffset - |
|
// time - |
|
//----------------------------------------------------------------------------- |
|
void C_BaseHLPlayer::Zoom( float FOVOffset, float time ) |
|
{ |
|
m_flZoomStart = GetZoom(); |
|
m_flZoomEnd = FOVOffset; |
|
m_flZoomRate = time; |
|
m_flZoomStartTime = gpGlobals->curtime; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Hack to zero out player's pitch, use value from poseparameter instead |
|
// Input : flags - |
|
// Output : int |
|
//----------------------------------------------------------------------------- |
|
int C_BaseHLPlayer::DrawModel( int flags ) |
|
{ |
|
// Not pitch for player |
|
QAngle saveAngles = GetLocalAngles(); |
|
|
|
QAngle useAngles = saveAngles; |
|
useAngles[ PITCH ] = 0.0f; |
|
|
|
SetLocalAngles( useAngles ); |
|
|
|
int iret = BaseClass::DrawModel( flags ); |
|
|
|
SetLocalAngles( saveAngles ); |
|
|
|
return iret; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Helper to remove from ladder |
|
//----------------------------------------------------------------------------- |
|
void C_BaseHLPlayer::ExitLadder() |
|
{ |
|
if ( MOVETYPE_LADDER != GetMoveType() ) |
|
return; |
|
|
|
SetMoveType( MOVETYPE_WALK ); |
|
SetMoveCollide( MOVECOLLIDE_DEFAULT ); |
|
// Remove from ladder |
|
m_HL2Local.m_hLadder = NULL; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Determines if a player can be safely moved towards a point |
|
// Input: pos - position to test move to, fVertDist - how far to trace downwards to see if the player would fall, |
|
// radius - how close the player can be to the object, objPos - position of the object to avoid, |
|
// objDir - direction the object is travelling |
|
//----------------------------------------------------------------------------- |
|
bool C_BaseHLPlayer::TestMove( const Vector &pos, float fVertDist, float radius, const Vector &objPos, const Vector &objDir ) |
|
{ |
|
trace_t trUp; |
|
trace_t trOver; |
|
trace_t trDown; |
|
float flHit1, flHit2; |
|
|
|
UTIL_TraceHull( GetAbsOrigin(), pos, GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver ); |
|
if ( trOver.fraction < 1.0f ) |
|
{ |
|
// check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move. |
|
if ( objDir.IsZero() || |
|
( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) && |
|
( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) ) |
|
) |
|
{ |
|
// our first trace failed, so see if we can go farther if we step up. |
|
|
|
// trace up to see if we have enough room. |
|
UTIL_TraceHull( GetAbsOrigin(), GetAbsOrigin() + Vector( 0, 0, m_Local.m_flStepSize ), |
|
GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trUp ); |
|
|
|
// do a trace from the stepped up height |
|
UTIL_TraceHull( trUp.endpos, pos + Vector( 0, 0, trUp.endpos.z - trUp.startpos.z ), |
|
GetPlayerMins(), GetPlayerMaxs(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &trOver ); |
|
|
|
if ( trOver.fraction < 1.0f ) |
|
{ |
|
// check if the endpos intersects with the direction the object is travelling. if it doesn't, this is a good direction to move. |
|
if ( objDir.IsZero() || |
|
( IntersectInfiniteRayWithSphere( objPos, objDir, trOver.endpos, radius, &flHit1, &flHit2 ) && ( ( flHit1 >= 0.0f ) || ( flHit2 >= 0.0f ) ) ) ) |
|
{ |
|
return false; |
|
} |
|
} |
|
} |
|
} |
|
|
|
// trace down to see if this position is on the ground |
|
UTIL_TraceLine( trOver.endpos, trOver.endpos - Vector( 0, 0, fVertDist ), |
|
MASK_SOLID_BRUSHONLY, NULL, COLLISION_GROUP_NONE, &trDown ); |
|
|
|
if ( trDown.fraction == 1.0f ) |
|
return false; |
|
|
|
return true; |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Client-side obstacle avoidance |
|
//----------------------------------------------------------------------------- |
|
void C_BaseHLPlayer::PerformClientSideObstacleAvoidance( float flFrameTime, CUserCmd *pCmd ) |
|
{ |
|
// Don't avoid if noclipping or in movetype none |
|
switch ( GetMoveType() ) |
|
{ |
|
case MOVETYPE_NOCLIP: |
|
case MOVETYPE_NONE: |
|
case MOVETYPE_OBSERVER: |
|
return; |
|
default: |
|
break; |
|
} |
|
|
|
// Try to steer away from any objects/players we might interpenetrate |
|
Vector size = WorldAlignSize(); |
|
|
|
float radius = 0.7f * sqrt( size.x * size.x + size.y * size.y ); |
|
float curspeed = GetLocalVelocity().Length2D(); |
|
|
|
//int slot = 1; |
|
//engine->Con_NPrintf( slot++, "speed %f\n", curspeed ); |
|
//engine->Con_NPrintf( slot++, "radius %f\n", radius ); |
|
|
|
// If running, use a larger radius |
|
float factor = 1.0f; |
|
|
|
if ( curspeed > 150.0f ) |
|
{ |
|
curspeed = MIN( 2048.0f, curspeed ); |
|
factor = ( 1.0f + ( curspeed - 150.0f ) / 150.0f ); |
|
|
|
//engine->Con_NPrintf( slot++, "scaleup (%f) to radius %f\n", factor, radius * factor ); |
|
|
|
radius = radius * factor; |
|
} |
|
|
|
Vector currentdir; |
|
Vector rightdir; |
|
|
|
QAngle vAngles = pCmd->viewangles; |
|
vAngles.x = 0; |
|
|
|
AngleVectors( vAngles, ¤tdir, &rightdir, NULL ); |
|
|
|
bool istryingtomove = false; |
|
bool ismovingforward = false; |
|
if ( fabs( pCmd->forwardmove ) > 0.0f || |
|
fabs( pCmd->sidemove ) > 0.0f ) |
|
{ |
|
istryingtomove = true; |
|
if ( pCmd->forwardmove > 1.0f ) |
|
{ |
|
ismovingforward = true; |
|
} |
|
} |
|
|
|
if ( istryingtomove == true ) |
|
radius *= 1.3f; |
|
|
|
CPlayerAndObjectEnumerator avoid( radius ); |
|
partition->EnumerateElementsInSphere( PARTITION_CLIENT_SOLID_EDICTS, GetAbsOrigin(), radius, false, &avoid ); |
|
|
|
// Okay, decide how to avoid if there's anything close by |
|
int c = avoid.GetObjectCount(); |
|
if ( c <= 0 ) |
|
return; |
|
|
|
//engine->Con_NPrintf( slot++, "moving %s forward %s\n", istryingtomove ? "true" : "false", ismovingforward ? "true" : "false" ); |
|
|
|
float adjustforwardmove = 0.0f; |
|
float adjustsidemove = 0.0f; |
|
|
|
for ( int i = 0; i < c; i++ ) |
|
{ |
|
C_AI_BaseNPC *obj = dynamic_cast< C_AI_BaseNPC *>(avoid.GetObject( i )); |
|
|
|
if( !obj ) |
|
continue; |
|
|
|
Vector vecToObject = obj->GetAbsOrigin() - GetAbsOrigin(); |
|
|
|
float flDist = vecToObject.Length2D(); |
|
|
|
// Figure out a 2D radius for the object |
|
Vector vecWorldMins, vecWorldMaxs; |
|
obj->CollisionProp()->WorldSpaceAABB( &vecWorldMins, &vecWorldMaxs ); |
|
Vector objSize = vecWorldMaxs - vecWorldMins; |
|
|
|
float objectradius = 0.5f * sqrt( objSize.x * objSize.x + objSize.y * objSize.y ); |
|
|
|
//Don't run this code if the NPC is not moving UNLESS we are in stuck inside of them. |
|
if ( !obj->IsMoving() && flDist > objectradius ) |
|
continue; |
|
|
|
if ( flDist > objectradius && obj->IsEffectActive( EF_NODRAW ) ) |
|
{ |
|
obj->RemoveEffects( EF_NODRAW ); |
|
} |
|
|
|
Vector vecNPCVelocity; |
|
obj->EstimateAbsVelocity( vecNPCVelocity ); |
|
float flNPCSpeed = VectorNormalize( vecNPCVelocity ); |
|
|
|
Vector vPlayerVel = GetAbsVelocity(); |
|
VectorNormalize( vPlayerVel ); |
|
|
|
float flHit1, flHit2; |
|
Vector vRayDir = vecToObject; |
|
VectorNormalize( vRayDir ); |
|
|
|
float flVelProduct = DotProduct( vecNPCVelocity, vPlayerVel ); |
|
float flDirProduct = DotProduct( vRayDir, vPlayerVel ); |
|
|
|
if ( !IntersectInfiniteRayWithSphere( |
|
GetAbsOrigin(), |
|
vRayDir, |
|
obj->GetAbsOrigin(), |
|
radius, |
|
&flHit1, |
|
&flHit2 ) ) |
|
continue; |
|
|
|
Vector dirToObject = -vecToObject; |
|
VectorNormalize( dirToObject ); |
|
|
|
float fwd = 0; |
|
float rt = 0; |
|
|
|
float sidescale = 2.0f; |
|
float forwardscale = 1.0f; |
|
bool foundResult = false; |
|
|
|
Vector vMoveDir = vecNPCVelocity; |
|
if ( flNPCSpeed > 0.001f ) |
|
{ |
|
// This NPC is moving. First try deflecting the player left or right relative to the NPC's velocity. |
|
// Start with whatever side they're on relative to the NPC's velocity. |
|
Vector vecNPCTrajectoryRight = CrossProduct( vecNPCVelocity, Vector( 0, 0, 1) ); |
|
int iDirection = ( vecNPCTrajectoryRight.Dot( dirToObject ) > 0 ) ? 1 : -1; |
|
for ( int nTries = 0; nTries < 2; nTries++ ) |
|
{ |
|
Vector vecTryMove = vecNPCTrajectoryRight * iDirection; |
|
VectorNormalize( vecTryMove ); |
|
|
|
Vector vTestPosition = GetAbsOrigin() + vecTryMove * radius * 2; |
|
|
|
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) |
|
{ |
|
fwd = currentdir.Dot( vecTryMove ); |
|
rt = rightdir.Dot( vecTryMove ); |
|
|
|
//Msg( "PUSH DEFLECT fwd=%f, rt=%f\n", fwd, rt ); |
|
|
|
foundResult = true; |
|
break; |
|
} |
|
else |
|
{ |
|
// Try the other direction. |
|
iDirection *= -1; |
|
} |
|
} |
|
} |
|
else |
|
{ |
|
// the object isn't moving, so try moving opposite the way it's facing |
|
Vector vecNPCForward; |
|
obj->GetVectors( &vecNPCForward, NULL, NULL ); |
|
|
|
Vector vTestPosition = GetAbsOrigin() - vecNPCForward * radius * 2; |
|
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) |
|
{ |
|
fwd = currentdir.Dot( -vecNPCForward ); |
|
rt = rightdir.Dot( -vecNPCForward ); |
|
|
|
if ( flDist < objectradius ) |
|
{ |
|
obj->AddEffects( EF_NODRAW ); |
|
} |
|
|
|
//Msg( "PUSH AWAY FACE fwd=%f, rt=%f\n", fwd, rt ); |
|
|
|
foundResult = true; |
|
} |
|
} |
|
|
|
if ( !foundResult ) |
|
{ |
|
// test if we can move in the direction the object is moving |
|
Vector vTestPosition = GetAbsOrigin() + vMoveDir * radius * 2; |
|
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) |
|
{ |
|
fwd = currentdir.Dot( vMoveDir ); |
|
rt = rightdir.Dot( vMoveDir ); |
|
|
|
if ( flDist < objectradius ) |
|
{ |
|
obj->AddEffects( EF_NODRAW ); |
|
} |
|
|
|
//Msg( "PUSH ALONG fwd=%f, rt=%f\n", fwd, rt ); |
|
|
|
foundResult = true; |
|
} |
|
else |
|
{ |
|
// try moving directly away from the object |
|
Vector vTestPosition = GetAbsOrigin() - dirToObject * radius * 2; |
|
if ( TestMove( vTestPosition, size.z * 2, radius * 2, obj->GetAbsOrigin(), vMoveDir ) ) |
|
{ |
|
fwd = currentdir.Dot( -dirToObject ); |
|
rt = rightdir.Dot( -dirToObject ); |
|
foundResult = true; |
|
|
|
//Msg( "PUSH AWAY fwd=%f, rt=%f\n", fwd, rt ); |
|
} |
|
} |
|
} |
|
|
|
if ( !foundResult ) |
|
{ |
|
// test if we can move through the object |
|
Vector vTestPosition = GetAbsOrigin() - vMoveDir * radius * 2; |
|
fwd = currentdir.Dot( -vMoveDir ); |
|
rt = rightdir.Dot( -vMoveDir ); |
|
|
|
if ( flDist < objectradius ) |
|
{ |
|
obj->AddEffects( EF_NODRAW ); |
|
} |
|
|
|
//Msg( "PUSH THROUGH fwd=%f, rt=%f\n", fwd, rt ); |
|
|
|
foundResult = true; |
|
} |
|
|
|
// If running, then do a lot more sideways veer since we're not going to do anything to |
|
// forward velocity |
|
if ( istryingtomove ) |
|
{ |
|
sidescale = 6.0f; |
|
} |
|
|
|
if ( flVelProduct > 0.0f && flDirProduct > 0.0f ) |
|
{ |
|
sidescale = 0.1f; |
|
} |
|
|
|
float force = 1.0f; |
|
float forward = forwardscale * fwd * force * AVOID_SPEED; |
|
float side = sidescale * rt * force * AVOID_SPEED; |
|
|
|
adjustforwardmove += forward; |
|
adjustsidemove += side; |
|
} |
|
|
|
pCmd->forwardmove += adjustforwardmove; |
|
pCmd->sidemove += adjustsidemove; |
|
|
|
// Clamp the move to within legal limits, preserving direction. This is a little |
|
// complicated because we have different limits for forward, back, and side |
|
|
|
//Msg( "PRECLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); |
|
|
|
float flForwardScale = 1.0f; |
|
if ( pCmd->forwardmove > fabs( cl_forwardspeed.GetFloat() ) ) |
|
{ |
|
flForwardScale = fabs( cl_forwardspeed.GetFloat() ) / pCmd->forwardmove; |
|
} |
|
else if ( pCmd->forwardmove < -fabs( cl_backspeed.GetFloat() ) ) |
|
{ |
|
flForwardScale = fabs( cl_backspeed.GetFloat() ) / fabs( pCmd->forwardmove ); |
|
} |
|
|
|
float flSideScale = 1.0f; |
|
if ( fabs( pCmd->sidemove ) > fabs( cl_sidespeed.GetFloat() ) ) |
|
{ |
|
flSideScale = fabs( cl_sidespeed.GetFloat() ) / fabs( pCmd->sidemove ); |
|
} |
|
|
|
float flScale = MIN( flForwardScale, flSideScale ); |
|
pCmd->forwardmove *= flScale; |
|
pCmd->sidemove *= flScale; |
|
|
|
//Msg( "POSTCLAMP: forwardmove=%f, sidemove=%f\n", pCmd->forwardmove, pCmd->sidemove ); |
|
} |
|
|
|
|
|
void C_BaseHLPlayer::PerformClientSideNPCSpeedModifiers( float flFrameTime, CUserCmd *pCmd ) |
|
{ |
|
if ( m_hClosestNPC == NULL ) |
|
{ |
|
if ( m_flSpeedMod != cl_forwardspeed.GetFloat() ) |
|
{ |
|
float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime); |
|
m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_outtime.GetFloat(), 0, m_flExitSpeedMod, cl_forwardspeed.GetFloat() ); |
|
} |
|
} |
|
else |
|
{ |
|
C_AI_BaseNPC *pNPC = dynamic_cast< C_AI_BaseNPC *>( m_hClosestNPC.Get() ); |
|
|
|
if ( pNPC ) |
|
{ |
|
float flDist = (GetAbsOrigin() - pNPC->GetAbsOrigin()).LengthSqr(); |
|
bool bShouldModSpeed = false; |
|
|
|
// Within range? |
|
if ( flDist < pNPC->GetSpeedModifyRadius() ) |
|
{ |
|
// Now, only slowdown if we're facing & running parallel to the target's movement |
|
// Facing check first (in 2D) |
|
Vector vecTargetOrigin = pNPC->GetAbsOrigin(); |
|
Vector los = ( vecTargetOrigin - EyePosition() ); |
|
los.z = 0; |
|
VectorNormalize( los ); |
|
Vector facingDir; |
|
AngleVectors( GetAbsAngles(), &facingDir ); |
|
float flDot = DotProduct( los, facingDir ); |
|
if ( flDot > 0.8 ) |
|
{ |
|
/* |
|
// Velocity check (abort if the target isn't moving) |
|
Vector vecTargetVelocity; |
|
pNPC->EstimateAbsVelocity( vecTargetVelocity ); |
|
float flSpeed = VectorNormalize(vecTargetVelocity); |
|
Vector vecMyVelocity = GetAbsVelocity(); |
|
VectorNormalize(vecMyVelocity); |
|
if ( flSpeed > 1.0 ) |
|
{ |
|
// Velocity roughly parallel? |
|
if ( DotProduct(vecTargetVelocity,vecMyVelocity) > 0.4 ) |
|
{ |
|
bShouldModSpeed = true; |
|
} |
|
} |
|
else |
|
{ |
|
// NPC's not moving, slow down if we're moving at him |
|
//Msg("Dot: %.2f\n", DotProduct( los, vecMyVelocity ) ); |
|
if ( DotProduct( los, vecMyVelocity ) > 0.8 ) |
|
{ |
|
bShouldModSpeed = true; |
|
} |
|
} |
|
*/ |
|
|
|
bShouldModSpeed = true; |
|
} |
|
} |
|
|
|
if ( !bShouldModSpeed ) |
|
{ |
|
m_hClosestNPC = NULL; |
|
m_flSpeedModTime = gpGlobals->curtime + cl_npc_speedmod_outtime.GetFloat(); |
|
m_flExitSpeedMod = m_flSpeedMod; |
|
return; |
|
} |
|
else |
|
{ |
|
if ( m_flSpeedMod != pNPC->GetSpeedModifySpeed() ) |
|
{ |
|
float flDeltaTime = (m_flSpeedModTime - gpGlobals->curtime); |
|
m_flSpeedMod = RemapValClamped( flDeltaTime, cl_npc_speedmod_intime.GetFloat(), 0, cl_forwardspeed.GetFloat(), pNPC->GetSpeedModifySpeed() ); |
|
} |
|
} |
|
} |
|
} |
|
|
|
if ( pCmd->forwardmove > 0.0f ) |
|
{ |
|
pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod ); |
|
} |
|
else |
|
{ |
|
pCmd->forwardmove = clamp( pCmd->forwardmove, -m_flSpeedMod, m_flSpeedMod ); |
|
} |
|
pCmd->sidemove = clamp( pCmd->sidemove, -m_flSpeedMod, m_flSpeedMod ); |
|
|
|
//Msg( "fwd %f right %f\n", pCmd->forwardmove, pCmd->sidemove ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handling |
|
//----------------------------------------------------------------------------- |
|
bool C_BaseHLPlayer::CreateMove( float flInputSampleTime, CUserCmd *pCmd ) |
|
{ |
|
bool bResult = BaseClass::CreateMove( flInputSampleTime, pCmd ); |
|
|
|
if ( !IsInAVehicle() ) |
|
{ |
|
PerformClientSideObstacleAvoidance( TICK_INTERVAL, pCmd ); |
|
PerformClientSideNPCSpeedModifiers( TICK_INTERVAL, pCmd ); |
|
} |
|
|
|
return bResult; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Input handling |
|
//----------------------------------------------------------------------------- |
|
void C_BaseHLPlayer::BuildTransformations( CStudioHdr *hdr, Vector *pos, Quaternion q[], const matrix3x4_t& cameraTransform, int boneMask, CBoneBitList &boneComputed ) |
|
{ |
|
BaseClass::BuildTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed ); |
|
BuildFirstPersonMeathookTransformations( hdr, pos, q, cameraTransform, boneMask, boneComputed, "ValveBiped.Bip01_Head1" ); |
|
} |
|
|
|
|