Beispiel #1
0
        public override IActivity Tick( Actor self )
        {
            if( IsCanceled || target.Destroyed || !target.IsInWorld) return NextActivity;

            var mobile = self.Trait<Mobile>();
            var ps1 = new PathSearch( self.World, mobile.Info )
            {
                checkForBlocked = true,
                heuristic = location => 0,
                inReverse = true
            };
            foreach( var cell in target.Trait<IOccupySpace>().OccupiedCells() )
            {
                ps1.AddInitialCell( cell.First );
                if( ( mobile.toCell - cell.First ).LengthSquared <= 2 )
                    return NextActivity;
            }
            ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );

            var ps2 = PathSearch.FromPoint( self.World, mobile.Info, mobile.toCell, target.Location, true );
            var ret = self.World.WorldActor.Trait<PathFinder>().FindBidiPath( ps1, ps2 );
            if( ret.Count > 0 )
                ret.RemoveAt( 0 );
            return Util.SequenceActivities( mobile.MoveTo( () => ret ), this );
        }
Beispiel #2
0
        public override Activity Tick( Actor self )
        {
            if( IsCanceled || !target.IsValid) return NextActivity;

            var mobile = self.Trait<Mobile>();

            var ps1 = new PathSearch( self.World, mobile.Info, self.Owner )
            {
                checkForBlocked = true,
                heuristic = location => 0,
                inReverse = true
            };

            foreach( var cell in Util.AdjacentCells(target) )
                if (cell == self.Location)
                    return NextActivity;
                else
                    ps1.AddInitialCell( cell );

            ps1.heuristic = PathSearch.DefaultEstimator( mobile.toCell );

            var ps2 = PathSearch.FromPoint( self.World, mobile.Info, self.Owner, mobile.toCell, Util.CellContaining(target.CenterLocation), true );
            var ret = self.World.WorldActor.Trait<PathFinder>().FindBidiPath( ps1, ps2 );

            return Util.SequenceActivities( mobile.MoveTo( () => ret ), this );
        }
Beispiel #3
0
        public static PathSearch FromPoint( World world, MobileInfo mi, int2 from, int2 target, bool checkForBlocked )
        {
            var search = new PathSearch(world, mi) {
                heuristic = DefaultEstimator( target ),
                checkForBlocked = checkForBlocked };

            search.AddInitialCell( from );
            return search;
        }
Beispiel #4
0
        const int MaxPathAge          = 50;     /* x 40ms ticks */

        public List <CPos> FindUnitPath(CPos from, CPos target, Actor self)
        {
            using (new PerfSample("Pathfinder"))
            {
                var cached = CachedPaths.FirstOrDefault(p => p.from == from && p.to == target && p.actor == self);
                if (cached != null)
                {
                    Log.Write("debug", "Actor {0} asked for a path from {1} tick(s) ago", self.ActorID, world.WorldTick - cached.tick);
                    if (world.WorldTick - cached.tick > MaxPathAge)
                    {
                        CachedPaths.Remove(cached);
                    }
                    return(new List <CPos>(cached.result));
                }

                var mi = self.Info.Traits.Get <MobileInfo>();

                // If a water-land transition is required, bail early
                var domainIndex = self.World.WorldActor.TraitOrDefault <DomainIndex>();
                if (domainIndex != null)
                {
                    var passable = mi.GetMovementClass(world.TileSet);
                    if (!domainIndex.IsPassable(from, target, (uint)passable))
                    {
                        return(emptyPath);
                    }
                }

                var pb = FindBidiPath(
                    PathSearch.FromPoint(world, mi, self, target, from, true),
                    PathSearch.FromPoint(world, mi, self, from, target, true).Reverse()
                    );

                CheckSanePath2(pb, from, target);

                CachedPaths.RemoveAll(p => world.WorldTick - p.tick > MaxPathAge);
                CachedPaths.Add(new CachedPath {
                    from = from, to = target, actor = self, result = pb, tick = world.WorldTick
                });
                return(new List <CPos>(pb));
            }
        }
Beispiel #5
0
        public List <CPos> FindUnitPathToRange(CPos src, SubCell srcSub, WPos target, WRange range, Actor self)
        {
            using (new PerfSample("Pathfinder"))
            {
                var mi           = self.Info.Traits.Get <MobileInfo>();
                var targetCell   = self.World.Map.CellContaining(target);
                var rangeSquared = range.Range * range.Range;

                // Correct for SubCell offset
                target -= MobileInfo.SubCellOffsets[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, self, t, null, true, true));

                // 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 = self.World.WorldActor.TraitOrDefault <DomainIndex>();
                if (domainIndex != null)
                {
                    var passable = mi.GetMovementClass(world.TileSet);
                    tilesInRange = new List <CPos>(tilesInRange.Where(t => domainIndex.IsPassable(src, t, (uint)passable)));
                    if (!tilesInRange.Any())
                    {
                        return(emptyPath);
                    }
                }

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

                return(path);
            }
        }
Beispiel #6
0
        public static PathSearch FromPoints(World world, MobileInfo mi, IEnumerable<int2> froms, int2 target, bool checkForBlocked)
        {
            var search = new PathSearch(world, mi)
            {
                heuristic = DefaultEstimator(target),
                checkForBlocked = checkForBlocked
            };

            foreach( var sl in froms )
                search.AddInitialCell( sl );

            return search;
        }
Beispiel #7
0
 public static PathSearch Search( World world, MobileInfo mi, bool checkForBlocked )
 {
     var search = new PathSearch(world, mi) {
         checkForBlocked = checkForBlocked };
     return search;
 }
Beispiel #8
0
        void UpdateInnerPath(Actor self)
        {
            var targetCells = Util.AdjacentCells(target);
            var searchCells = new List<CPos>();
            var loc = self.Location;

            foreach (var cell in targetCells)
                if (mobile.CanEnterCell(cell) && (domainIndex == null || domainIndex.IsPassable(loc, cell, movementClass)))
                    searchCells.Add(cell);

            if (searchCells.Any())
            {
                var ps1 = new PathSearch(self.World, mobile.Info, self)
                {
                    checkForBlocked = true,
                    heuristic = location => 0,
                    inReverse = true
                };

                foreach (var cell in searchCells)
                    ps1.AddInitialCell(cell);

                ps1.heuristic = PathSearch.DefaultEstimator(mobile.toCell);
                var ps2 = PathSearch.FromPoint(self.World, mobile.Info, self, mobile.toCell, targetPosition, true);
                var ret = pathFinder.FindBidiPath(ps1, ps2);

                inner = mobile.MoveTo(() => ret);
            }
        }