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: