Beispiel #1
0
        public List<CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WDist range, Actor self)
        {
            var mi = self.Info.TraitInfo<MobileInfo>();
            var li = mi.LocomotorInfo;
            var targetCell = world.Map.CellContaining(target);

            // Correct for SubCell offset
            target -= world.Map.Grid.OffsetOfSubCell(srcSub);

            // Select only the tiles that are within range from the requested SubCell
            // This assumes that the SubCell does not change during the path traversal
            var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Length / 1024 + 1)
                .Where(t => (world.Map.CenterOfCell(t) - target).LengthSquared <= range.LengthSquared
                            && mi.CanEnterCell(self.World, self, t));

            // See if there is any cell within range that does not involve a cross-domain request
            // Really, we only need to check the circle perimeter, but it's not clear that would be a performance win
            var domainIndex = world.WorldActor.TraitOrDefault<DomainIndex>();
            if (domainIndex != null)
            {
                tilesInRange = new List<CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, li)));
                if (!tilesInRange.Any())
                    return EmptyPath;
            }

            using (var fromSrc = PathSearch.FromPoints(world, li, self, tilesInRange, source, true))
            using (var fromDest = PathSearch.FromPoint(world, li, self, source, targetCell, true).Reverse())
                return FindBidiPath(fromSrc, fromDest);
        }
Beispiel #2
0
        List <CPos> CalculatePathToTarget(Actor self, BlockedByActor check)
        {
            var loc = self.Location;

            // PERF: Assume that CandidateMovementCells doesn't change within a tick to avoid repeated queries
            // when Move enumerates different BlockedByActor values
            if (searchCellsTick != self.World.WorldTick)
            {
                searchCells.Clear();
                searchCellsTick = self.World.WorldTick;
                foreach (var cell in CandidateMovementCells(self))
                {
                    if (domainIndex.IsPassable(loc, cell, Mobile.Info.LocomotorInfo) && Mobile.CanEnterCell(cell))
                    {
                        searchCells.Add(cell);
                    }
                }
            }

            if (!searchCells.Any())
            {
                return(NoPath);
            }

            using (var fromSrc = PathSearch.FromPoints(self.World, Mobile.Locomotor, self, searchCells, loc, check))
                using (var fromDest = PathSearch.FromPoint(self.World, Mobile.Locomotor, self, loc, lastVisibleTargetLocation, check).Reverse())
                    return(pathFinder.FindBidiPath(fromSrc, fromDest));
        }
Beispiel #3
0
        public List <CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WRange range, Actor self)
        {
            var mi           = self.Info.Traits.Get <MobileInfo>();
            var targetCell   = world.Map.CellContaining(target);
            var rangeSquared = range.Range * range.Range;

            // Correct for SubCell offset
            target -= world.Map.OffsetOfSubCell(srcSub);

            // Select only the tiles that are within range from the requested SubCell
            // This assumes that the SubCell does not change during the path traversal
            var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Range / 1024 + 1)
                               .Where(t => (world.Map.CenterOfCell(t) - target).LengthSquared <= rangeSquared &&
                                      mi.CanEnterCell(self.World as World, self as Actor, t));

            // See if there is any cell within range that does not involve a cross-domain request
            // Really, we only need to check the circle perimeter, but it's not clear that would be a performance win
            var domainIndex = world.WorldActor.TraitOrDefault <DomainIndex>();

            if (domainIndex != null)
            {
                var passable = mi.GetMovementClass(world.TileSet);
                tilesInRange = new List <CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, (uint)passable)));
                if (!tilesInRange.Any())
                {
                    return(EmptyPath);
                }
            }

            var path = FindBidiPath(
                PathSearch.FromPoints(world, mi, self, tilesInRange, source, true),
                PathSearch.FromPoint(world, mi, self, source, targetCell, true).Reverse());

            return(path);
        }
