rules-based terrain cost, part 1

This commit is contained in:
Chris Forbes
2010-04-02 15:14:58 +13:00
parent 45f9ec2f7e
commit 0596b08f2c
25 changed files with 235 additions and 239 deletions

View File

@@ -61,7 +61,7 @@ namespace OpenRA.FileFormats
public readonly string[] public readonly string[]
Folders, Packages, LegacyRules, Rules, Folders, Packages, LegacyRules, Rules,
Sequences, Chrome, Assemblies, ChromeLayout, Sequences, Chrome, Assemblies, ChromeLayout,
Weapons, Voices; Weapons, Voices, Terrain;
public Manifest(string[] mods) public Manifest(string[] mods)
{ {
@@ -79,6 +79,7 @@ namespace OpenRA.FileFormats
ChromeLayout = YamlList(yaml, "ChromeLayout"); ChromeLayout = YamlList(yaml, "ChromeLayout");
Weapons = YamlList(yaml, "Weapons"); Weapons = YamlList(yaml, "Weapons");
Voices = YamlList(yaml, "Voices"); Voices = YamlList(yaml, "Voices");
Terrain = YamlList(yaml, "Terrain");
} }
static string[] YamlList(Dictionary<string, MiniYaml> ys, string key) { return ys[key].Nodes.Keys.ToArray(); } static string[] YamlList(Dictionary<string, MiniYaml> ys, string key) { return ys[key].Nodes.Keys.ToArray(); }

View File

@@ -34,6 +34,7 @@ namespace OpenRA
public static Dictionary<string, ActorInfo> Info; public static Dictionary<string, ActorInfo> Info;
public static Dictionary<string, WeaponInfo> Weapons; public static Dictionary<string, WeaponInfo> Weapons;
public static Dictionary<string, VoiceInfo> Voices; public static Dictionary<string, VoiceInfo> Voices;
public static Dictionary<TerrainType, TerrainCost> TerrainTypes;
public static void LoadRules(string map, Manifest m) 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)); 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)); Weapons = LoadYamlRules(m.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, (k, _) => new VoiceInfo(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(); TechTree = new TechTree();
} }

View File

@@ -18,10 +18,11 @@
*/ */
#endregion #endregion
using OpenRA.Graphics; using System;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Graphics;
namespace OpenRA namespace OpenRA.GameRules
{ {
public enum UnitMovementType : byte public enum UnitMovementType : byte
{ {
@@ -32,35 +33,26 @@ namespace OpenRA
Fly = 4, Fly = 4,
} }
static class TerrainCosts public class TerrainCost
{ {
static float[][] costs = Util.MakeArray<float[]>(4, public readonly bool Buildable = true;
a => Util.MakeArray<float>(11, b => float.PositiveInfinity)); public readonly float Foot = 0, Track = 0, Wheel = 0, Float = 0;
public readonly bool AcceptSmudge = true;
static bool[] buildable = Util.MakeArray<bool>(11,b => false);
static TerrainCosts() 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; case UnitMovementType.Fly: return 1;
var section = Rules.AllRules.GetSection( ( (TerrainType)i ).ToString() ); case UnitMovementType.Foot: return 1 / Foot;
for( int j = 0 ; j < 4 ; j++ ) case UnitMovementType.Wheel: return 1 / Wheel;
{ case UnitMovementType.Track: return 1 / Track;
string val = section.GetValue( ( (UnitMovementType)j ).ToString(), "0%" ); case UnitMovementType.Float: return 1 / Float;
costs[j][i] = 100f / float.Parse(val.Substring(0, val.Length - 1)); default:
} throw new InvalidOperationException("wtf?");
buildable[i] = (section.GetValue("Buildable", "no") == "yes");
} }
} }
public static bool Buildable(TerrainType r)
{
return buildable[(int)r];
}
public static float Cost( UnitMovementType unitMovementType, TerrainType r )
{
return costs[ (byte)unitMovementType ][ (int)r ];
}
} }
} }

View File

@@ -188,7 +188,7 @@
<Compile Include="Graphics\Sprite.cs" /> <Compile Include="Graphics\Sprite.cs" />
<Compile Include="Graphics\SpriteRenderer.cs" /> <Compile Include="Graphics\SpriteRenderer.cs" />
<Compile Include="Graphics\SpriteSheetBuilder.cs" /> <Compile Include="Graphics\SpriteSheetBuilder.cs" />
<Compile Include="TerrainCosts.cs" /> <Compile Include="GameRules\TerrainCost.cs" />
<Compile Include="Graphics\TerrainRenderer.cs" /> <Compile Include="Graphics\TerrainRenderer.cs" />
<Compile Include="Traits\Activities\Harvest.cs" /> <Compile Include="Traits\Activities\Harvest.cs" />
<Compile Include="Traits\Activities\Move.cs" /> <Compile Include="Traits\Activities\Move.cs" />

