diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index c970f33890..24774dc06a 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -65,8 +65,8 @@ namespace OpenRa.Game public Order Order( int2 xy, bool lmb ) { if (Owner != Game.LocalPlayer) - return null; - + return null; + var underCursor = Game.UnitInfluence.GetUnitAt( xy ) ?? Game.BuildingInfluence.GetBuildingAt( xy ); return traits.WithInterface() diff --git a/OpenRa.Game/Controller.cs b/OpenRa.Game/Controller.cs index c0c7422cec..78519e5fc0 100644 --- a/OpenRa.Game/Controller.cs +++ b/OpenRa.Game/Controller.cs @@ -4,24 +4,33 @@ using System.Linq; using System.Text; using System.Windows.Forms; using IjwFramework.Types; -using System.Drawing; +using System.Drawing; using OpenRa.Game.Traits; namespace OpenRa.Game { class Controller { - public IOrderGenerator orderGenerator; - - void ApplyOrders(float2 xy, bool left) - { - var doVoice = true; - if (orderGenerator != null) - foreach (var order in orderGenerator.Order(xy.ToInt2(), left)) - { - order.Apply(doVoice); - doVoice = false; - } + public IOrderGenerator orderGenerator; + + void ApplyOrders(float2 xy, bool left) + { + var doVoice = null as Actor; + if (orderGenerator != null) + foreach( var order in orderGenerator.Order( xy.ToInt2(), left ) ) + { + UnitOrders.ProcessOrder( order ); + if( order.Subject != null && order.Player == Game.LocalPlayer ) + doVoice = order.Subject; + } + if( doVoice != null ) + Game.PlaySound( Game.SovietVoices.First.GetNext() + GetVoiceSuffix( doVoice ), false ); + } + + static string GetVoiceSuffix( Actor unit ) + { + var suffixes = new[] { ".r01", ".r03" }; + return suffixes[ unit.traits.Get().Voice ]; } float2 dragStart, dragEnd; @@ -32,7 +41,7 @@ namespace OpenRa.Game if (mi.Button == MouseButtons.Left && mi.Event == MouseInputEvent.Down) { if (!(orderGenerator is PlaceBuilding)) - dragStart = dragEnd = xy; + dragStart = dragEnd = xy; ApplyOrders(xy, true); } @@ -59,9 +68,9 @@ namespace OpenRa.Game /* update the cursor to reflect the thing under us - note this * needs to also happen when the *thing* changes, so per-frame hook */ dragStart = dragEnd = xy; - } - - if (mi.Button == MouseButtons.Right && mi.Event == MouseInputEvent.Down) + } + + if (mi.Button == MouseButtons.Right && mi.Event == MouseInputEvent.Down) ApplyOrders(xy, false); } @@ -84,10 +93,10 @@ namespace OpenRa.Game if (uog != null && uog.selection.Count > 0 && uog.selection.Any(a => a.traits.Contains()) && uog.selection.All( a => a.Owner == Game.LocalPlayer )) - { - var umts = uog.selection.Select(a => a.traits.GetOrDefault()) - .Where(m => m != null) - .Select(m => m.GetMovementType()) + { + var umts = uog.selection.Select(a => a.traits.GetOrDefault()) + .Where(m => m != null) + .Select(m => m.GetMovementType()) .Distinct(); if (!umts.Any( umt => Game.IsCellBuildable( dragEnd.ToInt2(), umt ) )) diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index 63f9c2980c..69e2960252 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -1,8 +1,8 @@ -using System.Drawing; +using System.Drawing; using System.Linq; -using System.Windows.Forms; -using IjwFramework.Types; -using System.Collections.Generic; +using System.Windows.Forms; +using IjwFramework.Types; +using System.Collections.Generic; using OpenRa.Game.Traits; namespace OpenRa.Game.Graphics @@ -12,13 +12,13 @@ namespace OpenRa.Game.Graphics public readonly SpriteRenderer spriteRenderer; public readonly LineRenderer lineRenderer; public readonly Region region; - public readonly UiOverlay uiOverlay; - + public readonly UiOverlay uiOverlay; + public static bool ShowUnitPaths = false; public WorldRenderer(Renderer renderer) { - // TODO: this is layout policy. it belongs at a higher level than this. + // TODO: this is layout policy. it belongs at a higher level than this. region = Region.Create(Game.viewport, DockStyle.Left, Game.viewport.Width - 128, Draw, Game.controller.HandleMouseInput); @@ -28,41 +28,41 @@ namespace OpenRa.Game.Graphics spriteRenderer = new SpriteRenderer(renderer, true); lineRenderer = new LineRenderer(renderer); uiOverlay = new UiOverlay(spriteRenderer); - } - - void DrawSpriteList(Player owner, RectangleF rect, - IEnumerable> images) - { - foreach (var image in images) - { - var loc = image.Second; - - if (loc.X > rect.Right || loc.X < rect.Left - - image.First.bounds.Width) - continue; - if (loc.Y > rect.Bottom || loc.Y < rect.Top - - image.First.bounds.Height) - continue; - - spriteRenderer.DrawSprite(image.First, loc, - (owner != null) ? owner.Palette : 0); - } - } - + } + + void DrawSpriteList(Player owner, RectangleF rect, + IEnumerable> images) + { + foreach (var image in images) + { + var loc = image.Second; + + if (loc.X > rect.Right || loc.X < rect.Left + - image.First.bounds.Width) + continue; + if (loc.Y > rect.Bottom || loc.Y < rect.Top + - image.First.bounds.Height) + continue; + + spriteRenderer.DrawSprite(image.First, loc, + (owner != null) ? owner.Palette : 0); + } + } + public void Draw() { var rect = new RectangleF((region.Position + Game.viewport.Location).ToPointF(), region.Size.ToSizeF()); foreach (Actor a in Game.world.Actors.OrderBy( u => u.CenterLocation.Y )) - DrawSpriteList(a.Owner, rect, a.Render()); - - foreach (var a in Game.world.Actors - .Where(u => u.traits.Contains()) - .Select(u => u.traits.Get())) - DrawSpriteList(a.self.Owner, rect, a.RenderRoof(a.self)); /* RUDE HACK */ - - foreach (IEffect e in Game.world.Effects) + DrawSpriteList(a.Owner, rect, a.Render()); + + foreach (var a in Game.world.Actors + .Where(u => u.traits.Contains()) + .Select(u => u.traits.Get())) + DrawSpriteList(a.self.Owner, rect, a.RenderRoof(a.self)); /* RUDE HACK */ + + foreach (IEffect e in Game.world.Effects) DrawSpriteList(e.Owner, rect, e.Render()); uiOverlay.Draw(); @@ -93,7 +93,7 @@ namespace OpenRa.Game.Graphics lineRenderer.Flush(); } - const float conditionYellow = 0.5f; /* todo: get these from gamerules */ + const float conditionYellow = 0.5f; /* todo: get these from gamerules */ const float conditionRed = 0.25f; void DrawSelectionBox(Actor selectedUnit, Color c, bool drawHealthBar) @@ -114,60 +114,60 @@ namespace OpenRa.Game.Graphics lineRenderer.DrawLine(xY, xY + new float2(4, 0), c, c); lineRenderer.DrawLine(xY, xY + new float2(0, -4), c, c); lineRenderer.DrawLine(XY, XY + new float2(-4, 0), c, c); - lineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c); - - if (drawHealthBar) - { - c = Color.Gray; - 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.unitInfo.Strength; - var healthColor = (healthAmount < conditionRed) ? Color.Red - : (healthAmount < conditionYellow) ? Color.Yellow - : Color.LimeGreen; - - var healthColor2 = Color.FromArgb( - 255, - healthColor.R / 2, - healthColor.G / 2, - healthColor.B / 2); - - var z = float2.Lerp(xy, Xy, healthAmount); - - lineRenderer.DrawLine(z + new float2(0, -4), Xy + new float2(0,-4), c, c); - lineRenderer.DrawLine(z + new float2(0, -2), Xy + new float2(0, -2), c, c); - - lineRenderer.DrawLine(xy + new float2(0, -3), - z + new float2(0, -3), - healthColor, healthColor); - - lineRenderer.DrawLine(xy + new float2(0, -2), - z + new float2(0, -2), - healthColor2, healthColor2); - - lineRenderer.DrawLine(xy + new float2(0, -4), - z + new float2(0, -4), - healthColor2, healthColor2); - } - - if (ShowUnitPaths) - { - var mobile = selectedUnit.traits.GetOrDefault(); - if (mobile != null) - { - var path = mobile.GetCurrentPath(); - var start = selectedUnit.Location; - - foreach (var step in path) - { - lineRenderer.DrawLine( - Game.CellSize * start + new float2(12, 12), - Game.CellSize * step + new float2(12, 12), - Color.Red, Color.Red); - start = step; - } - } + lineRenderer.DrawLine(XY, XY + new float2(0, -4), c, c); + + if (drawHealthBar) + { + c = Color.Gray; + 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.unitInfo.Strength; + var healthColor = (healthAmount < conditionRed) ? Color.Red + : (healthAmount < conditionYellow) ? Color.Yellow + : Color.LimeGreen; + + var healthColor2 = Color.FromArgb( + 255, + healthColor.R / 2, + healthColor.G / 2, + healthColor.B / 2); + + var z = float2.Lerp(xy, Xy, healthAmount); + + lineRenderer.DrawLine(z + new float2(0, -4), Xy + new float2(0,-4), c, c); + lineRenderer.DrawLine(z + new float2(0, -2), Xy + new float2(0, -2), c, c); + + lineRenderer.DrawLine(xy + new float2(0, -3), + z + new float2(0, -3), + healthColor, healthColor); + + lineRenderer.DrawLine(xy + new float2(0, -2), + z + new float2(0, -2), + healthColor2, healthColor2); + + lineRenderer.DrawLine(xy + new float2(0, -4), + z + new float2(0, -4), + healthColor2, healthColor2); + } + + if (ShowUnitPaths) + { + var mobile = selectedUnit.traits.GetOrDefault(); + if (mobile != null) + { + var path = mobile.GetCurrentPath(); + var start = selectedUnit.Location; + + foreach (var step in path) + { + lineRenderer.DrawLine( + Game.CellSize * start + new float2(12, 12), + Game.CellSize * step + new float2(12, 12), + Color.Red, Color.Red); + start = step; + } + } } } } diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index a509ba8e5e..c9fd6de09e 100755 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -2,7 +2,7 @@ using System.Drawing; using System.Windows.Forms; using OpenRa.FileFormats; using OpenRa.Game.Graphics; -using OpenRa.TechTree; +using OpenRa.TechTree; using System.Runtime.InteropServices; namespace OpenRa.Game @@ -48,9 +48,9 @@ namespace OpenRa.Game bool windowed = !settings.GetValue("fullscreen", false); renderer = new Renderer(this, GetResolution(settings), windowed); - SheetBuilder.Initialize(renderer); - - UiOverlay.ShowUnitDebug = settings.GetValue("udebug", false); + SheetBuilder.Initialize(renderer); + + UiOverlay.ShowUnitDebug = settings.GetValue("udebug", false); WorldRenderer.ShowUnitPaths = settings.GetValue("pathdebug", false); Game.Initialize(settings.GetValue("map", "scg11eb.ini"), renderer, new int2(ClientSize), diff --git a/OpenRa.Game/MoveOrder.cs b/OpenRa.Game/MoveOrder.cs deleted file mode 100644 index 57bbfeac5b..0000000000 --- a/OpenRa.Game/MoveOrder.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Linq; -using OpenRa.Game.Traits; - -namespace OpenRa.Game -{ - abstract class Order - { - public abstract void Apply(bool doVoice); - } - - class MoveOrder : Order - { - public readonly Actor Unit; - public readonly int2 Destination; - - public MoveOrder(Actor unit, int2 destination) - { - this.Unit = unit; - this.Destination = destination; - } - - string GetVoiceSuffix() - { - var suffixes = new[] { ".r01", ".r03" }; - return suffixes[Unit.traits.Get().Voice]; - } - - public override void Apply(bool doVoice) - { - if (doVoice && Game.LocalPlayer == Unit.Owner) - Game.PlaySound(Game.SovietVoices.First.GetNext() + GetVoiceSuffix(), false); - - var mobile = Unit.traits.Get(); - mobile.Cancel(Unit); - mobile.QueueActivity(new Mobile.MoveTo(Destination)); - - var attackBase = Unit.traits.WithInterface().FirstOrDefault(); - if (attackBase != null) - attackBase.target = null; /* move cancels attack order */ - } - } -} diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 157744246f..c82c6b29b7 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -1,196 +1,197 @@ - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {0DFB103F-2962-400F-8C6D-E2C28CCBA633} - WinExe - Properties - OpenRa.Game - OpenRa.Game - - - 2.0 - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - v3.5 - - - true - bin\x86\Debug\ - DEBUG;TRACE - true - full - x86 - false - prompt - - - bin\x86\Release\ - TRACE - true - true - pdbonly - x86 - false - prompt - - - - False - ..\Ijw.DirectX\Release\Ijw.DirectX.dll - - - False - ..\Ijw.DirectX\Ijw.Framework\IjwFramework\bin\Debug\IjwFramework.dll - - - False - ..\thirdparty\irrKlang.NET2.0.dll - - - - 3.5 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Form - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {2F9E7A23-56C0-4286-9C8E-1060A9B2F073} - OpenRa.DataStructures - - - {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA} - OpenRa.FileFormats - - - - - False - .NET Framework 2.0 %28x86%29 - true - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - - - - - - + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {0DFB103F-2962-400F-8C6D-E2C28CCBA633} + WinExe + Properties + OpenRa.Game + OpenRa.Game + + + 2.0 + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + v3.5 + + + true + bin\x86\Debug\ + DEBUG;TRACE + true + full + x86 + false + prompt + + + bin\x86\Release\ + TRACE + true + true + pdbonly + x86 + false + prompt + + + + False + ..\Ijw.DirectX\Release\Ijw.DirectX.dll + + + False + ..\Ijw.DirectX\Ijw.Framework\IjwFramework\bin\Debug\IjwFramework.dll + + + False + ..\thirdparty\irrKlang.NET2.0.dll + + + + 3.5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Form + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {2F9E7A23-56C0-4286-9C8E-1060A9B2F073} + OpenRa.DataStructures + + + {BDAEAB25-991E-46A7-AF1E-4F0E03358DAA} + OpenRa.FileFormats + + + + + False + .NET Framework 2.0 %28x86%29 + true + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + + + + + + \ No newline at end of file diff --git a/OpenRa.Game/Order.cs b/OpenRa.Game/Order.cs new file mode 100644 index 0000000000..a3a4686899 --- /dev/null +++ b/OpenRa.Game/Order.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; +using OpenRa.Game.Traits; + +namespace OpenRa.Game +{ + sealed class Order + { + public readonly Player Player; + public readonly string OrderString; + public readonly Actor Subject; + public readonly Actor TargetActor; + public readonly int2 TargetLocation; + public readonly string TargetString; + + private Order( Player player, string orderString, Actor subject, Actor targetActor, int2 targetLocation, string targetString ) + { + this.Player = player; + this.OrderString = orderString; + this.Subject = subject; + this.TargetActor = targetActor; + this.TargetLocation = targetLocation; + this.TargetString = targetString; + } + + // TODO: serialize / deserialize + + public static Order Attack( Actor subject, Actor target ) + { + return new Order( subject.Owner, "Attack", subject, target, int2.Zero, null ); + } + + public static Order Move( Actor subject, int2 target ) + { + return new Order( subject.Owner, "Move", subject, null, target, null ); + } + + public static Order DeployMcv( Actor subject ) + { + return new Order( subject.Owner, "DeployMcv", subject, null, int2.Zero, null ); + } + + public static Order PlaceBuilding( Player subject, int2 target, string buildingName ) + { + return new Order( subject, "PlaceBuilding", null, null, target, buildingName ); + } + } +} diff --git a/OpenRa.Game/PlaceBuilding.cs b/OpenRa.Game/PlaceBuilding.cs index 02095050f8..aa8e2f1817 100644 --- a/OpenRa.Game/PlaceBuilding.cs +++ b/OpenRa.Game/PlaceBuilding.cs @@ -1,53 +1,53 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OpenRa.Game.GameRules; - -namespace OpenRa.Game -{ - class PlaceBuilding : IOrderGenerator - { - public readonly Player Owner; - public readonly string Name; - - public PlaceBuilding(Player owner, string name) - { - Owner = owner; - Name = name; - } - - public IEnumerable Order(int2 xy, bool lmb) - { - if( lmb ) - { - // todo: check that space is free - var bi = (UnitInfo.BuildingInfo)Rules.UnitInfo[ Name ]; - if( Footprint.Tiles( bi, xy ).Any( - t => !Game.IsCellBuildable( t, - bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel ) ) ) - yield break; - - var maxDistance = bi.Adjacent + 2; /* real-ra is weird. this is 1 GAP. */ - if( !Footprint.Tiles( bi, xy ).Any( - t => Game.GetDistanceToBase( t, Owner ) < maxDistance ) ) - yield break; - - yield return new PlaceBuildingOrder( this, xy ); - } - else // rmb - { - Game.world.AddFrameEndTask( _ => - { - Game.controller.orderGenerator = null; - Game.worldRenderer.uiOverlay.KillOverlay(); - } ); - } - } - - public void PrepareOverlay(int2 xy) - { - Game.worldRenderer.uiOverlay.SetCurrentOverlay(xy, Name); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.GameRules; + +namespace OpenRa.Game +{ + class PlaceBuilding : IOrderGenerator + { + public readonly Player Owner; + public readonly string Name; + + public PlaceBuilding(Player owner, string name) + { + Owner = owner; + Name = name; + } + + public IEnumerable Order(int2 xy, bool lmb) + { + if( lmb ) + { + // todo: check that space is free + var bi = (UnitInfo.BuildingInfo)Rules.UnitInfo[ Name ]; + if( Footprint.Tiles( bi, xy ).Any( + t => !Game.IsCellBuildable( t, + bi.WaterBound ? UnitMovementType.Float : UnitMovementType.Wheel ) ) ) + yield break; + + var maxDistance = bi.Adjacent + 2; /* real-ra is weird. this is 1 GAP. */ + if( !Footprint.Tiles( bi, xy ).Any( + t => Game.GetDistanceToBase( t, Owner ) < maxDistance ) ) + yield break; + + yield return OpenRa.Game.Order.PlaceBuilding( Owner, xy, Name ); + } + else // rmb + { + Game.world.AddFrameEndTask( _ => + { + Game.controller.orderGenerator = null; + Game.worldRenderer.uiOverlay.KillOverlay(); + } ); + } + } + + public void PrepareOverlay(int2 xy) + { + Game.worldRenderer.uiOverlay.SetCurrentOverlay(xy, Name); + } + } +} diff --git a/OpenRa.Game/PlaceBuildingOrder.cs b/OpenRa.Game/PlaceBuildingOrder.cs deleted file mode 100644 index a5de59a3f6..0000000000 --- a/OpenRa.Game/PlaceBuildingOrder.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenRa.Game -{ - class PlaceBuildingOrder : Order - { - PlaceBuilding building; - int2 xy; - - public PlaceBuildingOrder( PlaceBuilding building, int2 xy ) - { - this.building = building; - this.xy = xy; - } - - public override void Apply(bool doVoice) - { - Game.world.AddFrameEndTask( _ => - { - Log.Write( "Player \"{0}\" builds {1}", building.Owner.PlayerName, building.Name ); - - //Adjust placement for cursor to be in middle - Game.world.Add( new Actor( building.Name, xy - GameRules.Footprint.AdjustForBuildingSize( building.Name ), building.Owner ) ); - - Game.controller.orderGenerator = null; - Game.worldRenderer.uiOverlay.KillOverlay(); - } ); - } - } -} diff --git a/OpenRa.Game/Traits/Activities/DeployMcv.cs b/OpenRa.Game/Traits/Activities/DeployMcv.cs new file mode 100755 index 0000000000..241e9fdc16 --- /dev/null +++ b/OpenRa.Game/Traits/Activities/DeployMcv.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits.Activities +{ + class DeployMcv : Mobile.CurrentActivity + { + public Mobile.CurrentActivity NextActivity { get; set; } + + public void Tick( Actor self, Mobile mobile ) + { + Game.world.AddFrameEndTask( _ => + { + Game.world.Remove( self ); + Game.world.Add( new Actor( "fact", self.Location - new int2( 1, 1 ), self.Owner ) ); + } ); + } + + public void Cancel( Actor self, Mobile mobile ) + { + // Cancel can't happen between this being moved to the head of the list, and it being Ticked. + throw new InvalidOperationException( "DeployMcvAction: Cancel() should never occur." ); + } + } +} diff --git a/OpenRa.Game/Traits/AttackTurreted.cs b/OpenRa.Game/Traits/AttackTurreted.cs index 2b0f92e3f8..bae3f1e05c 100755 --- a/OpenRa.Game/Traits/AttackTurreted.cs +++ b/OpenRa.Game/Traits/AttackTurreted.cs @@ -1,111 +1,79 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenRa.Game.Traits -{ - abstract class AttackBase : IOrder - { - public Actor target; - - // time (in frames) until each weapon can fire again. - protected int primaryFireDelay = 0; - protected int secondaryFireDelay = 0; - - protected bool CanAttack( Actor self ) - { - if( primaryFireDelay > 0 ) --primaryFireDelay; - if( secondaryFireDelay > 0 ) --secondaryFireDelay; - - if( target != null && target.IsDead ) target = null; /* he's dead, jim. */ - if( target == null ) return false; - - return true; - } - - protected void DoAttack( Actor self ) - { - if( self.unitInfo.Primary != null && CheckFire( self, self.unitInfo.Primary, ref primaryFireDelay ) ) - { - secondaryFireDelay = Math.Max( 4, secondaryFireDelay ); - return; - } - if( self.unitInfo.Secondary != null && CheckFire( self, self.unitInfo.Secondary, ref secondaryFireDelay ) ) - return; - } - - bool CheckFire( Actor self, string weaponName, ref int fireDelay ) - { - if( fireDelay > 0 ) return false; - var weapon = Rules.WeaponInfo[ weaponName ]; - if( weapon.Range * weapon.Range < ( target.Location - self.Location ).LengthSquared ) return false; - - fireDelay = weapon.ROF; - - Game.world.Add( new Bullet( weaponName, self.Owner, self, - self.CenterLocation.ToInt2(), - target.CenterLocation.ToInt2() ) ); - - return true; - } - - public Order Order( Actor self, int2 xy, bool lmb, Actor underCursor ) - { - if( lmb || underCursor == null ) return null; - - if( underCursor.Owner == self.Owner ) return null; - - return new AttackOrder( self, underCursor ); - } - } - - class AttackTurreted : AttackBase, ITick - { - public AttackTurreted( Actor self ) { self.traits.Get(); } - - public void Tick(Actor self) - { - if( !CanAttack( self ) ) return; - - var turreted = self.traits.Get(); - turreted.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, turreted.turretFacing ); - if( turreted.desiredFacing != turreted.turretFacing ) - return; - - DoAttack( self ); - } - } - - class AttackOrder : Order - { - public readonly Actor Attacker; - public readonly Actor Target; - - const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ - - public AttackOrder( Actor attacker, Actor target ) - { - this.Attacker = attacker; - this.Target = target; - } - - public override void Apply( bool doVoice ) - { - var mobile = Attacker.traits.GetOrDefault(); - if (mobile != null) - { - var weapon = Attacker.unitInfo.Primary ?? Attacker.unitInfo.Secondary; - /* todo: choose the appropriate weapon, when only one works against this target */ - var range = Rules.WeaponInfo[weapon].Range; - - mobile.Cancel(Attacker); - mobile.QueueActivity( - new Mobile.MoveTo(Target, - Math.Max(0, (int)range - RangeTolerance))); - } - - Attacker.traits.Get().target = Target; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + abstract class AttackBase : IOrder + { + public Actor target; + + // time (in frames) until each weapon can fire again. + protected int primaryFireDelay = 0; + protected int secondaryFireDelay = 0; + + protected bool CanAttack( Actor self ) + { + if( primaryFireDelay > 0 ) --primaryFireDelay; + if( secondaryFireDelay > 0 ) --secondaryFireDelay; + + if( target != null && target.IsDead ) target = null; /* he's dead, jim. */ + if( target == null ) return false; + + return true; + } + + protected void DoAttack( Actor self ) + { + if( self.unitInfo.Primary != null && CheckFire( self, self.unitInfo.Primary, ref primaryFireDelay ) ) + { + secondaryFireDelay = Math.Max( 4, secondaryFireDelay ); + return; + } + if( self.unitInfo.Secondary != null && CheckFire( self, self.unitInfo.Secondary, ref secondaryFireDelay ) ) + return; + } + + bool CheckFire( Actor self, string weaponName, ref int fireDelay ) + { + if( fireDelay > 0 ) return false; + var weapon = Rules.WeaponInfo[ weaponName ]; + if( weapon.Range * weapon.Range < ( target.Location - self.Location ).LengthSquared ) return false; + + fireDelay = weapon.ROF; + + Game.world.Add( new Bullet( weaponName, self.Owner, self, + self.CenterLocation.ToInt2(), + target.CenterLocation.ToInt2() ) ); + + return true; + } + + public Order Order( Actor self, int2 xy, bool lmb, Actor underCursor ) + { + if( lmb || underCursor == null ) return null; + + if( underCursor.Owner == self.Owner ) return null; + + return OpenRa.Game.Order.Attack( self, underCursor ); + } + } + + class AttackTurreted : AttackBase, ITick + { + public AttackTurreted( Actor self ) { self.traits.Get(); } + + public void Tick(Actor self) + { + if( !CanAttack( self ) ) return; + + var turreted = self.traits.Get(); + turreted.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, turreted.turretFacing ); + if( turreted.desiredFacing != turreted.turretFacing ) + return; + + DoAttack( self ); + } + } +} diff --git a/OpenRa.Game/Traits/McvDeploy.cs b/OpenRa.Game/Traits/McvDeploy.cs index 5b63fa10f8..204f0aa67c 100644 --- a/OpenRa.Game/Traits/McvDeploy.cs +++ b/OpenRa.Game/Traits/McvDeploy.cs @@ -1,64 +1,25 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace OpenRa.Game.Traits -{ - class McvDeploy : IOrder - { - public McvDeploy(Actor self) - { - } - - public Order Order(Actor self, int2 xy, bool lmb, Actor underCursor) - { - if( lmb ) return null; - - // TODO: check that there's enough space at the destination. - if( xy == self.Location ) - return new DeployMcvOrder( self, xy ); - - return null; - } - } - - class DeployMcvOrder : Order - { - Actor Unit; - int2 Location; - - public DeployMcvOrder( Actor unit, int2 location ) - { - Unit = unit; - Location = location; - } - - public override void Apply( bool doVoice ) - { - var mobile = Unit.traits.Get(); - mobile.QueueActivity( new Mobile.Turn( 96 ) ); - mobile.QueueActivity( new DeployAction() ); - } - - class DeployAction : Mobile.CurrentActivity - { - public Mobile.CurrentActivity NextActivity { get; set; } - - public void Tick( Actor self, Mobile mobile ) - { - Game.world.AddFrameEndTask( _ => - { - Game.world.Remove( self ); - Game.world.Add( new Actor( "fact", self.Location - new int2( 1, 1 ), self.Owner ) ); - } ); - } - - public void Cancel( Actor self, Mobile mobile ) - { - // Cancel can't happen between this being moved to the head of the list, and it being Ticked. - throw new InvalidOperationException( "DeployMcvAction: Cancel() should never occur." ); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class McvDeploy : IOrder + { + public McvDeploy(Actor self) + { + } + + public Order Order(Actor self, int2 xy, bool lmb, Actor underCursor) + { + if( lmb ) return null; + + // TODO: check that there's enough space at the destination. + if( xy == self.Location ) + return OpenRa.Game.Order.DeployMcv( self ); + + return null; + } + } +} diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs index e2f9a0f4fc..900c614191 100644 --- a/OpenRa.Game/Traits/Mobile.cs +++ b/OpenRa.Game/Traits/Mobile.cs @@ -21,7 +21,7 @@ namespace OpenRa.Game.Traits public Mobile(Actor self) { this.self = self; - fromCell = toCell; + fromCell = toCell; Game.UnitInfluence.Update( this ); } @@ -55,8 +55,8 @@ namespace OpenRa.Game.Traits if( underCursor != null ) return null; - if (xy != toCell) - return new MoveOrder(self, xy); + if( xy != toCell ) + return OpenRa.Game.Order.Move( self, xy ); return null; } diff --git a/OpenRa.Game/UnitOrders.cs b/OpenRa.Game/UnitOrders.cs new file mode 100755 index 0000000000..de2a61fc18 --- /dev/null +++ b/OpenRa.Game/UnitOrders.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Traits; + +namespace OpenRa.Game +{ + static class UnitOrders + { + public static void ProcessOrder( Order order ) + { + switch( order.OrderString ) + { + case "Move": + { + var mobile = order.Subject.traits.Get(); + mobile.Cancel( order.Subject ); + mobile.QueueActivity( new Mobile.MoveTo( order.TargetLocation ) ); + + var attackBase = order.Subject.traits.WithInterface().FirstOrDefault(); + if( attackBase != null ) + attackBase.target = null; /* move cancels attack order */ + break; + } + case "Attack": + { + const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ + var mobile = order.Subject.traits.GetOrDefault(); + var weapon = order.Subject.unitInfo.Primary ?? order.Subject.unitInfo.Secondary; + + mobile.Cancel( order.Subject ); + // TODO: this block should be a separate activity; "MoveNear", maybe? + { + /* todo: choose the appropriate weapon, when only one works against this target */ + var range = Rules.WeaponInfo[ weapon ].Range; + + mobile.QueueActivity( + new Mobile.MoveTo( order.TargetActor, + Math.Max( 0, (int)range - RangeTolerance ) ) ); + } + + order.Subject.traits.Get().target = order.TargetActor; + break; + } + case "DeployMcv": + { + var mobile = order.Subject.traits.Get(); + mobile.QueueActivity( new Mobile.Turn( 96 ) ); + mobile.QueueActivity( new Traits.Activities.DeployMcv() ); + break; + } + case "PlaceBuilding": + { + Game.world.AddFrameEndTask( _ => + { + var building = Rules.UnitInfo[ order.TargetString ]; + Log.Write( "Player \"{0}\" builds {1}", order.Player.PlayerName, building.Name ); + + //Adjust placement for cursor to be in middle + Game.world.Add( new Actor( building.Name, order.TargetLocation - GameRules.Footprint.AdjustForBuildingSize( building.Name ), order.Player ) ); + + Game.controller.orderGenerator = null; + Game.worldRenderer.uiOverlay.KillOverlay(); + } ); + break; + } + default: + throw new NotImplementedException(); + } + } + } +}