diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index 6f3df053c2..dbc8176fee 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -311,6 +311,29 @@ namespace OpenRa.Game return CanPlaceBuilding(building, xy, null, adjust); } + public static bool IsCloseEnoughToBase(Player p, UnitInfo.BuildingInfo bi, int2 position) + { + var maxDistance = bi.Adjacent + 2; /* real-ra is weird. this is 1 GAP. */ + + var search = new PathSearch() + { + heuristic = loc => + { + var b = Game.BuildingInfluence.GetBuildingAt(loc); + if (b != null && b.Owner == p) 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(bi, position)) search.AddInitialCell(t); + + return Game.PathFinder.FindPath(search).Count != 0; + } + public static void BuildUnit(Player player, string name) { var producerTypes = Rules.TechTree.UnitBuiltAt( Rules.UnitInfo[ name ] ); diff --git a/OpenRa.Game/PathSearch.cs b/OpenRa.Game/PathSearch.cs index ce63bde242..86d2646f81 100755 --- a/OpenRa.Game/PathSearch.cs +++ b/OpenRa.Game/PathSearch.cs @@ -15,6 +15,7 @@ namespace OpenRa.Game public UnitMovementType umt; Func customBlock; public bool checkForBlocked; + public bool ignoreTerrain; public PathSearch() { @@ -39,22 +40,31 @@ namespace OpenRa.Game if( cellInfo[ newHere.X, newHere.Y ].Seen ) continue; - if( passableCost[ (int)umt ][ newHere.X, newHere.Y ] == float.PositiveInfinity ) - continue; - if( !Game.BuildingInfluence.CanMoveHere( newHere ) ) - continue; + if (ignoreTerrain) + { + if (!Game.map.IsInMap(newHere.X, newHere.Y)) continue; + } + else + { + if (passableCost[(int)umt][newHere.X, newHere.Y] == float.PositiveInfinity) + continue; + if (!Game.BuildingInfluence.CanMoveHere(newHere)) + continue; + if (Game.map.IsOverlaySolid(newHere)) + continue; + } if( checkForBlocked && Game.UnitInfluence.GetUnitAt( newHere ) != null ) continue; if (customBlock != null && customBlock(newHere)) continue; - if (Game.map.IsOverlaySolid(newHere)) - continue; + var est = heuristic( newHere ); if( est == float.PositiveInfinity ) continue; - float cellCost = ( ( d.X * d.Y != 0 ) ? 1.414213563f : 1.0f ) * passableCost[ (int)umt ][ newHere.X, newHere.Y ]; + float cellCost = ( ( d.X * d.Y != 0 ) ? 1.414213563f : 1.0f ) * + (ignoreTerrain ? 1 : passableCost[ (int)umt ][ newHere.X, newHere.Y ]); float newCost = cellInfo[ p.Location.X, p.Location.Y ].MinCost + cellCost; if( newCost >= cellInfo[ newHere.X, newHere.Y ].MinCost ) diff --git a/OpenRa.Game/PlaceBuilding.cs b/OpenRa.Game/PlaceBuilding.cs index ff9803ac3e..5b49e337fe 100644 --- a/OpenRa.Game/PlaceBuilding.cs +++ b/OpenRa.Game/PlaceBuilding.cs @@ -24,11 +24,9 @@ namespace OpenRa.Game if( !Game.CanPlaceBuilding( Building, xy, true ) ) yield break; - var maxDistance = Building.Adjacent + 2; /* real-ra is weird. this is 1 GAP. */ - if( !Footprint.Tiles( Building, xy ).Any( - t => Game.GetDistanceToBase( t, Owner ) < maxDistance ) ) + if (!Game.IsCloseEnoughToBase(Owner, Building, xy)) yield break; - + yield return OpenRa.Game.Order.PlaceBuilding( Owner, xy, Building.Name ); } else // rmb diff --git a/OpenRa.Game/UiOverlay.cs b/OpenRa.Game/UiOverlay.cs index 8c93e44060..e8a80c2375 100644 --- a/OpenRa.Game/UiOverlay.cs +++ b/OpenRa.Game/UiOverlay.cs @@ -46,22 +46,10 @@ namespace OpenRa.Game public void DrawBuildingGrid( UnitInfo.BuildingInfo bi ) { var position = Game.controller.MousePosition.ToInt2(); - - var maxDistance = bi.Adjacent + 2; /* real-ra is weird. this is 1 GAP. */ - - //if( ShowBuildDebug ) - // for( var j = 0 ; j < 128 ; j++ ) - // for( var i = 0 ; i < 128 ; i++ ) - // if( Game.GetDistanceToBase( new int2( i, j ), Game.LocalPlayer ) < maxDistance ) - // if( Game.IsCellBuildable( new int2( i, j ), bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel ) ) - // if( !Game.map.ContainsResource( new int2( i, j ) ) ) - // spriteRenderer.DrawSprite( unitDebug, Game.CellSize * new float2( i, j ), 0 ); - - var tooFarFromBase = !Footprint.Tiles( bi, position ).Any( - t => Game.GetDistanceToBase( t, Game.LocalPlayer ) < maxDistance ); - + var isCloseEnough = Game.IsCloseEnoughToBase(Game.LocalPlayer, bi, position); + foreach( var t in Footprint.Tiles( bi, position ) ) - spriteRenderer.DrawSprite( ( !tooFarFromBase && Game.IsCellBuildable( t, bi.WaterBound + spriteRenderer.DrawSprite( ( isCloseEnough && Game.IsCellBuildable( t, bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel ) && !Game.map.ContainsResource( t ) ) ? buildOk : buildBlocked, Game.CellSize * t, 0 );