merged yaml

This commit is contained in:
Chris Forbes
2010-01-10 22:51:09 +13:00
137 changed files with 4508 additions and 5099 deletions

58
OpenRa.FileFormats/MiniYaml.cs Executable file
View File

@@ -0,0 +1,58 @@
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<string, MiniYaml> Nodes = new Dictionary<string,MiniYaml>();
public MiniYaml( string value ) : this( value, new Dictionary<string, MiniYaml>() ) { }
public MiniYaml( string value, Dictionary<string, MiniYaml> nodes )
{
Value = value;
Nodes = nodes;
}
public static Dictionary<string, MiniYaml> FromFile( string path )
{
var lines = File.ReadAllLines( path );
var levels = new List<Dictionary<string, MiniYaml>>();
levels.Add( new Dictionary<string, MiniYaml>() );
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<string, MiniYaml>();
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 ];
}
}
}

View File

@@ -57,6 +57,7 @@
<Compile Include="IniWriter.cs" />
<Compile Include="IPaletteRemap.cs" />
<Compile Include="Map.cs" />
<Compile Include="MiniYaml.cs" />
<Compile Include="PackageEntry.cs" />
<Compile Include="Package.cs" />
<Compile Include="Palette.cs" />

View File

@@ -12,7 +12,10 @@ namespace OpenRa.Game
{
[Sync]
public readonly TypeDictionary traits = new TypeDictionary();
public readonly UnitInfo Info;
[Obsolete]
public readonly LegacyUnitInfo LegacyInfo;
public readonly NewUnitInfo Info;
public readonly uint ActorID;
[Sync]
@@ -23,33 +26,25 @@ 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 )
{
ActorID = Game.world.NextAID();
Info = (UnitInfo)info; // temporary
LegacyInfo = (LegacyUnitInfo)info; // temporary
Location = location;
CenterLocation = Traits.Util.CenterOfCell(Location);
Owner = owner;
if (Info == null) return;
if (LegacyInfo == null) return;
Health = Info.Strength; /* todo: fix walls, etc so this is always true! */
Health = LegacyInfo.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) );
if( LegacyInfo.Traits == null )
throw new InvalidOperationException( "No Actor traits for {0}; add Traits= to units.ini for appropriate unit".F(LegacyInfo.Name) );
foreach (var traitName in Info.Traits)
traits.Add(ConstructTrait(traitName));
Info = Rules.NewUnitInfo[LegacyInfo.Name.ToLowerInvariant()];
foreach (var trait in Info.Traits.WithInterface<ITraitInfo>())
traits.Add(trait.Create(this));
}
public void Tick()
@@ -75,8 +70,8 @@ namespace OpenRa.Game
{
get
{
if (Info != null && Info.SelectionSize != null)
return new float2(Info.SelectionSize[0], Info.SelectionSize[1]);
if (LegacyInfo != null && LegacyInfo.SelectionSize != null)
return new float2(LegacyInfo.SelectionSize[0], LegacyInfo.SelectionSize[1]);
var firstSprite = Render().FirstOrDefault();
if (firstSprite.Sprite == null) return float2.Zero;
@@ -102,7 +97,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.LegacyInfo.Selectable)
underCursor = null;
return traits.WithInterface<IIssueOrder>()
@@ -114,8 +109,8 @@ namespace OpenRa.Game
{
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 (LegacyInfo != null && LegacyInfo.SelectionSize != null && LegacyInfo.SelectionSize.Length > 2)
loc += new float2(LegacyInfo.SelectionSize[2], LegacyInfo.SelectionSize[3]);
if (useAltitude)
{
@@ -132,7 +127,7 @@ namespace OpenRa.Game
public DamageState GetDamageState()
{
if (Health <= 0) return DamageState.Dead;
var halfStrength = Info.Strength * Rules.General.ConditionYellow;
var halfStrength = LegacyInfo.Strength * Rules.General.ConditionYellow;
return Health < halfStrength ? DamageState.Half : DamageState.Normal;
}
@@ -155,8 +150,8 @@ namespace OpenRa.Game
Game.world.AddFrameEndTask(w => w.Remove(this));
}
if (Health > Info.Strength)
Health = Info.Strength;
if (Health > LegacyInfo.Strength)
Health = LegacyInfo.Strength;
var newState = GetDamageState();

View File

@@ -216,7 +216,7 @@ namespace OpenRa.Game
{
var hasNewRadar = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<ProvidesRadar>()
&& a.traits.Get<ProvidesRadar>().IsActive());
&& a.traits.Get<ProvidesRadar>().IsActive(a));
if (hasNewRadar != hasRadar)
{
@@ -738,7 +738,7 @@ namespace OpenRa.Game
DrawRightAligned( "${0}".F(info.Cost), pos + new int2(-5,5),
Game.LocalPlayer.Cash + Game.LocalPlayer.Ore >= info.Cost ? Color.White : Color.Red);
var bi = info as BuildingInfo;
var bi = info as LegacyBuildingInfo;
if (bi != null)
DrawRightAligned("ϟ{0}".F(bi.Power), pos + new int2(-5, 20),
Game.LocalPlayer.PowerProvided - Game.LocalPlayer.PowerDrained + bi.Power >= 0

View File

@@ -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.LegacyInfo.Armor);
return rawDamage * multiplier;
}
@@ -59,7 +59,7 @@ namespace OpenRa.Game
var warhead = Rules.WarheadInfo[weapon.Warhead];
var unit = target.traits.GetOrDefault<Unit>();
if (warhead.EffectivenessAgainst(target.Info.Armor) <= 0)
if (warhead.EffectivenessAgainst(target.LegacyInfo.Armor) <= 0)
return false;
if (target.traits.Contains<Submarine>())
@@ -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.LegacyInfo.WaterBound)
return false;
return projectile.AG;
@@ -76,10 +76,10 @@ 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;
if (self.LegacyInfo.Primary != null &&
WeaponValidForTarget(Rules.WeaponInfo[self.LegacyInfo.Primary], target)) return true;
if (self.LegacyInfo.Secondary != null &&
WeaponValidForTarget(Rules.WeaponInfo[self.LegacyInfo.Secondary], target)) return true;
return false;
}

View File

