diff --git a/OpenRA.Mods.Common/AIUtils.cs b/OpenRA.Mods.Common/AIUtils.cs index 0f4e8dc522..09804b9330 100644 --- a/OpenRA.Mods.Common/AIUtils.cs +++ b/OpenRA.Mods.Common/AIUtils.cs @@ -79,5 +79,39 @@ namespace OpenRA.Mods.Common if (Game.Settings.Debug.BotDebug) TextNotificationsManager.Debug(format, args); } + + public static IEnumerable ClearBlockersOrders(IEnumerable tiles, Player owner, Actor ignoreActor = null) + { + var world = owner.World; + var adjacentTiles = Util.ExpandFootprint(tiles, true).Except(tiles) + .Where(world.Map.Contains).ToList(); + + var blockers = tiles.SelectMany(world.ActorMap.GetActorsAt) + .Where(a => a.Owner == owner && a.IsIdle && (ignoreActor == null || a != ignoreActor)) + .Select(a => new TraitPair(a, a.TraitOrDefault())) + .Where(x => x.Trait != null); + + foreach (var blocker in blockers) + { + CPos moveCell; + if (blocker.Trait is Mobile mobile) + { + var availableCells = adjacentTiles.Where(t => mobile.CanEnterCell(t)).ToList(); + if (availableCells.Count == 0) + continue; + + moveCell = blocker.Actor.ClosestCell(availableCells); + } + else if (blocker.Trait is Aircraft) + moveCell = blocker.Actor.Location; + else + continue; + + yield return new Order("Move", blocker.Actor, Target.FromCell(world, moveCell), false) + { + SuppressVisualFeedback = true + }; + } + } } } diff --git a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs index dea3ee3526..90151ed091 100644 --- a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs @@ -192,7 +192,7 @@ namespace OpenRA.Mods.Common.Orders if (!world.CanPlaceBuilding(topLeft, ai, bi, null) || !bi.IsCloseEnoughToBase(world, owner, ai, topLeft)) { - foreach (var order in ClearBlockersOrders(world, topLeft)) + foreach (var order in ClearBlockersOrders(topLeft)) yield return order; Game.Sound.PlayNotification(world.Map.Rules, owner, "Speech", notification, owner.Faction.InternalName); @@ -326,38 +326,9 @@ namespace OpenRA.Mods.Common.Orders void IOrderGenerator.Deactivate() { } - IEnumerable ClearBlockersOrders(World world, CPos topLeft) + IEnumerable ClearBlockersOrders(CPos topLeft) { - var allTiles = variants[variant].BuildingInfo.Tiles(topLeft).ToArray(); - var adjacentTiles = Util.ExpandFootprint(allTiles, true).Except(allTiles) - .Where(world.Map.Contains).ToList(); - - var blockers = allTiles.SelectMany(world.ActorMap.GetActorsAt) - .Where(a => a.Owner == Queue.Actor.Owner && a.IsIdle) - .Select(a => new TraitPair(a, a.TraitOrDefault())) - .Where(x => x.Trait != null); - - foreach (var blocker in blockers) - { - CPos moveCell; - if (blocker.Trait is Mobile mobile) - { - var availableCells = adjacentTiles.Where(t => mobile.CanEnterCell(t)).ToList(); - if (availableCells.Count == 0) - continue; - - moveCell = blocker.Actor.ClosestCell(availableCells); - } - else if (blocker.Trait is Aircraft) - moveCell = blocker.Actor.Location; - else - continue; - - yield return new Order("Move", blocker.Actor, Target.FromCell(world, moveCell), false) - { - SuppressVisualFeedback = true - }; - } + return AIUtils.ClearBlockersOrders(variants[variant].BuildingInfo.Tiles(topLeft).ToList(), Queue.Actor.Owner); } } } diff --git a/OpenRA.Mods.Common/Traits/Transforms.cs b/OpenRA.Mods.Common/Traits/Transforms.cs index 7d424542d2..f96ee6be5a 100644 --- a/OpenRA.Mods.Common/Traits/Transforms.cs +++ b/OpenRA.Mods.Common/Traits/Transforms.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; +using System.Linq; using OpenRA.Activities; using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Orders; @@ -97,6 +98,11 @@ namespace OpenRA.Mods.Common.Traits return buildingInfo == null || self.World.CanPlaceBuilding(self.Location + Info.Offset, actorInfo, buildingInfo, self); } + IEnumerable ClearBlockersOrders(CPos topLeft) + { + return AIUtils.ClearBlockersOrders(buildingInfo.Tiles(topLeft).ToList(), self.Owner, self); + } + public Activity GetTransformActivity() { return new Transform(Info.IntoActor) @@ -139,6 +145,9 @@ namespace OpenRA.Mods.Common.Traits { if (!queued && !CanDeploy()) { + foreach (var order in ClearBlockersOrders(self.Location + Info.Offset)) + self.World.IssueOrder(order); + // Only play the "Cannot deploy here" audio // for non-queued orders foreach (var s in Info.NoTransformSounds)