Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
d1314f0
Fix bots bouncing on ladders and failing to descend
sunzenshen Sep 20, 2026
2d013b5
Mount ladder descents over a barrier at the top
sunzenshen Oct 3, 2026
f710510
Take a climb's exit from after its ladder
sunzenshen Oct 3, 2026
a69bfa0
Pick ladder top area with CNavLadder::GetTopArea across climb and loc…
sunzenshen Oct 6, 2026
0dd0f3f
Tidy ladder comments, constants and the descent hold
sunzenshen Oct 7, 2026
677d96f
Mount ladder descents over a level top
sunzenshen Oct 7, 2026
ae73931
Keep the ladder climb's teleport out of the brush
sunzenshen Oct 7, 2026
05789f1
Restart the unwanted-ladder wait on a climb's claim
sunzenshen Oct 7, 2026
03d81ac
Name the ladder teleport's clearance gap
sunzenshen Oct 7, 2026
fe52b95
Turn the view on a teleported ladder mount
sunzenshen Oct 7, 2026
5c0783b
Dismount toward a ladder landing's near point
sunzenshen Oct 9, 2026
d6224d6
Climb onto a ladder's wall-cap top by the mesh link
sunzenshen Oct 9, 2026
482f0df
Shimmy past a snag before abandoning a climb
sunzenshen Oct 9, 2026
00bc172
Wait out the pre-round freeze in a ladder approach
sunzenshen Oct 9, 2026
2873466
Keep a ladder climb's teleport out of solid
sunzenshen Oct 9, 2026
38209c6
Wait out the freeze by the bot's freeze flag
sunzenshen Oct 9, 2026
bbaa0d9
Scan the ladders only when adopting one
sunzenshen Oct 9, 2026
534eb0e
Return the wall cap from the climb-link test
sunzenshen Oct 9, 2026
bfd4137
Bound the launches onto a ladder's wall cap
sunzenshen Oct 9, 2026
082358e
Rename the ladder climb's dismount point
sunzenshen Oct 9, 2026
49c9819
Clarify ladder comments, constants and the hold
sunzenshen Oct 9, 2026
eab8ed8
Stand up below a ladder's hanging foot to mount it
sunzenshen Oct 9, 2026
9baa158
Give a stalled ladder climb three equal shimmies
sunzenshen Oct 12, 2026
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
58 changes: 58 additions & 0 deletions src/game/server/NextBot/Path/NextBotPathFollow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ ConVar NextBotDebugClimbing( "nb_debug_climbing", "0", FCVAR_CHEAT );
#ifdef NEO
// How far from its feet a bot that landed looks for a nav area, the range UpdateLastKnownArea() searches
static const float LANDING_NAV_AREA_RANGE = 50.0f;
// A climb onto a ladder's wall cap takes the mesh's link at most this many times a path segment,
// then is left to the ledge search: a bot that lands back at the launch point would otherwise jump on every landing
static const int LADDER_CAP_LAUNCHES = 3;
#endif


Expand All @@ -57,6 +60,8 @@ PathFollower::PathFollower( void )

#ifdef NEO
m_wasOnGround = true;
m_capClimbGoal = NULL;
m_capLaunches = 0;
#endif
}

Expand Down Expand Up @@ -121,6 +126,10 @@ void PathFollower::OnPathChanged( INextBot *bot, Path::ResultType result )

#ifdef NEO
m_pathObstacles.Reset();

// a new path reuses the segments' storage, so a launch count kept by segment starts over
m_capClimbGoal = NULL;
m_capLaunches = 0;
#endif
}

Expand Down Expand Up @@ -1284,6 +1293,27 @@ bool PathFollower::FindClimbLedge( INextBot *bot, Vector startTracePos, Vector l
#endif // _DEBUG


#ifdef NEO
//--------------------------------------------------------------------------------------------------------------
// The area after the goal when it is a ladder top less than a hull deep along the approach, else NULL:
// the ledge search cannot find such an area (not the dismount's IsNarrowLanding(), which asks whether a bot can stand on it)
const CNavArea *PathFollower::LadderCapAhead( INextBot *bot ) const
{
// an area a ladder goes down from is that ladder's top
const Segment *afterClimb = NextSegment( m_goal );
if ( !afterClimb || !afterClimb->area || afterClimb->area->GetLadders( CNavLadder::LADDER_DOWN )->Count() == 0 )
{
return NULL;
}

// the depth is the area's axis-aligned size along the approach's dominant axis
const CNavArea *cap = afterClimb->area;
const Vector toLedge = cap->GetCenter() - bot->GetLocomotionInterface()->GetFeet();
const float flDepth = ( fabsf( toLedge.x ) > fabsf( toLedge.y ) ) ? cap->GetSizeX() : cap->GetSizeY();
return ( flDepth < bot->GetBodyInterface()->GetHullWidth() ) ? cap : NULL;
}
#endif

//--------------------------------------------------------------------------------------------------------------
/**
* Climb up ledges
Expand Down Expand Up @@ -1349,6 +1379,34 @@ bool PathFollower::Climbing( INextBot *bot, const Path::Segment *goal, const Vec
return false;
}

#ifdef NEO
// The ledge search below looks for a ledge's floor a full look-ahead past its wall and misses a wall cap,
// so at the launch point of a climb onto one, take the mesh's climb link as the authoritative branch does
const CNavArea *cap = ( m_goal->type == CLIMB_UP ) ? LadderCapAhead( bot ) : NULL;
if ( cap && m_goal != m_capClimbGoal )
{
m_capClimbGoal = m_goal;
m_capLaunches = 0;
}

if ( cap && m_capLaunches < LADDER_CAP_LAUNCHES
&& ( m_goal->pos - mover->GetFeet() ).AsVector2D().IsLengthLessThan( body->GetHullWidth() ) )
{
// the authoritative branch's lines, repeated to leave that branch untouched
Vector nearClimbGoal;
cap->GetClosestPointOnArea( mover->GetFeet(), &nearClimbGoal );

climbDirection = nearClimbGoal - mover->GetFeet();
climbDirection.z = 0.0f;
climbDirection.NormalizeInPlace();

if ( mover->ClimbUpToLedge( nearClimbGoal, climbDirection, NULL ) )
{
++m_capLaunches;
return true;
}
}
#endif

// If we're approaching a CLIMB_UP link, save off the height delta for it, and trust the nav *just* enough
// to climb up to that ledge and only that ledge. We keep as large a tolerance as possible, to trust
Expand Down
3 changes: 3 additions & 0 deletions src/game/server/NextBot/Path/NextBotPathFollow.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,11 @@ class PathFollower : public Path

#ifdef NEO
bool HasFallenBelowPath( INextBot *bot ) const; // return true if we stand off the path, more than a step below it
const CNavArea *LadderCapAhead( INextBot *bot ) const; // return the ladder top shallower than a hull the climb ahead is onto, or NULL
bool m_wasOnGround;
CNEOBotPathObstacles m_pathObstacles; // looks ahead for props to steer around and breakables in the way
const Path::Segment *m_capClimbGoal; // the climb onto a ladder's wall cap m_capLaunches counts
int m_capLaunches;
#endif

float m_goalTolerance;
Expand Down
Loading
Loading