View File

@@ -24,6 +24,7 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using OpenRA.Support; using OpenRA.Support;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.GameRules;
namespace OpenRA namespace OpenRA
{ {
@@ -38,11 +39,12 @@ namespace OpenRA
var map = world.Map; var map = world.Map;
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++) for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++)
passableCost[(int)umt] = new float[map.MapSize, map.MapSize]; passableCost[(int)umt] = new float[map.MapSize, map.MapSize];
for( int x = 0 ; x < map.MapSize ; x++ ) for (int x = 0; x < map.MapSize; x++)
for( int y = 0 ; y < map.MapSize ; y++ ) for (int y = 0; y < map.MapSize; y++)
for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++ ) for (var umt = UnitMovementType.Foot; umt <= UnitMovementType.Float; umt++)
passableCost[(int)umt][ x, y ] = ( world.Map.IsInMap( x, y ) ) passableCost[(int)umt][x, y] = (world.Map.IsInMap(x, y))
? (float)TerrainCosts.Cost( umt, world.TileSet.GetTerrainType( world.Map.MapTiles[ x, y ] ) ) ? (float)Rules.TerrainTypes[world.TileSet.GetTerrainType(world.Map.MapTiles[x, y])]
.GetCost(umt)
: float.PositiveInfinity; : float.PositiveInfinity;
} }

View File

