diff --git a/OpenRA.Game/Map/Map.cs b/OpenRA.Game/Map/Map.cs index 9fbcdef740..fafdaeb28b 100644 --- a/OpenRA.Game/Map/Map.cs +++ b/OpenRA.Game/Map/Map.cs @@ -70,7 +70,6 @@ namespace OpenRA { public const int SupportedMapFormat = 10; - public const int MaxTilesInCircleRange = 50; public readonly MapGrid Grid; readonly ModData modData; @@ -1102,47 +1101,6 @@ namespace OpenRA return new WDist(Math.Min(x, y) * dir.Length); } - static readonly CVec[][] TilesByDistance = InitTilesByDistance(MaxTilesInCircleRange); - - static CVec[][] InitTilesByDistance(int max) - { - var ts = new List[max + 1]; - for (var i = 0; i < max + 1; i++) - ts[i] = new List(); - - for (var j = -max; j <= max; j++) - for (var i = -max; i <= max; i++) - if (max * max >= i * i + j * j) - ts[Exts.ISqrt(i * i + j * j, Exts.ISqrtRoundMode.Ceiling)].Add(new CVec(i, j)); - - // Sort each integer-distance group by the actual distance - foreach (var list in ts) - { - list.Sort((a, b) => - { - var result = a.LengthSquared.CompareTo(b.LengthSquared); - if (result != 0) - return result; - - // If the lengths are equal, use other means to sort them. - // Try the hash code first because it gives more - // random-appearing results than X or Y that would always - // prefer the leftmost/topmost position. - result = a.GetHashCode().CompareTo(b.GetHashCode()); - if (result != 0) - return result; - - result = a.X.CompareTo(b.X); - if (result != 0) - return result; - - return a.Y.CompareTo(b.Y); - }); - } - - return ts.Select(list => list.ToArray()).ToArray(); - } - // Both ranges are inclusive because everything that calls it is designed for maxRange being inclusive: // it rounds the actual distance up to the next integer so that this call // will return any cells that intersect with the requested range circle. @@ -1152,8 +1110,9 @@ namespace OpenRA if (maxRange < minRange) throw new ArgumentOutOfRangeException("maxRange", "Maximum range is less than the minimum range."); - if (maxRange >= TilesByDistance.Length) - throw new ArgumentOutOfRangeException("maxRange", "The requested range ({0}) exceeds the maximum allowed ({1})".F(maxRange, MaxTilesInCircleRange)); + if (maxRange >= Grid.TilesByDistance.Length) + throw new ArgumentOutOfRangeException("maxRange", + "The requested range ({0}) cannot exceed the value of MaximumTileSearchRange ({1})".F(maxRange, Grid.MaximumTileSearchRange)); Func valid = Contains; if (allowOutsideBounds) @@ -1161,7 +1120,7 @@ namespace OpenRA for (var i = minRange; i <= maxRange; i++) { - foreach (var offset in TilesByDistance[i]) + foreach (var offset in Grid.TilesByDistance[i]) { var t = offset + center; if (valid(t)) diff --git a/OpenRA.Game/Map/MapGrid.cs b/OpenRA.Game/Map/MapGrid.cs index 77e8fdc63a..05cdf4f63f 100644 --- a/OpenRA.Game/Map/MapGrid.cs +++ b/OpenRA.Game/Map/MapGrid.cs @@ -9,6 +9,7 @@ */ #endregion +using System.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; @@ -25,6 +26,8 @@ namespace OpenRA public readonly byte MaximumTerrainHeight = 0; public readonly SubCell DefaultSubCell = (SubCell)byte.MaxValue; + public readonly int MaximumTileSearchRange = 50; + public readonly WVec[] SubCellOffsets = { new WVec(0, 0, 0), // full cell - index 0 @@ -73,6 +76,8 @@ namespace OpenRA new[] { 0, 1, 0, 1 } }; + internal readonly CVec[][] TilesByDistance; + public MapGrid(MiniYaml yaml) { FieldLoader.Load(this, yaml); @@ -95,6 +100,47 @@ namespace OpenRA rightDelta + new WVec(0, 0, 512 * ramp[2]), bottomDelta + new WVec(0, 0, 512 * ramp[3]) }).ToArray(); + + TilesByDistance = CreateTilesByDistance(); + } + + CVec[][] CreateTilesByDistance() + { + var ts = new List[MaximumTileSearchRange + 1]; + for (var i = 0; i < MaximumTileSearchRange + 1; i++) + ts[i] = new List(); + + for (var j = -MaximumTileSearchRange; j <= MaximumTileSearchRange; j++) + for (var i = -MaximumTileSearchRange; i <= MaximumTileSearchRange; i++) + if (MaximumTileSearchRange * MaximumTileSearchRange >= i * i + j * j) + ts[Exts.ISqrt(i * i + j * j, Exts.ISqrtRoundMode.Ceiling)].Add(new CVec(i, j)); + + // Sort each integer-distance group by the actual distance + foreach (var list in ts) + { + list.Sort((a, b) => + { + var result = a.LengthSquared.CompareTo(b.LengthSquared); + if (result != 0) + return result; + + // If the lengths are equal, use other means to sort them. + // Try the hash code first because it gives more + // random-appearing results than X or Y that would always + // prefer the leftmost/topmost position. + result = a.GetHashCode().CompareTo(b.GetHashCode()); + if (result != 0) + return result; + + result = a.X.CompareTo(b.X); + if (result != 0) + return result; + + return a.Y.CompareTo(b.Y); + }); + } + + return ts.Select(list => list.ToArray()).ToArray(); } public WVec OffsetOfSubCell(SubCell subCell) diff --git a/OpenRA.Mods.Common/AI/HackyAI.cs b/OpenRA.Mods.Common/AI/HackyAI.cs index 2694e9276f..6d044b3945 100644 --- a/OpenRA.Mods.Common/AI/HackyAI.cs +++ b/OpenRA.Mods.Common/AI/HackyAI.cs @@ -526,7 +526,7 @@ namespace OpenRA.Mods.Common.AI return findPos(baseCenter, baseCenter, Info.MinBaseRadius, Info.MaxBaseRadius); case BuildingType.Building: - return findPos(baseCenter, baseCenter, Info.MinBaseRadius, distanceToBaseIsImportant ? Info.MaxBaseRadius : Map.MaxTilesInCircleRange); + return findPos(baseCenter, baseCenter, Info.MinBaseRadius, distanceToBaseIsImportant ? Info.MaxBaseRadius : Map.Grid.MaximumTileSearchRange); } // Can't find a build location diff --git a/OpenRA.Mods.RA/Activities/Teleport.cs b/OpenRA.Mods.RA/Activities/Teleport.cs index 48e39a0670..68c284d3db 100644 --- a/OpenRA.Mods.RA/Activities/Teleport.cs +++ b/OpenRA.Mods.RA/Activities/Teleport.cs @@ -22,7 +22,6 @@ namespace OpenRA.Mods.RA.Activities public class Teleport : Activity { - const int MaxCellSearchRange = Map.MaxTilesInCircleRange; readonly Actor teleporter; readonly int? maximumDistance; CPos destination; @@ -32,8 +31,9 @@ namespace OpenRA.Mods.RA.Activities public Teleport(Actor teleporter, CPos destination, int? maximumDistance, bool killCargo, bool screenFlash, string sound) { - if (maximumDistance > MaxCellSearchRange) - throw new InvalidOperationException("Teleport cannot be used with a maximum teleport distance greater than {0}.".F(MaxCellSearchRange)); + var max = teleporter.World.Map.Grid.MaximumTileSearchRange; + if (maximumDistance > max) + throw new InvalidOperationException("Teleport distance cannot exceed the value of MaximumTileSearchRange ({0}).".F(max)); this.teleporter = teleporter; this.destination = destination; @@ -114,7 +114,7 @@ namespace OpenRA.Mods.RA.Activities if (pos.CanEnterCell(destination) && teleporter.Owner.Shroud.IsExplored(destination)) return destination; - var max = maximumDistance != null ? maximumDistance.Value : MaxCellSearchRange; + var max = maximumDistance != null ? maximumDistance.Value : teleporter.World.Map.Grid.MaximumTileSearchRange; foreach (var tile in self.World.Map.FindTilesInCircle(destination, max)) { if (teleporter.Owner.Shroud.IsExplored(tile)