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; }
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); }
// 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); }
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; }
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); }
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; }
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)); }
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)); }
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)); }
// 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)); }
public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All) { return(conditions(cell)); }
public static bool HasCellCondition(this CellConditions c, CellConditions cellCondition) { return((c & cellCondition) == cellCondition); }
// 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); }
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; }
// 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; }
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); }