diff options
Diffstat (limited to 'game/server/NextBot/Player/NextBotPlayerLocomotion.cpp')
| -rw-r--r-- | game/server/NextBot/Player/NextBotPlayerLocomotion.cpp | 826 |
1 files changed, 826 insertions, 0 deletions
diff --git a/game/server/NextBot/Player/NextBotPlayerLocomotion.cpp b/game/server/NextBot/Player/NextBotPlayerLocomotion.cpp new file mode 100644 index 0000000..ea30ee7 --- /dev/null +++ b/game/server/NextBot/Player/NextBotPlayerLocomotion.cpp @@ -0,0 +1,826 @@ +// NextBotPlayerLocomotion.cpp +// Implementation of Locomotion interface for CBasePlayer-derived classes +// Author: Michael Booth, November 2005 +//========= Copyright Valve Corporation, All rights reserved. ============// + +#include "cbase.h" +#include "nav_mesh.h" +#include "in_buttons.h" +#include "NextBot.h" +#include "NextBotUtil.h" +#include "NextBotPlayer.h" +#include "NextBotPlayerLocomotion.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +ConVar NextBotPlayerMoveDirect( "nb_player_move_direct", "0" ); + +//----------------------------------------------------------------------------------------------------- +PlayerLocomotion::PlayerLocomotion( INextBot *bot ) : ILocomotion( bot ) +{ + m_player = NULL; + Reset(); +} + + +//----------------------------------------------------------------------------------------------------- +/** + * Reset locomotor to initial state + */ +void PlayerLocomotion::Reset( void ) +{ + m_player = static_cast< CBasePlayer * >( GetBot()->GetEntity() ); + + m_isJumping = false; + m_isClimbingUpToLedge = false; + m_isJumpingAcrossGap = false; + m_hasLeftTheGround = false; + m_desiredSpeed = 0.0f; + + + m_ladderState = NO_LADDER; + m_ladderInfo = NULL; + m_ladderDismountGoal = NULL; + m_ladderTimer.Invalidate(); + + m_minSpeedLimit = 0.0f; + m_maxSpeedLimit = 9999999.9f; + + BaseClass::Reset(); +} + + +//----------------------------------------------------------------------------------------------------- +bool PlayerLocomotion::TraverseLadder( void ) +{ + switch( m_ladderState ) + { + case APPROACHING_ASCENDING_LADDER: + m_ladderState = ApproachAscendingLadder(); + return true; + + case APPROACHING_DESCENDING_LADDER: + m_ladderState = ApproachDescendingLadder(); + return true; + + case ASCENDING_LADDER: + m_ladderState = AscendLadder(); + return true; + + case DESCENDING_LADDER: + m_ladderState = DescendLadder(); + return true; + + case DISMOUNTING_LADDER_TOP: + m_ladderState = DismountLadderTop(); + return true; + + case DISMOUNTING_LADDER_BOTTOM: + m_ladderState = DismountLadderBottom(); + return true; + + case NO_LADDER: + default: + m_ladderInfo = NULL; + + if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER ) + { + // on ladder and don't want to be + GetBot()->GetEntity()->SetMoveType( MOVETYPE_WALK ); + } + return false; + } + + return true; +} + + +//----------------------------------------------------------------------------------------------------- +/** + * We're close, but not yet on, this ladder - approach it + */ +PlayerLocomotion::LadderState PlayerLocomotion::ApproachAscendingLadder( void ) +{ + if ( m_ladderInfo == NULL ) + { + return NO_LADDER; + } + + // sanity check - are we already at the end of this ladder? + if ( GetFeet().z >= m_ladderInfo->m_top.z - GetStepHeight() ) + { + m_ladderTimer.Start( 2.0f ); + return DISMOUNTING_LADDER_TOP; + } + + // sanity check - are we too far below this ladder to reach it? + if ( GetFeet().z <= m_ladderInfo->m_bottom.z - GetMaxJumpHeight() ) + { + return NO_LADDER; + } + + FaceTowards( m_ladderInfo->m_bottom ); + + // it is important to approach precisely, so use a very large weight to wash out all other Approaches + Approach( m_ladderInfo->m_bottom, 9999999.9f ); + + if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER ) + { + // we're on the ladder + return ASCENDING_LADDER; + } + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Approach ascending ladder", 0.1f, 255, 255, 255, 255 ); + } + + return APPROACHING_ASCENDING_LADDER; +} + + +//----------------------------------------------------------------------------------------------------- +PlayerLocomotion::LadderState PlayerLocomotion::ApproachDescendingLadder( void ) +{ + if ( m_ladderInfo == NULL ) + { + return NO_LADDER; + } + + // sanity check - are we already at the end of this ladder? + if ( GetFeet().z <= m_ladderInfo->m_bottom.z + GetMaxJumpHeight() ) + { + m_ladderTimer.Start( 2.0f ); + return DISMOUNTING_LADDER_BOTTOM; + } + + Vector mountPoint = m_ladderInfo->m_top + 0.25f * GetBot()->GetBodyInterface()->GetHullWidth() * m_ladderInfo->GetNormal(); + Vector to = mountPoint - GetFeet(); + to.z = 0.0f; + + float mountRange = to.NormalizeInPlace(); + Vector moveGoal; + + const float veryClose = 10.0f; + if ( mountRange < veryClose ) + { + // we're right at the ladder - just keep moving forward until we grab it + const Vector &forward = GetMotionVector(); + moveGoal = GetFeet() + 100.0f * forward; + } + else + { + if ( DotProduct( to, m_ladderInfo->GetNormal() ) < 0.0f ) + { + // approaching front of downward ladder + // ## + // ->+ ## + // | ## + // | ## + // | ## + // <-+ ## + // ###### + // + moveGoal = m_ladderInfo->m_top - 100.0f * m_ladderInfo->GetNormal(); + } + else + { + // approaching back of downward ladder + // + // ->+ + // ##| + // ##| + // ##+--> + // ###### + // + moveGoal = m_ladderInfo->m_top + 100.0f * m_ladderInfo->GetNormal(); + } + } + + FaceTowards( moveGoal ); + + // it is important to approach precisely, so use a very large weight to wash out all other Approaches + Approach( moveGoal, 9999999.9f ); + + if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER ) + { + // we're on the ladder + return DESCENDING_LADDER; + } + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Approach descending ladder", 0.1f, 255, 255, 255, 255 ); + } + + return APPROACHING_DESCENDING_LADDER; +} + + +//----------------------------------------------------------------------------------------------------- +PlayerLocomotion::LadderState PlayerLocomotion::AscendLadder( void ) +{ + if ( m_ladderInfo == NULL ) + { + return NO_LADDER; + } + + if ( GetBot()->GetEntity()->GetMoveType() != MOVETYPE_LADDER ) + { + // slipped off ladder + m_ladderInfo = NULL; + return NO_LADDER; + } + + if ( GetFeet().z >= m_ladderInfo->m_top.z ) + { + // reached top of ladder + m_ladderTimer.Start( 2.0f ); + return DISMOUNTING_LADDER_TOP; + } + + // climb up this ladder - look up + Vector goal = GetFeet() + 100.0f * ( -m_ladderInfo->GetNormal() + Vector( 0, 0, 2 ) ); + + GetBot()->GetBodyInterface()->AimHeadTowards( goal, IBody::MANDATORY, 0.1f, NULL, "Ladder" ); + + // it is important to approach precisely, so use a very large weight to wash out all other Approaches + Approach( goal, 9999999.9f ); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Ascend", 0.1f, 255, 255, 255, 255 ); + } + + return ASCENDING_LADDER; +} + + +//----------------------------------------------------------------------------------------------------- +PlayerLocomotion::LadderState PlayerLocomotion::DescendLadder( void ) +{ + if ( m_ladderInfo == NULL ) + { + return NO_LADDER; + } + + if ( GetBot()->GetEntity()->GetMoveType() != MOVETYPE_LADDER ) + { + // slipped off ladder + m_ladderInfo = NULL; + return NO_LADDER; + } + + if ( GetFeet().z <= m_ladderInfo->m_bottom.z + GetBot()->GetLocomotionInterface()->GetStepHeight() ) + { + // reached bottom of ladder + m_ladderTimer.Start( 2.0f ); + return DISMOUNTING_LADDER_BOTTOM; + } + + // climb down this ladder - look down + Vector goal = GetFeet() + 100.0f * ( m_ladderInfo->GetNormal() + Vector( 0, 0, -2 ) ); + + GetBot()->GetBodyInterface()->AimHeadTowards( goal, IBody::MANDATORY, 0.1f, NULL, "Ladder" ); + + // it is important to approach precisely, so use a very large weight to wash out all other Approaches + Approach( goal, 9999999.9f ); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Descend", 0.1f, 255, 255, 255, 255 ); + } + + return DESCENDING_LADDER; +} + + +//----------------------------------------------------------------------------------------------------- +PlayerLocomotion::LadderState PlayerLocomotion::DismountLadderTop( void ) +{ + if ( m_ladderInfo == NULL || m_ladderTimer.IsElapsed() ) + { + m_ladderInfo = NULL; + return NO_LADDER; + } + + IBody *body = GetBot()->GetBodyInterface(); + Vector toGoal = m_ladderDismountGoal->GetCenter() - GetFeet(); + toGoal.z = 0.0f; + float range = toGoal.NormalizeInPlace(); + toGoal.z = 1.0f; + + body->AimHeadTowards( body->GetEyePosition() + 100.0f * toGoal, IBody::MANDATORY, 0.1f, NULL, "Ladder dismount" ); + + // it is important to approach precisely, so use a very large weight to wash out all other Approaches + Approach( GetFeet() + 100.0f * toGoal, 9999999.9f ); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::EntityText( GetBot()->GetEntity()->entindex(), 0, "Dismount top", 0.1f, 255, 255, 255, 255 ); + NDebugOverlay::HorzArrow( GetFeet(), m_ladderDismountGoal->GetCenter(), 5.0f, 255, 255, 0, 255, true, 0.1f ); + } + + // test 2D vector here in case nav area is under the geometry a bit + const float tolerance = 10.0f; + if ( GetBot()->GetEntity()->GetLastKnownArea() == m_ladderDismountGoal && range < tolerance ) + { + // reached dismount goal + m_ladderInfo = NULL; + return NO_LADDER; + } + + return DISMOUNTING_LADDER_TOP; +} + + +//----------------------------------------------------------------------------------------------------- +PlayerLocomotion::LadderState PlayerLocomotion::DismountLadderBottom( void ) +{ + if ( m_ladderInfo == NULL || m_ladderTimer.IsElapsed() ) + { + m_ladderInfo = NULL; + return NO_LADDER; + } + + if ( GetBot()->GetEntity()->GetMoveType() == MOVETYPE_LADDER ) + { + // near the bottom - just let go + GetBot()->GetEntity()->SetMoveType( MOVETYPE_WALK ); + m_ladderInfo = NULL; + } + + return NO_LADDER; +} + + +//----------------------------------------------------------------------------------------------------- +/** + * Update internal state + */ +void PlayerLocomotion::Update( void ) +{ + if ( TraverseLadder() ) + { + return BaseClass::Update(); + } + + if ( m_isJumpingAcrossGap || m_isClimbingUpToLedge ) + { + // force a run + SetMinimumSpeedLimit( GetRunSpeed() ); + + Vector toLanding = m_landingGoal - GetFeet(); + toLanding.z = 0.0f; + toLanding.NormalizeInPlace(); + + if ( m_hasLeftTheGround ) + { + // face into the jump/climb + GetBot()->GetBodyInterface()->AimHeadTowards( GetBot()->GetEntity()->EyePosition() + 100.0 * toLanding, IBody::MANDATORY, 0.25f, NULL, "Facing impending jump/climb" ); + + if ( IsOnGround() ) + { + // back on the ground - jump is complete + m_isClimbingUpToLedge = false; + m_isJumpingAcrossGap = false; + SetMinimumSpeedLimit( 0.0f ); + } + } + else + { + // haven't left the ground yet - just starting the jump + + if ( !IsClimbingOrJumping() ) + { + Jump(); + } + + Vector vel = GetBot()->GetEntity()->GetAbsVelocity(); + + if ( m_isJumpingAcrossGap ) + { + // cheat and max our velocity in case we were stopped at the edge of this gap + vel.x = GetRunSpeed() * toLanding.x; + vel.y = GetRunSpeed() * toLanding.y; + // leave vel.z unchanged + } + + GetBot()->GetEntity()->SetAbsVelocity( vel ); + + if ( !IsOnGround() ) + { + // jump has begun + m_hasLeftTheGround = true; + } + } + + + Approach( m_landingGoal ); + } + + BaseClass::Update(); +} + + +//----------------------------------------------------------------------------------------------------- +void PlayerLocomotion::AdjustPosture( const Vector &moveGoal ) +{ + // This function has no effect if we're not standing or crouching + IBody *body = GetBot()->GetBodyInterface(); + if ( !body->IsActualPosture( IBody::STAND ) && !body->IsActualPosture( IBody::CROUCH ) ) + return; + + // not all games have auto-crouch, so don't assume it here + BaseClass::AdjustPosture( moveGoal ); +} + + +//----------------------------------------------------------------------------------------------------- +/** + * Build a user command to move this player towards the goal position + */ +void PlayerLocomotion::Approach( const Vector &pos, float goalWeight ) +{ + VPROF_BUDGET( "PlayerLocomotion::Approach", "NextBot" ); + + BaseClass::Approach( pos ); + + AdjustPosture( pos ); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::Line( GetFeet(), pos, 255, 255, 0, true, 0.1f ); + } + + INextBotPlayerInput *playerButtons = dynamic_cast< INextBotPlayerInput * >( GetBot() ); + + if ( !playerButtons ) + { + DevMsg( "PlayerLocomotion::Approach: No INextBotPlayerInput\n " ); + return; + } + + Vector forward3D; + m_player->EyeVectors( &forward3D ); + + Vector2D forward( forward3D.x, forward3D.y ); + forward.NormalizeInPlace(); + + Vector2D right( forward.y, -forward.x ); + + // compute unit vector to goal position + Vector2D to = ( pos - GetFeet() ).AsVector2D(); + float goalDistance = to.NormalizeInPlace(); + + float ahead = to.Dot( forward ); + float side = to.Dot( right ); + +#ifdef NEED_TO_INTEGRATE_MOTION_CONTROLLED_CODE_FROM_L4D_PLAYERS + // If we're climbing ledges, we need to stay crouched to prevent player movement code from messing + // with our origin. + CTerrorPlayer *player = ToTerrorPlayer(m_player); + if ( player && player->IsMotionControlledZ( player->GetMainActivity() ) ) + { + playerButtons->PressCrouchButton(); + return; + } +#endif + + if ( m_player->IsOnLadder() && IsUsingLadder() && ( m_ladderState == ASCENDING_LADDER || m_ladderState == DESCENDING_LADDER ) ) + { + // we are on a ladder and WANT to be on a ladder. + playerButtons->PressForwardButton(); + + // Stay in center of ladder. The gamemovement will autocenter us in most cases, but this is needed in case it doesn't. + if ( m_ladderInfo ) + { + Vector posOnLadder; + CalcClosestPointOnLine( GetFeet(), m_ladderInfo->m_bottom, m_ladderInfo->m_top, posOnLadder ); + + Vector alongLadder = m_ladderInfo->m_top - m_ladderInfo->m_bottom; + alongLadder.NormalizeInPlace(); + + Vector rightLadder = CrossProduct( alongLadder, m_ladderInfo->GetNormal() ); + + Vector away = GetFeet() - posOnLadder; + + // we only want error in plane of ladder + float error = DotProduct( away, rightLadder ); + away.NormalizeInPlace(); + + const float tolerance = 5.0f + 0.25f * GetBot()->GetBodyInterface()->GetHullWidth(); + if ( error > tolerance ) + { + if ( DotProduct( away, rightLadder ) > 0.0f ) + { + playerButtons->PressLeftButton(); + } + else + { + playerButtons->PressRightButton(); + } + } + } + } + else + { + const float epsilon = 0.25f; + if ( NextBotPlayerMoveDirect.GetBool() ) + { + if ( goalDistance > epsilon ) + { + playerButtons->SetButtonScale( ahead, side ); + } + } + + if ( ahead > epsilon ) + { + playerButtons->PressForwardButton(); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() + 50.0f * Vector( forward.x, forward.y, 0.0f ), 15.0f, 0, 255, 0, 255, true, 0.1f ); + } + } + else if ( ahead < -epsilon ) + { + playerButtons->PressBackwardButton(); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() - 50.0f * Vector( forward.x, forward.y, 0.0f ), 15.0f, 255, 0, 0, 255, true, 0.1f ); + } + } + + if ( side <= -epsilon ) + { + playerButtons->PressLeftButton(); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() - 50.0f * Vector( right.x, right.y, 0.0f ), 15.0f, 255, 0, 255, 255, true, 0.1f ); + } + } + else if ( side >= epsilon ) + { + playerButtons->PressRightButton(); + + if ( GetBot()->IsDebugging( NEXTBOT_LOCOMOTION ) ) + { + NDebugOverlay::HorzArrow( m_player->GetAbsOrigin(), m_player->GetAbsOrigin() + 50.0f * Vector( right.x, right.y, 0.0f ), 15.0f, 0, 255, 255, 255, true, 0.1f ); + } + } + } + + if ( !IsRunning() ) + { + playerButtons->PressWalkButton(); + } +} + + +//---------------------------------------------------------------------------------------------------- +/** + * Move the bot to the precise given position immediately, + */ +void PlayerLocomotion::DriveTo( const Vector &pos ) +{ + BaseClass::DriveTo( pos ); + + Approach( pos ); +} + + +//---------------------------------------------------------------------------------------------------- +bool PlayerLocomotion::IsClimbPossible( INextBot *me, const CBaseEntity *obstacle ) const +{ + // don't jump unless we have to + const PathFollower *path = GetBot()->GetCurrentPath(); + if ( path ) + { + const float watchForClimbRange = 75.0f; + if ( !path->IsDiscontinuityAhead( GetBot(), Path::CLIMB_UP, watchForClimbRange ) ) + { + // we are not planning on climbing + + // always allow climbing over movable obstacles + if ( obstacle && !const_cast< CBaseEntity * >( obstacle )->IsWorld() ) + { + IPhysicsObject *physics = obstacle->VPhysicsGetObject(); + if ( physics && physics->IsMoveable() ) + { + // movable physics object - climb over it + return true; + } + } + + if ( !GetBot()->GetLocomotionInterface()->IsStuck() ) + { + // we're not stuck - don't try to jump up yet + return false; + } + } + } + + return true; +} + + +//---------------------------------------------------------------------------------------------------- +bool PlayerLocomotion::ClimbUpToLedge( const Vector &landingGoal, const Vector &landingForward, const CBaseEntity *obstacle ) +{ + if ( !IsClimbPossible( GetBot(), obstacle ) ) + { + return false; + } + + Jump(); + + m_isClimbingUpToLedge = true; + m_landingGoal = landingGoal; + m_hasLeftTheGround = false; + + return true; +} + + +//---------------------------------------------------------------------------------------------------- +void PlayerLocomotion::JumpAcrossGap( const Vector &landingGoal, const Vector &landingForward ) +{ + Jump(); + + // face forward + GetBot()->GetBodyInterface()->AimHeadTowards( landingGoal, IBody::MANDATORY, 1.0f, NULL, "Looking forward while jumping a gap" ); + + m_isJumpingAcrossGap = true; + m_landingGoal = landingGoal; + m_hasLeftTheGround = false; +} + + +//---------------------------------------------------------------------------------------------------- +void PlayerLocomotion::Jump( void ) +{ + m_isJumping = true; + m_jumpTimer.Start( 0.5f ); + + INextBotPlayerInput *playerButtons = dynamic_cast< INextBotPlayerInput * >( GetBot() ); + if ( playerButtons ) + { + playerButtons->PressJumpButton(); + } +} + + +//---------------------------------------------------------------------------------------------------- +bool PlayerLocomotion::IsClimbingOrJumping( void ) const +{ + if ( !m_isJumping ) + return false; + + if ( m_jumpTimer.IsElapsed() && IsOnGround() ) + { + m_isJumping = false; + return false; + } + + return true; +} + + +//---------------------------------------------------------------------------------------------------- +bool PlayerLocomotion::IsClimbingUpToLedge( void ) const +{ + return m_isClimbingUpToLedge; +} + + +//---------------------------------------------------------------------------------------------------- +bool PlayerLocomotion::IsJumpingAcrossGap( void ) const +{ + return m_isJumpingAcrossGap; +} + + +//---------------------------------------------------------------------------------------------------- +/** + * Return true if standing on something + */ +bool PlayerLocomotion::IsOnGround( void ) const +{ + return (m_player->GetGroundEntity() != NULL); +} + + +//---------------------------------------------------------------------------------------------------- +/** + * Return the current ground entity or NULL if not on the ground + */ +CBaseEntity *PlayerLocomotion::GetGround( void ) const +{ + return m_player->GetGroundEntity(); +} + + +//---------------------------------------------------------------------------------------------------- +/** + * Surface normal of the ground we are in contact with + */ +const Vector &PlayerLocomotion::GetGroundNormal( void ) const +{ + static Vector up( 0, 0, 1.0f ); + return up; + + // TODO: Integrate movehelper_server for this: return m_player->GetGroundNormal(); +} + + +//---------------------------------------------------------------------------------------------------- +/** + * Climb the given ladder to the top and dismount + */ +void PlayerLocomotion::ClimbLadder( const CNavLadder *ladder, const CNavArea *dismountGoal ) +{ + // look up and push forward +// Vector goal = GetBot()->GetPosition() + 100.0f * ( Vector( 0, 0, 1.0f ) - ladder->GetNormal() ); +// Approach( goal ); +// FaceTowards( goal ); + + m_ladderState = APPROACHING_ASCENDING_LADDER; + m_ladderInfo = ladder; + m_ladderDismountGoal = dismountGoal; +} + + +//---------------------------------------------------------------------------------------------------- +/** + * Descend the given ladder to the bottom and dismount + */ +void PlayerLocomotion::DescendLadder( const CNavLadder *ladder, const CNavArea *dismountGoal ) +{ + // look down and push forward +// Vector goal = GetBot()->GetPosition() + 100.0f * ( Vector( 0, 0, -1.0f ) - ladder->GetNormal() ); +// Approach( goal ); +// FaceTowards( goal ); + + m_ladderState = APPROACHING_DESCENDING_LADDER; + m_ladderInfo = ladder; + m_ladderDismountGoal = dismountGoal; +} + + +//---------------------------------------------------------------------------------------------------- +bool PlayerLocomotion::IsUsingLadder( void ) const +{ + return ( m_ladderState != NO_LADDER ); +} + + +//---------------------------------------------------------------------------------------------------- +/** + * Rotate body to face towards "target" + */ +void PlayerLocomotion::FaceTowards( const Vector &target ) +{ + // player body follows view direction + Vector look( target.x, target.y, GetBot()->GetEntity()->EyePosition().z ); + + GetBot()->GetBodyInterface()->AimHeadTowards( look, IBody::BORING, 0.1f, NULL, "Body facing" ); +} + + +//----------------------------------------------------------------------------------------------------- +/** +* Return position of "feet" - point below centroid of bot at feet level +*/ +const Vector &PlayerLocomotion::GetFeet( void ) const +{ + return m_player->GetAbsOrigin(); +} + + +//----------------------------------------------------------------------------------------------------- +/** + * Return current world space velocity + */ +const Vector &PlayerLocomotion::GetVelocity( void ) const +{ + return m_player->GetAbsVelocity(); +} + + +//----------------------------------------------------------------------------------------------------- +float PlayerLocomotion::GetRunSpeed( void ) const +{ + return m_player->MaxSpeed(); +} + + +//----------------------------------------------------------------------------------------------------- +float PlayerLocomotion::GetWalkSpeed( void ) const +{ + return 0.5f * m_player->MaxSpeed(); +} + |