diff --git a/OpenRA.Mods.Common/Traits/Buildings/Building.cs b/OpenRA.Mods.Common/Traits/Buildings/Building.cs index 354b6d10cc..53cf7fdca0 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/Building.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/Building.cs @@ -235,7 +235,7 @@ namespace OpenRA.Mods.Common.Traits // Building bibs and pathable footprint cells are not included in the ActorMap // TODO: Allow ActorMap to track these and finally remove the BuildingInfluence layer completely - if (AnyGivesBuildableArea(new[] { bi.GetBuildingAt(c) }, p, allyBuildEnabled, requiresBuildableArea)) + if (AnyGivesBuildableArea(bi.GetBuildingsAt(c), p, allyBuildEnabled, requiresBuildableArea)) nearnessCandidates.Add(c); } } diff --git a/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs b/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs index 7c630f6d16..987afd5de0 100644 --- a/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs +++ b/OpenRA.Mods.Common/Traits/Buildings/BuildingInfluence.cs @@ -22,33 +22,65 @@ namespace OpenRA.Mods.Common.Traits public class BuildingInfluence { + class InfluenceNode + { + public InfluenceNode Next; + public Actor Actor; + } + readonly Map map; - readonly CellLayer influence; + readonly CellLayer influence; public BuildingInfluence(World world) { map = world.Map; - influence = new CellLayer(map); + influence = new CellLayer(map); } - internal void AddInfluence(Actor a, IEnumerable tiles) + internal void AddInfluence(Actor a, IEnumerable cells) { - foreach (var u in tiles) - if (influence.Contains(u) && influence[u] == null) - influence[u] = a; + foreach (var c in cells) + { + var uv = c.ToMPos(map); + if (influence.Contains(uv)) + influence[uv] = new InfluenceNode { Next = influence[uv], Actor = a }; + } } - internal void RemoveInfluence(Actor a, IEnumerable tiles) + internal void RemoveInfluence(Actor a, IEnumerable cells) { - foreach (var u in tiles) - if (influence.Contains(u) && influence[u] == a) - influence[u] = null; + foreach (var c in cells) + { + var uv = c.ToMPos(map); + if (!influence.Contains(uv)) + continue; + + influence[uv] = RemoveInfluenceInner(influence[uv], a); + } } - public Actor GetBuildingAt(CPos cell) + static InfluenceNode RemoveInfluenceInner(InfluenceNode influenceNode, Actor toRemove) { - return influence.Contains(cell) ? influence[cell] : null; + if (influenceNode == null) + return null; + + influenceNode.Next = RemoveInfluenceInner(influenceNode.Next, toRemove); + return influenceNode.Actor == toRemove ? influenceNode.Next : influenceNode; + } + + public IEnumerable GetBuildingsAt(CPos cell) + { + var uv = cell.ToMPos(map); + if (!influence.Contains(uv)) + yield break; + + var node = influence[uv]; + while (node != null) + { + yield return node.Actor; + node = node.Next; + } } public bool AnyBuildingAt(CPos cell) diff --git a/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs b/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs index 0dc9b6acb5..5e3c65d24e 100644 --- a/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs +++ b/OpenRA.Mods.D2k/Traits/Buildings/D2kBuilding.cs @@ -97,7 +97,7 @@ namespace OpenRA.Mods.D2k.Traits.Buildings continue; // Don't place under other buildings (or their bib) - if (bi.GetBuildingAt(c) != self) + if (bi.GetBuildingsAt(c).Any(a => a != self)) continue; var index = Game.CosmeticRandom.Next(template.TilesCount); @@ -115,7 +115,7 @@ namespace OpenRA.Mods.D2k.Traits.Buildings continue; // Don't place under other buildings (or their bib) - if (bi.GetBuildingAt(c) != self) + if (bi.GetBuildingsAt(c).Any(a => a != self)) continue; layer.AddTile(c, new TerrainTile(template.Id, (byte)i));