Beispiel #1
0
        public SubCell GetAvailableSubCell(Actor self, CPos cell, BlockedByActor check, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null)
        {
            if (MovementCostForCell(cell) == short.MaxValue)
            {
                return(SubCell.Invalid);
            }

            if (check > BlockedByActor.None)
            {
                Func <Actor, bool> checkTransient = otherActor => IsBlockedBy(self, otherActor, ignoreActor, cell, check, GetCache(cell).CellFlag);

                if (!sharesCell)
                {
                    return(world.ActorMap.AnyActorsAt(cell, SubCell.FullCell, checkTransient) ? SubCell.Invalid : SubCell.FullCell);
                }

                return(world.ActorMap.FreeSubCell(cell, preferredSubCell, checkTransient));
            }

            if (!sharesCell)
            {
                return(world.ActorMap.AnyActorsAt(cell, SubCell.FullCell) ? SubCell.Invalid : SubCell.FullCell);
            }

            return(world.ActorMap.FreeSubCell(cell, preferredSubCell));
        }
Beispiel #2
0
        public PathGraph(CellInfoLayerPool layerPool, Locomotor locomotor, Actor actor, World world, BlockedByActor check,
                         Func <CPos, int> customCost, Actor ignoreActor, bool inReverse, bool laneBias)
        {
            customMovementLayers = world.GetCustomMovementLayers();
            customMovementLayersEnabledForLocomotor = customMovementLayers.Count(cml => cml != null && cml.EnabledForLocomotor(locomotor.Info));
            this.locomotor     = locomotor;
            this.world         = world;
            this.actor         = actor;
            this.check         = check;
            this.customCost    = customCost;
            this.ignoreActor   = ignoreActor;
            this.inReverse     = inReverse;
            this.laneBias      = laneBias;
            checkTerrainHeight = world.Map.Grid.MaximumTerrainHeight > 0;

            // As we support a search over the whole map area,
            // use the pool to grab the CellInfos we need to track the graph state.
            // This allows us to avoid the cost of allocating large arrays constantly.
            // PERF: Avoid LINQ
            pooledLayer         = layerPool.Get();
            cellInfoForLayer    = new CellLayer <CellInfo> [customMovementLayers.Length];
            cellInfoForLayer[0] = pooledLayer.GetLayer();
            foreach (var cml in customMovementLayers)
            {
                if (cml != null && cml.EnabledForLocomotor(locomotor.Info))
                {
                    cellInfoForLayer[cml.Index] = pooledLayer.GetLayer();
                }
            }
        }
Beispiel #3
0
        public PathGraph(CellInfoLayerPool layerPool, Locomotor locomotor, Actor actor, World world, BlockedByActor check)
        {
            this.locomotor = locomotor;

            // As we support a search over the whole map area,
            // use the pool to grab the CellInfos we need to track the graph state.
            // This allows us to avoid the cost of allocating large arrays constantly.
            // PERF: Avoid LINQ
            var cmls = world.GetCustomMovementLayers();

            pooledLayer         = layerPool.Get();
            cellInfoForLayer    = new CellLayer <CellInfo> [cmls.Length];
            cellInfoForLayer[0] = pooledLayer.GetLayer();
            foreach (var cml in cmls)
            {
                if (cml != null && cml.EnabledForLocomotor(locomotor.Info))
                {
                    cellInfoForLayer[cml.Index] = pooledLayer.GetLayer();
                }
            }

            World              = world;
            Actor              = actor;
            LaneBias           = 1;
            checkConditions    = check;
            checkTerrainHeight = world.Map.Grid.MaximumTerrainHeight > 0;
        }
Beispiel #4
0
        List <CPos> EvalPath(BlockedByActor check)
        {
            var path = getPath(check).TakeWhile(a => a != mobile.ToCell).ToList();

            mobile.PathHash = HashList(path);
            return(path);
        }
Beispiel #5
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 #6
0
 public static PathSearch ToTargetCell(
     World world, Locomotor locomotor, Actor self, CPos from, CPos target, BlockedByActor check,
     Func <CPos, int> customCost = null,
     Actor ignoreActor           = null,
     bool inReverse = false,
     bool laneBias  = DefaultLaneBias)
 {
     return(ToTargetCell(world, locomotor, self, new[] { from }, target, check, customCost, ignoreActor, inReverse, laneBias));
 }
