diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 2d59e8808c..a3e242d3b3 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -265,7 +265,11 @@ namespace OpenRA.Traits [RequireExplicitImplementation] public interface ISelectionBar { float GetValue(); Color GetColor(); bool DisplayWhenEmpty { get; } } - public interface IPositionableInfo : ITraitInfoInterface { } + public interface IPositionableInfo : ITraitInfoInterface + { + bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true); + } + public interface IPositionable : IOccupySpace { bool IsLeavingCell(CPos location, SubCell subCell = SubCell.Any); diff --git a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs index a345723198..240037e077 100644 --- a/OpenRA.Mods.Common/Traits/Air/Aircraft.cs +++ b/OpenRA.Mods.Common/Traits/Air/Aircraft.cs @@ -94,6 +94,25 @@ namespace OpenRA.Mods.Common.Traits public IReadOnlyDictionary OccupiedCells(ActorInfo info, CPos location, SubCell subCell = SubCell.Any) { return new ReadOnlyDictionary(); } bool IOccupySpaceInfo.SharesCell { get { return false; } } + + // Used to determine if an aircraft can spawn landed + public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) + { + if (!world.Map.Contains(cell)) + return false; + + var type = world.Map.GetTerrainInfo(cell).Type; + if (!LandableTerrainTypes.Contains(type)) + return false; + + if (world.WorldActor.Trait().GetBuildingAt(cell) != null) + return false; + + if (!checkTransientActors) + return true; + + return !world.ActorMap.GetActorsAt(cell).Any(x => x != ignoreActor); + } } public class Aircraft : ITick, ISync, IFacing, IPositionable, IMove, IIssueOrder, IResolveOrder, IOrderVoice, IDeathActorInitModifier, diff --git a/OpenRA.Mods.Common/Traits/Crates/Crate.cs b/OpenRA.Mods.Common/Traits/Crates/Crate.cs index 596957d364..e8c04e25f6 100644 --- a/OpenRA.Mods.Common/Traits/Crates/Crate.cs +++ b/OpenRA.Mods.Common/Traits/Crates/Crate.cs @@ -38,6 +38,30 @@ namespace OpenRA.Mods.Common.Traits } bool IOccupySpaceInfo.SharesCell { get { return false; } } + + public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) + { + return GetAvailableSubCell(world, cell, ignoreActor, checkTransientActors) != SubCell.Invalid; + } + + public SubCell GetAvailableSubCell(World world, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) + { + if (!world.Map.Contains(cell)) + return SubCell.Invalid; + + var type = world.Map.GetTerrainInfo(cell).Type; + if (!TerrainTypes.Contains(type)) + return SubCell.Invalid; + + if (world.WorldActor.Trait().GetBuildingAt(cell) != null) + return SubCell.Invalid; + + if (!checkTransientActors) + return SubCell.FullCell; + + return !world.ActorMap.GetActorsAt(cell).Any(x => x != ignoreActor) + ? SubCell.FullCell : SubCell.Invalid; + } } class Crate : ITick, IPositionable, ICrushable, ISync, @@ -174,22 +198,7 @@ namespace OpenRA.Mods.Common.Traits public SubCell GetValidSubCell(SubCell preferred = SubCell.Any) { return SubCell.FullCell; } public SubCell GetAvailableSubCell(CPos cell, SubCell preferredSubCell = SubCell.Any, Actor ignoreActor = null, bool checkTransientActors = true) { - if (!self.World.Map.Contains(cell)) - return SubCell.Invalid; - - var type = self.World.Map.GetTerrainInfo(cell).Type; - if (!info.TerrainTypes.Contains(type)) - return SubCell.Invalid; - - if (self.World.WorldActor.Trait().GetBuildingAt(cell) != null) - return SubCell.Invalid; - - if (!checkTransientActors) - return SubCell.FullCell; - - return !self.World.ActorMap.GetActorsAt(cell) - .Any(x => x != ignoreActor) - ? SubCell.FullCell : SubCell.Invalid; + return info.GetAvailableSubCell(self.World, cell, ignoreActor, checkTransientActors); } public bool CanEnterCell(CPos a, Actor ignoreActor = null, bool checkTransientActors = true) diff --git a/OpenRA.Mods.Common/Traits/Crates/GiveUnitCrateAction.cs b/OpenRA.Mods.Common/Traits/Crates/GiveUnitCrateAction.cs index 7c6985d5a7..5b50971f8b 100644 --- a/OpenRA.Mods.Common/Traits/Crates/GiveUnitCrateAction.cs +++ b/OpenRA.Mods.Common/Traits/Crates/GiveUnitCrateAction.cs @@ -97,11 +97,11 @@ namespace OpenRA.Mods.Common.Traits IEnumerable GetSuitableCells(CPos near, string unitName) { - var mi = self.World.Map.Rules.Actors[unitName].TraitInfo(); + var ip = self.World.Map.Rules.Actors[unitName].TraitInfo(); for (var i = -1; i < 2; i++) for (var j = -1; j < 2; j++) - if (mi.CanEnterCell(self.World, self, near + new CVec(i, j))) + if (ip.CanEnterCell(self.World, self, near + new CVec(i, j))) yield return near + new CVec(i, j); } diff --git a/OpenRA.Mods.Common/Traits/Mobile.cs b/OpenRA.Mods.Common/Traits/Mobile.cs index fba438ae69..4e8fdd4b22 100644 --- a/OpenRA.Mods.Common/Traits/Mobile.cs +++ b/OpenRA.Mods.Common/Traits/Mobile.cs @@ -263,11 +263,12 @@ namespace OpenRA.Mods.Common.Traits (current, terrainInfo) => unchecked(current * 31 + terrainInfo.Cost)); } - public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, CellConditions check = CellConditions.All) + public bool CanEnterCell(World world, Actor self, CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) { if (MovementCostForCell(world, cell) == int.MaxValue) return false; + var check = checkTransientActors ? CellConditions.All : CellConditions.BlockedByMovers; return CanMoveFreelyInto(world, self, cell, ignoreActor, check); } @@ -699,7 +700,7 @@ namespace OpenRA.Mods.Common.Traits public bool CanEnterCell(CPos cell, Actor ignoreActor = null, bool checkTransientActors = true) { - return Info.CanEnterCell(self.World, self, cell, ignoreActor, checkTransientActors ? CellConditions.All : CellConditions.BlockedByMovers); + return Info.CanEnterCell(self.World, self, cell, ignoreActor, checkTransientActors); } public bool CanMoveFreelyInto(CPos cell, Actor ignoreActor = null, bool checkTransientActors = true)