@@ -23,6 +23,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.GameRules;
namespace OpenRA namespace OpenRA
{ {

View File

@@ -19,6 +19,7 @@
#endregion #endregion
using System.Linq; using System.Linq;
using OpenRA.GameRules;
namespace OpenRA.Traits.Activities namespace OpenRA.Traits.Activities
{ {

View File

@@ -18,6 +18,7 @@
*/ */
#endregion #endregion
using OpenRA.GameRules;
namespace OpenRA.Traits.Activities namespace OpenRA.Traits.Activities
{ {
class HeliLand : IActivity class HeliLand : IActivity

View File

@@ -19,6 +19,7 @@
#endregion #endregion
using System.Linq; using System.Linq;
using OpenRA.GameRules;
namespace OpenRA.Traits.Activities namespace OpenRA.Traits.Activities
{ {

View File

@@ -23,6 +23,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.Graphics; using OpenRA.Graphics;
using OpenRA.GameRules;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {
@@ -128,10 +129,7 @@ namespace OpenRA.Traits
public float GetCost(int2 p, UnitMovementType umt) public float GetCost(int2 p, UnitMovementType umt)
{ {
// just use the standard walkability from templates.ini. no hackery. return Rules.TerrainTypes[Templates[state].TerrainType[Tiles[p]]].GetCost(umt);
return TerrainCosts.Cost(umt,
Templates[state].TerrainType[Tiles[p]]);
} }
static bool IsIntact(Bridge b) static bool IsIntact(Bridge b)

View File

@@ -20,6 +20,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using OpenRA.Traits.Activities; using OpenRA.Traits.Activities;
using OpenRA.GameRules;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {

View File

@@ -19,6 +19,7 @@
#endregion #endregion
using OpenRA.Traits.Activities; using OpenRA.Traits.Activities;
using OpenRA.GameRules;
namespace OpenRA.Traits 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 // HACK: This should make reference to an MCV actor, and use of its Mobile trait
public UnitMovementType GetMovementType() public UnitMovementType GetMovementType() { return UnitMovementType.Wheel; }
{
return UnitMovementType.Wheel;
}
public bool CanEnterCell(int2 a) public bool CanEnterCell(int2 a)
{ {
@@ -88,10 +86,10 @@ namespace OpenRA.Traits
} }
if (!crushable) return false; if (!crushable) return false;
return self.World.Map.IsInMap(a.X, a.Y) && return self.World.Map.IsInMap(a.X, a.Y) &&
TerrainCosts.Cost(GetMovementType(), Rules.TerrainTypes[self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])]
self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; .GetCost(GetMovementType()) < float.PositiveInfinity;
} }
} }
} }

View File

@@ -21,6 +21,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.FileFormats; using OpenRA.FileFormats;
using OpenRA.GameRules;
/* /*
* Crates left to implement: * Crates left to implement:
@@ -75,24 +76,15 @@ namespace OpenRA.Traits
n -= s.Second; n -= s.Second;
} }
public bool IsPathableCrush(UnitMovementType umt, Player player) public bool IsPathableCrush(UnitMovementType umt, Player player) { return true; }
{ public bool IsCrushableBy(UnitMovementType umt, Player player) { return true; }
return true;
}
public bool IsCrushableBy(UnitMovementType umt, Player player)
{
return true;
}
public IEnumerable<int2> OccupiedCells() { yield return self.Location; } public IEnumerable<int2> OccupiedCells() { yield return self.Location; }
public void Tick(Actor self) public void Tick(Actor self)
{ {
if (++ticks >= self.Info.Traits.Get<CrateInfo>().Lifetime * 25) if (++ticks >= self.Info.Traits.Get<CrateInfo>().Lifetime * 25)
{
self.World.AddFrameEndTask(w => w.Remove(self)); self.World.AddFrameEndTask(w => w.Remove(self));
}
} }
} }
} }

View File

@@ -20,6 +20,7 @@
using System; using System;
using OpenRA.Traits.Activities; using OpenRA.Traits.Activities;
using OpenRA.GameRules;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {

View File

@@ -20,6 +20,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using OpenRA.GameRules;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {
@@ -131,10 +132,10 @@ namespace OpenRA.Traits
} }
if (!crushable) return false; if (!crushable) return false;
return self.World.Map.IsInMap(a.X, a.Y) && return self.World.Map.IsInMap(a.X, a.Y) &&
TerrainCosts.Cost(GetMovementType(), Rules.TerrainTypes[self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])]
self.World.TileSet.GetTerrainType(self.World.Map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; .GetCost(GetMovementType()) < float.PositiveInfinity;
} }
public IEnumerable<int2> GetCurrentPath() public IEnumerable<int2> GetCurrentPath()

View File

@@ -21,6 +21,7 @@
using System; using System;
using System.Linq; using System.Linq;
using OpenRA.Traits.Activities; using OpenRA.Traits.Activities;
using OpenRA.GameRules;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {

View File

@@ -18,6 +18,7 @@
*/ */
#endregion #endregion
using OpenRA.GameRules;
namespace OpenRA.Traits namespace OpenRA.Traits
{ {
class SquishByTankInfo : ITraitInfo class SquishByTankInfo : ITraitInfo

View File

@@ -34,8 +34,10 @@ namespace OpenRA
{ {
if (world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(a) != null) return false; if (world.WorldActor.traits.Get<BuildingInfluence>().GetBuildingAt(a) != null) return false;
if (world.WorldActor.traits.Get<UnitInfluence>().GetUnitsAt(a).Any()) return false; if (world.WorldActor.traits.Get<UnitInfluence>().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) public static bool IsCellBuildable(this World world, int2 a, bool waterBound)
@@ -50,8 +52,10 @@ namespace OpenRA
if (waterBound) if (waterBound)
return world.Map.IsInMap(a.X,a.Y) && GetTerrainType(world,a) == TerrainType.Water; 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) public static bool IsActorCrushableByActor(this World world, Actor a, Actor b)

View File

@@ -23,6 +23,7 @@ using System.Linq;
using OpenRA.Effects; using OpenRA.Effects;
using OpenRA.Traits; using OpenRA.Traits;
using OpenRA.Traits.Activities; using OpenRA.Traits.Activities;
using OpenRA.GameRules;
namespace OpenRA.Mods.RA namespace OpenRA.Mods.RA
{ {

View File

@@ -14,86 +14,3 @@ LowPowerSlowdown=3 ; slowdown factor for low power
GapRegenInterval=.1 ; gap generators will regenerate their shroud at this time interval 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 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

View File

@@ -50,4 +50,7 @@ Weapons:
mods/cnc/weapons.yaml: mods/cnc/weapons.yaml:
Voices: Voices:
mods/cnc/voices.yaml: mods/cnc/voices.yaml:
Terrain:
mods/cnc/terrain.yaml

82
mods/cnc/terrain.yaml Normal file
View File

@@ -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

View File

@@ -43,4 +43,7 @@ Weapons:
mods/ra/weapons.yaml mods/ra/weapons.yaml
Voices: Voices:
mods/ra/voices.yaml mods/ra/voices.yaml
Terrain:
mods/ra/terrain.yaml

View File

@@ -88,94 +88,3 @@ TeamDelay=.6 ; interval between checking for and creating teams
; misc ; misc
FineDiffControl=no ; Allow 5 difficulty settings instead of only 3 settings? FineDiffControl=no ; Allow 5 difficulty settings instead of only 3 settings?
LowPowerSlowdown=3 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

82
mods/ra/terrain.yaml Normal file
View File

@@ -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