/// <summary> /// Calculates a path for the actor from multiple possible sources, whilst searching for an acceptable target. /// Returned path is *reversed* and given target to source. /// The shortest path between a source and a discovered target is returned. /// </summary> /// <remarks> /// Searches with this method are slower than <see cref="FindUnitPathToTargetCell"/> due to the need to search for /// and discover an acceptable target cell. Use this search sparingly. /// </remarks> public List <CPos> FindUnitPathToTargetCellByPredicate( Actor self, IEnumerable <CPos> sources, Func <CPos, bool> targetPredicate, BlockedByActor check, Func <CPos, int> customCost = null, Actor ignoreActor = null, bool laneBias = true) { // With no pre-specified target location, we can only use a unidirectional search. using (var search = PathSearch.ToTargetCellByPredicate( world, GetLocomotor(self), self, sources, targetPredicate, check, customCost, ignoreActor, laneBias)) return(search.FindPath()); }
Target FindNextResource(Actor actor, HarvesterTraitWrapper harv) { Func <CPos, bool> isValidResource = cell => harv.Harvester.CanHarvestCell(actor, cell) && claimLayer.CanClaimCell(actor, cell); List <CPos> path; using (var search = PathSearch.ToTargetCellByPredicate( world, harv.Locomotor, actor, new[] { actor.Location }, isValidResource, BlockedByActor.Stationary, loc => world.FindActorsInCircle(world.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius) .Where(u => !u.IsDead && actor.Owner.RelationshipWith(u.Owner) == PlayerRelationship.Enemy) .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (world.Map.CenterOfCell(loc) - u.CenterPosition).Length)))) path = pathfinder.FindPath(search); if (path.Count == 0) { return(Target.Invalid); } return(Target.FromCell(world, path[0])); }
/// <summary> /// Finds the closest harvestable pos between the current position of the harvester /// and the last order location /// </summary> CPos?ClosestHarvestablePos(Actor self) { // Harvesters should respect an explicit harvest order instead of harvesting the current cell. if (orderLocation == null) { if (harv.CanHarvestCell(self.Location) && claimLayer.CanClaimCell(self, self.Location)) { return(self.Location); } } else { if (harv.CanHarvestCell(orderLocation.Value) && claimLayer.CanClaimCell(self, orderLocation.Value)) { return(orderLocation); } orderLocation = null; } // Determine where to search from and how far to search: var procLoc = GetSearchFromProcLocation(); var searchFromLoc = lastHarvestedCell ?? procLoc ?? self.Location; var searchRadius = lastHarvestedCell.HasValue ? harvInfo.SearchFromHarvesterRadius : harvInfo.SearchFromProcRadius; var searchRadiusSquared = searchRadius * searchRadius; var map = self.World.Map; var procPos = procLoc.HasValue ? (WPos?)map.CenterOfCell(procLoc.Value) : null; var harvPos = self.CenterPosition; // Find any harvestable resources: List <CPos> path; using (var search = PathSearch.ToTargetCellByPredicate( self.World, mobile.Locomotor, self, new[] { searchFromLoc, self.Location }, loc => harv.CanHarvestCell(loc) && claimLayer.CanClaimCell(self, loc), BlockedByActor.Stationary, loc => { if ((loc - searchFromLoc).LengthSquared > searchRadiusSquared) { return(PathGraph.PathCostForInvalidPath); } // Add a cost modifier to harvestable cells to prefer resources that are closer to the refinery. // This reduces the tendency for harvesters to move in straight lines if (procPos.HasValue && harvInfo.ResourceRefineryDirectionPenalty > 0 && harv.CanHarvestCell(loc)) { var pos = map.CenterOfCell(loc); // Calculate harv-cell-refinery angle (cosine rule) var b = pos - procPos.Value; if (b != WVec.Zero) { var c = pos - harvPos; if (c != WVec.Zero) { var a = harvPos - procPos.Value; var cosA = (int)(512 * (b.LengthSquared + c.LengthSquared - a.LengthSquared) / b.Length / c.Length); // Cost modifier varies between 0 and ResourceRefineryDirectionPenalty return(Math.Abs(harvInfo.ResourceRefineryDirectionPenalty / 2) + harvInfo.ResourceRefineryDirectionPenalty * cosA / 2048); } } } return(0); })) path = mobile.Pathfinder.FindPath(search); if (path.Count > 0) { return(path[0]); } return(null); }