Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions src/game/server/neo/bot/neo_bot_locomotion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

extern ConVar falldamage;

// How far towards its move goal a bot checks its headroom: at least about a hull width, so it ducks at the
// obstacle rather than a long way before it,
static const float NEO_BOT_HEADROOM_LOOKAHEAD = 32.0f;
// and how often, while the crouch press of one check lasts until the next
static const float NEO_BOT_HEADROOM_CHECK_INTERVAL = 0.2f;
static const float NEO_BOT_HEADROOM_CROUCH_HOLD = 0.3f;

//-----------------------------------------------------------------------------------------
void CNEOBotLocomotion::Update( void )
{
Expand Down Expand Up @@ -56,6 +63,90 @@ void CNEOBotLocomotion::Approach( const Vector& pos, float goalWeight )
}


//-----------------------------------------------------------------------------------------
// Duck when a standing hull would hit something just ahead but a crouched one would not: a beam,
// light fitting or lintel at head height. The bot template this came from never crouched to navigate
void CNEOBotLocomotion::AdjustPosture( const Vector &moveGoal )
{
if ( !IsOnGround() )
{
return;
}

CNEOBot *me = ToNEOBot( GetBot()->GetEntity() );
if ( !me || me->IsBotOnLadder() )
{
return;
}

// A crouch area already holds the duck, and a bot at a ladder's foot or top lines up with the ladder standing
const CNavArea *area = me->GetLastKnownArea();
if ( area && ( area->HasAttributes( NAV_MESH_CROUCH ) || IsLadderEnd( area ) ) )
{
return;
}

if ( !m_headroomTimer.IsElapsed() )
{
return;
}

m_headroomTimer.Start( NEO_BOT_HEADROOM_CHECK_INTERVAL );

// look as far as the bot moves before the next check, plus a hull width
const float flReach = MAX( NEO_BOT_HEADROOM_LOOKAHEAD,
GetGroundSpeed() * NEO_BOT_HEADROOM_CHECK_INTERVAL + GetBot()->GetBodyInterface()->GetHullWidth() );
if ( IsOnlyCrouchClearAhead( moveGoal, flReach ) )
{
me->PressCrouchButton( NEO_BOT_HEADROOM_CROUCH_HOLD );
}
}


//-----------------------------------------------------------------------------------------
bool CNEOBotLocomotion::IsLadderEnd( const CNavArea *area )
{
return area->GetLadders( CNavLadder::LADDER_UP )->Count() > 0
|| area->GetLadders( CNavLadder::LADDER_DOWN )->Count() > 0;
}


//-----------------------------------------------------------------------------------------
bool CNEOBotLocomotion::IsOnlyCrouchClearAhead( const Vector &moveGoal, float flReach ) const
{
const Vector &feet = GetFeet();
Vector toGoal = moveGoal - feet;
toGoal.z = 0.0f;
const float flGoalDist = toGoal.NormalizeInPlace();
if ( flGoalDist < 1.0f )
{
return false;
}

// Sweep from step height up, so a step the bot can walk onto does not count as blocking
const IBody *body = GetBot()->GetBodyInterface();
const float flStep = GetStepHeight();
const float flHalfWidth = 0.5f * body->GetHullWidth();
const Vector mins( -flHalfWidth, -flHalfWidth, 0.0f );
const Vector standMaxs( flHalfWidth, flHalfWidth, body->GetStandHullHeight() - flStep );
const Vector crouchMaxs( flHalfWidth, flHalfWidth, body->GetCrouchHullHeight() - flStep );
const Vector from = feet + Vector( 0.0f, 0.0f, flStep );
const Vector to = from + toGoal * Min( flGoalDist, flReach );

// Players move out of the way, so only the world and props count
NextBotTraceFilterIgnoreActors filter( GetBot()->GetEntity(), COLLISION_GROUP_NONE );
trace_t trace;
TraceHull( from, to, mins, standMaxs, body->GetSolidMask(), &filter, &trace );
if ( trace.fraction >= 1.0f && !trace.startsolid )
{
return false;
}

TraceHull( from, to, mins, crouchMaxs, body->GetSolidMask(), &filter, &trace );
return trace.fraction >= 1.0f && !trace.startsolid;
}


//-----------------------------------------------------------------------------------------
// Distance at which we will die if we fall
float CNEOBotLocomotion::GetDeathDropHeight( void ) const
Expand Down
8 changes: 7 additions & 1 deletion src/game/server/neo/bot/neo_bot_locomotion.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,13 @@ class CNEOBotLocomotion : public PlayerLocomotion
virtual bool IsEntityTraversable( CBaseEntity *obstacle, TraverseWhenType when = EVENTUALLY ) const;

protected:
virtual void AdjustPosture( const Vector &moveGoal ) { } // never crouch to navigate
virtual void AdjustPosture( const Vector &moveGoal ); // duck when only a crouched hull fits ahead

private:
bool IsOnlyCrouchClearAhead( const Vector &moveGoal, float flReach ) const;
static bool IsLadderEnd( const CNavArea *area );

CountdownTimer m_headroomTimer;
};

inline float CNEOBotLocomotion::GetMaxJumpHeight( void ) const
Expand Down
Loading