Beispiel #4
0
        public List <CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WDist range, Actor self)
        {
            var mi         = self.Info.TraitInfo <MobileInfo>();
            var targetCell = world.Map.CellContaining(target);

            //Correct for SubCell offset.
            //纠正SubCell偏移
            target -= world.Map.Grid.OffsetOfSubCell(srcSub);

            var tilesInRange = world.Map.FindTilesInCircle(targetCell, range.Length / 1024 + 1).
                               Where(t => (world.Map.CenterOfCell(t) - target).LengthSquared <= range.LengthSquared && mi.CanEnterCell(self.World, self, t));

            var domainIndex = world.WorldActor.TraitOrDefault <DomainIndex>();

            if (domainIndex != null)
            {
                var passable = mi.GetMovementClass(world.Map.Rules.TileSet);
                tilesInRange = new List <CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, mi, (uint)passable)));
                if (!tilesInRange.Any())
                {
                    return(EmptyPath);
                }
            }

            using (var fromSrc = PathSearch.FromPoints(world, mi, self, tilesInRange, source, true))
                using (var fromDest = PathSearch.FromPoint(world, mi, self, source, targetCell, true).Reverse())
                    return(FindBidiPath(fromSrc, fromDest));
        }
Beispiel #5
0
        public Actor ClosestProc(Actor self, Actor ignore)
        {
            // Find all refineries and their occupancy count:
            var refs = self.World.ActorsWithTrait <IAcceptResources>()
                       .Where(r => r.Actor != ignore && r.Actor.Owner == self.Owner && IsAcceptableProcType(r.Actor))
                       .Select(r => new {
                Location  = r.Actor.Location + r.Trait.DeliveryOffset,
                Actor     = r.Actor,
                Occupancy = self.World.ActorsHavingTrait <Harvester>(h => h.LinkedProc == r.Actor).Count()
            })
                       .ToDictionary(r => r.Location);

            // Start a search from each refinery's delivery location:
            List <CPos> path;
            var         mi = self.Info.TraitInfo <MobileInfo>();

            using (var search = PathSearch.FromPoints(self.World, mi, self, refs.Values.Select(r => r.Location), self.Location, false)
                                .WithCustomCost(loc =>
            {
                if (!refs.ContainsKey(loc))
                {
                    return(0);
                }

                var occupancy = refs[loc].Occupancy;

                // Too many harvesters clogs up the refinery's delivery location:
                if (occupancy >= Info.MaxUnloadQueue)
                {
                    return(Constants.InvalidNode);
                }

                // Prefer refineries with less occupancy (multiplier is to offset distance cost):
                return(occupancy * Info.UnloadQueueCostModifier);
            }))
                path = self.World.WorldActor.Trait <IPathFinder>().FindPath(search);

            if (path.Count != 0)
            {
                return(refs[path.Last()].Actor);
            }

            return(null);
        }
Beispiel #6
0
        Actor ClosestProc(Actor self, Actor ignore)
        {
            // Find all refineries and their occupancy count:
            var refs = (
                from r in self.World.ActorsWithTrait <IAcceptOre>()
                where r.Actor != ignore && r.Actor.Owner == self.Owner && IsAcceptableProcType(r.Actor)
                let linkedHarvs = self.World.ActorsWithTrait <Harvester>().Where(a => a.Trait.LinkedProc == r.Actor).Count()
                                  select new { Location = r.Actor.Location + r.Trait.DeliverOffset, Actor = r.Actor, Occupancy = linkedHarvs }
                ).ToDictionary(r => r.Location);

            // Start a search from each refinery's delivery location:
            var mi   = self.Info.Traits.Get <MobileInfo>();
            var path = self.World.WorldActor.Trait <PathFinder>().FindPath(
                PathSearch.FromPoints(self.World, mi, self, refs.Values.Select(r => r.Location), self.Location, false)
                .WithCustomCost((loc) =>
            {
                if (!refs.ContainsKey(loc))
                {
                    return(0);
                }

                var occupancy = refs[loc].Occupancy;
                // 4 harvesters clogs up the refinery's delivery location:
                if (occupancy >= 3)
                {
                    return(int.MaxValue);
                }

                // Prefer refineries with less occupancy (multiplier is to offset distance cost):
                return(occupancy * 12);
            })
                );

            // Reverse the found-path to find the refinery location instead of our location:
            path.Reverse();

            if (path.Count != 0)
            {
                return(refs[path[0]].Actor);
            }

            return(null);
        }
