Added UnitInfo.

- units.txt turned into infantry.txt and vehicles.txt
    - slight sidebar fixes
This commit is contained in:
Bob
2009-10-09 21:28:56 +13:00
parent 02f0b882cb
commit 04dd5e68ba
13 changed files with 294 additions and 100 deletions

View File

@@ -30,7 +30,9 @@ namespace OpenRa.Game
public Game(string mapName, Renderer renderer, int2 clientSize)
{
for (int i = 0; i < 8; i++)
Rules.LoadRules();
for( int i = 0 ; i < 8 ; i++ )
players.Add(i, new Player(i, string.Format("Multi{0}", i), OpenRa.TechTree.Race.Soviet));
map = new Map(new IniFile(FileSystem.Open(mapName)));

19
OpenRa.Game/GameRules/Rules.cs Executable file
View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRa.FileFormats;
using OpenRa.Game.GameRules;
namespace OpenRa.Game
{
static class Rules
{
public static UnitInfo UnitInfo;
// TODO: load rules from the map, where appropriate.
public static void LoadRules()
{
UnitInfo = new UnitInfo( new IniFile( FileSystem.Open( "rules.ini" ) ) );
}
}
}

200
OpenRa.Game/GameRules/UnitInfo.cs Executable file
View File

@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using OpenRa.FileFormats;
using OpenRa.Game.Graphics;
namespace OpenRa.Game.GameRules
{
public class UnitInfo
{
static bool ParseYesNo( string p )
{
p = p.ToLowerInvariant();
if( p == "yes" ) return true;
if( p == "true" ) return true;
if( p == "no" ) return false;
if( p == "false" ) return false;
throw new InvalidOperationException();
}
readonly Dictionary<string, BaseInfo> unitInfos = new Dictionary<string, BaseInfo>();
public UnitInfo( IniFile rules )
{
foreach( var s in Util.ReadAllLines( FileSystem.Open( "buildings.txt" ) ) )
{
var unitName = s.Split( ',' )[ 0 ];
unitInfos.Add( unitName.ToLowerInvariant(), new BuildingInfo( unitName, rules.GetSection( unitName ) ) );
}
foreach( var s in Util.ReadAllLines( FileSystem.Open( "infantry.txt" ) ) )
{
var unitName = s.Split( ',' )[ 0 ];
unitInfos.Add( unitName.ToLowerInvariant(), new InfantryInfo( unitName, rules.GetSection( unitName ) ) );
}
foreach( var s in Util.ReadAllLines( FileSystem.Open( "vehicles.txt" ) ) )
{
var unitName = s.Split( ',' )[ 0 ];
unitInfos.Add( unitName.ToLowerInvariant(), new VehicleInfo( unitName, rules.GetSection( unitName ) ) );
}
}
public BaseInfo Get( string unitName )
{
return unitInfos[ unitName.ToLowerInvariant() ];
}
public enum ArmorType
{
none = 0,
wood = 1,
light = 2,
heavy = 3,
concrete = 4,
}
public class BaseInfo
{
public readonly string Name;
public readonly int Ammo = -1;
public readonly ArmorType Armor = ArmorType.none;
public readonly bool DoubleOwned = false;
public readonly bool Cloakable = false;
public readonly int Cost = 0;
public readonly bool Crewed = false;
public readonly bool Explodes = false;
public readonly int GuardRange = -1; // -1 = use weapon's range
public readonly string Image = null; // sprite-set to use when rendering
public readonly bool Invisible = false;
public readonly string Owner = "allies,soviet"; // TODO: make this an enum
public readonly int Points = 0;
public readonly string Prerequisite = "";
public readonly string Primary = null;
public readonly string Secondary = null;
public readonly int ROT = 0;
public readonly int Reload = 0;
public readonly bool SelfHealing = false;
public readonly bool Sensors = false; // no idea what this does
public readonly int Sight = 1;
public readonly int Strength = 1;
public readonly int TechLevel = -1;
public BaseInfo( string name, IniSection ini )
{
Name = name;
foreach( var x in ini )
{
var field = this.GetType().GetField( x.Key );
if( field.FieldType == typeof( int ) )
field.SetValue( this, int.Parse( x.Value ) );
else if( field.FieldType == typeof( float ) )
field.SetValue( this, float.Parse( x.Value ) );
else if( field.FieldType == typeof( string ) )
field.SetValue( this, x.Value );
else if( field.FieldType == typeof( ArmorType ) )
field.SetValue( this, Enum.Parse( typeof( ArmorType ), x.Value ) );
else if( field.FieldType == typeof( bool ) )
field.SetValue( this, ParseYesNo( x.Value ) );
else
do { } while( false );
}
}
}
public class MobileInfo : BaseInfo
{
public readonly int Passengers = 0;
public readonly int Speed = 0;
public MobileInfo( string name, IniSection ini )
: base( name, ini )
{
}
}
public class InfantryInfo : MobileInfo
{
public readonly bool C4 = false;
public readonly bool FraidyCat = false;
public readonly bool Infiltrate = false;
public readonly bool IsCanine = false;
public InfantryInfo( string name, IniSection ini )
: base( name, ini )
{
}
}
public class VehicleInfo : MobileInfo
{
public readonly bool Crushable = false;
public readonly bool Tracked = false;
public readonly bool NoMovingFire = false;
public VehicleInfo( string name, IniSection ini )
: base( name, ini )
{
}
}
public class BuildingInfo : BaseInfo
{
public readonly bool BaseNormal = true;
public readonly int Adjacent = 1;
public readonly bool Bib = false;
public readonly bool Capturable = false;
public readonly int Power = 0;
public readonly bool Powered = false;
public readonly bool Repairable = true;
public readonly int Storage = 0;
public readonly bool Unsellable = false;
public readonly bool WaterBound = false;
public BuildingInfo( string name, IniSection ini )
: base( name, ini )
{
}
}
/*
* Example: HARV
* Unit (can move, etc)
* PlayerOwned
* Selectable
* CanHarvest
*
* Example: PROC (refinery)
* Building (can't move)
* AcceptsOre (harvester returns here)
*
* Example: 3TNK (soviet heavy tank)
* Unit
* Turret (can aim in different direction to movement)
*
* Example: GUN (allied base defense turret)
* Building
* Turret
*
* some traits can be determined by fields in rules.ini
* and some can't :
* Gap-generator's ability
* Nuke, chrone, curtain, (super-weapons)
* Aircraft-landable
* Selectable (bomber/spyplane can't be selected, for example)
* AppearsFriendly (spy)
* IsInfantry (can be build in TENT/BARR, 5-in-a-square)
* IsVehicle
* Squashable (sandbags, infantry)
* Special rendering for war factory
*/
}
}

View File

@@ -23,8 +23,12 @@ namespace OpenRa.Game.Graphics
{
List<string> result = new List<string>();
using (StreamReader reader = new StreamReader(s))
while (!reader.EndOfStream)
result.Add(reader.ReadLine());
while(!reader.EndOfStream)
{
var line = reader.ReadLine();
if( !string.IsNullOrEmpty( line ) && line[0] != '#' )
result.Add( line );
}
return result.ToArray();
}

View File

@@ -72,6 +72,8 @@
<ItemGroup>
<Compile Include="Actor.cs" />
<Compile Include="Controller.cs" />
<Compile Include="GameRules\Rules.cs" />
<Compile Include="GameRules\UnitInfo.cs" />
<Compile Include="Graphics\Animation.cs" />
<Compile Include="Building.cs" />
<Compile Include="Game.cs" />
@@ -83,7 +85,6 @@
<Compile Include="Player.cs" />
<Compile Include="PlayerOwned.cs" />
<Compile Include="Race.cs" />
<Compile Include="Rules.cs" />
<Compile Include="Support\SharedResources.cs" />
<Compile Include="Graphics\Sheet.cs" />
<Compile Include="Support\Log.cs" />
@@ -115,7 +116,6 @@
<Compile Include="Graphics\TreeCache.cs" />
<Compile Include="UiOverlay.cs" />
<Compile Include="Unit.cs" />
<Compile Include="UnitInfo.cs" />
<Compile Include="UnitMissions.cs" />
<Compile Include="Graphics\UnitSheetBuilder.cs" />
<Compile Include="Graphics\Util.cs" />

View File

@@ -1,36 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using OpenRa.FileFormats;
using OpenRa.Game.Graphics;
namespace OpenRa.Game
{
static class Rules
{
static readonly Dictionary<string, UnitInfo> unitInfos = new Dictionary<string, UnitInfo>();
static Rules()
{
var rulesIni = SharedResources.Rules;
foreach (string line in Util.ReadAllLines(FileSystem.Open("units.txt")))
{
string unit = line.Substring( 0, line.IndexOf( ',' ) ).ToUpperInvariant();
IniSection section = rulesIni.GetSection( unit );
if (section == null)
{
Log.Write("rules.ini doesnt contain entry for unit \"{0}\"", unit);
continue;
}
unitInfos.Add( unit, new UnitInfo( unit, section ) );
}
}
public static UnitInfo UnitInfo( string name )
{
return unitInfos[ name.ToUpperInvariant() ];
}
}
}

View File

@@ -45,7 +45,8 @@ namespace OpenRa.Game
clockRenderer = new SpriteRenderer(renderer, true);
LoadSprites("buildings.txt");
LoadSprites("units.txt");
LoadSprites("vehicles.txt");
LoadSprites("infantry.txt");
foreach (string s in groups)
{
@@ -159,6 +160,16 @@ namespace OpenRa.Game
}
}
}
else if( mi.Button == MouseButtons.Right && mi.Event == MouseInputEvent.Down )
{
var point = new float2(mi.Location.X, mi.Location.Y);
var item = GetItem(point);
if( item != null )
{
string group = itemGroups[ item.techTreeItem.tag ];
selectedItems[ group ] = null;
}
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using OpenRa.FileFormats;
using OpenRa.Game.GameRules;
namespace OpenRa.TechTree
{
@@ -10,31 +11,26 @@ namespace OpenRa.TechTree
public bool IsStructure { get { return isStructure; } }
public Item(string tag, string friendlyName, IniSection section, bool isStructure)
public Item(string tag, string friendlyName, UnitInfo.BaseInfo unitInfo, bool isStructure)
{
this.tag = tag;
this.friendlyName = friendlyName;
this.isStructure = isStructure;
owner = ParseOwner(section);
techLevel = ParseTechLevel(section);
Tuple<string[], string[]> pre = ParsePrerequisites(section, tag);
owner = ParseOwner(unitInfo.Owner, unitInfo.DoubleOwned);
techLevel = unitInfo.TechLevel;
Tuple<string[], string[]> pre = ParsePrerequisites(unitInfo.Prerequisite, tag);
alliedPrerequisites = pre.a;
sovietPrerequisites = pre.b;
}
static int ParseTechLevel(IniSection section)
static Race ParseOwner(string owners, bool doubleOwned)
{
return int.Parse(section.GetValue("TechLevel", "-1"));
}
static Race ParseOwner(IniSection section)
{
if (section.GetValue("DoubleOwned", "No") == "Yes")
if (doubleOwned)
return Race.Allies | Race.Soviet;
Race race = Race.None;
string[] frags = section.GetValue("Owner", "").Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
string[] frags = owners.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string s in frags)
race |= (Race)Enum.Parse(typeof(Race), s, true);
@@ -42,9 +38,9 @@ namespace OpenRa.TechTree
return race;
}
static Tuple<string[],string[]> ParsePrerequisites(IniSection section, string tag)
static Tuple<string[],string[]> ParsePrerequisites(string prerequisites, string tag)
{
List<string> allied = new List<string>(section.GetValue("Prerequisite", "").ToUpper().Split(
List<string> allied = new List<string>(prerequisites.ToUpper().Split(
new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries));
List<string> soviet = new List<string>(allied);

View File

@@ -55,14 +55,15 @@ namespace OpenRa.TechTree
void LoadRules()
{
IEnumerable<Tuple<string, string, bool>> definitions = Concat(
IEnumerable<Tuple<string, string, bool>> definitions = Concat( Concat(
Lines("buildings.txt", true),
Lines("units.txt", false));
Lines("vehicles.txt", false) ),
Lines("infantry.txt", false) );
var rules = SharedResources.Rules;
foreach (Tuple<string, string, bool> p in definitions)
objects.Add(p.a, new Item(p.a, p.b, rules.GetSection(p.a), p.c));
objects.Add(p.a, new Item(p.a, p.b, Rules.UnitInfo.Get(p.a), p.c));
}
public bool Build(string key, bool force)
@@ -102,7 +103,8 @@ namespace OpenRa.TechTree
changed = true;
}
if (changed) BuildableItemsChanged();
//if (changed)
BuildableItemsChanged();
}
public IEnumerable<Item> BuildableItems

View File

@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRa.Game.Graphics;
using IjwFramework.Types;
using OpenRa.Game.GameRules;
using OpenRa.Game.Graphics;
namespace OpenRa.Game
{
@@ -20,7 +20,7 @@ namespace OpenRa.Game
public int moveFraction, moveFractionTotal;
readonly float2 renderOffset;
public readonly UnitInfo unitInfo;
public readonly UnitInfo.MobileInfo unitInfo;
public Unit( string name, int2 cell, Player owner, Game game )
: base( game, name, cell )
@@ -28,7 +28,7 @@ namespace OpenRa.Game
fromCell = toCell = cell;
this.owner = owner;
this.unitInfo = Rules.UnitInfo( name );
this.unitInfo = (UnitInfo.MobileInfo)Rules.UnitInfo.Get( name );
animation.PlayFetchIndex( "idle", () => facing );
renderOffset = animation.Center;
@@ -90,7 +90,11 @@ namespace OpenRa.Game
bool SupportsMission( SupportedMissions mission )
{
return mission == ( unitInfo.supportedMissions & mission );
if( mission == SupportedMissions.Deploy )
return this.unitInfo.Name == "MCV";
if( mission == SupportedMissions.Harvest )
return this.unitInfo.Name == "HARV";
return false;
}
public Order Order( Game game, int2 xy )

View File

@@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.FileFormats;
namespace OpenRa.Game
{
class UnitInfo
{
public readonly int Speed;
public readonly SupportedMissions supportedMissions;
public UnitInfo(string unitName, IniSection ini)
{
Speed = int.Parse(ini.GetValue("Speed", "0"));
supportedMissions = SupportedMissions.Stop;
if (unitName == "MCV")
supportedMissions |= SupportedMissions.Deploy;
if (unitName == "HARV")
supportedMissions |= SupportedMissions.Harvest;
}
}
}