@@ -15,7 +15,8 @@ namespace OpenRa.Game.Effects
public Corpse(Actor fromActor, int death)
{
anim = new Animation(fromActor.Info.Image ?? fromActor.Info.Name);
var info = fromActor.Info.Traits.WithInterface<RenderSimpleInfo>().First();
anim = new Animation(info.Image ?? fromActor.Info.Name);
anim.PlayThen("die{0}".F(death + 1),
() => Game.world.AddFrameEndTask(w => w.Remove(this)));

View File

@@ -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.LegacyInfo != null)
a.Owner.Shroud.Explore(a);
};
@@ -311,8 +311,8 @@ namespace OpenRa.Game
public static IEnumerable<Actor> 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.LegacyInfo.Selectable )
.GroupBy(x => (x.Owner == LocalPlayer) ? x.LegacyInfo.SelectionPriority : 0)
.OrderByDescending(g => g.Key)
.Select( g => g.AsEnumerable() )
.DefaultIfEmpty( new Actor[] {} )
@@ -322,7 +322,7 @@ 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(LegacyBuildingInfo building, int2 xy, Actor toIgnore, bool adjust)
{
return !Footprint.Tiles(building, xy, adjust).Any(
t => !Rules.Map.IsInMap(t.X, t.Y) || Rules.Map.ContainsResource(t) || !Game.IsCellBuildable(t,
@@ -330,7 +330,7 @@ namespace OpenRa.Game
toIgnore));
}
public static bool IsCloseEnoughToBase(Player p, BuildingInfo bi, int2 position)
public static bool IsCloseEnoughToBase(Player p, LegacyBuildingInfo bi, int2 position)
{
var maxDistance = bi.Adjacent + 1;
@@ -339,7 +339,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.LegacyInfo as LegacyBuildingInfo).BaseNormal) return 0;
if ((loc - position).Length > maxDistance)
return float.PositiveInfinity; /* not quite right */
return 1;

View File

@@ -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<string, MiniYaml> 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() ) );
}
}

View File

