diff --git a/OpenRA.Game/Traits/Mobile.cs b/OpenRA.Game/Traits/Mobile.cs index 5cc51983a6..22b9bc27d1 100644 --- a/OpenRA.Game/Traits/Mobile.cs +++ b/OpenRA.Game/Traits/Mobile.cs @@ -165,30 +165,40 @@ namespace OpenRA.Traits if (!self.World.Map.IsInMap(cell.X,cell.Y)) return float.PositiveInfinity; - var type = self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[cell.X, cell.Y]); - return (float)TerrainCost[type]* - self.World.WorldActor.traits.WithInterface() - .Select(t => t.GetCost(cell, self)) - .Product(); + // Custom terrain types don't stack: pick one + var customTerrain = self.World.WorldActor.traits.WithInterface() + .Where( t => t.GetTerrainType(cell) != null ) + .Select( t => t.GetTerrainType(cell) ) + .FirstOrDefault(); + + // Todo: Hack this until i finish migrating TerrainType to a string + var type = (customTerrain != null) ? (TerrainType)Enum.Parse(typeof(TerrainType), customTerrain) : self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[cell.X, cell.Y]); + var additionalCost = self.World.WorldActor.traits.WithInterface() + .Select( t => t.GetTerrainCost(cell, self) ).Sum(); + + return TerrainCost[type] + additionalCost; } public virtual float MovementSpeedForCell(Actor self, int2 cell) { var unitInfo = self.Info.Traits.GetOrDefault(); - if( unitInfo == null || !self.World.Map.IsInMap(cell.X,cell.Y)) + if( unitInfo == null ) return 0f; - var type = self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[cell.X, cell.Y]); - var terrain = TerrainSpeed[type]*self.World.WorldActor.traits - .WithInterface() - .Select(t => t.GetSpeedModifier(self.Location, self)) - .Product(); + // Custom terrain types don't stack: pick one + var customTerrain = self.World.WorldActor.traits.WithInterface() + .Where( t => t.GetTerrainType(cell) != null ) + .Select( t => t.GetTerrainType(cell) ) + .FirstOrDefault(); + // Todo: Hack this until i finish migrating TerrainType to a string + var type = (customTerrain != null) ? (TerrainType)Enum.Parse(typeof(TerrainType), customTerrain) : self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[cell.X, cell.Y]); + var modifier = self.traits .WithInterface() .Select(t => t.GetSpeedModifier()) .Product(); - return unitInfo.Speed * terrain * modifier; + return unitInfo.Speed * TerrainSpeed[type] * modifier; } public IEnumerable GetCurrentPath(Actor self) diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index f341f6c76e..251fb98f42 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -57,11 +57,8 @@ namespace OpenRA.Traits public interface IProvideHazard { IEnumerable HazardCells(Actor self); } public interface IAvoidHazard { string Type { get; } } - public interface ICustomTerrain - { - float GetCost(int2 p, Actor forActor); - float GetSpeedModifier(int2 p, Actor forActor); - } + public interface ITerrainTypeModifier { string GetTerrainType(int2 cell); } + public interface ITerrainCost { float GetTerrainCost(int2 cell, Actor forActor); } public interface IDisable { bool Disabled { get; } } diff --git a/OpenRA.Game/Traits/World/HazardLayer.cs b/OpenRA.Game/Traits/World/HazardLayer.cs index 952eca497c..861d3068e3 100644 --- a/OpenRA.Game/Traits/World/HazardLayer.cs +++ b/OpenRA.Game/Traits/World/HazardLayer.cs @@ -31,14 +31,13 @@ namespace OpenRA.Traits public object Create( ActorInitializer init ) { return new HazardLayer( init.world ); } } - public class HazardLayer : ICustomTerrain + public class HazardLayer : ITerrainCost { 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++) @@ -48,30 +47,21 @@ namespace OpenRA.Traits world.ActorRemoved += a => Remove( a, a.traits.GetOrDefault() ); } - - public float GetSpeedModifier(int2 p, Actor forActor) + public float GetTerrainCost(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); + + var intensity = hazards[p.X,p.Y].Where(a => avoid.Contains(a.Second.type)) + .Select(b => b.Second.intensity) + .Sum(); 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)); } } diff --git a/OpenRA.Game/Traits/World/ResourceLayer.cs b/OpenRA.Game/Traits/World/ResourceLayer.cs index 09ad3f37c7..ef78af789d 100644 --- a/OpenRA.Game/Traits/World/ResourceLayer.cs +++ b/OpenRA.Game/Traits/World/ResourceLayer.cs @@ -23,12 +23,13 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.GameRules; using System.Drawing; +using OpenRA.FileFormats; namespace OpenRA.Traits { public class ResourceLayerInfo : TraitInfo { } - public class ResourceLayer: IRenderOverlay, ILoadWorldHook, ICustomTerrain + public class ResourceLayer: IRenderOverlay, ILoadWorldHook, ITerrainTypeModifier { SpriteRenderer sr; World world; @@ -93,28 +94,14 @@ namespace OpenRA.Traits content[x, y].density = GetIdealDensity(x, y); } - public float GetSpeedModifier(int2 p, Actor forActor) + public string GetTerrainType(int2 cell) { - if (content[p.X,p.Y].type == null) - return 1.0f; + if (content[cell.X,cell.Y].type == null) + return null; - // Todo: Reenable based off something that isn't umt - return 1f; - //var umt = forActor.traits.Get().GetMovementType(); - //return content[p.X,p.Y].type.GetSpeedModifier(umt); + return content[cell.X,cell.Y].type.info.TerrainType; } - - public float GetCost(int2 p, Actor forActor) - { - if (content[p.X,p.Y].type == null) - return 1.0f; - - // Todo: Reenable based off something that isn't umt - return 1f; - //var umt = forActor.traits.Get().GetMovementType(); - //return content[p.X,p.Y].type.GetCost(umt); - } - + Sprite[] ChooseContent(ResourceType t) { return t.info.Sprites[world.SharedRandom.Next(t.info.Sprites.Length)]; diff --git a/OpenRA.Game/Traits/World/ResourceType.cs b/OpenRA.Game/Traits/World/ResourceType.cs index 6cdc568f57..cc58575d09 100644 --- a/OpenRA.Game/Traits/World/ResourceType.cs +++ b/OpenRA.Game/Traits/World/ResourceType.cs @@ -32,9 +32,7 @@ namespace OpenRA.Traits public readonly int ValuePerUnit = 0; public readonly string Name = null; - - public readonly string MovementTerrainType = null; - public readonly string PathingTerrainType = null; + public readonly string TerrainType = null; public Sprite[][] Sprites; @@ -44,32 +42,9 @@ namespace OpenRA.Traits public class ResourceType { public ResourceTypeInfo info; - float[] movementSpeed = new float[5]; - float[] pathCost = new float[5]; - public ResourceType(ResourceTypeInfo info) { - for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++ ) - { - // HACK: hardcode "ore" terraintype for now - movementSpeed[(int)umt] = (info.MovementTerrainType != null) ? (float)Rules.TerrainTypes[TerrainType.Ore].GetSpeedModifier(umt) : 1.0f; - pathCost[(int)umt] = (info.PathingTerrainType != null) ? (float)Rules.TerrainTypes[TerrainType.Ore].GetCost(umt) - : (info.MovementTerrainType != null) ? (float)Rules.TerrainTypes[TerrainType.Ore].GetCost(umt) : 1.0f; - } - movementSpeed[(int)UnitMovementType.Fly] = 1.0f; - pathCost[(int)UnitMovementType.Fly] = 1.0f; - this.info = info; } - - public float GetSpeedModifier(UnitMovementType umt) - { - return movementSpeed[(int)umt]; - } - - public float GetCost(UnitMovementType umt) - { - return pathCost[(int)umt]; - } } } diff --git a/OpenRA.Mods.Cnc/MobileAir.cs b/OpenRA.Mods.Cnc/MobileAir.cs index 7aff58c4ca..a056623aa2 100644 --- a/OpenRA.Mods.Cnc/MobileAir.cs +++ b/OpenRA.Mods.Cnc/MobileAir.cs @@ -62,18 +62,21 @@ namespace OpenRA.Traits return self.World.WorldActor.traits.Get().GetUnitsAt(p).Count() == 0; } - public override float MovementCostForCell(Actor self, int2 cell) + public virtual float MovementCostForCell(Actor self, int2 cell) { if (!self.World.Map.IsInMap(cell.X,cell.Y)) return float.PositiveInfinity; - return self.World.WorldActor.traits.WithInterface().Aggregate(1f, (a, x) => a * x.GetCost(cell,self)); + var additionalCost = self.World.WorldActor.traits.WithInterface() + .Select( t => t.GetTerrainCost(cell, self) ).Sum(); + + return additionalCost; } - - public override float MovementSpeedForCell(Actor self, int2 cell) + + public virtual float MovementSpeedForCell(Actor self, int2 cell) { var unitInfo = self.Info.Traits.GetOrDefault(); - if( unitInfo == null || !self.World.Map.IsInMap(cell.X,cell.Y)) + if( unitInfo == null ) return 0f; var modifier = self.traits @@ -82,7 +85,7 @@ namespace OpenRA.Traits .Product(); return unitInfo.Speed * modifier; } - + public override IEnumerable OccupiedCells() { // Todo: do the right thing when landed diff --git a/OpenRA.Mods.RA/Bridge.cs b/OpenRA.Mods.RA/Bridge.cs index 9f2f885076..fb2838f74a 100644 --- a/OpenRA.Mods.RA/Bridge.cs +++ b/OpenRA.Mods.RA/Bridge.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.Drawing; using System.Linq; +using System; using OpenRA.FileFormats; using OpenRA.GameRules; using OpenRA.Graphics; @@ -126,14 +127,10 @@ namespace OpenRA.Mods.RA self.Health = (int)(self.GetMaxHP() * template.HP); } - public float GetCost(int2 p, UnitMovementType umt) + public string GetTerrainType(int2 cell) { - return Rules.TerrainTypes[Templates[state].TerrainType[Tiles[p]]].GetCost(umt); - } - - public float GetSpeedModifier(int2 p, UnitMovementType umt) - { - return Rules.TerrainTypes[Templates[state].TerrainType[Tiles[p]]].GetSpeedModifier(umt); + // Ugly hack until terraintypes are converted from enums + return Enum.GetName( typeof(TerrainType), Templates[state].TerrainType[Tiles[cell]]); } static bool IsIntact(Bridge b) diff --git a/OpenRA.Mods.RA/BridgeLayer.cs b/OpenRA.Mods.RA/BridgeLayer.cs index 86b087359b..713e1a6982 100644 --- a/OpenRA.Mods.RA/BridgeLayer.cs +++ b/OpenRA.Mods.RA/BridgeLayer.cs @@ -27,10 +27,10 @@ namespace OpenRA.Mods.RA { class BridgeLayerInfo : TraitInfo { } - class BridgeLayer : ILoadWorldHook, ICustomTerrain + class BridgeLayer : ILoadWorldHook, ITerrainTypeModifier { // for tricky things like bridges. - Bridge[,] customTerrain; + Bridge[,] bridges; void MakeBridges(World w) { @@ -43,7 +43,7 @@ namespace OpenRA.Mods.RA ConvertBridgeToActor(w, i, j); foreach (var b in w.Actors.SelectMany(a => a.traits.WithInterface())) - b.FinalizeBridges(w, customTerrain); + b.FinalizeBridges(w, bridges); } void ConvertBridgeToActor(World w, int i, int j) @@ -84,30 +84,19 @@ namespace OpenRA.Mods.RA var br = a.traits.Get(); foreach (var t in replacedTiles.Keys) - customTerrain[t.X, t.Y] = br; + bridges[t.X, t.Y] = br; br.SetTiles(w, template, replacedTiles); } } - public float GetCost(int2 p, Actor forActor) + public string GetTerrainType(int2 cell) { - // Todo: Do we even need to reenable this since cost = 100% for everything? - //var umt = forActor.traits.Get().GetMovementType(); - //if (customTerrain[p.X, p.Y] != null) - // return customTerrain[p.X,p.Y].GetCost(p,umt); - return 1f; + if (bridges[ cell.X, cell.Y ] != null) + return bridges[ cell.X, cell.Y ].GetTerrainType(cell); + return null; } - - public float GetSpeedModifier(int2 p, Actor forActor) - { - // Todo: Do we even need to reenable this since cost = 100% for everything? - //var umt = forActor.traits.Get().GetMovementType(); - //if (customTerrain[p.X, p.Y] != null) - // return customTerrain[p.X,p.Y].GetSpeedModifier(p,umt); - return 1f; - } - + static bool IsBridge(World w, ushort t) { return w.TileSet.walk[t].Bridge != null; @@ -115,7 +104,7 @@ namespace OpenRA.Mods.RA public void WorldLoaded(World w) { - customTerrain = new Bridge[w.Map.MapSize.X, w.Map.MapSize.Y]; + bridges = new Bridge[w.Map.MapSize.X, w.Map.MapSize.Y]; MakeBridges(w); } }