Beispiel #7
0
        bool IsBlockedBy(Actor self, Actor otherActor, Actor ignoreActor, BlockedByActor check, CellFlag cellFlag)
        {
            if (otherActor == ignoreActor)
            {
                return(false);
            }

            // If the check allows: We are not blocked by units that we can force to move out of the way.
            if (check <= BlockedByActor.Immovable && cellFlag.HasCellFlag(CellFlag.HasMovableActor) &&
                self.Owner.Stances[otherActor.Owner] == Stance.Ally)
            {
                var mobile = otherActor.TraitOrDefault <Mobile>();
                if (mobile != null && !mobile.IsTraitDisabled && !mobile.IsTraitPaused && !mobile.IsImmovable)
                {
                    return(false);
                }
            }

            // If the check allows: we are not blocked by moving units.
            if (check <= BlockedByActor.Stationary && cellFlag.HasCellFlag(CellFlag.HasMovingActor) &&
                IsMoving(self, otherActor))
            {
                return(false);
            }

            if (cellFlag.HasCellFlag(CellFlag.HasTemporaryBlocker))
            {
                // If there is a temporary blocker in our path, but we can remove it, we are not blocked.
                var temporaryBlocker = otherActor.TraitOrDefault <ITemporaryBlocker>();
                if (temporaryBlocker != null && temporaryBlocker.CanRemoveBlockage(otherActor, self))
                {
                    return(false);
                }
            }

            // If we cannot crush the other actor in our way, we are blocked.
            if (!cellFlag.HasCellFlag(CellFlag.HasCrushableActor) || Info.Crushes.IsEmpty)
            {
                return(true);
            }

            // If the other actor in our way cannot be crushed, we are blocked.
            // PERF: Avoid LINQ.
            var crushables = otherActor.TraitsImplementing <ICrushable>();

            foreach (var crushable in crushables)
            {
                if (crushable.CrushableBy(otherActor, self, Info.Crushes))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #8
0
        /// <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());
        }
 protected DensePathGraph(Locomotor locomotor, Actor actor, World world, BlockedByActor check,
                          Func <CPos, int> customCost, Actor ignoreActor, bool laneBias, bool inReverse)
 {
     CustomMovementLayers = world.GetCustomMovementLayers();
     customMovementLayersEnabledForLocomotor = CustomMovementLayers.Count(cml => cml != null && cml.EnabledForLocomotor(locomotor.Info));
     this.locomotor     = locomotor;
     this.world         = world;
     this.actor         = actor;
     this.check         = check;
     this.customCost    = customCost;
     this.ignoreActor   = ignoreActor;
     this.laneBias      = laneBias;
     this.inReverse     = inReverse;
     checkTerrainHeight = world.Map.Grid.MaximumTerrainHeight > 0;
 }
Beispiel #10
0
        public bool CanUnload(BlockedByActor check = BlockedByActor.None)
        {
            if (checkTerrainType)
            {
                var terrainType = self.World.Map.GetTerrainInfo(self.Location).Type;

                if (!Info.UnloadTerrainTypes.Contains(terrainType))
                {
                    return(false);
                }
            }

            return(!IsEmpty(self) && (aircraft == null || aircraft.CanLand(self.Location, blockedByMobile: false)) &&
                   CurrentAdjacentCells != null && CurrentAdjacentCells.Any(c => Passengers.Any(p => !p.IsDead && p.Trait <IPositionable>().CanEnterCell(c, null, check))));
        }
Beispiel #11
0
        public short MovementCostToEnterCell(Actor actor, CPos destNode, BlockedByActor check, Actor ignoreActor)
        {
            if (!world.Map.Contains(destNode))
            {
                return(short.MaxValue);
            }

            var cellCost = destNode.Layer == 0 ? cellsCost[destNode] : customLayerCellsCost[destNode.Layer][destNode];

            if (cellCost == short.MaxValue ||
                !CanMoveFreelyInto(actor, destNode, check, ignoreActor))
            {
                return(short.MaxValue);
            }

            return(cellCost);
        }
Beispiel #12
0
        public PathGraph(CellInfoLayerPool layerPool, Locomotor locomotor, Actor actor, World world, BlockedByActor check)
        {
            pooledLayer = layerPool.Get();
            groundInfo  = pooledLayer.GetLayer();
            var locomotorInfo = locomotor.Info;

            this.locomotor = locomotor;
            var layers = world.GetCustomMovementLayers().Values
                         .Where(cml => cml.EnabledForActor(actor.Info, locomotorInfo));

            foreach (var cml in layers)
            {
                customLayerInfo[cml.Index] = Pair.New(cml, pooledLayer.GetLayer());
            }

            World              = world;
            worldMovementInfo  = locomotorInfo.GetWorldMovementInfo(world);
            Actor              = actor;
            LaneBias           = 1;
            checkConditions    = check;
            checkTerrainHeight = world.Map.Grid.MaximumTerrainHeight > 0;
        }
Beispiel #13
0
        List <CPos> CalculatePathToTarget(Actor self, BlockedByActor check)
        {
            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.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 #14
0
        public static IPathSearch Search(World world, Locomotor locomotor, Actor self, BlockedByActor check, Func <CPos, bool> goalCondition)
        {
            var graph  = new PathGraph(LayerPoolForWorld(world), locomotor, self, world, check);
            var search = new PathSearch(graph);

            search.isGoal    = goalCondition;
            search.heuristic = loc => 0;
            return(search);
        }
Beispiel #15
0
        public bool CanMoveFreelyInto(Actor actor, CPos cell, SubCell subCell, BlockedByActor check, Actor ignoreActor)
        {
            var cellCache = GetCache(cell);
            var cellFlag  = cellCache.CellFlag;

            // If the check allows: We are not blocked by transient actors.
            if (check == BlockedByActor.None)
            {
                return(true);
            }

            // No actor in the cell or free SubCell.
            if (cellFlag == CellFlag.HasFreeSpace)
            {
                return(true);
            }

            // If actor is null we're just checking what would happen theoretically.
            // In such a scenario - we'll just assume any other actor in the cell will block us by default.
            // If we have a real actor, we can then perform the extra checks that allow us to avoid being blocked.
            if (actor == null)
            {
                return(false);
            }

            // All actors that may be in the cell can be crushed.
            if (cellCache.Crushable.Overlaps(actor.Owner.PlayerMask))
            {
                return(true);
            }

            // If the check allows: We are not blocked by moving units.
            if (check <= BlockedByActor.Stationary && !cellFlag.HasCellFlag(CellFlag.HasStationaryActor))
            {
                return(true);
            }

            // If the check allows: We are not blocked by units that we can force to move out of the way.
            if (check <= BlockedByActor.Immovable && !cellCache.Immovable.Overlaps(actor.Owner.PlayerMask))
            {
                return(true);
            }

            // Cache doesn't account for ignored actors, temporary blockers, or subcells - these must use the slow path.
            if (ignoreActor == null && !cellFlag.HasCellFlag(CellFlag.HasTemporaryBlocker) && subCell == SubCell.FullCell)
            {
                // We already know there are uncrushable actors in the cell so we are always blocked.
                if (check == BlockedByActor.All)
                {
                    return(false);
                }

                // We already know there are either immovable or stationary actors which the check does not allow.
                if (!cellFlag.HasCellFlag(CellFlag.HasCrushableActor))
                {
                    return(false);
                }

                // All actors in the cell are immovable and some cannot be crushed.
                if (!cellFlag.HasCellFlag(CellFlag.HasMovableActor))
                {
                    return(false);
                }

                // All actors in the cell are stationary and some cannot be crushed.
                if (check == BlockedByActor.Stationary && !cellFlag.HasCellFlag(CellFlag.HasMovingActor))
                {
                    return(false);
                }
            }

            var otherActors = subCell == SubCell.FullCell ? world.ActorMap.GetActorsAt(cell) : world.ActorMap.GetActorsAt(cell, subCell);

            foreach (var otherActor in otherActors)
            {
                if (IsBlockedBy(actor, otherActor, ignoreActor, cell, check, cellFlag))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #16
0
 // Determines whether the actor is blocked by other Actors
 public bool CanMoveFreelyInto(Actor actor, CPos cell, BlockedByActor check, Actor ignoreActor)
 {
     return(CanMoveFreelyInto(actor, cell, SubCell.FullCell, check, ignoreActor));
 }
Beispiel #17
0
 public SubCell GetAvailableSubCell(CPos a, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // Does not use any subcell
     return(SubCell.Invalid);
 }
Beispiel #18
0
        /// <summary>
        /// Note: If the target <paramref name="cell"/> has any free subcell, the value of <paramref name="subCell"/> is ignored.
        /// </summary>
        public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
        {
            // PERF: Avoid repeated trait queries on the hot path
            if (locomotor == null)
            {
                locomotor = world.WorldActor.TraitsImplementing <Locomotor>()
                            .SingleOrDefault(l => l.Info.Name == Locomotor);
            }

            if (locomotor.MovementCostForCell(cell) == PathGraph.MovementCostForUnreachableCell)
            {
                return(false);
            }

            return(locomotor.CanMoveFreelyInto(self, cell, subCell, check, ignoreActor));
        }
Beispiel #19
0
        public static IPathSearch FromPoints(World world, Locomotor locomotor, Actor self, IEnumerable <CPos> froms, CPos target, BlockedByActor check)
        {
            var graph  = new PathGraph(LayerPoolForWorld(world), locomotor, self, world, check);
            var search = new PathSearch(graph);

            search.heuristic = search.DefaultEstimator(target);

            // The search will aim for the shortest path by default, a weight of 100%.
            // We can allow the search to find paths that aren't optimal by changing the weight.
            // We provide a weight that limits the worst case length of the path,
            // e.g. a weight of 110% will find a path no more than 10% longer than the shortest possible.
            // The benefit of allowing the search to return suboptimal paths is faster computation time.
            // The search can skip some areas of the search space, meaning it has less work to do.
            // We allow paths up to 25% longer than the shortest, optimal path, to improve pathfinding time.
            search.heuristicWeightPercentage = 125;

            search.isGoal = loc =>
            {
                var locInfo = search.Graph[loc];
                return(locInfo.EstimatedTotal - locInfo.CostSoFar == 0);
            };

            foreach (var sl in froms)
            {
                if (world.Map.Contains(sl))
                {
                    search.AddInitialCell(sl);
                }
            }

            return(search);
        }
Beispiel #20
0
        bool IsBlockedBy(Actor actor, Actor otherActor, Actor ignoreActor, CPos cell, BlockedByActor check, CellFlag cellFlag)
        {
            if (otherActor == ignoreActor)
            {
                return(false);
            }

            // If the check allows: We are not blocked by units that we can force to move out of the way.
            if (check <= BlockedByActor.Immovable && cellFlag.HasCellFlag(CellFlag.HasMovableActor) &&
                actor.Owner.RelationshipWith(otherActor.Owner) == PlayerRelationship.Ally)
            {
                var mobile = otherActor.OccupiesSpace as Mobile;
                if (mobile != null && !mobile.IsTraitDisabled && !mobile.IsTraitPaused && !mobile.IsImmovable)
                {
                    return(false);
                }
            }

            // If the check allows: we are not blocked by moving units.
            if (check <= BlockedByActor.Stationary && cellFlag.HasCellFlag(CellFlag.HasMovingActor) &&
                IsMoving(actor, otherActor))
            {
                return(false);
            }

            if (cellFlag.HasCellFlag(CellFlag.HasTemporaryBlocker))
            {
                // If there is a temporary blocker in our path, but we can remove it, we are not blocked.
                var temporaryBlocker = otherActor.TraitOrDefault <ITemporaryBlocker>();
                if (temporaryBlocker != null && temporaryBlocker.CanRemoveBlockage(otherActor, actor))
                {
                    return(false);
                }
            }

            if (cellFlag.HasCellFlag(CellFlag.HasTransitOnlyActor))
            {
                // Transit only tiles should not block movement
                var building = otherActor.OccupiesSpace as Building;
                if (building != null && building.TransitOnlyCells().Contains(cell))
                {
                    return(false);
                }
            }

            // If we cannot crush the other actor in our way, we are blocked.
            if (!cellFlag.HasCellFlag(CellFlag.HasCrushableActor) || Info.Crushes.IsEmpty)
            {
                return(true);
            }

            // If the other actor in our way cannot be crushed, we are blocked.
            // PERF: Avoid LINQ.
            var crushables = otherActor.TraitsImplementing <ICrushable>();

            foreach (var crushable in crushables)
            {
                if (crushable.CrushableBy(otherActor, actor, Info.Crushes))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #21
0
 public MapPathGraph(CellInfoLayerPool layerPool, Locomotor locomotor, Actor actor, World world, BlockedByActor check,
                     Func <CPos, int> customCost, Actor ignoreActor, bool laneBias, bool inReverse)
     : base(locomotor, actor, world, check, customCost, ignoreActor, laneBias, inReverse)
 {
     // As we support a search over the whole map area,
     // use the pool to grab the CellInfos we need to track the graph state.
     // This allows us to avoid the cost of allocating large arrays constantly.
     // PERF: Avoid LINQ
     pooledLayer         = layerPool.Get();
     cellInfoForLayer    = new CellLayer <CellInfo> [CustomMovementLayers.Length];
     cellInfoForLayer[0] = pooledLayer.GetLayer();
     foreach (var cml in CustomMovementLayers)
     {
         if (cml != null && cml.EnabledForLocomotor(locomotor.Info))
         {
             cellInfoForLayer[cml.Index] = pooledLayer.GetLayer();
         }
     }
 }
Beispiel #22
0
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // Since crates don't share cells and GetAvailableSubCell only returns SubCell.Full or SubCell.Invalid, we ignore the subCell parameter
     return(GetAvailableSubCell(world, cell, ignoreActor, check) != SubCell.Invalid);
 }
Beispiel #23
0
 public static IPathSearch FromPoint(World world, Locomotor locomotor, Actor self, CPos @from, CPos target, BlockedByActor check)
 {
     return(FromPoints(world, locomotor, self, new[] { from }, target, check));
 }
Beispiel #24
0
        public SubCell GetAvailableSubCell(World world, CPos cell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
        {
            if (!CanExistInCell(world, cell))
            {
                return(SubCell.Invalid);
            }

            if (world.WorldActor.Trait <BuildingInfluence>().GetBuildingAt(cell) != null)
            {
                return(SubCell.Invalid);
            }

            if (check == BlockedByActor.None)
            {
                return(SubCell.FullCell);
            }

            return(!world.ActorMap.GetActorsAt(cell).Any(x => x != ignoreActor)
                                ? SubCell.FullCell : SubCell.Invalid);
        }
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // SBMs may not land.
     return(false);
 }
Beispiel #26
0
        public SubCell GetAvailableSubCell(CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
        {
            if (!CanExistInCell(cell))
            {
                return(SubCell.Invalid);
            }

            if (check == BlockedByActor.None)
            {
                return(SubCell.FullCell);
            }

            return(self.World.ActorMap.GetActorsAt(cell)
                   .All(x => x == ignoreActor) ? SubCell.FullCell : SubCell.Invalid);
        }
Beispiel #27
0
 public bool CanEnterCell(CPos cell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     return(true);
 }
Beispiel #28
0
 public bool CanEnterCell(CPos a, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     return(GetAvailableSubCell(a, SubCell.Any, ignoreActor, check) != SubCell.Invalid);
 }
Beispiel #29
0
 // Used to determine if actor can spawn
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     return(world.Map.Contains(cell));
 }
Beispiel #30
0
 public bool CanEnterCell(World world, Actor self, CPos cell, SubCell subCell = SubCell.FullCell, Actor ignoreActor = null, BlockedByActor check = BlockedByActor.All)
 {
     // IPositionable*Info*.CanEnterCell is only ever used for things like exiting production facilities,
     // all places relevant for husks check IPositionable.CanEnterCell instead, so we can safely set this to true.
     return(true);
 }