@@ -6,12 +6,12 @@ namespace OpenRa.Game.GameRules
{
static class Footprint
{
public static IEnumerable<int2> Tiles( BuildingInfo buildingInfo, int2 position )
public static IEnumerable<int2> Tiles( LegacyBuildingInfo buildingInfo, int2 position )
{
return Tiles(buildingInfo, position, true);
}
public static IEnumerable<int2> Tiles( BuildingInfo buildingInfo, int2 position, bool adjustForPlacement )
public static IEnumerable<int2> Tiles( LegacyBuildingInfo buildingInfo, int2 position, bool adjustForPlacement )
{
var dim = buildingInfo.Dimensions;
@@ -33,7 +33,7 @@ namespace OpenRa.Game.GameRules
return Tiles( building.unitInfo, a.Location, false );
}
public static IEnumerable<int2> UnpathableTiles( BuildingInfo buildingInfo, int2 position )
public static IEnumerable<int2> UnpathableTiles( LegacyBuildingInfo 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' ) )
@@ -52,7 +52,7 @@ namespace OpenRa.Game.GameRules
yield return new int2( x, y );
}
public static int2 AdjustForBuildingSize( BuildingInfo unitInfo )
public static int2 AdjustForBuildingSize( LegacyBuildingInfo unitInfo )
{
var dim = unitInfo.Dimensions;
return new int2( dim.X / 2, dim.Y > 1 ? ( dim.Y + 1 ) / 2 : 0 );

View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRa.FileFormats;
using OpenRa.Game.Traits;
namespace OpenRa.Game.GameRules
{
class NewUnitInfo
{
public readonly string Parent;
public readonly TypeDictionary Traits = new TypeDictionary();
public readonly string Name;
public NewUnitInfo( string name, MiniYaml node )
{
Name = name;
// todo: make inheritance actually work
MiniYaml inherit;
if( node.Nodes.TryGetValue( "Inherits", out inherit ) )
{
Parent = inherit.Value;
node.Nodes.Remove( "Inherits" );
}
foreach (var t in node.Nodes)
Traits.Add(LoadTraitInfo(t.Key, t.Value));
}
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;
}
}
}

View File

@@ -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,7 @@ namespace OpenRa.Game
public static IniFile AllRules;
public static Dictionary<string, List<string>> Categories = new Dictionary<string, List<string>>();
public static Dictionary<string, string> UnitCategory;
public static InfoLoader<UnitInfo> UnitInfo;
public static InfoLoader<LegacyUnitInfo> UnitInfo;
public static InfoLoader<WeaponInfo> WeaponInfo;
public static InfoLoader<WarheadInfo> WarheadInfo;
public static InfoLoader<ProjectileInfo> ProjectileInfo;
@@ -24,6 +25,8 @@ namespace OpenRa.Game
public static Map Map;
public static TileSet TileSet;
public static Dictionary<string, NewUnitInfo> NewUnitInfo;
public static void LoadRules(string mapFileName, bool useAftermath)
{
if( useAftermath )
@@ -61,13 +64,13 @@ namespace OpenRa.Game
"Plane");
UnitCategory = Categories.SelectMany(x => x.Value.Select(y => new KeyValuePair<string, string>(y, x.Key))).ToDictionary(x => x.Key, x => x.Value);
UnitInfo = new InfoLoader<UnitInfo>(
Pair.New<string, Func<string, UnitInfo>>("Building", s => new BuildingInfo(s)),
Pair.New<string, Func<string, UnitInfo>>("Defense", s => new BuildingInfo(s)),
Pair.New<string, Func<string, UnitInfo>>("Infantry", s => new InfantryInfo(s)),
Pair.New<string, Func<string, UnitInfo>>("Vehicle", s => new VehicleInfo(s)),
Pair.New<string, Func<string, UnitInfo>>("Ship", s => new VehicleInfo(s)),
Pair.New<string, Func<string, UnitInfo>>("Plane", s => new VehicleInfo(s)));
UnitInfo = new InfoLoader<LegacyUnitInfo>(
Pair.New<string, Func<string, LegacyUnitInfo>>("Building", s => new LegacyBuildingInfo(s)),
Pair.New<string, Func<string, LegacyUnitInfo>>("Defense", s => new LegacyBuildingInfo(s)),
Pair.New<string, Func<string, LegacyUnitInfo>>("Infantry", s => new InfantryInfo(s)),
Pair.New<string, Func<string, LegacyUnitInfo>>("Vehicle", s => new VehicleInfo(s)),
Pair.New<string, Func<string, LegacyUnitInfo>>("Ship", s => new VehicleInfo(s)),
Pair.New<string, Func<string, LegacyUnitInfo>>("Plane", s => new VehicleInfo(s)));
LoadCategories(
"Weapon",
@@ -91,6 +94,10 @@ namespace OpenRa.Game
Map = new Map( AllRules );
FileSystem.MountTemporary( new Package( Rules.Map.Theater + ".mix" ) );
TileSet = new TileSet( Map.TileSuffix );
NewUnitInfo = new Dictionary<string, NewUnitInfo>();
foreach( var kv in MiniYaml.FromFile( "ra.yaml" ) )
NewUnitInfo.Add(kv.Key.ToLowerInvariant(), new NewUnitInfo(kv.Key.ToLowerInvariant(), kv.Value));
}
static void LoadCategories(params string[] types)

View File

@@ -6,13 +6,13 @@ namespace OpenRa.Game.GameRules
{
class TechTree
{
readonly Cache<string, List<UnitInfo>> producesIndex = new Cache<string, List<UnitInfo>>( x => new List<UnitInfo>() );
readonly Cache<string, List<LegacyUnitInfo>> producesIndex = new Cache<string, List<LegacyUnitInfo>>( x => new List<LegacyUnitInfo>() );
public TechTree()
{
foreach( var b in Rules.Categories[ "Building" ] )
{
var info = (BuildingInfo)Rules.UnitInfo[ b ];
var info = (LegacyBuildingInfo)Rules.UnitInfo[ b ];
foreach( var p in info.Produces )
producesIndex[ p ].Add( info );
}
@@ -21,12 +21,12 @@ namespace OpenRa.Game.GameRules
public Cache<string, List<Actor>> GatherBuildings( Player player )
{
var ret = new Cache<string, List<Actor>>( x => new List<Actor>() );
foreach( var b in Game.world.Actors.Where( x => x.Owner == player && x.Info is BuildingInfo ) )
ret[ b.Info.Name ].Add( b );
foreach( var b in Game.world.Actors.Where( x => x.Owner == player && x.LegacyInfo is LegacyBuildingInfo ) )
ret[ b.LegacyInfo.Name ].Add( b );
return ret;
}
public bool CanBuild( UnitInfo unit, Player player, Cache<string, List<Actor>> playerBuildings )
public bool CanBuild( LegacyUnitInfo unit, Player player, Cache<string, List<Actor>> playerBuildings )
{
if( unit.TechLevel == -1 )
return false;
@@ -59,7 +59,7 @@ namespace OpenRa.Game.GameRules
.Where(x => Rules.UnitInfo[x].Owner.Contains(player.Race)); /* todo: fix for dual-race scenarios (captured buildings) */
}
public IEnumerable<UnitInfo> UnitBuiltAt( UnitInfo info )
public IEnumerable<LegacyUnitInfo> UnitBuiltAt( LegacyUnitInfo info )
{
if( info.BuiltAt.Length != 0 )
return info.BuiltAt.Select( x => Rules.UnitInfo[ x.ToLowerInvariant() ] );

View File

@@ -11,7 +11,7 @@ namespace OpenRa.Game.GameRules
concrete = 4,
}
public class UnitInfo : ActorInfo
public class LegacyUnitInfo : ActorInfo
{
public readonly string Name;
@@ -64,19 +64,19 @@ namespace OpenRa.Game.GameRules
public readonly int[] PrimaryLocalOffset = { };
public readonly int[] SecondaryLocalOffset = { };
public UnitInfo(string name) { Name = name; }
public LegacyUnitInfo(string name) { Name = name; }
}
public class MobileInfo : UnitInfo
public class LegacyMobileInfo : LegacyUnitInfo
{
public readonly int Speed = 0;
public readonly bool NoMovingFire = false;
public readonly string Voice = "GenericVoice";
public MobileInfo(string name) : base(name) { }
public LegacyMobileInfo(string name) : base(name) { }
}
public class InfantryInfo : MobileInfo
public class InfantryInfo : LegacyMobileInfo
{
public readonly bool C4 = false;
public readonly bool FraidyCat = false;
@@ -87,14 +87,14 @@ namespace OpenRa.Game.GameRules
public InfantryInfo(string name) : base(name) { }
}
public class VehicleInfo : MobileInfo
public class VehicleInfo : LegacyMobileInfo
{
public readonly bool Tracked = false;
public VehicleInfo(string name) : base(name) { }
}
public class BuildingInfo : UnitInfo
public class LegacyBuildingInfo : LegacyUnitInfo
{
public readonly int2 Dimensions = new int2(1, 1);
public readonly string Footprint = "x";
@@ -112,6 +112,6 @@ namespace OpenRa.Game.GameRules
public readonly int[] RallyPoint = { 1, 3 };
public readonly float[] SpawnOffset = null;
public BuildingInfo(string name) : base(name) { }
public LegacyBuildingInfo(string name) : base(name) { }
}
}

View File

@@ -97,7 +97,7 @@ namespace OpenRa.Game.Graphics
public void GoToStartLocation()
{
Center(Game.world.Actors.Where(a => a.Info != null && a.Owner == Game.LocalPlayer));
Center(Game.world.Actors.Where(a => a.LegacyInfo != null && a.Owner == Game.LocalPlayer));
}
}
}

View File

@@ -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.LegacyInfo.Strength;
var healthColor = (healthAmount < Rules.General.ConditionRed) ? Color.Red
: (healthAmount < Rules.General.ConditionYellow) ? Color.Yellow
: Color.LimeGreen;

View File

@@ -95,6 +95,7 @@
<Compile Include="GameRules\ActorInfo.cs" />
<Compile Include="GameRules\AftermathInfo.cs" />
<Compile Include="GameRules\GeneralInfo.cs" />
<Compile Include="GameRules\NewUnitInfo.cs" />
<Compile Include="GameRules\SupportPowerInfo.cs" />
<Compile Include="GameRules\TechTree.cs" />
<Compile Include="GameRules\UserSettings.cs" />
@@ -216,6 +217,7 @@
<Compile Include="Traits\AutoHeal.cs" />
<Compile Include="Traits\AutoTarget.cs" />
<Compile Include="Traits\BelowUnits.cs" />
<Compile Include="Traits\Buildable.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\C4Demolition.cs" />
<Compile Include="Traits\Cargo.cs" />
@@ -241,6 +243,7 @@
<Compile Include="Traits\ProvidesRadar.cs" />
<Compile Include="Traits\Repairable.cs" />
<Compile Include="Traits\Reservable.cs" />
<Compile Include="Traits\Selectable.cs" />
<Compile Include="Traits\SquishByTank.cs" />
<Compile Include="Traits\Plane.cs" />
<Compile Include="Traits\ProductionQueue.cs" />
@@ -269,7 +272,6 @@
<Compile Include="Traits\TakeCover.cs" />
<Compile Include="Traits\Thief.cs" />
<Compile Include="Traits\TraitsInterfaces.cs" />
<Compile Include="Traits\Tree.cs" />
<Compile Include="Traits\Turreted.cs" />
<Compile Include="Traits\Unit.cs" />
<Compile Include="Traits\WaterPaletteRotation.cs" />

View File

@@ -31,9 +31,9 @@ namespace OpenRa.Game.Orders
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.WithInterface<Chronoshiftable>().Any()
&& a.Info.Selectable).FirstOrDefault();
&& a.LegacyInfo.Selectable).FirstOrDefault();
var unit = underCursor != null ? underCursor.Info as UnitInfo : null;
var unit = underCursor != null ? underCursor.LegacyInfo as LegacyUnitInfo : null;
if (unit != null)
yield return new Order("ChronosphereSelect", underCursor, null, int2.Zero, power.Name);

View File