Beispiel #7
0
        public Actor ClosestProc(Actor self, Actor ignore)
        {
            // Find all refineries and their occupancy count:
            var refineries = self.World.ActorsWithTrait <IAcceptResources>()
                             .Where(r => r.Actor != ignore && r.Actor.Owner == self.Owner && IsAcceptableProcType(r.Actor))
                             .Select(r => new
            {
                Location  = r.Actor.Location + r.Trait.DeliveryOffset,
                Actor     = r.Actor,
                Occupancy = self.World.ActorsHavingTrait <Harvester>(h => h.LinkedProc == r.Actor).Count()
            }).ToLookup(r => r.Location);

            // Start a search from each refinery's delivery location:
            List <CPos> path;

            using (var search = PathSearch.FromPoints(self.World, mobile.Locomotor, self, refineries.Select(r => r.Key), self.Location, BlockedByActor.None)
                                .WithCustomCost(location =>
            {
                if (!refineries.Contains(location))
                {
                    return(0);
                }

                var occupancy = refineries[location].First().Occupancy;

                // Too many harvesters clogs up the refinery's delivery location:
                if (occupancy >= Info.MaxUnloadQueue)
                {
                    return(PathGraph.PathCostForInvalidPath);
                }

                // Prefer refineries with less occupancy (multiplier is to offset distance cost):
                return(occupancy * Info.UnloadQueueCostModifier);
            }))
                path = mobile.Pathfinder.FindPath(search);

            if (path.Count != 0)
            {
                return(refineries[path.Last()].First().Actor);
            }

            return(null);
        }
