diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 3a4b5d3602..496b2e2a79 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -241,6 +241,7 @@ namespace OpenRA bool initializedCellProjection; CellLayer cellProjection; CellLayer> inverseCellProjection; + CellLayer projectedHeight; public static string ComputeUID(IReadOnlyPackage package) { @@ -420,6 +421,7 @@ namespace OpenRA cellProjection = new CellLayer(this); inverseCellProjection = new CellLayer>(this); + projectedHeight = new CellLayer(this); // Initialize collections foreach (var cell in AllCells) @@ -455,13 +457,48 @@ namespace OpenRA // Remove old reverse projection foreach (var puv in cellProjection[uv]) - inverseCellProjection[(MPos)puv].Remove(uv); + { + var temp = (MPos)puv; + inverseCellProjection[temp].Remove(uv); + projectedHeight[temp] = ProjectedCellHeightInner(puv); + } var projected = ProjectCellInner(uv); cellProjection[uv] = projected; foreach (var puv in projected) - inverseCellProjection[(MPos)puv].Add(uv); + { + var temp = (MPos)puv; + inverseCellProjection[temp].Add(uv); + + var height = ProjectedCellHeightInner(puv); + projectedHeight[temp] = height; + + // Propagate height up cliff faces + while (true) + { + temp = new MPos(temp.U, temp.V - 1); + if (!inverseCellProjection.Contains(temp) || inverseCellProjection[temp].Any()) + break; + + projectedHeight[temp] = height; + } + } + } + + byte ProjectedCellHeightInner(PPos puv) + { + while (inverseCellProjection.Contains((MPos)puv)) + { + var inverse = inverseCellProjection[(MPos)puv]; + if (inverse.Any()) + return Height[inverse.MaxBy(uv => uv.V)]; + + // Try the next cell down if this is a cliff face + puv = new PPos(puv.U, puv.V + 1); + } + + return 0; } PPos[] ProjectCellInner(MPos uv) @@ -786,6 +823,11 @@ namespace OpenRA return inverseCellProjection[uv]; } + public byte ProjectedHeight(PPos puv) + { + return projectedHeight[(MPos)puv]; + } + public int FacingBetween(CPos cell, CPos towards, int fallbackfacing) { var delta = CenterOfCell(towards) - CenterOfCell(cell);