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.
263 lines
6.7 KiB
263 lines
6.7 KiB
//========= Copyright Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose: Base class for many flying NPCs
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
#include "cbase.h"
|
|
#include "ai_basenpc_flyer.h"
|
|
#include "ai_route.h"
|
|
#include "ai_navigator.h"
|
|
#include "ai_motor.h"
|
|
|
|
// memdbgon must be the last include file in a .cpp file!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
BEGIN_DATADESC( CAI_BaseFlyingBot )
|
|
|
|
DEFINE_FIELD( m_vCurrentVelocity, FIELD_VECTOR),
|
|
DEFINE_FIELD( m_vCurrentAngularVelocity, FIELD_VECTOR ),
|
|
DEFINE_FIELD( m_vCurrentBanking, FIELD_VECTOR),
|
|
DEFINE_FIELD( m_vNoiseMod, FIELD_VECTOR),
|
|
DEFINE_FIELD( m_fHeadYaw, FIELD_FLOAT),
|
|
DEFINE_FIELD( m_vLastPatrolDir, FIELD_VECTOR),
|
|
|
|
END_DATADESC()
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose : Override to return correct velocity
|
|
// Input :
|
|
// Output :
|
|
//------------------------------------------------------------------------------
|
|
void CAI_BaseFlyingBot::GetVelocity(Vector *vVelocity, AngularImpulse *vAngVelocity)
|
|
{
|
|
if (vVelocity != NULL)
|
|
{
|
|
VectorCopy(m_vCurrentVelocity,*vVelocity);
|
|
}
|
|
if (vAngVelocity != NULL)
|
|
{
|
|
QAngle tmp = GetLocalAngularVelocity();
|
|
QAngleToAngularImpulse( tmp, *vAngVelocity );
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose: Turn head yaw into facing direction
|
|
// Input :
|
|
// Output :
|
|
//-----------------------------------------------------------------------------
|
|
QAngle CAI_BaseFlyingBot::BodyAngles()
|
|
{
|
|
return QAngle(0,m_fHeadYaw,0);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input :
|
|
// Output :
|
|
//-----------------------------------------------------------------------------
|
|
void CAI_BaseFlyingBot::TurnHeadToTarget(float flInterval, const Vector &MoveTarget )
|
|
{
|
|
float flDestYaw = VecToYaw( MoveTarget - GetLocalOrigin() );
|
|
|
|
float newYaw = AI_ClampYaw( GetHeadTurnRate() * 10.0f, m_fHeadYaw, flDestYaw, gpGlobals->curtime - GetLastThink() );
|
|
|
|
if ( newYaw != m_fHeadYaw )
|
|
{
|
|
m_fHeadYaw = newYaw;
|
|
}
|
|
|
|
// Set us to face that way
|
|
SetBoneController( 0, m_fHeadYaw );
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
// Input :
|
|
// Output :
|
|
//------------------------------------------------------------------------------
|
|
float CAI_BaseFlyingBot::MinGroundDist(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
// Input :
|
|
// Output :
|
|
//------------------------------------------------------------------------------
|
|
Vector CAI_BaseFlyingBot::VelocityToAvoidObstacles(float flInterval)
|
|
{
|
|
// --------------------------------
|
|
// Avoid banging into stuff
|
|
// --------------------------------
|
|
trace_t tr;
|
|
Vector vTravelDir = m_vCurrentVelocity*flInterval;
|
|
Vector endPos = GetAbsOrigin() + vTravelDir;
|
|
AI_TraceEntity( this, GetAbsOrigin(), endPos, MASK_NPCSOLID|CONTENTS_WATER, &tr );
|
|
if (tr.fraction != 1.0)
|
|
{
|
|
// Bounce off in normal
|
|
Vector vBounce = tr.plane.normal * 0.5 * m_vCurrentVelocity.Length();
|
|
return (vBounce);
|
|
}
|
|
|
|
// --------------------------------
|
|
// Try to remain above the ground.
|
|
// --------------------------------
|
|
float flMinGroundDist = MinGroundDist();
|
|
AI_TraceLine(GetAbsOrigin(), GetAbsOrigin() + Vector(0, 0, -flMinGroundDist),
|
|
MASK_NPCSOLID_BRUSHONLY|CONTENTS_WATER, this, COLLISION_GROUP_NONE, &tr);
|
|
if (tr.fraction < 1)
|
|
{
|
|
// Clamp veloctiy
|
|
if (tr.fraction < 0.1)
|
|
{
|
|
tr.fraction = 0.1;
|
|
}
|
|
|
|
return Vector(0, 0, 50/tr.fraction);
|
|
}
|
|
return vec3_origin;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
// Input :
|
|
// Output :
|
|
//------------------------------------------------------------------------------
|
|
void CAI_BaseFlyingBot::StartTask( const Task_t *pTask )
|
|
{
|
|
switch (pTask->iTask)
|
|
{
|
|
// Skip as done via bone controller
|
|
case TASK_FACE_ENEMY:
|
|
{
|
|
TaskComplete();
|
|
break;
|
|
}
|
|
// Activity is just idle (have no run)
|
|
case TASK_RUN_PATH:
|
|
{
|
|
GetNavigator()->SetMovementActivity(ACT_IDLE);
|
|
TaskComplete();
|
|
break;
|
|
}
|
|
// Don't check for run/walk activity
|
|
case TASK_SCRIPT_RUN_TO_TARGET:
|
|
case TASK_SCRIPT_WALK_TO_TARGET:
|
|
{
|
|
if (GetTarget() == NULL)
|
|
{
|
|
TaskFail(FAIL_NO_TARGET);
|
|
}
|
|
else
|
|
{
|
|
if (!GetNavigator()->SetGoal( GOALTYPE_TARGETENT ) )
|
|
{
|
|
TaskFail(FAIL_NO_ROUTE);
|
|
GetNavigator()->ClearGoal();
|
|
}
|
|
}
|
|
TaskComplete();
|
|
break;
|
|
}
|
|
// Override to get more to get a directional path
|
|
case TASK_GET_PATH_TO_RANDOM_NODE:
|
|
{
|
|
if ( GetNavigator()->SetRandomGoal( pTask->flTaskData, m_vLastPatrolDir ) )
|
|
TaskComplete();
|
|
else
|
|
TaskFail(FAIL_NO_REACHABLE_NODE);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
BaseClass::StartTask(pTask);
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void CAI_BaseFlyingBot::MoveToTarget(float flInterval, const Vector &MoveTarget)
|
|
{
|
|
Assert(0); // This must be overridden in the leaf classes
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
AI_NavPathProgress_t CAI_BaseFlyingBot::ProgressFlyPath(
|
|
float flInterval,
|
|
const CBaseEntity *pNewTarget,
|
|
unsigned collisionMask,
|
|
bool bNewTrySimplify,
|
|
float strictPointTolerance)
|
|
{
|
|
AI_ProgressFlyPathParams_t params( collisionMask, strictPointTolerance );
|
|
|
|
params.SetCurrent( pNewTarget, bNewTrySimplify );
|
|
|
|
AI_NavPathProgress_t progress = GetNavigator()->ProgressFlyPath( params );
|
|
|
|
switch ( progress )
|
|
{
|
|
case AINPP_NO_CHANGE:
|
|
case AINPP_ADVANCED:
|
|
{
|
|
MoveToTarget(flInterval, GetNavigator()->GetCurWaypointPos());
|
|
break;
|
|
}
|
|
|
|
case AINPP_COMPLETE:
|
|
{
|
|
TaskMovementComplete();
|
|
break;
|
|
}
|
|
|
|
case AINPP_BLOCKED: // function is not supposed to test blocking, just simple path progression
|
|
default:
|
|
{
|
|
AssertMsg( 0, ( "Unexpected result" ) );
|
|
break;
|
|
}
|
|
}
|
|
|
|
return progress;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Purpose:
|
|
// Input : *pTarget -
|
|
// &chasePosition -
|
|
//-----------------------------------------------------------------------------
|
|
void CAI_BaseFlyingBot::TranslateNavGoal( CBaseEntity *pTarget, Vector &chasePosition )
|
|
{
|
|
Assert( pTarget != NULL );
|
|
|
|
if ( pTarget == NULL )
|
|
{
|
|
chasePosition = vec3_origin;
|
|
return;
|
|
}
|
|
|
|
// Chase their eyes
|
|
chasePosition = pTarget->GetAbsOrigin() + pTarget->GetViewOffset();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
// Purpose :
|
|
// Input :
|
|
// Output :
|
|
//------------------------------------------------------------------------------
|
|
CAI_BaseFlyingBot::CAI_BaseFlyingBot()
|
|
{
|
|
#ifdef _DEBUG
|
|
m_vCurrentVelocity.Init();
|
|
m_vCurrentBanking.Init();
|
|
m_vLastPatrolDir.Init();
|
|
#endif
|
|
}
|