diff --git a/OpenRA.FileFormats/Session.cs b/OpenRA.FileFormats/Session.cs index 686c6bba9d..843c1d5088 100644 --- a/OpenRA.FileFormats/Session.cs +++ b/OpenRA.FileFormats/Session.cs @@ -61,7 +61,7 @@ namespace OpenRA.FileFormats public readonly string[] Folders, Packages, LegacyRules, Rules, Sequences, Chrome, Assemblies, ChromeLayout, - Weapons, Voices; + Weapons, Voices, Terrain; public Manifest(string[] mods) { @@ -79,6 +79,7 @@ namespace OpenRA.FileFormats ChromeLayout = YamlList(yaml, "ChromeLayout"); Weapons = YamlList(yaml, "Weapons"); Voices = YamlList(yaml, "Voices"); + Terrain = YamlList(yaml, "Terrain"); } static string[] YamlList(Dictionary ys, string key) { return ys[key].Nodes.Keys.ToArray(); } diff --git a/OpenRA.Game/GameRules/Rules.cs b/OpenRA.Game/GameRules/Rules.cs index 0a4635dee0..c92a487cc0 100755 --- a/OpenRA.Game/GameRules/Rules.cs +++ b/OpenRA.Game/GameRules/Rules.cs @@ -34,6 +34,7 @@ namespace OpenRA public static Dictionary Info; public static Dictionary Weapons; public static Dictionary Voices; + public static Dictionary TerrainTypes; public static void LoadRules(string map, Manifest m) { @@ -48,6 +49,8 @@ namespace OpenRA Info = LoadYamlRules(m.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y)); Weapons = LoadYamlRules(m.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value)); Voices = LoadYamlRules(m.Voices, (k, _) => new VoiceInfo(k.Value)); + TerrainTypes = LoadYamlRules(m.Terrain, (k, _) => new TerrainCost(k.Value)) + .ToDictionary(kv => (TerrainType)Enum.Parse(typeof(TerrainType), kv.Key, true), kv => kv.Value); TechTree = new TechTree(); } diff --git a/OpenRA.Game/TerrainCosts.cs b/OpenRA.Game/GameRules/TerrainCost.cs similarity index 51% rename from OpenRA.Game/TerrainCosts.cs rename to OpenRA.Game/GameRules/TerrainCost.cs index 45a4a0ef17..5510e66a70 100644 --- a/OpenRA.Game/TerrainCosts.cs +++ b/OpenRA.Game/GameRules/TerrainCost.cs @@ -18,10 +18,11 @@ */ #endregion -using OpenRA.Graphics; +using System; using OpenRA.FileFormats; +using OpenRA.Graphics; -namespace OpenRA +namespace OpenRA.GameRules { public enum UnitMovementType : byte { @@ -32,35 +33,26 @@ namespace OpenRA Fly = 4, } - static class TerrainCosts + public class TerrainCost { - static float[][] costs = Util.MakeArray(4, - a => Util.MakeArray(11, b => float.PositiveInfinity)); - - static bool[] buildable = Util.MakeArray(11,b => false); - static TerrainCosts() + public readonly bool Buildable = true; + public readonly float Foot = 0, Track = 0, Wheel = 0, Float = 0; + public readonly bool AcceptSmudge = true; + + public TerrainCost(MiniYaml y) { FieldLoader.Load(this, y); } + + public float GetCost(UnitMovementType umt) { - for( int i = 0 ; i < 11 ; i++ ) + switch (umt) /* todo: make this nice */ { - if( i == 4 ) continue; - var section = Rules.AllRules.GetSection( ( (TerrainType)i ).ToString() ); - for( int j = 0 ; j < 4 ; j++ ) - { - string val = section.GetValue( ( (UnitMovementType)j ).ToString(), "0%" ); - costs[j][i] = 100f / float.Parse(val.Substring(0, val.Length - 1)); - } - buildable[i] = (section.GetValue("Buildable", "no") == "yes"); + case UnitMovementType.Fly: return 1; + case UnitMovementType.Foot: return 1 / Foot; + case UnitMovementType.Wheel: return 1 / Wheel; + case UnitMovementType.Track: return 1 / Track; + case UnitMovementType.Float: return 1 / Float; + default: + throw new InvalidOperationException("wtf?"); } } - - public static bool Buildable(TerrainType r) - { - return buildable[(int)r]; - } - - public static float Cost( UnitMovementType unitMovementType, TerrainType r ) - { - return costs[ (byte)unitMovementType ][ (int)r ]; - } } } diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index a0e3841592..1fbd2e15de 100755 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -188,7 +188,7 @@ - + diff --git a/OpenRA.Game/PathFinder.cs b/OpenRA.Game/PathFinder.cs index 64e94f44fd..e1dda7184a 100644 --- a/OpenRA.Game/PathFinder.cs +++ b/OpenRA.Game/PathFinder.cs @@ -24,6 +24,7 @@ using System.Diagnostics; using System.Linq; using OpenRA.Support; using OpenRA.Traits; +using OpenRA.GameRules; namespace OpenRA { @@ -38,11 +39,12 @@ namespace OpenRA var map = world.Map; for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++) passableCost[(int)umt] = new float[map.MapSize, map.MapSize]; - for( int x = 0 ; x < map.MapSize ; x++ ) - for( int y = 0 ; y < map.MapSize ; y++ ) - for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++ ) - passableCost[(int)umt][ x, y ] = ( world.Map.IsInMap( x, y ) ) - ? (float)TerrainCosts.Cost( umt, world.TileSet.GetTerrainType( world.Map.MapTiles[ x, y ] ) ) + for (int x = 0; x < map.MapSize; x++) + for (int y = 0; y < map.MapSize; y++) + for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++) + passableCost[(int)umt][x, y] = (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 46f73917fb..59182f94f9 100755 --- a/OpenRA.Game/PathSearch.cs +++ b/OpenRA.Game/PathSearch.cs @@ -23,6 +23,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; using OpenRA.Traits; +using OpenRA.GameRules; namespace OpenRA { diff --git a/OpenRA.Game/Traits/Activities/Harvest.cs b/OpenRA.Game/Traits/Activities/Harvest.cs index 597d57d00a..41f5058371 100644 --- a/OpenRA.Game/Traits/Activities/Harvest.cs +++ b/OpenRA.Game/Traits/Activities/Harvest.cs @@ -19,6 +19,7 @@ #endregion using System.Linq; +using OpenRA.GameRules; namespace OpenRA.Traits.Activities { diff --git a/OpenRA.Game/Traits/Activities/HeliLand.cs b/OpenRA.Game/Traits/Activities/HeliLand.cs index 3818214106..a45c2e6180 100644 --- a/OpenRA.Game/Traits/Activities/HeliLand.cs +++ b/OpenRA.Game/Traits/Activities/HeliLand.cs @@ -18,6 +18,7 @@ */ #endregion +using OpenRA.GameRules; namespace OpenRA.Traits.Activities { class HeliLand : IActivity diff --git a/OpenRA.Game/Traits/Activities/UnloadCargo.cs b/OpenRA.Game/Traits/Activities/UnloadCargo.cs index b6b851b288..c76113f1ba 100644 --- a/OpenRA.Game/Traits/Activities/UnloadCargo.cs +++ b/OpenRA.Game/Traits/Activities/UnloadCargo.cs @@ -19,6 +19,7 @@ #endregion using System.Linq; +using OpenRA.GameRules; namespace OpenRA.Traits.Activities { diff --git a/OpenRA.Game/Traits/Bridge.cs b/OpenRA.Game/Traits/Bridge.cs index 95ecacb038..ef29e4d07d 100644 --- a/OpenRA.Game/Traits/Bridge.cs +++ b/OpenRA.Game/Traits/Bridge.cs @@ -23,6 +23,7 @@ using System.Drawing; using System.Linq; using OpenRA.FileFormats; using OpenRA.Graphics; +using OpenRA.GameRules; namespace OpenRA.Traits { @@ -128,10 +129,7 @@ namespace OpenRA.Traits public float GetCost(int2 p, UnitMovementType umt) { - // just use the standard walkability from templates.ini. no hackery. - - return TerrainCosts.Cost(umt, - Templates[state].TerrainType[Tiles[p]]); + return Rules.TerrainTypes[Templates[state].TerrainType[Tiles[p]]].GetCost(umt); } static bool IsIntact(Bridge b) diff --git a/OpenRA.Game/Traits/Cargo.cs b/OpenRA.Game/Traits/Cargo.cs index 4ff7606dcf..3f524e2097 100644 --- a/OpenRA.Game/Traits/Cargo.cs +++ b/OpenRA.Game/Traits/Cargo.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using OpenRA.Traits.Activities; +using OpenRA.GameRules; namespace OpenRA.Traits { diff --git a/OpenRA.Game/Traits/ConstructionYard.cs b/OpenRA.Game/Traits/ConstructionYard.cs index 160cca540f..b45d808e19 100644 --- a/OpenRA.Game/Traits/ConstructionYard.cs +++ b/OpenRA.Game/Traits/ConstructionYard.cs @@ -19,6 +19,7 @@ #endregion using OpenRA.Traits.Activities; +using OpenRA.GameRules; namespace OpenRA.Traits { @@ -66,10 +67,7 @@ namespace OpenRA.Traits } // HACK: This should make reference to an MCV actor, and use of its Mobile trait - public UnitMovementType GetMovementType() - { - return UnitMovementType.Wheel; - } + public UnitMovementType GetMovementType() { return UnitMovementType.Wheel; } public bool CanEnterCell(int2 a) { @@ -88,10 +86,10 @@ namespace OpenRA.Traits } if (!crushable) return false; - + return self.World.Map.IsInMap(a.X, a.Y) && - TerrainCosts.Cost(GetMovementType(), - self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; + Rules.TerrainTypes[self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])] + .GetCost(GetMovementType()) < float.PositiveInfinity; } } } diff --git a/OpenRA.Game/Traits/Crate.cs b/OpenRA.Game/Traits/Crate.cs index b144f62824..d70652b0a8 100644 --- a/OpenRA.Game/Traits/Crate.cs +++ b/OpenRA.Game/Traits/Crate.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Linq; using OpenRA.FileFormats; +using OpenRA.GameRules; /* * Crates left to implement: @@ -75,24 +76,15 @@ namespace OpenRA.Traits n -= s.Second; } - public bool IsPathableCrush(UnitMovementType umt, Player player) - { - return true; - } - - public bool IsCrushableBy(UnitMovementType umt, Player player) - { - return true; - } + public bool IsPathableCrush(UnitMovementType umt, Player player) { return true; } + public bool IsCrushableBy(UnitMovementType umt, Player player) { return true; } public IEnumerable OccupiedCells() { yield return self.Location; } public void Tick(Actor self) { if (++ticks >= self.Info.Traits.Get().Lifetime * 25) - { self.World.AddFrameEndTask(w => w.Remove(self)); - } } } } diff --git a/OpenRA.Game/Traits/Helicopter.cs b/OpenRA.Game/Traits/Helicopter.cs index 3224a35e9c..712945b410 100644 --- a/OpenRA.Game/Traits/Helicopter.cs +++ b/OpenRA.Game/Traits/Helicopter.cs @@ -20,6 +20,7 @@ using System; using OpenRA.Traits.Activities; +using OpenRA.GameRules; namespace OpenRA.Traits { diff --git a/OpenRA.Game/Traits/Mobile.cs b/OpenRA.Game/Traits/Mobile.cs index 7822dc2624..b02127be44 100644 --- a/OpenRA.Game/Traits/Mobile.cs +++ b/OpenRA.Game/Traits/Mobile.cs @@ -20,6 +20,7 @@ using System.Collections.Generic; using System.Linq; +using OpenRA.GameRules; namespace OpenRA.Traits { @@ -131,10 +132,10 @@ namespace OpenRA.Traits } if (!crushable) return false; - + return self.World.Map.IsInMap(a.X, a.Y) && - TerrainCosts.Cost(GetMovementType(), - self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; + Rules.TerrainTypes[self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])] + .GetCost(GetMovementType()) < float.PositiveInfinity; } public IEnumerable GetCurrentPath() diff --git a/OpenRA.Game/Traits/Plane.cs b/OpenRA.Game/Traits/Plane.cs index 816d38f19a..7662b64ac9 100644 --- a/OpenRA.Game/Traits/Plane.cs +++ b/OpenRA.Game/Traits/Plane.cs @@ -21,6 +21,7 @@ using System; using System.Linq; using OpenRA.Traits.Activities; +using OpenRA.GameRules; namespace OpenRA.Traits { diff --git a/OpenRA.Game/Traits/SquishByTank.cs b/OpenRA.Game/Traits/SquishByTank.cs index 642338b95d..8ae94fc37b 100644 --- a/OpenRA.Game/Traits/SquishByTank.cs +++ b/OpenRA.Game/Traits/SquishByTank.cs @@ -18,6 +18,7 @@ */ #endregion +using OpenRA.GameRules; namespace OpenRA.Traits { class SquishByTankInfo : ITraitInfo diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs index c80efb66a3..d6757e329b 100755 --- a/OpenRA.Game/WorldUtils.cs +++ b/OpenRA.Game/WorldUtils.cs @@ -34,8 +34,10 @@ namespace OpenRA { if (world.WorldActor.traits.Get().GetBuildingAt(a) != null) return false; if (world.WorldActor.traits.Get().GetUnitsAt(a).Any()) return false; - - return world.Map.IsInMap(a.X, a.Y) && TerrainCosts.Cost(umt, world.TileSet.GetTerrainType(world.Map.MapTiles[a.X,a.Y])) < double.PositiveInfinity; + + return world.Map.IsInMap(a.X, a.Y) && + Rules.TerrainTypes[world.TileSet.GetTerrainType(world.Map.MapTiles[a.X, a.Y])] + .GetCost(umt) < float.PositiveInfinity; } public static bool IsCellBuildable(this World world, int2 a, bool waterBound) @@ -50,8 +52,10 @@ namespace OpenRA if (waterBound) return world.Map.IsInMap(a.X,a.Y) && GetTerrainType(world,a) == TerrainType.Water; - - return world.Map.IsInMap(a.X, a.Y) && TerrainCosts.Buildable(world.TileSet.GetTerrainType(world.Map.MapTiles[a.X, a.Y])); + + return world.Map.IsInMap(a.X, a.Y) && + Rules.TerrainTypes[world.TileSet.GetTerrainType(world.Map.MapTiles[a.X, a.Y])] + .Buildable; } public static bool IsActorCrushableByActor(this World world, Actor a, Actor b) diff --git a/OpenRA.Mods.RA/Mine.cs b/OpenRA.Mods.RA/Mine.cs index 1a945f8f49..b7ffbe40ce 100644 --- a/OpenRA.Mods.RA/Mine.cs +++ b/OpenRA.Mods.RA/Mine.cs @@ -23,6 +23,7 @@ using System.Linq; using OpenRA.Effects; using OpenRA.Traits; using OpenRA.Traits.Activities; +using OpenRA.GameRules; namespace OpenRA.Mods.RA { diff --git a/mods/cnc/minimal.ini b/mods/cnc/minimal.ini index 8888077132..baaa96e56a 100644 --- a/mods/cnc/minimal.ini +++ b/mods/cnc/minimal.ini @@ -14,86 +14,3 @@ LowPowerSlowdown=3 ; slowdown factor for low power GapRegenInterval=.1 ; gap generators will regenerate their shroud at this time interval SubmergeDelay=.02 ; forced delay that subs will remain on surface before allowing to submerge - - -; ******* Land Characteristics ******* - -; clear grassy terrain -[Clear] -Foot=90% -Track=80% -Wheel=60% -Float=0% -Buildable=yes - -; rocky terrain -[Rough] -Foot=80% -Track=70% -Wheel=40% -Float=0% -Buildable=no - -; roads -[Road] -Foot=100% -Track=100% -Wheel=100% -Float=0% -Buildable=yes - -; open water -[Water] -Foot=0% -Track=0% -Wheel=0% -Float=100% -Buildable=no - -; cliffs -[Rock] -Foot=0% -Track=0% -Wheel=0% -Float=0% -Buildable=no - -; walls and other man made obstacles -[Wall] -Foot=0% -Track=0% -Wheel=0% -Float=0% -Buildable=no - -; ore (Tiberium) -[Ore] -Foot=90% -Track=70% -Wheel=50% -Float=0% -Buildable=no - -; sandy beach -[Beach] -Foot=80% -Track=70% -Wheel=40% -Float=0% -Buildable=no - -; craggy riverbed -[River] -Foot=0% -Track=0% -Wheel=0% -Float=0% -Buildable=no - -; special tile for bridge hacks -[Special] -Foot=100% -Track=100% -Wheel=100% -Float=100% -Buildable=no \ No newline at end of file diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 8df61292c4..a644bb2b02 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -50,4 +50,7 @@ Weapons: mods/cnc/weapons.yaml: Voices: - mods/cnc/voices.yaml: \ No newline at end of file + mods/cnc/voices.yaml: + +Terrain: + mods/cnc/terrain.yaml \ No newline at end of file diff --git a/mods/cnc/terrain.yaml b/mods/cnc/terrain.yaml new file mode 100644 index 0000000000..a9192f7efb --- /dev/null +++ b/mods/cnc/terrain.yaml @@ -0,0 +1,82 @@ +Clear: + Foot: 90% + Track: 80% + Wheel: 60% + Float: 0% + Buildable: yes + +Rough: + Foot: 80% + Track: 70% + Wheel: 40% + Float: 0% + Buildable: no + +Road: + Foot: 100% + Track: 100% + Wheel: 100% + Float: 0% + Buildable: yes + +Tree: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + AcceptSmudge: no + +Water: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 100% + Buildable: no + AcceptSmudge: no + +Rock: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + AcceptSmudge: no + +Wall: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + +Ore: + Foot: 90% + Track: 70% + Wheel: 50% + Float: 0% + Buildable: no + +Beach: + Foot: 80% + Track: 70% + Wheel: 40% + Float: 0% + Buildable: no + AcceptSmudge: no + +River: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + AcceptSmudge: no + +Special: + Foot: 100% + Track: 100% + Wheel: 100% + Float: 100% + Buildable: no + AcceptSmudge: no \ No newline at end of file diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 36f0a263dd..9a40345166 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -43,4 +43,7 @@ Weapons: mods/ra/weapons.yaml Voices: - mods/ra/voices.yaml \ No newline at end of file + mods/ra/voices.yaml + +Terrain: + mods/ra/terrain.yaml \ No newline at end of file diff --git a/mods/ra/rules.ini b/mods/ra/rules.ini index da9560bf61..8885a7ad59 100644 --- a/mods/ra/rules.ini +++ b/mods/ra/rules.ini @@ -88,94 +88,3 @@ TeamDelay=.6 ; interval between checking for and creating teams ; misc FineDiffControl=no ; Allow 5 difficulty settings instead of only 3 settings? LowPowerSlowdown=3 - -; ******* Land Characteristics ******* -; This section specifies the characteristics of the various -; terrain types. The primary purpose is to differentiate the -; movement capabilities. - -; Float = % of full speed for ships [0 means impassable] (def=100) -; Foot = % of full speed for foot soldiers [0 means impassable] (def=100) -; Track = % of full speed for tracked vehicles [0 means impassable] (def=100) -; Wheel = % of full speed for wheeled vehicles [0 means impassable] (def=100) -; Buildable = Can buildings be built upon this terrain (def=no)? - -; clear grassy terrain -[Clear] -Foot=90% -Track=80% -Wheel=60% -Float=0% -Buildable=yes - -; rocky terrain -[Rough] -Foot=80% -Track=70% -Wheel=40% -Float=0% -Buildable=no - -; roads -[Road] -Foot=100% -Track=100% -Wheel=100% -Float=0% -Buildable=yes - -; open water -[Water] -Foot=0% -Track=0% -Wheel=0% -Float=100% -Buildable=no - -; cliffs -[Rock] -Foot=0% -Track=0% -Wheel=0% -Float=0% -Buildable=no - -; walls and other man made obstacles -[Wall] -Foot=0% -Track=0% -Wheel=0% -Float=0% -Buildable=no - -; ore (Tiberium) -[Ore] -Foot=90% -Track=70% -Wheel=50% -Float=0% -Buildable=no - -; sandy beach -[Beach] -Foot=80% -Track=70% -Wheel=40% -Float=0% -Buildable=no - -; craggy riverbed -[River] -Foot=0% -Track=0% -Wheel=0% -Float=0% -Buildable=no - -; special tile for bridge hacks -[Special] -Foot=100% -Track=100% -Wheel=100% -Float=100% -Buildable=no diff --git a/mods/ra/terrain.yaml b/mods/ra/terrain.yaml new file mode 100644 index 0000000000..a9192f7efb --- /dev/null +++ b/mods/ra/terrain.yaml @@ -0,0 +1,82 @@ +Clear: + Foot: 90% + Track: 80% + Wheel: 60% + Float: 0% + Buildable: yes + +Rough: + Foot: 80% + Track: 70% + Wheel: 40% + Float: 0% + Buildable: no + +Road: + Foot: 100% + Track: 100% + Wheel: 100% + Float: 0% + Buildable: yes + +Tree: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + AcceptSmudge: no + +Water: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 100% + Buildable: no + AcceptSmudge: no + +Rock: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + AcceptSmudge: no + +Wall: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + +Ore: + Foot: 90% + Track: 70% + Wheel: 50% + Float: 0% + Buildable: no + +Beach: + Foot: 80% + Track: 70% + Wheel: 40% + Float: 0% + Buildable: no + AcceptSmudge: no + +River: + Foot: 0% + Track: 0% + Wheel: 0% + Float: 0% + Buildable: no + AcceptSmudge: no + +Special: + Foot: 100% + Track: 100% + Wheel: 100% + Float: 100% + Buildable: no + AcceptSmudge: no \ No newline at end of file