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.
805 lines
20 KiB
805 lines
20 KiB
// NextBotPlayerBody.cpp
|
|
// Implementation of Body interface for CBasePlayer-derived classes
|
|
// Author: Michael Booth, October 2006
|
|
// Copyright (c) 2006 Turtle Rock Studios, Inc. - 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 NextBotSaccadeTime( "nb_saccade_time", "0.1", FCVAR_CHEAT );
|
|
ConVar NextBotSaccadeSpeed( "nb_saccade_speed", "1000", FCVAR_CHEAT );
|
|
ConVar NextBotHeadAimSteadyMaxRate( "nb_head_aim_steady_max_rate", "100", FCVAR_CHEAT );
|
|
ConVar NextBotHeadAimSettleDuration( "nb_head_aim_settle_duration", "0.3", FCVAR_CHEAT );
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
/**
|
|
* 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_lookAtPriority = BORING;
|
|
m_lookAtExpireTimer.Invalidate();
|
|
m_lookAtDurationTimer.Invalidate();
|
|
m_isSightedIn = false;
|
|
m_hasBeenSightedIn = false;
|
|
m_headSteadyTimer.Invalidate();
|
|
m_yawRate = 0.0f;
|
|
m_pitchRate = 0.0f;
|
|
m_priorAngles = vec3_angle;
|
|
}
|
|
|
|
static 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 ) > NextBotHeadAimSteadyMaxRate.GetFloat() * deltaT )
|
|
{
|
|
isSteady = false;
|
|
}
|
|
else
|
|
{
|
|
float actualYawRate = AngleDiff( currentAngles.y, m_priorAngles.y );
|
|
|
|
if ( abs( actualYawRate ) > NextBotHeadAimSteadyMaxRate.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, 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;
|
|
}
|
|
|
|
|
|
// if we have a subject, update lookat point
|
|
CBaseEntity *subject = m_lookAtSubject;
|
|
if ( subject )
|
|
{
|
|
if ( subject->MyCombatCharacterPointer() )
|
|
{
|
|
m_lookAtPos = GetBot()->GetIntentionInterface()->SelectTargetPoint( GetBot(), subject->MyCombatCharacterPointer() );
|
|
}
|
|
else
|
|
{
|
|
m_lookAtPos = subject->WorldSpaceCenter();
|
|
}
|
|
|
|
m_lookAtPos += GetHeadAimSubjectLeadTime() * subject->GetAbsVelocity();
|
|
}
|
|
|
|
// aim view towards last look at point
|
|
Vector to = m_lookAtPos - GetEyePosition();
|
|
to.NormalizeInPlace();
|
|
|
|
QAngle desiredAngles;
|
|
VectorAngles( to, desiredAngles );
|
|
|
|
QAngle angles;
|
|
|
|
const Vector &forward = GetViewVector();
|
|
|
|
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 g = subject ? 255 : 0;
|
|
NDebugOverlay::HorzArrow( GetEyePosition(), m_lookAtPos, thickness, 0, 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;
|
|
m_hasBeenSightedIn = true;
|
|
|
|
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, 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() < NextBotHeadAimSettleDuration.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 rejected - previous aim not settled\n",
|
|
gpGlobals->curtime,
|
|
m_player->GetPlayerName() );
|
|
}
|
|
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 rejected - higher priority aim in progress\n",
|
|
gpGlobals->curtime,
|
|
m_player->GetPlayerName() );
|
|
}
|
|
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();
|
|
m_isSightedIn = false;
|
|
m_hasBeenSightedIn = false;
|
|
|
|
if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
|
|
{
|
|
NDebugOverlay::Cross3D( lookAtPos, 2.0f, 255, 255, 100, true, 2.0f * duration );
|
|
|
|
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() < NextBotHeadAimSettleDuration.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 rejected - previous aim not settled\n",
|
|
gpGlobals->curtime,
|
|
m_player->GetPlayerName() );
|
|
}
|
|
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 rejected - higher priority aim in progress\n",
|
|
gpGlobals->curtime,
|
|
m_player->GetPlayerName() );
|
|
}
|
|
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();
|
|
m_isSightedIn = false;
|
|
m_hasBeenSightedIn = false;
|
|
|
|
if ( GetBot()->IsDebugging( NEXTBOT_LOOK_AT ) )
|
|
{
|
|
NDebugOverlay::Cross3D( m_lookAtPos, 2.0f, 100, 100, 100, true, duration );
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
float PlayerBody::GetMaxHeadAngularVelocity( void ) const
|
|
{
|
|
return NextBotSaccadeSpeed.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.x - VEC_HULL_MIN.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.z - VEC_HULL_MIN.z;
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------------------------
|
|
/**
|
|
* Height of bot's collision hull when crouched
|
|
*/
|
|
float PlayerBody::GetCrouchHullHeight( void ) const
|
|
{
|
|
return VEC_DUCK_HULL_MAX.z - VEC_DUCK_HULL_MIN.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;
|
|
}
|
|
else
|
|
{
|
|
m_hullMins = VEC_HULL_MIN;
|
|
}
|
|
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
m_hullMaxs = VEC_HULL_MAX;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
|
|
|