Пример #1
0
        public bool CanEnterCell(World world, Actor self, CPos cell, out int movementCost, Actor ignoreActor = null, CellConditions check = CellConditions.All)
        {
            if ((movementCost = MovementCostForCell(world, cell)) == int.MaxValue)
            {
                return(false);
            }

            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);
        }
Пример #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.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));
        }