moved helper functions out of Game, into WorldUtils

This commit is contained in:
Bob
2010-01-18 02:46:22 +13:00
parent 6f0c2c5a5d
commit ab1abee843
31 changed files with 176 additions and 163 deletions

View File

@@ -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<Selectable>())
underCursor = null;

View File

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

View File

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

View File

@@ -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<IMovement>().GetMovementType());
}
public static bool IsActorPathableToCrush(Actor a, UnitMovementType umt)
{
return a != null &&
a.traits.WithInterface<ICrushable>()
.Any(c => c.IsPathableCrush(umt, a.Owner));
}
public static bool IsActorCrushableByMovementType(Actor a, UnitMovementType umt)
{
return a != null &&
a.traits.WithInterface<ICrushable>()
.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<Actor> 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<Actor> 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<int2> 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<Actor> SelectActorsInBox(float2 a, float2 b)
{
return FindUnits(a, b)
.Where( x => x.traits.Contains<Selectable>() )
.GroupBy(x => (x.Owner == LocalPlayer) ? x.Info.Traits.Get<SelectableInfo>().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<BuildingInfo>().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();

View File

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

View File

@@ -7,7 +7,7 @@
<ProjectGuid>{0DFB103F-2962-400F-8C6D-E2C28CCBA633}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>OpenRa.Game</RootNamespace>
<RootNamespace>OpenRa</RootNamespace>
<AssemblyName>OpenRa.Game</AssemblyName>
<FileUpgradeFlags>
</FileUpgradeFlags>
@@ -274,6 +274,7 @@
<Compile Include="UnitInfluenceMap.cs" />
<Compile Include="Orders\UnitOrderGenerator.cs" />
<Compile Include="World.cs" />
<Compile Include="WorldUtils.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRa.FileFormats\OpenRa.FileFormats.csproj">

View File

@@ -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<Chronoshiftable>()
&& a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -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<IronCurtainable>()
&& a.traits.Contains<Selectable>()).FirstOrDefault();

View File

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

View File

@@ -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<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -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<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -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<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault();

View File

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

View File

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

View File

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

View File

@@ -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<OwnedActorInfo>().Sight))
{
a.Info.Traits.Get<OwnedActorInfo>().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)

View File

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

View File

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

View File

@@ -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<RenderBuilding>());
if (hostBuilding != null)

View File

@@ -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<RenderBuilding>());
if (hostBuilding != null)

View File

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

View File

@@ -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 */

View File

@@ -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 */

View File

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

View File

@@ -28,7 +28,7 @@ namespace OpenRa.Traits
// Gap Generator building; powered down
return (self.traits.Contains<Building>() && self.traits.Get<Building>().Disabled)
? new int2[] {}
: Game.FindTilesInCircle(self.Location, range);
: Game.world.FindTilesInCircle(self.Location, range);
}
}
}

View File

@@ -25,7 +25,7 @@ namespace OpenRa.Traits
if( order.OrderString == "DeployMcv" )
{
var factBuildingInfo = Rules.ActorInfo[ "fact" ].Traits.Get<BuildingInfo>();
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 ) );

View File

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

View File

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

View File

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

View File

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

133
OpenRa.Game/WorldUtils.cs Executable file
View File

@@ -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<IMovement>().GetMovementType());
}
public static bool IsActorPathableToCrush(this World world, Actor a, UnitMovementType umt)
{
return a != null &&
a.traits.WithInterface<ICrushable>()
.Any(c => c.IsPathableCrush(umt, a.Owner));
}
public static bool IsActorCrushableByMovementType(this World world, Actor a, UnitMovementType umt)
{
return a != null &&
a.traits.WithInterface<ICrushable>()
.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<Actor> 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<Actor> 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<int2> 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<Actor> SelectActorsInBox(this World world, float2 a, float2 b)
{
return world.FindUnits(a, b)
.Where( x => x.traits.Contains<Selectable>() )
.GroupBy(x => (x.Owner == Game.LocalPlayer) ? x.Info.Traits.Get<SelectableInfo>().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<BuildingInfo>().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;
}
}
}