diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 9a73b02f03..ec720892f5 100644 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -10,7 +10,7 @@ namespace OpenRa.Game { abstract class Actor { - protected readonly Game game; + public readonly Game game; public abstract float2 RenderLocation { get; } public Player owner; diff --git a/OpenRa.Game/Building.cs b/OpenRa.Game/Building.cs index 2f47e992fb..7dbf501924 100644 --- a/OpenRa.Game/Building.cs +++ b/OpenRa.Game/Building.cs @@ -4,18 +4,13 @@ using System.Text; namespace OpenRa.Game { - class Building : Actor + class Building : PlayerOwned { - protected Animation animation; - protected int2 location; - public Building( string name, int2 location, Player owner, Game game ) - : base( game ) + : base( game, name, location ) { - this.location = location; this.owner = owner; - animation = new Animation( name ); animation.PlayThen( "make", delegate { animation.PlayRepeating( "idle" ); } ); owner.TechTree.Build( name, true ); } @@ -25,14 +20,5 @@ namespace OpenRa.Game animation.Tick( t ); } - public override Sprite[] CurrentImages - { - get { return animation.Images; } - } - - public override float2 RenderLocation - { - get { return 24.0f * (float2)location; } - } } } diff --git a/OpenRa.Game/Harvester.cs b/OpenRa.Game/Harvester.cs deleted file mode 100644 index 8ec7d5f458..0000000000 --- a/OpenRa.Game/Harvester.cs +++ /dev/null @@ -1,60 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace OpenRa.Game -{ - class Harvester : Unit - { - public Harvester( int2 cell, Player owner, Game game ) - : base( "harv", cell, owner, new float2( 12, 12 ), game ) - { - } - - public override IOrder Order( Game game, int2 xy ) - { - if( ( fromCell == toCell || moveFraction == 0 ) && fromCell == xy ) - return new HarvestOrder( this ); - return base.Order( game, xy ); - } - - void AcceptHarvestOrder() - { - TickFunc order = null; - order = nextOrder = delegate - { - // TODO: check that there's actually some ore in this cell :) - - // face in one of the 8 directions - if( Turn( ( facing + 1 ) & ~3 ) ) - return; - - currentOrder = delegate { }; - if( nextOrder == null ) - nextOrder = order; - - string sequenceName = string.Format( "harvest{0}", facing / 4 ); - animation.PlayThen( sequenceName, delegate - { - currentOrder = null; - animation.PlayFetchIndex( "idle", delegate { return facing; } ); - } ); - }; - } - - public class HarvestOrder : IOrder - { - Harvester harvester; - - public HarvestOrder( Harvester harv ) - { - harvester = harv; - } - - public void Apply( Game game ) - { - harvester.AcceptHarvestOrder(); - } - } - } -} diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index a0bd8303c9..ff7d709ac0 100644 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -45,9 +45,9 @@ namespace OpenRa.Game SequenceProvider.ForcePrecache(); - game.world.Add( new Mcv( new int2( 5, 5 ), game.players[ 3 ], game ) ); - game.world.Add( new Mcv( new int2( 7, 5 ), game.players[ 2 ], game ) ); - Mcv mcv = new Mcv( new int2( 9, 5 ), game.players[ 1 ], game ); + game.world.Add( new Unit( "mcv", new int2( 5, 5 ), game.players[ 3 ], game ) ); + game.world.Add( new Unit( "mcv", new int2( 7, 5 ), game.players[ 2 ], game ) ); + Unit mcv = new Unit( "mcv", new int2( 9, 5 ), game.players[ 1 ], game ); game.world.orderGenerator = mcv; game.world.Add( mcv ); diff --git a/OpenRa.Game/Mcv.cs b/OpenRa.Game/Mcv.cs deleted file mode 100644 index 98637ab3e6..0000000000 --- a/OpenRa.Game/Mcv.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using OpenRa.FileFormats; -using System.Drawing; -using BluntDirectX.Direct3D; - -namespace OpenRa.Game -{ - class Mcv : Unit - { - public Mcv( int2 location, Player owner, Game game ) - : base( "mcv", location, owner, new float2( 12, 12 ), game ) - { - } - - public void AcceptDeployOrder() - { - nextOrder = delegate( Game game, int t ) - { - if( Turn( 12 ) ) - return; - - World world = game.world; - world.AddFrameEndTask( delegate - { - world.Remove( this ); - world.Add( new ConstructionYard( fromCell - new int2( 1, 1 ), owner, game ) ); - } ); - currentOrder = null; - }; - } - - public override IOrder Order( Game game, int2 xy ) - { - if( ( fromCell == toCell || moveFraction == 0 ) && fromCell == xy ) - return new DeployMcvOrder( this ); - - return base.Order( game, xy ); - } - } -} diff --git a/OpenRa.Game/MoveOrder.cs b/OpenRa.Game/MoveOrder.cs index 8611f756e0..87aeebb36f 100644 --- a/OpenRa.Game/MoveOrder.cs +++ b/OpenRa.Game/MoveOrder.cs @@ -22,22 +22,37 @@ namespace OpenRa.Game public void Apply( Game game ) { - Unit.AcceptMoveOrder( Destination ); + Unit.nextOrder = UnitMissions.Move( Unit, Destination ); } } class DeployMcvOrder : IOrder { - public Mcv Mcv; + Unit unit; - public DeployMcvOrder( Mcv mcv ) + public DeployMcvOrder( Unit unit ) { - this.Mcv = mcv; + this.unit = unit; } public void Apply( Game game ) { - Mcv.AcceptDeployOrder(); + unit.nextOrder = UnitMissions.Deploy( unit ); + } + } + + class HarvestOrder : IOrder + { + Unit unit; + + public HarvestOrder( Unit unit ) + { + this.unit = unit; + } + + public void Apply( Game game ) + { + unit.nextOrder = UnitMissions.Harvest( unit ); } } } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 0ecffd43f7..17fef9f087 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -47,9 +47,9 @@ + - @@ -63,7 +63,6 @@ Form - @@ -80,6 +79,7 @@ + diff --git a/OpenRa.Game/PathFinder.cs b/OpenRa.Game/PathFinder.cs index 9518711354..e4672d857e 100644 --- a/OpenRa.Game/PathFinder.cs +++ b/OpenRa.Game/PathFinder.cs @@ -26,9 +26,9 @@ namespace OpenRa.Game // returns estimate to destination, 0.0 is cell is dest public delegate double DistanceHeuristic( int2 cell ); - public List FindUnitPath( Unit unit, DistanceHeuristic estimator ) + public List FindUnitPath( int2 unitLocation, DistanceHeuristic estimator ) { - int2 startLocation = unit.Location + map.Offset; + int2 startLocation = unitLocation + map.Offset; CellInfo[ , ] cellInfo = new CellInfo[ 128, 128 ]; diff --git a/OpenRa.Game/PlayerOwned.cs b/OpenRa.Game/PlayerOwned.cs new file mode 100644 index 0000000000..c1dda4eb2f --- /dev/null +++ b/OpenRa.Game/PlayerOwned.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenRa.Game +{ + abstract class PlayerOwned : Actor + { + public Animation animation; + protected int2 location; + + public UnitMission currentOrder = null; + public UnitMission nextOrder = null; + + protected PlayerOwned( Game game, string name, int2 location ) + : base( game ) + { + animation = new Animation( name ); + this.location = location; + } + + public override float2 RenderLocation + { + get { return 24.0f * (float2)location; } + } + + public override Sprite[] CurrentImages { get { return animation.Images; } } + } +} diff --git a/OpenRa.Game/Refinery.cs b/OpenRa.Game/Refinery.cs index 3e575c9f2e..49d1ad3b29 100644 --- a/OpenRa.Game/Refinery.cs +++ b/OpenRa.Game/Refinery.cs @@ -18,7 +18,7 @@ namespace OpenRa.Game game.world.AddFrameEndTask(delegate { - Unit harvester = new Harvester(location + new int2(1, 2), owner, game); + Unit harvester = new Unit( "harv", location + new int2( 1, 2 ), owner, game ); harvester.facing = 8; game.world.Add(harvester); game.world.orderGenerator = harvester; diff --git a/OpenRa.Game/Rules.cs b/OpenRa.Game/Rules.cs index 4744de0b32..8d13b2a0dc 100644 --- a/OpenRa.Game/Rules.cs +++ b/OpenRa.Game/Rules.cs @@ -16,14 +16,14 @@ namespace OpenRa.Game foreach (string line in Util.ReadAllLines(FileSystem.Open("units.txt"))) { - string unit = line.Substring(0, line.IndexOf(',')); - IniSection section = rulesIni.GetSection(unit.ToUpperInvariant()); + string unit = line.Substring( 0, line.IndexOf( ',' ) ).ToUpperInvariant(); + IniSection section = rulesIni.GetSection( unit ); if (section == null) { Log.Write("rules.ini doesnt contain entry for unit \"{0}\"", unit); continue; } - unitInfos.Add(unit, new UnitInfo(section)); + unitInfos.Add( unit, new UnitInfo( unit, section ) ); } } @@ -36,37 +36,17 @@ namespace OpenRa.Game class UnitInfo { public readonly int Speed; + public readonly SupportedMissions supportedMissions; - public UnitInfo( IniSection ini ) + public UnitInfo( string unitName, IniSection ini ) { Speed = int.Parse( ini.GetValue( "Speed", "0" ) ); + + supportedMissions = SupportedMissions.Stop; + if( unitName == "MCV" ) + supportedMissions |= SupportedMissions.Deploy; + if( unitName == "HARV" ) + supportedMissions |= SupportedMissions.Harvest; } } - - //Unit Missions: - //{ - // Sleep - no-op - // Harmless - no-op, and also not considered a threat - // Sticky - // Attack - // Move - // QMove - // Retreat - // Guard - // Enter - // Capture - // Harvest - // Area Guard - // [Return] - // Stop - // [Ambush] - // Hunt - // Unload - // Sabotage - // Construction - // Selling - // Repair - // Rescue - // Missile - //} } diff --git a/OpenRa.Game/Unit.cs b/OpenRa.Game/Unit.cs index c88bce2450..f9fa5d0cac 100644 --- a/OpenRa.Game/Unit.cs +++ b/OpenRa.Game/Unit.cs @@ -4,26 +4,26 @@ using System.Text; namespace OpenRa.Game { - abstract class Unit : Actor, IOrderGenerator + class Unit : PlayerOwned, IOrderGenerator { - protected Animation animation; - public int facing = 0; - protected int2 fromCell, toCell; - protected int moveFraction, moveFractionTotal; + public int2 fromCell; + public int2 toCell + { + get { return location; } + set { location = value; } + } - protected delegate void TickFunc( Game game, int t ); - protected TickFunc currentOrder = null; - protected TickFunc nextOrder = null; + public int moveFraction, moveFractionTotal; - protected readonly float2 renderOffset; - protected readonly UnitInfo unitInfo; + readonly float2 renderOffset; + public readonly UnitInfo unitInfo; - public Unit( string name, int2 cell, Player owner, float2 renderOffset, Game game ) - : base( game ) + public Unit( string name, int2 cell, Player owner, Game game ) + : base( game, name, cell ) { fromCell = toCell = cell; - this.renderOffset = renderOffset; + this.renderOffset = new float2( 12, 12 ); // TODO: pull this from the sprite this.owner = owner; this.unitInfo = Rules.UnitInfo( name ); @@ -34,7 +34,7 @@ namespace OpenRa.Game static float2[] fvecs = Util.MakeArray( 32, delegate( int i ) { return -float2.FromAngle( i / 16.0f * (float)Math.PI ) * new float2( 1f, 1.3f ); } ); - int GetFacing( float2 d ) + public int GetFacing( float2 d ) { if( float2.WithinEpsilon( d, float2.Zero, 0.001f ) ) return facing; @@ -65,70 +65,37 @@ namespace OpenRa.Game } if( currentOrder != null ) - currentOrder( game, t ); - } - - public void AcceptMoveOrder( int2 destination ) - { - nextOrder = delegate( Game game, int t ) - { - if( nextOrder != null ) - destination = toCell; - - if( Turn( GetFacing( toCell - fromCell ) ) ) - return; - - moveFraction += t * unitInfo.Speed; - if( moveFraction < moveFractionTotal ) - return; - - moveFraction = 0; - moveFractionTotal = 0; - fromCell = toCell; - - if( toCell == destination ) - { - currentOrder = null; - return; - } - - List res = game.pathFinder.FindUnitPath( this, PathFinder.DefaultEstimator( destination ) ); - if( res.Count != 0 ) - { - toCell = res[ res.Count - 1 ]; - - int2 dir = toCell - fromCell; - moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 2500 : 2000; - } - else - destination = toCell; - }; - } - - protected bool Turn( int desiredFacing ) - { - if( facing == desiredFacing ) - return false; - - int df = ( desiredFacing - facing + 32 ) % 32; - facing = ( facing + ( df > 16 ? 31 : 1 ) ) % 32; - return true; + currentOrder( t ); } public override float2 RenderLocation { get { - float fraction = (moveFraction > 0) ? (float)moveFraction / moveFractionTotal : 0f; + float fraction = ( moveFraction > 0 ) ? (float)moveFraction / moveFractionTotal : 0f; float2 location = 24 * float2.Lerp( fromCell, toCell, fraction ); - return ( location - renderOffset ).Round(); ; + return ( location - renderOffset ).Round(); } } - public int2 Location { get { return toCell; } } - public virtual IOrder Order(Game game, int2 xy) { return new MoveOrder(this, xy); } - public override Sprite[] CurrentImages { get { return animation.Images; } } + bool SupportsMission( SupportedMissions mission ) + { + return mission == ( unitInfo.supportedMissions & mission ); + } + + public IOrder Order( Game game, int2 xy ) + { + if( ( fromCell == toCell || moveFraction == 0 ) && fromCell == xy ) + { + if( SupportsMission( SupportedMissions.Deploy ) ) + return new DeployMcvOrder( this ); + if( SupportsMission( SupportedMissions.Harvest ) ) + return new HarvestOrder( this ); + } + + return new MoveOrder( this, xy ); + } public void PrepareOverlay(Game game, int2 xy) { } } diff --git a/OpenRa.Game/UnitMissions.cs b/OpenRa.Game/UnitMissions.cs new file mode 100644 index 0000000000..b391176fb4 --- /dev/null +++ b/OpenRa.Game/UnitMissions.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenRa.Game +{ + //Unit Missions: + //{ + //in rules.ini: + // Sleep - no-op + // Harmless - no-op, and also not considered a threat + // Sticky + // Attack + // Move + // QMove + // Retreat + // Guard + // Enter + // Capture + // Harvest + // Area Guard + // [Return] - unused + // Stop + // [Ambush] - unused + // Hunt + // Unload + // Sabotage + // Construction + // Selling + // Repair + // Rescue + // Missile + // + //not in original RA: + // Deploy (Mcv -> Fact) [should this be construction/unload?] + //} + + [Flags] + enum SupportedMissions + { + Stop = 0, + Harvest = 1, + Deploy = 2, + } + + delegate void UnitMission( int t ); + static class UnitMissions + { + public static UnitMission Sleep() + { + return delegate { }; + } + + public static UnitMission Move( Unit unit, int2 destination ) + { + return delegate( int t ) + { + Game game = unit.game; + + if( unit.nextOrder != null ) + destination = unit.toCell; + + if( Turn( unit, unit.GetFacing( unit.toCell - unit.fromCell ) ) ) + return; + + unit.moveFraction += t * unit.unitInfo.Speed; + if( unit.moveFraction < unit.moveFractionTotal ) + return; + + unit.moveFraction = 0; + unit.moveFractionTotal = 0; + unit.fromCell = unit.toCell; + + if( unit.toCell == destination ) + { + unit.currentOrder = null; + return; + } + + List res = game.pathFinder.FindUnitPath( unit.toCell, PathFinder.DefaultEstimator( destination ) ); + if( res.Count != 0 ) + { + unit.toCell = res[ res.Count - 1 ]; + + int2 dir = unit.toCell - unit.fromCell; + unit.moveFractionTotal = ( dir.X != 0 && dir.Y != 0 ) ? 2500 : 2000; + } + else + destination = unit.toCell; + }; + } + + public static UnitMission Deploy( Unit unit ) + { + return delegate( int t ) + { + Game game = unit.game; + + if( Turn( unit, 12 ) ) + return; + + game.world.AddFrameEndTask( delegate + { + game.world.Remove( unit ); + game.world.Add( new ConstructionYard( unit.fromCell - new int2( 1, 1 ), unit.owner, game ) ); + } ); + unit.currentOrder = null; + }; + } + + + public static UnitMission Harvest( Unit unit ) + { + UnitMission order = null; + order = delegate + { + // TODO: check that there's actually some ore in this cell :) + + // face in one of the 8 directions + if( Turn( unit, ( unit.facing + 1 ) & ~3 ) ) + return; + + unit.currentOrder = delegate { }; + if( unit.nextOrder == null ) + unit.nextOrder = order; + + string sequenceName = string.Format( "harvest{0}", unit.facing / 4 ); + unit.animation.PlayThen( sequenceName, delegate + { + unit.currentOrder = null; + unit.animation.PlayFetchIndex( "idle", delegate { return unit.facing; } ); + } ); + }; + return order; + } + + static bool Turn( Unit unit, int desiredFacing ) + { + if( unit.facing == desiredFacing ) + return false; + + int df = ( desiredFacing - unit.facing + 32 ) % 32; + unit.facing = ( unit.facing + ( df > 16 ? 31 : 1 ) ) % 32; + return true; + } + } +}