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)
{
@@ -158,6 +159,16 @@ namespace OpenRa.Game
Build(item);
}
}
}
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;
}
}
}

17
infantry.txt Executable file
View File

@@ -0,0 +1,17 @@
#
# The infantry that we (currently) support.
#
DOG,Attack Dog,infantry
E1,Rifle Infantry,infantry
E2,Grenadier,infantry
E3,Rocket Soldier,infantry
E4,Flamethrower,infantry
E6,Engineer,infantry
SPY,Spy,infantry
THF,Thief,infantry
E7,Tanya,infantry
MEDI,Medic,infantry
# TODO: civilians, special (campaign) units

20
units.txt → vehicles.txt Normal file → Executable file
View File

@@ -1,3 +1,7 @@
#
# The vehicles that we (currently) support.
#
V2RL,V2 Rocket,vehicle
1TNK,Light Tank,vehicle
3TNK,Heavy Tank,vehicle
@@ -11,23 +15,19 @@ MCV,Mobile Construction Vehicle,vehicle
JEEP,Ranger,vehicle
APC,Armored Personnel Carrier,vehicle
MNLY,Minelayer,vehicle
# TODO: move ships and planes into their own files
SS,Submarine,boat
DD,Destroyer,boat
CA,Cruiser,boat
LST,Transport,boat
PT,Gunboat,boat
DOG,Attack Dog,infantry
E1,Rifle Infantry,infantry
E2,Grenadier,infantry
E3,Rocket Soldier,infantry
E4,Flamethrower,infantry
E6,Engineer,infantry
SPY,Spy,infantry
THF,Thief,infantry
E7,Tanya,infantry
MEDI,Medic,infantry
MIG,Mig Attack Plane,plane
YAK,Yak Attack Plane,plane
TRAN,Transport Helicopter,plane
HELI,Longbow,plane
HIND,Hind,plane
# TODO: U2 (spyplane), BADR (paratrooper/paradrop plane)