/// <summary> /// Calculates a path for the actor from multiple possible sources to target. /// Returned path is *reversed* and given target to source. /// The shortest path between a source and the target is returned. /// </summary> /// <remarks> /// Searches that provide a multiple source cells are slower than those than provide only a single source cell, /// as optimizations are possible for the single source case. Use searches from multiple source cells /// sparingly. /// </remarks> public List <CPos> FindUnitPathToTargetCell( Actor self, IEnumerable <CPos> sources, CPos target, BlockedByActor check, Func <CPos, int> customCost = null, Actor ignoreActor = null, bool laneBias = true) { var sourcesList = sources.ToList(); if (sourcesList.Count == 0) { return(NoPath); } var locomotor = GetLocomotor(self); // If the target cell is inaccessible, bail early. var inaccessible = !locomotor.CanMoveFreelyInto(self, target, check, ignoreActor) || (!(customCost is null) && customCost(target) == PathGraph.PathCostForInvalidPath); if (inaccessible) { return(NoPath); } // When searching from only one source cell, some optimizations are possible. if (sourcesList.Count == 1) { var source = sourcesList[0]; // For adjacent cells on the same layer, we can return the path without invoking a full search. if (source.Layer == target.Layer && (source - target).LengthSquared < 3) { return new List <CPos>(2) { target, source } } ; // With one starting point, we can use a bidirectional search. using (var fromTarget = PathSearch.ToTargetCell( world, locomotor, self, new[] { target }, source, check, ignoreActor: ignoreActor)) using (var fromSource = PathSearch.ToTargetCell( world, locomotor, self, new[] { source }, target, check, ignoreActor: ignoreActor, inReverse: true)) return(PathSearch.FindBidiPath(fromTarget, fromSource)); } // With multiple starting points, we can only use a unidirectional search. using (var search = PathSearch.ToTargetCell( world, locomotor, self, sourcesList, target, check, customCost, ignoreActor, laneBias)) return(search.FindPath()); }