Пример #1
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, self.Location) && claimLayer.CanClaimCell(self, self.Location))
                {
                    return(self.Location);
                }
            }
            else
            {
                if (harv.CanHarvestCell(self, orderLocation.Value) && claimLayer.CanClaimCell(self, orderLocation.Value))
                {
                    return(orderLocation);
                }

                orderLocation = null;
            }

            // Determine where to search from and how far to search:
            var searchFromLoc       = lastHarvestedCell ?? GetSearchFromLocation(self);
            var searchRadius        = lastHarvestedCell.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius;
            var searchRadiusSquared = searchRadius * searchRadius;

            // Find any harvestable resources:
            List <CPos> path;

            using (var search = PathSearch.Search(self.World, locomotorInfo, self, true, loc =>
                                                  domainIndex.IsPassable(self.Location, loc, locomotorInfo) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
                                .WithCustomCost(loc =>
            {
                if ((loc - searchFromLoc).LengthSquared > searchRadiusSquared)
                {
                    return(int.MaxValue);
                }

                return(0);
            })
                                .FromPoint(searchFromLoc)
                                .FromPoint(self.Location))
                path = pathFinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }
Пример #2
0
        /// <summary>
        /// Using LastOrderLocation and self.Location as starting points,
        /// perform A* search to find the nearest accessible and harvestable cell.
        /// </summary>
        CPos?ClosestHarvestablePos(Actor self, int searchRadius)
        {
            if (harv.CanHarvestCell(self, self.Location) && claimLayer.CanClaimCell(self, self.Location))
            {
                return(self.Location);
            }

            // Determine where to search from and how far to search:
            var searchFromLoc       = harv.LastOrderLocation ?? self.Location;
            var searchRadiusSquared = searchRadius * searchRadius;

            // Find any harvestable resources:
            // var passable = (uint)mobileInfo.GetMovementClass(self.World.Map.Rules.TileSet);
            List <CPos> path;

            using (var search = PathSearch.Search(self.World, mobile.Locomotor, self, BlockedByActor.All,
                                                  loc => domainIndex.IsPassable(self.Location, loc, mobileInfo.LocomotorInfo) &&
                                                  harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
                                .WithCustomCost(loc =>
            {
                if ((avoidCell.HasValue && loc == avoidCell.Value) ||
                    (loc - self.Location).LengthSquared > searchRadiusSquared)
                {
                    return(int.MaxValue);
                }

                return(0);
            })
                                .FromPoint(self.Location)
                                .FromPoint(searchFromLoc))
                path = pathFinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }
Пример #3
0
        Target FindNextResource(Actor actor, HarvesterTraitWrapper harv)
        {
            bool IsValidResource(CPos cell) =>
            domainIndex.IsPassable(actor.Location, cell, harv.Mobile.Locomotor) &&
            harv.Harvester.CanHarvestCell(cell) &&
            claimLayer.CanClaimCell(actor, cell);

            var path = harv.Mobile.PathFinder.FindUnitPathToTargetCellByPredicate(
                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)));

            if (path.Count == 0)
            {
                return(Target.Invalid);
            }

            return(Target.FromCell(world, path[0]));
        }
Пример #4
0
        Target FindNextResource(Actor actor, HarvesterTraitWrapper harv)
        {
            Func <CPos, bool> isValidResource = cell =>
                                                domainIndex.IsPassable(actor.Location, cell, harv.Locomotor) &&
                                                harv.Harvester.CanHarvestCell(actor, cell) &&
                                                claimLayer.CanClaimCell(actor, cell);

            var path = pathfinder.FindPath(
                PathSearch.Search(world, harv.Locomotor, actor, BlockedByActor.Stationary, isValidResource)
                .WithCustomCost(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)))
                .FromPoint(actor.Location));

            if (path.Count == 0)
            {
                return(Target.Invalid);
            }

            return(Target.FromCell(world, path[0]));
        }