Beispiel #8
0
        public List <CPos> FindUnitPathToRange(CPos source, SubCell srcSub, WPos target, WDist range, Actor self, BlockedByActor check)
        {
            if (!cached)
            {
                domainIndex = world.WorldActor.TraitOrDefault <DomainIndex>();

                cached = true;
            }

            // PERF: Because we can be sure that OccupiesSpace is Mobile here, we can save some performance by avoiding querying for the trait.
            var mobile    = (Mobile)self.OccupiesSpace;
            var locomotor = mobile.Locomotor;

            var targetCell = world.Map.CellContaining(target);

            // Correct for SubCell offset
            target -= world.Map.Grid.OffsetOfSubCell(srcSub);

            var rangeLengthSquared = range.LengthSquared;
            var map = world.Map;

            // Select only the tiles that are within range from the requested SubCell
            // This assumes that the SubCell does not change during the path traversal
            var tilesInRange = map.FindTilesInCircle(targetCell, range.Length / 1024 + 1)
                               .Where(t => (map.CenterOfCell(t) - target).LengthSquared <= rangeLengthSquared &&
                                      mobile.Info.CanEnterCell(world, self, t));

            // See if there is any cell within range that does not involve a cross-domain request
            // Really, we only need to check the circle perimeter, but it's not clear that would be a performance win
            if (domainIndex != null)
            {
                tilesInRange = new List <CPos>(tilesInRange.Where(t => domainIndex.IsPassable(source, t, locomotor)));
                if (!tilesInRange.Any())
                {
                    return(EmptyPath);
                }
            }

            using (var fromSrc = PathSearch.FromPoints(world, locomotor, self, tilesInRange, source, check))
                using (var fromDest = PathSearch.FromPoint(world, locomotor, self, source, targetCell, check).Reverse())
                    return(FindBidiPath(fromSrc, fromDest));
        }
        public Actor ClosestDestination(Actor self)
        {
            var refineries = self.World.ActorsWithTrait <AcceptsDeliveredResources>()
                             .Where(r => r.Actor.Owner == self.Owner);

            List <CPos> path;

            using (var search = PathSearch.FromPoints(self.World, mobile.Locomotor, self, refineries.Select(r => r.Actor.Location), self.Location, BlockedByActor.None)
                                .WithCustomCost(loc => self.World.FindActorsInCircle(self.World.Map.CenterOfCell(loc), Info.EnemyAvoidanceRadius)
                                                .Where(u => !u.IsDead && self.Owner.Stances[u.Owner] == Stance.Enemy)
                                                .Sum(u => Math.Max(WDist.Zero.Length, Info.EnemyAvoidanceRadius.Length - (self.World.Map.CenterOfCell(loc) - u.CenterPosition).Length))))
                path = self.World.WorldActor.Trait <IPathFinder>().FindPath(search);

            if (path.Count != 0)
            {
                return(refineries.First(r => r.Actor.Location == path.Last()).Actor);
            }

            return(null);
        }
        public Actor ClosestDestination(Actor self)
        {
            var actors = string.IsNullOrEmpty(ResourceType)
                         ? self.World.ActorsHavingTrait <ResourceCollector>().Where(r => r.Owner == self.Owner)
                         : self.World.ActorsHavingTrait <AcceptsDeliveredResources>().Where(r => r.Owner == self.Owner);

            List <CPos> path;

            using (var search = PathSearch.FromPoints(self.World, mobile.Locomotor, self, actors.Select(a => a.Location), self.Location, BlockedByActor.None)
                                .WithCustomCost(loc => self.World.FindActorsInCircle(self.World.Map.CenterOfCell(loc), Info.EnemyAvoidanceRadius)
                                                .Where(u => !u.IsDead && self.Owner.RelationshipWith(u.Owner) == PlayerRelationship.Enemy)
                                                .Sum(u => Math.Max(WDist.Zero.Length, Info.EnemyAvoidanceRadius.Length - (self.World.Map.CenterOfCell(loc) - u.CenterPosition).Length))))
                path = self.World.WorldActor.Trait <IPathFinder>().FindPath(search);

            if (path.Count != 0)
            {
                return(actors.First(r => r.Location == path.Last()));
            }

            return(null);
        }
Beispiel #11
0
        List <CPos> CalculatePathToTarget(Actor self)
        {
            var targetCells = CandidateMovementCells(self);
            var searchCells = new List <CPos>();
            var loc         = self.Location;

            foreach (var cell in targetCells)
            {
                if (domainIndex.IsPassable(loc, cell, Mobile.Info, movementClass) && Mobile.CanEnterCell(cell))
                {
                    searchCells.Add(cell);
                }
            }

            if (!searchCells.Any())
            {
                return(NoPath);
            }

            using (var fromSrc = PathSearch.FromPoints(self.World, Mobile.Info, self, searchCells, loc, true))
                using (var fromDest = PathSearch.FromPoint(self.World, Mobile.Info, self, loc, targetPosition, true).Reverse())
                    return(pathFinder.FindBidiPath(fromSrc, fromDest));
        }
Beispiel #12
0
        Actor ClosestProc(Actor self, Actor ignore)
        {
            var refs = self.World.ActorsWithTrait <IAcceptOre>()
                       .Where(x => x.Actor != ignore && x.Actor.Owner == self.Owner)
                       .ToList();
            var mi   = self.Info.Traits.Get <MobileInfo>();
            var path = self.World.WorldActor.Trait <PathFinder>().FindPath(
                PathSearch.FromPoints(self.World, mi, self.Owner,
                                      refs.Select(r => r.Actor.Location + r.Trait.DeliverOffset),
                                      self.Location, false));

            path.Reverse();

            if (path.Count != 0)
            {
                return(refs.Where(x => x.Actor.Location + x.Trait.DeliverOffset == path[0])
                       .Select(a => a.Actor).FirstOrDefault());
            }
            else
            {
                return(null);
            }
        }