diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/shared/hl2/hl_gamemovement.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/shared/hl2/hl_gamemovement.cpp')
| -rw-r--r-- | mp/src/game/shared/hl2/hl_gamemovement.cpp | 2302 |
1 files changed, 1151 insertions, 1151 deletions
diff --git a/mp/src/game/shared/hl2/hl_gamemovement.cpp b/mp/src/game/shared/hl2/hl_gamemovement.cpp index 3218c991..e7e573ec 100644 --- a/mp/src/game/shared/hl2/hl_gamemovement.cpp +++ b/mp/src/game/shared/hl2/hl_gamemovement.cpp @@ -1,1152 +1,1152 @@ -//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose: Special handling for hl2 usable ladders
-//
-//=============================================================================//
-#include "cbase.h"
-#include "hl_gamemovement.h"
-#include "in_buttons.h"
-#include "utlrbtree.h"
-#include "hl2_shareddefs.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-static ConVar sv_autoladderdismount( "sv_autoladderdismount", "1", FCVAR_REPLICATED, "Automatically dismount from ladders when you reach the end (don't have to +USE)." );
-static ConVar sv_ladderautomountdot( "sv_ladderautomountdot", "0.4", FCVAR_REPLICATED, "When auto-mounting a ladder by looking up its axis, this is the tolerance for looking now directly along the ladder axis." );
-
-static ConVar sv_ladder_useonly( "sv_ladder_useonly", "0", FCVAR_REPLICATED, "If set, ladders can only be mounted by pressing +USE" );
-
-#define USE_DISMOUNT_SPEED 100
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-CHL2GameMovement::CHL2GameMovement()
-{
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : type -
-// Output : int
-//-----------------------------------------------------------------------------
-int CHL2GameMovement::GetCheckInterval( IntervalType_t type )
-{
- // HL2 ladders need to check every frame!!!
- if ( type == LADDER )
- return 1;
-
- return BaseClass::GetCheckInterval( type );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CHL2GameMovement::IsForceMoveActive()
-{
- LadderMove_t *lm = GetLadderMove();
- return lm->m_bForceLadderMove;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Debounce the USE button
-//-----------------------------------------------------------------------------
-void CHL2GameMovement::SwallowUseKey()
-{
- mv->m_nOldButtons |= IN_USE;
- player->m_afButtonPressed &= ~IN_USE;
-
- GetHL2Player()->m_bPlayUseDenySound = false;
-}
-
-#if !defined( CLIENT_DLL )
-// This is a simple helper class to reserver a player sized hull at a spot, owned by the current player so that nothing
-// can move into this spot and cause us to get stuck when we get there
-class CReservePlayerSpot : public CBaseEntity
-{
- DECLARE_CLASS( CReservePlayerSpot, CBaseEntity )
-public:
- static CReservePlayerSpot *ReserveSpot( CBasePlayer *owner, const Vector& org, const Vector& mins, const Vector& maxs, bool& validspot );
-
- virtual void Spawn();
-};
-
-CReservePlayerSpot *CReservePlayerSpot::ReserveSpot(
- CBasePlayer *owner, const Vector& org, const Vector& mins, const Vector& maxs, bool& validspot )
-{
- CReservePlayerSpot *spot = ( CReservePlayerSpot * )CreateEntityByName( "reserved_spot" );
- Assert( spot );
-
- spot->SetAbsOrigin( org );
- UTIL_SetSize( spot, mins, maxs );
- spot->SetOwnerEntity( owner );
- spot->Spawn();
-
- // See if spot is valid
- trace_t tr;
- UTIL_TraceHull(
- org,
- org,
- mins,
- maxs,
- MASK_PLAYERSOLID,
- owner,
- COLLISION_GROUP_PLAYER_MOVEMENT,
- &tr );
-
- validspot = !tr.startsolid;
-
- if ( !validspot )
- {
- Vector org2 = org + Vector( 0, 0, 1 );
-
- // See if spot is valid
- trace_t tr;
- UTIL_TraceHull(
- org2,
- org2,
- mins,
- maxs,
- MASK_PLAYERSOLID,
- owner,
- COLLISION_GROUP_PLAYER_MOVEMENT,
- &tr );
- validspot = !tr.startsolid;
- }
-
- return spot;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void CReservePlayerSpot::Spawn()
-{
- BaseClass::Spawn();
-
- SetSolid( SOLID_BBOX );
- SetMoveType( MOVETYPE_NONE );
- // Make entity invisible
- AddEffects( EF_NODRAW );
-}
-
-LINK_ENTITY_TO_CLASS( reserved_spot, CReservePlayerSpot );
-
-#endif
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : mounting -
-// transit_speed -
-// goalpos -
-// *ladder -
-//-----------------------------------------------------------------------------
-void CHL2GameMovement::StartForcedMove( bool mounting, float transit_speed, const Vector& goalpos, CFuncLadder *ladder )
-{
- LadderMove_t* lm = GetLadderMove();
- Assert( lm );
- // Already active, just ignore
- if ( lm->m_bForceLadderMove )
- {
- return;
- }
-
-#if !defined( CLIENT_DLL )
- if ( ladder )
- {
- ladder->PlayerGotOn( GetHL2Player() );
-
- // If the Ladder only wants to be there for automount checking, abort now
- if ( ladder->DontGetOnLadder() )
- return;
- }
-
- // Reserve goal slot here
- bool valid = false;
- lm->m_hReservedSpot = CReservePlayerSpot::ReserveSpot(
- player,
- goalpos,
- GetPlayerMins( ( player->GetFlags() & FL_DUCKING ) ? true : false ),
- GetPlayerMaxs( ( player->GetFlags() & FL_DUCKING ) ? true : false ),
- valid );
- if ( !valid )
- {
- // FIXME: Play a deny sound?
- if ( lm->m_hReservedSpot )
- {
- UTIL_Remove( lm->m_hReservedSpot );
- lm->m_hReservedSpot = NULL;
- }
- return;
- }
-#endif
-
- // Use current player origin as start and new origin as dest
- lm->m_vecGoalPosition = goalpos;
- lm->m_vecStartPosition = mv->GetAbsOrigin();
-
- // Figure out how long it will take to make the gap based on transit_speed
- Vector delta = lm->m_vecGoalPosition - lm->m_vecStartPosition;
-
- float distance = delta.Length();
-
- Assert( transit_speed > 0.001f );
-
- // Compute time required to move that distance
- float transit_time = distance / transit_speed;
- if ( transit_time < 0.001f )
- {
- transit_time = 0.001f;
- }
-
- lm->m_bForceLadderMove = true;
- lm->m_bForceMount = mounting;
-
- lm->m_flStartTime = gpGlobals->curtime;
- lm->m_flArrivalTime = lm->m_flStartTime + transit_time;
-
- lm->m_hForceLadder = ladder;
-
- // Don't get stuck during this traversal since we'll just be slamming the player origin
- player->SetMoveType( MOVETYPE_NONE );
- player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
- player->SetSolid( SOLID_NONE );
- SetLadder( ladder );
-
- // Debounce the use key
- SwallowUseKey();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Returns false when finished
-//-----------------------------------------------------------------------------
-bool CHL2GameMovement::ContinueForcedMove()
-{
- LadderMove_t* lm = GetLadderMove();
- Assert( lm );
- Assert( lm->m_bForceLadderMove );
-
- // Suppress regular motion
- mv->m_flForwardMove = 0.0f;
- mv->m_flSideMove = 0.0f;
- mv->m_flUpMove = 0.0f;
-
- // How far along are we
- float frac = ( gpGlobals->curtime - lm->m_flStartTime ) / ( lm->m_flArrivalTime - lm->m_flStartTime );
- if ( frac > 1.0f )
- {
- lm->m_bForceLadderMove = false;
-#if !defined( CLIENT_DLL )
- // Remove "reservation entity"
- if ( lm->m_hReservedSpot )
- {
- UTIL_Remove( lm->m_hReservedSpot );
- lm->m_hReservedSpot = NULL;
- }
-#endif
- }
-
- frac = clamp( frac, 0.0f, 1.0f );
-
- // Move origin part of the way
- Vector delta = lm->m_vecGoalPosition - lm->m_vecStartPosition;
-
- // Compute interpolated position
- Vector org;
- VectorMA( lm->m_vecStartPosition, frac, delta, org );
- mv->SetAbsOrigin( org );
-
- // If finished moving, reset player to correct movetype (or put them on the ladder)
- if ( !lm->m_bForceLadderMove )
- {
- player->SetSolid( SOLID_BBOX );
- player->SetMoveType( MOVETYPE_WALK );
-
- if ( lm->m_bForceMount && lm->m_hForceLadder != NULL )
- {
- player->SetMoveType( MOVETYPE_LADDER );
- SetLadder( lm->m_hForceLadder );
- }
-
- // Zero out any velocity
- mv->m_vecVelocity.Init();
- }
-
- // Stil active
- return lm->m_bForceLadderMove;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Returns true if the player is on a ladder
-// Input : &trace - ignored
-//-----------------------------------------------------------------------------
-bool CHL2GameMovement::OnLadder( trace_t &trace )
-{
- return ( GetLadder() != NULL ) ? true : false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : ladders -
-// maxdist -
-// **ppLadder -
-// ladderOrigin -
-//-----------------------------------------------------------------------------
-void CHL2GameMovement::Findladder( float maxdist, CFuncLadder **ppLadder, Vector& ladderOrigin, const CFuncLadder *skipLadder )
-{
- CFuncLadder *bestLadder = NULL;
- float bestDist = MAX_COORD_INTEGER;
- Vector bestOrigin;
-
- bestOrigin.Init();
-
- float maxdistSqr = maxdist * maxdist;
-
-
- int c = CFuncLadder::GetLadderCount();
- for ( int i = 0 ; i < c; i++ )
- {
- CFuncLadder *ladder = CFuncLadder::GetLadder( i );
-
- if ( !ladder->IsEnabled() )
- continue;
-
- if ( skipLadder && ladder == skipLadder )
- continue;
-
- Vector topPosition;
- Vector bottomPosition;
-
- ladder->GetTopPosition( topPosition );
- ladder->GetBottomPosition( bottomPosition );
-
- Vector closest;
- CalcClosestPointOnLineSegment( mv->GetAbsOrigin(), bottomPosition, topPosition, closest, NULL );
-
- float distSqr = ( closest - mv->GetAbsOrigin() ).LengthSqr();
-
- // Too far away
- if ( distSqr > maxdistSqr )
- {
- continue;
- }
-
- // Need to trace to see if it's clear
- trace_t tr;
-
- UTIL_TraceLine( mv->GetAbsOrigin(), closest,
- MASK_PLAYERSOLID,
- player,
- COLLISION_GROUP_NONE,
- &tr );
-
- if ( tr.fraction != 1.0f &&
- tr.m_pEnt &&
- tr.m_pEnt != ladder )
- {
- // Try a trace stepped up from the ground a bit, in case there's something at ground level blocking us.
- float sizez = GetPlayerMaxs().z - GetPlayerMins().z;
-
- UTIL_TraceLine( mv->GetAbsOrigin() + Vector( 0, 0, sizez * 0.5f ), closest,
- MASK_PLAYERSOLID,
- player,
- COLLISION_GROUP_NONE,
- &tr );
-
- if ( tr.fraction != 1.0f &&
- tr.m_pEnt &&
- tr.m_pEnt != ladder &&
- !tr.m_pEnt->IsSolidFlagSet( FSOLID_TRIGGER ) )
- {
- continue;
- }
- }
-
- // See if this is the best one so far
- if ( distSqr < bestDist )
- {
- bestDist = distSqr;
- bestLadder = ladder;
- bestOrigin = closest;
- }
- }
-
- // Return best ladder spot
- *ppLadder = bestLadder;
- ladderOrigin = bestOrigin;
-
-}
-
-static bool NearbyDismountLessFunc( const NearbyDismount_t& lhs, const NearbyDismount_t& rhs )
-{
- return lhs.distSqr < rhs.distSqr;
-}
-
-void CHL2GameMovement::GetSortedDismountNodeList( const Vector &org, float radius, CFuncLadder *ladder, CUtlRBTree< NearbyDismount_t, int >& list )
-{
- float radiusSqr = radius * radius;
-
- int i;
- int c = ladder->GetDismountCount();
- for ( i = 0; i < c; i++ )
- {
- CInfoLadderDismount *spot = ladder->GetDismount( i );
- if ( !spot )
- continue;
-
- float distSqr = ( spot->GetAbsOrigin() - org ).LengthSqr();
- if ( distSqr > radiusSqr )
- continue;
-
- NearbyDismount_t nd;
- nd.dismount = spot;
- nd.distSqr = distSqr;
-
- list.Insert( nd );
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// *ladder -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CHL2GameMovement::ExitLadderViaDismountNode( CFuncLadder *ladder, bool strict, bool useAlternate )
-{
- // Find the best ladder exit node
- float bestDot = -99999.0f;
- float bestDistance = 99999.0f;
- Vector bestDest;
- bool found = false;
-
- // For 'alternate' dismount
- bool foundAlternate = false;
- Vector alternateDest;
- float alternateDist = 99999.0f;
-
- CUtlRBTree< NearbyDismount_t, int > nearbyDismounts( 0, 0, NearbyDismountLessFunc );
-
- GetSortedDismountNodeList( mv->GetAbsOrigin(), 100.0f, ladder, nearbyDismounts );
-
- int i;
-
- for ( i = nearbyDismounts.FirstInorder(); i != nearbyDismounts.InvalidIndex() ; i = nearbyDismounts.NextInorder( i ) )
- {
- CInfoLadderDismount *spot = nearbyDismounts[ i ].dismount;
- if ( !spot )
- {
- Assert( !"What happened to the spot!!!" );
- continue;
- }
-
- // See if it's valid to put the player there...
- Vector org = spot->GetAbsOrigin() + Vector( 0, 0, 1 );
-
- trace_t tr;
- UTIL_TraceHull(
- org,
- org,
- GetPlayerMins( ( player->GetFlags() & FL_DUCKING ) ? true : false ),
- GetPlayerMaxs( ( player->GetFlags() & FL_DUCKING ) ? true : false ),
- MASK_PLAYERSOLID,
- player,
- COLLISION_GROUP_PLAYER_MOVEMENT,
- &tr );
-
- // Nope...
- if ( tr.startsolid )
- {
- continue;
- }
-
- // Find the best dot product
- Vector vecToSpot = org - ( mv->GetAbsOrigin() + player->GetViewOffset() );
- vecToSpot.z = 0.0f;
- float d = VectorNormalize( vecToSpot );
-
- float dot = vecToSpot.Dot( m_vecForward );
-
- // We're not facing at it...ignore
- if ( dot < 0.5f )
- {
- if( useAlternate && d < alternateDist )
- {
- alternateDest = org;
- alternateDist = d;
- foundAlternate = true;
- }
-
- continue;
- }
-
- if ( dot > bestDot )
- {
- bestDest = org;
- bestDistance = d;
- bestDot = dot;
- found = true;
- }
- }
-
- if ( found )
- {
- // Require a more specific
- if ( strict &&
- ( ( bestDot < 0.7f ) || ( bestDistance > 40.0f ) ) )
- {
- return false;
- }
-
- StartForcedMove( false, player->MaxSpeed(), bestDest, NULL );
- return true;
- }
-
- if( useAlternate )
- {
- // Desperate. Don't refuse to let a person off of a ladder if it can be helped. Use the
- // alternate dismount if there is one.
- if( foundAlternate && alternateDist <= 60.0f )
- {
- StartForcedMove( false, player->MaxSpeed(), alternateDest, NULL );
- return true;
- }
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : bOnLadder -
-//-----------------------------------------------------------------------------
-void CHL2GameMovement::FullLadderMove()
-{
-#if !defined( CLIENT_DLL )
- CFuncLadder *ladder = GetLadder();
- Assert( ladder );
- if ( !ladder )
- {
- return;
- }
-
- CheckWater();
-
- // Was jump button pressed? If so, don't do anything here
- if ( mv->m_nButtons & IN_JUMP )
- {
- CheckJumpButton();
- return;
- }
- else
- {
- mv->m_nOldButtons &= ~IN_JUMP;
- }
-
- player->SetGroundEntity( NULL );
-
- // Remember old positions in case we cancel this movement
- Vector oldVelocity = mv->m_vecVelocity;
- Vector oldOrigin = mv->GetAbsOrigin();
-
- Vector topPosition;
- Vector bottomPosition;
-
- ladder->GetTopPosition( topPosition );
- ladder->GetBottomPosition( bottomPosition );
-
- // Compute parametric distance along ladder vector...
- float oldt;
- CalcDistanceSqrToLine( mv->GetAbsOrigin(), topPosition, bottomPosition, &oldt );
-
- // Perform the move accounting for any base velocity.
- VectorAdd (mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity);
- TryPlayerMove();
- VectorSubtract (mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity);
-
- // Pressed buttons are "changed(xor)" and'ed with the mask of currently held buttons
- int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame
- int buttonsPressed = buttonsChanged & mv->m_nButtons;
- bool pressed_use = ( buttonsPressed & IN_USE ) ? true : false;
- bool pressing_forward_or_side = mv->m_flForwardMove != 0.0f || mv->m_flSideMove != 0.0f;
-
- Vector ladderVec = topPosition - bottomPosition;
- float LadderLength = VectorNormalize( ladderVec );
- // This test is not perfect by any means, but should help a bit
- bool moving_along_ladder = false;
- if ( pressing_forward_or_side )
- {
- float fwdDot = m_vecForward.Dot( ladderVec );
- if ( fabs( fwdDot ) > 0.9f )
- {
- moving_along_ladder = true;
- }
- }
-
- // Compute parametric distance along ladder vector...
- float newt;
- CalcDistanceSqrToLine( mv->GetAbsOrigin(), topPosition, bottomPosition, &newt );
-
- // Fudge of 2 units
- float tolerance = 1.0f / LadderLength;
-
- bool wouldleaveladder = false;
- // Moving pPast top or bottom?
- if ( newt < -tolerance )
- {
- wouldleaveladder = newt < oldt;
- }
- else if ( newt > ( 1.0f + tolerance ) )
- {
- wouldleaveladder = newt > oldt;
- }
-
- // See if we are near the top or bottom but not moving
- float dist1sqr, dist2sqr;
-
- dist1sqr = ( topPosition - mv->GetAbsOrigin() ).LengthSqr();
- dist2sqr = ( bottomPosition - mv->GetAbsOrigin() ).LengthSqr();
-
- float dist = MIN( dist1sqr, dist2sqr );
- bool neardismountnode = ( dist < 16.0f * 16.0f ) ? true : false;
- float ladderUnitsPerTick = ( MAX_CLIMB_SPEED * gpGlobals->interval_per_tick );
- bool neardismountnode2 = ( dist < ladderUnitsPerTick * ladderUnitsPerTick ) ? true : false;
-
- // Really close to node, cvar is set, and pressing a key, then simulate a +USE
- bool auto_dismount_use = ( neardismountnode2 &&
- sv_autoladderdismount.GetBool() &&
- pressing_forward_or_side &&
- !moving_along_ladder );
-
- bool fully_underwater = ( player->GetWaterLevel() == WL_Eyes ) ? true : false;
-
- // If the user manually pressed use or we're simulating it, then use_dismount will occur
- bool use_dismount = pressed_use || auto_dismount_use;
-
- if ( fully_underwater && !use_dismount )
- {
- // If fully underwater, we require looking directly at a dismount node
- /// to "float off" a ladder mid way...
- if ( ExitLadderViaDismountNode( ladder, true ) )
- {
- // See if they +used a dismount point mid-span..
- return;
- }
- }
-
- // If the movement would leave the ladder and they're not automated or pressing use, disallow the movement
- if ( !use_dismount )
- {
- if ( wouldleaveladder )
- {
- // Don't let them leave the ladder if they were on it
- mv->m_vecVelocity = oldVelocity;
- mv->SetAbsOrigin( oldOrigin );
- }
- return;
- }
-
- // If the move would not leave the ladder and we're near close to the end, then just accept the move
- if ( !wouldleaveladder && !neardismountnode )
- {
- // Otherwise, if the move would leave the ladder, disallow it.
- if ( pressed_use )
- {
- if ( ExitLadderViaDismountNode( ladder, false, IsX360() ) )
- {
- // See if they +used a dismount point mid-span..
- return;
- }
-
- player->SetMoveType( MOVETYPE_WALK );
- player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
- SetLadder( NULL );
- GetHL2Player()->m_bPlayUseDenySound = false;
-
- // Dismount with a bit of velocity in facing direction
- VectorScale( m_vecForward, USE_DISMOUNT_SPEED, mv->m_vecVelocity );
- mv->m_vecVelocity.z = 50;
- }
- return;
- }
-
- // Debounce the use key
- if ( pressed_use )
- {
- SwallowUseKey();
- }
-
- // Try auto exit, if possible
- if ( ExitLadderViaDismountNode( ladder, false, pressed_use ) )
- {
- return;
- }
-
- if ( wouldleaveladder )
- {
- // Otherwise, if the move would leave the ladder, disallow it.
- if ( pressed_use )
- {
- player->SetMoveType( MOVETYPE_WALK );
- player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
- SetLadder( NULL );
-
- // Dismount with a bit of velocity in facing direction
- VectorScale( m_vecForward, USE_DISMOUNT_SPEED, mv->m_vecVelocity );
- mv->m_vecVelocity.z = 50;
- }
- else
- {
- mv->m_vecVelocity = oldVelocity;
- mv->SetAbsOrigin( oldOrigin );
- }
- }
-#endif
-}
-
-bool CHL2GameMovement::CheckLadderAutoMountEndPoint( CFuncLadder *ladder, const Vector& bestOrigin )
-{
- // See if we're really near an endpoint
- if ( !ladder )
- return false;
-
- Vector top, bottom;
- ladder->GetTopPosition( top );
- ladder->GetBottomPosition( bottom );
-
- float d1, d2;
-
- d1 = ( top - mv->GetAbsOrigin() ).LengthSqr();
- d2 = ( bottom - mv->GetAbsOrigin() ).LengthSqr();
-
- if ( d1 > 16 * 16 && d2 > 16 * 16 )
- return false;
-
- Vector ladderAxis;
-
- if ( d1 < 16 * 16 )
- {
- // Close to top
- ladderAxis = bottom - top;
- }
- else
- {
- ladderAxis = top - bottom;
- }
-
- VectorNormalize( ladderAxis );
-
- if ( ladderAxis.Dot( m_vecForward ) > sv_ladderautomountdot.GetFloat() )
- {
- StartForcedMove( true, player->MaxSpeed(), bestOrigin, ladder );
- return true;
- }
-
- return false;
-}
-
-bool CHL2GameMovement::CheckLadderAutoMountCone( CFuncLadder *ladder, const Vector& bestOrigin, float maxAngleDelta, float maxDistToLadder )
-{
- // Never 'back' onto ladders or stafe onto ladders
- if ( ladder != NULL &&
- ( mv->m_flForwardMove > 0.0f ) )
- {
- Vector top, bottom;
- ladder->GetTopPosition( top );
- ladder->GetBottomPosition( bottom );
-
- Vector ladderAxis = top - bottom;
- VectorNormalize( ladderAxis );
-
- Vector probe = mv->GetAbsOrigin();
-
- Vector closest;
- CalcClosestPointOnLineSegment( probe, bottom, top, closest, NULL );
-
- Vector vecToLadder = closest - probe;
-
- float dist = VectorNormalize( vecToLadder );
-
- Vector flatLadder = vecToLadder;
- flatLadder.z = 0.0f;
- Vector flatForward = m_vecForward;
- flatForward.z = 0.0f;
-
- VectorNormalize( flatLadder );
- VectorNormalize( flatForward );
-
- float facingDot = flatForward.Dot( flatLadder );
- float angle = acos( facingDot ) * 180 / M_PI;
-
- bool closetoladder = ( dist != 0.0f && dist < maxDistToLadder ) ? true : false;
- bool reallyclosetoladder = ( dist != 0.0f && dist < 4.0f ) ? true : false;
-
- bool facingladderaxis = ( angle < maxAngleDelta ) ? true : false;
- bool facingalongaxis = ( (float)fabs( ladderAxis.Dot( m_vecForward ) ) > sv_ladderautomountdot.GetFloat() ) ? true : false;
-#if 0
- Msg( "close %i length %.3f maxdist %.3f facing %.3f dot %.3f ang %.3f\n",
- closetoladder ? 1 : 0,
- dist,
- maxDistToLadder,
- (float)fabs( ladderAxis.Dot( m_vecForward ) ),
- facingDot,
- angle);
-#endif
-
- // Tracker 21776: Don't mount ladders this way if strafing
- bool strafing = ( fabs( mv->m_flSideMove ) < 1.0f ) ? false : true;
-
- if ( ( ( facingDot > 0.0f && !strafing ) || facingalongaxis ) &&
- ( facingladderaxis || reallyclosetoladder ) &&
- closetoladder )
- {
- StartForcedMove( true, player->MaxSpeed(), bestOrigin, ladder );
- return true;
- }
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Must be facing toward ladder
-// Input : *ladder -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool CHL2GameMovement::LookingAtLadder( CFuncLadder *ladder )
-{
- if ( !ladder )
- {
- return false;
- }
-
- // Get ladder end points
- Vector top, bottom;
- ladder->GetTopPosition( top );
- ladder->GetBottomPosition( bottom );
-
- // Find closest point on ladder to player (could be an endpoint)
- Vector closest;
- CalcClosestPointOnLineSegment( mv->GetAbsOrigin(), bottom, top, closest, NULL );
-
- // Flatten our view direction to 2D
- Vector flatForward = m_vecForward;
- flatForward.z = 0.0f;
-
- // Because the ladder itself is not a solid, the player's origin may actually be
- // permitted to pass it, and that will screw up our dot product.
- // So back up the player's origin a bit to do the facing calculation.
- Vector vecAdjustedOrigin = mv->GetAbsOrigin() - 8.0f * flatForward;
-
- // Figure out vector from player to closest point on ladder
- Vector vecToLadder = closest - vecAdjustedOrigin;
-
- // Flatten it to 2D
- Vector flatLadder = vecToLadder;
- flatLadder.z = 0.0f;
-
- // Normalize the vectors (unnecessary)
- VectorNormalize( flatLadder );
- VectorNormalize( flatForward );
-
- // Compute dot product to see if forward is in same direction as vec to ladder
- float facingDot = flatForward.Dot( flatLadder );
-
- float requiredDot = ( sv_ladder_useonly.GetBool() ) ? -0.99 : 0.0;
-
- // Facing same direction if dot > = requiredDot...
- bool facingladder = ( facingDot >= requiredDot );
-
- return facingladder;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &trace -
-//-----------------------------------------------------------------------------
-bool CHL2GameMovement::CheckLadderAutoMount( CFuncLadder *ladder, const Vector& bestOrigin )
-{
-#if !defined( CLIENT_DLL )
-
- if ( ladder != NULL )
- {
- StartForcedMove( true, player->MaxSpeed(), bestOrigin, ladder );
- return true;
- }
-
-#endif
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-bool CHL2GameMovement::LadderMove( void )
-{
-
- if ( player->GetMoveType() == MOVETYPE_NOCLIP )
- {
- SetLadder( NULL );
- return false;
- }
-
- // If being forced to mount/dismount continue to act like we are on the ladder
- if ( IsForceMoveActive() && ContinueForcedMove() )
- {
- return true;
- }
-
- CFuncLadder *bestLadder = NULL;
- Vector bestOrigin( 0, 0, 0 );
-
- CFuncLadder *ladder = GetLadder();
-
- // Something 1) deactivated the ladder... or 2) something external applied
- // a force to us. In either case make the player fall, etc.
- if ( ladder &&
- ( !ladder->IsEnabled() ||
- ( player->GetBaseVelocity().LengthSqr() > 1.0f ) ) )
- {
- GetHL2Player()->ExitLadder();
- ladder = NULL;
- }
-
- if ( !ladder )
- {
- Findladder( 64.0f, &bestLadder, bestOrigin, NULL );
- }
-
-#if !defined (CLIENT_DLL)
- if( !ladder && bestLadder && sv_ladder_useonly.GetBool() )
- {
- GetHL2Player()->DisplayLadderHudHint();
- }
-#endif
-
- int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame
- int buttonsPressed = buttonsChanged & mv->m_nButtons;
- bool pressed_use = ( buttonsPressed & IN_USE ) ? true : false;
-
- // If I'm already moving on a ladder, use the previous ladder direction
- if ( !ladder && !pressed_use )
- {
- // If flying through air, allow mounting ladders if we are facing < 15 degress from the ladder and we are close
- if ( !ladder && !sv_ladder_useonly.GetBool() )
- {
- // Tracker 6625: Don't need to be leaping to auto mount using this method...
- // But if we are on the ground, then we must not be backing into the ladder (Tracker 12961)
- bool onground = player->GetGroundEntity() ? true : false;
- if ( !onground || ( mv->m_flForwardMove > 0.0f ) )
- {
- if ( CheckLadderAutoMountCone( bestLadder, bestOrigin, 15.0f, 32.0f ) )
- {
- return true;
- }
- }
-
- // Pressing forward while looking at ladder and standing (or floating) near a mounting point
- if ( mv->m_flForwardMove > 0.0f )
- {
- if ( CheckLadderAutoMountEndPoint( bestLadder, bestOrigin ) )
- {
- return true;
- }
- }
- }
-
- return false;
- }
-
- if ( !ladder &&
- LookingAtLadder( bestLadder ) &&
- CheckLadderAutoMount( bestLadder, bestOrigin ) )
- {
- return true;
- }
-
- // Reassign the ladder
- ladder = GetLadder();
- if ( !ladder )
- {
- return false;
- }
-
- // Don't play the deny sound
- if ( pressed_use )
- {
- GetHL2Player()->m_bPlayUseDenySound = false;
- }
-
- // Make sure we are on the ladder
- player->SetMoveType( MOVETYPE_LADDER );
- player->SetMoveCollide( MOVECOLLIDE_DEFAULT );
-
- player->SetGravity( 0.0f );
-
- float forwardSpeed = 0.0f;
- float rightSpeed = 0.0f;
-
- float speed = player->MaxSpeed();
-
-
- if ( mv->m_nButtons & IN_BACK )
- {
- forwardSpeed -= speed;
- }
-
- if ( mv->m_nButtons & IN_FORWARD )
- {
- forwardSpeed += speed;
- }
-
- if ( mv->m_nButtons & IN_MOVELEFT )
- {
- rightSpeed -= speed;
- }
-
- if ( mv->m_nButtons & IN_MOVERIGHT )
- {
- rightSpeed += speed;
- }
-
- if ( mv->m_nButtons & IN_JUMP )
- {
- player->SetMoveType( MOVETYPE_WALK );
- // Remove from ladder
- SetLadder( NULL );
-
- // Jump in view direction
- Vector jumpDir = m_vecForward;
-
- // unless pressing backward or something like that
- if ( mv->m_flForwardMove < 0.0f )
- {
- jumpDir = -jumpDir;
- }
-
- VectorNormalize( jumpDir );
-
- VectorScale( jumpDir, MAX_CLIMB_SPEED, mv->m_vecVelocity );
- // Tracker 13558: Don't add any extra z velocity if facing downward at all
- if ( m_vecForward.z >= 0.0f )
- {
- mv->m_vecVelocity.z = mv->m_vecVelocity.z + 50;
- }
- return false;
- }
-
- if ( forwardSpeed != 0 || rightSpeed != 0 )
- {
- // See if the player is looking toward the top or the bottom
- Vector velocity;
-
- VectorScale( m_vecForward, forwardSpeed, velocity );
- VectorMA( velocity, rightSpeed, m_vecRight, velocity );
-
- VectorNormalize( velocity );
-
- Vector ladderUp;
- ladder->ComputeLadderDir( ladderUp );
- VectorNormalize( ladderUp );
-
- Vector topPosition;
- Vector bottomPosition;
-
- ladder->GetTopPosition( topPosition );
- ladder->GetBottomPosition( bottomPosition );
-
- // Check to see if we've mounted the ladder in a bogus spot and, if so, just fall off the ladder...
- float dummyt = 0.0f;
- float distFromLadderSqr = CalcDistanceSqrToLine( mv->GetAbsOrigin(), topPosition, bottomPosition, &dummyt );
- if ( distFromLadderSqr > 36.0f )
- {
- // Uh oh, we fell off zee ladder...
- player->SetMoveType( MOVETYPE_WALK );
- // Remove from ladder
- SetLadder( NULL );
- return false;
- }
-
- bool ishorizontal = fabs( topPosition.z - bottomPosition.z ) < 64.0f ? true : false;
-
- float changeover = ishorizontal ? 0.0f : 0.3f;
-
- float factor = 1.0f;
- if ( velocity.z >= 0 )
- {
- float dotTop = ladderUp.Dot( velocity );
- if ( dotTop < -changeover )
- {
- // Aimed at bottom
- factor = -1.0f;
- }
- }
- else
- {
- float dotBottom = -ladderUp.Dot( velocity );
- if ( dotBottom > changeover )
- {
- factor = -1.0f;
- }
- }
-
-#ifdef _XBOX
- if( sv_ladders_useonly.GetBool() )
- {
- // Stick up climbs up, stick down climbs down. No matter which way you're looking.
- if ( mv->m_nButtons & IN_FORWARD )
- {
- factor = 1.0f;
- }
- else if( mv->m_nButtons & IN_BACK )
- {
- factor = -1.0f;
- }
- }
-#endif//_XBOX
-
- mv->m_vecVelocity = MAX_CLIMB_SPEED * factor * ladderUp;
- }
- else
- {
- mv->m_vecVelocity.Init();
- }
-
- return true;
-}
-
-void CHL2GameMovement::SetGroundEntity( trace_t *pm )
-{
- CBaseEntity *newGround = pm ? pm->m_pEnt : NULL;
-
- //Adrian: Special case for combine balls.
- if ( newGround && newGround->GetCollisionGroup() == HL2COLLISION_GROUP_COMBINE_BALL_NPC )
- {
- return;
- }
-
- BaseClass::SetGroundEntity( pm );
-}
-
-bool CHL2GameMovement::CanAccelerate()
-{
-#ifdef HL2MP
- if ( player->IsObserver() )
- {
- return true;
- }
-#endif
-
- BaseClass::CanAccelerate();
-
- return true;
-}
-
-
-#ifndef PORTAL // Portal inherits from this but needs to declare it's own global interface
- // Expose our interface.
- static CHL2GameMovement g_GameMovement;
- IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement;
-
- EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement );
+//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Special handling for hl2 usable ladders +// +//=============================================================================// +#include "cbase.h" +#include "hl_gamemovement.h" +#include "in_buttons.h" +#include "utlrbtree.h" +#include "hl2_shareddefs.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +static ConVar sv_autoladderdismount( "sv_autoladderdismount", "1", FCVAR_REPLICATED, "Automatically dismount from ladders when you reach the end (don't have to +USE)." ); +static ConVar sv_ladderautomountdot( "sv_ladderautomountdot", "0.4", FCVAR_REPLICATED, "When auto-mounting a ladder by looking up its axis, this is the tolerance for looking now directly along the ladder axis." ); + +static ConVar sv_ladder_useonly( "sv_ladder_useonly", "0", FCVAR_REPLICATED, "If set, ladders can only be mounted by pressing +USE" ); + +#define USE_DISMOUNT_SPEED 100 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +CHL2GameMovement::CHL2GameMovement() +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : type - +// Output : int +//----------------------------------------------------------------------------- +int CHL2GameMovement::GetCheckInterval( IntervalType_t type ) +{ + // HL2 ladders need to check every frame!!! + if ( type == LADDER ) + return 1; + + return BaseClass::GetCheckInterval( type ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHL2GameMovement::IsForceMoveActive() +{ + LadderMove_t *lm = GetLadderMove(); + return lm->m_bForceLadderMove; +} + +//----------------------------------------------------------------------------- +// Purpose: Debounce the USE button +//----------------------------------------------------------------------------- +void CHL2GameMovement::SwallowUseKey() +{ + mv->m_nOldButtons |= IN_USE; + player->m_afButtonPressed &= ~IN_USE; + + GetHL2Player()->m_bPlayUseDenySound = false; +} + +#if !defined( CLIENT_DLL ) +// This is a simple helper class to reserver a player sized hull at a spot, owned by the current player so that nothing +// can move into this spot and cause us to get stuck when we get there +class CReservePlayerSpot : public CBaseEntity +{ + DECLARE_CLASS( CReservePlayerSpot, CBaseEntity ) +public: + static CReservePlayerSpot *ReserveSpot( CBasePlayer *owner, const Vector& org, const Vector& mins, const Vector& maxs, bool& validspot ); + + virtual void Spawn(); +}; + +CReservePlayerSpot *CReservePlayerSpot::ReserveSpot( + CBasePlayer *owner, const Vector& org, const Vector& mins, const Vector& maxs, bool& validspot ) +{ + CReservePlayerSpot *spot = ( CReservePlayerSpot * )CreateEntityByName( "reserved_spot" ); + Assert( spot ); + + spot->SetAbsOrigin( org ); + UTIL_SetSize( spot, mins, maxs ); + spot->SetOwnerEntity( owner ); + spot->Spawn(); + + // See if spot is valid + trace_t tr; + UTIL_TraceHull( + org, + org, + mins, + maxs, + MASK_PLAYERSOLID, + owner, + COLLISION_GROUP_PLAYER_MOVEMENT, + &tr ); + + validspot = !tr.startsolid; + + if ( !validspot ) + { + Vector org2 = org + Vector( 0, 0, 1 ); + + // See if spot is valid + trace_t tr; + UTIL_TraceHull( + org2, + org2, + mins, + maxs, + MASK_PLAYERSOLID, + owner, + COLLISION_GROUP_PLAYER_MOVEMENT, + &tr ); + validspot = !tr.startsolid; + } + + return spot; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CReservePlayerSpot::Spawn() +{ + BaseClass::Spawn(); + + SetSolid( SOLID_BBOX ); + SetMoveType( MOVETYPE_NONE ); + // Make entity invisible + AddEffects( EF_NODRAW ); +} + +LINK_ENTITY_TO_CLASS( reserved_spot, CReservePlayerSpot ); + +#endif +//----------------------------------------------------------------------------- +// Purpose: +// Input : mounting - +// transit_speed - +// goalpos - +// *ladder - +//----------------------------------------------------------------------------- +void CHL2GameMovement::StartForcedMove( bool mounting, float transit_speed, const Vector& goalpos, CFuncLadder *ladder ) +{ + LadderMove_t* lm = GetLadderMove(); + Assert( lm ); + // Already active, just ignore + if ( lm->m_bForceLadderMove ) + { + return; + } + +#if !defined( CLIENT_DLL ) + if ( ladder ) + { + ladder->PlayerGotOn( GetHL2Player() ); + + // If the Ladder only wants to be there for automount checking, abort now + if ( ladder->DontGetOnLadder() ) + return; + } + + // Reserve goal slot here + bool valid = false; + lm->m_hReservedSpot = CReservePlayerSpot::ReserveSpot( + player, + goalpos, + GetPlayerMins( ( player->GetFlags() & FL_DUCKING ) ? true : false ), + GetPlayerMaxs( ( player->GetFlags() & FL_DUCKING ) ? true : false ), + valid ); + if ( !valid ) + { + // FIXME: Play a deny sound? + if ( lm->m_hReservedSpot ) + { + UTIL_Remove( lm->m_hReservedSpot ); + lm->m_hReservedSpot = NULL; + } + return; + } +#endif + + // Use current player origin as start and new origin as dest + lm->m_vecGoalPosition = goalpos; + lm->m_vecStartPosition = mv->GetAbsOrigin(); + + // Figure out how long it will take to make the gap based on transit_speed + Vector delta = lm->m_vecGoalPosition - lm->m_vecStartPosition; + + float distance = delta.Length(); + + Assert( transit_speed > 0.001f ); + + // Compute time required to move that distance + float transit_time = distance / transit_speed; + if ( transit_time < 0.001f ) + { + transit_time = 0.001f; + } + + lm->m_bForceLadderMove = true; + lm->m_bForceMount = mounting; + + lm->m_flStartTime = gpGlobals->curtime; + lm->m_flArrivalTime = lm->m_flStartTime + transit_time; + + lm->m_hForceLadder = ladder; + + // Don't get stuck during this traversal since we'll just be slamming the player origin + player->SetMoveType( MOVETYPE_NONE ); + player->SetMoveCollide( MOVECOLLIDE_DEFAULT ); + player->SetSolid( SOLID_NONE ); + SetLadder( ladder ); + + // Debounce the use key + SwallowUseKey(); +} + +//----------------------------------------------------------------------------- +// Purpose: Returns false when finished +//----------------------------------------------------------------------------- +bool CHL2GameMovement::ContinueForcedMove() +{ + LadderMove_t* lm = GetLadderMove(); + Assert( lm ); + Assert( lm->m_bForceLadderMove ); + + // Suppress regular motion + mv->m_flForwardMove = 0.0f; + mv->m_flSideMove = 0.0f; + mv->m_flUpMove = 0.0f; + + // How far along are we + float frac = ( gpGlobals->curtime - lm->m_flStartTime ) / ( lm->m_flArrivalTime - lm->m_flStartTime ); + if ( frac > 1.0f ) + { + lm->m_bForceLadderMove = false; +#if !defined( CLIENT_DLL ) + // Remove "reservation entity" + if ( lm->m_hReservedSpot ) + { + UTIL_Remove( lm->m_hReservedSpot ); + lm->m_hReservedSpot = NULL; + } +#endif + } + + frac = clamp( frac, 0.0f, 1.0f ); + + // Move origin part of the way + Vector delta = lm->m_vecGoalPosition - lm->m_vecStartPosition; + + // Compute interpolated position + Vector org; + VectorMA( lm->m_vecStartPosition, frac, delta, org ); + mv->SetAbsOrigin( org ); + + // If finished moving, reset player to correct movetype (or put them on the ladder) + if ( !lm->m_bForceLadderMove ) + { + player->SetSolid( SOLID_BBOX ); + player->SetMoveType( MOVETYPE_WALK ); + + if ( lm->m_bForceMount && lm->m_hForceLadder != NULL ) + { + player->SetMoveType( MOVETYPE_LADDER ); + SetLadder( lm->m_hForceLadder ); + } + + // Zero out any velocity + mv->m_vecVelocity.Init(); + } + + // Stil active + return lm->m_bForceLadderMove; +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the player is on a ladder +// Input : &trace - ignored +//----------------------------------------------------------------------------- +bool CHL2GameMovement::OnLadder( trace_t &trace ) +{ + return ( GetLadder() != NULL ) ? true : false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : ladders - +// maxdist - +// **ppLadder - +// ladderOrigin - +//----------------------------------------------------------------------------- +void CHL2GameMovement::Findladder( float maxdist, CFuncLadder **ppLadder, Vector& ladderOrigin, const CFuncLadder *skipLadder ) +{ + CFuncLadder *bestLadder = NULL; + float bestDist = MAX_COORD_INTEGER; + Vector bestOrigin; + + bestOrigin.Init(); + + float maxdistSqr = maxdist * maxdist; + + + int c = CFuncLadder::GetLadderCount(); + for ( int i = 0 ; i < c; i++ ) + { + CFuncLadder *ladder = CFuncLadder::GetLadder( i ); + + if ( !ladder->IsEnabled() ) + continue; + + if ( skipLadder && ladder == skipLadder ) + continue; + + Vector topPosition; + Vector bottomPosition; + + ladder->GetTopPosition( topPosition ); + ladder->GetBottomPosition( bottomPosition ); + + Vector closest; + CalcClosestPointOnLineSegment( mv->GetAbsOrigin(), bottomPosition, topPosition, closest, NULL ); + + float distSqr = ( closest - mv->GetAbsOrigin() ).LengthSqr(); + + // Too far away + if ( distSqr > maxdistSqr ) + { + continue; + } + + // Need to trace to see if it's clear + trace_t tr; + + UTIL_TraceLine( mv->GetAbsOrigin(), closest, + MASK_PLAYERSOLID, + player, + COLLISION_GROUP_NONE, + &tr ); + + if ( tr.fraction != 1.0f && + tr.m_pEnt && + tr.m_pEnt != ladder ) + { + // Try a trace stepped up from the ground a bit, in case there's something at ground level blocking us. + float sizez = GetPlayerMaxs().z - GetPlayerMins().z; + + UTIL_TraceLine( mv->GetAbsOrigin() + Vector( 0, 0, sizez * 0.5f ), closest, + MASK_PLAYERSOLID, + player, + COLLISION_GROUP_NONE, + &tr ); + + if ( tr.fraction != 1.0f && + tr.m_pEnt && + tr.m_pEnt != ladder && + !tr.m_pEnt->IsSolidFlagSet( FSOLID_TRIGGER ) ) + { + continue; + } + } + + // See if this is the best one so far + if ( distSqr < bestDist ) + { + bestDist = distSqr; + bestLadder = ladder; + bestOrigin = closest; + } + } + + // Return best ladder spot + *ppLadder = bestLadder; + ladderOrigin = bestOrigin; + +} + +static bool NearbyDismountLessFunc( const NearbyDismount_t& lhs, const NearbyDismount_t& rhs ) +{ + return lhs.distSqr < rhs.distSqr; +} + +void CHL2GameMovement::GetSortedDismountNodeList( const Vector &org, float radius, CFuncLadder *ladder, CUtlRBTree< NearbyDismount_t, int >& list ) +{ + float radiusSqr = radius * radius; + + int i; + int c = ladder->GetDismountCount(); + for ( i = 0; i < c; i++ ) + { + CInfoLadderDismount *spot = ladder->GetDismount( i ); + if ( !spot ) + continue; + + float distSqr = ( spot->GetAbsOrigin() - org ).LengthSqr(); + if ( distSqr > radiusSqr ) + continue; + + NearbyDismount_t nd; + nd.dismount = spot; + nd.distSqr = distSqr; + + list.Insert( nd ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// *ladder - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHL2GameMovement::ExitLadderViaDismountNode( CFuncLadder *ladder, bool strict, bool useAlternate ) +{ + // Find the best ladder exit node + float bestDot = -99999.0f; + float bestDistance = 99999.0f; + Vector bestDest; + bool found = false; + + // For 'alternate' dismount + bool foundAlternate = false; + Vector alternateDest; + float alternateDist = 99999.0f; + + CUtlRBTree< NearbyDismount_t, int > nearbyDismounts( 0, 0, NearbyDismountLessFunc ); + + GetSortedDismountNodeList( mv->GetAbsOrigin(), 100.0f, ladder, nearbyDismounts ); + + int i; + + for ( i = nearbyDismounts.FirstInorder(); i != nearbyDismounts.InvalidIndex() ; i = nearbyDismounts.NextInorder( i ) ) + { + CInfoLadderDismount *spot = nearbyDismounts[ i ].dismount; + if ( !spot ) + { + Assert( !"What happened to the spot!!!" ); + continue; + } + + // See if it's valid to put the player there... + Vector org = spot->GetAbsOrigin() + Vector( 0, 0, 1 ); + + trace_t tr; + UTIL_TraceHull( + org, + org, + GetPlayerMins( ( player->GetFlags() & FL_DUCKING ) ? true : false ), + GetPlayerMaxs( ( player->GetFlags() & FL_DUCKING ) ? true : false ), + MASK_PLAYERSOLID, + player, + COLLISION_GROUP_PLAYER_MOVEMENT, + &tr ); + + // Nope... + if ( tr.startsolid ) + { + continue; + } + + // Find the best dot product + Vector vecToSpot = org - ( mv->GetAbsOrigin() + player->GetViewOffset() ); + vecToSpot.z = 0.0f; + float d = VectorNormalize( vecToSpot ); + + float dot = vecToSpot.Dot( m_vecForward ); + + // We're not facing at it...ignore + if ( dot < 0.5f ) + { + if( useAlternate && d < alternateDist ) + { + alternateDest = org; + alternateDist = d; + foundAlternate = true; + } + + continue; + } + + if ( dot > bestDot ) + { + bestDest = org; + bestDistance = d; + bestDot = dot; + found = true; + } + } + + if ( found ) + { + // Require a more specific + if ( strict && + ( ( bestDot < 0.7f ) || ( bestDistance > 40.0f ) ) ) + { + return false; + } + + StartForcedMove( false, player->MaxSpeed(), bestDest, NULL ); + return true; + } + + if( useAlternate ) + { + // Desperate. Don't refuse to let a person off of a ladder if it can be helped. Use the + // alternate dismount if there is one. + if( foundAlternate && alternateDist <= 60.0f ) + { + StartForcedMove( false, player->MaxSpeed(), alternateDest, NULL ); + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : bOnLadder - +//----------------------------------------------------------------------------- +void CHL2GameMovement::FullLadderMove() +{ +#if !defined( CLIENT_DLL ) + CFuncLadder *ladder = GetLadder(); + Assert( ladder ); + if ( !ladder ) + { + return; + } + + CheckWater(); + + // Was jump button pressed? If so, don't do anything here + if ( mv->m_nButtons & IN_JUMP ) + { + CheckJumpButton(); + return; + } + else + { + mv->m_nOldButtons &= ~IN_JUMP; + } + + player->SetGroundEntity( NULL ); + + // Remember old positions in case we cancel this movement + Vector oldVelocity = mv->m_vecVelocity; + Vector oldOrigin = mv->GetAbsOrigin(); + + Vector topPosition; + Vector bottomPosition; + + ladder->GetTopPosition( topPosition ); + ladder->GetBottomPosition( bottomPosition ); + + // Compute parametric distance along ladder vector... + float oldt; + CalcDistanceSqrToLine( mv->GetAbsOrigin(), topPosition, bottomPosition, &oldt ); + + // Perform the move accounting for any base velocity. + VectorAdd (mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity); + TryPlayerMove(); + VectorSubtract (mv->m_vecVelocity, player->GetBaseVelocity(), mv->m_vecVelocity); + + // Pressed buttons are "changed(xor)" and'ed with the mask of currently held buttons + int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame + int buttonsPressed = buttonsChanged & mv->m_nButtons; + bool pressed_use = ( buttonsPressed & IN_USE ) ? true : false; + bool pressing_forward_or_side = mv->m_flForwardMove != 0.0f || mv->m_flSideMove != 0.0f; + + Vector ladderVec = topPosition - bottomPosition; + float LadderLength = VectorNormalize( ladderVec ); + // This test is not perfect by any means, but should help a bit + bool moving_along_ladder = false; + if ( pressing_forward_or_side ) + { + float fwdDot = m_vecForward.Dot( ladderVec ); + if ( fabs( fwdDot ) > 0.9f ) + { + moving_along_ladder = true; + } + } + + // Compute parametric distance along ladder vector... + float newt; + CalcDistanceSqrToLine( mv->GetAbsOrigin(), topPosition, bottomPosition, &newt ); + + // Fudge of 2 units + float tolerance = 1.0f / LadderLength; + + bool wouldleaveladder = false; + // Moving pPast top or bottom? + if ( newt < -tolerance ) + { + wouldleaveladder = newt < oldt; + } + else if ( newt > ( 1.0f + tolerance ) ) + { + wouldleaveladder = newt > oldt; + } + + // See if we are near the top or bottom but not moving + float dist1sqr, dist2sqr; + + dist1sqr = ( topPosition - mv->GetAbsOrigin() ).LengthSqr(); + dist2sqr = ( bottomPosition - mv->GetAbsOrigin() ).LengthSqr(); + + float dist = MIN( dist1sqr, dist2sqr ); + bool neardismountnode = ( dist < 16.0f * 16.0f ) ? true : false; + float ladderUnitsPerTick = ( MAX_CLIMB_SPEED * gpGlobals->interval_per_tick ); + bool neardismountnode2 = ( dist < ladderUnitsPerTick * ladderUnitsPerTick ) ? true : false; + + // Really close to node, cvar is set, and pressing a key, then simulate a +USE + bool auto_dismount_use = ( neardismountnode2 && + sv_autoladderdismount.GetBool() && + pressing_forward_or_side && + !moving_along_ladder ); + + bool fully_underwater = ( player->GetWaterLevel() == WL_Eyes ) ? true : false; + + // If the user manually pressed use or we're simulating it, then use_dismount will occur + bool use_dismount = pressed_use || auto_dismount_use; + + if ( fully_underwater && !use_dismount ) + { + // If fully underwater, we require looking directly at a dismount node + /// to "float off" a ladder mid way... + if ( ExitLadderViaDismountNode( ladder, true ) ) + { + // See if they +used a dismount point mid-span.. + return; + } + } + + // If the movement would leave the ladder and they're not automated or pressing use, disallow the movement + if ( !use_dismount ) + { + if ( wouldleaveladder ) + { + // Don't let them leave the ladder if they were on it + mv->m_vecVelocity = oldVelocity; + mv->SetAbsOrigin( oldOrigin ); + } + return; + } + + // If the move would not leave the ladder and we're near close to the end, then just accept the move + if ( !wouldleaveladder && !neardismountnode ) + { + // Otherwise, if the move would leave the ladder, disallow it. + if ( pressed_use ) + { + if ( ExitLadderViaDismountNode( ladder, false, IsX360() ) ) + { + // See if they +used a dismount point mid-span.. + return; + } + + player->SetMoveType( MOVETYPE_WALK ); + player->SetMoveCollide( MOVECOLLIDE_DEFAULT ); + SetLadder( NULL ); + GetHL2Player()->m_bPlayUseDenySound = false; + + // Dismount with a bit of velocity in facing direction + VectorScale( m_vecForward, USE_DISMOUNT_SPEED, mv->m_vecVelocity ); + mv->m_vecVelocity.z = 50; + } + return; + } + + // Debounce the use key + if ( pressed_use ) + { + SwallowUseKey(); + } + + // Try auto exit, if possible + if ( ExitLadderViaDismountNode( ladder, false, pressed_use ) ) + { + return; + } + + if ( wouldleaveladder ) + { + // Otherwise, if the move would leave the ladder, disallow it. + if ( pressed_use ) + { + player->SetMoveType( MOVETYPE_WALK ); + player->SetMoveCollide( MOVECOLLIDE_DEFAULT ); + SetLadder( NULL ); + + // Dismount with a bit of velocity in facing direction + VectorScale( m_vecForward, USE_DISMOUNT_SPEED, mv->m_vecVelocity ); + mv->m_vecVelocity.z = 50; + } + else + { + mv->m_vecVelocity = oldVelocity; + mv->SetAbsOrigin( oldOrigin ); + } + } +#endif +} + +bool CHL2GameMovement::CheckLadderAutoMountEndPoint( CFuncLadder *ladder, const Vector& bestOrigin ) +{ + // See if we're really near an endpoint + if ( !ladder ) + return false; + + Vector top, bottom; + ladder->GetTopPosition( top ); + ladder->GetBottomPosition( bottom ); + + float d1, d2; + + d1 = ( top - mv->GetAbsOrigin() ).LengthSqr(); + d2 = ( bottom - mv->GetAbsOrigin() ).LengthSqr(); + + if ( d1 > 16 * 16 && d2 > 16 * 16 ) + return false; + + Vector ladderAxis; + + if ( d1 < 16 * 16 ) + { + // Close to top + ladderAxis = bottom - top; + } + else + { + ladderAxis = top - bottom; + } + + VectorNormalize( ladderAxis ); + + if ( ladderAxis.Dot( m_vecForward ) > sv_ladderautomountdot.GetFloat() ) + { + StartForcedMove( true, player->MaxSpeed(), bestOrigin, ladder ); + return true; + } + + return false; +} + +bool CHL2GameMovement::CheckLadderAutoMountCone( CFuncLadder *ladder, const Vector& bestOrigin, float maxAngleDelta, float maxDistToLadder ) +{ + // Never 'back' onto ladders or stafe onto ladders + if ( ladder != NULL && + ( mv->m_flForwardMove > 0.0f ) ) + { + Vector top, bottom; + ladder->GetTopPosition( top ); + ladder->GetBottomPosition( bottom ); + + Vector ladderAxis = top - bottom; + VectorNormalize( ladderAxis ); + + Vector probe = mv->GetAbsOrigin(); + + Vector closest; + CalcClosestPointOnLineSegment( probe, bottom, top, closest, NULL ); + + Vector vecToLadder = closest - probe; + + float dist = VectorNormalize( vecToLadder ); + + Vector flatLadder = vecToLadder; + flatLadder.z = 0.0f; + Vector flatForward = m_vecForward; + flatForward.z = 0.0f; + + VectorNormalize( flatLadder ); + VectorNormalize( flatForward ); + + float facingDot = flatForward.Dot( flatLadder ); + float angle = acos( facingDot ) * 180 / M_PI; + + bool closetoladder = ( dist != 0.0f && dist < maxDistToLadder ) ? true : false; + bool reallyclosetoladder = ( dist != 0.0f && dist < 4.0f ) ? true : false; + + bool facingladderaxis = ( angle < maxAngleDelta ) ? true : false; + bool facingalongaxis = ( (float)fabs( ladderAxis.Dot( m_vecForward ) ) > sv_ladderautomountdot.GetFloat() ) ? true : false; +#if 0 + Msg( "close %i length %.3f maxdist %.3f facing %.3f dot %.3f ang %.3f\n", + closetoladder ? 1 : 0, + dist, + maxDistToLadder, + (float)fabs( ladderAxis.Dot( m_vecForward ) ), + facingDot, + angle); +#endif + + // Tracker 21776: Don't mount ladders this way if strafing + bool strafing = ( fabs( mv->m_flSideMove ) < 1.0f ) ? false : true; + + if ( ( ( facingDot > 0.0f && !strafing ) || facingalongaxis ) && + ( facingladderaxis || reallyclosetoladder ) && + closetoladder ) + { + StartForcedMove( true, player->MaxSpeed(), bestOrigin, ladder ); + return true; + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Must be facing toward ladder +// Input : *ladder - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CHL2GameMovement::LookingAtLadder( CFuncLadder *ladder ) +{ + if ( !ladder ) + { + return false; + } + + // Get ladder end points + Vector top, bottom; + ladder->GetTopPosition( top ); + ladder->GetBottomPosition( bottom ); + + // Find closest point on ladder to player (could be an endpoint) + Vector closest; + CalcClosestPointOnLineSegment( mv->GetAbsOrigin(), bottom, top, closest, NULL ); + + // Flatten our view direction to 2D + Vector flatForward = m_vecForward; + flatForward.z = 0.0f; + + // Because the ladder itself is not a solid, the player's origin may actually be + // permitted to pass it, and that will screw up our dot product. + // So back up the player's origin a bit to do the facing calculation. + Vector vecAdjustedOrigin = mv->GetAbsOrigin() - 8.0f * flatForward; + + // Figure out vector from player to closest point on ladder + Vector vecToLadder = closest - vecAdjustedOrigin; + + // Flatten it to 2D + Vector flatLadder = vecToLadder; + flatLadder.z = 0.0f; + + // Normalize the vectors (unnecessary) + VectorNormalize( flatLadder ); + VectorNormalize( flatForward ); + + // Compute dot product to see if forward is in same direction as vec to ladder + float facingDot = flatForward.Dot( flatLadder ); + + float requiredDot = ( sv_ladder_useonly.GetBool() ) ? -0.99 : 0.0; + + // Facing same direction if dot > = requiredDot... + bool facingladder = ( facingDot >= requiredDot ); + + return facingladder; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : &trace - +//----------------------------------------------------------------------------- +bool CHL2GameMovement::CheckLadderAutoMount( CFuncLadder *ladder, const Vector& bestOrigin ) +{ +#if !defined( CLIENT_DLL ) + + if ( ladder != NULL ) + { + StartForcedMove( true, player->MaxSpeed(), bestOrigin, ladder ); + return true; + } + +#endif + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +bool CHL2GameMovement::LadderMove( void ) +{ + + if ( player->GetMoveType() == MOVETYPE_NOCLIP ) + { + SetLadder( NULL ); + return false; + } + + // If being forced to mount/dismount continue to act like we are on the ladder + if ( IsForceMoveActive() && ContinueForcedMove() ) + { + return true; + } + + CFuncLadder *bestLadder = NULL; + Vector bestOrigin( 0, 0, 0 ); + + CFuncLadder *ladder = GetLadder(); + + // Something 1) deactivated the ladder... or 2) something external applied + // a force to us. In either case make the player fall, etc. + if ( ladder && + ( !ladder->IsEnabled() || + ( player->GetBaseVelocity().LengthSqr() > 1.0f ) ) ) + { + GetHL2Player()->ExitLadder(); + ladder = NULL; + } + + if ( !ladder ) + { + Findladder( 64.0f, &bestLadder, bestOrigin, NULL ); + } + +#if !defined (CLIENT_DLL) + if( !ladder && bestLadder && sv_ladder_useonly.GetBool() ) + { + GetHL2Player()->DisplayLadderHudHint(); + } +#endif + + int buttonsChanged = ( mv->m_nOldButtons ^ mv->m_nButtons ); // These buttons have changed this frame + int buttonsPressed = buttonsChanged & mv->m_nButtons; + bool pressed_use = ( buttonsPressed & IN_USE ) ? true : false; + + // If I'm already moving on a ladder, use the previous ladder direction + if ( !ladder && !pressed_use ) + { + // If flying through air, allow mounting ladders if we are facing < 15 degress from the ladder and we are close + if ( !ladder && !sv_ladder_useonly.GetBool() ) + { + // Tracker 6625: Don't need to be leaping to auto mount using this method... + // But if we are on the ground, then we must not be backing into the ladder (Tracker 12961) + bool onground = player->GetGroundEntity() ? true : false; + if ( !onground || ( mv->m_flForwardMove > 0.0f ) ) + { + if ( CheckLadderAutoMountCone( bestLadder, bestOrigin, 15.0f, 32.0f ) ) + { + return true; + } + } + + // Pressing forward while looking at ladder and standing (or floating) near a mounting point + if ( mv->m_flForwardMove > 0.0f ) + { + if ( CheckLadderAutoMountEndPoint( bestLadder, bestOrigin ) ) + { + return true; + } + } + } + + return false; + } + + if ( !ladder && + LookingAtLadder( bestLadder ) && + CheckLadderAutoMount( bestLadder, bestOrigin ) ) + { + return true; + } + + // Reassign the ladder + ladder = GetLadder(); + if ( !ladder ) + { + return false; + } + + // Don't play the deny sound + if ( pressed_use ) + { + GetHL2Player()->m_bPlayUseDenySound = false; + } + + // Make sure we are on the ladder + player->SetMoveType( MOVETYPE_LADDER ); + player->SetMoveCollide( MOVECOLLIDE_DEFAULT ); + + player->SetGravity( 0.0f ); + + float forwardSpeed = 0.0f; + float rightSpeed = 0.0f; + + float speed = player->MaxSpeed(); + + + if ( mv->m_nButtons & IN_BACK ) + { + forwardSpeed -= speed; + } + + if ( mv->m_nButtons & IN_FORWARD ) + { + forwardSpeed += speed; + } + + if ( mv->m_nButtons & IN_MOVELEFT ) + { + rightSpeed -= speed; + } + + if ( mv->m_nButtons & IN_MOVERIGHT ) + { + rightSpeed += speed; + } + + if ( mv->m_nButtons & IN_JUMP ) + { + player->SetMoveType( MOVETYPE_WALK ); + // Remove from ladder + SetLadder( NULL ); + + // Jump in view direction + Vector jumpDir = m_vecForward; + + // unless pressing backward or something like that + if ( mv->m_flForwardMove < 0.0f ) + { + jumpDir = -jumpDir; + } + + VectorNormalize( jumpDir ); + + VectorScale( jumpDir, MAX_CLIMB_SPEED, mv->m_vecVelocity ); + // Tracker 13558: Don't add any extra z velocity if facing downward at all + if ( m_vecForward.z >= 0.0f ) + { + mv->m_vecVelocity.z = mv->m_vecVelocity.z + 50; + } + return false; + } + + if ( forwardSpeed != 0 || rightSpeed != 0 ) + { + // See if the player is looking toward the top or the bottom + Vector velocity; + + VectorScale( m_vecForward, forwardSpeed, velocity ); + VectorMA( velocity, rightSpeed, m_vecRight, velocity ); + + VectorNormalize( velocity ); + + Vector ladderUp; + ladder->ComputeLadderDir( ladderUp ); + VectorNormalize( ladderUp ); + + Vector topPosition; + Vector bottomPosition; + + ladder->GetTopPosition( topPosition ); + ladder->GetBottomPosition( bottomPosition ); + + // Check to see if we've mounted the ladder in a bogus spot and, if so, just fall off the ladder... + float dummyt = 0.0f; + float distFromLadderSqr = CalcDistanceSqrToLine( mv->GetAbsOrigin(), topPosition, bottomPosition, &dummyt ); + if ( distFromLadderSqr > 36.0f ) + { + // Uh oh, we fell off zee ladder... + player->SetMoveType( MOVETYPE_WALK ); + // Remove from ladder + SetLadder( NULL ); + return false; + } + + bool ishorizontal = fabs( topPosition.z - bottomPosition.z ) < 64.0f ? true : false; + + float changeover = ishorizontal ? 0.0f : 0.3f; + + float factor = 1.0f; + if ( velocity.z >= 0 ) + { + float dotTop = ladderUp.Dot( velocity ); + if ( dotTop < -changeover ) + { + // Aimed at bottom + factor = -1.0f; + } + } + else + { + float dotBottom = -ladderUp.Dot( velocity ); + if ( dotBottom > changeover ) + { + factor = -1.0f; + } + } + +#ifdef _XBOX + if( sv_ladders_useonly.GetBool() ) + { + // Stick up climbs up, stick down climbs down. No matter which way you're looking. + if ( mv->m_nButtons & IN_FORWARD ) + { + factor = 1.0f; + } + else if( mv->m_nButtons & IN_BACK ) + { + factor = -1.0f; + } + } +#endif//_XBOX + + mv->m_vecVelocity = MAX_CLIMB_SPEED * factor * ladderUp; + } + else + { + mv->m_vecVelocity.Init(); + } + + return true; +} + +void CHL2GameMovement::SetGroundEntity( trace_t *pm ) +{ + CBaseEntity *newGround = pm ? pm->m_pEnt : NULL; + + //Adrian: Special case for combine balls. + if ( newGround && newGround->GetCollisionGroup() == HL2COLLISION_GROUP_COMBINE_BALL_NPC ) + { + return; + } + + BaseClass::SetGroundEntity( pm ); +} + +bool CHL2GameMovement::CanAccelerate() +{ +#ifdef HL2MP + if ( player->IsObserver() ) + { + return true; + } +#endif + + BaseClass::CanAccelerate(); + + return true; +} + + +#ifndef PORTAL // Portal inherits from this but needs to declare it's own global interface + // Expose our interface. + static CHL2GameMovement g_GameMovement; + IGameMovement *g_pGameMovement = ( IGameMovement * )&g_GameMovement; + + EXPOSE_SINGLE_INTERFACE_GLOBALVAR(CGameMovement, IGameMovement,INTERFACENAME_GAMEMOVEMENT, g_GameMovement ); #endif
\ No newline at end of file |