diff --git a/OpenRa.DataStructures/OpenRa.DataStructures.csproj b/OpenRa.DataStructures/OpenRa.DataStructures.csproj index 8da1f21edd..b0d2c9ca21 100644 --- a/OpenRa.DataStructures/OpenRa.DataStructures.csproj +++ b/OpenRa.DataStructures/OpenRa.DataStructures.csproj @@ -33,6 +33,10 @@ prompt + + False + ..\Ijw.DirectX\Release\IjwFramework.dll + 3.5 diff --git a/OpenRa.DataStructures/TypeDictionary.cs b/OpenRa.DataStructures/TypeDictionary.cs index 574e624cbe..81fedaf549 100755 --- a/OpenRa.DataStructures/TypeDictionary.cs +++ b/OpenRa.DataStructures/TypeDictionary.cs @@ -1,50 +1,56 @@ using System; using System.Collections.Generic; -using System.Text; +using System.Linq; +using System.Reflection; +using IjwFramework.Collections; namespace OpenRa { public class TypeDictionary { - Dictionary inner = new Dictionary(); - - public void Add( Type t, object val ) - { - inner.Add( t, val ); - } + Cache> innerInherit = new Cache>( _ => new List() ); public void Add( object val ) { - Add( val.GetType(), val ); - } + var t = val.GetType(); - public void Remove() - { - inner.Remove( typeof( T ) ); + foreach( var i in t.GetInterfaces() ) + innerInherit[ i ].Add( val ); + foreach( var tt in t.BaseTypes() ) + innerInherit[ tt ].Add( val ); } public bool Contains() { - return inner.ContainsKey( typeof( T ) ); + return innerInherit[ typeof( T ) ].Count != 0; } public T Get() { - return (T)inner[ typeof( T ) ]; + var l = innerInherit[ typeof( T ) ]; + if( l.Count == 1 ) + return (T)l[ 0 ]; + else if( l.Count == 0 ) + throw new InvalidOperationException( string.Format( "TypeDictionary does not contain instance of type `{0}`", typeof( T ) ) ); + else + throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); } public T GetOrDefault() { - object o = null; - inner.TryGetValue(typeof(T), out o); - return (T)o; + var l = innerInherit[ typeof( T ) ]; + if( l.Count == 1 ) + return (T)l[ 0 ]; + else if( l.Count == 0 ) + return default( T ); + else + throw new InvalidOperationException( string.Format( "TypeDictionary contains multiple instance of type `{0}`", typeof( T ) ) ); } public IEnumerable WithInterface() { - foreach( var i in inner ) - if( i.Value is T ) - yield return (T)i.Value; + foreach( var i in innerInherit[ typeof( T ) ] ) + yield return (T)i; } public IEnumerator GetEnumerator() @@ -52,4 +58,16 @@ namespace OpenRa return WithInterface().GetEnumerator(); } } + + static class TypeExts + { + public static IEnumerable BaseTypes( this Type t ) + { + while( t != null ) + { + yield return t; + t = t.BaseType; + } + } + } } diff --git a/OpenRa.FileFormats/MiniYaml.cs b/OpenRa.FileFormats/MiniYaml.cs new file mode 100755 index 0000000000..b26b69d9b1 --- /dev/null +++ b/OpenRa.FileFormats/MiniYaml.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; + +namespace OpenRa.FileFormats +{ + public class MiniYaml + { + public string Value; + public Dictionary Nodes = new Dictionary(); + + public MiniYaml( string value ) : this( value, new Dictionary() ) { } + + public MiniYaml( string value, Dictionary nodes ) + { + Value = value; + Nodes = nodes; + } + + public static Dictionary FromFile( string path ) + { + var lines = File.ReadAllLines( path ); + + var levels = new List>(); + levels.Add( new Dictionary() ); + + foreach( var line in lines ) + { + var t = line.TrimStart( ' ', '\t' ); + if( t.Length == 0 || t[ 0 ] == '#' ) + continue; + var level = line.Length - t.Length; + + if( levels.Count <= level ) + throw new InvalidOperationException( "Bad indent in miniyaml" ); + while( levels.Count > level + 1 ) + levels.RemoveAt( levels.Count - 1 ); + + var colon = t.IndexOf( ':' ); + var d = new Dictionary(); + + if( colon == -1 ) + levels[ level ].Add( t.Trim(), new MiniYaml( null, d ) ); + else + { + var value = t.Substring( colon + 1 ).Trim(); + if( value.Length == 0 ) + value = null; + levels[ level ].Add( t.Substring( 0, colon ).Trim(), new MiniYaml( value, d ) ); + } + levels.Add( d ); + } + return levels[ 0 ]; + } + + public static Dictionary Merge( Dictionary a, Dictionary b ) + { + if( a.Count == 0 ) + return b; + if( b.Count == 0 ) + return a; + + var ret = new Dictionary(); + + var keys = a.Keys.Union( b.Keys ).ToList(); + + foreach( var key in keys ) + { + MiniYaml aa, bb; + a.TryGetValue( key, out aa ); + b.TryGetValue( key, out bb ); + ret.Add( key, Merge( aa, bb ) ); + } + + return ret; + } + + public static MiniYaml Merge( MiniYaml a, MiniYaml b ) + { + if( a == null ) + return b; + if( b == null ) + return a; + + return new MiniYaml( a.Value ?? b.Value, Merge( a.Nodes, b.Nodes ) ); + } + } +} diff --git a/OpenRa.FileFormats/OpenRa.FileFormats.csproj b/OpenRa.FileFormats/OpenRa.FileFormats.csproj index 0016cbc237..5c8fd2cd1b 100644 --- a/OpenRa.FileFormats/OpenRa.FileFormats.csproj +++ b/OpenRa.FileFormats/OpenRa.FileFormats.csproj @@ -57,6 +57,7 @@ + diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 2c7e3b9677..0d8b72f5a6 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -12,8 +12,7 @@ namespace OpenRa.Game { [Sync] public readonly TypeDictionary traits = new TypeDictionary(); - public readonly UnitInfo Info; - + public readonly NewUnitInfo Info; public readonly uint ActorID; [Sync] public int2 Location; @@ -23,33 +22,21 @@ namespace OpenRa.Game public int Health; IActivity currentActivity; - object ConstructTrait(string traitName) - { - /* todo: allow mods to introduce traits */ - var type = typeof(Mobile).Assembly.GetType(typeof(Mobile).Namespace + "." + traitName, true, false); - var ctor = type.GetConstructor(new[] { typeof(Actor) }); - if (ctor == null) - throw new InvalidOperationException("Trait {0} does not have the correct constructor: {0}(Actor self)".F(type.Name)); - return ctor.Invoke(new object[] { this }); - } - - public Actor( ActorInfo info, int2 location, Player owner ) + public Actor( string name, int2 location, Player owner ) { ActorID = Game.world.NextAID(); - Info = (UnitInfo)info; // temporary Location = location; CenterLocation = Traits.Util.CenterOfCell(Location); Owner = owner; - if (Info == null) return; + if (name != null) + { + Info = Rules.NewUnitInfo[name.ToLowerInvariant()]; + Health = this.GetMaxHP(); - Health = Info.Strength; /* todo: fix walls, etc so this is always true! */ - - if( Info.Traits == null ) - throw new InvalidOperationException( "No Actor traits for {0}; add Traits= to units.ini for appropriate unit".F(Info.Name) ); - - foreach (var traitName in Info.Traits) - traits.Add(ConstructTrait(traitName)); + foreach (var trait in Info.Traits.WithInterface()) + traits.Add(trait.Create(this)); + } } public void Tick() @@ -71,12 +58,13 @@ namespace OpenRa.Game } public float2 CenterLocation; - public float2 SelectedSize + float2 SelectedSize { - get + get // todo: inline into GetBounds { - if (Info != null && Info.SelectionSize != null) - return new float2(Info.SelectionSize[0], Info.SelectionSize[1]); + var si = Info != null ? Info.Traits.GetOrDefault() : null; + if (si != null && si.Bounds != null) + return new float2(si.Bounds[0], si.Bounds[1]); var firstSprite = Render().FirstOrDefault(); if (firstSprite.Sprite == null) return float2.Zero; @@ -102,7 +90,7 @@ namespace OpenRa.Game var loc = mi.Location + Game.viewport.Location; var underCursor = Game.FindUnits(loc, loc).FirstOrDefault(); - if (underCursor != null && !underCursor.Info.Selectable) + if (underCursor != null && !underCursor.traits.Contains()) underCursor = null; return traits.WithInterface() @@ -112,10 +100,13 @@ namespace OpenRa.Game public RectangleF GetBounds(bool useAltitude) { + var si = Info != null ? Info.Traits.GetOrDefault() : null; + var size = SelectedSize; var loc = CenterLocation - 0.5f * size; - if (Info != null && Info.SelectionSize != null && Info.SelectionSize.Length > 2) - loc += new float2(Info.SelectionSize[2], Info.SelectionSize[3]); + + if (si != null && si.Bounds != null && si.Bounds.Length > 2) + loc += new float2(si.Bounds[2], si.Bounds[3]); if (useAltitude) { @@ -132,7 +123,7 @@ namespace OpenRa.Game public DamageState GetDamageState() { if (Health <= 0) return DamageState.Dead; - var halfStrength = Info.Strength * Rules.General.ConditionYellow; + var halfStrength = this.GetMaxHP() * Rules.General.ConditionYellow; return Health < halfStrength ? DamageState.Half : DamageState.Normal; } @@ -155,8 +146,10 @@ namespace OpenRa.Game Game.world.AddFrameEndTask(w => w.Remove(this)); } - if (Health > Info.Strength) - Health = Info.Strength; + + var maxHP = this.GetMaxHP(); + + if (Health > maxHP) Health = maxHP; var newState = GetDamageState(); diff --git a/OpenRa.Game/BuildingInfluenceMap.cs b/OpenRa.Game/BuildingInfluenceMap.cs index 636a75bdd9..4d8f7bfb54 100644 --- a/OpenRa.Game/BuildingInfluenceMap.cs +++ b/OpenRa.Game/BuildingInfluenceMap.cs @@ -18,15 +18,15 @@ namespace OpenRa.Game ChangeInfluence(a, a.traits.Get(), false); }; } - void ChangeInfluence(Actor a, Building building, bool isAdd) + void ChangeInfluence( Actor a, Building building, bool isAdd ) { - foreach (var u in Footprint.UnpathableTiles(building.unitInfo, a.Location)) - if (IsValid(u)) - blocked[u.X, u.Y] = isAdd; + foreach( var u in Footprint.UnpathableTiles( a.Info.Name, a.Info.Traits.Get(), a.Location ) ) + if( IsValid( u ) ) + blocked[ u.X, u.Y ] = isAdd; - foreach (var u in Footprint.Tiles(building.unitInfo, a.Location, false)) - if (IsValid(u)) - influence[u.X, u.Y] = isAdd ? a : null; + foreach( var u in Footprint.Tiles( a.Info.Name, a.Info.Traits.Get(), a.Location, false ) ) + if( IsValid( u ) ) + influence[ u.X, u.Y ] = isAdd ? a : null; } bool IsValid(int2 t) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index f114ab494b..e584be55bc 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -112,10 +112,10 @@ namespace OpenRa.Game tabSprites = groups .SelectMany(g => Rules.Categories[g]) - .Where(u => Rules.UnitInfo[u].TechLevel != -1) + .Where(u => Rules.NewUnitInfo[u].Traits.Contains()) .ToDictionary( u => u, - u => SpriteSheetBuilder.LoadAllSprites(Rules.UnitInfo[u].Icon ?? (u + "icon"))[0]); + u => SpriteSheetBuilder.LoadAllSprites(Rules.NewUnitInfo[u].Traits.Get().Icon ?? (u + "icon"))[0]); spsprites = Rules.SupportPowerInfo .ToDictionary( @@ -216,7 +216,7 @@ namespace OpenRa.Game { var hasNewRadar = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains() - && a.traits.Get().IsActive()); + && a.traits.Get().IsActive(a)); if (hasNewRadar != hasRadar) { @@ -529,8 +529,9 @@ namespace OpenRa.Game var buildableItems = Rules.TechTree.BuildableItems(Game.LocalPlayer, queueName).ToArray(); var allItems = Rules.TechTree.AllItems(Game.LocalPlayer, queueName) - .Where(a => Rules.UnitInfo[a].TechLevel != -1) - .OrderBy(a => Rules.UnitInfo[a].TechLevel); + .Where(a => Rules.NewUnitInfo[a].Traits.Contains()) + .Where(a => Rules.NewUnitInfo[a].Traits.Get().Owner.Contains(Game.LocalPlayer.Race)) + .OrderBy(a => Rules.NewUnitInfo[a].Traits.Get().TechLevel); var queue = Game.LocalPlayer.PlayerActor.traits.Get(); @@ -729,14 +730,15 @@ namespace OpenRa.Game rgbaRenderer.DrawSprite(tooltipSprite, p, PaletteType.Chrome); rgbaRenderer.Flush(); - var info = Rules.UnitInfo[unit]; + var info = Rules.NewUnitInfo[unit]; + var buildable = info.Traits.Get(); - renderer.DrawText2(info.Description, p.ToInt2() + new int2(5,5), Color.White); + renderer.DrawText2(buildable.Description, p.ToInt2() + new int2(5,5), Color.White); - DrawRightAligned( "${0}".F(info.Cost), pos + new int2(-5,5), - Game.LocalPlayer.Cash + Game.LocalPlayer.Ore >= info.Cost ? Color.White : Color.Red); + DrawRightAligned( "${0}".F(buildable.Cost), pos + new int2(-5,5), + Game.LocalPlayer.Cash + Game.LocalPlayer.Ore >= buildable.Cost ? Color.White : Color.Red); - var bi = info as BuildingInfo; + var bi = info.Traits.GetOrDefault(); if (bi != null) DrawRightAligned("ϟ{0}".F(bi.Power), pos + new int2(-5, 20), Game.LocalPlayer.PowerProvided - Game.LocalPlayer.PowerDrained + bi.Power >= 0 @@ -747,21 +749,27 @@ namespace OpenRa.Game p += new int2(0, 15); if (!Rules.TechTree.CanBuild(info, Game.LocalPlayer, buildings)) { - var prereqs = info.Prerequisite - .Select(a => Rules.UnitInfo[a.ToLowerInvariant()]) - .Where( u => u.Owner.Any( o => o == Game.LocalPlayer.Race ) ) - .Select( a => a.Description ); + var prereqs = buildable.Prerequisites + .Select( a => Description( a ) ); renderer.DrawText("Requires {0}".F( string.Join( ", ", prereqs.ToArray() ) ), p.ToInt2(), Color.White); } - if (info.LongDesc != null) + if (buildable.LongDesc != null) { p += new int2(0, 15); - renderer.DrawText(info.LongDesc.Replace( "\\n", "\n" ), p.ToInt2(), Color.White); + renderer.DrawText(buildable.LongDesc.Replace( "\\n", "\n" ), p.ToInt2(), Color.White); } } + private static string Description( string a ) + { + if( a[ 0 ] == '@' ) + return "any " + a.Substring( 1 ); + else + return Rules.NewUnitInfo[ a.ToLowerInvariant() ].Traits.Get().Description; + } + void DrawSupportPowers() { var numPowers = Game.LocalPlayer.SupportPowers.Values diff --git a/OpenRa.Game/Combat.cs b/OpenRa.Game/Combat.cs index b6cb373754..7cd6c5cfa8 100644 --- a/OpenRa.Game/Combat.cs +++ b/OpenRa.Game/Combat.cs @@ -49,7 +49,7 @@ namespace OpenRa.Game var distance = (target.CenterLocation - loc).Length*1/24f; var rawDamage = weapon.Damage * (float)Math.Exp(-distance / warhead.Spread); - var multiplier = warhead.EffectivenessAgainst(target.Info.Armor); + var multiplier = warhead.EffectivenessAgainst(target.Info.Traits.Get().Armor); return rawDamage * multiplier; } @@ -59,7 +59,7 @@ namespace OpenRa.Game var warhead = Rules.WarheadInfo[weapon.Warhead]; var unit = target.traits.GetOrDefault(); - if (warhead.EffectivenessAgainst(target.Info.Armor) <= 0) + if (warhead.EffectivenessAgainst(target.Info.Traits.Get().Armor) <= 0) return false; if (target.traits.Contains()) @@ -68,7 +68,7 @@ namespace OpenRa.Game if (unit != null && unit.Altitude > 0) return projectile.AA; - if (projectile.UnderWater && !target.Info.WaterBound) + if (projectile.UnderWater && !target.Info.Traits.Get().WaterBound) return false; return projectile.AG; @@ -76,10 +76,11 @@ namespace OpenRa.Game public static bool HasAnyValidWeapons(Actor self, Actor target) { - if (self.Info.Primary != null && - WeaponValidForTarget(Rules.WeaponInfo[self.Info.Primary], target)) return true; - if (self.Info.Secondary != null && - WeaponValidForTarget(Rules.WeaponInfo[self.Info.Secondary], target)) return true; + var info = self.Info.Traits.Get(); + if (info.PrimaryWeapon != null && + WeaponValidForTarget(self.GetPrimaryWeapon(), target)) return true; + if (info.SecondaryWeapon != null && + WeaponValidForTarget(self.GetSecondaryWeapon(), target)) return true; return false; } diff --git a/OpenRa.Game/Effects/Bullet.cs b/OpenRa.Game/Effects/Bullet.cs index 5104585dd3..15b6e80fc8 100755 --- a/OpenRa.Game/Effects/Bullet.cs +++ b/OpenRa.Game/Effects/Bullet.cs @@ -23,8 +23,12 @@ namespace OpenRa.Game.Effects const int BaseBulletSpeed = 100; /* pixels / 40ms frame */ + public Bullet(string weapon, Player owner, Actor firedBy, + int2 src, int2 dest, int srcAltitude, int destAltitude) + : this(Rules.WeaponInfo[weapon], owner, firedBy, src, dest, srcAltitude, destAltitude) { } + /* src, dest are *pixel* coords */ - public Bullet(string weapon, Player owner, Actor firedBy, + public Bullet(WeaponInfo weapon, Player owner, Actor firedBy, int2 src, int2 dest, int srcAltitude, int destAltitude) { Owner = owner; @@ -36,7 +40,7 @@ namespace OpenRa.Game.Effects VisualDest = Dest + new int2( Game.CosmeticRandom.Next(-10, 10), Game.CosmeticRandom.Next(-10, 10)); - Weapon = Rules.WeaponInfo[weapon]; + Weapon = weapon; Projectile = Rules.ProjectileInfo[Weapon.Projectile]; Warhead = Rules.WarheadInfo[Weapon.Warhead]; diff --git a/OpenRa.Game/Effects/Corpse.cs b/OpenRa.Game/Effects/Corpse.cs index efdbf8cb4c..2e89a40d7b 100755 --- a/OpenRa.Game/Effects/Corpse.cs +++ b/OpenRa.Game/Effects/Corpse.cs @@ -15,7 +15,7 @@ namespace OpenRa.Game.Effects public Corpse(Actor fromActor, int death) { - anim = new Animation(fromActor.Info.Image ?? fromActor.Info.Name); + anim = new Animation(fromActor.traits.GetOrDefault().GetImage(fromActor)); anim.PlayThen("die{0}".F(death + 1), () => Game.world.AddFrameEndTask(w => w.Remove(this))); diff --git a/OpenRa.Game/Effects/Missile.cs b/OpenRa.Game/Effects/Missile.cs index c0247567d1..bf71137b03 100755 --- a/OpenRa.Game/Effects/Missile.cs +++ b/OpenRa.Game/Effects/Missile.cs @@ -20,10 +20,10 @@ namespace OpenRa.Game.Effects int t; int Altitude; - public Missile(string weapon, Player owner, Actor firedBy, + public Missile(WeaponInfo weapon, Player owner, Actor firedBy, int2 src, Actor target, int altitude, int facing) { - Weapon = Rules.WeaponInfo[weapon]; + Weapon = weapon; Projectile = Rules.ProjectileInfo[Weapon.Projectile]; Warhead = Rules.WarheadInfo[Weapon.Warhead]; FiredBy = firedBy; diff --git a/OpenRa.Game/Exts.cs b/OpenRa.Game/Exts.cs index 3de1b767a5..e69d1eed42 100644 --- a/OpenRa.Game/Exts.cs +++ b/OpenRa.Game/Exts.cs @@ -2,6 +2,8 @@ using System.Windows.Forms; using System.Collections.Generic; using System.Linq; +using OpenRa.Game.GameRules; +using OpenRa.Game.Traits; namespace OpenRa.Game { @@ -27,5 +29,35 @@ namespace OpenRa.Game { return xs.Aggregate(1f, (a, x) => a * x); } + + public static WeaponInfo GetPrimaryWeapon(this Actor self) + { + var info = self.Info.Traits.GetOrDefault(); + if (info == null) return null; + + var weapon = info.PrimaryWeapon; + if (weapon == null) return null; + + return Rules.WeaponInfo[weapon]; + } + + public static WeaponInfo GetSecondaryWeapon(this Actor self) + { + var info = self.Info.Traits.GetOrDefault(); + if (info == null) return null; + + var weapon = info.SecondaryWeapon; + if (weapon == null) return null; + + return Rules.WeaponInfo[weapon]; + } + + public static int GetMaxHP(this Actor self) + { + if (self.Info == null) return 0; + var oai = self.Info.Traits.GetOrDefault(); + if (oai == null) return 0; + return oai.HP; + } } } diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index df65ce57c7..0773aa2264 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -61,7 +61,7 @@ namespace OpenRa.Game world = new World(); Game.world.ActorAdded += a => { - if (a.Owner != null && a.Info != null) + if (a.Owner != null && a.Info != null && a.Info.Traits.Contains()) a.Owner.Shroud.Explore(a); }; @@ -80,7 +80,7 @@ namespace OpenRa.Game var worldActor = new Actor(null, new int2(int.MaxValue, int.MaxValue), null); worldActor.traits.Add(new Traits.WaterPaletteRotation(worldActor)); worldActor.traits.Add(new Traits.LightPaletteRotator(worldActor)); - worldActor.traits.Add(new Traits.ChronoshiftPaletteEffect(worldActor)); + worldActor.traits.Add(new Traits.ChronoshiftPaletteEffect(worldActor)); Game.world.Add(worldActor); Rules.Map.InitOreDensity(); @@ -96,9 +96,7 @@ namespace OpenRa.Game skipMakeAnims = true; foreach (var treeReference in Rules.Map.Trees) - world.Add(new Actor(Rules.UnitInfo[treeReference.Image], - new int2(treeReference.Location), - null)); + world.Add(new Actor(treeReference.Image, new int2(treeReference.Location), null)); LoadMapActors(Rules.AllRules); skipMakeAnims = false; @@ -149,7 +147,7 @@ namespace OpenRa.Game //num=owner,type,health,location,facing,... var parts = s.Value.Split( ',' ); var loc = int.Parse(parts[3]); - world.Add(new Actor(Rules.UnitInfo[parts[1].ToLowerInvariant()], new int2(loc % 128, loc / 128), + world.Add(new Actor(parts[1].ToLowerInvariant(), new int2(loc % 128, loc / 128), players.Values.FirstOrDefault(p => p.InternalName == parts[0]) ?? players[0])); } } @@ -247,7 +245,7 @@ namespace OpenRa.Game public static bool IsActorCrushableByActor(Actor a, Actor b) { - return IsActorCrushableByMovementType(a, b.traits.WithInterface().FirstOrDefault().GetMovementType()); + return IsActorCrushableByMovementType(a, b.traits.GetOrDefault().GetMovementType()); } public static bool IsActorPathableToCrush(Actor a, UnitMovementType umt) @@ -312,8 +310,8 @@ namespace OpenRa.Game public static IEnumerable SelectActorsInBox(float2 a, float2 b) { return FindUnits(a, b) - .Where( x => x.Info.Selectable ) - .GroupBy(x => (x.Owner == LocalPlayer) ? x.Info.SelectionPriority : 0) + .Where( x => x.traits.Contains() ) + .GroupBy(x => (x.Owner == LocalPlayer) ? x.Info.Traits.Get().Priority : 0) .OrderByDescending(g => g.Key) .Select( g => g.AsEnumerable() ) .DefaultIfEmpty( new Actor[] {} ) @@ -323,15 +321,15 @@ namespace OpenRa.Game public static Random SharedRandom = new Random(0); /* for things that require sync */ public static Random CosmeticRandom = new Random(); /* for things that are just fluff */ - public static bool CanPlaceBuilding(BuildingInfo building, int2 xy, Actor toIgnore, bool adjust) + public static bool CanPlaceBuilding(string name, BuildingInfo building, int2 xy, Actor toIgnore, bool adjust) { - return !Footprint.Tiles(building, xy, adjust).Any( + return !Footprint.Tiles(name, building, xy, adjust).Any( t => !Rules.Map.IsInMap(t.X, t.Y) || Rules.Map.ContainsResource(t) || !Game.IsCellBuildable(t, building.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel, toIgnore)); } - public static bool IsCloseEnoughToBase(Player p, BuildingInfo bi, int2 position) + public static bool IsCloseEnoughToBase(Player p, string buildingName, BuildingInfo bi, int2 position) { var maxDistance = bi.Adjacent + 1; @@ -340,7 +338,7 @@ namespace OpenRa.Game heuristic = loc => { var b = Game.BuildingInfluence.GetBuildingAt(loc); - if (b != null && b.Owner == p && (b.Info as BuildingInfo).BaseNormal) return 0; + if (b != null && b.Owner == p && b.Info.Traits.Get().BaseNormal) return 0; if ((loc - position).Length > maxDistance) return float.PositiveInfinity; /* not quite right */ return 1; @@ -349,7 +347,7 @@ namespace OpenRa.Game ignoreTerrain = true, }; - foreach (var t in Footprint.Tiles(bi, position)) search.AddInitialCell(t); + foreach (var t in Footprint.Tiles(buildingName, bi, position)) search.AddInitialCell(t); return Game.PathFinder.FindPath(search).Count != 0; } diff --git a/OpenRa.Game/GameRules/ArmorType.cs b/OpenRa.Game/GameRules/ArmorType.cs new file mode 100755 index 0000000000..bc2ac7e51b --- /dev/null +++ b/OpenRa.Game/GameRules/ArmorType.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.GameRules +{ + public enum ArmorType + { + none = 0, + wood = 1, + light = 2, + heavy = 3, + concrete = 4, + } +} diff --git a/OpenRa.Game/GameRules/FieldLoader.cs b/OpenRa.Game/GameRules/FieldLoader.cs index bff21b7c5a..71fb420c06 100755 --- a/OpenRa.Game/GameRules/FieldLoader.cs +++ b/OpenRa.Game/GameRules/FieldLoader.cs @@ -1,17 +1,62 @@ using System; using System.Linq; using OpenRa.FileFormats; +using System.Collections.Generic; namespace OpenRa.Game.GameRules { static class FieldLoader { - public static void Load( object self, IniSection ini ) + public static void Load(object self, IniSection ini) { - foreach( var x in ini ) + foreach (var x in ini) { - var field = self.GetType().GetField( x.Key.Trim() ); - field.SetValue( self, GetValue( field.FieldType, x.Value.Trim() ) ); + var field = self.GetType().GetField(x.Key.Trim()); + field.SetValue(self, GetValue(field.FieldType, x.Value.Trim())); + } + } + + public static void Load(object self, MiniYaml my) + { + foreach (var x in my.Nodes) + { + var field = self.GetType().GetField(x.Key.Trim()); + if (field == null) + throw new NotImplementedException("Missing field `{0}` on `{1}`".F(x.Key.Trim(), self.GetType().Name)); + field.SetValue(self, GetValue(field.FieldType, x.Value.Value.Trim())); + } + } + + public static void CheckYaml( object self, Dictionary d ) + { + //foreach( var x in d ) + //{ + // if( x.Key == "Tab" ) continue; + // if( x.Key == "Description" ) continue; + // if( x.Key == "LongDesc" ) continue; + + // var key = x.Key; + // if( key == "Prerequisites" ) key = "Prerequisite"; + // if( key == "HP" ) key = "Strength"; + // if( key == "Priority" ) key = "SelectionPriority"; + // if( key == "Bounds" ) key = "SelectionSize"; + // var field = self.GetType().GetField( key ); + // var old = field.GetValue( self ); + // var neww = GetValue( field.FieldType, x.Value.Value.Trim() ); + // if( old.ToString() != neww.ToString() ) + // throw new NotImplementedException(); + //} + foreach( var x in d ) + { + var key = x.Key; + if( key == "Tab" ) + continue; + if( key == "Prerequisites" ) key = "Prerequisite"; + if( key == "HP" ) key = "Strength"; + if( key == "Priority" ) key = "SelectionPriority"; + if( key == "Bounds" ) key = "SelectionSize"; + var field = self.GetType().GetField( key.Trim() ); + field.SetValue( self, GetValue( field.FieldType, x.Value.Value.Trim() ) ); } } diff --git a/OpenRa.Game/GameRules/Footprint.cs b/OpenRa.Game/GameRules/Footprint.cs index 2a2311496d..63d1306ab8 100644 --- a/OpenRa.Game/GameRules/Footprint.cs +++ b/OpenRa.Game/GameRules/Footprint.cs @@ -1,17 +1,18 @@ using System; using System.Collections.Generic; using System.Linq; +using OpenRa.Game.Traits; namespace OpenRa.Game.GameRules { static class Footprint { - public static IEnumerable Tiles( BuildingInfo buildingInfo, int2 position ) + public static IEnumerable Tiles( string name, BuildingInfo buildingInfo, int2 position ) { - return Tiles(buildingInfo, position, true); + return Tiles(name, buildingInfo, position, true); } - public static IEnumerable Tiles( BuildingInfo buildingInfo, int2 position, bool adjustForPlacement ) + public static IEnumerable Tiles( string name, BuildingInfo buildingInfo, int2 position, bool adjustForPlacement ) { var dim = buildingInfo.Dimensions; @@ -24,19 +25,19 @@ namespace OpenRa.Game.GameRules var adjustment = adjustForPlacement ? AdjustForBuildingSize(buildingInfo) : int2.Zero; - var tiles = TilesWhere(buildingInfo.Name, dim, footprint.ToArray(), a => a != '_'); + var tiles = TilesWhere(name, dim, footprint.ToArray(), a => a != '_'); return tiles.Select(t => t + position - adjustment); } public static IEnumerable Tiles(Actor a, Traits.Building building) { - return Tiles( building.unitInfo, a.Location, false ); + return Tiles( a.Info.Name, a.Info.Traits.Get(), a.Location, false ); } - public static IEnumerable UnpathableTiles( BuildingInfo buildingInfo, int2 position ) + public static IEnumerable UnpathableTiles( string name, BuildingInfo buildingInfo, int2 position ) { var footprint = buildingInfo.Footprint.Where( x => !char.IsWhiteSpace( x ) ).ToArray(); - foreach( var tile in TilesWhere( buildingInfo.Name, buildingInfo.Dimensions, footprint, a => a == 'x' ) ) + foreach( var tile in TilesWhere( name, buildingInfo.Dimensions, footprint, a => a == 'x' ) ) yield return tile + position; } @@ -52,9 +53,9 @@ namespace OpenRa.Game.GameRules yield return new int2( x, y ); } - public static int2 AdjustForBuildingSize( BuildingInfo unitInfo ) + public static int2 AdjustForBuildingSize( BuildingInfo buildingInfo ) { - var dim = unitInfo.Dimensions; + var dim = buildingInfo.Dimensions; return new int2( dim.X / 2, dim.Y > 1 ? ( dim.Y + 1 ) / 2 : 0 ); } } diff --git a/OpenRa.Game/GameRules/NewUnitInfo.cs b/OpenRa.Game/GameRules/NewUnitInfo.cs new file mode 100755 index 0000000000..ec966e037d --- /dev/null +++ b/OpenRa.Game/GameRules/NewUnitInfo.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRa.FileFormats; +using OpenRa.Game.Traits; + +namespace OpenRa.Game.GameRules +{ + class NewUnitInfo + { + public readonly TypeDictionary Traits = new TypeDictionary(); + public readonly string Name; + + public NewUnitInfo( string name, MiniYaml node, Dictionary allUnits ) + { + Name = name; + + foreach( var t in MergeWithParent( node, allUnits ).Nodes ) + if( t.Key != "Inherits" ) + Traits.Add( LoadTraitInfo( t.Key, t.Value ) ); + } + + static MiniYaml GetParent( MiniYaml node, Dictionary allUnits ) + { + MiniYaml inherits; + node.Nodes.TryGetValue( "Inherits", out inherits ); + if( inherits == null || string.IsNullOrEmpty( inherits.Value ) ) + return null; + + MiniYaml parent; + allUnits.TryGetValue( inherits.Value, out parent ); + if( parent == null ) + return null; + + return parent; + } + + static MiniYaml MergeWithParent( MiniYaml node, Dictionary allUnits ) + { + var parent = GetParent( node, allUnits ); + if( parent != null ) + return MiniYaml.Merge( node, MergeWithParent( parent, allUnits ) ); + return node; + } + + static ITraitInfo LoadTraitInfo(string traitName, MiniYaml my) + { + var fullTypeName = typeof(ITraitInfo).Namespace + "." + traitName + "Info"; + var info = (ITraitInfo)typeof(ITraitInfo).Assembly.CreateInstance(fullTypeName); + + if (info == null) + throw new NotImplementedException("Missing traitinfo type `{0}`".F(fullTypeName)); + + FieldLoader.Load(info, my); + return info; + } + } +} diff --git a/OpenRa.Game/GameRules/Rules.cs b/OpenRa.Game/GameRules/Rules.cs index 3a9c135180..7571ac1dc2 100755 --- a/OpenRa.Game/GameRules/Rules.cs +++ b/OpenRa.Game/GameRules/Rules.cs @@ -4,6 +4,7 @@ using System.Linq; using IjwFramework.Types; using OpenRa.FileFormats; using OpenRa.Game.GameRules; +using OpenRa.Game.Traits; namespace OpenRa.Game { @@ -12,7 +13,6 @@ namespace OpenRa.Game public static IniFile AllRules; public static Dictionary> Categories = new Dictionary>(); public static Dictionary UnitCategory; - public static InfoLoader UnitInfo; public static InfoLoader WeaponInfo; public static InfoLoader WarheadInfo; public static InfoLoader ProjectileInfo; @@ -24,6 +24,8 @@ namespace OpenRa.Game public static Map Map; public static TileSet TileSet; + public static Dictionary NewUnitInfo; + public static void LoadRules(string mapFileName, bool useAftermath) { if( useAftermath ) @@ -61,14 +63,6 @@ namespace OpenRa.Game "Plane"); UnitCategory = Categories.SelectMany(x => x.Value.Select(y => new KeyValuePair(y, x.Key))).ToDictionary(x => x.Key, x => x.Value); - UnitInfo = new InfoLoader( - Pair.New>("Building", s => new BuildingInfo(s)), - Pair.New>("Defense", s => new BuildingInfo(s)), - Pair.New>("Infantry", s => new InfantryInfo(s)), - Pair.New>("Vehicle", s => new VehicleInfo(s)), - Pair.New>("Ship", s => new VehicleInfo(s)), - Pair.New>("Plane", s => new VehicleInfo(s))); - LoadCategories( "Weapon", "Warhead", @@ -87,6 +81,14 @@ namespace OpenRa.Game SupportPowerInfo = new InfoLoader( Pair.New>("SupportPower", _ => new SupportPowerInfo())); + var yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "ra.yaml" ), MiniYaml.FromFile( "defaults.yaml" ) ); + if( useAftermath ) + yamlRules = MiniYaml.Merge( MiniYaml.FromFile( "aftermath.yaml" ), yamlRules ); + + NewUnitInfo = new Dictionary(); + foreach( var kv in yamlRules ) + NewUnitInfo.Add(kv.Key.ToLowerInvariant(), new NewUnitInfo(kv.Key.ToLowerInvariant(), kv.Value, yamlRules)); + TechTree = new TechTree(); Map = new Map( AllRules ); FileSystem.MountTemporary( new Package( Rules.Map.Theater + ".mix" ) ); diff --git a/OpenRa.Game/GameRules/TechTree.cs b/OpenRa.Game/GameRules/TechTree.cs index c2cfb0c230..135d38dacd 100755 --- a/OpenRa.Game/GameRules/TechTree.cs +++ b/OpenRa.Game/GameRules/TechTree.cs @@ -1,45 +1,53 @@ using System.Collections.Generic; using System.Linq; using IjwFramework.Collections; +using OpenRa.Game.Traits; namespace OpenRa.Game.GameRules { class TechTree { - readonly Cache> producesIndex = new Cache>( x => new List() ); + readonly Cache> producesIndex = new Cache>(x => new List()); public TechTree() { foreach( var b in Rules.Categories[ "Building" ] ) { - var info = (BuildingInfo)Rules.UnitInfo[ b ]; - foreach( var p in info.Produces ) - producesIndex[ p ].Add( info ); + var info = Rules.NewUnitInfo[ b ]; + var pi = info.Traits.GetOrDefault(); + if (pi != null) + foreach( var p in pi.Produces ) + producesIndex[ p ].Add( info ); } } public Cache> GatherBuildings( Player player ) { var ret = new Cache>( x => new List() ); - foreach( var b in Game.world.Actors.Where( x => x.Owner == player && x.Info is BuildingInfo ) ) + foreach( var b in Game.world.Actors.Where( x => x.Owner == player && x.Info != null && x.Info.Traits.Contains() ) ) + { ret[ b.Info.Name ].Add( b ); + var buildable = b.Info.Traits.GetOrDefault(); + if( buildable != null ) + foreach( var alt in buildable.AlternateName ) + ret[ alt ].Add( b ); + } return ret; } - public bool CanBuild( UnitInfo unit, Player player, Cache> playerBuildings ) + public bool CanBuild( NewUnitInfo info, Player player, Cache> playerBuildings ) { - if( unit.TechLevel == -1 ) + var bi = info.Traits.GetOrDefault(); + if( bi == null ) return false; + + if( !bi.Owner.Contains( player.Race ) ) return false; - if( !unit.Owner.Any( x => x == player.Race ) ) - return false; + foreach( var p in bi.Prerequisites ) + if( playerBuildings[ p ].Count == 0 ) + return false; - foreach( var p in unit.Prerequisite ) - if (Rules.UnitInfo[p.ToLowerInvariant()].Owner.Any(x => x == player.Race)) - if( playerBuildings[ p ].Count == 0 ) - return false; - - if( producesIndex[ Rules.UnitCategory[ unit.Name ] ].All( x => playerBuildings[ x.Name ].Count == 0 ) ) + if( producesIndex[ Rules.UnitCategory[ info.Name ] ].All( x => playerBuildings[ x.Name ].Count == 0 ) ) return false; return true; @@ -48,21 +56,21 @@ namespace OpenRa.Game.GameRules public IEnumerable BuildableItems( Player player, params string[] categories ) { var playerBuildings = GatherBuildings( player ); - foreach( var unit in categories.SelectMany( x => Rules.Categories[ x ] ).Select( x => Rules.UnitInfo[ x ] ) ) + foreach( var unit in categories.SelectMany( x => Rules.Categories[ x ] ).Select( x => Rules.NewUnitInfo[ x ] ) ) if( CanBuild( unit, player, playerBuildings ) ) yield return unit.Name; } public IEnumerable AllItems(Player player, params string[] categories) { - return categories.SelectMany(x => Rules.Categories[x]).Select(x => Rules.UnitInfo[x].Name) - .Where(x => Rules.UnitInfo[x].Owner.Contains(player.Race)); /* todo: fix for dual-race scenarios (captured buildings) */ + return categories.SelectMany(x => Rules.Categories[x]).Select(x => Rules.NewUnitInfo[x].Name); } - public IEnumerable UnitBuiltAt( UnitInfo info ) + public IEnumerable UnitBuiltAt( NewUnitInfo info ) { - if( info.BuiltAt.Length != 0 ) - return info.BuiltAt.Select( x => Rules.UnitInfo[ x.ToLowerInvariant() ] ); + var builtAt = info.Traits.Get().BuiltAt; + if( builtAt.Length != 0 ) + return builtAt.Select( x => Rules.NewUnitInfo[ x.ToLowerInvariant() ] ); else return producesIndex[ Rules.UnitCategory[ info.Name ] ]; } diff --git a/OpenRa.Game/GameRules/UnitInfo.cs b/OpenRa.Game/GameRules/UnitInfo.cs deleted file mode 100755 index 6054874fe0..0000000000 --- a/OpenRa.Game/GameRules/UnitInfo.cs +++ /dev/null @@ -1,117 +0,0 @@ - -using System; -namespace OpenRa.Game.GameRules -{ - public enum ArmorType - { - none = 0, - wood = 1, - light = 2, - heavy = 3, - concrete = 4, - } - - public class UnitInfo : ActorInfo - { - public readonly string Name; - - public readonly string Description = ""; - public readonly string[] Traits; - - public readonly int Ammo = -1; - public readonly ArmorType Armor = ArmorType.none; - [Obsolete] public readonly bool DoubleOwned = false; - [Obsolete] 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 Race[] Owner = { Race.Allies, Race.Soviet }; - public readonly int Points = 0; - public readonly string[] Prerequisite = { }; - public readonly string Primary = null; - public readonly string Secondary = null; - public readonly int ROT = 255; - public readonly int Reload = 0; - public readonly bool SelfHealing = false; - [Obsolete] 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 readonly bool WaterBound = false; - public readonly string[] BuiltAt = { }; - public readonly int[] PrimaryOffset = { 0, 0 }; - public readonly int[] SecondaryOffset = null; - public readonly int[] RotorOffset = { 0, 0 }; - public readonly int[] RotorOffset2 = null; - public readonly int Recoil = 0; - public readonly bool MuzzleFlash = false; - public readonly int SelectionPriority = 10; - public readonly int InitialFacing = 128; - public readonly bool Selectable = true; - public readonly int FireDelay = 0; - public readonly string LongDesc = null; - public readonly int OrePips = 0; - public readonly string Icon = null; - public readonly int[] SelectionSize = null; - public readonly int Passengers = 0; - public readonly int UnloadFacing = 0; - public readonly UnitMovementType[] PassengerTypes = null; - - // weapon origins and firing angles within the turrets. 3 values per position. - public readonly int[] PrimaryLocalOffset = { }; - public readonly int[] SecondaryLocalOffset = { }; - - public UnitInfo(string name) { Name = name; } - } - - public class MobileInfo : UnitInfo - { - public readonly int Speed = 0; - public readonly bool NoMovingFire = false; - public readonly string Voice = "GenericVoice"; - - public MobileInfo(string name) : base(name) { } - } - - 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 readonly int SquadSize = 1; - - public InfantryInfo(string name) : base(name) { } - } - - public class VehicleInfo : MobileInfo - { - public readonly bool Tracked = false; - - public VehicleInfo(string name) : base(name) { } - } - - public class BuildingInfo : UnitInfo - { - public readonly int2 Dimensions = new int2(1, 1); - public readonly string Footprint = "x"; - public readonly string[] Produces = { }; - - 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 int[] RallyPoint = { 1, 3 }; - public readonly float[] SpawnOffset = null; - - public BuildingInfo(string name) : base(name) { } - } -} diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index 1060f5467a..a3c82c409c 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -169,7 +169,7 @@ namespace OpenRa.Game.Graphics lineRenderer.DrawLine(xy + new float2(0, -2), xy + new float2(0, -4), c, c); lineRenderer.DrawLine(Xy + new float2(0, -2), Xy + new float2(0, -4), c, c); - var healthAmount = (float)selectedUnit.Health / selectedUnit.Info.Strength; + var healthAmount = (float)selectedUnit.Health / selectedUnit.Info.Traits.Get().HP; var healthColor = (healthAmount < Rules.General.ConditionRed) ? Color.Red : (healthAmount < Rules.General.ConditionYellow) ? Color.Yellow : Color.LimeGreen; @@ -220,7 +220,7 @@ namespace OpenRa.Game.Graphics spriteRenderer.DrawSprite(pipImages.Image, pipxyBase + pipxyOffset, PaletteType.Chrome); pipxyOffset += new float2(4, 0); - if (pipxyOffset.X+5 > selectedUnit.SelectedSize.X) + if (pipxyOffset.X+5 > selectedUnit.GetBounds(false).Width) { pipxyOffset.X = 0; pipxyOffset.Y -= 4; diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index d3d3fc46b2..8cb9f315dc 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -94,7 +94,9 @@ + + @@ -156,7 +158,6 @@ - @@ -216,6 +217,7 @@ + @@ -243,6 +245,7 @@ + @@ -271,7 +274,6 @@ - diff --git a/OpenRa.Game/Orders/ChronoshiftDestinationOrderGenerator.cs b/OpenRa.Game/Orders/ChronoshiftDestinationOrderGenerator.cs index a32d0ca117..2babfc2232 100644 --- a/OpenRa.Game/Orders/ChronoshiftDestinationOrderGenerator.cs +++ b/OpenRa.Game/Orders/ChronoshiftDestinationOrderGenerator.cs @@ -40,7 +40,7 @@ namespace OpenRa.Game.Orders if (!Game.LocalPlayer.Shroud.IsExplored(xy)) return Cursor.MoveBlocked; - var movement = self.traits.WithInterface().FirstOrDefault(); + var movement = self.traits.GetOrDefault(); return (movement.CanEnterCell(xy)) ? Cursor.Chronoshift : Cursor.MoveBlocked; } } diff --git a/OpenRa.Game/Orders/ChronoshiftSelfDestinationOrderGenerator.cs b/OpenRa.Game/Orders/ChronoshiftSelfDestinationOrderGenerator.cs index 5c949c1c51..d44ccbd88a 100644 --- a/OpenRa.Game/Orders/ChronoshiftSelfDestinationOrderGenerator.cs +++ b/OpenRa.Game/Orders/ChronoshiftSelfDestinationOrderGenerator.cs @@ -38,7 +38,7 @@ namespace OpenRa.Game.Orders if (!Game.LocalPlayer.Shroud.IsExplored(xy)) return Cursor.MoveBlocked; - var movement = self.traits.WithInterface().FirstOrDefault(); + var movement = self.traits.GetOrDefault(); return (movement.CanEnterCell(xy)) ? Cursor.Chronoshift : Cursor.MoveBlocked; } } diff --git a/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs index ec0c0f4edf..bc59e480c5 100644 --- a/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs +++ b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs @@ -31,11 +31,9 @@ namespace OpenRa.Game.Orders var underCursor = Game.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.WithInterface().Any() - && a.Info.Selectable).FirstOrDefault(); + && a.traits.Contains()).FirstOrDefault(); - var unit = underCursor != null ? underCursor.Info as UnitInfo : null; - - if (unit != null) + if (underCursor != null) yield return new Order("ChronosphereSelect", underCursor, null, int2.Zero, power.Name); } } diff --git a/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs b/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs index 0a75ca1dd6..2d56000335 100644 --- a/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs +++ b/OpenRa.Game/Orders/IronCurtainOrderGenerator.cs @@ -31,11 +31,9 @@ namespace OpenRa.Game.Orders var underCursor = Game.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() - && a.Info.Selectable).FirstOrDefault(); + && a.traits.Contains()).FirstOrDefault(); - var unit = underCursor != null ? underCursor.Info as UnitInfo : null; - - if (unit != null) + if (underCursor != null) yield return new Order("IronCurtain", underCursor, null, int2.Zero, power.Name); } } diff --git a/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs b/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs index 5c9d2b25fc..1377bbc5ec 100644 --- a/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs +++ b/OpenRa.Game/Orders/PlaceBuildingOrderGenerator.cs @@ -1,17 +1,19 @@ using System.Collections.Generic; using OpenRa.Game.GameRules; +using OpenRa.Game.Traits; namespace OpenRa.Game.Orders { class PlaceBuildingOrderGenerator : IOrderGenerator { readonly Actor Producer; - readonly BuildingInfo Building; + readonly string Building; + BuildingInfo BuildingInfo { get { return Rules.NewUnitInfo[ Building ].Traits.Get(); } } public PlaceBuildingOrderGenerator(Actor producer, string name) { Producer = producer; - Building = (BuildingInfo)Rules.UnitInfo[ name ]; + Building = name; } public IEnumerable Order(int2 xy, MouseInput mi) @@ -26,27 +28,27 @@ namespace OpenRa.Game.Orders { if (mi.Button == MouseButton.Left) { - if (!Game.CanPlaceBuilding(Building, xy, null, true) - || !Game.IsCloseEnoughToBase(Producer.Owner, Building, xy)) + if (!Game.CanPlaceBuilding( Building, BuildingInfo, xy, null, true) + || !Game.IsCloseEnoughToBase(Producer.Owner, Building, BuildingInfo, xy)) { Sound.Play("nodeply1.aud"); yield break; } - yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, null, xy, Building.Name); + yield return new Order("PlaceBuilding", Producer.Owner.PlayerActor, null, xy, Building); } } public void Tick() { - var producing = Producer.traits.Get().CurrentItem( Rules.UnitCategory[ Building.Name ] ); - if (producing == null || producing.Item != Building.Name || producing.RemainingTime != 0) + var producing = Producer.traits.Get().CurrentItem( Rules.UnitCategory[ Building ] ); + if (producing == null || producing.Item != Building || producing.RemainingTime != 0) Game.controller.CancelInputMode(); } public void Render() { - Game.worldRenderer.uiOverlay.DrawBuildingGrid( Building ); + Game.worldRenderer.uiOverlay.DrawBuildingGrid( Building, BuildingInfo ); } public Cursor GetCursor(int2 xy, MouseInput mi) diff --git a/OpenRa.Game/Orders/PowerDownOrderGenerator.cs b/OpenRa.Game/Orders/PowerDownOrderGenerator.cs index 5779e81a20..80ecba3ad1 100644 --- a/OpenRa.Game/Orders/PowerDownOrderGenerator.cs +++ b/OpenRa.Game/Orders/PowerDownOrderGenerator.cs @@ -25,11 +25,9 @@ namespace OpenRa.Game.Orders var underCursor = Game.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() - && a.Info.Selectable).FirstOrDefault(); + && a.traits.Contains()).FirstOrDefault(); - var building = underCursor != null ? underCursor.Info as BuildingInfo : null; - - if (building != null) + if (underCursor != null) yield return new Order("PowerDown", underCursor, null, int2.Zero, null); } } diff --git a/OpenRa.Game/Orders/RepairOrderGenerator.cs b/OpenRa.Game/Orders/RepairOrderGenerator.cs index bc79d65ed4..60d36c79ef 100644 --- a/OpenRa.Game/Orders/RepairOrderGenerator.cs +++ b/OpenRa.Game/Orders/RepairOrderGenerator.cs @@ -25,11 +25,11 @@ namespace OpenRa.Game.Orders var underCursor = Game.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() - && a.Info.Selectable).FirstOrDefault(); + && a.traits.Contains()).FirstOrDefault(); - var building = underCursor != null ? underCursor.Info as BuildingInfo : null; + var building = underCursor != null ? underCursor.Info.Traits.Get() : null; - if (building != null && building.Repairable && underCursor.Health < building.Strength) + if (building != null && building.Repairable && underCursor.Health < building.HP) yield return new Order("Repair", underCursor, null, int2.Zero, null); } } diff --git a/OpenRa.Game/Orders/SellOrderGenerator.cs b/OpenRa.Game/Orders/SellOrderGenerator.cs index 3576c59d1e..5c6f240f5b 100644 --- a/OpenRa.Game/Orders/SellOrderGenerator.cs +++ b/OpenRa.Game/Orders/SellOrderGenerator.cs @@ -25,9 +25,9 @@ namespace OpenRa.Game.Orders var underCursor = Game.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer && a.traits.Contains() - && a.Info.Selectable).FirstOrDefault(); + && a.traits.Contains()).FirstOrDefault(); - var building = underCursor != null ? underCursor.Info as BuildingInfo : null; + var building = underCursor != null ? underCursor.Info.Traits.Get() : null; if (building != null && !building.Unsellable) yield return new Order("Sell", underCursor, null, int2.Zero, null); diff --git a/OpenRa.Game/Orders/UnitOrderGenerator.cs b/OpenRa.Game/Orders/UnitOrderGenerator.cs index 95ad375bbb..a7800482f7 100644 --- a/OpenRa.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRa.Game/Orders/UnitOrderGenerator.cs @@ -57,7 +57,7 @@ namespace OpenRa.Game.Orders Cursor CursorForOrderString(string s, Actor a, int2 location) { - var movement = a.traits.WithInterface().FirstOrDefault(); + var movement = a.traits.GetOrDefault(); switch (s) { case "Attack": return Cursor.Attack; @@ -69,8 +69,8 @@ namespace OpenRa.Game.Orders else return Cursor.MoveBlocked; case "DeployMcv": - var factBuildingInfo = (BuildingInfo)Rules.UnitInfo["fact"]; - if (Game.CanPlaceBuilding(factBuildingInfo, a.Location - new int2(1, 1), a, false)) + var factBuildingInfo = Rules.NewUnitInfo["fact"].Traits.Get(); + if (Game.CanPlaceBuilding("fact", factBuildingInfo, a.Location - new int2(1, 1), a, false)) return Cursor.Deploy; else return Cursor.DeployBlocked; diff --git a/OpenRa.Game/Orders/UnitOrders.cs b/OpenRa.Game/Orders/UnitOrders.cs index 6e11cfad3a..177a48386b 100644 --- a/OpenRa.Game/Orders/UnitOrders.cs +++ b/OpenRa.Game/Orders/UnitOrders.cs @@ -15,22 +15,19 @@ namespace OpenRa.Game.Orders { Game.world.AddFrameEndTask( _ => { - var queue = order.Player.PlayerActor.traits.Get(); - var building = (BuildingInfo)Rules.UnitInfo[ order.TargetString ]; + var queue = order.Player.PlayerActor.traits.Get(); var producing = queue.CurrentItem(Rules.UnitCategory[order.TargetString]); if( producing == null || producing.Item != order.TargetString || producing.RemainingTime != 0 ) return; - Log.Write( "Player \"{0}\" builds {1}", order.Player.PlayerName, building.Name ); - - Game.world.Add( new Actor( building, order.TargetLocation - GameRules.Footprint.AdjustForBuildingSize( building ), order.Player ) ); + Game.world.Add( new Actor( order.TargetString, order.TargetLocation - Footprint.AdjustForBuildingSize( Rules.NewUnitInfo[ order.TargetString ].Traits.Get() ), order.Player ) ); if (order.Player == Game.LocalPlayer) { Sound.Play("placbldg.aud"); Sound.Play("build5.aud"); } - queue.FinishProduction(Rules.UnitCategory[building.Name]); + queue.FinishProduction(Rules.UnitCategory[order.TargetString]); } ); break; } diff --git a/OpenRa.Game/Player.cs b/OpenRa.Game/Player.cs index 79006dbff5..0385e226f2 100644 --- a/OpenRa.Game/Player.cs +++ b/OpenRa.Game/Player.cs @@ -84,9 +84,8 @@ namespace OpenRa.Game { OreCapacity = Game.world.Actors .Where(a => a.Owner == this && a.traits.Contains()) - .Select(a => a.Info as BuildingInfo) - .Where(b => b != null) - .Sum(b => b.Storage); + .Select(a => a.Info.Traits.Get()) + .Sum(b => b.Capacity); } void GiveAdvice(string advice) diff --git a/OpenRa.Game/Shroud.cs b/OpenRa.Game/Shroud.cs index eb7dc5c196..589a4ef49c 100644 --- a/OpenRa.Game/Shroud.cs +++ b/OpenRa.Game/Shroud.cs @@ -78,8 +78,10 @@ namespace OpenRa.Game public void Explore(Actor a) { - foreach (var t in Game.FindTilesInCircle((1f / Game.CellSize * a.CenterLocation).ToInt2(), a.Info.Sight)) - { + foreach (var t in Game.FindTilesInCircle( + (1f / Game.CellSize * a.CenterLocation).ToInt2(), + a.Info.Traits.Get().Sight)) + { explored[t.X, t.Y] = true; gapField[t.X, t.Y] = 0; } diff --git a/OpenRa.Game/Sound.cs b/OpenRa.Game/Sound.cs index 537d4b59f6..6c773d0ae0 100644 --- a/OpenRa.Game/Sound.cs +++ b/OpenRa.Game/Sound.cs @@ -2,6 +2,7 @@ using IrrKlang; using OpenRa.FileFormats; using OpenRa.Game.GameRules; +using OpenRa.Game.Traits; namespace OpenRa.Game { @@ -92,7 +93,7 @@ namespace OpenRa.Game { if (voicedUnit == null) return; - var mi = voicedUnit.Info as MobileInfo; + var mi = voicedUnit.Info.Traits.GetOrDefault(); if (mi == null) return; var vi = Rules.VoiceInfo[mi.Voice]; diff --git a/OpenRa.Game/Support/PerfHistory.cs b/OpenRa.Game/Support/PerfHistory.cs index c9aaecdf5a..2fe624e33d 100644 --- a/OpenRa.Game/Support/PerfHistory.cs +++ b/OpenRa.Game/Support/PerfHistory.cs @@ -9,7 +9,7 @@ namespace OpenRa.Game.Support { static class PerfHistory { - static readonly Color[] colors = { Color.Red, Color.Green, Color.Blue, Color.Yellow, Color.Orange, Color.Fuchsia, Color.Lime, Color.LightBlue }; + static readonly Color[] colors = { Color.Red, Color.Green, Color.Blue, Color.Yellow, Color.Orange, Color.Fuchsia, Color.Lime, Color.LightBlue, Color.White, Color.Black }; static int nextColor; public static Cache items = new Cache( diff --git a/OpenRa.Game/SupportPower.cs b/OpenRa.Game/SupportPower.cs index 0c54dd6718..75471de595 100644 --- a/OpenRa.Game/SupportPower.cs +++ b/OpenRa.Game/SupportPower.cs @@ -2,6 +2,7 @@ using System.Linq; using OpenRa.Game.GameRules; using OpenRa.Game.SupportPowers; +using OpenRa.Game.Traits; namespace OpenRa.Game { @@ -49,8 +50,7 @@ namespace OpenRa.Game var buildings = Rules.TechTree.GatherBuildings(Owner); var effectivePrereq = Info.Prerequisite .Select( a => a.ToLowerInvariant() ) - .Where( a => Rules.UnitInfo[a].Owner - .Any( r => r == Owner.Race )); + .Where( a => Rules.NewUnitInfo[a].Traits.Get().Owner.Contains( Owner.Race )); IsAvailable = Info.TechLevel > -1 && effectivePrereq.Any() diff --git a/OpenRa.Game/Traits/APMine.cs b/OpenRa.Game/Traits/APMine.cs index 41a6b3db9c..4d443321ed 100644 --- a/OpenRa.Game/Traits/APMine.cs +++ b/OpenRa.Game/Traits/APMine.cs @@ -1,10 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRa.Game.GameRules; +using System.Collections.Generic; using OpenRa.Game.Effects; + namespace OpenRa.Game.Traits { + class APMineInfo : ITraitInfo + { + public object Create(Actor self) { return new APMine(self); } + } + class APMine : ICrushable, IOccupySpace { readonly Actor self; diff --git a/OpenRa.Game/Traits/ATMine.cs b/OpenRa.Game/Traits/ATMine.cs index 9ee444195c..0a0bcda360 100644 --- a/OpenRa.Game/Traits/ATMine.cs +++ b/OpenRa.Game/Traits/ATMine.cs @@ -1,11 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using OpenRa.Game.GameRules; +using System.Collections.Generic; using OpenRa.Game.Effects; namespace OpenRa.Game.Traits { + class ATMineInfo : ITraitInfo + { + public object Create(Actor self) { return new ATMine(self); } + } + class ATMine : ICrushable, IOccupySpace { readonly Actor self; diff --git a/OpenRa.Game/Traits/AcceptsOre.cs b/OpenRa.Game/Traits/AcceptsOre.cs index 49d6bc129a..6029420859 100644 --- a/OpenRa.Game/Traits/AcceptsOre.cs +++ b/OpenRa.Game/Traits/AcceptsOre.cs @@ -2,6 +2,11 @@ namespace OpenRa.Game.Traits { + class AcceptsOreInfo : ITraitInfo + { + public object Create(Actor self) { return new AcceptsOre(self); } + } + class AcceptsOre { public AcceptsOre(Actor self) @@ -9,7 +14,7 @@ namespace OpenRa.Game.Traits Game.world.AddFrameEndTask( w => { /* create the free harvester! */ - var harvester = new Actor(Rules.UnitInfo["harv"], self.Location + new int2(1, 2), self.Owner); + var harvester = new Actor("harv", self.Location + new int2(1, 2), self.Owner); var unit = harvester.traits.Get(); var mobile = harvester.traits.Get(); unit.Facing = 64; diff --git a/OpenRa.Game/Traits/Activities/Attack.cs b/OpenRa.Game/Traits/Activities/Attack.cs index edb64ea905..3a13213597 100644 --- a/OpenRa.Game/Traits/Activities/Attack.cs +++ b/OpenRa.Game/Traits/Activities/Attack.cs @@ -27,7 +27,7 @@ namespace OpenRa.Game.Traits.Activities return new Move( Target, Range ) { NextActivity = this }; var desiredFacing = Util.GetFacing((Target.Location - self.Location).ToFloat2(), 0); - var renderUnit = self.traits.WithInterface().FirstOrDefault(); + var renderUnit = self.traits.GetOrDefault(); var numDirs = (renderUnit != null) ? renderUnit.anim.CurrentSequence.Length : 8; @@ -37,7 +37,7 @@ namespace OpenRa.Game.Traits.Activities return new Turn( desiredFacing ) { NextActivity = this }; } - var attack = self.traits.WithInterface().First(); + var attack = self.traits.Get(); attack.target = Target; attack.DoAttack(self); return this; diff --git a/OpenRa.Game/Traits/Activities/CaptureBuilding.cs b/OpenRa.Game/Traits/Activities/CaptureBuilding.cs index 6cb033960c..ca304c8505 100644 --- a/OpenRa.Game/Traits/Activities/CaptureBuilding.cs +++ b/OpenRa.Game/Traits/Activities/CaptureBuilding.cs @@ -19,7 +19,7 @@ namespace OpenRa.Game.Traits.Activities if (target.Owner == self.Owner) { - if (target.Health == target.Info.Strength) + if (target.Health == target.Info.Traits.Get().HP) return NextActivity; target.InflictDamage(self, -EngineerCapture.EngineerDamage, Rules.WarheadInfo["Super"]); } diff --git a/OpenRa.Game/Traits/Activities/DeliverOre.cs b/OpenRa.Game/Traits/Activities/DeliverOre.cs index c41c69c6c5..edc5b25f3d 100644 --- a/OpenRa.Game/Traits/Activities/DeliverOre.cs +++ b/OpenRa.Game/Traits/Activities/DeliverOre.cs @@ -64,7 +64,7 @@ namespace OpenRa.Game.Traits.Activities else if( unit.Facing != 64 ) return new Turn( 64 ) { NextActivity = this }; - var renderUnit = self.traits.WithInterface().First(); + var renderUnit = self.traits.Get(); if( renderUnit.anim.CurrentSequence.Name != "empty" ) renderUnit.PlayCustomAnimation( self, "empty", () => isDone = true ); diff --git a/OpenRa.Game/Traits/Activities/DeployMcv.cs b/OpenRa.Game/Traits/Activities/DeployMcv.cs index 49b8488abf..a738664e8a 100755 --- a/OpenRa.Game/Traits/Activities/DeployMcv.cs +++ b/OpenRa.Game/Traits/Activities/DeployMcv.cs @@ -17,7 +17,7 @@ namespace OpenRa.Game.Traits.Activities Sound.Play("placbldg.aud"); Sound.Play("build5.aud"); } - Game.world.Add( new Actor( Rules.UnitInfo["fact"], self.Location - new int2( 1, 1 ), self.Owner ) ); + Game.world.Add( new Actor( "fact", self.Location - new int2( 1, 1 ), self.Owner ) ); } ); return this; } diff --git a/OpenRa.Game/Traits/Activities/Fly.cs b/OpenRa.Game/Traits/Activities/Fly.cs index 4f7a4241f7..7c6a497a17 100644 --- a/OpenRa.Game/Traits/Activities/Fly.cs +++ b/OpenRa.Game/Traits/Activities/Fly.cs @@ -31,7 +31,7 @@ namespace OpenRa.Game.Traits.Activities var desiredFacing = Util.GetFacing(d, unit.Facing); if (unit.Altitude == CruiseAltitude) - Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.ROT); + Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.Traits.Get().ROT); var speed = .2f * Util.GetEffectiveSpeed(self); var angle = unit.Facing / 128f * Math.PI; diff --git a/OpenRa.Game/Traits/Activities/Harvest.cs b/OpenRa.Game/Traits/Activities/Harvest.cs index 677c34e953..0de6440655 100644 --- a/OpenRa.Game/Traits/Activities/Harvest.cs +++ b/OpenRa.Game/Traits/Activities/Harvest.cs @@ -33,7 +33,7 @@ namespace OpenRa.Game.Traits.Activities { var unit = self.traits.Get(); var harv = self.traits.Get(); - var renderUnit = self.traits.WithInterface().First(); /* better have one of these! */ + var renderUnit = self.traits.Get(); /* better have one of these! */ var isGem = false; if (!Rules.Map.ContainsResource(self.Location) || diff --git a/OpenRa.Game/Traits/Activities/HeliAttack.cs b/OpenRa.Game/Traits/Activities/HeliAttack.cs index 65c6f44ef3..3bfd902388 100644 --- a/OpenRa.Game/Traits/Activities/HeliAttack.cs +++ b/OpenRa.Game/Traits/Activities/HeliAttack.cs @@ -30,11 +30,11 @@ namespace OpenRa.Game.Traits.Activities return this; } - var range = Rules.WeaponInfo[ self.Info.Primary ].Range - 1; + var range = self.GetPrimaryWeapon().Range - 1; var dist = target.CenterLocation - self.CenterLocation; var desiredFacing = Util.GetFacing(dist, unit.Facing); - Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.ROT); + Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.Traits.Get().ROT); if (!float2.WithinEpsilon(float2.Zero, dist, range * Game.CellSize)) { diff --git a/OpenRa.Game/Traits/Activities/HeliFly.cs b/OpenRa.Game/Traits/Activities/HeliFly.cs index 4f9fb658c6..32ba04e293 100644 --- a/OpenRa.Game/Traits/Activities/HeliFly.cs +++ b/OpenRa.Game/Traits/Activities/HeliFly.cs @@ -39,7 +39,8 @@ namespace OpenRa.Game.Traits.Activities } var desiredFacing = Util.GetFacing(dist, unit.Facing); - Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.ROT); + Util.TickFacing(ref unit.Facing, desiredFacing, + self.Info.Traits.Get().ROT); var rawSpeed = .2f * Util.GetEffectiveSpeed(self); self.CenterLocation += (rawSpeed / dist.Length) * dist; diff --git a/OpenRa.Game/Traits/Activities/HeliReturn.cs b/OpenRa.Game/Traits/Activities/HeliReturn.cs index 913ab24a84..52d4c12f47 100644 --- a/OpenRa.Game/Traits/Activities/HeliReturn.cs +++ b/OpenRa.Game/Traits/Activities/HeliReturn.cs @@ -14,7 +14,7 @@ namespace OpenRa.Game.Traits.Activities static Actor ChooseHelipad(Actor self) { return Game.world.Actors.FirstOrDefault( - a => a.Info == Rules.UnitInfo["HPAD"] && + a => a.Info == Rules.NewUnitInfo["HPAD"] && a.Owner == self.Owner && !Reservable.IsReserved(a)); } @@ -24,9 +24,11 @@ namespace OpenRa.Game.Traits.Activities if (isCanceled) return NextActivity; var dest = ChooseHelipad(self); + var initialFacing = self.Info.Traits.Get().InitialFacing; + if (dest == null) return Util.SequenceActivities( - new Turn(self.Info.InitialFacing), + new Turn(initialFacing), new HeliLand(true), NextActivity); @@ -34,12 +36,13 @@ namespace OpenRa.Game.Traits.Activities if (res != null) self.traits.Get().reservation = res.Reserve(self); - var offset = (dest.Info as BuildingInfo).SpawnOffset; + var pi = dest.Info.Traits.GetOrDefault(); + var offset = pi != null ? pi.SpawnOffset : null; var offsetVec = offset != null ? new float2(offset[0], offset[1]) : float2.Zero; return Util.SequenceActivities( new HeliFly(dest.CenterLocation + offsetVec), - new Turn(self.Info.InitialFacing), + new Turn(initialFacing), new HeliLand(false), new Rearm(), NextActivity); diff --git a/OpenRa.Game/Traits/Activities/Land.cs b/OpenRa.Game/Traits/Activities/Land.cs index 5c4cf06ea5..e6f6145c7e 100644 --- a/OpenRa.Game/Traits/Activities/Land.cs +++ b/OpenRa.Game/Traits/Activities/Land.cs @@ -28,7 +28,7 @@ namespace OpenRa.Game.Traits.Activities --unit.Altitude; var desiredFacing = Util.GetFacing(d, unit.Facing); - Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.ROT); + Util.TickFacing(ref unit.Facing, desiredFacing, self.Info.Traits.Get().ROT); var speed = .2f * Util.GetEffectiveSpeed(self); var angle = unit.Facing / 128f * Math.PI; diff --git a/OpenRa.Game/Traits/Activities/Repair.cs b/OpenRa.Game/Traits/Activities/Repair.cs index 63f6e1fd92..1edf56ae36 100644 --- a/OpenRa.Game/Traits/Activities/Repair.cs +++ b/OpenRa.Game/Traits/Activities/Repair.cs @@ -16,8 +16,11 @@ namespace OpenRa.Game.Traits.Activities if (isCanceled) return NextActivity; if (remainingTicks == 0) { - var costPerHp = (Rules.General.URepairPercent * self.Info.Cost) / self.Info.Strength; - var hpToRepair = Math.Min(Rules.General.URepairStep, self.Info.Strength - self.Health); + var unitCost = self.Info.Traits.Get().Cost; + var hp = self.Info.Traits.Get().HP; + + var costPerHp = (Rules.General.URepairPercent * unitCost) / hp; + var hpToRepair = Math.Min(Rules.General.URepairStep, hp - self.Health); var cost = (int)Math.Ceiling(costPerHp * hpToRepair); if (!self.Owner.TakeCash(cost)) { @@ -26,7 +29,7 @@ namespace OpenRa.Game.Traits.Activities } self.InflictDamage(self, -hpToRepair, Rules.WarheadInfo["Super"]); - if (self.Health == self.Info.Strength) + if (self.Health == hp) return NextActivity; var hostBuilding = Game.FindUnits(self.CenterLocation, self.CenterLocation) diff --git a/OpenRa.Game/Traits/Activities/ReturnToBase.cs b/OpenRa.Game/Traits/Activities/ReturnToBase.cs index 29aad3bc5d..51cac44f92 100644 --- a/OpenRa.Game/Traits/Activities/ReturnToBase.cs +++ b/OpenRa.Game/Traits/Activities/ReturnToBase.cs @@ -19,7 +19,7 @@ namespace OpenRa.Game.Traits.Activities Actor ChooseAirfield(Actor self) { var airfield = Game.world.Actors - .Where(a => a.Info == Rules.UnitInfo["AFLD"] /* todo: generalize this */ + .Where(a => a.Info.Name == "afld" && a.Owner == self.Owner && !Reservable.IsReserved(a)) .FirstOrDefault(); @@ -41,7 +41,7 @@ namespace OpenRa.Game.Traits.Activities var unit = self.traits.Get(); var speed = .2f * Util.GetEffectiveSpeed(self); var approachStart = landPos - new float2(unit.Altitude * speed, 0); - var turnRadius = (128f / self.Info.ROT) * speed / (float)Math.PI; + var turnRadius = (128f / self.Info.Traits.Get().ROT) * speed / (float)Math.PI; /* work out the center points */ var fwd = -float2.FromAngle(unit.Facing / 128f * (float)Math.PI); diff --git a/OpenRa.Game/Traits/Activities/Sell.cs b/OpenRa.Game/Traits/Activities/Sell.cs index bb30986ffd..a185d47a7c 100644 --- a/OpenRa.Game/Traits/Activities/Sell.cs +++ b/OpenRa.Game/Traits/Activities/Sell.cs @@ -13,8 +13,9 @@ namespace OpenRa.Game.Traits.Activities void DoSell(Actor self) { - var refund = Rules.General.RefundPercent - * self.Health * self.Info.Cost / self.Info.Strength; + var cost = self.Info.Traits.Get().Cost; + var hp = self.Info.Traits.Get().HP; + var refund = Rules.General.RefundPercent * self.Health * cost / hp; self.Owner.GiveCash((int)refund); self.Health = 0; @@ -29,7 +30,7 @@ namespace OpenRa.Game.Traits.Activities { if (!started) { - var rb = self.traits.WithInterface().First(); + var rb = self.traits.Get(); //var rb = self.traits.Get(); rb.PlayCustomAnimBackwards(self, "make", () => Game.world.AddFrameEndTask(w => DoSell(self))); diff --git a/OpenRa.Game/Traits/Activities/Turn.cs b/OpenRa.Game/Traits/Activities/Turn.cs index 1b81859e31..a992a2aedd 100755 --- a/OpenRa.Game/Traits/Activities/Turn.cs +++ b/OpenRa.Game/Traits/Activities/Turn.cs @@ -19,7 +19,7 @@ namespace OpenRa.Game.Traits.Activities if( desiredFacing == unit.Facing ) return NextActivity; - Util.TickFacing( ref unit.Facing, desiredFacing, self.Info.ROT ); + Util.TickFacing( ref unit.Facing, desiredFacing, self.Info.Traits.Get().ROT ); return this; } diff --git a/OpenRa.Game/Traits/Activities/UndeployMcv.cs b/OpenRa.Game/Traits/Activities/UndeployMcv.cs index 7e9241157d..912c993616 100644 --- a/OpenRa.Game/Traits/Activities/UndeployMcv.cs +++ b/OpenRa.Game/Traits/Activities/UndeployMcv.cs @@ -14,7 +14,7 @@ namespace OpenRa.Game.Traits.Activities ns.Sold(self); w.Remove(self); - var mcv = new Actor(Rules.UnitInfo["MCV"], self.Location + new int2(1, 1), self.Owner); + var mcv = new Actor("mcv", self.Location + new int2(1, 1), self.Owner); mcv.traits.Get().Facing = 96; w.Add(mcv); } diff --git a/OpenRa.Game/Traits/Activities/UnloadCargo.cs b/OpenRa.Game/Traits/Activities/UnloadCargo.cs index b0af980ab5..3b5a1fe3a7 100644 --- a/OpenRa.Game/Traits/Activities/UnloadCargo.cs +++ b/OpenRa.Game/Traits/Activities/UnloadCargo.cs @@ -33,8 +33,9 @@ namespace OpenRa.Game.Traits.Activities // if we're a thing that can turn, turn to the // right facing for the unload animation var unit = self.traits.GetOrDefault(); - if (unit != null && unit.Facing != self.Info.UnloadFacing) - return new Turn(self.Info.UnloadFacing) { NextActivity = this }; + var unloadFacing = self.Info.Traits.Get().UnloadFacing; + if (unit != null && unit.Facing != unloadFacing) + return new Turn(unloadFacing) { NextActivity = this }; // todo: handle the BS of open/close sequences, which are inconsistent, // for reasons that probably make good sense to the westwood guys. @@ -43,7 +44,7 @@ namespace OpenRa.Game.Traits.Activities if (cargo.IsEmpty(self)) return NextActivity; - var ru = self.traits.WithInterface().FirstOrDefault(); + var ru = self.traits.GetOrDefault(); if (ru != null) ru.PlayCustomAnimation(self, "unload", null); diff --git a/OpenRa.Game/Traits/AttackBase.cs b/OpenRa.Game/Traits/AttackBase.cs index 6b78edfe9c..b5f5bb66dd 100644 --- a/OpenRa.Game/Traits/AttackBase.cs +++ b/OpenRa.Game/Traits/AttackBase.cs @@ -6,6 +6,21 @@ using OpenRa.Game.Effects; namespace OpenRa.Game.Traits { + class AttackBaseInfo : ITraitInfo + { + public readonly string PrimaryWeapon = null; + public readonly string SecondaryWeapon = null; + public readonly int Recoil = 0; + public readonly int[] PrimaryLocalOffset = { }; + public readonly int[] SecondaryLocalOffset = { }; + public readonly int[] PrimaryOffset = { 0, 0 }; + public readonly int[] SecondaryOffset = null; + public readonly bool MuzzleFlash = false; + public readonly int FireDelay = 0; + + public virtual object Create(Actor self) { return new AttackBase(self); } + } + class AttackBase : IIssueOrder, IResolveOrder, ITick { [Sync] public Actor target; @@ -23,8 +38,8 @@ namespace OpenRa.Game.Traits public AttackBase(Actor self) { - var primaryWeapon = self.Info.Primary != null ? Rules.WeaponInfo[self.Info.Primary] : null; - var secondaryWeapon = self.Info.Secondary != null ? Rules.WeaponInfo[self.Info.Secondary] : null; + var primaryWeapon = self.GetPrimaryWeapon(); + var secondaryWeapon = self.GetSecondaryWeapon(); primaryBurst = primaryWeapon != null ? primaryWeapon.Burst : 1; secondaryBurst = secondaryWeapon != null ? secondaryWeapon.Burst : 1; @@ -73,19 +88,20 @@ namespace OpenRa.Game.Traits public void DoAttack(Actor self) { var unit = self.traits.GetOrDefault(); + var info = self.Info.Traits.Get(); - if (self.Info.Primary != null && CheckFire(self, unit, self.Info.Primary, ref primaryFireDelay, - self.Info.PrimaryOffset, ref primaryBurst, self.Info.PrimaryLocalOffset)) + if (info.PrimaryWeapon != null && CheckFire(self, unit, info.PrimaryWeapon, ref primaryFireDelay, + info.PrimaryOffset, ref primaryBurst, info.PrimaryLocalOffset)) { secondaryFireDelay = Math.Max(4, secondaryFireDelay); primaryRecoil = 1; return; } - if (self.Info.Secondary != null && CheckFire(self, unit, self.Info.Secondary, ref secondaryFireDelay, - self.Info.SecondaryOffset ?? self.Info.PrimaryOffset, ref secondaryBurst, self.Info.SecondaryLocalOffset)) + if (info.SecondaryWeapon != null && CheckFire(self, unit, info.SecondaryWeapon, ref secondaryFireDelay, + info.SecondaryOffset ?? info.PrimaryOffset, ref secondaryBurst, info.SecondaryLocalOffset)) { - if (self.Info.SecondaryOffset != null) secondaryRecoil = 1; + if (info.SecondaryOffset != null) secondaryRecoil = 1; else primaryRecoil = 1; return; } @@ -126,8 +142,9 @@ namespace OpenRa.Game.Traits var firePos = self.CenterLocation.ToInt2() + Util.GetTurretPosition(self, unit, fireOffset, 0f).ToInt2(); var thisTarget = target; // closure. var destUnit = thisTarget.traits.GetOrDefault(); + var info = self.Info.Traits.Get(); - ScheduleDelayedAction(self.Info.FireDelay, () => + ScheduleDelayedAction(info.FireDelay, () => { var srcAltitude = unit != null ? unit.Altitude : 0; var destAltitude = destUnit != null ? destUnit.Altitude : 0; @@ -140,11 +157,11 @@ namespace OpenRa.Game.Traits var fireFacing = thisLocalOffset.ElementAtOrDefault(2) + (self.traits.Contains() ? self.traits.Get().turretFacing : unit.Facing); - Game.world.Add(new Missile(weaponName, self.Owner, self, + Game.world.Add(new Missile(weapon, self.Owner, self, firePos, thisTarget, srcAltitude, fireFacing)); } else - Game.world.Add(new Bullet(weaponName, self.Owner, self, + Game.world.Add(new Bullet(weapon, self.Owner, self, firePos, thisTarget.CenterLocation.ToInt2(), srcAltitude, destAltitude)); if (!string.IsNullOrEmpty(weapon.Report)) @@ -161,10 +178,13 @@ namespace OpenRa.Game.Traits { if (mi.Button == MouseButton.Left || underCursor == null) return null; if (self == underCursor) return null; - var isHeal = Rules.WeaponInfo[self.Info.Primary].Damage < 0; + + var isHeal = self.GetPrimaryWeapon().Damage < 0; if (((underCursor.Owner == self.Owner) ^ isHeal) && !mi.Modifiers.HasModifier( Modifiers.Ctrl )) return null; + if (!Combat.HasAnyValidWeapons(self, underCursor)) return null; + return new Order(isHeal ? "Heal" : "Attack", self, underCursor, int2.Zero, null); } @@ -186,10 +206,10 @@ namespace OpenRa.Game.Traits { const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ /* todo: choose the appropriate weapon, when only one works against this target */ - var weapon = order.Subject.Info.Primary ?? order.Subject.Info.Secondary; + var weapon = self.GetPrimaryWeapon() ?? self.GetSecondaryWeapon(); self.QueueActivity(new Activities.Attack(order.TargetActor, - Math.Max(0, (int)Rules.WeaponInfo[weapon].Range - RangeTolerance))); + Math.Max(0, (int)weapon.Range - RangeTolerance))); } } } diff --git a/OpenRa.Game/Traits/AttackHeli.cs b/OpenRa.Game/Traits/AttackHeli.cs index 4749edc089..41d3fc2c51 100644 --- a/OpenRa.Game/Traits/AttackHeli.cs +++ b/OpenRa.Game/Traits/AttackHeli.cs @@ -2,6 +2,11 @@ namespace OpenRa.Game.Traits { + class AttackHeliInfo : AttackBaseInfo + { + public override object Create(Actor self) { return new AttackHeli(self); } + } + class AttackHeli : AttackFrontal { public AttackHeli(Actor self) : base(self, 20) { } diff --git a/OpenRa.Game/Traits/AttackPlane.cs b/OpenRa.Game/Traits/AttackPlane.cs index 05fad7ecb8..b4f4f9e02a 100644 --- a/OpenRa.Game/Traits/AttackPlane.cs +++ b/OpenRa.Game/Traits/AttackPlane.cs @@ -2,6 +2,11 @@ namespace OpenRa.Game.Traits { + class AttackPlaneInfo : AttackBaseInfo + { + public override object Create(Actor self) { return new AttackPlane(self); } + } + class AttackPlane : AttackFrontal { public AttackPlane(Actor self) : base(self, 20) { } diff --git a/OpenRa.Game/Traits/AttackTurreted.cs b/OpenRa.Game/Traits/AttackTurreted.cs index 9c0f513251..33aef0b1ad 100755 --- a/OpenRa.Game/Traits/AttackTurreted.cs +++ b/OpenRa.Game/Traits/AttackTurreted.cs @@ -3,9 +3,14 @@ using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { + class AttackTurretedInfo : AttackBaseInfo + { + public override object Create(Actor self) { return new AttackTurreted( self ); } + } + class AttackTurreted : AttackBase, INotifyBuildComplete { - public AttackTurreted( Actor self ) : base(self) { self.traits.Get(); } + public AttackTurreted(Actor self) : base(self) { } public override void Tick(Actor self) { @@ -31,11 +36,11 @@ namespace OpenRa.Game.Traits const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ /* todo: choose the appropriate weapon, when only one works against this target */ - var weapon = order.Subject.Info.Primary ?? order.Subject.Info.Secondary; + var weapon = order.Subject.GetPrimaryWeapon() ?? order.Subject.GetSecondaryWeapon(); if (self.traits.Contains()) self.QueueActivity( new Traits.Activities.Follow( order.TargetActor, - Math.Max( 0, (int)Rules.WeaponInfo[ weapon ].Range - RangeTolerance ) ) ); + Math.Max( 0, (int)weapon.Range - RangeTolerance ) ) ); target = order.TargetActor; diff --git a/OpenRa.Game/Traits/AutoHeal.cs b/OpenRa.Game/Traits/AutoHeal.cs index 61018ed3cd..c9918aee83 100644 --- a/OpenRa.Game/Traits/AutoHeal.cs +++ b/OpenRa.Game/Traits/AutoHeal.cs @@ -3,13 +3,13 @@ using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class AutoHealInfo : StatelessTraitInfo { } + class AutoHeal : ITick { - public AutoHeal(Actor self) { } - void AttackTarget(Actor self, Actor target) { - var attack = self.traits.WithInterface().First(); + var attack = self.traits.Get(); if (target != null) attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null)); else @@ -17,23 +17,16 @@ namespace OpenRa.Game.Traits self.CancelActivity(); } - float GetMaximumRange(Actor self) - { - return new[] { self.Info.Primary, self.Info.Secondary } - .Where(w => w != null) - .Max(w => Rules.WeaponInfo[w].Range); - } - bool NeedsNewTarget(Actor self) { - var attack = self.traits.WithInterface().First(); - var range = GetMaximumRange(self); + var attack = self.traits.Get(); + var range = Util.GetMaximumRange(self); if (attack.target == null) return true; // he's dead. if ((attack.target.Location - self.Location).LengthSquared > range * range + 2) return true; // wandered off faster than we could follow - if (attack.target.Health == attack.target.Info.Strength) + if (attack.target.Health == attack.target.Info.Traits.Get().HP) return true; // fully healed return false; @@ -41,8 +34,8 @@ namespace OpenRa.Game.Traits public void Tick(Actor self) { - var attack = self.traits.WithInterface().First(); - var range = GetMaximumRange(self); + var attack = self.traits.Get(); + var range = Util.GetMaximumRange(self); if (NeedsNewTarget(self)) AttackTarget(self, ChooseTarget(self, range)); @@ -55,7 +48,7 @@ namespace OpenRa.Game.Traits return inRange .Where(a => a.Owner == self.Owner && a != self) /* todo: one day deal with friendly players */ .Where(a => Combat.HasAnyValidWeapons(self, a)) - .Where(a => a.Health < a.Info.Strength) + .Where(a => a.Health < a.Info.Traits.Get().HP) .OrderBy(a => (a.Location - self.Location).LengthSquared) .FirstOrDefault(); } diff --git a/OpenRa.Game/Traits/AutoTarget.cs b/OpenRa.Game/Traits/AutoTarget.cs index bd7730d57c..a6721b6cfb 100644 --- a/OpenRa.Game/Traits/AutoTarget.cs +++ b/OpenRa.Game/Traits/AutoTarget.cs @@ -2,30 +2,23 @@ namespace OpenRa.Game.Traits { + class AutoTargetInfo : StatelessTraitInfo { } + class AutoTarget : ITick, INotifyDamage { - public AutoTarget(Actor self) {} - void AttackTarget(Actor self, Actor target) { - var attack = self.traits.WithInterface().First(); + var attack = self.traits.Get(); if (target != null) attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null)); } - float GetMaximumRange(Actor self) - { - return new[] { self.Info.Primary, self.Info.Secondary } - .Where(w => w != null) - .Max(w => Rules.WeaponInfo[w].Range); - } - public void Tick(Actor self) { if (!self.IsIdle) return; - var attack = self.traits.WithInterface().First(); - var range = GetMaximumRange(self); + var attack = self.traits.Get(); + var range = Util.GetMaximumRange(self); if (attack.target == null || (attack.target.Location - self.Location).LengthSquared > range * range + 2) @@ -55,7 +48,7 @@ namespace OpenRa.Game.Traits if (e.Damage < 0) return; // don't retaliate against healers - var attack = self.traits.WithInterface().First(); + var attack = self.traits.Get(); if (attack.target != null) return; AttackTarget(self, e.Attacker); diff --git a/OpenRa.Game/Traits/BelowUnits.cs b/OpenRa.Game/Traits/BelowUnits.cs index 7bc4d84681..f5d82d6727 100644 --- a/OpenRa.Game/Traits/BelowUnits.cs +++ b/OpenRa.Game/Traits/BelowUnits.cs @@ -3,10 +3,10 @@ using System.Linq; namespace OpenRa.Game.Traits { + class BelowUnitsInfo : StatelessTraitInfo { } + class BelowUnits : IRenderModifier { - public BelowUnits(Actor self) { } - public IEnumerable ModifyRender(Actor self, IEnumerable r) { return r.Select(a => a.WithZOffset(-1)); diff --git a/OpenRa.Game/Traits/Buildable.cs b/OpenRa.Game/Traits/Buildable.cs new file mode 100755 index 0000000000..8a15e43b8e --- /dev/null +++ b/OpenRa.Game/Traits/Buildable.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class BuildableInfo : StatelessTraitInfo + { + public readonly int TechLevel = -1; + public readonly string Tab = null; + public readonly string[] Prerequisites = { }; + public readonly string[] BuiltAt = { }; + public readonly Race[] Owner = { }; + public readonly int Cost = 0; + public readonly string Description = ""; + public readonly string LongDesc = ""; + public readonly string Icon = null; + public readonly string[] AlternateName = { }; + } + + class Buildable { } +} diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs index 1fa3538314..f5920cfae7 100644 --- a/OpenRa.Game/Traits/Building.cs +++ b/OpenRa.Game/Traits/Building.cs @@ -9,35 +9,63 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class OwnedActorInfo + { + public readonly int HP = 0; + public readonly ArmorType Armor = ArmorType.none; + public readonly bool Crewed = false; // replace with trait? + public readonly int Sight = 0; + public readonly bool WaterBound = false; + } + + class BuildingInfo : OwnedActorInfo, ITraitInfo + { + public readonly int Power = 0; + public readonly bool RequiresPower = false; + public readonly bool BaseNormal = true; + public readonly int Adjacent = 1; + public readonly bool Bib = false; + public readonly bool Capturable = false; + public readonly bool Repairable = true; + public readonly string Footprint = "x"; + public readonly string[] Produces = { }; // does this go somewhere else? + public readonly int2 Dimensions = new int2(1, 1); + public readonly bool Unsellable = false; + + public object Create(Actor self) { return new Building(self); } + } + class Building : INotifyDamage, IResolveOrder, ITick { readonly Actor self; - public readonly BuildingInfo unitInfo; + public readonly BuildingInfo Info; [Sync] bool isRepairing = false; [Sync] bool manuallyDisabled = false; public bool ManuallyDisabled { get { return manuallyDisabled; } } - public bool Disabled { get { return (manuallyDisabled || (unitInfo.Powered && self.Owner.GetPowerState() != PowerState.Normal)); } } + public bool Disabled { get { return (manuallyDisabled || (Info.RequiresPower && self.Owner.GetPowerState() != PowerState.Normal)); } } bool wasDisabled = false; public Building(Actor self) { this.self = self; - unitInfo = (BuildingInfo)self.Info; + Info = self.Info.Traits.Get(); self.CenterLocation = Game.CellSize - * ((float2)self.Location + .5f * (float2)unitInfo.Dimensions); + * ((float2)self.Location + .5f * (float2)Info.Dimensions); } public int GetPowerUsage() { if (manuallyDisabled) return 0; - - if (unitInfo.Power > 0) /* todo: is this how real-ra scales it? */ - return (self.Health * unitInfo.Power) / unitInfo.Strength; + + var maxHP = self.Info.Traits.Get().HP; + + if (Info.Power > 0) + return (self.Health * Info.Power) / maxHP; else - return unitInfo.Power; + return Info.Power; } public void Damaged(Actor self, AttackInfo e) @@ -79,8 +107,9 @@ namespace OpenRa.Game.Traits if (remainingTicks == 0) { - var costPerHp = (Rules.General.URepairPercent * self.Info.Cost) / self.Info.Strength; - var hpToRepair = Math.Min(Rules.General.URepairStep, self.Info.Strength - self.Health); + var maxHP = self.Info.Traits.Get().HP; + var costPerHp = (Rules.General.URepairPercent * self.Info.Traits.Get().Cost) / maxHP; + var hpToRepair = Math.Min(Rules.General.URepairStep, maxHP - self.Health); var cost = (int)Math.Ceiling(costPerHp * hpToRepair); if (!self.Owner.TakeCash(cost)) { @@ -90,7 +119,7 @@ namespace OpenRa.Game.Traits Game.world.AddFrameEndTask(w => w.Add(new RepairIndicator(self))); self.InflictDamage(self, -hpToRepair, Rules.WarheadInfo["Super"]); - if (self.Health == self.Info.Strength) + if (self.Health == maxHP) { isRepairing = false; return; diff --git a/OpenRa.Game/Traits/C4Demolition.cs b/OpenRa.Game/Traits/C4Demolition.cs index e6b75178b2..68ae518333 100644 --- a/OpenRa.Game/Traits/C4Demolition.cs +++ b/OpenRa.Game/Traits/C4Demolition.cs @@ -2,10 +2,10 @@ namespace OpenRa.Game.Traits { + class C4DemolitionInfo : StatelessTraitInfo { } + class C4Demolition : IIssueOrder, IResolveOrder { - public C4Demolition(Actor self) { } - public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { if (mi.Button != MouseButton.Right) return null; diff --git a/OpenRa.Game/Traits/Cargo.cs b/OpenRa.Game/Traits/Cargo.cs index 088cde0640..c9b99b79a7 100644 --- a/OpenRa.Game/Traits/Cargo.cs +++ b/OpenRa.Game/Traits/Cargo.cs @@ -7,6 +7,15 @@ using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class CargoInfo : ITraitInfo + { + public readonly int Passengers = 0; + public readonly UnitMovementType[] PassengerTypes = { }; + public readonly int UnloadFacing = 0; + + public object Create(Actor self) { return new Cargo(self); } + } + class Cargo : IPips, IIssueOrder, IResolveOrder { List cargo = new List(); @@ -39,7 +48,7 @@ namespace OpenRa.Game.Traits public bool IsFull(Actor self) { - return cargo.Count == self.Info.Passengers; + return cargo.Count == self.Info.Traits.Get().Passengers; } public bool IsEmpty(Actor self) @@ -56,7 +65,8 @@ namespace OpenRa.Game.Traits public IEnumerable GetPips( Actor self ) { - for (var i = 0; i < self.Info.Passengers; i++) + var numPips = self.Info.Traits.Get().Passengers; + for (var i = 0; i < numPips; i++) if (i >= cargo.Count) yield return PipType.Transparent; else diff --git a/OpenRa.Game/Traits/ChronoshiftDeploy.cs b/OpenRa.Game/Traits/ChronoshiftDeploy.cs index 2cc8a2a9a4..5b814d1038 100644 --- a/OpenRa.Game/Traits/ChronoshiftDeploy.cs +++ b/OpenRa.Game/Traits/ChronoshiftDeploy.cs @@ -4,6 +4,11 @@ using OpenRa.Game.Orders; namespace OpenRa.Game.Traits { + class ChronoshiftDeployInfo : ITraitInfo + { + public object Create(Actor self) { return new ChronoshiftDeploy(self); } + } + class ChronoshiftDeploy : IIssueOrder, IResolveOrder, ISpeedModifier, ITick, IPips { // Recharge logic @@ -35,7 +40,7 @@ namespace OpenRa.Game.Traits return; } - var movement = self.traits.WithInterface().FirstOrDefault(); + var movement = self.traits.GetOrDefault(); if (order.OrderString == "ChronoshiftSelf" && movement.CanEnterCell(order.TargetLocation)) { // Cannot chronoshift into unexplored location diff --git a/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs index 36a4f0e40c..dc2ef912e2 100644 --- a/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs +++ b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs @@ -3,6 +3,9 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + // this is NOT bound through rules (it belongs on the world actor!) + // so no *Info required + class ChronoshiftPaletteEffect : IPaletteModifier, ITick { const int chronoEffectLength = 20; diff --git a/OpenRa.Game/Traits/Chronoshiftable.cs b/OpenRa.Game/Traits/Chronoshiftable.cs index 2df077e0bb..067c43716e 100644 --- a/OpenRa.Game/Traits/Chronoshiftable.cs +++ b/OpenRa.Game/Traits/Chronoshiftable.cs @@ -5,6 +5,11 @@ using System.Linq; namespace OpenRa.Game.Traits { + class ChronoshiftableInfo : ITraitInfo + { + public object Create(Actor self) { return new Chronoshiftable(self); } + } + class Chronoshiftable : IResolveOrder, ISpeedModifier, ITick { // Return-to-sender logic @@ -40,7 +45,7 @@ namespace OpenRa.Game.Traits Game.controller.orderGenerator = new ChronoshiftDestinationOrderGenerator(self, power); } - var movement = self.traits.WithInterface().FirstOrDefault(); + var movement = self.traits.GetOrDefault(); if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation)) { // Cannot chronoshift into unexplored location diff --git a/OpenRa.Game/Traits/Chronosphere.cs b/OpenRa.Game/Traits/Chronosphere.cs index 771cc8f4b4..2dcbef7490 100644 --- a/OpenRa.Game/Traits/Chronosphere.cs +++ b/OpenRa.Game/Traits/Chronosphere.cs @@ -5,10 +5,10 @@ using System.Text; namespace OpenRa.Game.Traits { + class ChronosphereInfo : StatelessTraitInfo { } + class Chronosphere : IResolveOrder { - public Chronosphere(Actor self) { } - public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "PlayAnimation") diff --git a/OpenRa.Game/Traits/Cloak.cs b/OpenRa.Game/Traits/Cloak.cs index 5b225438d6..b782d854e1 100644 --- a/OpenRa.Game/Traits/Cloak.cs +++ b/OpenRa.Game/Traits/Cloak.cs @@ -4,6 +4,11 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class CloakInfo : ITraitInfo + { + public object Create(Actor self) { return new Cloak(self); } + } + class Cloak : IRenderModifier, INotifyAttack, ITick { [Sync] diff --git a/OpenRa.Game/Traits/ConstructionYard.cs b/OpenRa.Game/Traits/ConstructionYard.cs index 0dbcc76277..4d4368b21a 100644 --- a/OpenRa.Game/Traits/ConstructionYard.cs +++ b/OpenRa.Game/Traits/ConstructionYard.cs @@ -3,6 +3,11 @@ using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class ConstructionYardInfo : ITraitInfo + { + public object Create(Actor self) { return new ConstructionYard(self); } + } + class ConstructionYard : IIssueOrder, IResolveOrder, IMovement { readonly Actor self; diff --git a/OpenRa.Game/Traits/DemoTruck.cs b/OpenRa.Game/Traits/DemoTruck.cs index 53a3d86a1e..2816729f98 100644 --- a/OpenRa.Game/Traits/DemoTruck.cs +++ b/OpenRa.Game/Traits/DemoTruck.cs @@ -6,19 +6,19 @@ using OpenRa.Game.Orders; namespace OpenRa.Game.Traits { + class DemoTruckInfo : ITraitInfo + { + public object Create(Actor self) { return new DemoTruck(self); } + } + class DemoTruck : Chronoshiftable, IResolveOrder, INotifyDamage { - readonly Actor self; - public DemoTruck(Actor self) - : base(self) - { - this.self = self; - } + public DemoTruck(Actor self) : base(self) {} public new void ResolveOrder(Actor self, Order order) { // Override chronoshifting action to detonate vehicle - var movement = self.traits.WithInterface().FirstOrDefault(); + var movement = self.traits.GetOrDefault(); var chronosphere = Game.world.Actors.Where(a => a.Owner == order.Subject.Owner && a.traits.Contains()).FirstOrDefault(); if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation)) { @@ -44,7 +44,7 @@ namespace OpenRa.Game.Traits int2 detonateLocation = self.CenterLocation.ToInt2(); Game.world.AddFrameEndTask( - w => w.Add(new Bullet(self.Info.Primary, detonatedBy.Owner, detonatedBy, + w => w.Add( new Bullet( self.Info.Traits.Get().PrimaryWeapon, detonatedBy.Owner, detonatedBy, detonateLocation, detonateLocation, altitude, altitude))); } } diff --git a/OpenRa.Game/Traits/EngineerCapture.cs b/OpenRa.Game/Traits/EngineerCapture.cs index 771e2a015a..efc03dc6cd 100644 --- a/OpenRa.Game/Traits/EngineerCapture.cs +++ b/OpenRa.Game/Traits/EngineerCapture.cs @@ -2,12 +2,12 @@ namespace OpenRa.Game.Traits { + class EngineerCaptureInfo : StatelessTraitInfo { } + class EngineerCapture : IIssueOrder, IResolveOrder { public const int EngineerDamage = 300; // todo: push into rules, as a weapon - public EngineerCapture(Actor self) { } - public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { if (mi.Button != MouseButton.Right) return null; diff --git a/OpenRa.Game/Traits/Explodes.cs b/OpenRa.Game/Traits/Explodes.cs index 08fc4e0db4..2b058de917 100644 --- a/OpenRa.Game/Traits/Explodes.cs +++ b/OpenRa.Game/Traits/Explodes.cs @@ -2,10 +2,10 @@ namespace OpenRa.Game.Traits { + class ExplodesInfo : StatelessTraitInfo { } + class Explodes : INotifyDamage { - public Explodes(Actor self) {} - public void Damaged(Actor self, AttackInfo e) { if (self.IsDead) diff --git a/OpenRa.Game/Traits/Fake.cs b/OpenRa.Game/Traits/Fake.cs index a14a0142ff..9eb9127856 100644 --- a/OpenRa.Game/Traits/Fake.cs +++ b/OpenRa.Game/Traits/Fake.cs @@ -2,13 +2,10 @@ namespace OpenRa.Game.Traits { + class FakeInfo : StatelessTraitInfo { } + class Fake : ITags { - public Fake(Actor self){} - - public IEnumerable GetTags() - { - yield return TagType.Fake; - } + public IEnumerable GetTags() { yield return TagType.Fake; } } } diff --git a/OpenRa.Game/Traits/GpsLaunchSite.cs b/OpenRa.Game/Traits/GpsLaunchSite.cs index 639f5b93a1..ed10b56620 100644 --- a/OpenRa.Game/Traits/GpsLaunchSite.cs +++ b/OpenRa.Game/Traits/GpsLaunchSite.cs @@ -2,5 +2,6 @@ namespace OpenRa.Game.Traits { - class GpsLaunchSite { public GpsLaunchSite(Actor self) { } } + class GpsLaunchSiteInfo : StatelessTraitInfo { } + class GpsLaunchSite { } } diff --git a/OpenRa.Game/Traits/Harvester.cs b/OpenRa.Game/Traits/Harvester.cs index aa374e943c..d9f72f592f 100644 --- a/OpenRa.Game/Traits/Harvester.cs +++ b/OpenRa.Game/Traits/Harvester.cs @@ -3,6 +3,11 @@ using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class HarvesterInfo : ITraitInfo + { + public object Create(Actor self) { return new Harvester(); } + } + class Harvester : IIssueOrder, IResolveOrder, IPips { [Sync] @@ -13,8 +18,6 @@ namespace OpenRa.Game.Traits public bool IsFull { get { return oreCarried + gemsCarried == Rules.General.BailCount; } } public bool IsEmpty { get { return oreCarried == 0 && gemsCarried == 0; } } - public Harvester(Actor self) { } - public void AcceptResource(bool isGem) { if (isGem) gemsCarried++; diff --git a/OpenRa.Game/Traits/Helicopter.cs b/OpenRa.Game/Traits/Helicopter.cs index 27d6143c8b..34731a21c7 100644 --- a/OpenRa.Game/Traits/Helicopter.cs +++ b/OpenRa.Game/Traits/Helicopter.cs @@ -1,19 +1,24 @@ -using OpenRa.Game.Traits.Activities; -using System; +using System; +using System.Linq; using OpenRa.Game.GameRules; +using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class HelicopterInfo : ITraitInfo + { + public object Create(Actor self) { return new Helicopter(self); } + } + class Helicopter : IIssueOrder, IResolveOrder, IMovement { public IDisposable reservation; public Helicopter(Actor self) {} - // todo: push into data! static bool HeliCanEnter(Actor a) { - if (a.Info == Rules.UnitInfo["HPAD"]) return true; - if (a.Info == Rules.UnitInfo["FIX"]) return true; + if (a.Info.Name == "hpad") return true; + if (a.Info.Name == "fix") return true; return false; } @@ -44,7 +49,7 @@ namespace OpenRa.Game.Traits { self.CancelActivity(); self.QueueActivity(new HeliFly(Util.CenterOfCell(order.TargetLocation))); - self.QueueActivity(new Turn(self.Info.InitialFacing)); + self.QueueActivity( new Turn( self.Info.Traits.GetOrDefault().InitialFacing ) ); self.QueueActivity(new HeliLand(true)); } @@ -55,14 +60,15 @@ namespace OpenRa.Game.Traits if (res != null) reservation = res.Reserve(self); - var offset = (order.TargetActor.Info as BuildingInfo).SpawnOffset; + var productionInfo = order.TargetActor.Info.Traits.Get(); + var offset = productionInfo.SpawnOffset; var offsetVec = offset != null ? new float2(offset[0], offset[1]) : float2.Zero; self.CancelActivity(); self.QueueActivity(new HeliFly(order.TargetActor.CenterLocation + offsetVec)); - self.QueueActivity(new Turn(self.Info.InitialFacing)); + self.QueueActivity( new Turn( self.Info.Traits.GetOrDefault().InitialFacing ) ); self.QueueActivity(new HeliLand(false)); - self.QueueActivity(order.TargetActor.Info == Rules.UnitInfo["HPAD"] + self.QueueActivity(order.TargetActor.Info.Name == "hpad" ? (IActivity)new Rearm() : new Repair()); } } diff --git a/OpenRa.Game/Traits/InvisibleToOthers.cs b/OpenRa.Game/Traits/InvisibleToOthers.cs index 46491a6766..dab24dfc59 100644 --- a/OpenRa.Game/Traits/InvisibleToOthers.cs +++ b/OpenRa.Game/Traits/InvisibleToOthers.cs @@ -2,10 +2,10 @@ namespace OpenRa.Game.Traits { + class InvisibleToOthersInfo : StatelessTraitInfo { } + class InvisibleToOthers : IRenderModifier { - public InvisibleToOthers(Actor self) { } - public IEnumerable ModifyRender(Actor self, IEnumerable r) { return Game.LocalPlayer == self.Owner diff --git a/OpenRa.Game/Traits/IronCurtain.cs b/OpenRa.Game/Traits/IronCurtain.cs index 995af17d38..e2bb3b0055 100644 --- a/OpenRa.Game/Traits/IronCurtain.cs +++ b/OpenRa.Game/Traits/IronCurtain.cs @@ -1,14 +1,10 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - + namespace OpenRa.Game.Traits { + class IronCurtainInfo : StatelessTraitInfo { } + class IronCurtain : IResolveOrder { - public IronCurtain(Actor self) {} - public void ResolveOrder(Actor self, Order order) { if (order.OrderString == "PlayAnimation") diff --git a/OpenRa.Game/Traits/IronCurtainable.cs b/OpenRa.Game/Traits/IronCurtainable.cs index 4feda533ad..e00474fdd1 100644 --- a/OpenRa.Game/Traits/IronCurtainable.cs +++ b/OpenRa.Game/Traits/IronCurtainable.cs @@ -3,13 +3,16 @@ using OpenRa.Game.Effects; namespace OpenRa.Game.Traits { + class IronCurtainableInfo : ITraitInfo + { + public object Create(Actor self) { return new IronCurtainable(); } + } + class IronCurtainable : IResolveOrder, IDamageModifier, ITick { [Sync] int RemainingTicks = 0; - public IronCurtainable(Actor self) { } - public void Tick(Actor self) { if (RemainingTicks > 0) diff --git a/OpenRa.Game/Traits/LimitedAmmo.cs b/OpenRa.Game/Traits/LimitedAmmo.cs index b3ffe3535f..5d1a705e6d 100644 --- a/OpenRa.Game/Traits/LimitedAmmo.cs +++ b/OpenRa.Game/Traits/LimitedAmmo.cs @@ -2,6 +2,13 @@ namespace OpenRa.Game.Traits { + class LimitedAmmoInfo : ITraitInfo + { + public readonly int Ammo = 0; + + public object Create(Actor self) { return new LimitedAmmo(self); } + } + class LimitedAmmo : INotifyAttack, IPips { [Sync] @@ -10,14 +17,14 @@ namespace OpenRa.Game.Traits public LimitedAmmo(Actor self) { - ammo = self.Info.Ammo; + ammo = self.Info.Traits.Get().Ammo; this.self = self; } public bool HasAmmo() { return ammo > 0; } public bool GiveAmmo() { - if (ammo >= self.Info.Ammo) return false; + if (ammo >= self.Info.Traits.Get().Ammo) return false; ++ammo; return true; } @@ -26,7 +33,8 @@ namespace OpenRa.Game.Traits public IEnumerable GetPips(Actor self) { - return Graphics.Util.MakeArray(self.Info.Ammo, + var maxAmmo = self.Info.Traits.Get().Ammo; + return Graphics.Util.MakeArray(maxAmmo, i => ammo > i ? PipType.Green : PipType.Transparent); } } diff --git a/OpenRa.Game/Traits/McvDeploy.cs b/OpenRa.Game/Traits/McvDeploy.cs index 4848378acb..ac6c0ce924 100644 --- a/OpenRa.Game/Traits/McvDeploy.cs +++ b/OpenRa.Game/Traits/McvDeploy.cs @@ -3,6 +3,11 @@ using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class McvDeployInfo : ITraitInfo + { + public object Create(Actor self) { return new McvDeploy(self); } + } + class McvDeploy : IIssueOrder, IResolveOrder { public McvDeploy(Actor self) { } @@ -19,8 +24,8 @@ namespace OpenRa.Game.Traits { if( order.OrderString == "DeployMcv" ) { - var factBuildingInfo = (BuildingInfo)Rules.UnitInfo[ "fact" ]; - if( Game.CanPlaceBuilding( factBuildingInfo, self.Location - new int2( 1, 1 ), self, false ) ) + var factBuildingInfo = Rules.NewUnitInfo[ "fact" ].Traits.Get(); + if( Game.CanPlaceBuilding( "fact", factBuildingInfo, self.Location - new int2( 1, 1 ), self, false ) ) { self.CancelActivity(); self.QueueActivity( new Turn( 96 ) ); diff --git a/OpenRa.Game/Traits/MineImmune.cs b/OpenRa.Game/Traits/MineImmune.cs index d711a036ba..04f488a096 100644 --- a/OpenRa.Game/Traits/MineImmune.cs +++ b/OpenRa.Game/Traits/MineImmune.cs @@ -1,8 +1,6 @@  namespace OpenRa.Game.Traits { - class MineImmune - { - public MineImmune(Actor self) { } - } + class MineImmuneInfo : StatelessTraitInfo { } + class MineImmune { } } diff --git a/OpenRa.Game/Traits/Minelayer.cs b/OpenRa.Game/Traits/Minelayer.cs index 871029b159..0e6092f922 100644 --- a/OpenRa.Game/Traits/Minelayer.cs +++ b/OpenRa.Game/Traits/Minelayer.cs @@ -1,22 +1,27 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Linq; namespace OpenRa.Game.Traits { + class MinelayerInfo : ITraitInfo + { + public readonly string Mine = "minv"; + + public object Create( Actor self ) + { + return new Minelayer(); + } + } + class Minelayer : IIssueOrder, IResolveOrder { - public Minelayer(Actor self) { } - public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { var limitedAmmo = self.traits.GetOrDefault(); if (limitedAmmo != null && !limitedAmmo.HasAmmo()) return null; - + // Ensure that the cell is empty except for the minelayer - if (Game.UnitInfluence.GetUnitsAt( xy ).Any(a => a != self)) + if (Game.UnitInfluence.GetUnitsAt(xy).Any(a => a != self)) return null; if (mi.Button == MouseButton.Right && underCursor == self) @@ -36,7 +41,7 @@ namespace OpenRa.Game.Traits // todo: delay a bit? (req making deploy-mine an activity) Game.world.AddFrameEndTask( - w => w.Add(new Actor(Rules.UnitInfo[self.Info.Primary], self.Location, self.Owner))); + w => w.Add(new Actor(self.Info.Traits.Get().Mine, self.Location, self.Owner))); } } } diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs index de1f0dca25..2a1da2f3aa 100644 --- a/OpenRa.Game/Traits/Mobile.cs +++ b/OpenRa.Game/Traits/Mobile.cs @@ -5,6 +5,13 @@ using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { + class MobileInfo : ITraitInfo + { + public readonly UnitMovementType MovementType = UnitMovementType.Wheel; + + public object Create(Actor self) { return new Mobile(self); } + } + class Mobile : IIssueOrder, IResolveOrder, IOccupySpace, IMovement { readonly Actor self; @@ -78,19 +85,7 @@ namespace OpenRa.Game.Traits public UnitMovementType GetMovementType() { - switch (Rules.UnitCategory[self.Info.Name]) - { - case "Infantry": - return UnitMovementType.Foot; - case "Vehicle": - return (self.Info as VehicleInfo).Tracked ? UnitMovementType.Track : UnitMovementType.Wheel; - case "Ship": - return UnitMovementType.Float; - case "Plane": - return UnitMovementType.Fly; - default: - throw new InvalidOperationException("GetMovementType on unit that shouldn't be able to move."); - } + return self.Info.Traits.Get().MovementType; } public bool CanEnterCell(int2 a) diff --git a/OpenRa.Game/Traits/Passenger.cs b/OpenRa.Game/Traits/Passenger.cs index 20ee863d2d..2339b37325 100644 --- a/OpenRa.Game/Traits/Passenger.cs +++ b/OpenRa.Game/Traits/Passenger.cs @@ -1,15 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Linq; using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class PassengerInfo : StatelessTraitInfo {} + class Passenger : IIssueOrder, IResolveOrder { - public Passenger(Actor self) { } - public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { if (mi.Button != MouseButton.Right) @@ -22,8 +19,8 @@ namespace OpenRa.Game.Traits if (cargo == null || cargo.IsFull(underCursor)) return null; - var umt = self.traits.WithInterface().First().GetMovementType(); - if (!underCursor.Info.PassengerTypes.Contains(umt)) + var umt = self.traits.Get().GetMovementType(); + if (!underCursor.Info.Traits.Get().PassengerTypes.Contains(umt)) return null; return new Order("EnterTransport", self, underCursor, int2.Zero, null); diff --git a/OpenRa.Game/Traits/Plane.cs b/OpenRa.Game/Traits/Plane.cs index 6b5c9827a3..613bf1863d 100644 --- a/OpenRa.Game/Traits/Plane.cs +++ b/OpenRa.Game/Traits/Plane.cs @@ -1,11 +1,13 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class PlaneInfo : ITraitInfo + { + public object Create(Actor self) { return new Plane(self); } + } + class Plane : IIssueOrder, IResolveOrder, IMovement { public IDisposable reservation; @@ -15,8 +17,8 @@ namespace OpenRa.Game.Traits // todo: push into data! static bool PlaneCanEnter(Actor a) { - if (a.Info == Rules.UnitInfo["AFLD"]) return true; - if (a.Info == Rules.UnitInfo["FIX"]) return true; + if (a.Info.Name == "afld") return true; + if (a.Info.Name == "fix") return true; return false; } @@ -59,7 +61,7 @@ namespace OpenRa.Game.Traits self.CancelActivity(); self.QueueActivity(new ReturnToBase(self, order.TargetActor)); - self.QueueActivity(order.TargetActor.Info == Rules.UnitInfo["AFLD"] + self.QueueActivity(order.TargetActor.Info.Name == "afld" ? (IActivity)new Rearm() : new Repair()); } } diff --git a/OpenRa.Game/Traits/Production.cs b/OpenRa.Game/Traits/Production.cs index fb83d73a85..28cbda8be8 100755 --- a/OpenRa.Game/Traits/Production.cs +++ b/OpenRa.Game/Traits/Production.cs @@ -1,9 +1,17 @@ -using OpenRa.Game.GameRules; +using System.Collections.Generic; using System.Linq; -using System.Collections.Generic; +using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { + class ProductionInfo : ITraitInfo + { + public readonly int[] SpawnOffset = null; + public readonly string[] Produces = { }; + + public object Create(Actor self) { return new Production(self); } + } + class Production : IIssueOrder, IResolveOrder, IProducer, ITags { bool isPrimary = false; @@ -11,23 +19,23 @@ namespace OpenRa.Game.Traits public Production( Actor self ) { } - public virtual int2? CreationLocation( Actor self, UnitInfo producee ) + public virtual int2? CreationLocation( Actor self, NewUnitInfo producee ) { return ( 1 / 24f * self.CenterLocation ).ToInt2(); } public virtual int CreationFacing( Actor self, Actor newUnit ) { - return newUnit.Info.InitialFacing; + return newUnit.Info.Traits.GetOrDefault().InitialFacing; } - public bool Produce( Actor self, UnitInfo producee ) + public bool Produce( Actor self, NewUnitInfo producee ) { var location = CreationLocation( self, producee ); if( location == null || Game.UnitInfluence.GetUnitsAt( location.Value ).Any() ) return false; - var newUnit = new Actor( producee, location.Value, self.Owner ); + var newUnit = new Actor( producee.Name, location.Value, self.Owner ); newUnit.traits.Get().Facing = CreationFacing( self, newUnit ); ; var rp = self.traits.GetOrDefault(); @@ -38,10 +46,10 @@ namespace OpenRa.Game.Traits newUnit.QueueActivity( new Activities.Move( rp.rallyPoint, 1 ) ); } - var bi = self.Info as BuildingInfo; - if (bi != null && bi.SpawnOffset != null) + var pi = self.Info.Traits.Get(); + if (pi != null && pi.SpawnOffset != null) newUnit.CenterLocation = self.CenterLocation - + new float2(bi.SpawnOffset[0], bi.SpawnOffset[1]); + + new float2(pi.SpawnOffset[0], pi.SpawnOffset[1]); Game.world.Add( newUnit ); @@ -78,12 +86,12 @@ namespace OpenRa.Game.Traits } // Cancel existing primaries - foreach (var p in (self.Info as BuildingInfo).Produces) + foreach (var p in self.Info.Traits.Get().Produces) { foreach (var b in Game.world.Actors.Where(x => x.traits.Contains() && x.Owner == self.Owner && x.traits.Get().IsPrimary == true - && (x.Info as BuildingInfo).Produces.Contains(p))) + && (x.Info.Traits.Get().Produces.Contains(p)))) { b.traits.Get().SetPrimaryProducer(b, false); } diff --git a/OpenRa.Game/Traits/ProductionQueue.cs b/OpenRa.Game/Traits/ProductionQueue.cs index eabd106c8c..edbe3a9a8c 100755 --- a/OpenRa.Game/Traits/ProductionQueue.cs +++ b/OpenRa.Game/Traits/ProductionQueue.cs @@ -6,6 +6,11 @@ using IjwFramework.Collections; namespace OpenRa.Game.Traits { + class ProductionQueueInfo : ITraitInfo + { + public object Create(Actor self) { return new ProductionQueue(self); } + } + class ProductionQueue : IResolveOrder, ITick { Actor self; @@ -29,7 +34,7 @@ namespace OpenRa.Game.Traits case "StartProduction": { string group = Rules.UnitCategory[ order.TargetString ]; - var ui = Rules.UnitInfo[ order.TargetString ]; + var ui = Rules.NewUnitInfo[ order.TargetString ].Traits.Get(); var time = ui.Cost * Rules.General.BuildSpeed /* todo: country-specific build speed bonus */ * ( 25 * 60 ) /* frames per min */ /* todo: build acceleration, if we do that */ @@ -121,7 +126,7 @@ namespace OpenRa.Game.Traits public void BuildUnit( string name ) { - var newUnitType = Rules.UnitInfo[ name ]; + var newUnitType = Rules.NewUnitInfo[ name ]; var producerTypes = Rules.TechTree.UnitBuiltAt( newUnitType ); Actor producer = null; diff --git a/OpenRa.Game/Traits/ProductionSurround.cs b/OpenRa.Game/Traits/ProductionSurround.cs index 4fb0091697..0bf3ec8066 100644 --- a/OpenRa.Game/Traits/ProductionSurround.cs +++ b/OpenRa.Game/Traits/ProductionSurround.cs @@ -1,11 +1,13 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Linq; using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { + class ProductionSurroundInfo : ITraitInfo + { + public object Create(Actor self) { return new ProductionSurround(self); } + } + class ProductionSurround : Production { public ProductionSurround(Actor self) : base(self) { } @@ -24,9 +26,9 @@ namespace OpenRa.Game.Traits return null; } - public override int2? CreationLocation(Actor self, UnitInfo producee) + public override int2? CreationLocation(Actor self, NewUnitInfo producee) { - return FindAdjacentTile(self, producee.WaterBound ? + return FindAdjacentTile(self, producee.Traits.Get().WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel); /* hackety hack */ } diff --git a/OpenRa.Game/Traits/ProvidesRadar.cs b/OpenRa.Game/Traits/ProvidesRadar.cs index 7a4ba5e0c6..ec6c0c0536 100644 --- a/OpenRa.Game/Traits/ProvidesRadar.cs +++ b/OpenRa.Game/Traits/ProvidesRadar.cs @@ -1,19 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - + namespace OpenRa.Game.Traits { + class ProvidesRadarInfo : StatelessTraitInfo {} + class ProvidesRadar { - Actor self; - public ProvidesRadar(Actor self) - { - this.self = self; - } - - public bool IsActive() + public bool IsActive(Actor self) { // TODO: Check for nearby MRJ diff --git a/OpenRa.Game/Traits/RallyPoint.cs b/OpenRa.Game/Traits/RallyPoint.cs index fb2006fa5d..6a7fc5c434 100644 --- a/OpenRa.Game/Traits/RallyPoint.cs +++ b/OpenRa.Game/Traits/RallyPoint.cs @@ -4,6 +4,13 @@ using OpenRa.Game.Orders; namespace OpenRa.Game.Traits { + class RallyPointInfo : ITraitInfo + { + public readonly int[] RallyPoint = { 1, 3 }; + + public object Create(Actor self) { return new RallyPoint(self); } + } + class RallyPoint : IRender, IIssueOrder, IResolveOrder, ITick { [Sync] @@ -12,8 +19,8 @@ namespace OpenRa.Game.Traits public RallyPoint(Actor self) { - var bi = self.traits.Get().unitInfo; - rallyPoint = self.Location + new int2(bi.RallyPoint[0], bi.RallyPoint[1]); + var info = self.Info.Traits.Get(); + rallyPoint = self.Location + new int2(info.RallyPoint[0], info.RallyPoint[1]); anim = new Animation("flagfly"); anim.PlayRepeating("idle"); } diff --git a/OpenRa.Game/Traits/RenderBuilding.cs b/OpenRa.Game/Traits/RenderBuilding.cs index d5291d0b59..1024581177 100644 --- a/OpenRa.Game/Traits/RenderBuilding.cs +++ b/OpenRa.Game/Traits/RenderBuilding.cs @@ -1,10 +1,13 @@ using System; -using System.Collections.Generic; -using OpenRa.Game.Graphics; using OpenRa.Game.Effects; namespace OpenRa.Game.Traits { + class RenderBuildingInfo : RenderSimpleInfo + { + public override object Create(Actor self) { return new RenderBuilding(self); } + } + class RenderBuilding : RenderSimple, INotifyDamage, INotifySold { const int SmallBibStart = 1; @@ -30,7 +33,7 @@ namespace OpenRa.Game.Traits void DoBib(Actor self, bool isRemove) { - var buildingInfo = self.traits.Get().unitInfo; + var buildingInfo = self.Info.Traits.Get(); if (buildingInfo.Bib) { var size = buildingInfo.Dimensions.X; diff --git a/OpenRa.Game/Traits/RenderBuildingCharge.cs b/OpenRa.Game/Traits/RenderBuildingCharge.cs index e0a5e7bd3f..9c6b88efd5 100644 --- a/OpenRa.Game/Traits/RenderBuildingCharge.cs +++ b/OpenRa.Game/Traits/RenderBuildingCharge.cs @@ -1,10 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - + namespace OpenRa.Game.Traits { + class RenderBuildingChargeInfo : RenderBuildingInfo + { + public override object Create(Actor self) { return new RenderBuildingCharge(self); } + } + /* used for tesla */ class RenderBuildingCharge : RenderBuilding, INotifyAttack { diff --git a/OpenRa.Game/Traits/RenderBuildingOre.cs b/OpenRa.Game/Traits/RenderBuildingOre.cs index 015db7721e..1e06072a1e 100644 --- a/OpenRa.Game/Traits/RenderBuildingOre.cs +++ b/OpenRa.Game/Traits/RenderBuildingOre.cs @@ -1,7 +1,11 @@ -using System; - + namespace OpenRa.Game.Traits { + class RenderBuildingOreInfo : RenderBuildingInfo + { + public override object Create(Actor self) { return new RenderBuildingOre(self); } + } + class RenderBuildingOre : RenderBuilding, INotifyBuildComplete { public RenderBuildingOre(Actor self) diff --git a/OpenRa.Game/Traits/RenderBuildingTurreted.cs b/OpenRa.Game/Traits/RenderBuildingTurreted.cs index 628377efd2..021c23ad65 100644 --- a/OpenRa.Game/Traits/RenderBuildingTurreted.cs +++ b/OpenRa.Game/Traits/RenderBuildingTurreted.cs @@ -1,6 +1,11 @@  namespace OpenRa.Game.Traits { + class RenderBuildingTurretedInfo : RenderBuildingInfo + { + public override object Create(Actor self) { return new RenderBuildingTurreted(self); } + } + class RenderBuildingTurreted : RenderBuilding, INotifyBuildComplete { public RenderBuildingTurreted(Actor self) diff --git a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs index 074d058068..6386120fa5 100644 --- a/OpenRa.Game/Traits/RenderBuildingWarFactory.cs +++ b/OpenRa.Game/Traits/RenderBuildingWarFactory.cs @@ -4,6 +4,11 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class RenderWarFactoryInfo : ITraitInfo + { + public object Create(Actor self) { return new RenderWarFactory(self); } + } + class RenderWarFactory : IRender, INotifyBuildComplete, INotifyDamage, ITick, INotifyProduction { public Animation roof; @@ -21,7 +26,7 @@ namespace OpenRa.Game.Traits public RenderWarFactory(Actor self) { this.self = self; - roof = new Animation(self.Info.Image ?? self.Info.Name); + roof = new Animation(self.traits.Get().GetImage(self)); } public void BuildingComplete( Actor self ) diff --git a/OpenRa.Game/Traits/RenderInfantry.cs b/OpenRa.Game/Traits/RenderInfantry.cs index 04ae828be7..d3edc1ee33 100644 --- a/OpenRa.Game/Traits/RenderInfantry.cs +++ b/OpenRa.Game/Traits/RenderInfantry.cs @@ -1,13 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OpenRa.Game.Graphics; -using OpenRa.Game.GameRules; -using OpenRa.Game.Effects; +using OpenRa.Game.Effects; namespace OpenRa.Game.Traits { + class RenderInfantryInfo : RenderSimpleInfo + { + public override object Create(Actor self) { return new RenderInfantry(self); } + } + class RenderInfantry : RenderSimple, INotifyAttack, INotifyDamage { public RenderInfantry(Actor self) diff --git a/OpenRa.Game/Traits/RenderSimple.cs b/OpenRa.Game/Traits/RenderSimple.cs index d5db307c09..b27d49f887 100644 --- a/OpenRa.Game/Traits/RenderSimple.cs +++ b/OpenRa.Game/Traits/RenderSimple.cs @@ -1,18 +1,30 @@ using System; using System.Collections.Generic; -using IjwFramework.Collections; +using System.Linq; using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + abstract class RenderSimpleInfo : ITraitInfo + { + public readonly string Image = null; + + public abstract object Create(Actor self); + } + abstract class RenderSimple : IRender, ITick { public Dictionary anims = new Dictionary(); public Animation anim { get { return anims[ "" ].Animation; } } + public string GetImage(Actor self) + { + return self.Info.Traits.Get().Image ?? self.Info.Name; + } + public RenderSimple(Actor self) { - anims.Add( "", new Animation( self.Info.Image ?? self.Info.Name ) ); + anims.Add( "", new Animation( GetImage(self) ) ); } public virtual IEnumerable Render( Actor self ) diff --git a/OpenRa.Game/Traits/RenderUnit.cs b/OpenRa.Game/Traits/RenderUnit.cs index 9d293d8340..067b4ccc90 100644 --- a/OpenRa.Game/Traits/RenderUnit.cs +++ b/OpenRa.Game/Traits/RenderUnit.cs @@ -5,6 +5,11 @@ using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { + class RenderUnitInfo : RenderSimpleInfo + { + public override object Create(Actor self) { return new RenderUnit(self); } + } + class RenderUnit : RenderSimple, INotifyDamage { public RenderUnit(Actor self) diff --git a/OpenRa.Game/Traits/RenderUnitMuzzleFlash.cs b/OpenRa.Game/Traits/RenderUnitMuzzleFlash.cs index 0e198ba1ad..9e18c5830a 100644 --- a/OpenRa.Game/Traits/RenderUnitMuzzleFlash.cs +++ b/OpenRa.Game/Traits/RenderUnitMuzzleFlash.cs @@ -5,22 +5,26 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class RenderUnitMuzzleFlashInfo : RenderUnitInfo + { + public override object Create(Actor self) { return new RenderUnitMuzzleFlash(self); } + } + class RenderUnitMuzzleFlash : RenderUnit { public RenderUnitMuzzleFlash(Actor self) : base(self) { - if (!self.Info.MuzzleFlash) throw new InvalidOperationException("wtf??"); - var unit = self.traits.Get(); - var attack = self.traits.WithInterface().First(); + var attack = self.traits.Get(); + var attackInfo = self.Info.Traits.Get(); - var muzzleFlash = new Animation(self.Info.Name); + var muzzleFlash = new Animation(GetImage(self)); muzzleFlash.PlayFetchIndex("muzzle", () => (Util.QuantizeFacing(unit.Facing, 8)) * 6 + (int)(attack.primaryRecoil * 5.9f)); anims.Add( "muzzle", new AnimationWithOffset( muzzleFlash, - () => self.Info.PrimaryOffset.AbsOffset(), + () => attackInfo.PrimaryOffset.AbsOffset(), () => attack.primaryRecoil <= 0 ) ); } } diff --git a/OpenRa.Game/Traits/RenderUnitReload.cs b/OpenRa.Game/Traits/RenderUnitReload.cs index 59f05a5ea7..ea966477c4 100644 --- a/OpenRa.Game/Traits/RenderUnitReload.cs +++ b/OpenRa.Game/Traits/RenderUnitReload.cs @@ -2,6 +2,11 @@ namespace OpenRa.Game.Traits { + class RenderUnitReloadInfo : RenderUnitInfo + { + public override object Create(Actor self) { return new RenderUnitReload(self); } + } + class RenderUnitReload : RenderUnit { public RenderUnitReload(Actor self) @@ -11,7 +16,7 @@ namespace OpenRa.Game.Traits { var isAttacking = self.GetCurrentActivity() is Activities.Attack; - var attack = self.traits.WithInterface().FirstOrDefault(); + var attack = self.traits.GetOrDefault(); if (attack != null) anim.ReplaceAnim((attack.IsReloading() ? "empty-" : "") diff --git a/OpenRa.Game/Traits/RenderUnitRotor.cs b/OpenRa.Game/Traits/RenderUnitRotor.cs index b2174a97c4..7606453a91 100755 --- a/OpenRa.Game/Traits/RenderUnitRotor.cs +++ b/OpenRa.Game/Traits/RenderUnitRotor.cs @@ -2,6 +2,14 @@ namespace OpenRa.Game.Traits { + class RenderUnitRotorInfo : RenderUnitInfo + { + public readonly int[] PrimaryOffset = { 0, 0 }; + public readonly int[] SecondaryOffset = null; + + public override object Create(Actor self) { return new RenderUnitRotor(self); } + } + class RenderUnitRotor : RenderUnit { public Animation rotorAnim, secondRotorAnim; @@ -10,21 +18,22 @@ namespace OpenRa.Game.Traits : base(self) { var unit = self.traits.Get(); + var info = self.Info.Traits.Get(); - rotorAnim = new Animation(self.Info.Name); + rotorAnim = new Animation(GetImage(self)); rotorAnim.PlayRepeating("rotor"); anims.Add( "rotor_1", new AnimationWithOffset( rotorAnim, - () => Util.GetTurretPosition( self, unit, self.Info.RotorOffset, 0 ), + () => Util.GetTurretPosition( self, unit, info.PrimaryOffset, 0 ), null ) ); - if (self.Info.RotorOffset2 == null) return; + if (info.SecondaryOffset == null) return; - secondRotorAnim = new Animation( self.Info.Name ); + secondRotorAnim = new Animation(GetImage(self)); secondRotorAnim.PlayRepeating( "rotor2" ); anims.Add( "rotor_2", new AnimationWithOffset( secondRotorAnim, - () => Util.GetTurretPosition(self, unit, self.Info.RotorOffset2, 0), + () => Util.GetTurretPosition(self, unit, info.SecondaryOffset, 0), null ) ); } diff --git a/OpenRa.Game/Traits/RenderUnitSpinner.cs b/OpenRa.Game/Traits/RenderUnitSpinner.cs index aefb72329f..f0a3f3dce0 100755 --- a/OpenRa.Game/Traits/RenderUnitSpinner.cs +++ b/OpenRa.Game/Traits/RenderUnitSpinner.cs @@ -1,22 +1,28 @@ using System.Collections.Generic; +using System.Linq; using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class RenderUnitSpinnerInfo : RenderUnitInfo + { + public readonly int[] Offset = { 0, 0 }; + public override object Create(Actor self) { return new RenderUnitSpinner(self); } + } + class RenderUnitSpinner : RenderUnit { - public Animation spinnerAnim; - public RenderUnitSpinner( Actor self ) : base(self) { var unit = self.traits.Get(); + var info = self.Info.Traits.Get(); - spinnerAnim = new Animation( self.Info.Name ); + var spinnerAnim = new Animation( GetImage(self) ); spinnerAnim.PlayRepeating( "spinner" ); anims.Add( "spinner", new AnimationWithOffset( spinnerAnim, - () => Util.GetTurretPosition( self, unit, self.Info.PrimaryOffset, 0 ), + () => Util.GetTurretPosition( self, unit, info.Offset, 0 ), null ) ); } } diff --git a/OpenRa.Game/Traits/RenderUnitTurreted.cs b/OpenRa.Game/Traits/RenderUnitTurreted.cs index f05caa57f4..30a204f6a0 100644 --- a/OpenRa.Game/Traits/RenderUnitTurreted.cs +++ b/OpenRa.Game/Traits/RenderUnitTurreted.cs @@ -4,41 +4,45 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class RenderUnitTurretedInfo : RenderUnitInfo + { + public override object Create(Actor self) { return new RenderUnitTurreted(self); } + } + class RenderUnitTurreted : RenderUnit { - public Animation muzzleFlash; - public RenderUnitTurreted(Actor self) : base(self) { var unit = self.traits.Get(); var turreted = self.traits.Get(); - var attack = self.traits.WithInterface().FirstOrDefault(); + var attack = self.traits.GetOrDefault(); + var attackInfo = self.Info.Traits.Get(); - var turretAnim = new Animation(self.Info.Name); + var turretAnim = new Animation(GetImage(self)); turretAnim.PlayFacing( "turret", () => turreted.turretFacing ); - if( self.Info.PrimaryOffset != null ) + if( attackInfo.PrimaryOffset != null ) anims.Add("turret_1", new AnimationWithOffset( turretAnim, - () => Util.GetTurretPosition(self, unit, self.Info.PrimaryOffset, attack.primaryRecoil), + () => Util.GetTurretPosition(self, unit, attackInfo.PrimaryOffset, attack.primaryRecoil), null) { ZOffset = 1 }); - if( self.Info.SecondaryOffset != null ) + if (attackInfo.SecondaryOffset != null) anims.Add("turret_2", new AnimationWithOffset( turretAnim, - () => Util.GetTurretPosition(self, unit, self.Info.SecondaryOffset, attack.secondaryRecoil), + () => Util.GetTurretPosition(self, unit, attackInfo.SecondaryOffset, attack.secondaryRecoil), null) { ZOffset = 1 }); - if( self.Info.MuzzleFlash ) + if( attackInfo.MuzzleFlash ) { - muzzleFlash = new Animation( self.Info.Name ); + var muzzleFlash = new Animation( GetImage(self) ); muzzleFlash.PlayFetchIndex( "muzzle", () => ( Util.QuantizeFacing( self.traits.Get().turretFacing, 8 ) ) * 6 + (int)( attack.primaryRecoil * 5.9f ) ); /* hack: recoil can be 1.0f, but don't overflow into next anim */ anims.Add( "muzzle_flash", new AnimationWithOffset( muzzleFlash, - () => Util.GetTurretPosition( self, unit, self.Info.PrimaryOffset, attack.primaryRecoil ), + () => Util.GetTurretPosition(self, unit, attackInfo.PrimaryOffset, attack.primaryRecoil), () => attack.primaryRecoil <= 0 ) ); } } diff --git a/OpenRa.Game/Traits/Repairable.cs b/OpenRa.Game/Traits/Repairable.cs index c5c38caf84..0cada1212e 100644 --- a/OpenRa.Game/Traits/Repairable.cs +++ b/OpenRa.Game/Traits/Repairable.cs @@ -6,6 +6,11 @@ using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { + class RepairableInfo : ITraitInfo + { + public object Create(Actor self) { return new Repairable(self); } + } + class Repairable : IIssueOrder, IResolveOrder { IDisposable reservation; @@ -16,7 +21,7 @@ namespace OpenRa.Game.Traits if (mi.Button != MouseButton.Right) return null; if (underCursor == null) return null; - if (underCursor.Info == Rules.UnitInfo["FIX"] + if (underCursor.Info.Name == "fix" && underCursor.Owner == self.Owner && !Reservable.IsReserved(underCursor)) return new Order("Enter", self, underCursor, int2.Zero, null); diff --git a/OpenRa.Game/Traits/Reservable.cs b/OpenRa.Game/Traits/Reservable.cs index b459bc3da7..b25b610839 100644 --- a/OpenRa.Game/Traits/Reservable.cs +++ b/OpenRa.Game/Traits/Reservable.cs @@ -2,6 +2,11 @@ namespace OpenRa.Game.Traits { + class ReservableInfo : ITraitInfo + { + public object Create(Actor self) { return new Reservable(self); } + } + class Reservable : ITick { public Reservable(Actor self) { } diff --git a/OpenRa.Game/Traits/SeedsOre.cs b/OpenRa.Game/Traits/SeedsOre.cs index 98bb98ab9e..a722e3f858 100644 --- a/OpenRa.Game/Traits/SeedsOre.cs +++ b/OpenRa.Game/Traits/SeedsOre.cs @@ -1,10 +1,10 @@  namespace OpenRa.Game.Traits { + class SeedsOreInfo : StatelessTraitInfo {} + class SeedsOre : ITick { - public SeedsOre( Actor self ) {} - const double OreSeedProbability = .05; // todo: push this out into rules public void Tick(Actor self) diff --git a/OpenRa.Game/Traits/Selectable.cs b/OpenRa.Game/Traits/Selectable.cs new file mode 100755 index 0000000000..5e7a42c575 --- /dev/null +++ b/OpenRa.Game/Traits/Selectable.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class SelectableInfo : StatelessTraitInfo + { + public readonly int Priority = 10; + public readonly int[] Bounds = null; + public readonly string Voice = "GenericVoice"; + } + + class Selectable {} +} diff --git a/OpenRa.Game/Traits/SquishByTank.cs b/OpenRa.Game/Traits/SquishByTank.cs index ed84275899..baaeacb70b 100644 --- a/OpenRa.Game/Traits/SquishByTank.cs +++ b/OpenRa.Game/Traits/SquishByTank.cs @@ -5,6 +5,11 @@ using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { + class SquishByTankInfo : ITraitInfo + { + public object Create(Actor self) { return new SquishByTank(self); } + } + class SquishByTank : ICrushable { readonly Actor self; diff --git a/OpenRa.Game/Traits/StoresOre.cs b/OpenRa.Game/Traits/StoresOre.cs index bdabfca5d2..f3591580c3 100644 --- a/OpenRa.Game/Traits/StoresOre.cs +++ b/OpenRa.Game/Traits/StoresOre.cs @@ -3,21 +3,18 @@ using System; using OpenRa.Game.GameRules; namespace OpenRa.Game.Traits { + class StoresOreInfo : StatelessTraitInfo + { + public readonly int Pips = 0; + public readonly int Capacity = 0; + } + class StoresOre : IPips, IAcceptThief { - public const int MaxStealAmount = 100; //todo: How is cash stolen determined? - - readonly Actor self; - - public StoresOre(Actor self) - { - this.self = self; - } - public void OnSteal(Actor self, Actor thief) { // Steal half the ore the building holds - var toSteal = (self.Info as BuildingInfo).Storage/2; + var toSteal = self.Info.Traits.Get().Capacity / 2; self.Owner.TakeCash(toSteal); thief.Owner.GiveCash(toSteal); @@ -31,15 +28,12 @@ namespace OpenRa.Game.Traits public IEnumerable GetPips(Actor self) { - for (int i = 0; i < self.Info.OrePips; i++) - { - if (Game.LocalPlayer.GetSiloFullness() > i * 1.0f / self.Info.OrePips) - { - yield return PipType.Yellow; - continue; - } - yield return PipType.Transparent; - } + var numPips = self.Info.Traits.Get().Pips; + + return Graphics.Util.MakeArray( numPips, + i => (Game.LocalPlayer.GetSiloFullness() > i * 1.0f / numPips) + ? PipType.Yellow : PipType.Transparent ); + } } } diff --git a/OpenRa.Game/Traits/Submarine.cs b/OpenRa.Game/Traits/Submarine.cs index 3183072b85..79033ed5b5 100644 --- a/OpenRa.Game/Traits/Submarine.cs +++ b/OpenRa.Game/Traits/Submarine.cs @@ -4,6 +4,11 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class SubmarineInfo : ITraitInfo + { + public object Create(Actor self) { return new Submarine(self); } + } + class Submarine : IRenderModifier, INotifyAttack, ITick, INotifyDamage { [Sync] diff --git a/OpenRa.Game/Traits/TakeCover.cs b/OpenRa.Game/Traits/TakeCover.cs index 192f2e899b..abd2148592 100644 --- a/OpenRa.Game/Traits/TakeCover.cs +++ b/OpenRa.Game/Traits/TakeCover.cs @@ -1,6 +1,11 @@  namespace OpenRa.Game.Traits { + class TakeCoverInfo : ITraitInfo + { + public object Create(Actor self) { return new TakeCover(self); } + } + // infantry prone behavior class TakeCover : ITick, INotifyDamage, IDamageModifier, ISpeedModifier { diff --git a/OpenRa.Game/Traits/Thief.cs b/OpenRa.Game/Traits/Thief.cs index 54b34b5d5c..685ccefa68 100644 --- a/OpenRa.Game/Traits/Thief.cs +++ b/OpenRa.Game/Traits/Thief.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using System.Linq; namespace OpenRa.Game.Traits { + class ThiefInfo : StatelessTraitInfo { } + class Thief : IIssueOrder, IResolveOrder { - public Thief(Actor self) { } - public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { if (mi.Button != MouseButton.Right) return null; diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index 849679042b..6a1e6aa0a6 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -2,6 +2,7 @@ using System.Drawing; using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; +using IjwFramework.Types; namespace OpenRa.Game.Traits { @@ -24,7 +25,7 @@ namespace OpenRa.Game.Traits interface IProducer { - bool Produce( Actor self, UnitInfo producee ); + bool Produce( Actor self, NewUnitInfo producee ); void SetPrimaryProducer(Actor self, bool isPrimary); } interface IOccupySpace { IEnumerable OccupiedCells(); } @@ -69,4 +70,14 @@ namespace OpenRa.Game.Traits public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, newOffset); } public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, ZOffset); } } + + interface ITraitInfo { object Create(Actor self); } + + class StatelessTraitInfo : ITraitInfo + where T : new() + { + static Lazy Instance = Lazy.New(() => new T()); + public object Create(Actor self) { return Instance.Value; } + } + } diff --git a/OpenRa.Game/Traits/Tree.cs b/OpenRa.Game/Traits/Tree.cs deleted file mode 100644 index f4c3ebced1..0000000000 --- a/OpenRa.Game/Traits/Tree.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; -using OpenRa.Game.Graphics; - -namespace OpenRa.Game.Traits -{ - class Tree : IRender - { - Sprite Image; - - public Tree(Sprite treeImage) - { - Image = treeImage; - } - - public IEnumerable Render(Actor self) - { - yield return new Renderable(Image, Game.CellSize * (float2)self.Location, 0); - } - } -} diff --git a/OpenRa.Game/Traits/Turreted.cs b/OpenRa.Game/Traits/Turreted.cs index b20de37e63..3df089fae2 100644 --- a/OpenRa.Game/Traits/Turreted.cs +++ b/OpenRa.Game/Traits/Turreted.cs @@ -1,6 +1,15 @@ - +using System.Linq; + namespace OpenRa.Game.Traits { + class TurretedInfo : ITraitInfo + { + public readonly int ROT = 0; + public readonly int InitialFacing = 128; + + public object Create(Actor self) { return new Turreted(self); } + } + class Turreted : ITick { [Sync] @@ -9,13 +18,13 @@ namespace OpenRa.Game.Traits public Turreted(Actor self) { - turretFacing = self.Info.InitialFacing; + turretFacing = self.Info.Traits.Get().InitialFacing; } public void Tick( Actor self ) { var df = desiredFacing ?? ( self.traits.Contains() ? self.traits.Get().Facing : turretFacing ); - Util.TickFacing( ref turretFacing, df, self.Info.ROT ); + Util.TickFacing(ref turretFacing, df, self.Info.Traits.Get().ROT); } } } diff --git a/OpenRa.Game/Traits/Unit.cs b/OpenRa.Game/Traits/Unit.cs index ebfc56cf31..d0fe1b0ed6 100755 --- a/OpenRa.Game/Traits/Unit.cs +++ b/OpenRa.Game/Traits/Unit.cs @@ -1,6 +1,16 @@ - +using OpenRa.Game.GameRules; + namespace OpenRa.Game.Traits { + class UnitInfo : OwnedActorInfo, ITraitInfo + { + public readonly int InitialFacing = 128; + public readonly int ROT = 0; + public readonly int Speed = 0; + + public object Create( Actor self ) { return new Unit( self ); } + } + class Unit : INotifyDamage { [Sync] diff --git a/OpenRa.Game/Traits/Util.cs b/OpenRa.Game/Traits/Util.cs index fa918b337d..3e9018f05b 100755 --- a/OpenRa.Game/Traits/Util.cs +++ b/OpenRa.Game/Traits/Util.cs @@ -82,14 +82,14 @@ namespace OpenRa.Game.Traits static float2 GetRecoil(Actor self, float recoil) { - if (self.Info.Recoil == 0) return float2.Zero; - var rut = self.traits.WithInterface().FirstOrDefault(); + if (self.Info.Traits.Get().Recoil == 0) return float2.Zero; + var rut = self.traits.GetOrDefault(); if (rut == null) return float2.Zero; var facing = self.traits.Get().turretFacing; var quantizedFacing = QuantizeFacing(facing, rut.anim.CurrentSequence.Length) * (256 / rut.anim.CurrentSequence.Length); - return RotateVectorByFacing(new float2(0, recoil * self.Info.Recoil), quantizedFacing, .7f); + return RotateVectorByFacing(new float2(0, recoil * self.Info.Traits.Get().Recoil), quantizedFacing, .7f); } public static float2 CenterOfCell(int2 loc) @@ -106,7 +106,7 @@ namespace OpenRa.Game.Traits { if( unit == null ) return int2.Zero; /* things that don't have a rotating base don't need the turrets repositioned */ - var ru = self.traits.WithInterface().FirstOrDefault(); + var ru = self.traits.GetOrDefault(); var numDirs = (ru != null) ? ru.anim.CurrentSequence.Length : 8; var bodyFacing = unit.Facing; var quantizedFacing = QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs); @@ -127,14 +127,14 @@ namespace OpenRa.Game.Traits public static float GetEffectiveSpeed(Actor self) { - var mi = self.Info as MobileInfo; - if (mi == null) return 0f; + var unitInfo = self.Info.Traits.GetOrDefault(); + if( unitInfo == null ) return 0f; var modifier = self.traits .WithInterface() .Select(t => t.GetSpeedModifier()) .Product(); - return mi.Speed * modifier; + return unitInfo.Speed * modifier; } public static IActivity SequenceActivities(params IActivity[] acts) @@ -142,5 +142,12 @@ namespace OpenRa.Game.Traits return acts.Reverse().Aggregate( (next, a) => { a.NextActivity = next; return a; }); } + + public static float GetMaximumRange(Actor self) + { + var info = self.Info.Traits.Get(); + return new[] { self.GetPrimaryWeapon(), self.GetSecondaryWeapon() } + .Where(w => w != null).Max(w => w.Range); + } } } diff --git a/OpenRa.Game/Traits/WaterPaletteRotation.cs b/OpenRa.Game/Traits/WaterPaletteRotation.cs index ec31812731..cba52f71a5 100644 --- a/OpenRa.Game/Traits/WaterPaletteRotation.cs +++ b/OpenRa.Game/Traits/WaterPaletteRotation.cs @@ -2,6 +2,9 @@ namespace OpenRa.Game.Traits { + // this is NOT bound through rules (it belongs on the world actor!) + // so no *Info required + class WaterPaletteRotation : ITick, IPaletteModifier { public WaterPaletteRotation(Actor self) { } diff --git a/OpenRa.Game/Traits/WithShadow.cs b/OpenRa.Game/Traits/WithShadow.cs index 7575573781..5eb49890bc 100644 --- a/OpenRa.Game/Traits/WithShadow.cs +++ b/OpenRa.Game/Traits/WithShadow.cs @@ -6,10 +6,10 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { + class WithShadowInfo : StatelessTraitInfo {} + class WithShadow : IRenderModifier { - public WithShadow(Actor self) {} - public IEnumerable ModifyRender(Actor self, IEnumerable r) { var unit = self.traits.Get(); diff --git a/OpenRa.Game/UiOverlay.cs b/OpenRa.Game/UiOverlay.cs index 0dfc1272cc..4c60fd59d3 100644 --- a/OpenRa.Game/UiOverlay.cs +++ b/OpenRa.Game/UiOverlay.cs @@ -2,6 +2,7 @@ using System.Drawing; using System.Linq; using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; +using OpenRa.Game.Traits; namespace OpenRa.Game { @@ -42,12 +43,12 @@ namespace OpenRa.Game spriteRenderer.DrawSprite(unitDebug, Game.CellSize * new float2(i, j), 0); } - public void DrawBuildingGrid( BuildingInfo bi ) + public void DrawBuildingGrid( string name, BuildingInfo bi ) { var position = Game.controller.MousePosition.ToInt2(); - var isCloseEnough = Game.IsCloseEnoughToBase(Game.LocalPlayer, bi, position); + var isCloseEnough = Game.IsCloseEnoughToBase(Game.LocalPlayer, name, bi, position); - foreach( var t in Footprint.Tiles( bi, position ) ) + foreach( var t in Footprint.Tiles( name, bi, position ) ) spriteRenderer.DrawSprite( ( isCloseEnough && Game.IsCellBuildable( t, bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel ) && !Rules.Map.ContainsResource( t ) ) ? buildOk : buildBlocked, Game.CellSize * t, 0 ); diff --git a/OpenRa.Game/UnitInfluenceMap.cs b/OpenRa.Game/UnitInfluenceMap.cs index 0982ea957d..c796f52e0a 100644 --- a/OpenRa.Game/UnitInfluenceMap.cs +++ b/OpenRa.Game/UnitInfluenceMap.cs @@ -16,8 +16,8 @@ namespace OpenRa.Game for (int i = 0; i < 128; i++) for (int j = 0; j < 128; j++) influence[ i, j ] = new List(); - - Game.world.ActorRemoved += a => Remove(a, a.traits.WithInterface().FirstOrDefault()); + + Game.world.ActorRemoved += a => Remove( a, a.traits.GetOrDefault() ); } public void Tick() @@ -53,7 +53,7 @@ namespace OpenRa.Game for( int x = 0 ; x < 128 ; x++ ) if( influence[ x, y ] != null ) foreach (var a in influence[ x, y ]) - if (!a.traits.WithInterface().First().OccupiedCells().Contains( new int2( x, y ) ) ) + if (!a.traits.Get().OccupiedCells().Contains( new int2( x, y ) ) ) throw new InvalidOperationException( "UIM: Sanity check failed A" ); foreach( Actor a in Game.world.Actors ) diff --git a/OpenRa.sln b/OpenRa.sln index 2d8e00e87b..580ec2fce2 100644 --- a/OpenRa.sln +++ b/OpenRa.sln @@ -15,6 +15,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SequenceEditor", "SequenceE EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenRA.Server", "OpenRA.Server\OpenRA.Server.csproj", "{76F621A1-3D8E-4A99-9F7E-B071EB657817}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RulesConverter", "RulesConverter\RulesConverter.csproj", "{BBE7C0D7-7529-4C34-9910-206866F204EF}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug (x86)|Any CPU = Debug (x86)|Any CPU @@ -158,6 +160,27 @@ Global {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release|Mixed Platforms.Build.0 = Release|Any CPU {76F621A1-3D8E-4A99-9F7E-B071EB657817}.Release|Win32.ActiveCfg = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug (x86)|Any CPU.ActiveCfg = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug (x86)|Any CPU.Build.0 = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug (x86)|Mixed Platforms.ActiveCfg = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug (x86)|Mixed Platforms.Build.0 = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug (x86)|Win32.ActiveCfg = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug (x86)|Win32.Build.0 = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Debug|Win32.ActiveCfg = Debug|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release (x86)|Any CPU.ActiveCfg = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release (x86)|Any CPU.Build.0 = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release (x86)|Mixed Platforms.ActiveCfg = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release (x86)|Mixed Platforms.Build.0 = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release (x86)|Win32.ActiveCfg = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release|Any CPU.Build.0 = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {BBE7C0D7-7529-4C34-9910-206866F204EF}.Release|Win32.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/RulesConverter/MiniYamlExts.cs b/RulesConverter/MiniYamlExts.cs new file mode 100755 index 0000000000..fcf0220e65 --- /dev/null +++ b/RulesConverter/MiniYamlExts.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.FileFormats; + +namespace RulesConverter +{ + using MiniYamlNodes = Dictionary; + using System.IO; + + static class MiniYamlExts + { + public static void WriteToFile( this MiniYamlNodes y, string filename ) + { + File.WriteAllLines( filename, y.ToLines( true ).Select( x => x.TrimEnd() ).ToArray() ); + } + + public static IEnumerable ToLines( this MiniYamlNodes y, bool lowest ) + { + foreach( var kv in y ) + { + foreach( var line in kv.Value.ToLines( kv.Key ) ) + yield return line; + if( lowest ) + yield return ""; + } + } + + public static IEnumerable ToLines( this MiniYaml y, string name ) + { + yield return name + ": " + y.Value; + if( y.Nodes != null ) + foreach( var line in y.Nodes.ToLines( false ) ) + yield return "\t" + line; + } + + public static void OptimizeInherits( this MiniYamlNodes y, MiniYamlNodes baseYaml ) + { + foreach( var key in y.Keys.ToList() ) + { + var node = y[ key ]; + try + { + MiniYaml inherits; + node.Nodes.TryGetValue( "Inherits", out inherits ); + if( inherits == null || string.IsNullOrEmpty( inherits.Value ) ) + continue; + + MiniYaml parent; + baseYaml.TryGetValue( inherits.Value, out parent ); + if( parent == null ) + continue; + + y[ key ] = Diff( node, parent ); + if( y[ key ] == null ) + y.Remove( key ); + } + catch + { + node.Nodes.Remove( "Inherits" ); + } + } + } + + public static MiniYamlNodes Diff( MiniYamlNodes a, MiniYamlNodes b ) + { + if( a.Count == 0 && b.Count == 0 ) + return null; + if( b.Count == 0 ) + return a; + if( a.Count == 0 ) + throw new NotImplementedException( "parent has key not in child" ); + + var ret = new MiniYamlNodes(); + + var keys = a.Keys.Union( b.Keys ).ToList(); + + foreach( var key in keys ) + { + MiniYaml aa, bb; + a.TryGetValue( key, out aa ); + b.TryGetValue( key, out bb ); + var diff = Diff( aa, bb ); + if( diff != null ) + ret.Add( key, diff ); + } + + if( ret.Count == 0 ) return null; + return ret; + } + + public static MiniYaml Diff( MiniYaml a, MiniYaml b ) + { + if( a == null && b == null ) + throw new InvalidOperationException( "can't happen" ); + else if( a == null ) + throw new NotImplementedException( "parent has key not in child" ); + else if( b == null ) + return a; + + var diff = Diff( a.Nodes, b.Nodes ); + if( diff == null && a.Value == b.Value ) + return null; + return new MiniYaml( a.Value, diff ); + } + } +} diff --git a/RulesConverter/Program.cs b/RulesConverter/Program.cs new file mode 100644 index 0000000000..a5eeebc252 --- /dev/null +++ b/RulesConverter/Program.cs @@ -0,0 +1,227 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.FileFormats; +using System.IO; +using IjwFramework.Types; + +namespace RulesConverter +{ + using PL = Dictionary; + + class Program + { + static void Main(string[] args) + { + FileSystem.Mount(new Folder("./")); + + var ruleStreams = args + .Where(a => a.EndsWith(".ini")) + .Select(a => FileSystem.Open(a)).ToArray(); + + var rules = new IniFile(ruleStreams); + + var outputFile = args.Single(a => !a.EndsWith(".ini")); + + var categoryMap = new Dictionary> + { + { "VehicleTypes", Pair.New( "DefaultVehicle", "Vehicle" ) }, + { "ShipTypes", Pair.New( "DefaultShip", "Ship" ) }, + { "PlaneTypes", Pair.New( "DefaultPlane", "Plane" ) }, + { "DefenseTypes", Pair.New( "DefaultDefense", "Defense" ) }, + { "BuildingTypes", Pair.New( "DefaultBuilding", "Building" ) }, + { "InfantryTypes", Pair.New( "DefaultInfantry", "Infantry" ) }, + }; + + var traitMap = new Dictionary + { + { "Unit", new PL { + { "HP", "Strength" }, + { "Armor", "Armor" }, + { "Crewed", "Crewed" }, + { "InitialFacing", "InitialFacing" }, + { "ROT", "ROT" }, + { "Sight", "Sight" }, + { "Speed", "Speed" }, + { "WaterBound", "WaterBound" } } + }, + + { "Selectable", new PL { + { "Priority", "SelectionPriority" }, + { "Voice", "Voice" }, + { "Bounds", "SelectionSize" } } + }, + + { "Mobile", new PL { + { "MovementType", "$MovementType" } } + }, + + { "RenderBuilding", new PL { + { "Image", "Image" } } + }, + + { "RenderUnitSpinner", new PL { + { "Image", "Image" }, + { "Offset", "PrimaryOffset" } } + }, + + { "RenderUnitRotor", new PL { + { "Image", "Image" }, + { "PrimaryOffset", "RotorOffset" }, + { "SecondaryOffset", "RotorOffset2" } } + }, + + { "Buildable", new PL { + { "TechLevel", "TechLevel" }, + { "Tab", "$Tab" }, + { "Prerequisites", "Prerequisite" }, + { "BuiltAt", "BuiltAt" }, + { "Owner", "Owner" }, + { "Cost", "Cost" }, + { "Icon", "Icon" }, + { "Description", "Description" }, + { "LongDesc", "LongDesc" }, + { "AlternateName", "AlternateName" } } + }, + + { "Cargo", new PL { + { "PassengerTypes", "PassengerTypes" }, + { "Passengers", "Passengers" }, + { "UnloadFacing", "UnloadFacing" } } + }, + + { "LimitedAmmo", new PL { + { "Ammo", "Ammo" } } + }, + + { "Building", new PL { + { "Power", "Power" }, + { "RequiresPower", "Powered" }, + { "Footprint", "Footprint" }, + { "Dimensions", "Dimensions" }, + { "Capturable", "Capturable" }, + { "Repairable", "Repairable" }, + { "BaseNormal", "BaseNormal" }, + { "Adjacent", "Adjacent" }, + { "Bib", "Bib" }, + { "HP", "Strength" }, + { "Armor", "Armor" }, + { "Crewed", "Crewed" }, + { "WaterBound", "WaterBound" }, + { "Sight", "Sight" }, + { "Unsellable", "Unsellable" } } + }, + + { "StoresOre", new PL { + { "Pips", "OrePips" }, + { "Capacity", "Storage" } } + }, + + { "Harvester", new PL { + { "Pips", "OrePips" } } + //{ "Capacity" + }, + + { "AttackBase", new PL { + { "PrimaryWeapon", "Primary" }, + { "SecondaryWeapon", "SecondaryWeapon" }, + { "PrimaryOffset", "PrimaryOffset" }, + { "SecondaryOffset", "SecondaryOffset" }, + { "PrimaryLocalOffset", "PrimaryLocalOffset" }, + { "SecondaryLocalOffset", "SecondaryLocalOffset" }, + { "MuzzleFlash", "MuzzleFlash" }, // maybe + { "Recoil", "Recoil"}, + { "FireDelay", "FireDelay" } } + }, + + { "Production", new PL { + { "SpawnOffset", "SpawnOffset" }, + { "Produces", "Produces" } } + }, + + { "Minelayer", new PL { + { "Mine", "Primary" } } + }, + + { "Turreted", new PL { + { "ROT", "ROT" }, + { "InitialFacing", "InitialFacing" } } + }, + }; + + traitMap["RenderUnit"] = traitMap["RenderBuilding"]; + traitMap["RenderBuildingCharge"] = traitMap["RenderBuilding"]; + traitMap["RenderBuildingOre"] = traitMap["RenderBuilding"]; + traitMap["RenderBuildingTurreted"] = traitMap["RenderBuilding"]; + traitMap["RenderInfantry"] = traitMap["RenderBuilding"]; + traitMap["RenderUnitMuzzleFlash"] = traitMap["RenderBuilding"]; + traitMap["RenderUnitReload"] = traitMap["RenderBuilding"]; + traitMap["RenderUnitTurreted"] = traitMap["RenderBuilding"]; + + traitMap["AttackTurreted"] = traitMap["AttackBase"]; + traitMap["AttackPlane"] = traitMap["AttackBase"]; + traitMap["AttackHeli"] = traitMap["AttackBase"]; + + using (var writer = File.CreateText(outputFile)) + { + foreach (var cat in categoryMap) + try + { + foreach (var item in rules.GetSection(cat.Key).Select(a => a.Key)) + { + var iniSection = rules.GetSection(item); + writer.WriteLine("{0}:", item); + writer.WriteLine("\tInherits: {0}", cat.Value.First); + + var traits = iniSection.GetValue("Traits", "") + .Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries).ToList(); + + if (iniSection.GetValue("Selectable", "yes") == "yes") + traits.Insert(0, "Selectable"); + + if (iniSection.GetValue("TechLevel", "-1") != "-1") + traits.Insert(0, "Buildable"); + + foreach (var t in traits) + { + writer.WriteLine("\t{0}:", t); + + if (traitMap.ContainsKey(t)) + foreach (var kv in traitMap[t]) + { + var v = iniSection.GetValue(kv.Value, ""); + if (kv.Value == "$Tab") v = cat.Value.Second; + if (kv.Value == "$MovementType") v = GetMovementType(iniSection, traits); + if (!string.IsNullOrEmpty(v)) writer.WriteLine("\t\t{0}: {1}", kv.Key, v); + } + } + + writer.WriteLine(); + } + } + catch { } + } + + var yaml = MiniYaml.FromFile( outputFile ); + if( File.Exists( "merge-" + outputFile ) ) + yaml = MiniYaml.Merge( MiniYaml.FromFile( "merge-" + outputFile ), yaml ); + yaml.OptimizeInherits( MiniYaml.FromFile( "defaults.yaml" ) ); + yaml.WriteToFile( outputFile ); + } + + static string GetMovementType(IniSection unit, List traits) + { + if (unit.GetValue("WaterBound", "no") == "yes") + return "Float"; + if (unit.GetValue("Tracked", "no") == "yes") + return "Track"; + if (traits.Contains("Plane") || traits.Contains("Helicopter")) + return "Fly"; + if (traits.Contains("RenderInfantry")) + return "Foot"; + + return "Wheel"; + } + } +} diff --git a/RulesConverter/Properties/AssemblyInfo.cs b/RulesConverter/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..3209d221c5 --- /dev/null +++ b/RulesConverter/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("RulesConverter")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("RulesConverter")] +[assembly: AssemblyCopyright("Copyright © 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6b0eb619-b53d-4b2a-bbfd-585fcab99b22")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/RulesConverter/RulesConverter.csproj b/RulesConverter/RulesConverter.csproj new file mode 100644 index 0000000000..4669eb6b9d --- /dev/null +++ b/RulesConverter/RulesConverter.csproj @@ -0,0 +1,75 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {BBE7C0D7-7529-4C34-9910-206866F204EF} + Exe + Properties + RulesConverter + RulesConverter + v3.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\Ijw.DirectX\Ijw.Framework\IjwFramework\bin\Release\IjwFramework.dll + + + + 3.5 + + + 3.5 + + + 3.5 + + + + + + + + + + + + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073} + OpenRa.DataStructures + + + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA} + OpenRa.FileFormats + + + + + \ No newline at end of file diff --git a/aftermath.yaml b/aftermath.yaml new file mode 100644 index 0000000000..96625aaf47 --- /dev/null +++ b/aftermath.yaml @@ -0,0 +1,162 @@ +STNK: + Inherits: DefaultVehicle + Unit: + HP: 200 + Armor: heavy + Sight: 5 + Speed: 10 + Mobile: + MovementType: Track + Turreted: + ROT: 5 + AttackTurreted: + PrimaryWeapon: APTusk + Recoil: 2 + RenderUnitTurreted: + Cloak: + +TTNK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 8 + Tab: Vehicle + Prerequisites: tsla + Owner: soviet + Cost: 1500 + Description: Tesla Tank + Unit: + HP: 110 + Armor: light + Crewed: yes + Sight: 7 + Speed: 8 + Mobile: + MovementType: Track + AttackBase: + PrimaryWeapon: TTankZap + RenderUnitSpinner: + +CTNK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 12 + Tab: Vehicle + Prerequisites: atek + Owner: allies + Cost: 2400 + Description: Chrono Tank + Unit: + HP: 350 + Armor: light + Sight: 5 + Speed: 5 + Mobile: + MovementType: Track + AttackBase: + PrimaryWeapon: APTusk + RenderUnit: + ChronoshiftDeploy: + +DTRK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 13 + Tab: Vehicle + Prerequisites: mslo + Owner: allies,soviet + Cost: 2400 + Description: Demo Truck + Unit: + HP: 110 + Armor: light + Sight: 3 + Speed: 8 + AttackBase: + PrimaryWeapon: Democharge + RenderUnit: + DemoTruck: + +QTNK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 10 + Tab: Vehicle + Prerequisites: stek + Owner: soviet + Cost: 2300 + Description: M.A.D. Tank + Unit: + HP: 300 + Armor: heavy + Crewed: no + Sight: 6 + Speed: 3 + Mobile: + MovementType: Track + RenderUnit: + +MSUB: + Inherits: DefaultShip + Buildable: + TechLevel: 9 + Tab: Ship + Prerequisites: stek + BuiltAt: spen + Owner: soviet + Cost: 1650 + Description: Missile Submarine + Unit: + HP: 150 + Armor: light + ROT: 7 + Sight: 6 + Speed: 5 + WaterBound: yes + AttackBase: + PrimaryWeapon: SubSCUD + FireDelay: 2 + RenderUnit: + Submarine: + Chronoshiftable: + +SHOK: + Inherits: DefaultInfantry + Buildable: + TechLevel: 7 + Tab: Infantry + Prerequisites: tsla + Owner: soviet + Cost: 900 + Description: Tesla Trooper + Selectable: + Voice: ShokVoice + Unit: + HP: 80 + Speed: 3 + AttackBase: + PrimaryWeapon: PortaTesla + TakeCover: + +MECH: + Inherits: DefaultInfantry + Buildable: + TechLevel: 7 + Tab: Infantry + Prerequisites: fix + Owner: allies + Cost: 950 + Description: Mechanic + LongDesc: Heals nearby vehicles.\n Strong vs Nothing\n Weak vs Everything + Selectable: + Voice: MechVoice + Bounds: 12,17,0,-9 + Unit: + HP: 60 + Sight: 3 + Speed: 4 + AutoHeal: + AttackBase: + PrimaryWeapon: GoodWrench + TakeCover: + SquishByTank: + diff --git a/aftermathUnits.ini b/aftermathUnits.ini index 9e07413c2c..7a9879ecb2 100755 --- a/aftermathUnits.ini +++ b/aftermathUnits.ini @@ -7,28 +7,28 @@ QTNK [STNK] Description=Stealth Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, Cloak, Chronoshiftable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, Cloak, Repairable, Chronoshiftable, Passenger, IronCurtainable Recoil=2 Voice=VehicleVoice [TTNK] Description=Tesla Tank -Traits=Unit, Mobile, AttackBase, RenderUnitSpinner, Chronoshiftable +Traits=Unit, Mobile, AttackBase, RenderUnitSpinner, Repairable, Chronoshiftable, Passenger, IronCurtainable Voice=VehicleVoice [CTNK] Description=Chrono Tank -Traits=Unit, Mobile, AttackBase, RenderUnit, ChronoshiftDeploy, Chronoshiftable +Traits=Unit, Mobile, AttackBase, RenderUnit, ChronoshiftDeploy, Repairable, Chronoshiftable, Passenger, IronCurtainable Voice=VehicleVoice [DTRK] Description=Demo Truck -Traits=Unit, Mobile, AttackBase, RenderUnit, DemoTruck +Traits=Unit, Mobile, AttackBase, RenderUnit, DemoTruck, Repairable, Chronoshiftable, Passenger, IronCurtainable Voice=VehicleVoice [QTNK] Description=M.A.D. Tank -Traits=Unit, Mobile, RenderUnit, Chronoshiftable +Traits=Unit, Mobile, RenderUnit, Repairable, Chronoshiftable, Passenger, IronCurtainable Voice=VehicleVoice @@ -102,4 +102,4 @@ Attack=jburn1,jcrisp1,jshock1,jlight1 [MechVoice] Select=mhowdy1,mhotdig1,mhuh1 Move=mlaff1,mhotdig1,mhear1,mboss1,myeehaw1 -Attack=mwrench1,mrise1,mboss1,myeehaw1 \ No newline at end of file +Attack=mwrench1,mrise1,mboss1,myeehaw1 diff --git a/aftrmath.ini b/aftrmath.ini index db4e05f689..670d9cc51a 100755 --- a/aftrmath.ini +++ b/aftrmath.ini @@ -119,6 +119,7 @@ Cost=1650 Points=45 ROT=7 Cloakable=yes +Inaccurate=no ; Shock Trooper [SHOK] @@ -134,6 +135,7 @@ Cost=900 Points=15 Explodes=no NoMovingFire=yes +Crushable=no ; field mechanic [MECH] @@ -457,7 +459,7 @@ Cost=200 Points=5 IsCanine=yes GuardRange=7 -SelfHealing=no +Selfhealing=no [CHAN] Strength=25 diff --git a/campaignUnits.ini b/campaignUnits.ini index 15d37bd3f7..13ae1b8008 100755 --- a/campaignUnits.ini +++ b/campaignUnits.ini @@ -238,4 +238,6 @@ SelectionPriority=0 TRUK [TRUK] -Traits=Unit, Mobile, RenderUnit \ No newline at end of file +Traits=Unit, Mobile, RenderUnit, Repairable, Chronoshiftable, Passenger, IronCurtainable +Voice=VehicleVoice + diff --git a/defaults.yaml b/defaults.yaml new file mode 100644 index 0000000000..48442b5d48 --- /dev/null +++ b/defaults.yaml @@ -0,0 +1,37 @@ +DefaultVehicle: + Unit: + ROT: 5 + Mobile: + MovementType: Wheel + Selectable: + Voice: VehicleVoice + Repairable: + Chronoshiftable: + Passenger: + IronCurtainable: + +DefaultInfantry: + Unit: + Armor: none + Sight: 4 + Mobile: + MovementType: Foot + Selectable: + RenderInfantry: + Passenger: + +DefaultShip: + Unit: + Mobile: + MovementType: Float + Selectable: + +DefaultPlane: + Unit: + Selectable: + +DefaultBuilding: + Selectable: + Priority: 3 + Building: + diff --git a/ra.yaml b/ra.yaml index c6e03e0b9b..78cfb50d3d 100644 --- a/ra.yaml +++ b/ra.yaml @@ -1,17 +1,2224 @@ -# -# Red Alert rules -# +V2RL: + Inherits: DefaultVehicle + Buildable: + TechLevel: 4 + Tab: Vehicle + Prerequisites: weap,dome + Owner: soviet + Cost: 700 + Description: V2 Rocket + LongDesc: Long-range rocket artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft + Unit: + HP: 150 + Armor: light + Crewed: yes + Sight: 5 + Speed: 7 + Mobile: + MovementType: Track + AttackBase: + PrimaryWeapon: SCUD + RenderUnitReload: + AutoTarget: + +1TNK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 4 + Tab: Vehicle + Prerequisites: weap + Owner: allies + Cost: 700 + Description: Light Tank + LongDesc: Light Tank, good for scouting.\n Strong vs Light Vehicles\n Weak vs Tanks, Aircraft + Unit: + HP: 300 + Armor: heavy + Crewed: yes + Sight: 4 + Speed: 9 + Mobile: + MovementType: Track + Turreted: + ROT: 5 + AttackTurreted: + PrimaryWeapon: 75mm + Recoil: 2 + RenderUnitTurreted: + AutoTarget: + +2TNK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 6 + Tab: Vehicle + Prerequisites: weap + Owner: allies + Cost: 800 + Description: Medium Tank + LongDesc: Allied Main Battle Tank.\n Strong vs Tanks, Light Vehicles\n Weak vs Infantry, Aircraft + Unit: + HP: 400 + Armor: heavy + Crewed: yes + Sight: 5 + Speed: 8 + Mobile: + MovementType: Track + Turreted: + ROT: 5 + AttackTurreted: + PrimaryWeapon: 90mm + Recoil: 3 + RenderUnitTurreted: + AutoTarget: + +3TNK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 4 + Tab: Vehicle + Prerequisites: weap + Owner: soviet + Cost: 950 + Description: Heavy Tank + LongDesc: Soviet Main Battle Tank, with dual cannons\n Strong vs Tanks, Light Vehicles\n Weak vs Infantry, Aircraft + Unit: + HP: 400 + Armor: heavy + Crewed: yes + Sight: 5 + Speed: 7 + Mobile: + MovementType: Track + Turreted: + ROT: 5 + AttackTurreted: + PrimaryWeapon: 105mm + Recoil: 3 + RenderUnitTurreted: + AutoTarget: + +4TNK: + Inherits: DefaultVehicle + Buildable: + TechLevel: 10 + Tab: Vehicle + Prerequisites: weap,stek + Owner: soviet + Cost: 1700 + Description: Mammoth Tank + LongDesc: Big and slow tank, with anti-air capability.\n Strong vs Tanks, Aircraft\n Weak vs Infantry + Unit: + HP: 600 + Armor: heavy + Crewed: yes + Sight: 6 + Speed: 4 + Mobile: + MovementType: Track + Turreted: + ROT: 5 + AttackTurreted: + PrimaryWeapon: 120mm + PrimaryLocalOffset: -4,-5,0,4,-5,0 + SecondaryLocalOffset: -7,2,25,7,2,-25 + Recoil: 4 + RenderUnitTurreted: + AutoTarget: + +MRJ: + Inherits: DefaultVehicle + Buildable: + TechLevel: 12 + Tab: Vehicle + Prerequisites: weap,dome + Owner: allies + Cost: 600 + Description: Radar Jammer + LongDesc: Hides nearby units on the enemy's minimap.\n Unarmed + Selectable: + Priority: 3 + Unit: + HP: 110 + Armor: light + Crewed: yes + Sight: 7 + Speed: 9 + Mobile: + MovementType: Track + RenderUnitSpinner: + Offset: 0,4,0,-6 + +MGG: + Inherits: DefaultVehicle + Buildable: + TechLevel: 11 + Tab: Vehicle + Prerequisites: weap,atek + Owner: allies + Cost: 600 + Description: Mobile Gap Generator + LongDesc: Regenerates Fog of War in a small area \naround the unit.\n Unarmed + Selectable: + Priority: 3 + Unit: + HP: 110 + Armor: light + Crewed: yes + Sight: 4 + Speed: 9 + RenderUnitSpinner: + Offset: 0,6,0,-3 + +ARTY: + Inherits: DefaultVehicle + Buildable: + TechLevel: 8 + Tab: Vehicle + Prerequisites: weap + Owner: allies + Cost: 600 + Description: Artillery + LongDesc: Long-range artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft + Unit: + HP: 75 + Armor: light + Crewed: yes + ROT: 2 + Sight: 5 + Speed: 6 + Mobile: + MovementType: Track + AttackBase: + PrimaryWeapon: 155mm + RenderUnit: + Explodes: + AutoTarget: + +HARV: + Inherits: DefaultVehicle + Buildable: + TechLevel: 1 + Tab: Vehicle + Prerequisites: weap,proc + Owner: allies,soviet + Cost: 1400 + Description: Ore Truck + LongDesc: Collects Ore and Gems for processing.\n Unarmed + Selectable: + Priority: 7 + Harvester: + Unit: + HP: 600 + Armor: heavy + Crewed: yes + Sight: 4 + Speed: 6 + Mobile: + MovementType: Track + RenderUnit: + +MCV: + Inherits: DefaultVehicle + Buildable: + TechLevel: 11 + Tab: Vehicle + Prerequisites: weap,fix + Owner: allies,soviet + Cost: 2500 + Description: Mobile Construction Vehicle + LongDesc: Deploys into another Construction Yard.\n Unarmed + Selectable: + Priority: 3 + Unit: + HP: 600 + Armor: light + Crewed: yes + Sight: 4 + Speed: 6 + McvDeploy: + RenderUnit: + +JEEP: + Inherits: DefaultVehicle + Buildable: + TechLevel: 3 + Tab: Vehicle + Prerequisites: weap + Owner: allies + Cost: 600 + Description: Ranger + LongDesc: Fast scout & anti-infantry vehicle.\n Strong vs Infantry\n Weak vs Tanks, Aircraft + Unit: + HP: 150 + Armor: light + Crewed: yes + ROT: 10 + Sight: 6 + Speed: 10 + Turreted: + ROT: 10 + AttackTurreted: + PrimaryWeapon: M60mg + PrimaryOffset: 0,0,0,-2 + MuzzleFlash: yes + RenderUnitTurreted: + AutoTarget: + +APC: + Inherits: DefaultVehicle + Buildable: + TechLevel: 5 + Tab: Vehicle + Prerequisites: weap,tent + Owner: allies + Cost: 800 + Description: Armored Personnel Carrier + LongDesc: Tough infantry transport.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft + Unit: + HP: 200 + Armor: heavy + Sight: 5 + Speed: 10 + Mobile: + MovementType: Track + AttackBase: + PrimaryWeapon: M60mg + PrimaryOffset: 0,0,0,-4 + MuzzleFlash: yes + RenderUnitMuzzleFlash: + AutoTarget: + Cargo: + PassengerTypes: Foot + Passengers: 5 + UnloadFacing: 220 + +MNLY.AP: + Inherits: DefaultVehicle + Buildable: + TechLevel: 3 + Tab: Vehicle + Prerequisites: weap,fix + Owner: soviet + Cost: 800 + Icon: MNLYICON + Description: Minelayer (Anti-Personnel) + LongDesc: Lays mines to destroy unwary enemy units.\n Unarmed + Unit: + HP: 100 + Armor: heavy + Crewed: yes + Sight: 5 + Speed: 9 + Mobile: + MovementType: Track + RenderUnit: + Image: MNLY + Minelayer: + Mine: MINP + MineImmune: + LimitedAmmo: + Ammo: 5 + +MNLY.AT: + Inherits: DefaultVehicle + Buildable: + TechLevel: 3 + Tab: Vehicle + Prerequisites: weap,fix + Owner: allies + Cost: 800 + Icon: MNLYICON + Description: Minelayer (Anti-Tank) + LongDesc: Lays mines to destroy unwary enemy units.\n Unarmed + Unit: + HP: 100 + Armor: heavy + Crewed: yes + Sight: 5 + Speed: 9 + Mobile: + MovementType: Track + RenderUnit: + Image: MNLY + Minelayer: + Mine: MINV + MineImmune: + LimitedAmmo: + Ammo: 5 + +TRUK: + Inherits: DefaultVehicle + Unit: + HP: 110 + Armor: light + Sight: 3 + Speed: 10 + RenderUnit: + +SS: + Inherits: DefaultShip + Buildable: + TechLevel: 5 + Tab: Ship + Prerequisites: spen + BuiltAt: spen + Owner: soviet + Cost: 950 + Description: Submarine + LongDesc: Submerged anti-ship unit armed with \ntorpedoes.\n Strong vs Ships\n Weak vs Everything\n Special Ability: Submerge + Unit: + HP: 120 + Armor: light + ROT: 7 + Sight: 6 + Speed: 6 + WaterBound: yes + RenderUnit: + Submarine: + AttackBase: + PrimaryWeapon: TorpTube + FireDelay: 2 + Chronoshiftable: + IronCurtainable: + +DD: + Inherits: DefaultShip + Buildable: + TechLevel: 7 + Tab: Ship + Prerequisites: syrd + BuiltAt: syrd + Owner: allies + Cost: 1000 + Description: Destroyer + LongDesc: Fast multi-role ship. \n Strong vs Submarines, Aircraft\n Weak vs Infantry, Tanks + Unit: + HP: 400 + Armor: heavy + ROT: 7 + Sight: 6 + Speed: 6 + WaterBound: yes + Turreted: + ROT: 7 + AttackTurreted: + PrimaryWeapon: Stinger + PrimaryOffset: 0,-8,0,-3 + RenderUnitTurreted: + AutoTarget: + Chronoshiftable: + IronCurtainable: + +CA: + Inherits: DefaultShip + Buildable: + TechLevel: 10 + Tab: Ship + Prerequisites: syrd,atek + BuiltAt: syrd + Owner: allies + Cost: 2000 + Description: Cruiser + LongDesc: Very slow long-range ship. \n Strong vs Buildings\n Weak vs Ships, Submarines + Unit: + HP: 700 + Armor: heavy + ROT: 5 + Sight: 7 + Speed: 4 + WaterBound: yes + Turreted: + ROT: 5 + AttackTurreted: + PrimaryWeapon: 8Inch + PrimaryOffset: 0,17,0,-2 + SecondaryOffset: 0,-17,0,-2 + Recoil: 3 + RenderUnitTurreted: + AutoTarget: + Chronoshiftable: + IronCurtainable: + +LST: + Inherits: DefaultShip + Buildable: + TechLevel: 3 + Tab: Ship + Owner: allies,soviet + Cost: 700 + Description: Transport + LongDesc: General-purpose naval transport.\nCan carry infantry and tanks.\n Unarmed + Unit: + HP: 350 + Armor: heavy + ROT: 10 + Sight: 6 + Speed: 14 + WaterBound: yes + RenderUnit: + Cargo: + PassengerTypes: Foot,Wheel,Track + Passengers: 5 + IronCurtainable: + +PT: + Inherits: DefaultShip + Buildable: + TechLevel: 5 + Tab: Ship + Prerequisites: syrd + BuiltAt: syrd + Owner: allies + Cost: 500 + Description: Gunboat + LongDesc: Light scout & support ship. \n Strong vs Ships, Submarines\n Weak vs Aircraft + Unit: + HP: 200 + Armor: heavy + ROT: 7 + Sight: 7 + Speed: 9 + WaterBound: yes + Turreted: + ROT: 7 + AttackTurreted: + PrimaryWeapon: 2Inch + PrimaryOffset: 0,-6,0,-1 + RenderUnitTurreted: + AutoTarget: + Chronoshiftable: + IronCurtainable: + +MIG: + Inherits: DefaultPlane + Buildable: + TechLevel: 10 + Tab: Plane + Prerequisites: afld + BuiltAt: afld + Owner: soviet + Cost: 1200 + Description: Mig Attack Plane + LongDesc: Fast Ground-Attack Plane.\n Strong vs Buildings\n Weak vs Infantry, Light Vehicles + Unit: + HP: 50 + Armor: light + InitialFacing: 192 + ROT: 5 + Sight: 0 + Speed: 20 + AttackPlane: + PrimaryWeapon: Maverick + Plane: + RenderUnit: + WithShadow: + LimitedAmmo: + Ammo: 3 + IronCurtainable: + +YAK: + Inherits: DefaultPlane + Buildable: + TechLevel: 5 + Tab: Plane + Prerequisites: afld + BuiltAt: afld + Owner: soviet + Cost: 800 + Description: Yak Attack Plane + LongDesc: Anti-Tanks & Anti-Infantry Plane.\n Strong vs Infantry, Tanks\n Weak vs Buildings + Unit: + HP: 60 + Armor: light + Crewed: yes + InitialFacing: 192 + ROT: 5 + Sight: 0 + Speed: 16 + AttackPlane: + PrimaryWeapon: ChainGun + Plane: + RenderUnit: + WithShadow: + LimitedAmmo: + Ammo: 15 + IronCurtainable: + +TRAN: + Inherits: DefaultPlane + Buildable: + TechLevel: 11 + Tab: Plane + Prerequisites: hpad + BuiltAt: hpad + Owner: allies + Cost: 1200 + Description: Transport Helicopter + LongDesc: Fast Infantry Transport Helicopter.\n Unarmed + Unit: + HP: 90 + Armor: light + InitialFacing: 20 + ROT: 5 + Sight: 0 + Speed: 12 + Helicopter: + RenderUnitRotor: + PrimaryOffset: 0,14,0,-4 + SecondaryOffset: 0,-14,0,-2 + WithShadow: + Cargo: + PassengerTypes: Foot + Passengers: 5 + IronCurtainable: + +HELI: + Inherits: DefaultPlane + Buildable: + TechLevel: 9 + Tab: Plane + Prerequisites: hpad + BuiltAt: hpad + Owner: allies + Cost: 1200 + Description: Longbow + LongDesc: Helicopter Gunship with AG Missiles.\n Strong vs Buildings, Tanks\n Weak vs Infantry + Unit: + HP: 225 + Armor: heavy + Crewed: yes + InitialFacing: 20 + ROT: 4 + Sight: 0 + Speed: 16 + AttackHeli: + PrimaryWeapon: Hellfire + PrimaryOffset: -5,0,0,2 + SecondaryOffset: 5,0,0,2 + Helicopter: + RenderUnitRotor: + PrimaryOffset: 0,0,0,-2 + WithShadow: + LimitedAmmo: + Ammo: 6 + IronCurtainable: + +HIND: + Inherits: DefaultPlane + Buildable: + TechLevel: 9 + Tab: Plane + Prerequisites: hpad + BuiltAt: hpad + Owner: allies + Cost: 1200 + Description: Hind + LongDesc: Helicopter Gunship with Chainguns.\n Strong vs Infantry, Light Vehicles.\n Weak vs Tanks + Unit: + HP: 225 + Armor: heavy + Crewed: yes + InitialFacing: 20 + ROT: 4 + Sight: 0 + Speed: 12 + AttackHeli: + PrimaryWeapon: ChainGun + PrimaryOffset: -5,0,0,2 + SecondaryOffset: 5,0,0,2 + Helicopter: + RenderUnitRotor: + WithShadow: + LimitedAmmo: + Ammo: 12 + IronCurtainable: + +IRON: + Inherits: DefaultDefense + Buildable: + TechLevel: 12 + Tab: Defense + Prerequisites: stek + Owner: soviet + Cost: 2800 + Description: Iron Curtain + LongDesc: Makes a group of units invulnerable for a \nshort time.\n Special Ability: Invulnerability + Selectable: + Priority: 3 + Building: + Power: -200 + RequiresPower: true + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + HP: 400 + Armor: wood + Crewed: yes + Sight: 10 + RenderBuilding: + IronCurtainable: + IronCurtain: + +PDOX: + Inherits: DefaultDefense + Buildable: + TechLevel: 12 + Tab: Defense + Prerequisites: atek + Owner: allies + Cost: 2800 + Description: Chronosphere + LongDesc: Teleports a unit from one place \nto another, for a limited time.\n Special Ability: Chronoshift + Selectable: + Priority: 3 + Building: + Power: -200 + RequiresPower: true + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + HP: 400 + Armor: wood + Crewed: yes + Sight: 10 + RenderBuilding: + Chronosphere: + IronCurtainable: + +PBOX: + Inherits: DefaultDefense + Buildable: + TechLevel: 2 + Tab: Defense + Prerequisites: tent + Owner: allies + Cost: 400 + Description: Pillbox + LongDesc: Basic defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft + Selectable: + Priority: 3 + Building: + Power: -15 + Footprint: x + Dimensions: 1,1 + HP: 400 + Armor: wood + Crewed: yes + Sight: 5 + Turreted: + RenderBuilding: + AttackTurreted: + PrimaryWeapon: Vulcan + AutoTarget: + IronCurtainable: + +HBOX: + Inherits: DefaultDefense + Buildable: + TechLevel: 3 + Tab: Defense + Prerequisites: tent + Owner: allies + Cost: 600 + Description: Camo Pillbox + LongDesc: Hidden defensive structure.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft + Selectable: + Priority: 3 + Building: + Power: -15 + Footprint: x + Dimensions: 1,1 + HP: 600 + Armor: wood + Crewed: yes + Sight: 5 + Turreted: + RenderBuilding: + AttackTurreted: + PrimaryWeapon: Vulcan + AutoTarget: + IronCurtainable: + +TSLA: + Inherits: DefaultDefense + Buildable: + TechLevel: 7 + Tab: Defense + Prerequisites: weap + Owner: soviet + Cost: 1500 + Description: Tesla Coil + LongDesc: Advanced base defense. Requires power\nto operate.\n Strong vs Tanks, Infantry\n Weak vs Aircraft + Selectable: + Priority: 3 + Building: + Power: -150 + RequiresPower: true + Footprint: _ x + Dimensions: 1,2 + HP: 400 + Armor: heavy + Crewed: yes + Sight: 8 + Turreted: + RenderBuildingCharge: + AttackTurreted: + PrimaryWeapon: TeslaZap + FireDelay: 8 + AutoTarget: + IronCurtainable: + +GUN: + Inherits: DefaultDefense + Buildable: + TechLevel: 4 + Tab: Defense + Prerequisites: tent + Owner: allies + Cost: 600 + Description: Turret + LongDesc: Anti-Armor base defense.\n Strong vs Tanks\n Weak vs Infantry, Aircraft + Selectable: + Priority: 3 + Building: + Power: -40 + Footprint: x + Dimensions: 1,1 + HP: 400 + Armor: heavy + Crewed: yes + Sight: 6 + Turreted: + ROT: 12 + InitialFacing: 50 + RenderBuildingTurreted: + AttackTurreted: + PrimaryWeapon: TurretGun + AutoTarget: + IronCurtainable: + +AGUN: + Inherits: DefaultDefense + Buildable: + TechLevel: 5 + Tab: Defense + Prerequisites: dome + Owner: allies + Cost: 600 + Description: AA Gun + LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks + Selectable: + Priority: 3 + Building: + Power: -50 + RequiresPower: true + Footprint: _ x + Dimensions: 1,2 + HP: 400 + Armor: heavy + Crewed: yes + Sight: 6 + Turreted: + ROT: 15 + InitialFacing: 224 + RenderBuildingTurreted: + AttackTurreted: + PrimaryWeapon: ZSU-23 + AutoTarget: + IronCurtainable: + +FTUR: + Inherits: DefaultDefense + Buildable: + TechLevel: 2 + Tab: Defense + Prerequisites: barr + Owner: soviet + Cost: 600 + Description: Flame Turret + LongDesc: Anti-Infantry base defense.\n Strong vs Infantry\n Weak vs Aircraft + Selectable: + Priority: 3 + Turreted: + Building: + Power: -20 + Footprint: x + Dimensions: 1,1 + HP: 400 + Armor: heavy + Crewed: yes + Sight: 6 + RenderBuilding: + AttackTurreted: + PrimaryWeapon: FireballLauncher + AutoTarget: + IronCurtainable: + +GAP: + Inherits: DefaultDefense + Buildable: + TechLevel: 10 + Tab: Defense + Prerequisites: atek + Owner: allies + Cost: 500 + Description: Gap Generator + LongDesc: Regenerates the Fog of War nearby, \nobscuring the area.\n Unarmed + Selectable: + Priority: 3 + Building: + Power: -60 + RequiresPower: true + Footprint: _ x + Dimensions: 1,2 + Capturable: true + HP: 1000 + Armor: wood + Crewed: yes + Sight: 10 + RenderBuilding: + IronCurtainable: + +SAM: + Inherits: DefaultDefense + Buildable: + TechLevel: 9 + Tab: Defense + Prerequisites: dome + Owner: soviet + Cost: 750 + Description: SAM Site + LongDesc: Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks + Selectable: + Priority: 3 + Building: + Power: -20 + Footprint: xx + Dimensions: 2,1 + HP: 400 + Armor: heavy + Crewed: yes + Sight: 5 + Turreted: + ROT: 30 + RenderBuildingTurreted: + AttackTurreted: + PrimaryWeapon: Nike + AutoTarget: + IronCurtainable: + +MSLO: + Inherits: DefaultDefense + Buildable: + TechLevel: 13 + Tab: Defense + Prerequisites: @Tech Center + Owner: soviet,allies + Cost: 2500 + Description: Missile Silo + LongDesc: Launches a devastating nuclear strike.\n Strong vs Infantry, Buildings\n Weak vs Tanks\n Special Ability: Nuclear Missile + Selectable: + Priority: 3 + Building: + Power: -100 + Footprint: xx + Dimensions: 2,1 + HP: 400 + Armor: heavy + Crewed: yes + Sight: 5 + RenderBuilding: + IronCurtainable: + +ATEK: + Inherits: DefaultBuilding + Buildable: + TechLevel: 10 + Tab: Building + Prerequisites: weap,dome + Owner: allies + Cost: 1500 + Description: Allied Tech Center + LongDesc: Provides Allied advanced technologies.\n Special Ability: GPS Satellite + AlternateName: @Tech Center + Building: + Power: -200 + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Bib: yes + HP: 400 + Armor: wood + Crewed: yes + Sight: 10 + RenderBuilding: + IronCurtainable: + GpsLaunchSite: + +WEAP: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: proc + Owner: soviet,allies + Cost: 2000 + Description: War Factory + LongDesc: Produces tanks & light vehicles. + Building: + Power: -30 + Footprint: xxx xxx + Dimensions: 3,2 + Capturable: true + Bib: yes + HP: 1000 + Armor: light + Crewed: yes + Sight: 4 + RenderBuilding: + RenderWarFactory: + RallyPoint: + Production: + Produces: Vehicle + IronCurtainable: + +SYRD: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: powr + Owner: allies + Cost: 650 + Description: Shipyard + LongDesc: Produces and repairs ships + Building: + Power: -30 + Footprint: xxx xxx xxx + Dimensions: 3,3 + Capturable: true + BaseNormal: no + Adjacent: 8 + HP: 1000 + Armor: light + WaterBound: yes + Sight: 4 + RenderBuilding: + ProductionSurround: + IronCurtainable: + +SPEN: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: powr + Owner: soviet + Cost: 650 + Description: Sub Pen + LongDesc: Produces and repairs submarines and \ntransports + Building: + Power: -30 + Footprint: xxx xxx xxx + Dimensions: 3,3 + Capturable: true + BaseNormal: no + Adjacent: 8 + HP: 1000 + Armor: light + WaterBound: yes + Sight: 4 + RenderBuilding: + ProductionSurround: + IronCurtainable: + +FACT: + Inherits: DefaultBuilding + Building: + Power: 0 + Footprint: xxx xxx xxx + Dimensions: 3,3 + Capturable: true + Bib: yes + HP: 1000 + Armor: heavy + Crewed: yes + Sight: 5 + RenderBuilding: + Production: + Produces: Building,Defense + ConstructionYard: + IronCurtainable: + +PROC: + Inherits: DefaultBuilding + Buildable: + TechLevel: 1 + Tab: Building + Prerequisites: powr + Owner: allies,soviet + Cost: 2000 + Description: Ore Refinery + LongDesc: Converts Ore and Gems into money + Building: + Power: -30 + Footprint: _x_ xxx x== + Dimensions: 3,3 + Capturable: true + Bib: yes + HP: 900 + Armor: wood + Crewed: yes + Sight: 6 + RenderBuilding: + AcceptsOre: + StoresOre: + Pips: 17 + Capacity: 2000 + IronCurtainable: + +SILO: + Inherits: DefaultBuilding + Buildable: + TechLevel: 1 + Tab: Building + Prerequisites: proc + Owner: allies,soviet + Cost: 150 + Description: Silo + LongDesc: Stores excess harvested Ore + Building: + Power: -10 + Footprint: x + Dimensions: 1,1 + Capturable: true + HP: 300 + Armor: wood + Sight: 4 + RenderBuildingOre: + StoresOre: + Pips: 5 + Capacity: 1500 + IronCurtainable: + +HPAD: + Inherits: DefaultBuilding + Buildable: + TechLevel: 9 + Tab: Building + Prerequisites: dome + Owner: allies + Cost: 1500 + Description: Helipad + LongDesc: Produces and reloads helicopters + Building: + Power: -10 + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Bib: yes + HP: 800 + Armor: wood + Crewed: yes + Sight: 5 + RenderBuilding: + Production: + SpawnOffset: 0,-4 + Produces: Plane + BelowUnits: + Reservable: + IronCurtainable: + +DOME: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: proc + Owner: allies,soviet + Cost: 1000 + Description: Radar Dome + LongDesc: Provides an overview of the battlefield.\n Requires power to operate. + Building: + Power: -40 + RequiresPower: true + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Bib: yes + HP: 1000 + Armor: wood + Crewed: yes + Sight: 10 + RenderBuilding: + ProvidesRadar: + IronCurtainable: + +AFLD: + Inherits: DefaultBuilding + Buildable: + TechLevel: 5 + Tab: Building + Prerequisites: dome + Owner: soviet + Cost: 600 + Description: Airstrip + LongDesc: Produces and reloads planes\n Special Ability: Paratroopers\n Special Ability: Spy Plane + Building: + Power: -30 + Footprint: xxx xxx + Dimensions: 3,2 + Capturable: true + HP: 1000 + Armor: heavy + Crewed: yes + Sight: 7 + RenderBuilding: + Production: + Produces: Plane + BelowUnits: + Reservable: + IronCurtainable: + +POWR: + Inherits: DefaultBuilding + Buildable: + TechLevel: 1 + Tab: Building + Owner: allies,soviet + Cost: 300 + Description: Power Plant + LongDesc: Provides power for other structures + Building: + Power: 100 + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Bib: yes + HP: 400 + Armor: wood + Crewed: yes + Sight: 4 + RenderBuilding: + IronCurtainable: + +APWR: + Inherits: DefaultBuilding + Buildable: + TechLevel: 8 + Tab: Building + Prerequisites: powr + Owner: allies,soviet + Cost: 500 + Description: Advanced Power Plant + LongDesc: Provides more power, cheaper than the \nstandard Power Plant + Building: + Power: 200 + Footprint: ___ xxx xxx + Dimensions: 3,3 + Capturable: true + Bib: yes + HP: 700 + Armor: wood + Crewed: yes + Sight: 4 + RenderBuilding: + IronCurtainable: + +STEK: + Inherits: DefaultBuilding + Buildable: + TechLevel: 6 + Tab: Building + Prerequisites: weap,dome + Owner: soviet + Cost: 1500 + Description: Soviet Tech Center + LongDesc: Provides Soviet advanced technologies + AlternateName: @Tech Center + Building: + Power: -100 + Footprint: xxx xxx + Dimensions: 3,2 + Capturable: true + Bib: yes + HP: 600 + Armor: wood + Crewed: yes + Sight: 4 + RenderBuilding: + IronCurtainable: + +BARR: + Inherits: DefaultBuilding + Buildable: + TechLevel: 1 + Tab: Building + Prerequisites: powr + Owner: soviet + Cost: 300 + Description: Soviet Barracks + LongDesc: Produces infantry + Building: + Power: -20 + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Bib: yes + HP: 800 + Armor: wood + Crewed: yes + Sight: 5 + RenderBuilding: + RallyPoint: + Production: + Produces: Infantry + IronCurtainable: + +TENT: + Inherits: DefaultBuilding + Buildable: + TechLevel: 1 + Tab: Building + Prerequisites: powr + Owner: allies + Cost: 300 + Description: Allied Barracks + LongDesc: Produces infantry + Building: + Power: -20 + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Bib: yes + HP: 800 + Armor: wood + Crewed: yes + Sight: 5 + RenderBuilding: + RallyPoint: + Production: + Produces: Infantry + IronCurtainable: + +KENN: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: barr + Owner: soviet + Cost: 200 + Description: Kennel + LongDesc: Produces attack dogs + Building: + Power: -10 + Footprint: x + Dimensions: 1,1 + HP: 400 + Armor: wood + Sight: 4 + RenderBuilding: + RallyPoint: + Production: + IronCurtainable: + +FIX: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: weap + Owner: allies,soviet + Cost: 1200 + Description: Service Depot + LongDesc: Repairs vehicles, reloads minelayers, and \nallows the construction of additional bases. + Building: + Power: -30 + Footprint: _x_ xxx _x_ + Dimensions: 3,3 + Capturable: true + HP: 800 + Armor: wood + Crewed: yes + Sight: 5 + RenderBuilding: + BelowUnits: + Reservable: + IronCurtainable: + +FACF: + Inherits: DefaultBuilding + Buildable: + TechLevel: 1 + Tab: Building + Owner: allies + Cost: 50 + Description: Fake Construction Yard + LongDesc: Looks like a Construction Yard. + Building: + Power: -2 + Footprint: xxx xxx xxx + Dimensions: 3,3 + Capturable: true + BaseNormal: no + Bib: yes + HP: 30 + Sight: 4 + RenderBuilding: + Image: FACT + Fake: + IronCurtainable: + +WEAF: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: proc + Owner: allies + Cost: 50 + Description: Fake War Factory + LongDesc: Looks like a War Factory. + Building: + Power: -2 + Footprint: xxx xxx + Dimensions: 3,2 + Capturable: true + BaseNormal: no + Bib: yes + HP: 30 + Sight: 4 + RenderWarFactory: + RenderBuilding: + Image: WEAP + Fake: + IronCurtainable: + +SYRF: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: powr + Owner: allies + Cost: 50 + Description: Fake Shipyard + LongDesc: Looks like a Shipyard + Building: + Power: -2 + Footprint: xxx xxx xxx + Dimensions: 3,3 + Capturable: true + BaseNormal: no + Adjacent: 8 + HP: 30 + WaterBound: yes + Sight: 4 + RenderBuilding: + Image: SYRD + Fake: + +SPEF: + Inherits: DefaultBuilding + Building: + Power: -2 + Footprint: xxx xxx xxx + Dimensions: 3,3 + Capturable: true + BaseNormal: no + Adjacent: 8 + HP: 30 + WaterBound: yes + Sight: 4 + RenderBuilding: + Image: SPEN + Fake: + +DOMF: + Inherits: DefaultBuilding + Buildable: + TechLevel: 3 + Tab: Building + Prerequisites: proc + Owner: allies + Cost: 50 + Description: Fake Radar Dome + LongDesc: Looks like a Radar Dome + Building: + Power: -2 + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + BaseNormal: no + Bib: yes + HP: 30 + Sight: 4 + RenderBuilding: + Image: DOME + Fake: + +MINP: + Unit: + HP: 1 + RenderUnit: + APMine: + BelowUnits: + InvisibleToOthers: + +MINV: + Unit: + HP: 1 + RenderUnit: + ATMine: + BelowUnits: + InvisibleToOthers: + +T01: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +T02: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +T03: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +T05: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +T06: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +T07: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +T08: + Building: + Footprint: x_ + Dimensions: 2,1 + RenderBuilding: + +T10: + Building: + Footprint: xx xx + Dimensions: 2,2 + RenderBuilding: + +T11: + Building: + Footprint: xx xx + Dimensions: 2,2 + RenderBuilding: + +T12: + Building: + Footprint: xx xx + Dimensions: 2,2 + RenderBuilding: + +T13: + Building: + Footprint: xx xx + Dimensions: 2,2 + RenderBuilding: + +T14: + Building: + Footprint: xx xx + Dimensions: 2,2 + RenderBuilding: + +T15: + Building: + Footprint: xx xx + Dimensions: 2,2 + RenderBuilding: + +T16: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +T17: + Building: + Footprint: x_ x_ + Dimensions: 2,2 + RenderBuilding: + +TC01: + Building: + Footprint: xx_ xx_ + Dimensions: 3,2 + RenderBuilding: + +TC02: + Building: + Footprint: xx_ xx_ + Dimensions: 3,2 + RenderBuilding: + +TC03: + Building: + Footprint: xx_ xx_ + Dimensions: 3,2 + RenderBuilding: + +TC04: + Building: + Footprint: xxx_ xxx_ xxx_ + Dimensions: 4,3 + RenderBuilding: + +TC05: + Building: + Footprint: xxx_ xxx_ xxx_ + Dimensions: 4,3 + RenderBuilding: + +MINE: + Building: + Footprint: x + Dimensions: 1,1 + RenderBuilding: + SeedsOre: + +FCOM: + Inherits: DefaultBuilding + Building: + Power: -200 + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Bib: yes + HP: 400 + Armor: wood + Crewed: yes + Sight: 10 + RenderBuilding: + +V01: + Inherits: DefaultBuilding + Building: + Footprint: xx xx + Dimensions: 2,2 + Capturable: true + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V02: + Inherits: DefaultBuilding + Building: + Footprint: xx xx + Dimensions: 2,2 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V03: + Inherits: DefaultBuilding + Building: + Footprint: xx xx + Dimensions: 2,2 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V04: + Inherits: DefaultBuilding + Building: + Footprint: xx xx + Dimensions: 2,2 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V05: + Inherits: DefaultBuilding + Building: + Footprint: xx + Dimensions: 2,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V06: + Inherits: DefaultBuilding + Building: + Footprint: xx + Dimensions: 2,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V07: + Inherits: DefaultBuilding + Building: + Footprint: xx + Dimensions: 2,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V08: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V09: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V10: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V11: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V12: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V13: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V14: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V15: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V16: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V17: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V18: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V19: + Inherits: DefaultBuilding + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + +V20: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V21: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V22: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V23: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V24: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V25: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V26: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V27: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V28: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V29: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V30: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V31: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V32: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V33: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V34: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V35: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V36: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +V37: + Inherits: DefaultBuilding + Building: + Repairable: false + HP: 400 + Armor: wood + RenderBuilding: + Image: FCOM + +BARL: + Inherits: DefaultBuilding + Selectable: + Priority: 0 + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + BaseNormal: no + Adjacent: 0 + HP: 10 + RenderBuilding: + Explodes: + +BRL3: + Inherits: DefaultBuilding + Selectable: + Priority: 0 + Building: + Footprint: x + Dimensions: 1,1 + Repairable: false + BaseNormal: no + Adjacent: 0 + HP: 10 + RenderBuilding: + Explodes: + +MISS: + Inherits: DefaultBuilding + Selectable: + Priority: 0 + Building: + Footprint: xxx xxx + Dimensions: 3,2 + Capturable: true + Bib: yes + HP: 400 + Armor: wood + RenderBuilding: + +DOG: + Inherits: DefaultInfantry + Buildable: + TechLevel: 3 + Tab: Infantry + Prerequisites: kenn + BuiltAt: KENN + Owner: soviet + Cost: 200 + Description: Attack Dog + LongDesc: Anti-infantry unit. Not fooled by the \nSpy's disguise.\n Strong vs Infantry\n Weak vs Vehicles + Selectable: + Voice: DogVoice + Bounds: 12,17,-1,-4 + Unit: + HP: 12 + Sight: 5 + Speed: 4 + +E1: + Inherits: DefaultInfantry + Buildable: + TechLevel: 1 + Tab: Infantry + Owner: allies,soviet + Cost: 100 + Description: Rifle Infantry + LongDesc: General-purpose infantry. Strong vs Infantry\n Weak vs Vehicles + Selectable: + Bounds: 12,17,0,-9 + Unit: + HP: 50 + Speed: 4 + AttackBase: + PrimaryWeapon: M1Carbine + TakeCover: + SquishByTank: + AutoTarget: + +E2: + Inherits: DefaultInfantry + Buildable: + TechLevel: 1 + Tab: Infantry + Owner: soviet + Cost: 160 + Description: Grenadier + LongDesc: Infantry armed with grenades. \n Strong vs Buildings, Infantry\n Weak vs Vehicles + Selectable: + Bounds: 12,17,0,-9 + Unit: + HP: 50 + Speed: 5 + AttackBase: + PrimaryWeapon: Grenade + PrimaryOffset: 0,0,0,-13 + FireDelay: 15 + TakeCover: + SquishByTank: + AutoTarget: + +E3: + Inherits: DefaultInfantry + Buildable: + TechLevel: 2 + Tab: Infantry + Owner: allies,soviet + Cost: 300 + Description: Rocket Soldier + LongDesc: Anti-tank/Anti-aircraft infantry.\n Strong vs Tanks, Aircraft\n Weak vs Infantry + Selectable: + Bounds: 12,17,0,-9 + Unit: + HP: 45 + Speed: 3 + AttackBase: + PrimaryWeapon: RedEye + PrimaryOffset: 0,0,0,-13 + TakeCover: + SquishByTank: + AutoTarget: + +E4: + Inherits: DefaultInfantry + Buildable: + TechLevel: 6 + Tab: Infantry + Prerequisites: stek + Owner: soviet + Cost: 300 + Description: Flamethrower + LongDesc: Advanced Anti-infantry unit.\n Strong vs Infantry, Buildings\n Weak vs Vehicles + Selectable: + Bounds: 12,17,0,-9 + Unit: + HP: 40 + Speed: 3 + AttackBase: + PrimaryWeapon: Flamer + PrimaryOffset: 0,0,0,-7 + FireDelay: 8 + TakeCover: + SquishByTank: + AutoTarget: + +E6: + Inherits: DefaultInfantry + Buildable: + TechLevel: 5 + Tab: Infantry + Owner: soviet,allies + Cost: 500 + Description: Engineer + LongDesc: Infiltrates and captures enemy structures.\n Strong vs Nothing\n Weak vs Everything + Selectable: + Voice: EngineerVoice + Bounds: 12,17,0,-9 + Unit: + HP: 25 + Speed: 4 + EngineerCapture: + TakeCover: + SquishByTank: + +SPY: + Inherits: DefaultInfantry + Buildable: + TechLevel: 6 + Tab: Infantry + Prerequisites: dome + Owner: allies + Cost: 500 + Description: Spy + LongDesc: Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised + Selectable: + Voice: SpyVoice + Bounds: 12,17,0,-9 + Unit: + HP: 25 + Sight: 5 + Speed: 4 + TakeCover: + SquishByTank: + +THF: + Inherits: DefaultInfantry + Buildable: + TechLevel: 11 + Tab: Infantry + Prerequisites: atek + Owner: allies + Cost: 500 + Description: Thief + LongDesc: Infiltrates enemy refineries & \nsilos, and steals money stored there.\n Unarmed + Selectable: + Voice: ThiefVoice + Bounds: 12,17,0,-9 + Unit: + HP: 25 + Sight: 5 + Speed: 4 + TakeCover: + SquishByTank: + Thief: + +E7: + Inherits: DefaultInfantry + Buildable: + TechLevel: 11 + Tab: Infantry + Prerequisites: @Tech Center + Owner: allies,soviet + Cost: 1200 + Description: Tanya + LongDesc: Elite commando infantry, armed with \ndual pistols and C4.\n Strong vs Infantry, Buildings\n Weak vs Vehicles\n Special Ability: Destroy Building with C4 + Selectable: + Voice: TanyaVoice + Bounds: 12,17,0,-9 + Unit: + HP: 100 + Sight: 6 + Speed: 5 + C4Demolition: + AttackBase: + PrimaryWeapon: Colt45 + TakeCover: + SquishByTank: + AutoTarget: + +MEDI: + Inherits: DefaultInfantry + Buildable: + TechLevel: 2 + Tab: Infantry + Owner: allies + Cost: 800 + Description: Medic + LongDesc: Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything + Selectable: + Voice: MedicVoice + Bounds: 12,17,0,-9 + Unit: + HP: 80 + Sight: 3 + Speed: 4 + AutoHeal: + AttackBase: + PrimaryWeapon: Heal + TakeCover: + SquishByTank: -Vehicles: - V2RL: - Buildable: { Description="V2 Rocket", Prerequisites=[weap,dome], TechLevel=4, Cost=700, - LongDesc="Long-range rocket artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft" } - Unit: { HP=150, Armor=light, Crewed=yes, Voice=VehicleVoice } - Mobile: { Sight=5, ROT=5, Speed=7, UMT=Track } - AttackBase: { Primary=SCUD, Ammo=1 } - RenderUnitReload: {} - AutoTarget: {} - Repairable: {} - Chronoshiftable: {} - Passenger: {} - IronCurtainable: {} \ No newline at end of file diff --git a/regen-yaml.cmd b/regen-yaml.cmd new file mode 100755 index 0000000000..296337b094 --- /dev/null +++ b/regen-yaml.cmd @@ -0,0 +1,2 @@ +RulesConverter\bin\debug\RulesConverter.exe units.ini rules.ini trees.ini campaignUnits.ini ra.yaml +RulesConverter\bin\debug\RulesConverter.exe aftermathUnits.ini aftrmath.ini aftermath.yaml \ No newline at end of file diff --git a/rules.ini b/rules.ini index 8b753341e0..1bb007ac1a 100644 --- a/rules.ini +++ b/rules.ini @@ -601,7 +601,7 @@ Infiltrate=yes ; Tanya [E7] -Prerequisite=atek,stek +Prerequisite=@Tech Center Primary=Colt45 Secondary=Colt45 Strength=100 @@ -1228,7 +1228,7 @@ ROT=30 ; big missile silo [MSLO] -Prerequisite=stek,atek +Prerequisite=@Tech Center Primary=none Strength=400 Armor=heavy @@ -1256,7 +1256,6 @@ Crewed=yes ; normal power plant [POWR] -Prerequisite=fact Strength=400 Armor=wood TechLevel=1 diff --git a/session.ini b/session.ini index d63ac62a10..8df61230ca 100644 --- a/session.ini +++ b/session.ini @@ -10,4 +10,9 @@ s2=Multi1,mcv,600,12505,0,Guard,None ;s2=Multi1,e3,600,12505,0,Guard,None s3=Multi3,mcv,600,2910,0,Guard,None ;s4=Multi1,ctnk,600,12506,Gaurd,None -s5=Multi1,apc,600,12510,Gaurd,None \ No newline at end of file +s5=Multi1,apc,600,12510,Gaurd,None + + + +s6=Multi0,heli,600,2842,0,Guard,None + diff --git a/thirdparty/yaml/AssemblyInfo.cs b/thirdparty/yaml/AssemblyInfo.cs deleted file mode 100644 index 467ce787b3..0000000000 --- a/thirdparty/yaml/AssemblyInfo.cs +++ /dev/null @@ -1,55 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System.Reflection; -using System.Runtime.CompilerServices; - -// -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -// -[assembly: AssemblyTitle("Yaml Parser")] -[assembly: AssemblyDescription("Yaml .NET library")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("UHasselt students")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("Christophe Lambrechts and Jonathan Slenders")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Revision and Build Numbers -// by using the '*' as shown below: - -[assembly: AssemblyVersion("1.0.*")] diff --git a/thirdparty/yaml/Binary.cs b/thirdparty/yaml/Binary.cs deleted file mode 100644 index e1bd9bf30d..0000000000 --- a/thirdparty/yaml/Binary.cs +++ /dev/null @@ -1,154 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -namespace Yaml -{ - /// - /// A Yaml Boolean node - /// tag:yaml.org,2002:binary - /// - public class Binary : Scalar - { - private byte [] content; - - /// Binary constructor from byte array - /// This constructor only sets the reference, no new memory is allocated - public Binary (byte[] val) : - base ("tag:yaml.org,2002:binary", NodeType.Binary) - { - content = val; - } - - /// Parse a binary node - public Binary (ParseStream stream) : - base ("tag:yaml.org,2002:binary", NodeType.Binary) - { - try - { - content = Parse (stream); - } - catch (FormatException e) - { - throw new ParseException (stream, e); - } - } - - /// Binary content - /// There is no new memory allocated in the 'set'. - public byte [] Content - { - get { return content; } - set { content = value; } - } - - /// Parses a binairy node. - /// - /// This is not an efficient method. First the stream is placed - /// in a string. And after that the string is converted in a byte[]. - /// If there is a fault in the binairy string then that will only be detected - /// after reading the whole stream and after coneverting. - /// - public static new byte [] Parse (ParseStream stream) - { - bool quoted = false; - bool block = false; - System.Text.StringBuilder input = new System.Text.StringBuilder(); - - if (stream.EOF) - throw new ParseException (stream, "Empty node"); - - // Detect block scalar - stream.SkipSpaces (); - if (stream.Char == '|') - { - block = true; - stream.Next (); - stream.SkipSpaces (); - } - - while ( ! stream.EOF) - { - // Detect quotes - if (stream.Char == '\"') - if (quoted) - break; //End of stream - else - quoted = true; //Start of quoted stream - // Detect and ignore newline char's - else if (!(stream.Char == '\n' && block)) - input.Append( stream.Char ); - - stream.Next (); - } - - //Console.WriteLine("convert [" + input.ToString() + "]"); - - return System.Convert.FromBase64String (input.ToString ()); - } - - /// To String - /// The hexadecimal notation, 20 bytes for each line - public override string ToString () - { - System.Text.StringBuilder output = new System.Text.StringBuilder (); - - output.Append ("[BINARY]\n\t"); - for (uint i = 0; i < content.Length; i++) - { - if ((i%16) == 0) - output.Append( "\n\t" ); - output.AppendFormat ("{0:X2} ", content[i]); - } - output.Append ("\n[/BINARY]"); - - return output.ToString (); - } - - /// - /// Write the base64 content to YAML - /// - /// The lines are splitted in blocks of 20 bytes - protected internal override void Write (WriteStream stream) - { - stream.Append("!!binary |" + "\n" ); - - string bin = System.Convert.ToBase64String(content); - - while (bin.Length > 75) - { - stream.Append(" " + bin.Substring(0, 75) + "\n"); - bin = bin.Substring(75); - } - stream.Append(" " + bin ); - - // Old coden, everything on one line - // stream.Append ("!!binary \"" + System.Convert.ToBase64String (content) + "\""); - } - } - -} diff --git a/thirdparty/yaml/Boolean.cs b/thirdparty/yaml/Boolean.cs deleted file mode 100644 index a87172c0fc..0000000000 --- a/thirdparty/yaml/Boolean.cs +++ /dev/null @@ -1,132 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -namespace Yaml -{ - /// - /// Class for storing a Yaml Boolean node - /// tag:yaml.org,2002:bool - /// - public class Boolean : Scalar - { - private bool content; - - /// New boolean - public Boolean (bool val) : - base ("tag:yaml.org,2002:bool", NodeType.Boolean) - { - content = val; - } - - /// Parse boolean - public Boolean (ParseStream stream) : - base ("tag:yaml.org,2002:bool", NodeType.Boolean) - { - // Read the first 8 chars - char [] chars = new char [8]; - - int length = 0; - for (int i = 0; i < chars.Length && ! stream.EOF; i ++) - { - chars [i] = stream.Char; - length ++; - stream.Next (true); - } - - // Compare - if (length == 1) - { - if (chars[0] == 'Y' || chars[0] == 'y') - { content = true; return; } - - if (chars[0] == 'N' || chars[0] == 'n') - { content = false; return; } - } - if (length == 2) - { - string s = "" + chars [0] + chars [1]; - - if (s == "ON" || s == "On" || s == "on") - { content = true; return; } - - if (s == "NO" || s == "No" || s == "no") - { content = false; return; } - } - if (length == 3) - { - string s = "" + chars [0] + chars [1] + chars [2]; - - if (s == "YES" || s == "Yes" || s == "yes") - { content = true; return; } - - if (s == "OFF" || s == "Off" || s == "off") - { content = false; return; } - } - if (length == 4) - { - string s = "" + chars [0] + chars [1] + chars [2] + chars [3]; - - if (s == "TRUE" || s == "True" || s == "true") - { content = true; return; } - } - if (length == 5) - { - string s = "" + chars [0] + chars [1] + chars [2] + chars [3] + chars[4]; - - if (s == "FALSE" || s == "False" || s == "false") - { content = false; return; } - } - - // No boolean - throw new Exception ("No valid boolean"); - } - - /// Node content - public bool Content - { - get { return content; } - set { content = value; } - } - - /// To String - public override string ToString () - { - return "[BOOLEAN]" + content.ToString () + "[/BOOLEAN]"; - } - - /// Write to YAML - protected internal override void Write (WriteStream stream) - { - if (Content) - stream.Append ("y"); - else - stream.Append ("n"); - } - - } -} diff --git a/thirdparty/yaml/COPYING b/thirdparty/yaml/COPYING deleted file mode 100644 index 5faba9d48c..0000000000 --- a/thirdparty/yaml/COPYING +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/thirdparty/yaml/Float.cs b/thirdparty/yaml/Float.cs deleted file mode 100644 index 4ca857aabd..0000000000 --- a/thirdparty/yaml/Float.cs +++ /dev/null @@ -1,295 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -namespace Yaml -{ - /// - /// Class for storing a Yaml Float node - /// tag:yaml.org,2002:float - /// - public class Float : Scalar - { - private double content; - - /// New float - public Float (float val) : base ("tag:yaml.org,2002:float", NodeType.Float) - { - content = val; - } - - /// Parse float - public Float (ParseStream stream) : - base ("tag:yaml.org,2002:float", NodeType.Float) - { - // NaN - if (stream.Char == '.') - { - stream.Next (true); - ParseNaN (stream); - } - else - { - // By default positief - int sign = 1; - - // Negative sign - if (stream.Char == '-') - { - sign = -1; - stream.Next (true); - } - // Positive sign - else if (stream.Char == '+') - stream.Next (true); - - // Test for inf, Inf and INF - if ( ! stream.EOF && stream.Char == '.') - { - stream.Next (true); - ParseInf (stream, sign); - } - // Parse the numbers - else if (!stream.EOF) - ParseNumber (stream, sign); - - else - throw new ParseException (stream, - "No valid float, no data behind the sign"); - } - } - - #region Parse special formats (NaN and Inf) - /// - /// Test for the value's nan, NaN and NAN in the stream. If - /// found then it is placed inside the content. - /// There is no more data excepted behind it - /// - private void ParseNaN (ParseStream stream) - { - // Read the first 8 chars - char [] chars = new char [8]; - - int length = 0; - for (int i = 0; i < chars.Length && ! stream.EOF; i ++) - { - chars [i] = stream.Char; - length ++; - stream.Next (true); - } - - // Compare - if (length == 3) - { - string s = "" + chars [0] + chars [1] + chars [2]; - - if (s == "NAN" || s == "NaN" || s == "nan") - { - content = double.NaN; - return; - } - } - - throw new ParseException (stream, "No valid NaN"); - } - - /// - /// Test for the value's inf, Inf and INF in the stream. If - /// found then it 'merged' with the sign and placed in the content. - /// There is no more data excepted behind it. - /// - private void ParseInf (ParseStream stream, int sign) - { - // Read the first 8 chars - char [] chars = new char [8]; - - int length = 0; - for (int i = 0; i < chars.Length && ! stream.EOF; i ++) - { - chars [i] = stream.Char; - length ++; - stream.Next (true); - } - - // Compare - if (length == 3) - { - string s = "" + chars [0] + chars [1] + chars [2]; - - if (s == "INF" || s == "Inf" || s == "inf") - { - if (sign < 0) - content = double.NegativeInfinity; - else - content = double.PositiveInfinity; - - return; - } - } - - throw new ParseException (stream, "No valid infinity"); - } - #endregion - - /// - /// If it is not Infinity or NaN, then parse as a number - /// - private void ParseNumber (ParseStream stream, int sign) - { - bool base60 = false; // Base 60 with ':' - bool afterDecimal = false; // Before or after the decimal point - - double factor = 0.1; - double part; // If base60 different parts, else output value - - // Set sign - content = sign >= 0 ? 1 : -1; - - // First char must 0-9 - if (stream.Char >= '0' && stream.Char <= '9') - { - part = (uint) (stream.Char - '0'); - stream.Next (true); - } - else - throw new ParseException (stream, - "No valid float: Invalid first character of float: " + stream.Char); - - while (! stream.EOF) - { - // Decimal - if (stream.Char >= '0' && stream.Char <= '9') - if (afterDecimal) - { - part += (uint) (stream.Char - '0') * factor; - factor *= 0.1; - } - else - part = (part * 10) + (uint) (stream.Char - '0'); - - // Base60 detected - else if (stream.Char == ':') - { - if ( ! base60) // First time - { - content *= part; // Multiply to get sign - part = 0; - base60 = true; // We are now sure base 60 - } - else - { - if (part > 59) - throw new ParseException (stream, - "Part of base 60 can't be larger then 59"); - content = (60 * content) + part; - part = 0; - } - } - // If first '.', then after decimal, else it is ignored if not in Base60 - else if ( (!base60 || (base60 && !afterDecimal)) && stream.Char == '.' ) - afterDecimal = true; - - // Determine scientific notation - else if ( (stream.Char == 'E' || stream.Char == 'e') && ! base60 ) - { - stream.Next (true); - content *= Math.Pow (10, ParseScient (stream)); - } - // Ignore underscores if before the decimal point, special case if base 60 - else if ((!afterDecimal || (afterDecimal && base60)) && stream.Char != '_') - throw new ParseException (stream, "Unknown char"); - - stream.Next (true); - } - - // Add last part of base to content - if (base60) - content = (60 * content) + part; - else - content *= part; // Multiply to get sign - } - - /// Parses the exponential part of the float - private static long ParseScient (ParseStream stream) - { - ulong output = 0; - short sign; - - if (stream.Char == '-') - sign = -1; - else if (stream.Char == '+') - sign = 1; - else - throw new ParseException (stream, - "Excepted + or - for the exponential part"); - - stream.Next (true); - - while (! stream.EOF) - { - if (stream.Char >= '0' && stream.Char <= '9') - output = (10 * output) + (uint) stream.Char - '0'; - else - throw new ParseException (stream, - "Unexepted char in exponential part: >" + - stream.Char + "<"); - - stream.Next (true); - } - - return sign * (long) output; - } - - /// Content - public double Content - { - get { return content; } - set { content = value; } - } - - /// To string - public override string ToString() - { - return "[FLOAT]" + content + "[/FLOAT]"; - } - - /// Write to a YAML node - protected internal override void Write (WriteStream stream) - { - if (content.Equals( double.NaN )) - stream.Append ("!!float .NaN"); - - else if (content.Equals( double.NegativeInfinity )) - stream.Append ("!!float -.Inf"); - - else if (content.Equals( double.PositiveInfinity )) - stream.Append ("!!float +.Inf"); - - else stream.Append ("!!float " + content); - } - } -} diff --git a/thirdparty/yaml/Integer.cs b/thirdparty/yaml/Integer.cs deleted file mode 100644 index 948984e983..0000000000 --- a/thirdparty/yaml/Integer.cs +++ /dev/null @@ -1,266 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -namespace Yaml -{ - /// - /// Class for storing a Yaml Integer node - /// uri: tag:yaml.org,2002:int - /// - public class Integer : Scalar - { - private long content; - - /// New Integer - public Integer (long val) : - base ("tag:yaml.org,2002:int", NodeType.Integer) - { - content = val; - } - - /// Content - public long Content - { - get { return content; } - set { content = value; } - } - - /// Parse an integer - public Integer (ParseStream stream) : - base ("tag:yaml.org,2002:int", NodeType.Integer) - { - short sign = 1; // Positive sign by default - - // Negative sign - if (stream.Char == '-') - { - sign = -1; - stream.Next (); - } - // Positive sign - else if (stream.Char == '+') - stream.Next (); - - try - { - // Determine base - if (stream.Char == '0') - { - stream.Next (); - - // Base 2 - if (stream.Char == 'b') - { - stream.Next (); - content = ParseBase (stream, 2, sign); - return; - } - // Base 16 - else if (stream.Char == 'x') - { - stream.Next (); - content = Parse16 (stream, sign); - return; - } - // Base 8 - else - { - content = ParseBase (stream, 8, sign); - return; - } - } - - // Other base - stream.BuildLookaheadBuffer (); - - // First, try to parse with base 10 - try - { - content = ParseBase (stream, 10, sign); - stream.DestroyLookaheadBuffer (); - return; - } - catch { } - - // If not parseable with base 10, then try base 60 - stream.RewindLookaheadBuffer (); - stream.DestroyLookaheadBuffer (); - - content = Parse60 (stream, sign); - } - catch (Exception ex) - { - throw new ParseException (stream, ex.ToString ()); - } - } - - /// Hexadecimal string - private static long Parse16 (ParseStream stream, short sign) - { - uint output = 0; - - while (! stream.EOF) - { - // 0 .. 9 - if (stream.Char >= '0' && stream.Char <= '9') - { - output = (output * 16) + (uint) (stream.Char - '0'); - OverflowTest (output, sign); - } - // a .. f - else if (stream.Char >= 'a' && stream.Char <= 'f') - { - output = (output * 16) + (uint) (stream.Char - 'a') + 10; - OverflowTest (output, sign); - } - // A .. F - else if (stream.Char >= 'A' && stream.Char <= 'F') - { - output = (output * 16) + (uint) (stream.Char - 'A') + 10; - OverflowTest(output, sign); - } - // Ignore underscores, other chars are not allowed - else if (stream.Char != '_') - throw new Exception ("Unknown char in base 16"); - - stream.Next (); - } - - return (long) (sign * output); - } - - /// Parses a string with a given base (maximum 10) - /// - /// This is not completly correct. For base10 the first char may not be a '_' - /// The other bases allow this... - /// - private static long ParseBase (ParseStream stream, uint basis, short sign) - { - // Base must be <= 10 - if (basis > 10) - throw new Exception ("Base to large. Maximum 10"); - - ulong output = 0; - char max = (char) ((basis - 1) + (int) '0'); - - // Parse - while (! stream.EOF) - { - // Decimal - if (stream.Char >= '0' && stream.Char <= max) - { - output = (output * basis) + (uint) (stream.Char - '0'); - OverflowTest (output, sign); - } - // Ignore underscores, but other chars are not allowed - // see remarks - else if (stream.Char != '_') - throw new Exception ("Unknown char in base " + basis); - - stream.Next (); - } - return sign * (long) output; - } - - /// Parses a string with base 60, without sign - private static long Parse60 (ParseStream stream, short sign) - { - ulong output = 0; - - // Parse - ulong part = 0; - bool firstPart = true; // Only the first part can be larger then 59 - - while (! stream.EOF) - { - // Decimal - if (stream.Char >= '0' && stream.Char <= '9') - part = (part * 10) + (uint) (stream.Char - '0'); - - // New part - else if (stream.Char == ':') - { - // Only the first part can be largen then 60 - if ( ! firstPart) - if (part >= 60) - throw new - Exception ("Part of base 60 scalar is too large (max. 59)"); - else - firstPart = false; - - output = (output * 60) + part; - OverflowTest(output, sign); - part = 0; - } - - // Ignore underscores, other chars are not allowed - else if (stream.Char != '_') - throw new Exception ("Unknown char in base 16"); - - stream.Next (); - } - - // Add last part to the output - if (!firstPart) - if (part >= 60) - throw new Exception ( - "Part of base 60 scalar is too large (max. 59)"); - else - firstPart = false; - - output = (output * 60) + part; - OverflowTest (output, sign); - - return sign * (long) output; - } - - /// Test that the unsigned int fits in a signed int - /// Value to test - /// Sign of the int where it must fit in - private static void OverflowTest (ulong number, short sign) - { - // NOTE: Negatif numbers can be one larger - if ((sign >= 0 && number > System.Int64.MaxValue) || - (sign < 0 && number > (ulong) System.Int64.MaxValue + 1) ) - - throw new Exception ("YAML overflow exception"); - } - - /// To String - public override string ToString () - { - return "[INTEGER]" + content.ToString () + "[/INTEGER]"; - } - - /// Write to YAML - protected internal override void Write (WriteStream stream) - { - stream.Append (content.ToString ()); - } - } -} diff --git a/thirdparty/yaml/Mapping.cs b/thirdparty/yaml/Mapping.cs deleted file mode 100644 index c91133cfab..0000000000 --- a/thirdparty/yaml/Mapping.cs +++ /dev/null @@ -1,292 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; -using System.Collections; - - -// TODO Access to nodes via the [] overload - -namespace Yaml -{ - /// - /// Yaml Mapping - /// - public class Mapping : Node - { - private ArrayList childNodes = new ArrayList (); - - /// New empty mapping - public Mapping () : base ("tag:yaml.org,2002:map", NodeType.Mapping) { } - - /// New mapping from a mappingnode array - public Mapping (MappingNode [] nodes) : - base ("tag:yaml.org,2002:map", NodeType.Mapping) - { - foreach (MappingNode node in nodes) - childNodes.Add (node); - } - - /// Parse a mapping - public Mapping (ParseStream stream) : - base ("tag:yaml.org,2002:map", NodeType.Mapping) - { - // Mapping with eplicit key, (implicit mappings are threaded - // in Node.cs) - if (stream.Char == '?') - { - // Parse recursively - do { - Node key, val; - - // Skip over '?' - stream.Next (); - stream.SkipSpaces (); - - // Parse recursively. The false param avoids - // looking recursively for implicit mappings. - stream.StopAt (new char [] {':'}); - stream.Indent (); - key = Parse (stream, false); - stream.UnIndent (); - stream.DontStop (); - - // Parse recursively. The false param avoids - // looking for implit nodes - if (stream.Char == ':') - { - // Skip over ':' - stream.Next (); - stream.SkipSpaces (); - - // Parse recursively - stream.Indent (); - val = Parse (stream); - stream.UnIndent (); - } - else - val = new Null (); - - AddMappingNode (key, val); - - // Skip possible newline - // NOTE: this can't be done by the drop-newline - // method since this is not the end of a block - if (stream.Char == '\n') - stream.Next (); - } - while ( ! stream.EOF && stream.Char == '?'); - } - // Inline mapping - else if (stream.Char == '{') - { - // Override the parent's stop chars, never stop - stream.StopAt (new char [] { }); - - // Skip '{' - stream.Next (); - - do { - Node key, val; - - // Skip '?' - // (NOTE: it's not obligated to use this '?', - // especially because this is an inline mapping) - if (stream.Char == '?') - { - stream.Next (); - stream.SkipSpaces (); - } - - // Parse recursively the key - stream.StopAt (new char [] {':', ',', '}'}); - stream.Indent (); - key = Parse (stream, false); - stream.UnIndent (); - stream.DontStop (); - - // Value - if (stream.Char == ':') - { - // Skip colon - stream.Next (); - stream.SkipSpaces (); - - // Parse recursively the value - stream.StopAt (new char [] {'}', ','}); - stream.Indent (); - val = Parse (stream, false); - stream.UnIndent (); - stream.DontStop (); - } - else - val = new Null (); - - AddMappingNode (key, val); - - // Skip comma (key sepatator) - if (stream.Char != '}' && stream.Char != ',') - { - stream.DontStop (); - throw new ParseException (stream, "Comma expected in inline sequence"); - } - - if (stream.Char == ',') - { - stream.Next (); - stream.SkipSpaces (); - } - } - while ( ! stream.EOF && stream.Char != '}' ); - - // Re-accept the parent's stop chars - stream.DontStop (); - - // Skip '}' - if (stream.Char == '}') - stream.Next (); - else - throw new ParseException (stream, "Inline mapping not closed"); - } - } - - /// Add a node to this mapping - public void AddMappingNode (Node key, Node val) - { - childNodes.Add (new MappingNode (key, val)); - } - - /// Add a node to this mapping - public void AddMappingNode (MappingNode node) - { - if (node != null) - childNodes.Add (node); - else - childNodes.Add (new MappingNode (null, null)); - } - - /// Number of mappings - public int Count - { - get { return childNodes.Count; } - } - - /// To String - public override string ToString () - { - string result = ""; - foreach (MappingNode node in childNodes) - result += node.ToString (); - - return "[MAPPING]" + result + "[/MAPPING]"; - } - - /// Node info - public override Node Info () - { - Mapping mapping = new Mapping (); - mapping.AddMappingNode (new String ("kind"), new String ("mapping")); - mapping.AddMappingNode (new String ("type_id"), new String (URI)); - - Mapping childs = new Mapping (); - int i = 0; - foreach (MappingNode child in childNodes) - { - Sequence keyvaluepair = new Sequence (); - keyvaluepair.AddNode (child.Key.Info () ); - keyvaluepair.AddNode (child.Value.Info ()); - - childs.AddMappingNode (new String ("key_" + i), keyvaluepair); - i ++; - } - - mapping.AddMappingNode (new String ("value"), childs); - return mapping; - } - - /// Write to YAML - protected internal override void Write (WriteStream stream) - { - foreach (MappingNode node in childNodes) - { - stream.Append ("? "); - - stream.Indent (); - Yaml.Node key = node.Key; - key.Write (stream); - stream.UnIndent (); - - stream.Append (": "); - - stream.Indent (); - node.Value.Write (stream); - stream.UnIndent (); - } - } - - } - - /// - /// Node pair (key, value) of a mapping - /// - public class MappingNode - { - private Node key; - private Node val; - - /// Create a new mappingnode - public MappingNode (Node key, Node val) - { - if (key == null) key = new Null (); - if (val == null) val = new Null (); - - this.key = key; - this.val = val; - } - - /// Key property - public Node Key - { - get { return key; } - set { key = (value == null ? new Null () : value); } - } - - /// Value property - public Node Value - { - get { return val; } - set { val = (value == null ? new Null () : value); } - } - - /// To String - public override string ToString () - { - return - "[KEY]" + key.ToString () + "[/KEY]" + - "[VAL]" + val.ToString () + "[/VAL]"; - } - } -} diff --git a/thirdparty/yaml/Node.cs b/thirdparty/yaml/Node.cs deleted file mode 100644 index ea19cd6ddd..0000000000 --- a/thirdparty/yaml/Node.cs +++ /dev/null @@ -1,469 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -#define UNSTABLE -#define SUPPORT_EXPLICIT_TYPES -#define SUPPORT_IMPLICIT_MAPPINGS - -using System; -using System.Text; -using System.Collections; - -using System.IO; - -namespace Yaml -{ - /// - /// Kind of node, used to determine the type of node. - /// - public enum NodeType - { - /// A Yaml mapping - collection type - Mapping, - /// A Yaml sequence - collection type - Sequence, - - /// A Yaml binary scalar - Binary, - /// A Yaml boolean scalar - Boolean, - /// A Yaml float scalar - Float, - /// A Yaml integer scalar - Integer, - /// A Yaml null scalar - Null, - /// A Yaml string scalar - String, - /// A Yaml timestamp scalar - Timestamp - }; - - /// - /// Node in the Yaml tree - /// - - public abstract class Node - { - /// The uri given by http://yaml.org/type/ - protected readonly string uri; - - /// Determines wich node we are talking about - protected NodeType nodetype; - - /// Node Constructor - /// URI of the node - /// The type of node that we want to store - public Node (string uri, NodeType nodetype) - { - this.uri = uri; - this.nodetype = nodetype; - } - - /// Parse a Yaml string and return a Yaml tree - public static Node Parse (string lines) - { - StringReader reader = new StringReader (lines); - Node node = Parse (new ParseStream (reader)); - reader.Close (); - return node; - } - - /// Parse a Yaml string from a textreader and return a Yaml tree - public static Node Parse (TextReader textreader) - { - return Parse (new ParseStream (textreader)); - } - - /// Return a Yaml string - public string Write () - { - StringWriter stringWriter = new StringWriter (); - WriteStream writeStream = new WriteStream (stringWriter); - - Write (writeStream); - - stringWriter.Close (); - return stringWriter.ToString (); - } - - /// - /// Parse a Yaml string from a textfile and return a Yaml tree - /// - public static Node FromFile (string filename) - { - // Open YAML file - StreamReader reader = File.OpenText (filename); - ParseStream parsestream = new ParseStream (reader); - - // Parse - Node node = Parse (parsestream); - - // Close YAML file - reader.Close (); - return node; - } - - /// - /// Write a YAML tree to a file using UTF-8 encoding - /// - public void ToFile (string filename) - { - ToFile (filename, Encoding.UTF8); - } - - /// - /// Write a YAML tree to a file - /// - public void ToFile (string filename, Encoding enc) - { - // Open YAML file - StreamWriter writer = new StreamWriter (filename, false, enc); - WriteStream writestream = new WriteStream (writer); - - // Write - Write (writestream); - - // Close YAML file - writer.Close (); - } - - /// Parse function - protected static Node Parse (ParseStream stream) { return Parse (stream, true); } - - /// Internal parse method - /// - /// Avoids ethernal loops while parsing implicit mappings. Implicit mappings are - /// not rocognized by a leading character. So while trying to parse the key of - /// something we think that could be a mapping, we're sure that if it is a mapping, - /// the key of this implicit mapping is not a mapping itself. - /// - /// NOTE: Implicit mapping still belong to unstable code and require the UNSTABLE and - /// IMPLICIT_MAPPINGS preprocessor flags. - /// - /// - protected static Node Parse (ParseStream stream, bool parseImplicitMappings) - { - // ---------------- - // Skip Whitespace - // ---------------- - if (! stream.EOF) - { - // Move the firstindentation pointer after the whitespaces of this line - stream.SkipSpaces (); - while (stream.Char == '\n' && ! stream.EOF) - { - // Skip newline and next whitespaces - stream.Next (); - stream.SkipSpaces (); - } - } - - // ----------------- - // No remaining chars (Null/empty stream) - // ----------------- - if (stream.EOF) - return new Null (); - - // ----------------- - // Explicit type - // ----------------- - -#if SUPPORT_EXPLICIT_TYPES - stream.BuildLookaheadBuffer (); - - char a = '\0', b = '\0'; - - a = stream.Char; stream.Next (); - b = stream.Char; stream.Next (); - - // Starting with !! - if (a == '!' && b == '!' && ! stream.EOF) - { - stream.DestroyLookaheadBuffer (); - - // Read the tagname - string tag = ""; - - while (stream.Char != ' ' && stream.Char != '\n' && ! stream.EOF) - { - tag += stream.Char; - stream.Next (); - } - - // Skip Whitespace - if (! stream.EOF) - { - stream.SkipSpaces (); - while (stream.Char == '\n' && ! stream.EOF) - { - stream.Next (); - stream.SkipSpaces (); - } - } - - // Parse - Node n; - switch (tag) - { - // Mappings and sequences - // NOTE: - // - sets are mappings without values - // - Ordered maps are ordered sequence of key: value - // pairs without duplicates. - // - Pairs are ordered sequence of key: value pairs - // allowing duplicates. - - // TODO: Create new datatypes for omap and pairs - // derived from sequence with a extra duplicate - // checking. - - case "seq": n = new Sequence (stream); break; - case "map": n = new Mapping (stream); break; - case "set": n = new Mapping (stream); break; - case "omap": n = new Sequence (stream); break; - case "pairs": n = new Sequence (stream); break; - - // Scalars - // - // TODO: do we have to move this to Scalar.cs - // in order to get the following working: - // - // !!str "...": "..." - // !!str "...": "..." - - case "timestamp": n = new Timestamp (stream); break; - case "binary": n = new Binary (stream); break; - case "null": n = new Null (stream); break; - case "float": n = new Float (stream); break; - case "int": n = new Integer (stream); break; - case "bool": n = new Boolean (stream); break; - case "str": n = new String (stream); break; - - // Unknown data type - default: - throw new Exception ("Incorrect tag '!!" + tag + "'"); - } - - return n; - } - else - { - stream.RewindLookaheadBuffer (); - stream.DestroyLookaheadBuffer (); - } -#endif - // ----------------- - // Sequence - // ----------------- - - if (stream.Char == '-' || stream.Char == '[') - return new Sequence (stream); - - // ----------------- - // Mapping - // ----------------- - - if (stream.Char == '?' || stream.Char == '{') - return new Mapping (stream); - - // ----------------- - // Try implicit mapping - // ----------------- - - // This are mappings which are not preceded by a question - // mark. The keys have to be scalars. - -#if (UNSTABLE && SUPPORT_IMPLICIT_MAPPINGS) - - // NOTE: This code can't be included in Mapping.cs - // because of the way we are using to rewind the buffer. - - Node key, val; - - if (parseImplicitMappings) - { - // First Key/value pair - - stream.BuildLookaheadBuffer (); - - stream.StopAt (new char [] {':'}); - - // Keys of implicit mappings can't be sequences, or other mappings - // just look for scalars - key = Scalar.Parse (stream, false); - stream.DontStop (); - -Console.WriteLine ("key: " + key); - - // Followed by a colon, so this is a real mapping - if (stream.Char == ':') - { - stream.DestroyLookaheadBuffer (); - - Mapping mapping = new Mapping (); - - // Skip colon and spaces - stream.Next (); - stream.SkipSpaces (); - - // Parse the value -Console.Write ("using buffer: " + stream.UsingBuffer ()); - stream.Indent (); -Console.Write ("using buffer: " + stream.UsingBuffer ()); -// val = Parse (stream, false); -Console.Write ("<<"); -while (!stream.EOF) {Console.Write (stream.Char);stream.Next (true);} -Console.Write (">>"); - -val = new String (stream); - - -Console.Write ("using buffer: " + stream.UsingBuffer ()); - stream.UnIndent (); -Console.Write ("using buffer: " + stream.UsingBuffer ()); - -Console.Write ("<<"); -while (!stream.EOF) {Console.Write (stream.Char);stream.Next (true);} -Console.Write (">>"); - - - - -Console.WriteLine ("val: " + val); - mapping.AddMappingNode (key, val); - - // Skip possible newline - // NOTE: this can't be done by the drop-newline - // method since this is not the end of a block - while (stream.Char == '\n') - stream.Next (true); - - // Other key/value pairs - while (! stream.EOF) - { - stream.StopAt (new char [] {':'} ); - stream.Indent (); - key = Scalar.Parse (stream); - stream.UnIndent (); - stream.DontStop (); - -Console.WriteLine ("key 2: " + key); - if (stream.Char == ':') - { - // Skip colon and spaces - stream.Next (); - stream.SkipSpaces (); - - // Parse the value - stream.Indent (); - val = Parse (stream); - stream.UnIndent (); - -Console.WriteLine ("val 2: " + val); - mapping.AddMappingNode (key, val); - } - else // TODO: Is this an error? - { - // NOTE: We can't recover from this error, - // the last buffer has been destroyed, so - // rewinding is impossible. - throw new ParseException (stream, - "Implicit mapping without value node"); - } - - // Skip possible newline - while (stream.Char == '\n') - stream.Next (); - } - - return mapping; - } - - stream.RewindLookaheadBuffer (); - stream.DestroyLookaheadBuffer (); - } - -#endif - // ----------------- - // No known data structure, assume this is a scalar - // ----------------- - - Scalar scalar = Scalar.Parse (stream); - - // Skip trash - while (! stream.EOF) - stream.Next (); - - - return scalar; - } - - /// - /// URI of this node, according to the YAML documentation. - /// - public string URI - { - get { return uri; } - } - - /// - /// Kind of node: mapping, sequence, string, ... - /// - public NodeType Type - { - get { return nodetype; } - } - - /// - /// Writes a Yaml tree back to a file or stream - /// - /// - /// should not be called from outside the parser. This method - /// is only public from inside the Sequence and Mapping Write - /// methods. - /// - /// Were the output data go's - protected internal virtual void Write (WriteStream stream) {} - - /// - /// The ToString method here, and in all the classses - /// derived from this class, is used mainly for debugging - /// purpose. ToString returns a xml-like textual representation - /// of the objects. It's very useful to see how a Yaml document - /// has been parsed because of the disambiguous representation - /// of this notation. - /// - public override abstract string ToString (); - - /// - /// Node info returns a YAML node and is also mostly used - /// for debugging the parser. This could be used for - /// traversing the meta-info of another YAML tree - /// - public abstract Node Info (); - } -} diff --git a/thirdparty/yaml/Null.cs b/thirdparty/yaml/Null.cs deleted file mode 100644 index f68eb5fbaa..0000000000 --- a/thirdparty/yaml/Null.cs +++ /dev/null @@ -1,100 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -namespace Yaml -{ - /// - /// Class for storing a Yaml Null node - /// tag:yaml.org,2002:null - /// - public class Null : Scalar - { - /// Null Constructor - public Null () : base ("tag:yaml.org,2002:null", NodeType.Null) { } - - /// Parse a null node - public Null (ParseStream stream) : - base ("tag:yaml.org,2002:null", NodeType.Null) - { - // An empty string is a valid null node - if (stream.EOF) - return; - - else - { - // Read the first 4 chars - char [] chars = new char [8]; - int length = 0; - for (int i = 0; i < chars.Length && ! stream.EOF; i ++) - { - chars [i] = stream.Char; - length ++; - stream.Next (); - } - - // Compare - if (length == 1) - { - string s = "" + chars [0]; - - // Canonical notation - if (s == "~") - return; - } - if (length == 4) - { - string s = "" + chars [0] + chars [1] + chars [2] + chars [3]; - - // null, Null, NULL - if (s == "NULL" || s == "Null" || s == "null") - return; - } - - throw new ParseException (stream, "Not NULL"); - } - } - - /// Content property - public object Content - { - get { return null; } - } - - /// To String - public override string ToString () - { - return "[NULL]~[/NULL]"; - } - - /// Write to YAML - protected internal override void Write (WriteStream stream) - { - stream.Append ("~"); - } - } -} diff --git a/thirdparty/yaml/ParseException.cs b/thirdparty/yaml/ParseException.cs deleted file mode 100644 index b4298a0ed4..0000000000 --- a/thirdparty/yaml/ParseException.cs +++ /dev/null @@ -1,63 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -namespace Yaml -{ - /// - /// ParseException, could be thrown while parsing a YAML stream - /// - public class ParseException : Exception - { - // Line of the Yaml stream/file where the fault occures - private readonly int linenr; - - /// Constructor - /// The parse stream (contains the line number where it went wrong) - /// Info about the exception - public ParseException (ParseStream stream, string message) : - base ("Parse error near line " + stream.CurrentLine + ": " + message) - { - this.linenr = stream.CurrentLine; - } - - /// Constructor - /// The parse stream (contains the line number where it went wrong) - /// The exception that is for example throwed again - public ParseException (ParseStream stream, Exception child) : - base ( "Parse error near line " + stream.CurrentLine, child ) - { - this.linenr = stream.CurrentLine; - } - - /// The line where the error occured - public int LineNumber - { - get { return linenr; } - } - } -} diff --git a/thirdparty/yaml/ParseStream.cs b/thirdparty/yaml/ParseStream.cs deleted file mode 100644 index 271a59e5ec..0000000000 --- a/thirdparty/yaml/ParseStream.cs +++ /dev/null @@ -1,899 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; -using System.Collections; - -using System.IO; - -namespace Yaml -{ - /// - /// The Preprocessor class - /// Given a character stream, this class will - /// walk through that stream. - /// NOTE: Comments are not longer skipped at this level, - /// but now in the last level instead. (because of - /// problems with comments within the buffer) - /// NOTE: Null characters are skipped, read nulls should - /// be escaped. \0 - /// - public class Preprocessor - { - private TextReader stream; - private int currentline = 1; // Line numbers start with one - private bool literal = false; // Parse literal/verbatim - - /// Constuctor - public Preprocessor (TextReader stream) - { - this.stream = stream; - } - - /// Jump to the next character - public void Next () - { - // Transition to the next line? - if (Char == '\n') - currentline ++; - - // Not yet passed the end of file - if (! EOF) - { - // Next - stream.Read (); - - // Skip null chars - while (stream.Peek () == '\0') - stream.Read (); - } - } - - /// Start parsing literal - public void StartLiteral () - { - literal = true; - } - - /// Stop parsing literal - public void StopLiteral () - { - if (literal) - literal = false; - else - throw new Exception ("Called StopLiteral without " + - "calling StartLiteral before"); - } - - /// Literal parsing - public bool Literal - { - get { return literal; } - // No set method, setting must by using the {Start,Stop}Literal - // methods. They provide mory symmetry in the parser. - } - - /// The current character - public char Char - { - get - { - if (EOF) - return '\0'; - else - return (char) stream.Peek (); - } - } - - /// End of file/stream - public bool EOF - { - get { return stream.Peek () == -1; } - } - - /// Returns the current line number - public int CurrentLine - { - get { return currentline; } - } - } - - /// - /// The indentation processor, - /// This class divides the stream from the preprocessor - /// in substreams, according to the current level - /// of indentation. - /// - public class IndentationProcessor : Preprocessor - { - // While trying to readahead over whitespaces, - // This is how many whitespaces were skipped that weren't yet read - private int whitespaces = 0; - private int whitespacesSkipped = 0; - - // Reached the end - private bool endofstream = false; - - // Current level of indentation - private int indentationLevel = 0; - private bool indentationRequest = false; - private Stack indentationStack = new Stack (); - - /// Constructor - public IndentationProcessor (TextReader stream) : base (stream) { } - - /// - /// Request an indentation. When we meet a \n and the following - /// line is more indented then the current indentationlever, then - /// save this request - /// - public void Indent () - { - if (Literal) - throw new Exception ("Cannot (un)indent while literal parsing " + - "has been enabled"); - else - { - // Handle double requests - if (indentationRequest) - indentationStack.Push ((object) indentationLevel); - - // Remember - indentationRequest = true; - } - } - - /// Cancel the last indentation - public void UnIndent () - { - if (Literal) - throw new Exception ("Cannot (un)indent while literal parsing " + - "has been enabled"); - else - { - // Cancel the indentation request - if (indentationRequest) - { - indentationRequest = false; - return; - } - - // Unpop the last indentation - if (indentationStack.Count > 0) - indentationLevel = (int) indentationStack.Pop (); - - // When not indented - else - throw new Exception ("Unable to unindent a not indented parse stream"); - - // Parent stream not yet finished - // Skipped whitespaces in the childstream (at that time assumed to be - // indentation) can become content. - if (endofstream && indentationLevel <= whitespaces) - { - endofstream = false; - if (whitespaces == this.indentationLevel) - whitespaces = 0; - } - } - } - - /// Go to the next parsable char in the stream - public new void Next () - { - if (endofstream) - return; - - // Are there still whitespaces to skip - if (whitespaces > 0) - { - // All whitespaces were skipped - if (whitespaces == whitespacesSkipped + this.indentationLevel) - whitespaces = 0; - - // Else, skip one - else - { - whitespacesSkipped ++; - return; - } - } - - // All whitespaces have been skipped - if (whitespaces == 0 && ! base.EOF) - { - // When a char is positioned at a newline '\n', - // then skip 'indentation' chars and continue. - // When there are less spaces available, then we are - // at the end of the (sub)stream - if (! base.EOF && base.Char == '\n' && ! Literal) - { - // Skip over newline - base.Next (); - - // Skip indentation (and count the spaces) - int i = 0; - while (! base.EOF && base.Char == ' ' && i < this.indentationLevel) - { - i ++; - base.Next (); - } - - // Not enough indented? - if (i < this.indentationLevel) - { - // Remember the number of whitespaces, and - // continue at the moment that the indentationlevel - // drops below this number of whitespaces - whitespaces = i; - whitespacesSkipped = 0; - endofstream = true; - return; - } - // Indentation request - else if (indentationRequest) - { - while (! base.EOF && base.Char == ' ') - { - i ++; - base.Next (); - } - - // Remember current indentation - indentationStack.Push ((object) indentationLevel); - indentationRequest = false; - - // Number of spaces before this line is equal to the - // current level of indentation, so the - // indentation request cannot be fulfilled - if (indentationLevel == i) - { - whitespaces = i; - whitespacesSkipped = 0; - endofstream = true; - return; - } - else // i > indentationLevel - indentationLevel = i; - } - } - else - // Next char - base.Next (); - } - else - endofstream = true; - } - - /// Reads the current char from the stream - public new char Char - { - get - { - // In case of spaces - if (whitespaces > 0) - return ' '; - - // \0 at the end of the stream - else if (base.EOF || endofstream) - return '\0'; - - // Return the char - else - return base.Char; - } - } - - /// End of File/Stream - public new bool EOF - { - get { return endofstream || base.EOF; } - } - } - - /// - /// Third stream processor, this class adds a buffer with a maximum - /// size of 1024 chars. The buffer cannot encapsulate multiple lines - /// because that could do strange things while rewinding/indenting - /// - - public class BufferStream : IndentationProcessor - { - LookaheadBuffer buffer = new LookaheadBuffer (); - - // When the buffer is used, this is true - private bool useLookaheadBuffer = false; - - // In use, but requested to destroy. The buffer will keep to exists - // (only in this layer) and shall be destroyed when we move out of - // the buffer - private bool destroyRequest = false; - - /// Constructor - public BufferStream (TextReader stream) : base (stream) { } - - /// Build lookahead buffer - public void BuildLookaheadBuffer () - { - if (Literal) - throw new Exception ("Cannot build a buffer while " + - "literal parsing is enabled"); - else - { - // When the buffer is already in use - if (useLookaheadBuffer && ! destroyRequest) - throw new Exception ("Buffer already exist, cannot rebuild " + - "the buffer at this level"); - - // Cancel the destroy request - if (destroyRequest) - destroyRequest = false; - - // Or start a new buffer - else - { - buffer.Clear (); - buffer.Append (Char); - } - - useLookaheadBuffer = true; - } - } - - /// Move to the next character in the parse stream. - public new void Next () - { - // End of file (This check is not really necessary because base.next - // would skip this anyway) - if (EOF) return; - - // When it's not allowed to leave the buffer - if (useLookaheadBuffer && ! destroyRequest && ! NextInBuffer () ) - return; - - // When using the lookahead buffer - if (useLookaheadBuffer) - { - // Requested to destroy - if (destroyRequest) - { - // But not yet reached the end of the buffer - if (buffer.Position < buffer.LastPosition) - { - buffer.Position ++; - buffer.ForgetThePast (); - } - // Reached the end - else - { - buffer.Clear (); - useLookaheadBuffer = false; - destroyRequest = false; - - base.Next (); - } - } - // Continue in the buffer - else - { - // We've been here before - if (buffer.Position < buffer.LastPosition) - buffer.Position ++; - - // This is new to the buffer, but there is place - // to remember new chars - else if ( - buffer.Position == buffer.LastPosition && - ! buffer.Full) - { - // Save the next char in the buffer - base.Next(); - buffer.Append (base.Char); - } - // Otherwise, the buffer is full - else - throw new Exception ("buffer overflow"); - } - } - // Not using the buffer - else - base.Next(); - } - - /// Returns true when using a buffer - public bool UsingBuffer () - { - return useLookaheadBuffer && ! destroyRequest; - } - - /// - /// Returns true when the next char will still be in the buffer - /// (after calling next) - /// - private bool NextInBuffer () - { - return - // Using the buffer - useLookaheadBuffer && - - // Next char has been read before - (buffer.Position < buffer.LastPosition || - - // Or the next char will also be in the buffer - (Char != '\n' && ! base.EOF && - - // There is still unused space - ! buffer.Full)); - } - - /// Destroys the current lookaheadbuffer, if there is one - public void DestroyLookaheadBuffer () - { - if (useLookaheadBuffer && ! destroyRequest) - { - buffer.ForgetThePast (); - destroyRequest = true; - } - else - throw new Exception ("Called destroy buffer before building the buffer"); - } - - /// Rewind the buffer - public void RewindLookaheadBuffer () - { - if (! useLookaheadBuffer || destroyRequest) - throw new Exception ("Cannot rewind the buffer. No buffer in use"); - - else - buffer.Rewind (); - } - - /// The current character - public new char Char - { - get - { - // When using a buffer - if (useLookaheadBuffer) - return buffer.Char; - - else - return base.Char; - } - } - - /// End of stream/file - public new bool EOF - { - get - { - return - // When it's not allowed to run out of the buffer - (useLookaheadBuffer && ! destroyRequest && ! NextInBuffer () ) || - - // Not using the buffer, but the end of stream has been reached - (! useLookaheadBuffer && base.EOF); - } - } - - /// Current position in the lookahead buffer - protected int LookaheadPosition - { - get - { - if (useLookaheadBuffer) - return buffer.Position; - - else - throw new Exception ("Not using a lookahead buffer"); - } - set - { - if (useLookaheadBuffer) - { - if (value >= 0 && value <= buffer.LastPosition) - buffer.Position = value; - - else - throw new Exception ("Lookahead position not between 0 " + - "and the buffer size"); - } - else - throw new Exception ("Not using a lookahead buffer"); - } - } - } - - /// Parsestream with multilever buffer - public class MultiBufferStream : BufferStream - { - private Stack bufferStack = new Stack (); // Top is current buffer start - - /// Constructor - public MultiBufferStream (TextReader stream) : base (stream) { } - - /// Destroy the current buffer - public new void BuildLookaheadBuffer () - { - if (Literal) - throw new Exception ("Cannot build a buffer while " + - "literal parsing is enabled"); - else - { - // Already using a buffer - if (base.UsingBuffer ()) - // Remember the current position - bufferStack.Push ((object) base.LookaheadPosition); - - // Otherwise, create a new buffer - else - { - // Remember the current position (= 0) - bufferStack .Push ((object) 0); - - base.BuildLookaheadBuffer (); - } - } - } - - /// Destroy the current buffer - public new void DestroyLookaheadBuffer () - { - // Clear the buffer info when we runned out of the buffer, - if ( ! base.UsingBuffer () ) - bufferStack.Clear (); - - else - { - // Unpop the buffers start index - bufferStack.Pop (); - - // Destroy it when the last buffer is gone - if (bufferStack.Count == 0) - base.DestroyLookaheadBuffer (); - } - } - - /// Rewind the current buffer - public new void RewindLookaheadBuffer () - { - if (base.UsingBuffer () ) - base.LookaheadPosition = (int) bufferStack.Peek (); - else - throw new Exception ("Rewinding not possible. Not using a " + - "lookahead buffer."); - } - } - - /// - /// Drop the comments - /// (This is disabled when literal parsing is enabled) - /// - public class DropComments : MultiBufferStream - { - /// Constructor - public DropComments (TextReader stream) : base (stream) { } - - /// Move to the next character in the parse stream. - public new void Next () - { - base.Next (); - - // Skip comments - if (base.Char == '#' && ! Literal) - while (! base.EOF && base.Char != '\n') - base.Next (); - } - } - - /// - /// This layer removes the trailing newline at the end of each (sub)stream - /// - public class DropTrailingNewline : DropComments - { - // One char buffer - private bool newline = false; - - /// Constructor - public DropTrailingNewline (TextReader stream) : base (stream) { } - - /// The current character - public new char Char - { - get - { - if (EOF) - return '\0'; - else if (newline) - return '\n'; - else - return base.Char; - } - } - - /// End of File/Stream - public new bool EOF - { - get { return ! newline && base.EOF; } - } - - /// Skip space characters - public int SkipSpaces () - { - int count = 0; - while (Char == ' ') - { - Next (); - count ++; - } - return count; - } - - /// Move to the next character in the parse stream. - public new void Next () - { - Next (false); - } - - /// Move to the next character in the parse stream. - /// Forget the last newline - public void Next (bool dropLastNewLine) - { - if (newline) - newline = false; - else - { - base.Next (); - - if (dropLastNewLine && ! base.EOF && Char == '\n') - { - base.Next (); - - if (base.EOF) - newline = false; - else - newline = true; - } - } - } - } - - - /// - /// Stops parsing at specific characters, useful for parsing inline - /// structures like (for instance): - /// - /// [aaa, bbb, ccc, {ddd: eee, "fff": ggg}] - /// - public class ParseStream : DropTrailingNewline - { - private Stack stopstack = new Stack (); - - /// Constructor - public ParseStream (TextReader stream) : base (stream) { } - - /// Set the characters where we should stop. - public void StopAt (char [] characters) - { - stopstack.Push (characters); - } - - /// Unset the characters where we should stop. - public void DontStop () - { - if (stopstack.Count > 0) - stopstack.Pop (); - else - throw new Exception ("Called DontStop without " + - "calling StopAt before"); - } - - /// True when we have to stop here - private bool StopNow - { - get { - if (stopstack.Count > 0) - foreach (char c in (char []) stopstack.Peek ()) - if (c == base.Char) - return true; - - return false; - } - } - - /// Start parsing literal - public new void StartLiteral () - { - base.StartLiteral (); - - // Parsing literal disables stopping - StopAt (new Char [] { }); - } - - /// Stop parsing literal - public new void StopLiteral () - { - base.StopLiteral (); - - DontStop (); - } - /// Move to the next character in the parse stream. - public new void Next () - { - Next (false); - } - - /// Move to the next character in the parse stream. - public new void Next (bool dropLastNewLine) - { - if ( ! StopNow ) - base.Next (dropLastNewLine); - } - - /// The current character - public new char Char - { - get - { - if (StopNow) - return '\0'; - - else - return base.Char; - } - } - - /// End of stream/file - public new bool EOF - { - get { return StopNow || base.EOF; } - } - } - - /// - /// The lookahead buffer, used by the buffer layer in the parser - /// - class LookaheadBuffer - { - // The buffer array - private char [] buffer = new char [1024]; - - private int size = 0; // 0 = Nothing in the buffer - private int position = -1; // Current position - private int rotation = 0; // Start of circular buffer - - /// Character at the current position - public char Char - { - get - { - if (size > 0) - return buffer [(position + rotation) % buffer.Length]; - - else - throw new Exception ("Trying to read from an emty buffer"); - } - } - - /// The current position - public int Position - { - get { return position; } - - set - { - if (value >= 0 && value < size) - position = value; - else - throw new Exception ("Buffer position should be " + - "between zero and 'size' "); - } - } - - /// The last possible postition which could be set - public int LastPosition - { - get { return size - 1; } - } - - /// - /// The last possible position which could be set if - /// the buffer where full - /// - public int MaxPosition - { - get { return buffer.Length - 1; } - } - - /// True when the buffer is full - public bool Full - { - get { return size == buffer.Length; } - } - - /// Current buffer size - public int Size - { - get { return size; } - } - - /// Append a character to the buffer - public void Append (char c) - { - // Appending is only possible when the current position is the - // last in the buffer - if (position < LastPosition) - throw new Exception ("Appending to buffer only possible " + - "when the position is the last"); - - // Buffer overflow - if (size == buffer.Length) - throw new Exception ("Buffer full"); - - // Append - position ++; - size ++; - buffer [(position + rotation) % buffer.Length] = c; - } - - /// Rewind the buffer - public void Rewind () - { - position = 0; - } - - /// Reset (clear) the buffer - public void Clear () - { - position = -1; - size = 0; - } - - /// Move to the next character - public void Next () - { - if (Position < Size) - Position ++; - - else throw new Exception ("Cannot move past the buffer"); - } - - /// - /// Remove characters from the buffer before the current character - /// - public void ForgetThePast () - { - // Size becomes smaller, characters before the position should be dropped - size -= position; - - // The current position becomes the new startposition - rotation = (rotation + position + buffer.Length) % buffer.Length; - - // The current position in the new buffer becomes zero - position = 0; - } - } -} diff --git a/thirdparty/yaml/Scalar.cs b/thirdparty/yaml/Scalar.cs deleted file mode 100644 index 9d2cb849c0..0000000000 --- a/thirdparty/yaml/Scalar.cs +++ /dev/null @@ -1,137 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -#define SUPPORT_NULL_NODES -#define SUPPORT_INTEGER_NODES -#define SUPPORT_FLOAT_NODES -#define SUPPORT_BOOLEAN_NODES -#define SUPPORT_TIMESTAMP_NODES - -using System; - -namespace Yaml -{ - /// - /// All Yaml scalars are derived from this class - /// - public abstract class Scalar : Node - { - /// Constructor - public Scalar (string uri, NodeType nodetype) : base (uri, nodetype) { } - - - /// - /// Parses a scalar - /// - /// Integer - /// String - /// Boolean - /// Null - /// Timestamp - /// Float - /// Binary - /// - /// - /// - /// Binary is only parsed behind an explicit !!binary tag (in Node.cs) - /// - public static new Scalar Parse (ParseStream stream) - { - // ----------------- - // Parse scalars - // ----------------- - - stream.BuildLookaheadBuffer (); - - // Try Null -#if SUPPORT_NULL_NODES - try - { - Scalar s = new Null (stream); - stream.DestroyLookaheadBuffer (); - return s; - } catch { } -#endif - // Try boolean -#if SUPPORT_BOOLEAN_NODES - stream.RewindLookaheadBuffer (); - try - { - Scalar scalar = new Boolean (stream); - stream.DestroyLookaheadBuffer (); - return scalar; - } - catch { } -#endif - // Try integer -#if SUPPORT_INTEGER_NODES - stream.RewindLookaheadBuffer (); - try - { - Scalar scalar = new Integer (stream); - stream.DestroyLookaheadBuffer (); - return scalar; - } catch { } -#endif - // Try Float -#if SUPPORT_FLOAT_NODES - stream.RewindLookaheadBuffer (); - try - { - Scalar scalar = new Float (stream); - stream.DestroyLookaheadBuffer (); - return scalar; - } - catch { } -#endif - // Try timestamp -#if SUPPORT_TIMESTAMP_NODES - stream.RewindLookaheadBuffer (); - try { - Scalar scalar = new Timestamp (stream); - stream.DestroyLookaheadBuffer (); - return scalar; - } catch { } -#endif - // Other scalars are strings - stream.RewindLookaheadBuffer (); - stream.DestroyLookaheadBuffer (); - - return new String (stream); - } - - /// Node info -// TODO, move to each induvidual child - public override Node Info () - { - Mapping mapping = new Mapping (); - mapping.AddMappingNode (new String ("kind"), new String ("scalar")); - mapping.AddMappingNode (new String ("type_id"), new String (URI)); - mapping.AddMappingNode (new String ("value"), this); - return mapping; - } - } -} diff --git a/thirdparty/yaml/Sequence.cs b/thirdparty/yaml/Sequence.cs deleted file mode 100644 index e26bdbd8aa..0000000000 --- a/thirdparty/yaml/Sequence.cs +++ /dev/null @@ -1,197 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; -using System.Collections; - -namespace Yaml -{ - /// - /// Represents a Yaml Sequence - /// - public class Sequence : Node - { - private ArrayList childNodes = new ArrayList (); - - /// New, empty sequence - public Sequence ( ) : base ("tag:yaml.org,2002:seq", NodeType.Sequence) { } - - /// New sequence from a node array - public Sequence (Node [] nodes) : - base ("tag:yaml.org,2002:seq", NodeType.Sequence) - { - foreach (Node node in nodes) - childNodes.Add (node); - } - - /// Parse a sequence - public Sequence (ParseStream stream) : - base ("tag:yaml.org,2002:seq", NodeType.Sequence) - { - // Is this really a sequence? - if (stream.Char == '-') - { - // Parse recursively - do { - // Override the parent's stop chars, never stop - stream.StopAt (new char [] { } ); - - // Skip over '-' - stream.Next (); - - // Parse recursively - stream.Indent (); - AddNode (Parse (stream)); - stream.UnIndent (); - - // Re-accept the parent's stop chars - stream.DontStop (); - } - while ( ! stream.EOF && stream.Char == '-' ); - } - // Or inline Sequence - else if (stream.Char == '[') - { - // Override the parent's stop chars, never stop - stream.StopAt (new char [] { }); - - // Skip '[' - stream.Next (); - - do { - stream.StopAt (new char [] {']', ','}); - stream.Indent (); - AddNode (Parse (stream, false)); - stream.UnIndent (); - stream.DontStop (); - - // Skip ',' - if (stream.Char != ']' && stream.Char != ',') - { - stream.DontStop (); - throw new ParseException (stream, "Comma expected in inline sequence"); - } - - if (stream.Char == ',') - { - stream.Next (); - stream.SkipSpaces (); - } - } - while ( ! stream.EOF && stream.Char != ']'); - - // Re-accept the parent's stop chars - stream.DontStop (); - - // Skip ']' - if (stream.Char == ']') - stream.Next (true); - else - throw new ParseException (stream, "Inline sequence not closed"); - - } - // Throw an exception when not - else - throw new Exception ("This is not a sequence"); - } - - /// Add a node to this sequence - public void AddNode (Node node) - { - if (node != null) - childNodes.Add (node); - else - childNodes.Add (new Null ()); - } - - /// Get a node - public Node this [int index] - { - get - { - if (index > 0 && index < childNodes.Count) - return (Node) childNodes [index]; - - else - throw new IndexOutOfRangeException (); - } - } - - /// The node array - public Node [] Nodes - { - get - { - Node [] nodes = new Node [childNodes.Count]; - - for (int i = 0; i < childNodes.Count; i ++) - nodes [i] = (Node) childNodes [i]; - - return nodes; - } - } - - /// Textual destription of this node - public override string ToString () - { - string result = ""; - foreach (Node node in childNodes) - result += node.ToString (); - - return "[SEQUENCE]" + result + "[/SEQUENCE]"; - } - - /// Node info - public override Node Info () - { - Mapping mapping = new Mapping (); - mapping.AddMappingNode (new String ("kind"), new String ("sequence")); - mapping.AddMappingNode (new String ("type_id"), new String (URI)); - - Sequence childs = new Sequence (); - - foreach (Node child in childNodes) - childs.AddNode (child.Info ()); - - mapping.AddMappingNode (new String ("value"), childs); - return mapping; - } - - /// Write back to a stream - protected internal override void Write (WriteStream stream) - { - foreach (Node node in childNodes) - { - stream.Append ("- "); - - stream.Indent (); - node.Write (stream); - stream.UnIndent (); - } - } - - } -} diff --git a/thirdparty/yaml/String.cs b/thirdparty/yaml/String.cs deleted file mode 100644 index 25243dfbe2..0000000000 --- a/thirdparty/yaml/String.cs +++ /dev/null @@ -1,449 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -// Unicode support: -// http://www.yoda.arachsys.com/csharp/unicode.html - -namespace Yaml -{ - /// - /// Yaml String node - /// - public class String : Scalar - { - private string content; - private bool block = false; - private bool folded = false; - - /// New string constructor - public String (string val) : - base ("tag:yaml.org,2002:str", NodeType.String) - { - content = val; - } - - /// Parse a string - public String (ParseStream stream) : - base ("tag:yaml.org,2002:str", NodeType.String) - { - // set flags for folded or block scalar - if (stream.Char == '>') // TODO: '+' and '-' chomp chars - folded = true; - - else if (stream.Char == '|') - block = true; - - if (block || folded) - { - stream.Next (); - stream.SkipSpaces (); - } - - // ----------------- - // Folded Scalar - // ----------------- - if (folded) - { - System.Text.StringBuilder builder = new System.Text.StringBuilder (); - - // First line (the \n after the first line is always ignored, - // not replaced with a whitespace) - while (! stream.EOF && stream.Char != '\n') - { - builder.Append (stream.Char); - stream.Next (); - } - - // Skip the first newline - stream.Next (); - - // Next lines (newlines will be replaced by spaces in folded scalars) - while (! stream.EOF) - { - if (stream.Char == '\n') - builder.Append (' '); - else - builder.Append (stream.Char); - - stream.Next (true); - } - content = builder.ToString (); - } - - // ----------------- - // Block Scalar (verbatim block without folding) - // ----------------- - else if (block) - { -/* -Console.Write(">>"); -while (! stream.EOF) -{ - Console.Write (stream.Char); - stream.Next(); -} -Console.Write("<<"); -// */ - - System.Text.StringBuilder builder = new System.Text.StringBuilder (); - while (! stream.EOF) - { - builder.Append (stream.Char); - stream.Next (true); - } - content = builder.ToString (); - } - - // String between double quotes - if (stream.Char == '\"') - content = ParseDoubleQuoted (stream); - - // Single quoted string - else if (stream.Char == '\'') - content = ParseSingleQuoted (stream); - - // String without quotes - else - content = ParseUnQuoted (stream); - } - - /// - /// Parses a String surrounded with single quotes - /// - private string ParseSingleQuoted (ParseStream stream) - { - System.Text.StringBuilder builder = new System.Text.StringBuilder (); - - // Start literal parsing - stream.StartLiteral (); - - // Skip ''' - stream.Next (true); - - while (! stream.EOF) - { - if (stream.Char == '\'') - { - stream.Next (); - - // Escaped single quote - if (stream.Char == '\'') - builder.Append (stream.Char); - - // End of string - else - break; - } - else - builder.Append (stream.Char); - - stream.Next (); - - // Skip \' - if (stream.EOF) - { - stream.StopLiteral (); - throw new ParseException (stream, - "Single quoted string not closed"); - } - } - - // Stop literal parsing - stream.StopLiteral (); - - return builder.ToString(); - } - - /// - /// Parses a String surrounded with double quotes - /// - private string ParseDoubleQuoted(ParseStream stream) - { - System.Text.StringBuilder builder = new System.Text.StringBuilder (); - - // Skip '"' - stream.Next (); - - // Stop at " - stream.StopAt (new char [] {'\"'} ); - - while (! stream.EOF) - { - if (stream.Char == '\n') - { - builder.Append (' '); - stream.Next (); - } - else - builder.Append (NextUnescapedChar (stream)); - } - - // Don't stop at " - stream.DontStop (); - - // Skip '"' - if (stream.Char != '\"') - throw new ParseException (stream, - "Double quoted string not closed"); - else - stream.Next (true); - - return builder.ToString(); - } - - /// - /// Parses a String surrounded without nothing - /// - private string ParseUnQuoted(ParseStream stream) - { - System.Text.StringBuilder builder = new System.Text.StringBuilder (); - - while (! stream.EOF) - builder.Append (NextUnescapedChar (stream)); - - // Trimming left - int count = 0; - while (count < builder.Length && - (builder [count] == ' ' || builder [count] == '\t')) - count ++; - - if (count >= 0) - builder.Remove (0, count); - - // Trimming right - count = 0; - while (count < builder.Length && - (builder [builder.Length - count - 1] == ' ' || - builder [builder.Length - count - 1] == '\t')) - count ++; - - if (count >= 0) - builder.Remove (builder.Length - count, count); - - return builder.ToString(); - } - - /// - /// Reads a character from the stream, unescapes it, - /// and moves to the next character. - /// - private char NextUnescapedChar (ParseStream stream) - { - char c = stream.Char; - - // If escaped - if (c == '\\') - { - // Never stop, every special character - // looses its meaning behind a backslash. - stream.StopAt (new Char [] { }); - - stream.Next (true); - c = stream.Char; - - // ASCII null - if (c == '0') c = '\0'; - - // ASCII bell - else if (c == 'a') c = (char) 0x7; - - // ASCII backspace - else if (c == 'b') c = (char) 0x8; - - // ASCII horizontal tab - else if (c == 't') c = (char) 0x9; - - // ASCII newline - else if (c == 'n') c = (char) 0xA; - - // ASCII vertical tab - else if (c == 'v') c = (char) 0xB; - - // ASCII form feed - else if (c == 'f') c = (char) 0xC; - - // ASCII carriage return - else if (c == 'r') c = (char) 0xD; - - // ASCII escape - else if (c == 'e') c = (char) 0x1D; - - // Unicode next line - else if (c == 'N') c = (char) 0x85; - - // Unicode non breaking space - else if (c == '_') c = (char) 0xA0; - - // TODO larger unicode characters - - // Unicode line separator - // else if (c == 'L') c = (char) 0x20282028; - - // 8 bit hexadecimal - else if (c == 'x') - { - int c_int = (char) 0; - - for (int i = 0; i < 2; i ++) - { - c_int *= 16; - - stream.Next (); - char d = stream.Char; - - if (d >= '0' && d <= '9') - c_int += d - '0'; - - else if (d >= 'a' && d <= 'f') - c_int += d - 'a'; - - else if (d >= 'A' && d <= 'F') - c_int += d - 'A'; - else - { - stream.DontStop (); - throw new ParseException (stream, - "Invalid escape sequence"); - } - } - c = (char) c_int; - } - - stream.Next (true); - - // Restore last stop settings - stream.DontStop (); - } - else - stream.Next (true); - - return c; - } - - /// Content property - public string Content - { - get { return content; } - set { content = value; } - } - - /// To String - public override string ToString () - { - return "[STRING]" + content + "[/STRING]"; - } - - /// Write - protected internal override void Write (WriteStream stream) - { - // TODO, not required, but writing to block or folded scalars - // generates a little more neat code. - - // Analyze string - bool multiline = false; - bool mustbequoted = false; - - for (int i = 0; i < content.Length; i ++) - { - char c = content [i]; - - if (c == '\n') - multiline = true; - - // We quote everything except strings like /[a-zA-Z]*/ - // However there are more strings which don't require - // quotes. - if ( ! ( c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')) - mustbequoted = true; - } - - // Double quoted strings - if (mustbequoted) - { - stream.Append ("\""); - - for (int i = 0; i < content.Length; i ++) - { - char c = content [i]; - - // Backslash - if (c == '\\') stream.Append ("\\" + "\\"); - - // Double quote - else if (c == '\"') stream.Append ("\\" + "\""); - - // Single quote - else if (c == '\'') stream.Append ("\\" + "\'"); - - // ASCII null - else if (c == '\0') stream.Append ("\\0"); - - // ASCII bell - else if (c == (char) 0x7) stream.Append ("\\a"); - - // ASCII backspace - else if (c == (char) 0x8) stream.Append ("\\b"); - - // ASCII horizontal tab - else if (c == (char) 0x9) stream.Append ("\\t"); - - // ASCII newline - else if (c == (char) 0xA) stream.Append ("\\n"); - - // ASCII vertical tab - else if (c == (char) 0xB) stream.Append ("\\v"); - - // ASCII form feed - else if (c == (char) 0xC) stream.Append ("\\f"); - - // ASCII carriage return - else if (c == (char) 0xD) stream.Append ("\\r"); - - // ASCII escape - else if (c == (char) 0x1D) stream.Append ("\\e"); - - // Unicode next line - else if (c == (char) 0x85) stream.Append ("\\N"); - - // Unicode non breaking space - else if (c == (char) 0xA0) stream.Append ("\\_"); - - // TODO larger unicode characters - - else - stream.Append ("" + c); - } - stream.Append ("\""); - } - - // Simple non-quoted strings - else - stream.Append (content); - } - } -} diff --git a/thirdparty/yaml/Timestamp.cs b/thirdparty/yaml/Timestamp.cs deleted file mode 100644 index d8dc3f8e6f..0000000000 --- a/thirdparty/yaml/Timestamp.cs +++ /dev/null @@ -1,356 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -using System; - -namespace Yaml -{ - /// - /// Yaml Timestamp node - /// uri: tag:yaml.org,2002:timestamp - /// - public class Timestamp : Scalar - { - private System.DateTime content; - - /// - /// Represents the offset from the UTC time in hours - /// - /// - /// We use this extra variable for compatibility with Mono - /// and .NET 1.0. .NET 2.0 has an extra property for - /// System.Datetime for the timezone. - /// - private double timezone = 0; - - /// - /// Basic constructor that takes a given datetime - /// - /// A .NET 1.0 datetime - public Timestamp (DateTime datetime) : - base ("tag:yaml.org,2002:timestamp", NodeType.Timestamp) - { - this.content = datetime; - this.timezone = 0; - } - - /// - /// Basic constructor, that also gives the posibility to set a timezone - /// - /// A .NET 1.0 datetime - /// The offset, in hours,r to UTC that determine the timezone - public Timestamp (DateTime datetime, double timezone) : - base ("tag:yaml.org,2002:timestamp", NodeType.Timestamp) - { - this.content = datetime; - this.timezone = timezone; - } - - /// Content property - public System.DateTime Content - { - get { return content; } - set { content = value; } - } - - /// Timezone, an offset in hours - public double Timezone - { - get { return timezone; } - set { timezone = value; } - } - - /// To String - public override string ToString () - { - return "[TIMESTAMP]" + YamlString () + "[/TIMESTAMP]"; - } - - /// Parse a DateTime - public Timestamp (ParseStream stream) : - base ("tag:yaml.org,2002:timestamp", NodeType.Timestamp) - { - int year = 0; - int month = 0; - int day = 0; - int hour = 0; - int minutes = 0; - int seconds = 0; - int ms = 0; - - try - { - // Parse year - year = ParseNumber (stream, 4); - SkipChar (stream, '-'); - - // Parse month - month = ParseNumber (stream, 2); - SkipChar (stream, '-'); - - // Parse day - day = ParseNumber (stream, 2); - - // Additional, the time - if ( ! stream.EOF) - ParseTime (stream, out hour, out minutes, out seconds); - - // Additional, milliseconds - if ( ! stream.EOF) - ms = ParseMilliSeconds (stream); - - // Additional, the timezone - if ( ! stream.EOF) - timezone = ParseTimezone (stream); - - // If there is more, then a format exception - if ( ! stream.EOF) - throw new Exception ("More data then excepted"); - - content = new DateTime (year, month, day, hour, minutes, seconds, ms); - } - catch (Exception ex) - { - throw new ParseException (stream, ex.ToString ()); - } - } - - /// - /// Parse the time (hours, minutes, seconds) - /// - private void ParseTime (ParseStream stream, - out int hour, out int minutes, out int seconds) - { - if (stream.Char == 't' || stream.Char == 'T') - stream.Next (true); - else - SkipWhitespace (stream); - - // Parse hour - // Note: A hour can be represented by one or two digits. - string hulp = ""; - while (stream.Char >= '0' && stream.Char <= '9' && - ! stream.EOF && hulp.Length <= 2) - { - hulp += stream.Char; - stream.Next (true); - } - hour = Int32.Parse (hulp); - - SkipChar (stream, ':'); - - // Parse minutes - minutes = ParseNumber (stream, 2); - SkipChar (stream, ':'); - - // Parse seconds - seconds = ParseNumber (stream, 2); - } - - /// - /// Parse the milliseconds - /// - private int ParseMilliSeconds (ParseStream stream) - { - int ms = 0; - - // Look for fraction - if (stream.Char == '.') - { - stream.Next (true); - - // Parse fraction, can consists of an - // unlimited sequence of numbers, we only - // look to the first three (max 1000) - int count = 0; - - while (stream.Char >= '0' && stream.Char <= '9' && - count < 3 && ! stream.EOF) - { - ms *= 10; - ms += stream.Char - '0'; - - stream.Next (true); - count ++; - } - - if (count == 1) ms *= 100; - if (count == 2) ms *= 10; - if (count == 3) ms *= 1; - - // Ignore the rest - while (stream.Char >= '0' && stream.Char <= '9' && - ! stream.EOF) - stream.Next (true); - } - return ms; - } - - /// - /// Parse the time zone - /// - private double ParseTimezone (ParseStream stream) - { - double timezone = 0; - - SkipWhitespace (stream); - - // Timezone = UTC, use by default 0 - if (stream.Char == 'Z') - stream.Next (true); - else - { - // Find the sign of the offset - int sign = 0; - - if (stream.Char == '-') - sign = -1; - - else if (stream.Char == '+') - sign = +1; - - else - throw new Exception ("Invalid time zone: " + - "unexpected character"); - - // Read next char and test for more chars - stream.Next (true); - if (stream.EOF) - throw new Exception ("Invalid time zone"); - - // Parse hour offset - // Note: A hour can be represented by one or two digits. - string hulp = ""; - while (stream.Char >= '0' && - stream.Char <= '9' && - !stream.EOF && hulp.Length <= 2) - { - hulp += (stream.Char); - stream.Next (true); - } - timezone = sign * Double.Parse (hulp); - - // Parse the minutes of the timezone - // when there is still more to parse - if ( ! stream.EOF) - { - SkipChar (stream, ':'); - int temp = ParseNumber (stream, 2); - - timezone += (temp / 60.0); - } - } - - return timezone; - } - - /// - /// Parse an integer - /// - /// - /// The number of characters that the integer is expected to be. - /// - /// The stream that will be parsed - private int ParseNumber (ParseStream stream, int length) - { - System.Text.StringBuilder hulp = new System.Text.StringBuilder (); - - int i; - for (i = 0; i < length && !stream.EOF; i++) - { - hulp.Append (stream.Char); - stream.Next (true); - } - if (i == length) - return Int32.Parse (hulp.ToString ()); - else - throw new Exception ("Can't parse number"); - - } - - /// - /// Skips a specified char, and throws an exception when - /// another char was found. - /// - private void SkipChar (ParseStream stream, char toSkip) - { - if (stream.Char == toSkip) - stream.Next (true); - else - throw new Exception ("Unexpected character"); - } - - /// - /// Skips the spaces * and tabs * in the current stream - /// - private void SkipWhitespace (ParseStream stream) - { - while ((stream.Char == ' ' || stream.Char == '\t') && ! stream.EOF) - stream.Next (true); - } - - /// Yaml notation for this datetime - private string YamlString () - { - string date = content.ToString ("yyyy-MM-ddTHH:mm:ss"); - int ms = content.Millisecond; - if (ms != 0) - { - string hulp = "" + (ms / 1000.0); - hulp = hulp.Substring(2); // Cut of the '0,', first 2 digits - - date += "." + hulp; - } - string zone = ""; - - if (timezone != 0) - { - int timezoneHour = (int) Math.Floor (timezone); - int timezoneMinutes = (int) (60 * (timezone - timezoneHour)); - - // if positif offset add '+', a '-' is default added - if (timezone > 0) - zone = "+"; - - zone += timezoneHour.ToString (); - if (timezoneMinutes != 0) - zone += ":" + timezoneMinutes; - } - else - zone = "Z"; // UTC timezone as default and if offset == 0 - - return date + zone; - } - - /// Write to YAML - protected internal override void Write (WriteStream stream) - { - stream.Append (YamlString ()); - } - } -} - - diff --git a/thirdparty/yaml/WriteStream.cs b/thirdparty/yaml/WriteStream.cs deleted file mode 100644 index 508250d311..0000000000 --- a/thirdparty/yaml/WriteStream.cs +++ /dev/null @@ -1,121 +0,0 @@ -// ==================================================================================================== -// YAML Parser for the .NET Framework -// ==================================================================================================== -// -// Copyright (c) 2006 -// Christophe Lambrechts -// Jonathan Slenders -// -// ==================================================================================================== -// This file is part of the .NET YAML Parser. -// -// This .NET YAML parser is free software; you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// The .NET YAML parser is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with Foobar; if not, write to the Free Software -// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USAusing System.Reflection; -// ==================================================================================================== - -#define ENABLE_COMPRESSION - -using System; -using System.Collections; - -using System.IO; - -namespace Yaml -{ - /// - /// Help class for writing a Yaml tree to a string - /// - public class WriteStream - { - private TextWriter stream; - private int indentation = 0; - private bool lastcharisnewline = false; - - private static string indentationChars = " "; - - /// Constructor - public WriteStream (TextWriter stream) - { - this.stream = stream; - } - - /// Append a string - public void Append (string s) - { - // Just add the text to the output stream when - // there is no indentation - if (indentation == 0) - stream.Write (s); - - // Otherwise process each individual char - else - for (int i = 0; i < s.Length; i ++) - { - // Indent after a newline - if (lastcharisnewline) - { - WriteIndentation (); - lastcharisnewline = false; - } - - // Add char - stream.Write (s [i]); - - // Remember newlines - if (s [i] == '\n') - lastcharisnewline = true; - } - } - - /// Indentation - public void Indent () - { - // Increase indentation level - indentation ++; - - // Add a newline -#if ENABLE_COMPRESSION - lastcharisnewline = false; -#else - stream.Write ("\n"); - lastcharisnewline = true; -#endif - } - - /// Write the indentation to the output stream - private void WriteIndentation () - { - for (int i = 0; i < indentation; i ++) - stream.Write (indentationChars); - } - - /// Unindent - public void UnIndent () - { - if (indentation > 0) - { - // Decrease indentation level - indentation --; - - // Add a newline - if (! lastcharisnewline) - stream.Write ("\n"); - lastcharisnewline = true; - } - else - throw new Exception ("Cannot unindent a not indented writestream."); - - } - } -} diff --git a/thirdparty/yaml/Yaml.csproj b/thirdparty/yaml/Yaml.csproj deleted file mode 100644 index ee12932481..0000000000 --- a/thirdparty/yaml/Yaml.csproj +++ /dev/null @@ -1,188 +0,0 @@ - - - Local - 9.0.30729 - 2.0 - {D4424F4D-7939-4247-98F5-6A7F6DEBA7C9} - Debug - AnyCPU - - - - - Yaml - - - JScript - Grid - IE50 - false - Library - Yaml - OnBuildSuccess - - - - - 0.0 - - - v3.5 - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - bin\Debug\ - false - 285212672 - false - - - DEBUG;TRACE - - - true - 4096 - false - - - false - false - false - false - 4 - full - prompt - - - .\ - false - 285212672 - false - - - TRACE - - - false - 4096 - false - - - true - false - false - false - 4 - none - prompt - - - - System - - - 3.5 - - - System.Data - - - System.XML - - - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - Code - - - - - False - .NET Framework Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - false - - - - - - - - - - \ No newline at end of file diff --git a/thirdparty/yaml/Yaml.sln b/thirdparty/yaml/Yaml.sln deleted file mode 100644 index a451a53232..0000000000 --- a/thirdparty/yaml/Yaml.sln +++ /dev/null @@ -1,19 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 10.00 -# Visual Studio 2008 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Yaml", "Yaml.csproj", "{D4424F4D-7939-4247-98F5-6A7F6DEBA7C9}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D4424F4D-7939-4247-98F5-6A7F6DEBA7C9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D4424F4D-7939-4247-98F5-6A7F6DEBA7C9}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D4424F4D-7939-4247-98F5-6A7F6DEBA7C9}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D4424F4D-7939-4247-98F5-6A7F6DEBA7C9}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/thirdparty/yaml/test.yaml b/thirdparty/yaml/test.yaml deleted file mode 100644 index 0271bb757e..0000000000 --- a/thirdparty/yaml/test.yaml +++ /dev/null @@ -1,24 +0,0 @@ -? boolean: y -? float: 8.6e2 -? integer: 174832 -? null: ~ -? inline sequence: [item1, item2] -? inline mappings: {key: value, key2: value2} -? sequence: - - item 1 - - item 2 -? tricky situations: - - ? block scalar: | - regel 1 - regel 2 - - ? folded scalar: > - regel 1 - nog steeds regel 1 - - ? double quoted: "met veel escapes aa\"bb\n\'cc" - - ? met tags: - - !!int 2 - - !!string 2 - - !!float 2 - - { key: value, key 3: "{a: b}", key 2: a } - - ? [aaa]: bbb - - ? single quotes: 'regel 1 regel 2' diff --git a/units.ini b/units.ini index 089a0be145..7ba96ffe10 100644 --- a/units.ini +++ b/units.ini @@ -353,9 +353,10 @@ Dimensions=2,2 Footprint=xx xx SelectionPriority=3 LongDesc=Provides Allied advanced technologies.\n Special Ability: GPS Satellite +AlternateName=@Tech Center [WEAP] Description=War Factory -Traits=Building, RenderWarFactory, RenderBuilding, RallyPoint, Production, IronCurtainable +Traits=Building, RenderBuilding, RenderWarFactory, RallyPoint, Production, IronCurtainable Dimensions=3,2 Footprint=xxx xxx Produces=Vehicle @@ -380,7 +381,7 @@ SelectionPriority=3 LongDesc=Produces and repairs submarines and \ntransports [FACT] Description=Construction Yard -Traits=Building, RenderBuilding, ConstructionYard, IronCurtainable +Traits=Building, RenderBuilding, Production, ConstructionYard, IronCurtainable Dimensions=3,3 Footprint=xxx xxx xxx Produces=Building,Defense @@ -448,6 +449,7 @@ Dimensions=3,2 Footprint=xxx xxx SelectionPriority=3 LongDesc=Provides Soviet advanced technologies +AlternateName=@Tech Center [BARR] Description=Soviet Barracks Traits=Building, RenderBuilding, RallyPoint, Production, IronCurtainable @@ -898,4 +900,4 @@ LongDesc=Makes a single unit invulnerable for a \nshort time. Image=infxicon Prerequisite=IRON TechLevel=12 -Impl=IronCurtainPower +Impl=IronCurtainPower