diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/server/NextBot/Player/NextBotPlayerBody.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/server/NextBot/Player/NextBotPlayerBody.cpp')
| -rw-r--r-- | game/server/NextBot/Player/NextBotPlayerBody.cpp | 881 |
1 files changed, 881 insertions, 0 deletions
diff --git a/game/server/NextBot/Player/NextBotPlayerBody.cpp b/game/server/NextBot/Player/NextBotPlayerBody.cpp new file mode 100644 index 0000000..246b6fa --- /dev/null +++ b/game/server/NextBot/Player/NextBotPlayerBody.cpp @@ -0,0 +1,881 @@ +// NextBotPlayerBody.cpp +// Implementation of Body interface for CBasePlayer-derived classes +// Author: Michael Booth, October 2006 +//========= Copyright Valve Corporation, All rights reserved. ============// + +#include "cbase.h" + +#include "NextBot.h" +#include "NextBotPlayerBody.h" +#include "NextBotPlayer.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + + +ConVar nb_saccade_time( "nb_saccade_time", "0.1", FCVAR_CHEAT ); +ConVar nb_saccade_speed( "nb_saccade_speed", "1000", FCVAR_CHEAT ); +ConVar nb_head_aim_steady_max_rate( "nb_head_aim_steady_max_rate", "100", FCVAR_CHEAT ); +ConVar nb_head_aim_settle_duration( "nb_head_aim_settle_duration", "0.3", FCVAR_CHEAT ); +ConVar nb_head_aim_resettle_angle( "nb_head_aim_resettle_angle", "100", FCVAR_CHEAT, "After rotating through this angle, the bot pauses to 'recenter' its virtual mouse on its virtual mousepad" ); +ConVar nb_head_aim_resettle_time( "nb_head_aim_resettle_time", "0.3", FCVAR_CHEAT, "How long the bot pauses to 'recenter' its virtual mouse on its virtual mousepad" ); + + +//----------------------------------------------------------------------------------------------- +/** + * A useful reply for IBody::AimHeadTowards. When the + * head is aiming on target, press the fire button. + */ +void PressFireButtonReply::OnSuccess( INextBot *bot ) +{ + INextBotPlayerInput *playerInput = dynamic_cast< INextBotPlayerInput * >( bot->GetEntity() ); + if ( playerInput ) + { + playerInput->PressFireButton(); + } +} + + +//----------------------------------------------------------------------------------------------- +/** + * A useful reply for IBody::AimHeadTowards. When the + * head is aiming on target, press the alternate fire button. + */ +void PressAltFireButtonReply::OnSuccess( INextBot *bot ) +{ + INextBotPlayerInput *playerInput = dynamic_cast< INextBotPlayerInput * >( bot->GetEntity() ); + if ( playerInput ) + { + playerInput->PressMeleeButton(); + } +} + + +//----------------------------------------------------------------------------------------------- +/** + * A useful reply for IBody::AimHeadTowards. When the + * head is aiming on target, press the jump button. + */ +void PressJumpButtonReply::OnSuccess( INextBot *bot ) +{ + INextBotPlayerInput *playerInput = dynamic_cast< INextBotPlayerInput * >( bot->GetEntity() ); + if ( playerInput ) + { + playerInput->PressJumpButton(); + } +} + + +//----------------------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------------------- +PlayerBody::PlayerBody( INextBot *bot ) : IBody( bot ) +{ + m_player = static_cast< CBasePlayer * >( bot->GetEntity() ); +} + + +//----------------------------------------------------------------------------------------------- +PlayerBody::~PlayerBody() +{ +} + + +//----------------------------------------------------------------------------------------------- +/** + * reset to initial state + */ +void PlayerBody::Reset( void ) +{ + m_posture = STAND; + + m_lookAtPos = vec3_origin; + m_lookAtSubject = NULL; + m_lookAtReplyWhenAimed = NULL; + m_lookAtVelocity = vec3_origin; + m_lookAtExpireTimer.Invalidate(); + + m_lookAtPriority = BORING; + m_lookAtExpireTimer.Invalidate(); + m_lookAtDurationTimer.Invalidate(); + m_isSightedIn = false; + m_hasBeenSightedIn = false; + m_headSteadyTimer.Invalidate(); + m_priorAngles = vec3_angle; + m_anchorRepositionTimer.Invalidate(); + m_anchorForward = vec3_origin; +} + +ConVar bot_mimic( "bot_mimic", "0", 0, "Bot uses usercmd of player by index." ); + +//----------------------------------------------------------------------------------------------- +/** + * Update internal state. + * Do this every tick to keep head aims smooth and accurate + */ +void PlayerBody::Upkeep( void ) +{ + // If mimicking the player, don't modify the view angles. + static ConVarRef bot_mimic( "bot_mimic" ); + if ( bot_mimic.IsValid() && bot_mimic.GetBool() ) + return; + + const float deltaT = gpGlobals->frametime; + if ( deltaT < 0.00001f ) + { + return; + } + + CBasePlayer *player = ( CBasePlayer * )GetBot()->GetEntity(); + + // get current view angles + QAngle currentAngles = player->EyeAngles() + player->GetPunchAngle(); + + // track when our head is "steady" + bool isSteady = true; + + float actualPitchRate = AngleDiff( currentAngles.x, m_priorAngles.x ); + if ( abs( actualPitchRate ) > nb_head_aim_steady_max_rate.GetFloat() * deltaT ) + { + isSteady = false; + } + else + { + float actualYawRate = AngleDiff( currentAngles.y, m_priorAngles.y ); + + if ( abs( actualYawRate ) > nb_head_aim_steady_max_rate.GetFloat() * deltaT ) + { + isSteady = false; + } + } + + if ( isSteady ) + { + if ( !m_headSteadyTimer.HasStarted() ) + { + m_headSteadyTimer.Start(); + } + } + else + { + m_headSteadyTimer.Invalidate(); + } + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + if ( IsHeadSteady() ) + { + const float maxTime = 3.0f; + float t = GetHeadSteadyDuration() / maxTime; + t = clamp( t, 0.f, 1.0f ); + NDebugOverlay::Circle( player->EyePosition(), t * 10.0f, 0, 255, 0, 255, true, 2.0f * deltaT ); + } + } + + m_priorAngles = currentAngles; + + + // if our current look-at has expired, don't change our aim further + if ( m_hasBeenSightedIn && m_lookAtExpireTimer.IsElapsed() ) + { + return; + } + + // simulate limited range of mouse movements + // compute the angle change from "center" + const Vector &forward = GetViewVector(); + float deltaAngle = RAD2DEG( acos( DotProduct( forward, m_anchorForward ) ) ); + if ( deltaAngle > nb_head_aim_resettle_angle.GetFloat() ) + { + // time to recenter our 'virtual mouse' + m_anchorRepositionTimer.Start( RandomFloat( 0.9f, 1.1f ) * nb_head_aim_resettle_time.GetFloat() ); + m_anchorForward = forward; + return; + } + + // if we're currently recentering our "virtual mouse", wait + if ( m_anchorRepositionTimer.HasStarted() && !m_anchorRepositionTimer.IsElapsed() ) + { + return; + } + m_anchorRepositionTimer.Invalidate(); + + + // if we have a subject, update lookat point + CBaseEntity *subject = m_lookAtSubject; + if ( subject ) + { + if ( m_lookAtTrackingTimer.IsElapsed() ) + { + // update subject tracking by periodically estimating linear aim velocity, allowing for "slop" between updates + Vector desiredLookAtPos; + + if ( subject->MyCombatCharacterPointer() ) + { + desiredLookAtPos = GetBot()->GetIntentionInterface()->SelectTargetPoint( GetBot(), subject->MyCombatCharacterPointer() ); + } + else + { + desiredLookAtPos = subject->WorldSpaceCenter(); + } + + desiredLookAtPos += GetHeadAimSubjectLeadTime() * subject->GetAbsVelocity(); + + Vector errorVector = desiredLookAtPos - m_lookAtPos; + float error = errorVector.NormalizeInPlace(); + + float trackingInterval = GetHeadAimTrackingInterval(); + if ( trackingInterval < deltaT ) + { + trackingInterval = deltaT; + } + + float errorVel = error / trackingInterval; + + m_lookAtVelocity = ( errorVel * errorVector ) + subject->GetAbsVelocity(); + + m_lookAtTrackingTimer.Start( RandomFloat( 0.8f, 1.2f ) * trackingInterval ); + } + + m_lookAtPos += deltaT * m_lookAtVelocity; + } + + + // aim view towards last look at point + Vector to = m_lookAtPos - GetEyePosition(); + to.NormalizeInPlace(); + + QAngle desiredAngles; + VectorAngles( to, desiredAngles ); + + QAngle angles; + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + NDebugOverlay::Line( GetEyePosition(), GetEyePosition() + 100.0f * forward, 255, 255, 0, false, 2.0f * deltaT ); + + float thickness = isSteady ? 2.0f : 3.0f; + int r = m_isSightedIn ? 255 : 0; + int g = subject ? 255 : 0; + NDebugOverlay::HorzArrow( GetEyePosition(), m_lookAtPos, thickness, r, g, 255, 255, false, 2.0f * deltaT ); + } + + + const float onTargetTolerance = 0.98f; + float dot = DotProduct( forward, to ); + if ( dot > onTargetTolerance ) + { + // on target + m_isSightedIn = true; + + if ( !m_hasBeenSightedIn ) + { + m_hasBeenSightedIn = true; + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + ConColorMsg( Color( 255, 100, 0, 255 ), "%3.2f: %s Look At SIGHTED IN\n", + gpGlobals->curtime, + m_player->GetPlayerName() ); + } + } + + if ( m_lookAtReplyWhenAimed ) + { + m_lookAtReplyWhenAimed->OnSuccess( GetBot() ); + m_lookAtReplyWhenAimed = NULL; + } + } + else + { + // off target + m_isSightedIn = false; + } + + + // rotate view at a rate proportional to how far we have to turn + // max rate if we need to turn around + // want first derivative continuity of rate as our aim hits to avoid pop + float approachRate = GetMaxHeadAngularVelocity(); + + const float easeOut = 0.7f; + if ( dot > easeOut ) + { + float t = RemapVal( dot, easeOut, 1.0f, 1.0f, 0.02f ); + const float halfPI = 1.57f; + approachRate *= sin( halfPI * t ); + } + + const float easeInTime = 0.25f; + if ( m_lookAtDurationTimer.GetElapsedTime() < easeInTime ) + { + approachRate *= m_lookAtDurationTimer.GetElapsedTime() / easeInTime; + } + + angles.y = ApproachAngle( desiredAngles.y, currentAngles.y, approachRate * deltaT ); + angles.x = ApproachAngle( desiredAngles.x, currentAngles.x, 0.5f * approachRate * deltaT ); + angles.z = 0.0f; + + // back out "punch angle" + angles -= player->GetPunchAngle(); + + angles.x = AngleNormalize( angles.x ); + angles.y = AngleNormalize( angles.y ); + + player->SnapEyeAngles( angles ); +} + + +//----------------------------------------------------------------------------------------------- +bool PlayerBody::SetPosition( const Vector &pos ) +{ + m_player->SetAbsOrigin( pos ); + return true; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return the eye position of the bot in world coordinates + */ +const Vector &PlayerBody::GetEyePosition( void ) const +{ + m_eyePos = m_player->EyePosition(); + return m_eyePos; +} + + +CBaseEntity *PlayerBody::GetEntity( void ) +{ + return m_player; +} + +//----------------------------------------------------------------------------------------------- +/** + * Return the view unit direction vector in world coordinates + */ +const Vector &PlayerBody::GetViewVector( void ) const +{ + m_player->EyeVectors( &m_viewVector ); + return m_viewVector; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Aim the bot's head towards the given goal + */ +void PlayerBody::AimHeadTowards( const Vector &lookAtPos, LookAtPriorityType priority, float duration, INextBotReply *replyWhenAimed, const char *reason ) +{ + if ( duration <= 0.0f ) + { + duration = 0.1f; + } + + // don't spaz our aim around + if ( m_lookAtPriority == priority ) + { + if ( !IsHeadSteady() || GetHeadSteadyDuration() < nb_head_aim_settle_duration.GetFloat() ) + { + // we're still finishing a look-at at the same priority + if ( replyWhenAimed ) + { + replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED ); + } + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At '%s' rejected - previous aim not %s\n", + gpGlobals->curtime, + m_player->GetPlayerName(), + reason, + IsHeadSteady() ? "settled long enough" : "head-steady" ); + } + return; + } + } + + // don't short-circuit if "sighted in" to avoid rapid view jitter + if ( m_lookAtPriority > priority && !m_lookAtExpireTimer.IsElapsed() ) + { + // higher priority lookat still ongoing + if ( replyWhenAimed ) + { + replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED ); + } + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At '%s' rejected - higher priority aim in progress\n", + gpGlobals->curtime, + m_player->GetPlayerName(), + reason ); + } + return; + } + + if ( m_lookAtReplyWhenAimed ) + { + // in-process aim was interrupted + m_lookAtReplyWhenAimed->OnFail( GetBot(), INextBotReply::INTERRUPTED ); + } + + m_lookAtReplyWhenAimed = replyWhenAimed; + m_lookAtExpireTimer.Start( duration ); + + // if given the same point, just update priority + const float epsilon = 1.0f; + if ( ( m_lookAtPos - lookAtPos ).IsLengthLessThan( epsilon ) ) + { + m_lookAtPriority = priority; + return; + } + + // new look-at point + + m_lookAtPos = lookAtPos; + m_lookAtSubject = NULL; + + m_lookAtPriority = priority; + m_lookAtDurationTimer.Start(); + + // do NOT clear this here, or continuous calls to AimHeadTowards will keep IsHeadAimingOnTarget returning false all of the time + // m_isSightedIn = false; + + m_hasBeenSightedIn = false; + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + NDebugOverlay::Cross3D( lookAtPos, 2.0f, 255, 255, 100, true, 2.0f * duration ); + + const char *priName = ""; + switch( priority ) + { + case BORING: priName = "BORING"; break; + case INTERESTING: priName = "INTERESTING"; break; + case IMPORTANT: priName = "IMPORTANT"; break; + case CRITICAL: priName = "CRITICAL"; break; + } + + ConColorMsg( Color( 255, 100, 0, 255 ), "%3.2f: %s Look At ( %g, %g, %g ) for %3.2f s, Pri = %s, Reason = %s\n", + gpGlobals->curtime, + m_player->GetPlayerName(), + lookAtPos.x, lookAtPos.y, lookAtPos.z, + duration, + priName, + ( reason ) ? reason : "" ); + } +} + + +//----------------------------------------------------------------------------------------------- +/** + * Aim the bot's head towards the given goal + */ +void PlayerBody::AimHeadTowards( CBaseEntity *subject, LookAtPriorityType priority, float duration, INextBotReply *replyWhenAimed, const char *reason ) +{ + if ( duration <= 0.0f ) + { + duration = 0.1f; + } + + if ( subject == NULL ) + { + return; + } + + // don't spaz our aim around + if ( m_lookAtPriority == priority ) + { + if ( !IsHeadSteady() || GetHeadSteadyDuration() < nb_head_aim_settle_duration.GetFloat() ) + { + // we're still finishing a look-at at the same priority + if ( replyWhenAimed ) + { + replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED ); + } + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At '%s' rejected - previous aim not %s\n", + gpGlobals->curtime, + m_player->GetPlayerName(), + reason, + IsHeadSteady() ? "head-steady" : "settled long enough" ); + } + return; + } + } + + // don't short-circuit if "sighted in" to avoid rapid view jitter + if ( m_lookAtPriority > priority && !m_lookAtExpireTimer.IsElapsed() ) + { + // higher priority lookat still ongoing + if ( replyWhenAimed ) + { + replyWhenAimed->OnFail( GetBot(), INextBotReply::DENIED ); + } + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + ConColorMsg( Color( 255, 0, 0, 255 ), "%3.2f: %s Look At '%s' rejected - higher priority aim in progress\n", + gpGlobals->curtime, + m_player->GetPlayerName(), + reason ); + } + return; + } + + if ( m_lookAtReplyWhenAimed ) + { + // in-process aim was interrupted + m_lookAtReplyWhenAimed->OnFail( GetBot(), INextBotReply::INTERRUPTED ); + } + + m_lookAtReplyWhenAimed = replyWhenAimed; + m_lookAtExpireTimer.Start( duration ); + + // if given the same subject, just update priority + if ( subject == m_lookAtSubject ) + { + m_lookAtPriority = priority; + return; + } + + // new subject + m_lookAtSubject = subject; + +#ifdef REFACTOR_FOR_CLIENT_SIDE_EYE_TRACKING + CBasePlayer *pMyPlayer = static_cast< CBasePlayer * >( GetEntity() ); + if ( subject->IsPlayer() ) + { + // looking at a player, look at their eye position + TerrorPlayer *pMyTarget = ToTerrorPlayer( subject ); + m_lookAtPos = subject->EyePosition(); + if(pMyPlayer) + { + pMyPlayer->SetLookatPlayer( pMyTarget ); + } + } + else + { + // not looking at a player + m_lookAtPos = subject->WorldSpaceCenter(); + if(pMyPlayer) + { + pMyPlayer->SetLookatPlayer( NULL ); + } + } +#endif + + m_lookAtPriority = priority; + m_lookAtDurationTimer.Start(); + + // do NOT clear this here, or continuous calls to AimHeadTowards will keep IsHeadAimingOnTarget returning false all of the time + // m_isSightedIn = false; + + m_hasBeenSightedIn = false; + + if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) ) + { + NDebugOverlay::Cross3D( m_lookAtPos, 2.0f, 100, 100, 100, true, duration ); + + const char *priName = ""; + switch( priority ) + { + case BORING: priName = "BORING"; break; + case INTERESTING: priName = "INTERESTING"; break; + case IMPORTANT: priName = "IMPORTANT"; break; + case CRITICAL: priName = "CRITICAL"; break; + } + + ConColorMsg( Color( 255, 100, 0, 255 ), "%3.2f: %s Look At subject %s for %3.2f s, Pri = %s, Reason = %s\n", + gpGlobals->curtime, + m_player->GetPlayerName(), + subject->GetClassname(), + duration, + priName, + ( reason ) ? reason : "" ); + } +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if head is not rapidly turning to look somewhere else + */ +bool PlayerBody::IsHeadSteady( void ) const +{ + return m_headSteadyTimer.HasStarted(); +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return the duration that the bot's head has been on-target + */ +float PlayerBody::GetHeadSteadyDuration( void ) const +{ + // return ( IsHeadAimingOnTarget() ) ? m_headSteadyTimer.GetElapsedTime() : 0.0f; + return m_headSteadyTimer.HasStarted() ? m_headSteadyTimer.GetElapsedTime() : 0.0f; +} + + +//----------------------------------------------------------------------------------------------- +// Clear out currently pending replyWhenAimed callback +void PlayerBody::ClearPendingAimReply( void ) +{ + m_lookAtReplyWhenAimed = NULL; +} + + +//----------------------------------------------------------------------------------------------- +float PlayerBody::GetMaxHeadAngularVelocity( void ) const +{ + return nb_saccade_speed.GetFloat(); +} + + +//----------------------------------------------------------------------------------------------- +bool PlayerBody::StartActivity( Activity act, unsigned int flags ) +{ + // player animation state is controlled on the client + return false; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return currently animating activity + */ +Activity PlayerBody::GetActivity( void ) const +{ + return ACT_INVALID; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if currently animating activity matches the given one + */ +bool PlayerBody::IsActivity( Activity act ) const +{ + return false; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if currently animating activity has any of the given flags + */ +bool PlayerBody::HasActivityType( unsigned int flags ) const +{ + return false; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Request a posture change + */ +void PlayerBody::SetDesiredPosture( PostureType posture ) +{ + m_posture = posture; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Get posture body is trying to assume + */ +IBody::PostureType PlayerBody::GetDesiredPosture( void ) const +{ + return m_posture; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if body is trying to assume this posture + */ +bool PlayerBody::IsDesiredPosture( PostureType posture ) const +{ + return ( posture == m_posture ); +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if body's actual posture matches its desired posture + */ +bool PlayerBody::IsInDesiredPosture( void ) const +{ + return true; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return body's current actual posture + */ +IBody::PostureType PlayerBody::GetActualPosture( void ) const +{ + return m_posture; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if body is actually in the given posture + */ +bool PlayerBody::IsActualPosture( PostureType posture ) const +{ + return ( posture == m_posture ); +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if body's current posture allows it to move around the world + */ +bool PlayerBody::IsPostureMobile( void ) const +{ + return true; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if body's posture is in the process of changing to new posture + */ +bool PlayerBody::IsPostureChanging( void ) const +{ + return false; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Arousal level change + */ +void PlayerBody::SetArousal( ArousalType arousal ) +{ + m_arousal = arousal; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Get arousal level + */ +IBody::ArousalType PlayerBody::GetArousal( void ) const +{ + return m_arousal; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return true if body is at this arousal level + */ +bool PlayerBody::IsArousal( ArousalType arousal ) const +{ + return ( arousal == m_arousal ); +} + + +//----------------------------------------------------------------------------------------------- +/** + * Width of bot's collision hull in XY plane + */ +float PlayerBody::GetHullWidth( void ) const +{ + return VEC_HULL_MAX_SCALED( m_player ).x - VEC_HULL_MIN_SCALED( m_player ).x; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Height of bot's current collision hull based on posture + */ +float PlayerBody::GetHullHeight( void ) const +{ + if ( m_posture == CROUCH ) + { + return GetCrouchHullHeight(); + } + + return GetStandHullHeight(); +} + + +//----------------------------------------------------------------------------------------------- +/** + * Height of bot's collision hull when standing + */ +float PlayerBody::GetStandHullHeight( void ) const +{ + return VEC_HULL_MAX_SCALED( m_player ).z - VEC_HULL_MIN_SCALED( m_player ).z; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Height of bot's collision hull when crouched + */ +float PlayerBody::GetCrouchHullHeight( void ) const +{ + return VEC_DUCK_HULL_MAX_SCALED( m_player ).z - VEC_DUCK_HULL_MIN_SCALED( m_player ).z; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return current collision hull minimums based on actual body posture + */ +const Vector &PlayerBody::GetHullMins( void ) const +{ + if ( m_posture == CROUCH ) + { + m_hullMins = VEC_DUCK_HULL_MIN_SCALED( m_player ); + } + else + { + m_hullMins = VEC_HULL_MIN_SCALED( m_player ); + } + + return m_hullMins; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return current collision hull maximums based on actual body posture + */ +const Vector &PlayerBody::GetHullMaxs( void ) const +{ + if ( m_posture == CROUCH ) + { + m_hullMaxs = VEC_DUCK_HULL_MAX_SCALED( m_player ); + } + else + { + m_hullMaxs = VEC_HULL_MAX_SCALED( m_player ); + } + + return m_hullMaxs; +} + + +//----------------------------------------------------------------------------------------------- +/** + * Return the bot's collision mask (hack until we get a general hull trace abstraction here or in the locomotion interface) + */ +unsigned int PlayerBody::GetSolidMask( void ) const +{ + return ( m_player ) ? m_player->PlayerSolidMask() : MASK_PLAYERSOLID; +} + + + + + |