@@ -31,9 +31,9 @@ namespace OpenRa.Game.Orders
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<IronCurtainable>()
&& a.Info.Selectable).FirstOrDefault();
&& a.LegacyInfo.Selectable).FirstOrDefault();
var unit = underCursor != null ? underCursor.Info as UnitInfo : null;
var unit = underCursor != null ? underCursor.LegacyInfo as LegacyUnitInfo : null;
if (unit != null)
yield return new Order("IronCurtain", underCursor, null, int2.Zero, power.Name);

View File

@@ -6,12 +6,12 @@ namespace OpenRa.Game.Orders
class PlaceBuildingOrderGenerator : IOrderGenerator
{
readonly Actor Producer;
readonly BuildingInfo Building;
readonly LegacyBuildingInfo Building;
public PlaceBuildingOrderGenerator(Actor producer, string name)
{
Producer = producer;
Building = (BuildingInfo)Rules.UnitInfo[ name ];
Building = (LegacyBuildingInfo)Rules.UnitInfo[ name ];
}
public IEnumerable<Order> Order(int2 xy, MouseInput mi)

View File

@@ -25,9 +25,9 @@ namespace OpenRa.Game.Orders
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>()
&& a.Info.Selectable).FirstOrDefault();
&& a.LegacyInfo.Selectable).FirstOrDefault();
var building = underCursor != null ? underCursor.Info as BuildingInfo : null;
var building = underCursor != null ? underCursor.LegacyInfo as LegacyBuildingInfo : null;
if (building != null)
yield return new Order("PowerDown", underCursor, null, int2.Zero, null);

View File

@@ -25,9 +25,9 @@ namespace OpenRa.Game.Orders
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>()
&& a.Info.Selectable).FirstOrDefault();
&& a.LegacyInfo.Selectable).FirstOrDefault();
var building = underCursor != null ? underCursor.Info as BuildingInfo : null;
var building = underCursor != null ? underCursor.LegacyInfo as LegacyBuildingInfo : null;
if (building != null && building.Repairable && underCursor.Health < building.Strength)
yield return new Order("Repair", underCursor, null, int2.Zero, null);

View File

@@ -25,9 +25,9 @@ namespace OpenRa.Game.Orders
var underCursor = Game.FindUnits(loc, loc)
.Where(a => a.Owner == Game.LocalPlayer
&& a.traits.Contains<Building>()
&& a.Info.Selectable).FirstOrDefault();
&& a.LegacyInfo.Selectable).FirstOrDefault();
var building = underCursor != null ? underCursor.Info as BuildingInfo : null;
var building = underCursor != null ? underCursor.LegacyInfo as LegacyBuildingInfo : null;
if (building != null && !building.Unsellable)
yield return new Order("Sell", underCursor, null, int2.Zero, null);

View File

@@ -69,7 +69,7 @@ namespace OpenRa.Game.Orders
else
return Cursor.MoveBlocked;
case "DeployMcv":
var factBuildingInfo = (BuildingInfo)Rules.UnitInfo["fact"];
var factBuildingInfo = (LegacyBuildingInfo)Rules.UnitInfo["fact"];
if (Game.CanPlaceBuilding(factBuildingInfo, a.Location - new int2(1, 1), a, false))
return Cursor.Deploy;
else

View File

@@ -16,7 +16,7 @@ namespace OpenRa.Game.Orders
Game.world.AddFrameEndTask( _ =>
{
var queue = order.Player.PlayerActor.traits.Get<Traits.ProductionQueue>();
var building = (BuildingInfo)Rules.UnitInfo[ order.TargetString ];
var building = (LegacyBuildingInfo)Rules.UnitInfo[ order.TargetString ];
var producing = queue.CurrentItem(Rules.UnitCategory[order.TargetString]);
if( producing == null || producing.Item != order.TargetString || producing.RemainingTime != 0 )
return;

View File

@@ -84,7 +84,7 @@ namespace OpenRa.Game
{
OreCapacity = Game.world.Actors
.Where(a => a.Owner == this && a.traits.Contains<StoresOre>())
.Select(a => a.Info as BuildingInfo)
.Select(a => a.LegacyInfo as LegacyBuildingInfo)
.Where(b => b != null)
.Sum(b => b.Storage);
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using IjwFramework.Types;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game
{
@@ -32,7 +33,7 @@ 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.LegacyInfo.Sight))
explored[t.X, t.Y] = true;
dirty = true;

View File

@@ -92,7 +92,7 @@ namespace OpenRa.Game
{
if (voicedUnit == null) return;
var mi = voicedUnit.Info as MobileInfo;
var mi = voicedUnit.LegacyInfo as LegacyMobileInfo;
if (mi == null) return;
var vi = Rules.VoiceInfo[mi.Voice];

View File

@@ -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<string, PerfItem> items = new Cache<string, PerfItem>(

View File

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

View File

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

View File

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

View File

@@ -19,7 +19,7 @@ namespace OpenRa.Game.Traits.Activities
if (target.Owner == self.Owner)
{
if (target.Health == target.Info.Strength)
if (target.Health == target.LegacyInfo.Strength)
return NextActivity;
target.InflictDamage(self, -EngineerCapture.EngineerDamage, Rules.WarheadInfo["Super"]);
}

View File

@@ -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.LegacyInfo.ROT);
var speed = .2f * Util.GetEffectiveSpeed(self);
var angle = unit.Facing / 128f * Math.PI;

View File

@@ -30,11 +30,11 @@ namespace OpenRa.Game.Traits.Activities
return this;
}
var range = Rules.WeaponInfo[ self.Info.Primary ].Range - 1;
var range = Rules.WeaponInfo[ self.LegacyInfo.Primary ].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.LegacyInfo.ROT);
if (!float2.WithinEpsilon(float2.Zero, dist, range * Game.CellSize))
{

View File

@@ -39,7 +39,7 @@ 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.LegacyInfo.ROT);
var rawSpeed = .2f * Util.GetEffectiveSpeed(self);
self.CenterLocation += (rawSpeed / dist.Length) * dist;

View File

@@ -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));
}
@@ -26,7 +26,7 @@ namespace OpenRa.Game.Traits.Activities
if (dest == null)
return Util.SequenceActivities(
new Turn(self.Info.InitialFacing),
new Turn(self.LegacyInfo.InitialFacing),
new HeliLand(true),
NextActivity);
@@ -34,12 +34,12 @@ namespace OpenRa.Game.Traits.Activities
if (res != null)
self.traits.Get<Helicopter>().reservation = res.Reserve(self);
var offset = (dest.Info as BuildingInfo).SpawnOffset;
var offset = (dest.LegacyInfo as LegacyBuildingInfo).SpawnOffset;
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(self.LegacyInfo.InitialFacing),
new HeliLand(false),
new Rearm(),
NextActivity);

View File

@@ -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.LegacyInfo.ROT);
var speed = .2f * Util.GetEffectiveSpeed(self);
var angle = unit.Facing / 128f * Math.PI;

