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); }
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)); }