Ejemplo n.º 1
0
 public PathGraph(CellLayer <CellInfo> cellInfo, MobileInfo mobileInfo, Actor actor, World world, bool checkForBlocked)
 {
     this.cellInfo   = cellInfo;
     World           = world;
     this.mobileInfo = mobileInfo;
     Actor           = actor;
     LaneBias        = 1;
     checkConditions = checkForBlocked ? CellConditions.TransientActors : CellConditions.None;
 }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
0
        // Determines whether the actor is blocked by other Actors
        public bool CanMoveFreelyInto(Actor actor, CPos cell, 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);
                }
            }

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

            return(true);
        }
Ejemplo n.º 4
0
 public PathGraph(CellInfoLayerPool layerPool, MobileInfo mobileInfo, Actor actor, World world, bool checkForBlocked)
 {
     pooledLayer       = layerPool.Get();
     cellInfo          = pooledLayer.Layer;
     World             = world;
     this.mobileInfo   = mobileInfo;
     worldMovementInfo = mobileInfo.GetWorldMovementInfo(world);
     Actor             = actor;
     LaneBias          = 1;
     checkConditions   = checkForBlocked ? CellConditions.TransientActors : CellConditions.None;
 }
Ejemplo n.º 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);
        }
Ejemplo n.º 6
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);
        }
        public PathGraph(CellInfoLayerPool layerPool, LocomotorInfo li, Actor actor, World world, bool checkForBlocked)
        {
            pooledLayer   = layerPool.Get();
            groundInfo    = pooledLayer.GetLayer();
            locomotorInfo = li;
            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    = checkForBlocked ? CellConditions.TransientActors : CellConditions.None;
            checkTerrainHeight = world.Map.Grid.MaximumTerrainHeight > 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);
		}
		public int MovementCostToEnterCell(WorldMovementInfo worldMovementInfo, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All)
		{
			var cost = MovementCostForCell(worldMovementInfo.World, worldMovementInfo.TerrainInfos, cell);
			if (cost == int.MaxValue || !CanMoveFreelyInto(worldMovementInfo.World, self, cell, ignoreActor, check))
				return int.MaxValue;
			return cost;
		}
Ejemplo n.º 10
0
 public bool CanEnterCell(World world, Actor self, CPos cell, out int movementCost, Actor ignoreActor = null, CellConditions check = CellConditions.All)
 {
     movementCost = MovementCostForCell(world, cell);
     return(conditions(cell));
 }
Ejemplo n.º 11
0
        public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All)
        {
            if (MovementCostForCell(world, cell) == int.MaxValue)
            {
                return(false);
            }

            return(CanMoveFreelyInto(world, self, cell, ignoreActor, check));
        }
Ejemplo n.º 12
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.HasFlag(CellConditions.TransientActors))
            {
                var canIgnoreMovingAllies = self != null && !check.HasFlag(CellConditions.BlockedByMovers);
                var needsCellExclusively  = self == null || Crushes == null || !Crushes.Any();

                Func <Actor, bool> checkTransient = a =>
                {
                    if (a == ignoreActor)
                    {
                        return(false);
                    }

                    // Neutral/enemy units are blockers. Allied units that are moving are not blockers.
                    if (canIgnoreMovingAllies && self.Owner.Stances[a.Owner] == Stance.Ally && IsMovingInMyDirection(self, a))
                    {
                        return(false);
                    }

                    // Non-sharable unit can enter a cell with shareable units only if it can crush all of them.
                    if (needsCellExclusively)
                    {
                        return(true);
                    }
                    var crushables = a.TraitsImplementing <ICrushable>();
                    if (!crushables.Any())
                    {
                        return(true);
                    }
                    foreach (var crushable in crushables)
                    {
                        if (!crushable.CrushableBy(Crushes, self.Owner))
                        {
                            return(true);
                        }
                    }

                    return(false);
                };

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

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

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

            return(world.ActorMap.FreeSubCell(cell, preferredSubCell));
        }
Ejemplo n.º 13
0
 // Determines whether the actor is blocked by other Actors
 public bool CanMoveFreelyInto(Actor actor, CPos cell, Actor ignoreActor, CellConditions check)
 {
     return(CanMoveFreelyInto(actor, cell, SubCell.FullCell, ignoreActor, check));
 }
Ejemplo n.º 14
0
 public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All)
 {
     return(conditions(cell));
 }
Ejemplo n.º 15
0
 public static bool HasCellCondition(this CellConditions c, CellConditions cellCondition)
 {
     return((c & cellCondition) == cellCondition);
 }
Ejemplo n.º 16
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);
        }
Ejemplo n.º 17
0
        public SubCell GetAvailableSubCell(Actor self, CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, CellConditions check = CellConditions.All)
        {
            if (MovementCostForCell(cell) == 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));
        }
		// 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;
		}
Ejemplo n.º 19
0
        // Determines whether the actor is blocked by other Actors
        public bool CanMoveFreelyInto(World world, Actor self, CPos cell, Actor ignoreActor, CellConditions check)
        {
            if (SharesCell && world.ActorMap.HasFreeSubCell(cell))
            {
                return(true);
            }

            if (check.HasFlag(CellConditions.TransientActors))
            {
                var canIgnoreMovingAllies = self != null && !check.HasFlag(CellConditions.BlockedByMovers);
                var needsCellExclusively  = self == null || Crushes == null || !Crushes.Any();
                foreach (var a in world.ActorMap.GetUnitsAt(cell))
                {
                    if (a == ignoreActor)
                    {
                        continue;
                    }

                    // Neutral/enemy units are blockers. Allied units that are moving are not blockers.
                    if (canIgnoreMovingAllies && self.Owner.Stances[a.Owner] == Stance.Ally && IsMovingInMyDirection(self, a))
                    {
                        continue;
                    }

                    // Non-sharable unit can enter a cell with shareable units only if it can crush all of them.
                    if (needsCellExclusively)
                    {
                        return(false);
                    }
                    var crushables = a.TraitsImplementing <ICrushable>();
                    if (!crushables.Any())
                    {
                        return(false);
                    }
                    foreach (var crushable in crushables)
                    {
                        if (!crushable.CrushableBy(Crushes, self.Owner))
                        {
                            return(false);
                        }
                    }
                }
            }

            return(true);
        }
		public static bool HasCellCondition(this CellConditions c, CellConditions cellCondition)
		{
			// PERF: Enum.HasFlag is slower and requires allocations.
			return (c & cellCondition) == cellCondition;
		}
Ejemplo n.º 21
0
        public short MovementCostToEnterCell(Actor actor, CPos destNode, Actor ignoreActor, CellConditions check)
        {
            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, ignoreActor, check))
            {
                return(short.MaxValue);
            }

            return(cellCost);
        }