From 02be188d14d409daf2fc9956fe452599e17daaf6 Mon Sep 17 00:00:00 2001 From: Pavel Penev Date: Thu, 3 Sep 2015 12:47:36 +0300 Subject: [PATCH 1/2] Add ActorExts.ClosestCell() --- OpenRA.Mods.Common/ActorExts.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenRA.Mods.Common/ActorExts.cs b/OpenRA.Mods.Common/ActorExts.cs index 3d3633758c..651a2ba6f3 100644 --- a/OpenRA.Mods.Common/ActorExts.cs +++ b/OpenRA.Mods.Common/ActorExts.cs @@ -118,7 +118,8 @@ namespace OpenRA.Mods.Common NotifyBlocker(self, positions.SelectMany(p => self.World.ActorMap.GetUnitsAt(p))); } - public static bool CanHarvestAt(this Actor self, CPos pos, ResourceLayer resLayer, HarvesterInfo harvInfo, ResourceClaimLayer territory) + public static bool CanHarvestAt(this Actor self, CPos pos, ResourceLayer resLayer, HarvesterInfo harvInfo, + ResourceClaimLayer territory) { var resType = resLayer.GetResource(pos); if (resType == null) @@ -138,5 +139,10 @@ namespace OpenRA.Mods.Common return true; } + + public static CPos ClosestCell(this Actor self, IEnumerable cells) + { + return cells.MinByOrDefault(c => (self.Location - c).LengthSquared); + } } } From f942ab13891205fb436fc5ae90e680512f79f4aa Mon Sep 17 00:00:00 2001 From: Pavel Penev Date: Thu, 3 Sep 2015 13:06:07 +0300 Subject: [PATCH 2/2] Move any mobile actors that block the building's desired footprint when placing a building --- .../Orders/PlaceBuildingOrderGenerator.cs | 35 ++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs index b6ab928991..9ca77e0e82 100644 --- a/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRA.Mods.Common/Orders/PlaceBuildingOrderGenerator.cs @@ -12,9 +12,12 @@ using System; using System.Collections.Generic; using System.Linq; using OpenRA.Graphics; +using OpenRA.Mods.Common.Activities; using OpenRA.Mods.Common.Graphics; using OpenRA.Mods.Common.Traits; using OpenRA.Primitives; +using OpenRA.Traits; +using Util = OpenRA.Traits.Util; namespace OpenRA.Mods.Common.Orders { @@ -65,7 +68,11 @@ namespace OpenRA.Mods.Common.Orders world.CancelInputMode(); var ret = InnerOrder(world, xy, mi).ToArray(); - if (ret.Length > 0) + + // If there was a successful placement order + if (ret.Any(o => o.OrderString == "PlaceBuilding" + || o.OrderString == "LineBuild" + || o.OrderString == "PlacePlug")) world.CancelInputMode(); return ret; @@ -96,6 +103,9 @@ namespace OpenRA.Mods.Common.Orders if (!world.CanPlaceBuilding(building, buildingInfo, topLeft, null) || !buildingInfo.IsCloseEnoughToBase(world, producer.Owner, building, topLeft)) { + foreach (var order in ClearBlockersOrders(world, topLeft)) + yield return order; + Game.Sound.PlayNotification(world.Map.Rules, producer.Owner, "Speech", "BuildingCannotPlaceAudio", producer.Owner.Faction.InternalName); yield break; } @@ -210,5 +220,28 @@ namespace OpenRA.Mods.Common.Orders } public string GetCursor(World world, CPos xy, MouseInput mi) { return "default"; } + + IEnumerable ClearBlockersOrders(World world, CPos topLeft) + { + var allTiles = FootprintUtils.Tiles(world.Map.Rules, building, buildingInfo, topLeft).ToArray(); + var neightborTiles = Util.ExpandFootprint(allTiles, true).Except(allTiles) + .Where(world.Map.Contains).ToList(); + + var blockers = allTiles.SelectMany(world.ActorMap.GetUnitsAt) + .Where(a => a.Owner == producer.Owner && a.IsIdle) + .Select(a => new TraitPair { Actor = a, Trait = a.TraitOrDefault() }); + + foreach (var blocker in blockers.Where(x => x.Trait != null)) + { + var availableCells = neightborTiles.Where(t => blocker.Trait.CanEnterCell(t)).ToList(); + if (availableCells.Count == 0) + continue; + + yield return new Order("Move", blocker.Actor, false) + { + TargetLocation = blocker.Actor.ClosestCell(availableCells) + }; + } + } } }