You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
881 lines
23 KiB
881 lines
23 KiB
// 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; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|