View File

@@ -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<BuildableInfo>().Cost;
var hp = self.Info.Traits.WithInterface<OwnedActorInfo>().First().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)

View File

@@ -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.LegacyInfo == Rules.UnitInfo["AFLD"] /* todo: generalize this */
&& a.Owner == self.Owner
&& !Reservable.IsReserved(a))
.FirstOrDefault();
@@ -41,7 +41,7 @@ namespace OpenRa.Game.Traits.Activities
var unit = self.traits.Get<Unit>();
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.LegacyInfo.ROT) * speed / (float)Math.PI;
/* work out the center points */
var fwd = -float2.FromAngle(unit.Facing / 128f * (float)Math.PI);

View File

@@ -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<BuildableInfo>().Cost;
var hp = self.Info.Traits.WithInterface<OwnedActorInfo>().First().HP;
var refund = Rules.General.RefundPercent * self.Health * cost / hp;
self.Owner.GiveCash((int)refund);
self.Health = 0;

View File

@@ -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.LegacyInfo.ROT );
return this;
}

View File

@@ -33,8 +33,8 @@ 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<Unit>();
if (unit != null && unit.Facing != self.Info.UnloadFacing)
return new Turn(self.Info.UnloadFacing) { NextActivity = this };
if (unit != null && unit.Facing != self.LegacyInfo.UnloadFacing)
return new Turn(self.LegacyInfo.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.

View File

@@ -6,6 +6,20 @@ 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 virtual object Create(Actor self) { return new AttackBase(self); }
}
class AttackBase : IIssueOrder, IResolveOrder, ITick
{
[Sync] public Actor target;
@@ -23,8 +37,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.LegacyInfo.Primary != null ? Rules.WeaponInfo[self.LegacyInfo.Primary] : null;
var secondaryWeapon = self.LegacyInfo.Secondary != null ? Rules.WeaponInfo[self.LegacyInfo.Secondary] : null;
primaryBurst = primaryWeapon != null ? primaryWeapon.Burst : 1;
secondaryBurst = secondaryWeapon != null ? secondaryWeapon.Burst : 1;
@@ -74,18 +88,18 @@ namespace OpenRa.Game.Traits
{
var unit = self.traits.GetOrDefault<Unit>();
if (self.Info.Primary != null && CheckFire(self, unit, self.Info.Primary, ref primaryFireDelay,
self.Info.PrimaryOffset, ref primaryBurst, self.Info.PrimaryLocalOffset))
if (self.LegacyInfo.Primary != null && CheckFire(self, unit, self.LegacyInfo.Primary, ref primaryFireDelay,
self.LegacyInfo.PrimaryOffset, ref primaryBurst, self.LegacyInfo.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 (self.LegacyInfo.Secondary != null && CheckFire(self, unit, self.LegacyInfo.Secondary, ref secondaryFireDelay,
self.LegacyInfo.SecondaryOffset ?? self.LegacyInfo.PrimaryOffset, ref secondaryBurst, self.LegacyInfo.SecondaryLocalOffset))
{
if (self.Info.SecondaryOffset != null) secondaryRecoil = 1;
if (self.LegacyInfo.SecondaryOffset != null) secondaryRecoil = 1;
else primaryRecoil = 1;
return;
}
@@ -127,7 +141,7 @@ namespace OpenRa.Game.Traits
var thisTarget = target; // closure.
var destUnit = thisTarget.traits.GetOrDefault<Unit>();
ScheduleDelayedAction(self.Info.FireDelay, () =>
ScheduleDelayedAction(self.LegacyInfo.FireDelay, () =>
{
var srcAltitude = unit != null ? unit.Altitude : 0;
var destAltitude = destUnit != null ? destUnit.Altitude : 0;
@@ -161,7 +175,7 @@ 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 = Rules.WeaponInfo[self.LegacyInfo.Primary].Damage < 0;
if (((underCursor.Owner == self.Owner) ^ isHeal)
&& !mi.Modifiers.HasModifier( Modifiers.Ctrl )) return null;
if (!Combat.HasAnyValidWeapons(self, underCursor)) return null;
@@ -186,7 +200,7 @@ 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.LegacyInfo.Primary ?? order.Subject.LegacyInfo.Secondary;
self.QueueActivity(new Activities.Attack(order.TargetActor,
Math.Max(0, (int)Rules.WeaponInfo[weapon].Range - RangeTolerance)));

View File

@@ -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) { }

View File

@@ -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) { }

View File

@@ -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<Turreted>(); }
public AttackTurreted(Actor self) : base(self) { }
public override void Tick(Actor self)
{
@@ -31,7 +36,7 @@ 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.LegacyInfo.Primary ?? order.Subject.LegacyInfo.Secondary;
if (self.traits.Contains<Mobile>())
self.QueueActivity( new Traits.Activities.Follow( order.TargetActor,

View File

@@ -3,10 +3,10 @@ using OpenRa.Game.Traits.Activities;
namespace OpenRa.Game.Traits
{
class AutoHealInfo : StatelessTraitInfo<AutoHeal> { }
class AutoHeal : ITick
{
public AutoHeal(Actor self) { }
void AttackTarget(Actor self, Actor target)
{
var attack = self.traits.WithInterface<AttackBase>().First();
@@ -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<AttackBase>().First();
var range = GetMaximumRange(self);
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.WithInterface<OwnedActorInfo>().First().HP)
return true; // fully healed
return false;
@@ -42,7 +35,7 @@ namespace OpenRa.Game.Traits
public void Tick(Actor self)
{
var attack = self.traits.WithInterface<AttackBase>().First();
var range = GetMaximumRange(self);
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.LegacyInfo.Strength)
.OrderBy(a => (a.Location - self.Location).LengthSquared)
.FirstOrDefault();
}

View File

@@ -2,10 +2,10 @@
namespace OpenRa.Game.Traits
{
class AutoTargetInfo : StatelessTraitInfo<AutoTarget> { }
class AutoTarget : ITick, INotifyDamage
{
public AutoTarget(Actor self) {}
void AttackTarget(Actor self, Actor target)
{
var attack = self.traits.WithInterface<AttackBase>().First();
@@ -13,19 +13,12 @@ namespace OpenRa.Game.Traits
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<AttackBase>().First();
var range = GetMaximumRange(self);
var range = Util.GetMaximumRange(self);
if (attack.target == null ||
(attack.target.Location - self.Location).LengthSquared > range * range + 2)

View File

@@ -3,10 +3,10 @@ using System.Linq;
namespace OpenRa.Game.Traits
{
class BelowUnitsInfo : StatelessTraitInfo<BelowUnits> { }
class BelowUnits : IRenderModifier
{
public BelowUnits(Actor self) { }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
{
return r.Select(a => a.WithZOffset(-1));

21
OpenRa.Game/Traits/Buildable.cs Executable file
View File

@@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Game.Traits
{
class BuildableInfo : StatelessTraitInfo<Buildable>
{
public readonly int TechLevel = -1;
public readonly string Tab = null;
public readonly string[] Prerequisites = { };
public readonly Race[] Owner = { };
public readonly int Cost = 0;
public readonly string Description = "";
public readonly string LongDesc = "";
public readonly string Icon = null;
}
class Buildable { }
}

View File

@@ -9,10 +9,35 @@ 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 InitialFacing = 128;
}
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 WaterBound = false;
public object Create(Actor self) { return new Building(self); }
}
class Building : INotifyDamage, IResolveOrder, ITick
{
readonly Actor self;
public readonly BuildingInfo unitInfo;
public readonly LegacyBuildingInfo unitInfo;
[Sync]
bool isRepairing = false;
[Sync]
@@ -24,7 +49,7 @@ namespace OpenRa.Game.Traits
public Building(Actor self)
{
this.self = self;
unitInfo = (BuildingInfo)self.Info;
unitInfo = (LegacyBuildingInfo)self.LegacyInfo;
self.CenterLocation = Game.CellSize
* ((float2)self.Location + .5f * (float2)unitInfo.Dimensions);
}
@@ -79,8 +104,8 @@ 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 costPerHp = (Rules.General.URepairPercent * self.LegacyInfo.Cost) / self.LegacyInfo.Strength;
var hpToRepair = Math.Min(Rules.General.URepairStep, self.LegacyInfo.Strength - self.Health);
var cost = (int)Math.Ceiling(costPerHp * hpToRepair);
if (!self.Owner.TakeCash(cost))
{
@@ -90,7 +115,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 == self.LegacyInfo.Strength)
{
isRepairing = false;
return;

View File

@@ -2,10 +2,10 @@
namespace OpenRa.Game.Traits
{
class C4DemolitionInfo : StatelessTraitInfo<C4Demolition> { }
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;

View File

@@ -7,6 +7,14 @@ using OpenRa.Game.Traits.Activities;
namespace OpenRa.Game.Traits
{
class CargoInfo : ITraitInfo
{
public readonly UnitMovementType[] PassengerTypes = { };
public readonly int UnloadFacing = 0;
public object Create(Actor self) { return new Cargo(self); }
}
class Cargo : IPips, IIssueOrder, IResolveOrder
{
List<Actor> cargo = new List<Actor>();
@@ -39,7 +47,7 @@ namespace OpenRa.Game.Traits
public bool IsFull(Actor self)
{
return cargo.Count == self.Info.Passengers;
return cargo.Count == self.LegacyInfo.Passengers;
}
public bool IsEmpty(Actor self)
@@ -56,7 +64,7 @@ namespace OpenRa.Game.Traits
public IEnumerable<PipType> GetPips( Actor self )
{
for (var i = 0; i < self.Info.Passengers; i++)
for (var i = 0; i < self.LegacyInfo.Passengers; i++)
if (i >= cargo.Count)
yield return PipType.Transparent;
else

View File

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

View File

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

View File

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

View File

@@ -5,10 +5,10 @@ using System.Text;
namespace OpenRa.Game.Traits
{
class ChronosphereInfo : StatelessTraitInfo<Chronosphere> { }
class Chronosphere : IResolveOrder
{
public Chronosphere(Actor self) { }
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "PlayAnimation")

View File

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

View File

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

View File

@@ -6,14 +6,14 @@ 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)
{
@@ -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.LegacyInfo.Primary, detonatedBy.Owner, detonatedBy,
detonateLocation, detonateLocation, altitude, altitude)));
}
}

View File

@@ -2,12 +2,12 @@
namespace OpenRa.Game.Traits
{
class EngineerCaptureInfo : StatelessTraitInfo<EngineerCapture> { }
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;

View File

@@ -2,10 +2,10 @@
namespace OpenRa.Game.Traits
{
class ExplodesInfo : StatelessTraitInfo<Explodes> { }
class Explodes : INotifyDamage
{
public Explodes(Actor self) {}
public void Damaged(Actor self, AttackInfo e)
{
if (self.IsDead)

View File

@@ -2,13 +2,10 @@
namespace OpenRa.Game.Traits
{
class FakeInfo : StatelessTraitInfo<Fake> { }
class Fake : ITags
{
public Fake(Actor self){}
public IEnumerable<TagType> GetTags()
{
yield return TagType.Fake;
}
public IEnumerable<TagType> GetTags() { yield return TagType.Fake; }
}
}

View File

@@ -2,5 +2,6 @@
namespace OpenRa.Game.Traits
{
class GpsLaunchSite { public GpsLaunchSite(Actor self) { } }
class GpsLaunchSiteInfo : StatelessTraitInfo<GpsLaunchSite> { }
class GpsLaunchSite { }
}

View File

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

View File

@@ -4,6 +4,14 @@ using OpenRa.Game.GameRules;
namespace OpenRa.Game.Traits
{
class HelicopterInfo : ITraitInfo
{
public readonly int ROT = 0;
public readonly int Speed = 0;
public object Create(Actor self) { return new Helicopter(self); }
}
class Helicopter : IIssueOrder, IResolveOrder, IMovement
{
public IDisposable reservation;
@@ -12,8 +20,8 @@ namespace OpenRa.Game.Traits
// 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.LegacyInfo == Rules.UnitInfo["HPAD"]) return true;
if (a.LegacyInfo == Rules.UnitInfo["FIX"]) return true;
return false;
}
@@ -44,7 +52,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.LegacyInfo.InitialFacing));
self.QueueActivity(new HeliLand(true));
}
@@ -55,14 +63,14 @@ namespace OpenRa.Game.Traits
if (res != null)
reservation = res.Reserve(self);
var offset = (order.TargetActor.Info as BuildingInfo).SpawnOffset;
var offset = (order.TargetActor.LegacyInfo as LegacyBuildingInfo).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.LegacyInfo.InitialFacing));
self.QueueActivity(new HeliLand(false));
self.QueueActivity(order.TargetActor.Info == Rules.UnitInfo["HPAD"]
self.QueueActivity(order.TargetActor.LegacyInfo == Rules.UnitInfo["HPAD"]
? (IActivity)new Rearm() : new Repair());
}
}

View File

@@ -2,10 +2,10 @@
namespace OpenRa.Game.Traits
{
class InvisibleToOthersInfo : StatelessTraitInfo<InvisibleToOthers> { }
class InvisibleToOthers : IRenderModifier
{
public InvisibleToOthers(Actor self) { }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
{
return Game.LocalPlayer == self.Owner

View File

@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OpenRa.Game.Traits
{
class IronCurtainInfo : StatelessTraitInfo<IronCurtain> { }
class IronCurtain : IResolveOrder
{
public IronCurtain(Actor self) {}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString == "PlayAnimation")

View File

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

View File

@@ -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<LimitedAmmoInfo>().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<LimitedAmmoInfo>().Ammo) return false;
++ammo;
return true;
}
@@ -26,7 +33,8 @@ namespace OpenRa.Game.Traits
public IEnumerable<PipType> GetPips(Actor self)
{
return Graphics.Util.MakeArray(self.Info.Ammo,
var maxAmmo = self.Info.Traits.Get<LimitedAmmoInfo>().Ammo;
return Graphics.Util.MakeArray(maxAmmo,
i => ammo > i ? PipType.Green : PipType.Transparent);
}
}

View File

@@ -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,7 +24,7 @@ namespace OpenRa.Game.Traits
{
if( order.OrderString == "DeployMcv" )
{
var factBuildingInfo = (BuildingInfo)Rules.UnitInfo[ "fact" ];
var factBuildingInfo = (LegacyBuildingInfo)Rules.UnitInfo[ "fact" ];
if( Game.CanPlaceBuilding( factBuildingInfo, self.Location - new int2( 1, 1 ), self, false ) )
{
self.CancelActivity();

View File

@@ -1,8 +1,6 @@

namespace OpenRa.Game.Traits
{
class MineImmune
{
public MineImmune(Actor self) { }
}
class MineImmuneInfo : StatelessTraitInfo<MineImmune> { }
class MineImmune { }
}

View File

@@ -1,14 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq;
namespace OpenRa.Game.Traits
{
class MinelayerInfo : StatelessTraitInfo<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<LimitedAmmo>();
@@ -16,7 +13,7 @@ namespace OpenRa.Game.Traits
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 +33,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(Rules.UnitInfo[self.LegacyInfo.Primary], self.Location, self.Owner)));
}
}
}

View File

@@ -5,6 +5,15 @@ using OpenRa.Game.GameRules;
namespace OpenRa.Game.Traits
{
class MobileInfo : ITraitInfo
{
public readonly int Sight = 0;
public readonly int ROT = 0;
public readonly int Speed = 0;
public object Create(Actor self) { return new Mobile(self); }
}
class Mobile : IIssueOrder, IResolveOrder, IOccupySpace, IMovement
{
readonly Actor self;
@@ -78,12 +87,12 @@ namespace OpenRa.Game.Traits
public UnitMovementType GetMovementType()
{
switch (Rules.UnitCategory[self.Info.Name])
switch (Rules.UnitCategory[self.LegacyInfo.Name])
{
case "Infantry":
return UnitMovementType.Foot;
case "Vehicle":
return (self.Info as VehicleInfo).Tracked ? UnitMovementType.Track : UnitMovementType.Wheel;
return (self.LegacyInfo as VehicleInfo).Tracked ? UnitMovementType.Track : UnitMovementType.Wheel;
case "Ship":
return UnitMovementType.Float;
case "Plane":

View File

@@ -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<Passenger> {}
class Passenger : IIssueOrder, IResolveOrder
{
public Passenger(Actor self) { }
public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor)
{
if (mi.Button != MouseButton.Right)
@@ -23,7 +20,7 @@ namespace OpenRa.Game.Traits
return null;
var umt = self.traits.WithInterface<IMovement>().First().GetMovementType();
if (!underCursor.Info.PassengerTypes.Contains(umt))
if (!underCursor.LegacyInfo.PassengerTypes.Contains(umt))
return null;
return new Order("EnterTransport", self, underCursor, int2.Zero, null);

View File

@@ -1,11 +1,16 @@
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 readonly int ROT = 0;
public readonly int Speed = 0;
public object Create(Actor self) { return new Plane(self); }
}
class Plane : IIssueOrder, IResolveOrder, IMovement
{
public IDisposable reservation;
@@ -15,8 +20,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.LegacyInfo == Rules.UnitInfo["AFLD"]) return true;
if (a.LegacyInfo == Rules.UnitInfo["FIX"]) return true;
return false;
}
@@ -59,7 +64,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.LegacyInfo == Rules.UnitInfo["AFLD"]
? (IActivity)new Rearm() : new Repair());
}
}

View File

@@ -1,9 +1,14 @@
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 object Create(Actor self) { return new Production(self); }
}
class Production : IIssueOrder, IResolveOrder, IProducer, ITags
{
bool isPrimary = false;
@@ -11,17 +16,17 @@ namespace OpenRa.Game.Traits
public Production( Actor self ) { }
public virtual int2? CreationLocation( Actor self, UnitInfo producee )
public virtual int2? CreationLocation( Actor self, LegacyUnitInfo producee )
{
return ( 1 / 24f * self.CenterLocation ).ToInt2();
}
public virtual int CreationFacing( Actor self, Actor newUnit )
{
return newUnit.Info.InitialFacing;
return newUnit.LegacyInfo.InitialFacing;
}
public bool Produce( Actor self, UnitInfo producee )
public bool Produce( Actor self, LegacyUnitInfo producee )
{
var location = CreationLocation( self, producee );
if( location == null || Game.UnitInfluence.GetUnitsAt( location.Value ).Any() )
@@ -38,7 +43,7 @@ namespace OpenRa.Game.Traits
newUnit.QueueActivity( new Activities.Move( rp.rallyPoint, 1 ) );
}
var bi = self.Info as BuildingInfo;
var bi = self.LegacyInfo as LegacyBuildingInfo;
if (bi != null && bi.SpawnOffset != null)
newUnit.CenterLocation = self.CenterLocation
+ new float2(bi.SpawnOffset[0], bi.SpawnOffset[1]);
@@ -78,12 +83,12 @@ namespace OpenRa.Game.Traits
}
// Cancel existing primaries
foreach (var p in (self.Info as BuildingInfo).Produces)
foreach (var p in (self.LegacyInfo as LegacyBuildingInfo).Produces)
{
foreach (var b in Game.world.Actors.Where(x => x.traits.Contains<Production>()
&& x.Owner == self.Owner
&& x.traits.Get<Production>().IsPrimary == true
&& (x.Info as BuildingInfo).Produces.Contains(p)))
&& (x.LegacyInfo as LegacyBuildingInfo).Produces.Contains(p)))
{
b.traits.Get<Production>().SetPrimaryProducer(b, false);
}

View File

@@ -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;
@@ -128,7 +133,7 @@ namespace OpenRa.Game.Traits
// Prioritise primary structure in build order
var primaryProducers = Game.world.Actors
.Where(x => x.traits.Contains<Production>()
&& producerTypes.Contains(x.Info)
&& producerTypes.Contains(x.LegacyInfo)
&& x.Owner == self.Owner
&& x.traits.Get<Production>().IsPrimary == true);
@@ -148,7 +153,7 @@ namespace OpenRa.Game.Traits
if (producer == null)
{
producer = Game.world.Actors
.Where( x => producerTypes.Contains( x.Info ) && x.Owner == self.Owner )
.Where( x => producerTypes.Contains( x.LegacyInfo ) && x.Owner == self.Owner )
.FirstOrDefault();
}

View File

@@ -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,7 +26,7 @@ namespace OpenRa.Game.Traits
return null;
}
public override int2? CreationLocation(Actor self, UnitInfo producee)
public override int2? CreationLocation(Actor self, LegacyUnitInfo producee)
{
return FindAdjacentTile(self, producee.WaterBound ?
UnitMovementType.Float : UnitMovementType.Wheel); /* hackety hack */

View File

@@ -1,19 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace OpenRa.Game.Traits
{
class ProvidesRadarInfo : StatelessTraitInfo<ProvidesRadar> {}
class ProvidesRadar
{
Actor self;
public ProvidesRadar(Actor self)
{
this.self = self;
}
public bool IsActive()
public bool IsActive(Actor self)
{
// TODO: Check for nearby MRJ

View File

@@ -4,6 +4,11 @@ using OpenRa.Game.Orders;
namespace OpenRa.Game.Traits
{
class RallyPointInfo : ITraitInfo
{
public object Create(Actor self) { return new RallyPoint(self); }
}
class RallyPoint : IRender, IIssueOrder, IResolveOrder, ITick
{
[Sync]

View File

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

View File

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

View File

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

View File

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

View File

@@ -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.LegacyInfo.Image ?? self.LegacyInfo.Name);
}
public void BuildingComplete( Actor self )

View File

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

View File

@@ -1,10 +1,16 @@
using System;
using System.Collections.Generic;
using IjwFramework.Collections;
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<string, AnimationWithOffset> anims = new Dictionary<string, AnimationWithOffset>();
@@ -12,7 +18,7 @@ namespace OpenRa.Game.Traits
public RenderSimple(Actor self)
{
anims.Add( "", new Animation( self.Info.Image ?? self.Info.Name ) );
anims.Add( "", new Animation( self.LegacyInfo.Image ?? self.LegacyInfo.Name ) );
}
public virtual IEnumerable<Renderable> Render( Actor self )

View File

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

View File

@@ -5,22 +5,25 @@ 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<Unit>();
var attack = self.traits.WithInterface<AttackBase>().First();
var muzzleFlash = new Animation(self.Info.Name);
var muzzleFlash = new Animation(self.LegacyInfo.Name);
muzzleFlash.PlayFetchIndex("muzzle",
() => (Util.QuantizeFacing(unit.Facing, 8)) * 6 + (int)(attack.primaryRecoil * 5.9f));
anims.Add( "muzzle", new AnimationWithOffset(
muzzleFlash,
() => self.Info.PrimaryOffset.AbsOffset(),
() => self.LegacyInfo.PrimaryOffset.AbsOffset(),
() => attack.primaryRecoil <= 0 ) );
}
}

View File

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

View File

@@ -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<Unit>();
var info = self.Info.Traits.Get<RenderUnitRotorInfo>();
rotorAnim = new Animation(self.Info.Name);
rotorAnim = new Animation(info.Image ?? self.Info.Name);
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(info.Image ?? self.Info.Name);
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 ) );
}

View File

@@ -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<Unit>();
var info = self.Info.Traits.Get<RenderUnitSpinnerInfo>();
spinnerAnim = new Animation( self.Info.Name );
var spinnerAnim = new Animation( info.Image ?? self.Info.Name );
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 ) );
}
}

View File

@@ -4,10 +4,13 @@ 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)
{
@@ -15,30 +18,30 @@ namespace OpenRa.Game.Traits
var turreted = self.traits.Get<Turreted>();
var attack = self.traits.WithInterface<AttackBase>().FirstOrDefault();
var turretAnim = new Animation(self.Info.Name);
var turretAnim = new Animation(self.LegacyInfo.Name);
turretAnim.PlayFacing( "turret", () => turreted.turretFacing );
if( self.Info.PrimaryOffset != null )
if( self.LegacyInfo.PrimaryOffset != null )
anims.Add("turret_1", new AnimationWithOffset(
turretAnim,
() => Util.GetTurretPosition(self, unit, self.Info.PrimaryOffset, attack.primaryRecoil),
() => Util.GetTurretPosition(self, unit, self.LegacyInfo.PrimaryOffset, attack.primaryRecoil),
null) { ZOffset = 1 });
if( self.Info.SecondaryOffset != null )
if( self.LegacyInfo.SecondaryOffset != null )
anims.Add("turret_2", new AnimationWithOffset(
turretAnim,
() => Util.GetTurretPosition(self, unit, self.Info.SecondaryOffset, attack.secondaryRecoil),
() => Util.GetTurretPosition(self, unit, self.LegacyInfo.SecondaryOffset, attack.secondaryRecoil),
null) { ZOffset = 1 });
if( self.Info.MuzzleFlash )
if( self.LegacyInfo.MuzzleFlash )
{
muzzleFlash = new Animation( self.Info.Name );
var muzzleFlash = new Animation( self.LegacyInfo.Name );
muzzleFlash.PlayFetchIndex( "muzzle",
() => ( Util.QuantizeFacing( self.traits.Get<Turreted>().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, self.LegacyInfo.PrimaryOffset, attack.primaryRecoil ),
() => attack.primaryRecoil <= 0 ) );
}
}

View File

@@ -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.LegacyInfo == Rules.UnitInfo["FIX"]
&& underCursor.Owner == self.Owner
&& !Reservable.IsReserved(underCursor))
return new Order("Enter", self, underCursor, int2.Zero, null);

View File

@@ -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) { }

View File

@@ -1,10 +1,10 @@

namespace OpenRa.Game.Traits
{
class SeedsOreInfo : StatelessTraitInfo<SeedsOre> {}
class SeedsOre : ITick
{
public SeedsOre( Actor self ) {}
const double OreSeedProbability = .05; // todo: push this out into rules
public void Tick(Actor self)

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Game.Traits
{
class SelectableInfo : StatelessTraitInfo<Selectable>
{
public readonly int Priority = 10;
public readonly int[] Bounds = null;
public readonly string Voice = "GenericVoice";
}
class Selectable {}
}

View File

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

View File

@@ -3,21 +3,18 @@ using System;
using OpenRa.Game.GameRules;
namespace OpenRa.Game.Traits
{
class StoresOreInfo : StatelessTraitInfo<StoresOre>
{
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<StoresOreInfo>().Capacity / 2;
self.Owner.TakeCash(toSteal);
thief.Owner.GiveCash(toSteal);
@@ -31,15 +28,12 @@ namespace OpenRa.Game.Traits
public IEnumerable<PipType> 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<StoresOreInfo>().Pips;
return Graphics.Util.MakeArray( numPips,
i => (Game.LocalPlayer.GetSiloFullness() > i * 1.0f / numPips)
? PipType.Yellow : PipType.Transparent );
}
}
}

Some files were not shown because too many files have changed in this diff Show More