public SubCell GetAvailableSubCell(Actor self, CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, CellConditions check = CellConditions.All)
        {
            var cost = cellsCost[cell];

            if (cost == short.MaxValue)
            {
                return(SubCell.Invalid);
            }

            if (check.HasCellCondition(CellConditions.TransientActors))
            {
                Func <Actor, bool> checkTransient = otherActor => IsBlockedBy(self, otherActor, ignoreActor, 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 SubCell GetAvailableSubCell(
            World world, Actor self, CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, CellConditions check = CellConditions.All)
        {
            if (MovementCostForCell(world, cell) == int.MaxValue)
            {
                return(SubCell.Invalid);
            }

            if (check.HasCellCondition(CellConditions.TransientActors))
            {
                Func <Actor, bool> checkTransient = otherActor => IsBlockedBy(self, otherActor, ignoreActor, check);

                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 #3
0
        public bool CanMoveFreelyInto(Actor actor, CPos cell, SubCell subCell, Actor ignoreActor, CellConditions check)
        {
            var cellCache = GetCache(cell);
            var cellFlag  = cellCache.CellFlag;

            if (!check.HasCellCondition(CellConditions.TransientActors))
            {
                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);
            }

            // Cache doesn't account for ignored actors or temporary blockers - these must use the slow path.
            if (ignoreActor == null && !cellFlag.HasCellFlag(CellFlag.HasTemporaryBlocker))
            {
                // We are blocked by another actor in the cell.
                if (cellCache.Blocking.Overlaps(actor.Owner.PlayerMask))
                {
                    return(false);
                }

                if (check == CellConditions.BlockedByMovers && cellFlag < CellFlag.HasCrushableActor)
                {
                    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, check, cellFlag))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #4
0
        bool IsBlockedBy(Actor self, Actor otherActor, Actor ignoreActor, CellConditions check)
        {
            // We are not blocked by the actor we are ignoring.
            if (otherActor == ignoreActor)
            {
                return(false);
            }

            // If self is null, we don't have a real actor - 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 (self == null)
            {
                return(true);
            }

            // If the check allows: we are not blocked by allied units moving in our direction.
            if (!check.HasCellCondition(CellConditions.BlockedByMovers) &&
                self.Owner.Stances[otherActor.Owner] == Stance.Ally &&
                IsMovingInMyDirection(self, otherActor))
            {
                return(false);
            }

            // PERF: Only perform ITemporaryBlocker trait look-up if mod/map rules contain any actors that are temporary blockers
            if (self.World.RulesContainTemporaryBlocker)
            {
                // 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 (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, Crushes))
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #5
0
        bool IsBlockedBy(Actor self, Actor otherActor, Actor ignoreActor, CellConditions check, CellFlag cellFlag)
        {
            if (otherActor == ignoreActor)
            {
                return(false);
            }

            // If the check allows: we are not blocked by allied units moving in our direction.
            if (!check.HasCellCondition(CellConditions.BlockedByMovers) && cellFlag.HasCellFlag(CellFlag.HasMovingActor) &&
                self.Owner.Stances[otherActor.Owner] == Stance.Ally &&
                IsMovingInMyDirection(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 (!cellFlag.HasCellFlag(CellFlag.HasCrushableActor))
            {
                return(true);
            }

            // If we cannot crush the other actor in our way, we are blocked.
            if (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);
        }
		// Determines whether the actor is blocked by other Actors
		public bool CanMoveFreelyInto(World world, Actor self, CPos cell, Actor ignoreActor, CellConditions check)
		{
			if (!check.HasCellCondition(CellConditions.TransientActors))
				return true;

			if (SharesCell && world.ActorMap.HasFreeSubCell(cell))
				return true;

			// PERF: Avoid LINQ.
			foreach (var otherActor in world.ActorMap.GetActorsAt(cell))
				if (IsBlockedBy(self, otherActor, ignoreActor, check))
					return false;

			return true;
		}
Beispiel #7
0
        bool IsBlockedBy(Actor self, Actor otherActor, Actor ignoreActor, CellConditions check)
        {
            // We are not blocked by the actor we are ignoring.
            if (otherActor == ignoreActor)
            {
                return(false);
            }

            // If the check allows: we are not blocked by allied units moving in our direction.
            if (!check.HasCellCondition(CellConditions.BlockedByMovers) &&
                self != null &&
                self.Owner.Stances[otherActor.Owner] == Stance.Ally &&
                IsMovingInMyDirection(self, otherActor))
            {
                return(false);
            }

            // If we cannot crush the other actor in our way, we are blocked.
            if (self == null || Crushes == null || Crushes.Count == 0)
            {
                return(true);
            }

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

            foreach (var crushable in crushables)
            {
                lacksCrushability = false;
                if (!crushable.CrushableBy(Crushes, self.Owner))
                {
                    return(true);
                }
            }

            // If there are no crushable traits at all, this means the other actor cannot be crushed - we are blocked.
            if (lacksCrushability)
            {
                return(true);
            }

            // We are not blocked by the other actor.
            return(false);
        }
Beispiel #8
0
        // Determines whether the actor is blocked by other Actors
        public bool CanMoveFreelyInto(World world, Actor self, CPos cell, Actor ignoreActor, CellConditions check)
        {
            if (!check.HasCellCondition(CellConditions.TransientActors))
            {
                return(true);
            }

            if (SharesCell && world.ActorMap.HasFreeSubCell(cell))
            {
                return(true);
            }

            foreach (var otherActor in world.ActorMap.GetActorsAt(cell))
            {
                if (IsBlockedBy(self, otherActor, ignoreActor, check))
                {
                    return(false);
                }
            }

            return(true);
        }