Пример #5
0
        CPos FindNextResource(Actor actor, Harvester harv)
        {
            var mobileInfo = actor.Info.TraitInfo <MobileInfo>();
            var passable   = (uint)mobileInfo.GetMovementClass(World.Map.Rules.TileSet);

            Func <CPos, bool> isValidResource = cell =>
                                                domainIndex.IsPassable(actor.Location, cell, mobileInfo, passable) &&
                                                harv.CanHarvestCell(actor, cell) &&
                                                claimLayer.CanClaimCell(actor, cell);
            var path = pathfinder.FindPath(
                PathSearch.Search(World, mobileInfo, actor, true, isValidResource)
                .WithCustomCost(loc => World.FindActorsInCircle(World.Map.CenterOfCell(loc), Info.HarvesterEnemyAvoidanceRadius)
                                .Where(u => !u.IsDead && actor.Owner.Stances[u.Owner] == Stance.Enemy)
                                .Sum(u => Math.Max(WDist.Zero.Length, Info.HarvesterEnemyAvoidanceRadius.Length - (World.Map.CenterOfCell(loc) - u.CenterPosition).Length))).FromPoint(actor.Location));

            if (path.Count == 0)
            {
                return(CPos.Zero);
            }
            return(path[0]);
        }
Пример #6
0
        /// <summary>
        /// Finds the closest harvestable pos between the current position of the harvester
        /// and the last order location
        /// </summary>
        CPos?ClosestHarvestablePos(Actor self)
        {
            if (harv.CanHarvestCell(self, self.Location) && claimLayer.CanClaimCell(self, self.Location))
            {
                return(self.Location);
            }

            // Determine where to search from and how far to search:
            var searchFromLoc       = GetSearchFromLocation(self);
            var searchRadius        = harv.LastOrderLocation.HasValue ? harvInfo.SearchFromOrderRadius : harvInfo.SearchFromProcRadius;
            var searchRadiusSquared = searchRadius * searchRadius;

            // Find any harvestable resources:
            List <CPos> path;

            using (var search = PathSearch.Search(self.World, locomotorInfo, self, true, loc =>
                                                  domainIndex.IsPassable(self.Location, loc, locomotorInfo) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
                                .WithCustomCost(loc =>
            {
                if ((avoidCell.HasValue && loc == avoidCell.Value) ||
                    (loc - self.Location).LengthSquared > searchRadiusSquared)
                {
                    return(int.MaxValue);
                }

                return(0);
            })
                                .FromPoint(self.Location)
                                .FromPoint(searchFromLoc))
                path = pathFinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }
Пример #7
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, self.Location) && claimLayer.CanClaimCell(self, self.Location))
                {
                    return(self.Location);
                }
            }
            else
            {
                if (harv.CanHarvestCell(self, orderLocation.Value) && claimLayer.CanClaimCell(self, orderLocation.Value))
                {
                    return(orderLocation);
                }

                orderLocation = null;
            }

            // Determine where to search from and how far to search:
            var procLoc       = GetSearchFromProcLocation(self);
            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.Search(self.World, mobile.Locomotor, self, BlockedByActor.Stationary, loc =>
                                                  domainIndex.IsPassable(self.Location, loc, mobile.Locomotor) && harv.CanHarvestCell(self, loc) && claimLayer.CanClaimCell(self, loc))
                                .WithCustomCost(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(self, 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);
            })
                                .FromPoint(searchFromLoc)
                                .FromPoint(self.Location))
                path = mobile.Pathfinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }
Пример #8
0
        /// <summary>
        /// Finds the closest harvestable pos between the current position of the harvester
        /// and the last order location
        /// </summary>
        CPos?ClosestHarvestablePos(Actor self)
        {
            var mobile = self.Trait <Mobile>();

            // Determine where to search from and how far to search:
            Func <CPos, bool> canHarvest = pos =>
            {
                var resType = resourceLayer.GetResourceType(pos);
                if (resType != null && string.Compare(resType.Info.Name, Info.TargetResourceType, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return(true);
                }

                return(false);
            };

            // Find any harvestable resources:
            List <CPos> path;

            using (var search = PathSearch.Search(self.World, mobile.Locomotor, self, BlockedByActor.Stationary, loc =>
                                                  domainIndex.IsPassable(self.Location, loc, mobile.Locomotor) && canHarvest(loc) && claimLayer.CanClaimCell(self, loc))
                                .FromPoint(self.Location))
                path = pathFinder.FindPath(search);

            if (path.Count > 0)
            {
                return(path[0]);
            }

            return(null);
        }