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; return null;
var loc = mi.Location + Game.viewport.Location; 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>()) if (underCursor != null && !underCursor.traits.Contains<Selectable>())
underCursor = null; underCursor = null;

View File

@@ -15,8 +15,8 @@ namespace OpenRa
{ {
var targetTile = ((1f / Game.CellSize) * loc.ToFloat2()).ToInt2(); var targetTile = ((1f / Game.CellSize) * loc.ToFloat2()).ToInt2();
var isWater = Game.IsWater(targetTile); var isWater = Game.world.IsWater(targetTile);
var hitWater = Game.IsCellBuildable(targetTile, UnitMovementType.Float); var hitWater = Game.world.IsCellBuildable(targetTile, UnitMovementType.Float);
if (warhead.Explosion != 0) if (warhead.Explosion != 0)
Game.world.AddFrameEndTask( Game.world.AddFrameEndTask(
@@ -31,7 +31,7 @@ namespace OpenRa
if (warhead.Ore) Ore.Destroy(targetTile.X, targetTile.Y); if (warhead.Ore) Ore.Destroy(targetTile.X, targetTile.Y);
var maxSpread = GetMaximumSpread(weapon, warhead); var maxSpread = GetMaximumSpread(weapon, warhead);
var hitActors = Game.FindUnitsInCircle(loc, maxSpread); var hitActors = Game.world.FindUnitsInCircle(loc, maxSpread);
foreach (var victim in hitActors) foreach (var victim in hitActors)
victim.InflictDamage(firedBy, (int)GetDamageToInflict(victim, loc, weapon, warhead), warhead); victim.InflictDamage(firedBy, (int)GetDamageToInflict(victim, loc, weapon, warhead), warhead);

View File

@@ -95,7 +95,7 @@ namespace OpenRa
{ {
if (orderGenerator is UnitOrderGenerator) 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); CombineSelection(newSelection, mi.Modifiers.HasModifier(Modifiers.Shift), dragStart == xy);
} }

View File

@@ -208,130 +208,9 @@ namespace OpenRa
renderer.PaletteTexture = palette.Texture; 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 SharedRandom = new Random(0); /* for things that require sync */
public static Random CosmeticRandom = new Random(); /* for things that are just fluff */ 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) public static void SyncLobbyInfo(string data)
{ {
var session = new Session(); 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 + b + c, a + c, Color.White, Color.White);
lineRenderer.DrawLine(a, 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); DrawSelectionBox(u, Color.Yellow, false);
} }

View File

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

View File

@@ -28,7 +28,7 @@ namespace OpenRa.Orders
if (mi.Button == MouseButton.Left) if (mi.Button == MouseButton.Left)
{ {
var loc = mi.Location + Game.viewport.Location; 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 .Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Chronoshiftable>() && a.traits.Contains<Chronoshiftable>()
&& a.traits.Contains<Selectable>()).FirstOrDefault(); && a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -28,7 +28,7 @@ namespace OpenRa.Orders
if (mi.Button == MouseButton.Left) if (mi.Button == MouseButton.Left)
{ {
var loc = mi.Location + Game.viewport.Location; 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 .Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<IronCurtainable>() && a.traits.Contains<IronCurtainable>()
&& a.traits.Contains<Selectable>()).FirstOrDefault(); && a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -28,8 +28,8 @@ namespace OpenRa.Orders
{ {
if (mi.Button == MouseButton.Left) if (mi.Button == MouseButton.Left)
{ {
if (!Game.CanPlaceBuilding( Building, BuildingInfo, xy, null, true) if (!Game.world.CanPlaceBuilding( Building, BuildingInfo, xy, null, true)
|| !Game.IsCloseEnoughToBase(Producer.Owner, Building, BuildingInfo, xy)) || !Game.world.IsCloseEnoughToBase(Producer.Owner, Building, BuildingInfo, xy))
{ {
Sound.Play("nodeply1.aud"); Sound.Play("nodeply1.aud");
yield break; yield break;

View File

@@ -22,7 +22,7 @@ namespace OpenRa.Orders
if (mi.Button == MouseButton.Left) if (mi.Button == MouseButton.Left)
{ {
var loc = mi.Location + Game.viewport.Location; 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 .Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>() && a.traits.Contains<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault(); && a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -22,7 +22,7 @@ namespace OpenRa.Orders
if (mi.Button == MouseButton.Left) if (mi.Button == MouseButton.Left)
{ {
var loc = mi.Location + Game.viewport.Location; 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 .Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>() && a.traits.Contains<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault(); && a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -22,7 +22,7 @@ namespace OpenRa.Orders
if (mi.Button == MouseButton.Left) if (mi.Button == MouseButton.Left)
{ {
var loc = mi.Location + Game.viewport.Location; 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 .Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>() && a.traits.Contains<Building>()
&& a.traits.Contains<Selectable>()).FirstOrDefault(); && a.traits.Contains<Selectable>()).FirstOrDefault();

View File

@@ -50,7 +50,7 @@ namespace OpenRa.Orders
.FirstOrDefault(a => a != null); .FirstOrDefault(a => a != null);
return c ?? return c ??
(Game.SelectActorsInBox(Game.CellSize * p, (Game.world.SelectActorsInBox(Game.CellSize * p,
Game.CellSize * p).Any() Game.CellSize * p).Any()
? Cursor.Select : Cursor.Default); ? Cursor.Select : Cursor.Default);
} }
@@ -70,7 +70,7 @@ namespace OpenRa.Orders
return Cursor.MoveBlocked; return Cursor.MoveBlocked;
case "DeployMcv": case "DeployMcv":
var factBuildingInfo = Rules.ActorInfo["fact"].Traits.Get<BuildingInfo>(); 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; return Cursor.Deploy;
else else
return Cursor.DeployBlocked; return Cursor.DeployBlocked;

View File

@@ -40,8 +40,8 @@ namespace OpenRa
{ {
using( new PerfSample( "find_unit_path_multiple_src" ) ) using( new PerfSample( "find_unit_path_multiple_src" ) )
{ {
var tilesInRange = Game.FindTilesInCircle(target, range) var tilesInRange = Game.world.FindTilesInCircle(target, range)
.Where( t => Game.IsCellBuildable( t, umt ) ); .Where( t => Game.world.IsCellBuildable( t, umt ) );
var path = FindPath( PathSearch.FromPoints( tilesInRange, src, umt, false ).WithCustomBlocker(AvoidUnitsNear(src, 4))); var path = FindPath( PathSearch.FromPoints( tilesInRange, src, umt, false ).WithCustomBlocker(AvoidUnitsNear(src, 4)));
path.Reverse(); 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 // 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; continue;
if (customBlock != null && customBlock(newHere)) if (customBlock != null && customBlock(newHere))

View File

@@ -81,7 +81,7 @@ namespace OpenRa
public void Explore(Actor a) public void Explore(Actor a)
{ {
foreach (var t in Game.FindTilesInCircle( foreach (var t in Game.world.FindTilesInCircle(
(1f / Game.CellSize * a.CenterLocation).ToInt2(), (1f / Game.CellSize * a.CenterLocation).ToInt2(),
a.Info.Traits.Get<OwnedActorInfo>().Sight)) a.Info.Traits.Get<OwnedActorInfo>().Sight))
{ {

View File

@@ -16,7 +16,7 @@ namespace OpenRa.Traits.Activities
if (unit.Altitude == 0) if (unit.Altitude == 0)
return NextActivity; 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 return this; // fail to land if no space
--unit.Altitude; --unit.Altitude;

View File

@@ -63,7 +63,7 @@ namespace OpenRa.Traits.Activities
// Cannot enter a cell if any unit inside is uncrushable // Cannot enter a cell if any unit inside is uncrushable
// This will need to be updated for multiple-infantry-in-a-cell // 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 ) public IActivity Tick( Actor self )

View File

@@ -20,7 +20,7 @@ namespace OpenRa.Traits.Activities
{ {
if (!limitedAmmo.GiveAmmo()) return NextActivity; 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>()); .FirstOrDefault(a => a.traits.Contains<RenderBuilding>());
if (hostBuilding != null) if (hostBuilding != null)

View File

@@ -32,7 +32,7 @@ namespace OpenRa.Traits.Activities
if (self.Health == hp) if (self.Health == hp)
return NextActivity; 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>()); .FirstOrDefault(a => a.traits.Contains<RenderBuilding>());
if (hostBuilding != null) if (hostBuilding != null)

View File

@@ -19,7 +19,7 @@ namespace OpenRa.Traits.Activities
for (var i = -1; i < 2; i++) for (var i = -1; i < 2; i++)
for (var j = -1; j < 2; j++) for (var j = -1; j < 2; j++)
if ((i != 0 || j != 0) && if ((i != 0 || j != 0) &&
Game.IsCellBuildable(self.Location + new int2(i, j), Game.world.IsCellBuildable(self.Location + new int2(i, j),
UnitMovementType.Foot)) UnitMovementType.Foot))
return self.Location + new int2(i, j); return self.Location + new int2(i, j);

View File

@@ -43,7 +43,7 @@ namespace OpenRa.Traits
Actor ChooseTarget(Actor self, float range) 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 return inRange
.Where(a => a.Owner == self.Owner && a != self) /* todo: one day deal with friendly players */ .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) 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 return inRange
.Where(a => a.Owner != null && a.Owner != self.Owner) /* todo: one day deal with friendly players */ .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 // force-move
if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null; 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); return new Order("Move", self, null, xy, null);
@@ -57,7 +57,7 @@ namespace OpenRa.Traits
{ {
if (actor == self) continue; if (actor == self) continue;
if (!Game.IsActorCrushableByActor(actor, self)) if (!Game.world.IsActorCrushableByActor(actor, self))
{ {
crushable = false; crushable = false;
break; break;

View File

@@ -28,7 +28,7 @@ namespace OpenRa.Traits
// Gap Generator building; powered down // Gap Generator building; powered down
return (self.traits.Contains<Building>() && self.traits.Get<Building>().Disabled) return (self.traits.Contains<Building>() && self.traits.Get<Building>().Disabled)
? new int2[] {} ? 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" ) if( order.OrderString == "DeployMcv" )
{ {
var factBuildingInfo = Rules.ActorInfo[ "fact" ].Traits.Get<BuildingInfo>(); 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.CancelActivity();
self.QueueActivity( new Turn( 96 ) ); self.QueueActivity( new Turn( 96 ) );

View File

@@ -59,7 +59,7 @@ namespace OpenRa.Traits
{ {
// force-move // force-move
if (!mi.Modifiers.HasModifier(Modifiers.Alt)) return null; 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 */ 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 (actor == self) continue;
if (!Game.IsActorCrushableByActor(actor, self)) if (!Game.world.IsActorCrushableByActor(actor, self))
{ {
crushable = false; crushable = false;
break; break;

View File

@@ -20,7 +20,7 @@ namespace OpenRa.Traits
for (var j = min.Y; j <= max.Y; j++) for (var j = min.Y; j <= max.Y; j++)
for (var i = min.X; i <= max.X; i++) 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 new int2(i, j);
return null; return null;

View File

@@ -46,10 +46,10 @@ namespace OpenRa
public void DrawBuildingGrid( string name, BuildingInfo bi ) public void DrawBuildingGrid( string name, BuildingInfo bi )
{ {
var position = Game.controller.MousePosition.ToInt2(); 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 ) ) 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 ) ) ? UnitMovementType.Float : UnitMovementType.Wheel ) && !Game.world.Map.ContainsResource( t ) )
? buildOk : buildBlocked, Game.CellSize * t, 0 ); ? 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.) // 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 // 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) if (crusher != null)
{ {
Log.Write("{0} crushes {1}", crusher.Info.Name, a.Info.Name); 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;
}
}
}