Skip to content
Closed
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
13 changes: 11 additions & 2 deletions src/game/server/neo/bot/behavior/neo_bot_retreat_to_cover.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -351,9 +351,18 @@ ActionResult< CNEOBot > CNEOBotRetreatToCover::Update( CNEOBot *me, float interv

m_waitInCoverTimer.Reset();

if ( !m_path.IsValid() )
if ( !m_path.IsValid() && !CNEOBotPathCompute( me, m_path, m_coverArea->GetCenter(), RETREAT_ROUTE ) )
{
CNEOBotPathCompute( me, m_path, m_coverArea->GetCenter(), RETREAT_ROUTE );
// cover we have no path to is no cover: pick another spot, or stop retreating when the pick repeats
CNavArea *pUnreachableArea = m_coverArea;
m_coverArea = FindCoverArea( me );

if ( m_coverArea == NULL || m_coverArea == pUnreachableArea )
{
return Done( "No path to my cover" );
}

return Continue();
}

m_path.Update( me );
Expand Down
36 changes: 32 additions & 4 deletions src/game/server/neo/bot/neo_bot_path_compute.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,38 @@ static void CNEOBotReservePath(CNEOBot* me, PathFollower& path)
}
}

// The last leg walks from the last area the path reached to the goal position,
// and the path follower takes a goal more than a jump above that area's floor as a fall (FAIL_FELL_OFF)
static bool IsGoalLegTooHigh(CNEOBot* bot, const PathFollower& path)
{
const Path::Segment* goalSeg = path.LastSegment();
const Path::Segment* legStart = path.PriorSegment(goalSeg);
if (!legStart || !legStart->area)
{
return false;
}

// a planned jump-up, gap jump, drop or ladder carries the bot along this leg
if (legStart->type != Path::ON_GROUND || goalSeg->type != Path::ON_GROUND)
{
return false;
}

const float rise = goalSeg->pos.z - legStart->area->GetZ(goalSeg->pos);
return rise > bot->GetLocomotionInterface()->GetMaxJumpHeight();
}

// A path that stops short of the goal is only wanted if the caller asked for partial paths
static bool IsPathUsable(const PathFollower& path, bool reachedGoal, bool includeGoalIfPathFails)
static bool IsPathUsable(CNEOBot* bot, const PathFollower& path, bool reachedGoal, bool includeGoalIfPathFails)
{
return path.IsValid() && (reachedGoal || includeGoalIfPathFails);
// Path::Compute can take an area below the goal for the goal's own, as CNavArea::Contains skips areas outside its height range,
// so a complete path's last leg is checked too
if (!path.IsValid() || IsGoalLegTooHigh(bot, path))
{
return false;
}

return reachedGoal || includeGoalIfPathFails;
}

// By default, assumes that we would prefer to have partial paths even if we can't make a full path
Expand All @@ -49,7 +77,7 @@ bool CNEOBotPathCompute(CNEOBot* bot, PathFollower& path, const Vector& goal, Ro

CNEOBotPathCost cost_with_reservations(bot, route);
bool reachedGoal = path.Compute(bot, goal, cost_with_reservations, maxPathLength, includeGoalIfPathFails, requireGoalArea);
if (IsPathUsable(path, reachedGoal, includeGoalIfPathFails))
if (IsPathUsable(bot, path, reachedGoal, includeGoalIfPathFails))
{
CNEOBotReservePath(bot, path);
return true;
Expand All @@ -58,7 +86,7 @@ bool CNEOBotPathCompute(CNEOBot* bot, PathFollower& path, const Vector& goal, Ro
CNEOBotPathCost cost_without_reservations(bot, FASTEST_ROUTE);
cost_without_reservations.m_bIgnoreReservations = true;
reachedGoal = path.Compute(bot, goal, cost_without_reservations, maxPathLength, includeGoalIfPathFails, requireGoalArea);
if (IsPathUsable(path, reachedGoal, includeGoalIfPathFails))
if (IsPathUsable(bot, path, reachedGoal, includeGoalIfPathFails))
{
CNEOBotReservePath(bot, path);
return true;
Expand Down
Loading