diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 7c775fd7a2..b7010bbdbe 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -26,6 +26,7 @@ namespace OpenRa.Game readonly Animation repairButton; readonly Animation sellButton; + readonly Animation pwrdownButton; readonly SpriteRenderer buildPaletteRenderer; readonly Animation cantBuild; @@ -77,6 +78,9 @@ namespace OpenRa.Game sellButton = new Animation("sell"); sellButton.PlayRepeating("normal"); + + pwrdownButton = new Animation("repair"); + pwrdownButton.PlayRepeating("normal"); blank = SheetBuilder.Add(new Size(64, 48), 16); @@ -285,7 +289,7 @@ namespace OpenRa.Game // Repair - Rectangle repairRect = new Rectangle(Game.viewport.Width - 100, 5, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height); + Rectangle repairRect = new Rectangle(Game.viewport.Width - 120, 5, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height); var repairDrawPos = Game.viewport.Location + new float2(repairRect.Location); var hasFact = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains()); @@ -300,7 +304,7 @@ namespace OpenRa.Game buildPaletteRenderer.DrawSprite(repairButton.Image, repairDrawPos, PaletteType.Chrome); // Sell - Rectangle sellRect = new Rectangle(Game.viewport.Width - 60, 5, + Rectangle sellRect = new Rectangle(Game.viewport.Width - 80, 5, sellButton.Image.bounds.Width, sellButton.Image.bounds.Height); var sellDrawPos = Game.viewport.Location + new float2(sellRect.Location); @@ -310,6 +314,21 @@ namespace OpenRa.Game AddButton(sellRect, isLmb => Game.controller.ToggleInputMode()); buildPaletteRenderer.DrawSprite(sellButton.Image, sellDrawPos, PaletteType.Chrome); buildPaletteRenderer.Flush(); + + if (Game.Settings.PowerDownBuildings) + { + // Power Down + Rectangle pwrdownRect = new Rectangle(Game.viewport.Width - 40, 5, + pwrdownButton.Image.bounds.Width, pwrdownButton.Image.bounds.Height); + + var pwrdownDrawPos = Game.viewport.Location + new float2(pwrdownRect.Location); + + pwrdownButton.ReplaceAnim(Game.controller.orderGenerator is PowerDownOrderGenerator ? "pressed" : "normal"); + + AddButton(pwrdownRect, isLmb => Game.controller.ToggleInputMode()); + buildPaletteRenderer.DrawSprite(pwrdownButton.Image, pwrdownDrawPos, PaletteType.Chrome); + } + buildPaletteRenderer.Flush(); } void HandleChronosphereButton() diff --git a/OpenRa.Game/Cursor.cs b/OpenRa.Game/Cursor.cs index ee4115a229..54ebacc76d 100644 --- a/OpenRa.Game/Cursor.cs +++ b/OpenRa.Game/Cursor.cs @@ -32,5 +32,6 @@ namespace OpenRa.Game public static Cursor SellBlocked { get { return new Cursor("sell-blocked"); } } public static Cursor Repair { get { return new Cursor("repair"); } } public static Cursor RepairBlocked { get { return new Cursor("repair-blocked"); } } + public static Cursor PowerDown { get { return new Cursor("powerdown"); } } } } diff --git a/OpenRa.Game/GameRules/UserSettings.cs b/OpenRa.Game/GameRules/UserSettings.cs index fd102cf4bd..8c441320f3 100644 --- a/OpenRa.Game/GameRules/UserSettings.cs +++ b/OpenRa.Game/GameRules/UserSettings.cs @@ -27,6 +27,7 @@ namespace OpenRa.Game.GameRules // Gameplay options public readonly bool RepairRequiresConyard = true; + public readonly bool PowerDownBuildings = true; } } diff --git a/OpenRa.Game/Graphics/CursorSheetBuilder.cs b/OpenRa.Game/Graphics/CursorSheetBuilder.cs index 333a225da9..1a6b7291e3 100644 --- a/OpenRa.Game/Graphics/CursorSheetBuilder.cs +++ b/OpenRa.Game/Graphics/CursorSheetBuilder.cs @@ -11,8 +11,16 @@ namespace OpenRa.Game.Graphics static Sprite[] LoadCursors(string filename) { - var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts)); - return shp.Select(a => SheetBuilder.Add(a.Image, a.Size)).ToArray(); + try + { + var shp = new Dune2ShpReader(FileSystem.OpenWithExts(filename, exts)); + return shp.Select(a => SheetBuilder.Add(a.Image, a.Size)).ToArray(); + } + catch (System.IndexOutOfRangeException) // This will occur when loading a custom (RA-format) .shp + { + var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts)); + return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray(); + } } public static Sprite[] LoadAllSprites(string filename) { return cursors[filename]; } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 72f4caec37..5aa72ea0c5 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -103,6 +103,7 @@ + diff --git a/OpenRa.Game/Orders/PowerDownOrderGenerator.cs b/OpenRa.Game/Orders/PowerDownOrderGenerator.cs new file mode 100644 index 0000000000..5779e81a20 --- /dev/null +++ b/OpenRa.Game/Orders/PowerDownOrderGenerator.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.GameRules; +using OpenRa.Game.Traits; + +namespace OpenRa.Game.Orders +{ + class PowerDownOrderGenerator : IOrderGenerator + { + public IEnumerable Order(int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Right) + Game.controller.CancelInputMode(); + + return OrderInner(xy, mi); + } + + IEnumerable OrderInner(int2 xy, MouseInput mi) + { + if (mi.Button == MouseButton.Left) + { + var loc = mi.Location + Game.viewport.Location; + var underCursor = Game.FindUnits(loc, loc) + .Where(a => a.Owner == Game.LocalPlayer + && a.traits.Contains() + && a.Info.Selectable).FirstOrDefault(); + + var building = underCursor != null ? underCursor.Info as BuildingInfo : null; + + if (building != null) + yield return new Order("PowerDown", underCursor, null, int2.Zero, null); + } + } + + public void Tick() { } + public void Render() { } + + public Cursor GetCursor(int2 xy, MouseInput mi) + { + mi.Button = MouseButton.Left; + return OrderInner(xy, mi).Any() + ? Cursor.PowerDown : Cursor.PowerDown; + } + } +} diff --git a/OpenRa.Game/Player.cs b/OpenRa.Game/Player.cs index 5e40e92b32..5f1684ef50 100644 --- a/OpenRa.Game/Player.cs +++ b/OpenRa.Game/Player.cs @@ -1,5 +1,6 @@ using System; using System.Linq; +using System.Collections.Generic; using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; using OpenRa.Game.Traits; @@ -52,11 +53,11 @@ namespace OpenRa.Game foreach (var a in myBuildings) { - var bi = a.Info as BuildingInfo; - if (bi.Power > 0) /* todo: is this how real-ra scales it? */ - PowerProvided += (a.Health * bi.Power) / bi.Strength; + var p = a.traits.Get().GetPowerUsage(); + if (p > 0) + PowerProvided += p; else - PowerDrained -= bi.Power; + PowerDrained -= p; } if (PowerProvided - PowerDrained < 0) diff --git a/OpenRa.Game/Traits/AttackTurreted.cs b/OpenRa.Game/Traits/AttackTurreted.cs index 256bd25379..5ccfbdaeb5 100755 --- a/OpenRa.Game/Traits/AttackTurreted.cs +++ b/OpenRa.Game/Traits/AttackTurreted.cs @@ -26,12 +26,9 @@ namespace OpenRa.Game.Traits protected override void QueueAttack( Actor self, Order order ) { - var bi = self.Info as BuildingInfo; - if (bi != null && bi.Powered && self.Owner.GetPowerState() != PowerState.Normal) - { - if (self.Owner == Game.LocalPlayer) Sound.Play("nopowr1.aud"); + var bi = self.traits.Get(); + if (bi != null && !bi.IsActive()) return; - } 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 */ diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs index 5beea8d05f..ffdc657b17 100644 --- a/OpenRa.Game/Traits/Building.cs +++ b/OpenRa.Game/Traits/Building.cs @@ -10,15 +10,34 @@ namespace OpenRa.Game.Traits { class Building : INotifyDamage, IOrder, ITick { + readonly Actor self; public readonly BuildingInfo unitInfo; bool isRepairing = false; + bool isPoweredDown = false; public Building(Actor self) { + this.self = self; unitInfo = (BuildingInfo)self.Info; self.CenterLocation = Game.CellSize * ((float2)self.Location + .5f * (float2)unitInfo.Dimensions); } + + public bool IsActive() + { + return !(isPoweredDown || (unitInfo.Powered && self.Owner.GetPowerState() != PowerState.Normal)); + } + + public int GetPowerUsage() + { + if (isPoweredDown) + return 0; + + if (unitInfo.Power > 0) /* todo: is this how real-ra scales it? */ + return (self.Health * unitInfo.Power) / unitInfo.Strength; + else + return unitInfo.Power; + } public void Damaged(Actor self, AttackInfo e) { @@ -43,6 +62,11 @@ namespace OpenRa.Game.Traits { isRepairing = !isRepairing; } + + if (order.OrderString == "PowerDown") + { + isPoweredDown = !isPoweredDown; + } } int remainingTicks; diff --git a/sequences.xml b/sequences.xml index f659cf186a..2abe5428ed 100644 --- a/sequences.xml +++ b/sequences.xml @@ -401,6 +401,9 @@ + + +