diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 7544ff72cb..67cd3ba7f6 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -89,7 +89,7 @@ namespace OpenRa return null; var loc = mi.Location + Game.viewport.Location; - var underCursor = Game.FindUnits(loc, loc).FirstOrDefault(); + var underCursor = Game.world.FindUnits(loc, loc).FirstOrDefault(); if (underCursor != null && !underCursor.traits.Contains()) underCursor = null; diff --git a/OpenRa.Game/Combat.cs b/OpenRa.Game/Combat.cs index ed50bda6ee..159a4fffae 100644 --- a/OpenRa.Game/Combat.cs +++ b/OpenRa.Game/Combat.cs @@ -15,8 +15,8 @@ namespace OpenRa { var targetTile = ((1f / Game.CellSize) * loc.ToFloat2()).ToInt2(); - var isWater = Game.IsWater(targetTile); - var hitWater = Game.IsCellBuildable(targetTile, UnitMovementType.Float); + var isWater = Game.world.IsWater(targetTile); + var hitWater = Game.world.IsCellBuildable(targetTile, UnitMovementType.Float); if (warhead.Explosion != 0) Game.world.AddFrameEndTask( @@ -31,7 +31,7 @@ namespace OpenRa if (warhead.Ore) Ore.Destroy(targetTile.X, targetTile.Y); var maxSpread = GetMaximumSpread(weapon, warhead); - var hitActors = Game.FindUnitsInCircle(loc, maxSpread); + var hitActors = Game.world.FindUnitsInCircle(loc, maxSpread); foreach (var victim in hitActors) victim.InflictDamage(firedBy, (int)GetDamageToInflict(victim, loc, weapon, warhead), warhead); diff --git a/OpenRa.Game/Controller.cs b/OpenRa.Game/Controller.cs index 2c31b39f91..c58809c124 100644 --- a/OpenRa.Game/Controller.cs +++ b/OpenRa.Game/Controller.cs @@ -95,7 +95,7 @@ namespace OpenRa { if (orderGenerator is UnitOrderGenerator) { - var newSelection = Game.SelectActorsInBox(Game.CellSize * dragStart, Game.CellSize * xy); + var newSelection = Game.world.SelectActorsInBox(Game.CellSize * dragStart, Game.CellSize * xy); CombineSelection(newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy); } diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index 375a9f5b16..d5191f3ac8 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -208,130 +208,9 @@ namespace OpenRa renderer.PaletteTexture = palette.Texture; } - public static bool IsCellBuildable(int2 a, UnitMovementType umt) - { - return IsCellBuildable(a, umt, null); - } - - public static bool IsCellBuildable(int2 a, UnitMovementType umt, Actor toIgnore) - { - if (Game.world.BuildingInfluence.GetBuildingAt(a) != null) return false; - if (Game.world.UnitInfluence.GetUnitsAt(a).Any(b => b != toIgnore)) return false; - - return Game.world.Map.IsInMap(a.X, a.Y) && - TerrainCosts.Cost(umt, - Game.world.TileSet.GetWalkability(Game.world.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; - } - - public static bool IsActorCrushableByActor(Actor a, Actor b) - { - return IsActorCrushableByMovementType(a, b.traits.GetOrDefault().GetMovementType()); - } - - public static bool IsActorPathableToCrush(Actor a, UnitMovementType umt) - { - return a != null && - a.traits.WithInterface() - .Any(c => c.IsPathableCrush(umt, a.Owner)); - } - - public static bool IsActorCrushableByMovementType(Actor a, UnitMovementType umt) - { - return a != null && - a.traits.WithInterface() - .Any(c => c.IsCrushableBy(umt, a.Owner)); - } - - public static bool IsWater(int2 a) - { - return Game.world.Map.IsInMap(a.X, a.Y) && - TerrainCosts.Cost(UnitMovementType.Float, - Game.world.TileSet.GetWalkability(Game.world.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; - } - - public static IEnumerable FindUnits(float2 a, float2 b) - { - var min = float2.Min(a, b); - var max = float2.Max(a, b); - - var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); - - return world.Actors - .Where(x => x.GetBounds(true).IntersectsWith(rect)); - } - - public static IEnumerable FindUnitsInCircle(float2 a, float r) - { - var min = a - new float2(r, r); - var max = a + new float2(r, r); - - var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); - - var inBox = world.Actors.Where(x => x.GetBounds(false).IntersectsWith(rect)); - - return inBox.Where(x => (x.CenterLocation - a).LengthSquared < r * r); - } - - public static IEnumerable FindTilesInCircle(int2 a, int r) - { - var min = a - new int2(r, r); - var max = a + new int2(r, r); - if (min.X < 0) min.X = 0; - if (min.Y < 0) min.Y = 0; - if (max.X > 127) max.X = 127; - if (max.Y > 127) max.Y = 127; - - for (var j = min.Y; j <= max.Y; j++) - for (var i = min.X; i <= max.X; i++) - if (r * r >= (new int2(i, j) - a).LengthSquared) - yield return new int2(i, j); - } - - public static IEnumerable SelectActorsInBox(float2 a, float2 b) - { - return FindUnits(a, b) - .Where( x => x.traits.Contains() ) - .GroupBy(x => (x.Owner == LocalPlayer) ? x.Info.Traits.Get().Priority : 0) - .OrderByDescending(g => g.Key) - .Select( g => g.AsEnumerable() ) - .DefaultIfEmpty( new Actor[] {} ) - .FirstOrDefault(); - } - public static Random SharedRandom = new Random(0); /* for things that require sync */ public static Random CosmeticRandom = new Random(); /* for things that are just fluff */ - public static bool CanPlaceBuilding(string name, BuildingInfo building, int2 xy, Actor toIgnore, bool adjust) - { - return !Footprint.Tiles(name, building, xy, adjust).Any( - t => !Game.world.Map.IsInMap(t.X, t.Y) || Game.world.Map.ContainsResource(t) || !Game.IsCellBuildable(t, - building.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel, - toIgnore)); - } - - public static bool IsCloseEnoughToBase(Player p, string buildingName, BuildingInfo bi, int2 position) - { - var maxDistance = bi.Adjacent + 1; - - var search = new PathSearch() - { - heuristic = loc => - { - var b = Game.world.BuildingInfluence.GetBuildingAt(loc); - if (b != null && b.Owner == p && b.Info.Traits.Get().BaseNormal) return 0; - if ((loc - position).Length > maxDistance) - return float.PositiveInfinity; /* not quite right */ - return 1; - }, - checkForBlocked = false, - ignoreTerrain = true, - }; - - foreach (var t in Footprint.Tiles(buildingName, bi, position)) search.AddInitialCell(t); - - return Game.world.PathFinder.FindPath(search).Count != 0; - } - public static void SyncLobbyInfo(string data) { var session = new Session(); diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index 037aaca30f..b4d227041f 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -102,7 +102,7 @@ namespace OpenRa.Graphics lineRenderer.DrawLine(a + b + c, a + c, Color.White, Color.White); lineRenderer.DrawLine(a, a + c, Color.White, Color.White); - foreach (var u in Game.SelectActorsInBox(selbox.Value.First, selbox.Value.Second)) + foreach (var u in Game.world.SelectActorsInBox(selbox.Value.First, selbox.Value.Second)) DrawSelectionBox(u, Color.Yellow, false); } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index cfa53ae14e..c57308d299 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -7,7 +7,7 @@ {0DFB103F-2962-400F-8C6D-E2C28CCBA633} WinExe Properties - OpenRa.Game + OpenRa OpenRa.Game @@ -274,6 +274,7 @@ + diff --git a/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs index 43ff615c14..d83271fb9a 100644 --- a/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs +++ b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs @@ -28,7 +28,7 @@ namespace OpenRa.Orders if (mi.Button == MouseButton.Left) { var loc = mi.Location + Game.viewport.Location; - var underCursor = Game.FindUnits(loc, loc) + var underCursor = Game.world.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() && a.traits.Contains()).FirstOrDefault(); diff --git a/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs b/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs index a030ba2e04..8d46ad6c84 100644 --- a/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs +++ b/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs @@ -28,7 +28,7 @@ namespace OpenRa.Orders if (mi.Button == MouseButton.Left) { var loc = mi.Location + Game.viewport.Location; - var underCursor = Game.FindUnits(loc, loc) + var underCursor = Game.world.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() && a.traits.Contains()).FirstOrDefault(); diff --git a/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs b/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs index 68985cf561..ebcdcd994c 100644 --- a/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs @@ -28,8 +28,8 @@ namespace OpenRa.Orders { if (mi.Button == MouseButton.Left) { - if (!Game.CanPlaceBuilding( Building, BuildingInfo, xy, null, true) - || !Game.IsCloseEnoughToBase(Producer.Owner, Building, BuildingInfo, xy)) + if (!Game.world.CanPlaceBuilding( Building, BuildingInfo, xy, null, true) + || !Game.world.IsCloseEnoughToBase(Producer.Owner, Building, BuildingInfo, xy)) { Sound.Play("nodeply1.aud"); yield break; diff --git a/OpenRa.Game/Orders/PowerDownOrderGenerator.cs b/OpenRa.Game/Orders/PowerDownOrderGenerator.cs index 68d2c6c4fa..5debd3ebdd 100644 --- a/OpenRa.Game/Orders/PowerDownOrderGenerator.cs +++ b/OpenRa.Game/Orders/PowerDownOrderGenerator.cs @@ -22,7 +22,7 @@ namespace OpenRa.Orders if (mi.Button == MouseButton.Left) { var loc = mi.Location + Game.viewport.Location; - var underCursor = Game.FindUnits(loc, loc) + var underCursor = Game.world.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() && a.traits.Contains()).FirstOrDefault(); diff --git a/OpenRa.Game/Orders/RepairOrderGenerator.cs b/OpenRa.Game/Orders/RepairOrderGenerator.cs index 2fb1e49861..834803c4ef 100644 --- a/OpenRa.Game/Orders/RepairOrderGenerator.cs +++ b/OpenRa.Game/Orders/RepairOrderGenerator.cs @@ -22,7 +22,7 @@ namespace OpenRa.Orders if (mi.Button == MouseButton.Left) { var loc = mi.Location + Game.viewport.Location; - var underCursor = Game.FindUnits(loc, loc) + var underCursor = Game.world.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() && a.traits.Contains()).FirstOrDefault(); diff --git a/OpenRa.Game/Orders/SellOrderGenerator.cs b/OpenRa.Game/Orders/SellOrderGenerator.cs index 7edc0784f2..7ddf9a3039 100644 --- a/OpenRa.Game/Orders/SellOrderGenerator.cs +++ b/OpenRa.Game/Orders/SellOrderGenerator.cs @@ -22,7 +22,7 @@ namespace OpenRa.Orders if (mi.Button == MouseButton.Left) { var loc = mi.Location + Game.viewport.Location; - var underCursor = Game.FindUnits(loc, loc) + var underCursor = Game.world.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() && a.traits.Contains()).FirstOrDefault(); diff --git a/OpenRa.Game/Orders/UnitOrderGenerator.cs b/OpenRa.Game/Orders/UnitOrderGenerator.cs index 54ccab6fc8..44e2a38ed4 100644 --- a/OpenRa.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRa.Game/Orders/UnitOrderGenerator.cs @@ -50,7 +50,7 @@ namespace OpenRa.Orders .FirstOrDefault(a => a != null); return c ?? - (Game.SelectActorsInBox(Game.CellSize * p, + (Game.world.SelectActorsInBox(Game.CellSize * p, Game.CellSize * p).Any() ? Cursor.Select : Cursor.Default); } @@ -70,7 +70,7 @@ namespace OpenRa.Orders return Cursor.MoveBlocked; case "DeployMcv": var factBuildingInfo = Rules.ActorInfo["fact"].Traits.Get(); - if (Game.CanPlaceBuilding("fact", factBuildingInfo, a.Location - new int2(1, 1), a, false)) + if (Game.world.CanPlaceBuilding("fact", factBuildingInfo, a.Location - new int2(1, 1), a, false)) return Cursor.Deploy; else return Cursor.DeployBlocked; diff --git a/OpenRa.Game/PathFinder.cs b/OpenRa.Game/PathFinder.cs index c6428f9d0b..e27ca54284 100644 --- a/OpenRa.Game/PathFinder.cs +++ b/OpenRa.Game/PathFinder.cs @@ -40,8 +40,8 @@ namespace OpenRa { using( new PerfSample( "find_unit_path_multiple_src" ) ) { - var tilesInRange = Game.FindTilesInCircle(target, range) - .Where( t => Game.IsCellBuildable( t, umt ) ); + var tilesInRange = Game.world.FindTilesInCircle(target, range) + .Where( t => Game.world.IsCellBuildable( t, umt ) ); var path = FindPath( PathSearch.FromPoints( tilesInRange, src, umt, false ).WithCustomBlocker(AvoidUnitsNear(src, 4))); path.Reverse(); diff --git a/OpenRa.Game/PathSearch.cs b/OpenRa.Game/PathSearch.cs index 4fb5ba11ff..02561b8ace 100755 --- a/OpenRa.Game/PathSearch.cs +++ b/OpenRa.Game/PathSearch.cs @@ -64,7 +64,7 @@ namespace OpenRa } // Replicate real-ra behavior of not being able to enter a cell if there is a mixture of crushable and uncrushable units - if (checkForBlocked && (Game.world.UnitInfluence.GetUnitsAt(newHere).Any(a => !Game.IsActorPathableToCrush(a, umt)))) + if (checkForBlocked && (Game.world.UnitInfluence.GetUnitsAt(newHere).Any(a => !Game.world.IsActorPathableToCrush(a, umt)))) continue; if (customBlock != null && customBlock(newHere)) diff --git a/OpenRa.Game/Shroud.cs b/OpenRa.Game/Shroud.cs index abaad1b6e8..91622065cd 100644 --- a/OpenRa.Game/Shroud.cs +++ b/OpenRa.Game/Shroud.cs @@ -81,16 +81,16 @@ namespace OpenRa public void Explore(Actor a) { - foreach (var t in Game.FindTilesInCircle( + foreach (var t in Game.world.FindTilesInCircle( (1f / Game.CellSize * a.CenterLocation).ToInt2(), - a.Info.Traits.Get().Sight)) - { + a.Info.Traits.Get().Sight)) + { explored[t.X, t.Y] = true; gapField[t.X, t.Y] = 0; } dirty = true; } - + static readonly byte[][] SpecialShroudTiles = { new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, @@ -119,7 +119,7 @@ namespace OpenRa var v = 0; // bits are for unexploredness: TL, TR, BR, BL var u = 0; - + if( !IsExplored( i, j - 1 ) ) { v |= 1; u |= 3; } if( !IsExplored( i + 1, j ) ) { v |= 2; u |= 6; } if( !IsExplored( i, j + 1 ) ) { v |= 4; u |= 12; } @@ -132,7 +132,7 @@ namespace OpenRa if( !IsExplored( i + 1, j + 1 ) ) u |= 4; if( !IsExplored( i - 1, j + 1 ) ) u |= 8; - return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ]; + return shadowBits[ SpecialShroudTiles[ u ^ uSides ][ v ] ]; } internal void Draw(SpriteRenderer r) diff --git a/OpenRa.Game/Traits/Activities/HeliLand.cs b/OpenRa.Game/Traits/Activities/HeliLand.cs index b357c59f33..4d1600962b 100644 --- a/OpenRa.Game/Traits/Activities/HeliLand.cs +++ b/OpenRa.Game/Traits/Activities/HeliLand.cs @@ -16,7 +16,7 @@ namespace OpenRa.Traits.Activities if (unit.Altitude == 0) return NextActivity; - if (requireSpace && !Game.IsCellBuildable(self.Location, UnitMovementType.Foot)) + if (requireSpace && !Game.world.IsCellBuildable(self.Location, UnitMovementType.Foot)) return this; // fail to land if no space --unit.Altitude; diff --git a/OpenRa.Game/Traits/Activities/Move.cs b/OpenRa.Game/Traits/Activities/Move.cs index 7f12749983..c39abdeb6c 100755 --- a/OpenRa.Game/Traits/Activities/Move.cs +++ b/OpenRa.Game/Traits/Activities/Move.cs @@ -63,7 +63,7 @@ namespace OpenRa.Traits.Activities // Cannot enter a cell if any unit inside is uncrushable // This will need to be updated for multiple-infantry-in-a-cell - return (!Game.world.UnitInfluence.GetUnitsAt(c).Any(a => a != self && !Game.IsActorCrushableByActor(a, self))); + return (!Game.world.UnitInfluence.GetUnitsAt(c).Any(a => a != self && !Game.world.IsActorCrushableByActor(a, self))); } public IActivity Tick( Actor self ) diff --git a/OpenRa.Game/Traits/Activities/Rearm.cs b/OpenRa.Game/Traits/Activities/Rearm.cs index e3719c3918..d1917a9c6d 100644 --- a/OpenRa.Game/Traits/Activities/Rearm.cs +++ b/OpenRa.Game/Traits/Activities/Rearm.cs @@ -20,7 +20,7 @@ namespace OpenRa.Traits.Activities { if (!limitedAmmo.GiveAmmo()) return NextActivity; - var hostBuilding = Game.FindUnits(self.CenterLocation, self.CenterLocation) + var hostBuilding = Game.world.FindUnits(self.CenterLocation, self.CenterLocation) .FirstOrDefault(a => a.traits.Contains()); if (hostBuilding != null) diff --git a/OpenRa.Game/Traits/Activities/Repair.cs b/OpenRa.Game/Traits/Activities/Repair.cs index b6b63f566f..918b2417a6 100644 --- a/OpenRa.Game/Traits/Activities/Repair.cs +++ b/OpenRa.Game/Traits/Activities/Repair.cs @@ -32,7 +32,7 @@ namespace OpenRa.Traits.Activities if (self.Health == hp) return NextActivity; - var hostBuilding = Game.FindUnits(self.CenterLocation, self.CenterLocation) + var hostBuilding = Game.world.FindUnits(self.CenterLocation, self.CenterLocation) .FirstOrDefault(a => a.traits.Contains()); if (hostBuilding != null) diff --git a/OpenRa.Game/Traits/Activities/UnloadCargo.cs b/OpenRa.Game/Traits/Activities/UnloadCargo.cs index f123b2e4ef..06c59333ca 100644 --- a/OpenRa.Game/Traits/Activities/UnloadCargo.cs +++ b/OpenRa.Game/Traits/Activities/UnloadCargo.cs @@ -19,7 +19,7 @@ namespace OpenRa.Traits.Activities for (var i = -1; i < 2; i++) for (var j = -1; j < 2; j++) if ((i != 0 || j != 0) && - Game.IsCellBuildable(self.Location + new int2(i, j), + Game.world.IsCellBuildable(self.Location + new int2(i, j), UnitMovementType.Foot)) return self.Location + new int2(i, j); diff --git a/OpenRa.Game/Traits/AutoHeal.cs b/OpenRa.Game/Traits/AutoHeal.cs index b4a37b5b61..ebaa115fac 100644 --- a/OpenRa.Game/Traits/AutoHeal.cs +++ b/OpenRa.Game/Traits/AutoHeal.cs @@ -43,7 +43,7 @@ namespace OpenRa.Traits Actor ChooseTarget(Actor self, float range) { - var inRange = Game.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); + var inRange = Game.world.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); return inRange .Where(a => a.Owner == self.Owner && a != self) /* todo: one day deal with friendly players */ diff --git a/OpenRa.Game/Traits/AutoTarget.cs b/OpenRa.Game/Traits/AutoTarget.cs index 59e23260fd..7044fb240c 100644 --- a/OpenRa.Game/Traits/AutoTarget.cs +++ b/OpenRa.Game/Traits/AutoTarget.cs @@ -27,7 +27,7 @@ namespace OpenRa.Traits Actor ChooseTarget(Actor self, float range) { - var inRange = Game.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); + var inRange = Game.world.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range); return inRange .Where(a => a.Owner != null && a.Owner != self.Owner) /* todo: one day deal with friendly players */ diff --git a/OpenRa.Game/Traits/ConstructionYard.cs b/OpenRa.Game/Traits/ConstructionYard.cs index d691dfe85d..c4b1e915eb 100644 --- a/OpenRa.Game/Traits/ConstructionYard.cs +++ b/OpenRa.Game/Traits/ConstructionYard.cs @@ -27,7 +27,7 @@ namespace OpenRa.Traits { // force-move if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null; - if (!Game.IsActorCrushableByActor(underCursor, self)) return null; + if (!Game.world.IsActorCrushableByActor(underCursor, self)) return null; } return new Order("Move", self, null, xy, null); @@ -57,7 +57,7 @@ namespace OpenRa.Traits { if (actor == self) continue; - if (!Game.IsActorCrushableByActor(actor, self)) + if (!Game.world.IsActorCrushableByActor(actor, self)) { crushable = false; break; diff --git a/OpenRa.Game/Traits/GeneratesGap.cs b/OpenRa.Game/Traits/GeneratesGap.cs index 4aa84b7927..3ed67c8322 100644 --- a/OpenRa.Game/Traits/GeneratesGap.cs +++ b/OpenRa.Game/Traits/GeneratesGap.cs @@ -28,7 +28,7 @@ namespace OpenRa.Traits // Gap Generator building; powered down return (self.traits.Contains() && self.traits.Get().Disabled) ? new int2[] {} - : Game.FindTilesInCircle(self.Location, range); + : Game.world.FindTilesInCircle(self.Location, range); } } } diff --git a/OpenRa.Game/Traits/McvDeploy.cs b/OpenRa.Game/Traits/McvDeploy.cs index afa38ba12c..f570157229 100644 --- a/OpenRa.Game/Traits/McvDeploy.cs +++ b/OpenRa.Game/Traits/McvDeploy.cs @@ -25,7 +25,7 @@ namespace OpenRa.Traits if( order.OrderString == "DeployMcv" ) { var factBuildingInfo = Rules.ActorInfo[ "fact" ].Traits.Get(); - if( Game.CanPlaceBuilding( "fact", factBuildingInfo, self.Location - new int2( 1, 1 ), self, false ) ) + if( Game.world.CanPlaceBuilding( "fact", factBuildingInfo, self.Location - new int2( 1, 1 ), self, false ) ) { self.CancelActivity(); self.QueueActivity( new Turn( 96 ) ); diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs index 60b00d295d..244bdffd1c 100644 --- a/OpenRa.Game/Traits/Mobile.cs +++ b/OpenRa.Game/Traits/Mobile.cs @@ -59,7 +59,7 @@ namespace OpenRa.Traits { // force-move if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null; - if (!Game.IsActorCrushableByActor(underCursor, self)) return null; + if (!Game.world.IsActorCrushableByActor(underCursor, self)) return null; } if (Util.GetEffectiveSpeed(self) == 0) return null; /* allow disabling move orders from modifiers */ @@ -97,7 +97,7 @@ namespace OpenRa.Traits { if (actor == self) continue; - if (!Game.IsActorCrushableByActor(actor, self)) + if (!Game.world.IsActorCrushableByActor(actor, self)) { crushable = false; break; diff --git a/OpenRa.Game/Traits/ProductionSurround.cs b/OpenRa.Game/Traits/ProductionSurround.cs index 46d65117d6..9abb584492 100644 --- a/OpenRa.Game/Traits/ProductionSurround.cs +++ b/OpenRa.Game/Traits/ProductionSurround.cs @@ -20,7 +20,7 @@ namespace OpenRa.Traits for (var j = min.Y; j <= max.Y; j++) for (var i = min.X; i <= max.X; i++) - if (Game.IsCellBuildable(new int2(i, j), umt)) + if (Game.world.IsCellBuildable(new int2(i, j), umt)) return new int2(i, j); return null; diff --git a/OpenRa.Game/UiOverlay.cs b/OpenRa.Game/UiOverlay.cs index 4acaf4a805..91e8e24074 100644 --- a/OpenRa.Game/UiOverlay.cs +++ b/OpenRa.Game/UiOverlay.cs @@ -46,10 +46,10 @@ namespace OpenRa public void DrawBuildingGrid( string name, BuildingInfo bi ) { var position = Game.controller.MousePosition.ToInt2(); - var isCloseEnough = Game.IsCloseEnoughToBase(Game.LocalPlayer, name, bi, position); + var isCloseEnough = Game.world.IsCloseEnoughToBase(Game.LocalPlayer, name, bi, position); foreach( var t in Footprint.Tiles( name, bi, position ) ) - spriteRenderer.DrawSprite( ( isCloseEnough && Game.IsCellBuildable( t, bi.WaterBound + spriteRenderer.DrawSprite( ( isCloseEnough && Game.world.IsCellBuildable( t, bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel ) && !Game.world.Map.ContainsResource( t ) ) ? buildOk : buildBlocked, Game.CellSize * t, 0 ); diff --git a/OpenRa.Game/UnitInfluenceMap.cs b/OpenRa.Game/UnitInfluenceMap.cs index 6bc2f74457..e884cc5273 100644 --- a/OpenRa.Game/UnitInfluenceMap.cs +++ b/OpenRa.Game/UnitInfluenceMap.cs @@ -33,7 +33,7 @@ namespace OpenRa { // There should only be one (counterexample: An infantry and a tank try to pick up a crate at the same time.) // If there is more than one, do action on the first crusher - var crusher = GetUnitsAt(cell).Where(b => a != b && Game.IsActorCrushableByActor(a, b)).FirstOrDefault(); + var crusher = GetUnitsAt(cell).Where(b => a != b && Game.world.IsActorCrushableByActor(a, b)).FirstOrDefault(); if (crusher != null) { Log.Write("{0} crushes {1}", crusher.Info.Name, a.Info.Name); diff --git a/OpenRa.Game/WorldUtils.cs b/OpenRa.Game/WorldUtils.cs new file mode 100755 index 0000000000..3f9a84ab66 --- /dev/null +++ b/OpenRa.Game/WorldUtils.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRa.Traits; +using System.Drawing; +using OpenRa.GameRules; + +namespace OpenRa +{ + static class WorldUtils + { + public static bool IsCellBuildable(this World world, int2 a, UnitMovementType umt) + { + return world.IsCellBuildable(a, umt, null); + } + + public static bool IsCellBuildable(this World world, int2 a, UnitMovementType umt, Actor toIgnore) + { + if (world.BuildingInfluence.GetBuildingAt(a) != null) return false; + if (world.UnitInfluence.GetUnitsAt(a).Any(b => b != toIgnore)) return false; + + return world.Map.IsInMap(a.X, a.Y) && + TerrainCosts.Cost(umt, + world.TileSet.GetWalkability(world.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; + } + + public static bool IsActorCrushableByActor(this World world, Actor a, Actor b) + { + return world.IsActorCrushableByMovementType(a, b.traits.GetOrDefault().GetMovementType()); + } + + public static bool IsActorPathableToCrush(this World world, Actor a, UnitMovementType umt) + { + return a != null && + a.traits.WithInterface() + .Any(c => c.IsPathableCrush(umt, a.Owner)); + } + + public static bool IsActorCrushableByMovementType(this World world, Actor a, UnitMovementType umt) + { + return a != null && + a.traits.WithInterface() + .Any(c => c.IsCrushableBy(umt, a.Owner)); + } + + public static bool IsWater(this World world, int2 a) + { + return world.Map.IsInMap(a.X, a.Y) && + TerrainCosts.Cost(UnitMovementType.Float, + world.TileSet.GetWalkability(world.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; + } + + public static IEnumerable FindUnits(this World world, float2 a, float2 b) + { + var min = float2.Min(a, b); + var max = float2.Max(a, b); + + var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); + + return world.Actors + .Where(x => x.GetBounds(true).IntersectsWith(rect)); + } + + public static IEnumerable FindUnitsInCircle(this World world, float2 a, float r) + { + var min = a - new float2(r, r); + var max = a + new float2(r, r); + + var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); + + var inBox = world.Actors.Where(x => x.GetBounds(false).IntersectsWith(rect)); + + return inBox.Where(x => (x.CenterLocation - a).LengthSquared < r * r); + } + + public static IEnumerable FindTilesInCircle(this World world, int2 a, int r) + { + var min = a - new int2(r, r); + var max = a + new int2(r, r); + if (min.X < 0) min.X = 0; + if (min.Y < 0) min.Y = 0; + if (max.X > 127) max.X = 127; + if (max.Y > 127) max.Y = 127; + + for (var j = min.Y; j <= max.Y; j++) + for (var i = min.X; i <= max.X; i++) + if (r * r >= (new int2(i, j) - a).LengthSquared) + yield return new int2(i, j); + } + + public static IEnumerable SelectActorsInBox(this World world, float2 a, float2 b) + { + return world.FindUnits(a, b) + .Where( x => x.traits.Contains() ) + .GroupBy(x => (x.Owner == Game.LocalPlayer) ? x.Info.Traits.Get().Priority : 0) + .OrderByDescending(g => g.Key) + .Select( g => g.AsEnumerable() ) + .DefaultIfEmpty( new Actor[] {} ) + .FirstOrDefault(); + } + + public static bool CanPlaceBuilding(this World world, string name, BuildingInfo building, int2 xy, Actor toIgnore, bool adjust) + { + return !Footprint.Tiles(name, building, xy, adjust).Any( + t => !world.Map.IsInMap(t.X, t.Y) || world.Map.ContainsResource(t) || !world.IsCellBuildable(t, + building.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel, + toIgnore)); + } + + public static bool IsCloseEnoughToBase(this World world, Player p, string buildingName, BuildingInfo bi, int2 position) + { + var maxDistance = bi.Adjacent + 1; + + var search = new PathSearch() + { + heuristic = loc => + { + var b = world.BuildingInfluence.GetBuildingAt(loc); + if (b != null && b.Owner == p && b.Info.Traits.Get().BaseNormal) return 0; + if ((loc - position).Length > maxDistance) + return float.PositiveInfinity; /* not quite right */ + return 1; + }, + checkForBlocked = false, + ignoreTerrain = true, + }; + + foreach (var t in Footprint.Tiles(buildingName, bi, position)) search.AddInitialCell(t); + + return world.PathFinder.FindPath(search).Count != 0; + } + } +}