Index: source/simulation2/components/CCmpObstructionManager.cpp =================================================================== --- source/simulation2/components/CCmpObstructionManager.cpp +++ source/simulation2/components/CCmpObstructionManager.cpp @@ -821,18 +821,26 @@ bool CCmpObstructionManager::IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const { fixed dist = DistanceToPoint(ent, px, pz); - return dist != fixed::FromInt(-1) && dist <= maxRange + fixed::FromFloat(0.0001) && (opposite ? MaxDistanceToPoint(ent, px, pz) : dist) >= minRange - fixed::FromFloat(0.0001); + // Treat -1 max range as infinite + return dist != fixed::FromInt(-1) && + (dist <= (maxRange + fixed::FromFloat(0.0001)) || maxRange < fixed::Zero()) && + (opposite ? MaxDistanceToPoint(ent, px, pz) : dist) >= minRange - fixed::FromFloat(0.0001); } bool CCmpObstructionManager::IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const { fixed dist = DistanceToTarget(ent, target); - return dist != fixed::FromInt(-1) && dist <= maxRange + fixed::FromFloat(0.0001) && (opposite ? MaxDistanceToTarget(ent, target) : dist) >= minRange- fixed::FromFloat(0.0001); + // Treat -1 max range as infinite + return dist != fixed::FromInt(-1) && + (dist <= (maxRange + fixed::FromFloat(0.0001)) || maxRange < fixed::Zero()) && + (opposite ? MaxDistanceToTarget(ent, target) : dist) >= minRange - fixed::FromFloat(0.0001); } bool CCmpObstructionManager::IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const { entity_pos_t distance = (CFixedVector2D(x, z) - CFixedVector2D(px, pz)).Length(); - return distance <= maxRange + fixed::FromFloat(0.0001) && distance >= minRange - fixed::FromFloat(0.0001); + // Treat -1 max range as infinite + return (distance <= (maxRange + fixed::FromFloat(0.0001)) || maxRange < fixed::Zero()) && + distance >= minRange - fixed::FromFloat(0.0001); } bool CCmpObstructionManager::TestLine(const IObstructionTestFilter& filter, entity_pos_t x0, entity_pos_t z0, entity_pos_t x1, entity_pos_t z1, entity_pos_t r, bool relaxClearanceForUnits) const Index: source/simulation2/components/CCmpUnitMotion.cpp =================================================================== --- source/simulation2/components/CCmpUnitMotion.cpp +++ source/simulation2/components/CCmpUnitMotion.cpp @@ -1392,9 +1392,16 @@ if (distance < minRange) { // Too close to target - move outwards to a circle - // that's slightly larger than the min range + // that's slightly larger than the min range. + // Distance checks are nearest to nearest, so the range must incorporate the clearance, however: + // - units currently move to navcell's center in the long-range pathfinder, so + // that might lead us to a navcell not quite far away enough + // - units are treated as squares, so we need to multiply by sqrt(2). + // thus we need to add some correction factors. + // Max-range checks have the inverse problem, so the delta between min-range and max-range should + // generally be at least two navcells or so. goal.type = PathGoal::INVERTED_CIRCLE; - goal.hw = minRange + Pathfinding::GOAL_DELTA; + goal.hw = minRange + Pathfinding::GOAL_DELTA + m_Clearance * 3 / 2 + Pathfinding::NAVCELL_SIZE * 3 / 4; } else if (maxRange >= entity_pos_t::Zero() && distance > maxRange) { @@ -1473,7 +1480,7 @@ /* * If we're starting outside the maxRange, we need to move closer in. * If we're starting inside the minRange, we need to move further out. - * These ranges are measured from the center of this entity to the edge of the target; + * These ranges are measured from the edge of this entity to the edge of the target; * we add the goal range onto the size of the target shape to get the goal shape. * (Then we extend it outwards/inwards by a little bit to be sure we'll end up * within the right range, in case of minor numerical inaccuracies.) @@ -1515,7 +1522,14 @@ // Circumscribe the square entity_pos_t circleRadius = halfSize.Length(); - entity_pos_t goalDistance = minRange + Pathfinding::GOAL_DELTA; + // Distance checks are nearest to nearest, so the range must incorporate the clearance, however: + // - units currently move to navcell's center in the long-range pathfinder, so + // that might lead us to a navcell not quite far away enough + // - units are treated as squares, so we need to multiply by sqrt(2). + // thus we need to add some correction factors. + // Max-range checks have the inverse problem, so the delta between min-range and max-range should + // generally be at least two navcells or so. + entity_pos_t goalDistance = minRange + Pathfinding::GOAL_DELTA + m_Clearance * 3 / 2 + Pathfinding::NAVCELL_SIZE * 3 / 4; if (ShouldTreatTargetAsCircle(minRange, circleRadius)) { @@ -1573,7 +1587,7 @@ // The target is large relative to our range, so treat it as a square and // get close enough that the diagonals come within range - entity_pos_t goalDistance = (maxRange - Pathfinding::GOAL_DELTA)*2 / 3; // multiply by slightly less than 1/sqrt(2) + entity_pos_t goalDistance = (maxRange - Pathfinding::GOAL_DELTA) * 2 / 3; // multiply by slightly less than 1/sqrt(2) goal.type = PathGoal::SQUARE; goal.u = obstruction.u; Index: source/simulation2/components/ICmpObstructionManager.h =================================================================== --- source/simulation2/components/ICmpObstructionManager.h +++ source/simulation2/components/ICmpObstructionManager.h @@ -201,16 +201,19 @@ /** * Check if the given entity is in range of the other point given those parameters. + * @param maxRange - if -1, treated as infinite. */ virtual bool IsInPointRange(entity_id_t ent, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0; /** * Check if the given entity is in range of the target given those parameters. + * @param maxRange - if -1, treated as infinite. */ virtual bool IsInTargetRange(entity_id_t ent, entity_id_t target, entity_pos_t minRange, entity_pos_t maxRange, bool opposite) const = 0; /** * Check if the given point is in range of the other point given those parameters. + * @param maxRange - if -1, treated as infinite. */ virtual bool IsPointInPointRange(entity_pos_t x, entity_pos_t z, entity_pos_t px, entity_pos_t pz, entity_pos_t minRange, entity_pos_t maxRange) const = 0;