diff --git a/OpenRA.Game/GameRules/UserSettings.cs b/OpenRA.Game/GameRules/UserSettings.cs
index 44a51a5bb8..386ac6478c 100644
--- a/OpenRA.Game/GameRules/UserSettings.cs
+++ b/OpenRA.Game/GameRules/UserSettings.cs
@@ -23,8 +23,8 @@ namespace OpenRA.GameRules
public class UserSettings
{
// Debug settings
- public bool UnitDebug = false;
- public bool PathDebug = false;
+ public bool UnitDebug = true;
+ public bool PathDebug = true;
public bool PerfDebug = true;
public bool IndexDebug = false;
public bool RecordSyncReports = true;
diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj
index dd0b829c82..b81e6480f5 100755
--- a/OpenRA.Game/OpenRA.Game.csproj
+++ b/OpenRA.Game/OpenRA.Game.csproj
@@ -242,6 +242,8 @@
+
+
diff --git a/OpenRA.Game/PathFinder.cs b/OpenRA.Game/PathFinder.cs
index 1384aaa0dc..29ae47f370 100644
--- a/OpenRA.Game/PathFinder.cs
+++ b/OpenRA.Game/PathFinder.cs
@@ -42,7 +42,7 @@ namespace OpenRA
for( int x = 0 ; x < map.MapSize.X ; x++ )
for( int y = 0 ; y < map.MapSize.Y ; y++ )
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Fly; umt++ )
- passableCost[(int)umt][ x, y ] = (umt == UnitMovementType.Fly) ? 0f : ( world.Map.IsInMap( x, y ) )
+ passableCost[(int)umt][ x, y ] = (umt == UnitMovementType.Fly) ? 1f : ( world.Map.IsInMap( x, y ) )
? (float)Rules.TerrainTypes[world.TileSet.GetTerrainType(world.Map.MapTiles[x, y])]
.GetCost(umt)
: float.PositiveInfinity;
diff --git a/OpenRA.Game/PathSearch.cs b/OpenRA.Game/PathSearch.cs
index 9c56a9d061..814555d5cc 100755
--- a/OpenRA.Game/PathSearch.cs
+++ b/OpenRA.Game/PathSearch.cs
@@ -33,7 +33,6 @@ namespace OpenRA
public CellInfo[ , ] cellInfo;
public PriorityQueue queue;
public Func heuristic;
- public UnitMovementType umt;
Func customBlock;
public bool checkForBlocked;
public Actor ignoreBuilding;
@@ -48,9 +47,6 @@ namespace OpenRA
world = self.World;
cellInfo = InitCellInfo();
queue = new PriorityQueue();
-
- umt = self.traits.Get().GetMovementType();
-
buildingInfluence = world.WorldActor.traits.Get();
}
@@ -88,11 +84,13 @@ namespace OpenRA
public int2 Expand( World world, float[][ , ] passableCost )
{
+ var umt = self.traits.Get().GetMovementType();
+
var p = queue.Pop();
cellInfo[ p.Location.X, p.Location.Y ].Seen = true;
var thisCost = passableCost[(int)umt][p.Location.X, p.Location.Y]*
- world.WorldActor.traits.WithInterface().Aggregate(1f, (a, x) => a * x.GetCost(p.Location,umt));
+ world.WorldActor.traits.WithInterface().Aggregate(1f, (a, x) => a * x.GetCost(p.Location,self));
if (thisCost == float.PositiveInfinity)
return p.Location;
@@ -107,7 +105,7 @@ namespace OpenRA
var costHere = passableCost[(int)umt][newHere.X, newHere.Y]*
world.WorldActor.traits.WithInterface()
- .Aggregate(1f, (a, x) => a * x.GetCost(newHere,umt));
+ .Aggregate(1f, (a, x) => a * x.GetCost(newHere,self));
if (costHere == float.PositiveInfinity)
continue;
diff --git a/OpenRA.Game/Traits/Hazardous.cs b/OpenRA.Game/Traits/Hazardous.cs
new file mode 100644
index 0000000000..615472cb64
--- /dev/null
+++ b/OpenRA.Game/Traits/Hazardous.cs
@@ -0,0 +1,52 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System.Linq;
+using System.Collections.Generic;
+
+namespace OpenRA.Traits
+{
+ class AntiAirInfo : ITraitInfo
+ {
+ public readonly float Badness = 1000f;
+ public object Create( ActorInitializer init ) { return new AntiAir( init.self ); }
+ }
+
+ class AntiAir : IProvideHazard
+ {
+ public AntiAir(Actor self)
+ {
+ self.World.WorldActor.traits.Get().Add( self, this );
+ }
+
+ public IEnumerable HazardCells(Actor self)
+ {
+ var info = self.Info.Traits.Get();
+ return self.World.FindTilesInCircle(self.Location, (int)self.GetPrimaryWeapon().Range).Select(
+ t => new HazardLayer.Hazard(){location = t, type = "antiair", intensity = info.Badness});
+ }
+ }
+
+ class AvoidsAAInfo : TraitInfo {}
+ class AvoidsAA : IAvoidHazard
+ {
+ public string Type { get { return "antiair"; } }
+ }
+}
diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs
index b694e60eca..e1ee021cdb 100644
--- a/OpenRA.Game/Traits/TraitsInterfaces.cs
+++ b/OpenRA.Game/Traits/TraitsInterfaces.cs
@@ -22,6 +22,7 @@ using System.Collections.Generic;
using System.Drawing;
using OpenRA.GameRules;
using OpenRA.Graphics;
+using OpenRA.Traits;
namespace OpenRA.Traits
{
@@ -53,11 +54,13 @@ namespace OpenRA.Traits
public interface INotifyCapture { void OnCapture(Actor self, Actor captor); }
public interface IAcceptSpy { void OnInfiltrate(Actor self, Actor spy); }
public interface INotifyEnterCell { void OnEnterCell(Actor self, int2 cell); }
+ public interface IProvideHazard { IEnumerable HazardCells(Actor self); }
+ public interface IAvoidHazard { string Type { get; } }
public interface ICustomTerrain
{
- float GetCost(int2 p, UnitMovementType umt);
- float GetSpeedModifier(int2 p, UnitMovementType umt);
+ float GetCost(int2 p, Actor forActor);
+ float GetSpeedModifier(int2 p, Actor forActor);
}
public interface IDisable { bool Disabled { get; } }
diff --git a/OpenRA.Game/Traits/Util.cs b/OpenRA.Game/Traits/Util.cs
index f34cb5a14f..f87bb9391c 100755
--- a/OpenRA.Game/Traits/Util.cs
+++ b/OpenRA.Game/Traits/Util.cs
@@ -149,7 +149,7 @@ namespace OpenRA.Traits
var tt = self.World.GetTerrainType(self.Location);
terrain = Rules.TerrainTypes[tt].GetSpeedModifier(umt)*self.World.WorldActor.traits
.WithInterface()
- .Select(t => t.GetSpeedModifier(self.Location, umt))
+ .Select(t => t.GetSpeedModifier(self.Location, self))
.Product();
}
var modifier = self.traits
diff --git a/OpenRA.Game/Traits/World/AircraftInfluence.cs b/OpenRA.Game/Traits/World/AircraftInfluence.cs
new file mode 100644
index 0000000000..dcc23abf64
--- /dev/null
+++ b/OpenRA.Game/Traits/World/AircraftInfluence.cs
@@ -0,0 +1,97 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using OpenRA.FileFormats;
+
+namespace OpenRA.Traits
+{
+ public class AircraftInfluenceInfo : ITraitInfo
+ {
+ public object Create( ActorInitializer init ) { return new AircraftInfluence( init.world ); }
+ }
+
+ public class AircraftInfluence : ITick
+ {
+ List[,] influence;
+ Map map;
+
+ public AircraftInfluence( World world )
+ {
+ map = world.Map;
+ influence = new List[world.Map.MapSize.X, world.Map.MapSize.Y];
+ for (int i = 0; i < world.Map.MapSize.X; i++)
+ for (int j = 0; j < world.Map.MapSize.Y; j++)
+ influence[ i, j ] = new List();
+
+ world.ActorRemoved += a => Remove( a, a.traits.GetOrDefault() );
+ }
+
+ public void Tick( Actor self )
+ {
+ SanityCheck( self );
+ }
+
+ [Conditional( "SANITY_CHECKS" )]
+ void SanityCheck( Actor self )
+ {
+ for( int x = 0 ; x < self.World.Map.MapSize.X ; x++ )
+ for( int y = 0 ; y < self.World.Map.MapSize.Y ; y++ )
+ if( influence[ x, y ] != null )
+ foreach (var a in influence[ x, y ])
+ if (!a.traits.Get().OccupiedAirCells().Contains( new int2( x, y ) ) )
+ throw new InvalidOperationException( "AIM: Sanity check failed A" );
+
+ foreach( var t in self.World.Queries.WithTraitMultiple() )
+ foreach( var cell in t.Trait.OccupiedAirCells() )
+ if (!influence[cell.X, cell.Y].Contains(t.Actor))
+ throw new InvalidOperationException( "AIM: Sanity check failed B" );
+ }
+
+ Actor[] noActors = { };
+ public IEnumerable GetUnitsAt( int2 a )
+ {
+ if (!map.IsInMap(a)) return noActors;
+ return influence[ a.X, a.Y ];
+ }
+
+ public void Add( Actor self, IOccupyAir unit )
+ {
+ foreach( var c in unit.OccupiedAirCells() )
+ influence[c.X, c.Y].Add(self);
+ }
+
+ public void Remove( Actor self, IOccupyAir unit )
+ {
+ if (unit != null)
+ foreach (var c in unit.OccupiedAirCells())
+ influence[c.X, c.Y].Remove(self);
+ }
+
+ public void Update(Actor self, IOccupyAir unit)
+ {
+ Remove(self, unit);
+ if (!self.IsDead) Add(self, unit);
+ }
+ }
+}
diff --git a/OpenRA.Game/Traits/World/HazardLayer.cs b/OpenRA.Game/Traits/World/HazardLayer.cs
new file mode 100644
index 0000000000..952eca497c
--- /dev/null
+++ b/OpenRA.Game/Traits/World/HazardLayer.cs
@@ -0,0 +1,99 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using OpenRA.FileFormats;
+
+namespace OpenRA.Traits
+{
+ public class HazardLayerInfo : ITraitInfo
+ {
+ public object Create( ActorInitializer init ) { return new HazardLayer( init.world ); }
+ }
+
+ public class HazardLayer : ICustomTerrain
+ {
+ List>[,] hazards;
+ Map map;
+
+ public HazardLayer( World world )
+ {
+ //System.Console.WriteLine("Created HazardLayer");
+ map = world.Map;
+ hazards = new List>[world.Map.MapSize.X, world.Map.MapSize.Y];
+ for (int i = 0; i < world.Map.MapSize.X; i++)
+ for (int j = 0; j < world.Map.MapSize.Y; j++)
+ hazards[ i, j ] = new List>();
+
+ world.ActorRemoved += a => Remove( a, a.traits.GetOrDefault() );
+ }
+
+
+ public float GetSpeedModifier(int2 p, Actor forActor)
+ {
+ return 1f;
+ }
+
+ public float GetCost(int2 p, Actor forActor)
+ {
+ //System.Console.WriteLine("GetCost for {0}", forActor.Info.Name);
+
+ var avoid = forActor.traits.WithInterface().Select(h => h.Type).ToList();
+ var intensity = hazards[p.X,p.Y].Aggregate(1f,(a,b) => a + (avoid.Contains(b.Second.type) ? b.Second.intensity : 0f));
+ //System.Console.WriteLine("Avoid {0} cost {1}", avoid.Aggregate("",(a,b) => a+","+b), intensity);
+
+ return intensity;
+ }
+
+ public void Add( Actor self, IProvideHazard hazard )
+ {
+ //System.Console.WriteLine("Adding hazard {0}", self.Info.Name);
+
+ foreach( var h in hazard.HazardCells(self) )
+ {
+ // System.Console.WriteLine("\t{0} {1} {2}", h.location, h.type, h.intensity);
+ hazards[h.location.X, h.location.Y].Add(Pair.New(self, h));
+ }
+ }
+
+ public void Remove( Actor self, IProvideHazard hazard )
+ {
+ if (hazard != null)
+ foreach (var h in hazard.HazardCells(self))
+ hazards[h.location.X, h.location.Y].Remove(Pair.New(self,h));
+ }
+
+ public void Update(Actor self, IProvideHazard hazard)
+ {
+ Remove(self, hazard);
+ if (!self.IsDead) Add(self, hazard);
+ }
+
+ public struct Hazard
+ {
+ public int2 location;
+ public string type;
+ public float intensity;
+ }
+ }
+}
diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs
index 642204528d..002c698535 100644
--- a/OpenRA.Game/Traits/World/ResourceLayer.cs
+++ b/OpenRA.Game/Traits/World/ResourceLayer.cs
@@ -93,17 +93,21 @@ namespace OpenRA.Traits
content[x, y].density = GetIdealDensity(x, y);
}
- public float GetSpeedModifier(int2 p, UnitMovementType umt)
+ public float GetSpeedModifier(int2 p, Actor forActor)
{
if (content[p.X,p.Y].type == null)
return 1.0f;
+
+ var umt = forActor.traits.Get().GetMovementType();
return content[p.X,p.Y].type.GetSpeedModifier(umt);
}
- public float GetCost(int2 p,UnitMovementType umt)
+ public float GetCost(int2 p, Actor forActor)
{
if (content[p.X,p.Y].type == null)
return 1.0f;
+
+ var umt = forActor.traits.Get().GetMovementType();
return content[p.X,p.Y].type.GetCost(umt);
}
diff --git a/OpenRA.Mods.Cnc/MobileAir.cs b/OpenRA.Mods.Cnc/MobileAir.cs
new file mode 100644
index 0000000000..dbd2e0f5dc
--- /dev/null
+++ b/OpenRA.Mods.Cnc/MobileAir.cs
@@ -0,0 +1,100 @@
+#region Copyright & License Information
+/*
+ * Copyright 2007,2009,2010 Chris Forbes, Robert Pepperell, Matthew Bowra-Dean, Paul Chote, Alli Witheford.
+ * This file is part of OpenRA.
+ *
+ * OpenRA is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * OpenRA is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with OpenRA. If not, see .
+ */
+#endregion
+
+using System.Collections.Generic;
+using System.Linq;
+using OpenRA.GameRules;
+using OpenRA.Traits;
+
+namespace OpenRA.Traits
+{
+ public class MobileAirInfo : MobileInfo
+ {
+ public readonly int CruiseAltitude = 20;
+ public readonly float InstabilityMagnitude = 2.0f;
+ public readonly int InstabilityTicks = 5;
+ public readonly bool LandWhenIdle = true;
+
+ public override object Create(ActorInitializer init) { return new MobileAir(init, this); }
+ }
+
+ public class MobileAir : Mobile, ITick, IOccupyAir
+ {
+ MobileAirInfo Info;
+ public MobileAir (ActorInitializer init, MobileAirInfo info)
+ : base(init)
+ {
+ Info = info;
+ }
+
+ public override void AddInfluence()
+ {
+ self.World.WorldActor.traits.Get().Add( self, this );
+ }
+
+ public override void RemoveInfluence()
+ {
+ self.World.WorldActor.traits.Get().Remove( self, this );
+ }
+
+ public override bool CanEnterCell(int2 p, Actor ignoreBuilding, bool checkTransientActors)
+ {
+ if (!checkTransientActors)
+ return true;
+
+ return self.World.WorldActor.traits.Get().GetUnitsAt(p).Count() == 0;
+ }
+
+ public override IEnumerable OccupiedCells()
+ {
+ // Todo: do the right thing when landed
+ return new int2[] {};
+ }
+
+ public int2 TopLeft { get { return toCell; } }
+
+ public IEnumerable OccupiedAirCells()
+ {
+ return (fromCell == toCell)
+ ? new[] { fromCell }
+ : CanEnterCell(toCell)
+ ? new[] { toCell }
+ : new[] { fromCell, toCell };
+ }
+
+ int offsetTicks = 0;
+ public void Tick(Actor self)
+ {
+ var unit = self.traits.Get();
+ //if (unit.Altitude <= 0)
+ // return;
+
+ if (unit.Altitude < Info.CruiseAltitude)
+ unit.Altitude++;
+
+ if (--offsetTicks <= 0)
+ {
+ self.CenterLocation += Info.InstabilityMagnitude * self.World.SharedRandom.Gauss2D(5);
+ unit.Altitude += (int)(Info.InstabilityMagnitude * self.World.SharedRandom.Gauss1D(5));
+ offsetTicks = Info.InstabilityTicks;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenRA.Mods.RA/BridgeLayer.cs b/OpenRA.Mods.RA/BridgeLayer.cs
index 3a6823329f..e0ab1e91dc 100644
--- a/OpenRA.Mods.RA/BridgeLayer.cs
+++ b/OpenRA.Mods.RA/BridgeLayer.cs
@@ -90,14 +90,17 @@ namespace OpenRA.Mods.RA
}
}
- public float GetCost(int2 p, UnitMovementType umt)
+ public float GetCost(int2 p, Actor forActor)
{
+ var umt = forActor.traits.Get().GetMovementType();
if (customTerrain[p.X, p.Y] != null)
return customTerrain[p.X,p.Y].GetCost(p,umt);
return 1f;
}
- public float GetSpeedModifier(int2 p, UnitMovementType umt)
+
+ public float GetSpeedModifier(int2 p, Actor forActor)
{
+ var umt = forActor.traits.Get().GetMovementType();
if (customTerrain[p.X, p.Y] != null)
return customTerrain[p.X,p.Y].GetSpeedModifier(p,umt);
return 1f;
diff --git a/mods/cnc/structures.yaml b/mods/cnc/structures.yaml
index 95388f8e8c..b28fef0d1e 100644
--- a/mods/cnc/structures.yaml
+++ b/mods/cnc/structures.yaml
@@ -519,6 +519,8 @@ SAM:
AttackTurreted:
PrimaryWeapon: Nike
AutoTarget:
+ AntiAir:
+ Badness: 10
-RenderBuilding:
RenderRangeCircle:
diff --git a/mods/cnc/system.yaml b/mods/cnc/system.yaml
index 68c9473bcd..52904f4d2e 100644
--- a/mods/cnc/system.yaml
+++ b/mods/cnc/system.yaml
@@ -48,6 +48,7 @@ World:
BuildingInfluence:
UnitInfluence:
AircraftInfluence:
+ HazardLayer:
# BridgeLoadHook:
Theater@DESERT:
Name:Desert
diff --git a/mods/cnc/vehicles.yaml b/mods/cnc/vehicles.yaml
index 931e42fa05..070273e3a5 100644
--- a/mods/cnc/vehicles.yaml
+++ b/mods/cnc/vehicles.yaml
@@ -407,6 +407,7 @@ TRAN:
Sight: 8
Speed: 15
# Helicopter:
+ AvoidsAA:
MobileAir:
MovementType: Fly
RenderUnitRotor: