Allow BuildingInfluence to track overlapping buildings in the same cell.

This commit is contained in:
Paul Chote
2021-03-28 13:05:11 +01:00
committed by reaperrr
parent bc286b78bf
commit a1df91b665
3 changed files with 47 additions and 15 deletions

View File

@@ -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);
}
}

View File

@@ -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<Actor> influence;
readonly CellLayer<InfluenceNode> influence;
public BuildingInfluence(World world)
{
map = world.Map;
influence = new CellLayer<Actor>(map);
influence = new CellLayer<InfluenceNode>(map);
}
internal void AddInfluence(Actor a, IEnumerable<CPos> tiles)
internal void AddInfluence(Actor a, IEnumerable<CPos> 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<CPos> tiles)
internal void RemoveInfluence(Actor a, IEnumerable<CPos> 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<Actor> 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)

View File

@@ -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));