From dab388630b0672d82448df89065f68d88d0395d4 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 18:25:19 +1300 Subject: [PATCH 01/56] Screen fade on chonotank teleport (needs tweaking to replicate real-ra) --- OpenRa.Game/Traits/ChronoshiftDeploy.cs | 70 ++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/OpenRa.Game/Traits/ChronoshiftDeploy.cs b/OpenRa.Game/Traits/ChronoshiftDeploy.cs index 2730b979e7..f4bdc69cb2 100644 --- a/OpenRa.Game/Traits/ChronoshiftDeploy.cs +++ b/OpenRa.Game/Traits/ChronoshiftDeploy.cs @@ -1,19 +1,40 @@ using System.Collections.Generic; using System.Linq; using OpenRa.Game.Orders; +using System.Drawing; namespace OpenRa.Game.Traits { - class ChronoshiftDeploy : IOrder, ISpeedModifier, ITick, IPips + class ChronoshiftDeploy : IOrder, ISpeedModifier, ITick, IPips, IPaletteModifier { public ChronoshiftDeploy(Actor self) { } + // Recharge logic int remainingChargeTime = 0; // How long until we can chronoshift again? int chargeTime = (int)(Rules.Aftermath.ChronoTankDuration * 60 * 25); // How long between shifts? + // Screen fade logic + int animationTick = 0; + int animationLength = 10; + bool animationStarted = false; public void Tick(Actor self) { if (remainingChargeTime > 0) remainingChargeTime--; + + if (animationStarted) + { + if (animationTick < animationLength) + animationTick++; + else + animationStarted = false; + } + if (!animationStarted) + { + if (animationTick > 0) + animationTick--; + //else + // animationForwards = true; + } } public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) @@ -42,6 +63,7 @@ namespace OpenRa.Game.Traits self.QueueActivity(new Activities.Teleport(order.TargetLocation)); Sound.Play("chrotnk1.aud"); remainingChargeTime = chargeTime; + animationStarted = true; } } @@ -78,5 +100,51 @@ namespace OpenRa.Game.Traits } } } + + public void AdjustPalette(Bitmap bmp) + { + if (!animationStarted && animationTick == 0) + return; + + // saturation modifier + var f = 1 - (animationTick * 1.0f / animationLength); + + using (var bitmapCopy = new Bitmap(bmp)) + for (int j = 0; j < 8; j++) + for (int i = 0; i < bmp.Width; i++) + { + var h = bitmapCopy.GetPixel(i, j).GetHue(); // 0-360 + var s = f * bitmapCopy.GetPixel(i, j).GetSaturation(); // 0-1.0 + var l = bitmapCopy.GetPixel(i, j).GetBrightness(); // 0-1.0 + var alpha = bitmapCopy.GetPixel(i, j).A; + + // Convert from HSL to RGB + // Refactor me! + var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s); + var p = 2 * l - q; + var hk = h / 360.0f; + + double[] trgb = { hk + 1 / 3.0f, + hk, + hk - 1/3.0f }; + double[] rgb = { 0, 0, 0 }; + + for (int k = 0; k < 3; k++) + { + // mod doesn't seem to work right... do it manually + while (trgb[k] < 0) trgb[k] += 1.0f; + while (trgb[k] > 1) trgb[k] -= 1.0f; + } + + for (int k = 0; k < 3; k++) + { + if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); } + else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; } + else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); } + else { rgb[k] = p; } + } + bmp.SetPixel(i, j, Color.FromArgb(alpha, (int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255))); + } + } } } From 67cda2162bd18f01402c223556b54cc571ea353c Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 18:50:52 +1300 Subject: [PATCH 02/56] Fix chronoshift cursor --- OpenRa.Game/Orders/TeleportOrderGenerator.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/OpenRa.Game/Orders/TeleportOrderGenerator.cs b/OpenRa.Game/Orders/TeleportOrderGenerator.cs index 3fca07bc4b..4c9375105f 100644 --- a/OpenRa.Game/Orders/TeleportOrderGenerator.cs +++ b/OpenRa.Game/Orders/TeleportOrderGenerator.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; +using OpenRa.Game.Traits; namespace OpenRa.Game.Orders { @@ -34,7 +35,8 @@ namespace OpenRa.Game.Orders public Cursor GetCursor(int2 xy, MouseInput mi) { - return Cursor.Chronoshift; + var movement = self.traits.WithInterface().FirstOrDefault(); + return (movement.CanEnterCell(xy)) ? Cursor.Chronoshift : Cursor.MoveBlocked; } } } From a1fc5406ea60374ab8a371ff0d3e92662ae9e748 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 20:07:56 +1300 Subject: [PATCH 03/56] settings stuff --- OpenRa.Game/GameRules/UserSettings.cs | 2 +- OpenRa.Game/MainWindow.cs | 37 ++++++++++++--------------- settings-netplay-local.ini | 3 +++ 3 files changed, 20 insertions(+), 22 deletions(-) create mode 100644 settings-netplay-local.ini diff --git a/OpenRa.Game/GameRules/UserSettings.cs b/OpenRa.Game/GameRules/UserSettings.cs index bc502d4c36..fd102cf4bd 100644 --- a/OpenRa.Game/GameRules/UserSettings.cs +++ b/OpenRa.Game/GameRules/UserSettings.cs @@ -26,7 +26,7 @@ namespace OpenRa.Game.GameRules public readonly string Replay = ""; // Gameplay options - public readonly bool RepairRequiresConyard = false; + public readonly bool RepairRequiresConyard = true; } } diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index 8d1d61ce81..67a8d7c6e6 100755 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -4,9 +4,9 @@ using System.IO; using System.Runtime.InteropServices; using System.Windows.Forms; using OpenRa.FileFormats; +using OpenRa.Game.GameRules; using OpenRa.Game.Graphics; using OpenRa.Game.Orders; -using OpenRa.Game.GameRules; namespace OpenRa.Game @@ -31,51 +31,33 @@ namespace OpenRa.Game [DllImport("user32")] static extern int ShowCursor([MarshalAs(UnmanagedType.Bool)] bool visible); - - public MainWindow(Settings settings) { - - FormBorderStyle = FormBorderStyle.None; BackColor = Color.Black; StartPosition = FormStartPosition.Manual; Location = Point.Empty; Visible = true; - // Load user settings - Game.Settings = new UserSettings(); - while (!File.Exists("redalert.mix")) { var current = Directory.GetCurrentDirectory(); if (Directory.GetDirectoryRoot(current) == current) throw new InvalidOperationException("Unable to load MIX files."); Directory.SetCurrentDirectory(".."); - - try - { - // settings.ini should be located with the mix files - FileSystem.MountTemporary(new Folder("./")); - IniFile SettingsRules = new IniFile(FileSystem.Open("settings.ini")); - FieldLoader.Load(Game.Settings, SettingsRules.GetSection("Settings")); - FileSystem.UnmountTemporaryPackages(); - } - catch (FileNotFoundException) { } } + LoadUserSettings(settings); + UiOverlay.ShowUnitDebug = Game.Settings.UnitDebug; UiOverlay.ShowBuildDebug = Game.Settings.BuildingDebug; WorldRenderer.ShowUnitPaths = Game.Settings.PathDebug; Renderer.SheetSize = Game.Settings.SheetSize; - FileSystem.MountDefaultPackages(); if (Game.Settings.UseAftermath) - { FileSystem.MountAftermathPackages(); - } bool windowed = !Game.Settings.Fullscreen; renderer = new Renderer(this, GetResolution(settings), windowed); @@ -89,6 +71,19 @@ namespace OpenRa.Game Game.ResetTimer(); } + static void LoadUserSettings(Settings settings) + { + Game.Settings = new UserSettings(); + var settingsFile = settings.GetValue("settings", "settings.ini"); + // if (FileSystem.Exists(settingsFile)) + { + FileSystem.MountTemporary(new Folder("./")); + FieldLoader.Load(Game.Settings, + new IniFile(FileSystem.Open(settingsFile)).GetSection("Settings")); + FileSystem.UnmountTemporaryPackages(); + } + } + internal void Run() { while (Created && Visible) diff --git a/settings-netplay-local.ini b/settings-netplay-local.ini new file mode 100644 index 0000000000..7d13c14222 --- /dev/null +++ b/settings-netplay-local.ini @@ -0,0 +1,3 @@ +[Settings] +NetworkHost=localhost +NetworkPort=1234 \ No newline at end of file From c35f3f0bfb6ed014380169404d929f276d9fd385 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 20:16:55 +1300 Subject: [PATCH 04/56] invuln etc palette need hacked too. --- OpenRa.Game/Traits/ChronoshiftDeploy.cs | 3 ++- settings-netplay-local-aftermath.ini | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 settings-netplay-local-aftermath.ini diff --git a/OpenRa.Game/Traits/ChronoshiftDeploy.cs b/OpenRa.Game/Traits/ChronoshiftDeploy.cs index b2c280cf8e..df9726d26f 100644 --- a/OpenRa.Game/Traits/ChronoshiftDeploy.cs +++ b/OpenRa.Game/Traits/ChronoshiftDeploy.cs @@ -2,6 +2,7 @@ using System.Linq; using OpenRa.Game.Orders; using System.Drawing; +using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { @@ -109,7 +110,7 @@ namespace OpenRa.Game.Traits var f = 1 - (animationTick * 1.0f / animationLength); using (var bitmapCopy = new Bitmap(bmp)) - for (int j = 0; j < 8; j++) + for (int j = 0; j < (int)PaletteType.Chrome; j++) for (int i = 0; i < bmp.Width; i++) { var h = bitmapCopy.GetPixel(i, j).GetHue(); // 0-360 diff --git a/settings-netplay-local-aftermath.ini b/settings-netplay-local-aftermath.ini new file mode 100644 index 0000000000..fef7a12f8c --- /dev/null +++ b/settings-netplay-local-aftermath.ini @@ -0,0 +1,4 @@ +[Settings] +NetworkHost=localhost +NetworkPort=1234 +UseAftermath=yes \ No newline at end of file From 41e04c96386e4329098836e61ec1d15836afba14 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 20:19:00 +1300 Subject: [PATCH 05/56] min build palette height = 4 --- OpenRa.Game/Chrome.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 12844e1aed..c40e233cbb 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -40,6 +40,8 @@ namespace OpenRa.Game readonly int paletteColumns; readonly int2 paletteOrigin; + + const int MinRows = 4; public Chrome(Renderer r) { @@ -96,7 +98,7 @@ namespace OpenRa.Game cantBuild = new Animation("clock"); cantBuild.PlayFetchIndex("idle", () => 0); - digitSprites = OpenRa.Game.Graphics.Util.MakeArray(10, a => a) + digitSprites = Graphics.Util.MakeArray(10, a => a) .Select(n => new Sprite(specialBin, new Rectangle(32 + 13 * n, 0, 13, 17), TextureChannel.Alpha)).ToList(); shimSprites = new[] @@ -392,7 +394,7 @@ namespace OpenRa.Game if (++x == columns) { x = 0; y++; } } - while (x != 0) + while (x != 0 || y < MinRows) { var rect = new Rectangle(origin.X + x * 64, origin.Y + 48 * y, 64, 48); var drawPos = Game.viewport.Location + new float2(rect.Location); From 5757b904b29fadcdb0c4a8fde69dbc10a6bb3d15 Mon Sep 17 00:00:00 2001 From: Alli Date: Sun, 3 Jan 2010 21:39:44 +1300 Subject: [PATCH 06/56] uncommented settings.ini existance check --- OpenRa.Game/MainWindow.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index 67a8d7c6e6..d4d570a4ff 100755 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -75,7 +75,7 @@ namespace OpenRa.Game { Game.Settings = new UserSettings(); var settingsFile = settings.GetValue("settings", "settings.ini"); - // if (FileSystem.Exists(settingsFile)) + if (FileSystem.Exists(settingsFile)) { FileSystem.MountTemporary(new Folder("./")); FieldLoader.Load(Game.Settings, From 8d761abb4f0ce3b64835fdbcb764f7fa2978c77b Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 21:51:54 +1300 Subject: [PATCH 07/56] Basic chronosphere behavior --- OpenRa.Game/Chrome.cs | 18 ++- OpenRa.Game/Cursor.cs | 3 +- OpenRa.Game/OpenRa.Game.csproj | 5 +- ...> ChronoshiftDestinationOrderGenerator.cs} | 4 +- .../ChronosphereSelectOrderGenerator.cs | 57 ++++++++ OpenRa.Game/Traits/ChronoshiftDeploy.cs | 4 +- OpenRa.Game/Traits/Chronoshiftable.cs | 127 ++++++++++++++++++ OpenRa.Game/Traits/Chronosphere.cs | 12 ++ aftermathUnits.ini | 12 +- sequences.xml | 3 +- session.ini | 4 +- units.ini | 40 +++--- 12 files changed, 254 insertions(+), 35 deletions(-) rename OpenRa.Game/Orders/{TeleportOrderGenerator.cs => ChronoshiftDestinationOrderGenerator.cs} (83%) create mode 100644 OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs create mode 100644 OpenRa.Game/Traits/Chronoshiftable.cs create mode 100644 OpenRa.Game/Traits/Chronosphere.cs diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 12844e1aed..3d29042c2b 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -26,7 +26,7 @@ namespace OpenRa.Game readonly Animation repairButton; readonly Animation sellButton; - + readonly SpriteRenderer buildPaletteRenderer; readonly Animation cantBuild; readonly Animation ready; @@ -245,6 +245,22 @@ namespace OpenRa.Game void DrawButtons() { + // Chronoshift + Rectangle chronoshiftRect = new Rectangle(6, 14, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height); + var chronoshiftDrawPos = Game.viewport.Location + new float2(chronoshiftRect.Location); + + var hasChronosphere = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains()); + + if (!hasChronosphere) + repairButton.ReplaceAnim("disabled"); + else + { + //repairButton.ReplaceAnim(Game.controller.orderGenerator is RepairOrderGenerator ? "pressed" : "normal"); + AddButton(chronoshiftRect, isLmb => Game.controller.ToggleInputMode()); + } + buildPaletteRenderer.DrawSprite(repairButton.Image, chronoshiftDrawPos, PaletteType.Chrome); + + // Repair Rectangle repairRect = new Rectangle(Game.viewport.Width - 100, 5, repairButton.Image.bounds.Width, repairButton.Image.bounds.Height); var repairDrawPos = Game.viewport.Location + new float2(repairRect.Location); diff --git a/OpenRa.Game/Cursor.cs b/OpenRa.Game/Cursor.cs index d5ff149cb9..23f380a32e 100644 --- a/OpenRa.Game/Cursor.cs +++ b/OpenRa.Game/Cursor.cs @@ -22,7 +22,8 @@ namespace OpenRa.Game public static Cursor Deploy { get { return new Cursor("deploy"); } } public static Cursor Enter { get { return new Cursor("enter"); } } public static Cursor DeployBlocked { get { return new Cursor("deploy-blocked"); } } - public static Cursor Chronoshift { get { return new Cursor("chrono"); } } + public static Cursor Chronoshift { get { return new Cursor("chrono-target"); } } + public static Cursor ChronoshiftSelect { get { return new Cursor("chrono-select"); } } public static Cursor C4 { get { return new Cursor("c4"); } } public static Cursor Capture { get { return new Cursor("capture"); } } public static Cursor Heal { get { return new Cursor("heal"); } } diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index d5903beeee..d13fdbe492 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -95,6 +95,7 @@ + @@ -103,7 +104,7 @@ - + @@ -196,6 +197,8 @@ + + diff --git a/OpenRa.Game/Orders/TeleportOrderGenerator.cs b/OpenRa.Game/Orders/ChronoshiftDestinationOrderGenerator.cs similarity index 83% rename from OpenRa.Game/Orders/TeleportOrderGenerator.cs rename to OpenRa.Game/Orders/ChronoshiftDestinationOrderGenerator.cs index 4c9375105f..e85e248752 100644 --- a/OpenRa.Game/Orders/TeleportOrderGenerator.cs +++ b/OpenRa.Game/Orders/ChronoshiftDestinationOrderGenerator.cs @@ -7,11 +7,11 @@ using OpenRa.Game.Traits; namespace OpenRa.Game.Orders { - class TeleportOrderGenerator : IOrderGenerator + class ChronoshiftDestinationOrderGenerator : IOrderGenerator { public readonly Actor self; - public TeleportOrderGenerator(Actor self) + public ChronoshiftDestinationOrderGenerator(Actor self) { this.self = self; } diff --git a/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs new file mode 100644 index 0000000000..ffc5ea7b09 --- /dev/null +++ b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs @@ -0,0 +1,57 @@ +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 ChronosphereSelectOrderGenerator : 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 unit = underCursor != null ? underCursor.Info as UnitInfo : null; + + if (unit != null) + { + yield return new Order("ChronosphereSelect", underCursor, null, int2.Zero, null); + } + } + } + + public void Tick() + { + var hasChronosphere = Game.world.Actors + .Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains()); + + if (!hasChronosphere) + Game.controller.CancelInputMode(); + } + + public void Render() { } + + public Cursor GetCursor(int2 xy, MouseInput mi) + { + mi.Button = MouseButton.Left; + return OrderInner(xy, mi).Any() + ? Cursor.ChronoshiftSelect : Cursor.MoveBlocked; + } + } +} diff --git a/OpenRa.Game/Traits/ChronoshiftDeploy.cs b/OpenRa.Game/Traits/ChronoshiftDeploy.cs index b2c280cf8e..3f577df4b4 100644 --- a/OpenRa.Game/Traits/ChronoshiftDeploy.cs +++ b/OpenRa.Game/Traits/ChronoshiftDeploy.cs @@ -49,7 +49,7 @@ namespace OpenRa.Game.Traits { if (order.OrderString == "Deploy") { - Game.controller.orderGenerator = new TeleportOrderGenerator(self); + Game.controller.orderGenerator = new ChronoshiftDestinationOrderGenerator(self); return; } @@ -68,7 +68,7 @@ namespace OpenRa.Game.Traits public float GetSpeedModifier() { // ARGH! You must not do this, it will desync! - return (Game.controller.orderGenerator is TeleportOrderGenerator) ? 0f : 1f; + return (Game.controller.orderGenerator is ChronoshiftDestinationOrderGenerator) ? 0f : 1f; } // Display 5 pips indicating the current charge status diff --git a/OpenRa.Game/Traits/Chronoshiftable.cs b/OpenRa.Game/Traits/Chronoshiftable.cs new file mode 100644 index 0000000000..84f004a310 --- /dev/null +++ b/OpenRa.Game/Traits/Chronoshiftable.cs @@ -0,0 +1,127 @@ +using OpenRa.Game.Traits; +using OpenRa.Game.Orders; +using System.Collections.Generic; +using System.Linq; +using System.Drawing; + +namespace OpenRa.Game.Traits +{ + class Chronoshiftable : IOrder, ISpeedModifier, ITick, IPaletteModifier + { + // Return-to-sender logic + int2 chronoshiftOrigin; + int chronoshiftReturnTicks = 0; + + // Screen fade logic + int animationTick = 0; + int animationLength = 10; + bool animationStarted = false; + + public Chronoshiftable(Actor self) { } + + public void Tick(Actor self) + { + if (animationStarted) + { + if (animationTick < animationLength) + animationTick++; + else + animationStarted = false; + } + else if (animationTick > 0) + animationTick--; + + if (chronoshiftReturnTicks <= 0) + return; + + if (chronoshiftReturnTicks > 0) + chronoshiftReturnTicks--; + + // Return to original location + if (chronoshiftReturnTicks == 0) + { + self.CancelActivity(); + // Todo: need a new Teleport method that will move to the closest available cell + self.QueueActivity(new Activities.Teleport(chronoshiftOrigin)); + } + } + + public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) + { + return null; // Chronoshift order is issued through Chrome. + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "ChronosphereSelect") + { + Game.controller.orderGenerator = new ChronoshiftDestinationOrderGenerator(self); + } + + var movement = self.traits.WithInterface().FirstOrDefault(); + if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation)) + { + chronoshiftOrigin = self.Location; + chronoshiftReturnTicks = (int)(Rules.General.ChronoDuration * 60 * 25); + // TODO: Kill cargo if Rules.General.ChronoKillCargo says so + Game.controller.CancelInputMode(); + self.CancelActivity(); + self.QueueActivity(new Activities.Teleport(order.TargetLocation)); + Sound.Play("chrono2.aud"); + animationStarted = true; + } + } + + public float GetSpeedModifier() + { + // ARGH! You must not do this, it will desync! + return (Game.controller.orderGenerator is ChronoshiftDestinationOrderGenerator) ? 0f : 1f; + } + + public void AdjustPalette(Bitmap bmp) + { + if (!animationStarted && animationTick == 0) + return; + + // saturation modifier + var f = 1 - (animationTick * 1.0f / animationLength); + + using (var bitmapCopy = new Bitmap(bmp)) + for (int j = 0; j < 8; j++) + for (int i = 0; i < bmp.Width; i++) + { + var h = bitmapCopy.GetPixel(i, j).GetHue(); // 0-360 + var s = f * bitmapCopy.GetPixel(i, j).GetSaturation(); // 0-1.0 + var l = bitmapCopy.GetPixel(i, j).GetBrightness(); // 0-1.0 + var alpha = bitmapCopy.GetPixel(i, j).A; + + // Convert from HSL to RGB + // Refactor me! + var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s); + var p = 2 * l - q; + var hk = h / 360.0f; + + double[] trgb = { hk + 1 / 3.0f, + hk, + hk - 1/3.0f }; + double[] rgb = { 0, 0, 0 }; + + for (int k = 0; k < 3; k++) + { + // mod doesn't seem to work right... do it manually + while (trgb[k] < 0) trgb[k] += 1.0f; + while (trgb[k] > 1) trgb[k] -= 1.0f; + } + + for (int k = 0; k < 3; k++) + { + if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); } + else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; } + else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); } + else { rgb[k] = p; } + } + bmp.SetPixel(i, j, Color.FromArgb(alpha, (int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255))); + } + } + } +} diff --git a/OpenRa.Game/Traits/Chronosphere.cs b/OpenRa.Game/Traits/Chronosphere.cs new file mode 100644 index 0000000000..cad8a1cf13 --- /dev/null +++ b/OpenRa.Game/Traits/Chronosphere.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class Chronosphere + { + public Chronosphere(Actor self) { } + } +} diff --git a/aftermathUnits.ini b/aftermathUnits.ini index b0599a1ccd..f48554b9d7 100755 --- a/aftermathUnits.ini +++ b/aftermathUnits.ini @@ -7,28 +7,28 @@ QTNK [STNK] Description=Stealth Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, Cloak +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, Cloak, Chronoshiftable Recoil=2 Voice=VehicleVoice [TTNK] Description=Tesla Tank -Traits=Unit, Mobile, AttackBase, RenderUnitSpinner +Traits=Unit, Mobile, AttackBase, RenderUnitSpinner, Chronoshiftable Voice=VehicleVoice [CTNK] Description=Chrono Tank -Traits=Unit, Mobile, AttackBase, RenderUnit, ChronoshiftDeploy +Traits=Unit, Mobile, AttackBase, RenderUnit, ChronoshiftDeploy, Chronoshiftable Voice=VehicleVoice [DTRK] Description=Demo Truck -Traits=Unit, Mobile, AttackBase, RenderUnit +Traits=Unit, Mobile, AttackBase, RenderUnit, Chronoshiftable Voice=VehicleVoice [QTNK] Description=M.A.D. Tank -Traits=Unit, Mobile, RenderUnit +Traits=Unit, Mobile, RenderUnit, Chronoshiftable Voice=VehicleVoice @@ -42,7 +42,7 @@ MSUB Description=Missile Submarine WaterBound=yes BuiltAt=spen -Traits=Unit, Mobile, AttackBase, RenderUnit, Submarine +Traits=Unit, Mobile, AttackBase, RenderUnit, Submarine, Chronoshiftable FireDelay=2 diff --git a/sequences.xml b/sequences.xml index 18ad5e5e17..7e8d0a9378 100644 --- a/sequences.xml +++ b/sequences.xml @@ -376,7 +376,8 @@ - + + diff --git a/session.ini b/session.ini index e78029b52a..acafbf8481 100644 --- a/session.ini +++ b/session.ini @@ -8,4 +8,6 @@ s0=Multi0,mcv,600,2841,0,Guard,None s1=Multi2,mcv,600,12445,0,Guard,None s2=Multi1,mcv,600,12505,0,Guard,None ;s2=Multi1,e3,600,12505,0,Guard,None -s3=Multi3,mcv,600,2910,0,Guard,None \ No newline at end of file +s3=Multi3,mcv,600,2910,0,Guard,None +;s4=Multi1,ctnk,600,12506,Gaurd,None +s5=Multi1,pdox,600,12510,Gaurd,None \ No newline at end of file diff --git a/units.ini b/units.ini index 335bc7017f..5f54681c07 100644 --- a/units.ini +++ b/units.ini @@ -16,47 +16,47 @@ MNLY.AT [V2RL] Description=V2 Rocket -Traits=Unit, Mobile, AttackBase, RenderUnitReload, AutoTarget, Repairable +Traits=Unit, Mobile, AttackBase, RenderUnitReload, AutoTarget, Repairable, Chronoshiftable Voice=VehicleVoice LongDesc=Long-range rocket artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft [1TNK] Description=Light Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable Recoil=2 Voice=VehicleVoice LongDesc=Light Tank, good for scouting.\n Strong vs Light Vehicles\n Weak vs Tanks, Aircraft [2TNK] Description=Medium Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable Recoil=3 Voice=VehicleVoice LongDesc=Allied Main Battle Tank.\n Strong vs Tanks, Light Vehicles\n Weak vs Infantry, Aircraft [3TNK] Description=Heavy Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable Recoil=3 Voice=VehicleVoice LongDesc=Soviet Main Battle Tank, with dual cannons\n Strong vs Tanks, Light Vehicles\n Weak vs Infantry, Aircraft [4TNK] Description=Mammoth Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable Voice=VehicleVoice LongDesc=Big and slow tank, with anti-air capability.\n Strong vs Tanks, Aircraft\n Weak vs Infantry [ARTY] Description=Artillery -Traits=Unit, Mobile, AttackBase, RenderUnit, Explodes, AutoTarget, Repairable +Traits=Unit, Mobile, AttackBase, RenderUnit, Explodes, AutoTarget, Repairable, Chronoshiftable Voice=VehicleVoice LongDesc=Long-range artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft [JEEP] Description=Ranger -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable PrimaryOffset=0,0,0,-2 MuzzleFlash=yes Voice=VehicleVoice LongDesc=Fast scout & anti-infantry vehicle.\n Strong vs Infantry\n Weak vs Tanks, Aircraft [APC] Description=Armored Personnel Carrier -Traits=Unit, Mobile, AttackBase, RenderUnitMuzzleFlash, AutoTarget, Repairable +Traits=Unit, Mobile, AttackBase, RenderUnitMuzzleFlash, AutoTarget, Repairable, Chronoshiftable PrimaryOffset=0,0,0,-4 MuzzleFlash=yes Voice=VehicleVoice @@ -65,40 +65,40 @@ LongDesc=Tough infantry transport.\n Strong vs Infantry, Light Vehicles\n Weak ;; non-combat vehicles [MRJ] Description=Radar Jammer -Traits=Unit, Mobile, RenderUnitSpinner, Repairable +Traits=Unit, Mobile, RenderUnitSpinner, Repairable, Chronoshiftable PrimaryOffset=0,4,0,-6 SelectionPriority=3 Voice=VehicleVoice LongDesc=Hides nearby units on the enemy's minimap.\n Unarmed [MGG] Description=Mobile Gap Generator -Traits=Unit, Mobile, RenderUnitSpinner, Repairable +Traits=Unit, Mobile, RenderUnitSpinner, Repairable, Chronoshiftable PrimaryOffset=0,6,0,-3 SelectionPriority=3 Voice=VehicleVoice LongDesc=Regenerates Fog of War in a small area \naround the unit.\n Unarmed [HARV] Description=Ore Truck -Traits=Harvester, Unit, Mobile, RenderUnit, Repairable +Traits=Harvester, Unit, Mobile, RenderUnit, Repairable, Chronoshiftable SelectionPriority=7 Voice=VehicleVoice LongDesc=Collects Ore and Gems for processing.\n Unarmed [MCV] Description=Mobile Construction Vehicle -Traits=Unit, Mobile, McvDeploy, RenderUnit, Repairable +Traits=Unit, Mobile, McvDeploy, RenderUnit, Repairable, Chronoshiftable SelectionPriority=3 Voice=VehicleVoice LongDesc=Deploys into another Construction Yard.\n Unarmed [MNLY.AP] Description=Minelayer (Anti-Personnel) -Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo +Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo, Chronoshiftable Voice=VehicleVoice LongDesc=Lays mines to destroy unwary enemy units.\n Unarmed Primary=MINP ;; temporary hack [MNLY.AT] Description=Minelayer (Anti-Tank) -Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo +Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo, Chronoshiftable Voice=VehicleVoice LongDesc=Lays mines to destroy unwary enemy units.\n Unarmed Primary=MINV ;; temporary hack @@ -116,21 +116,21 @@ PT Description=Submarine WaterBound=yes BuiltAt=spen -Traits=Unit, Mobile, RenderUnit, Submarine, AttackBase +Traits=Unit, Mobile, RenderUnit, Submarine, AttackBase, Chronoshiftable FireDelay=2 LongDesc=Submerged anti-ship unit armed with \ntorpedoes.\n Strong vs Ships\n Weak vs Everything\n Special Ability: Submerge [DD] Description=Destroyer WaterBound=yes BuiltAt=syrd -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Chronoshiftable PrimaryOffset=0,-8,0,-3 LongDesc=Fast multi-role ship. \n Strong vs Submarines, Aircraft\n Weak vs Infantry, Tanks [CA] Description=Cruiser WaterBound=yes BuiltAt=syrd -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Chronoshiftable PrimaryOffset=0,17,0,-2 SecondaryOffset=0,-17,0,-2 LongDesc=Very slow long-range ship. \n Strong vs Buildings\n Weak vs Ships, Submarines @@ -138,13 +138,13 @@ Recoil=3 [LST] Description=Transport WaterBound=yes -Traits=Unit, Mobile, RenderUnit +Traits=Unit, Mobile, RenderUnit, Chronoshiftable LongDesc=General-purpose naval transport.\nCan carry infantry and tanks.\n Unarmed [PT] Description=Gunboat WaterBound=yes BuiltAt=syrd -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Chronoshiftable PrimaryOffset=0,-6,0,-1 LongDesc=Light scout & support ship. \n Strong vs Ships, Submarines\n Weak vs Aircraft @@ -289,7 +289,7 @@ SelectionPriority=3 LongDesc=Makes a group of units invulnerable for a \nshort time.\n Special Ability: Invulnerability [PDOX] Description=Chronosphere -Traits=Building, RenderBuilding +Traits=Building, RenderBuilding, Chronosphere Dimensions=2,2 Footprint=xx xx SelectionPriority=3 From de1ae72229afa31f259cc9f1f1e7831a00c8da97 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 22:07:16 +1300 Subject: [PATCH 08/56] Chronosphere animation and don't shift LST --- OpenRa.Game/Traits/Chronoshiftable.cs | 14 +++++++++++++- units.ini | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/OpenRa.Game/Traits/Chronoshiftable.cs b/OpenRa.Game/Traits/Chronoshiftable.cs index 84f004a310..e14dad3f95 100644 --- a/OpenRa.Game/Traits/Chronoshiftable.cs +++ b/OpenRa.Game/Traits/Chronoshiftable.cs @@ -14,7 +14,7 @@ namespace OpenRa.Game.Traits // Screen fade logic int animationTick = 0; - int animationLength = 10; + int animationLength = 20; bool animationStarted = false; public Chronoshiftable(Actor self) { } @@ -61,14 +61,26 @@ namespace OpenRa.Game.Traits var movement = self.traits.WithInterface().FirstOrDefault(); if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation)) { + + // Set up return-to-sender info chronoshiftOrigin = self.Location; chronoshiftReturnTicks = (int)(Rules.General.ChronoDuration * 60 * 25); + // TODO: Kill cargo if Rules.General.ChronoKillCargo says so + + // Set up the teleport Game.controller.CancelInputMode(); self.CancelActivity(); self.QueueActivity(new Activities.Teleport(order.TargetLocation)); Sound.Play("chrono2.aud"); + + // Start the screen-fade animation animationStarted = true; + + // Play chronosphere active anim + var chronosphere = Game.world.Actors.Where(a => a.Owner == order.Subject.Owner && a.traits.Contains()).FirstOrDefault(); + if (chronosphere != null) + chronosphere.traits.Get().PlayCustomAnim(chronosphere, "active"); } } diff --git a/units.ini b/units.ini index 5f54681c07..5b0d90121e 100644 --- a/units.ini +++ b/units.ini @@ -138,7 +138,7 @@ Recoil=3 [LST] Description=Transport WaterBound=yes -Traits=Unit, Mobile, RenderUnit, Chronoshiftable +Traits=Unit, Mobile, RenderUnit LongDesc=General-purpose naval transport.\nCan carry infantry and tanks.\n Unarmed [PT] Description=Gunboat From 4ff41fcc15692264a3503b56ed7160c3b174a8b5 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 22:16:52 +1300 Subject: [PATCH 09/56] unfail palette effect --- OpenRa.Game/Game.cs | 1 + OpenRa.Game/OpenRa.Game.csproj | 1 + OpenRa.Game/Traits/ChronoshiftDeploy.cs | 72 ++----------------- .../Traits/ChronoshiftPaletteEffect.cs | 54 ++++++++++++++ OpenRa.Game/Traits/Chronoshiftable.cs | 67 ++--------------- 5 files changed, 64 insertions(+), 131 deletions(-) create mode 100644 OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index 964f9012e7..a068834f48 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -73,6 +73,7 @@ namespace OpenRa.Game var worldActor = new Actor(null, new int2(int.MaxValue, int.MaxValue), null); worldActor.traits.Add(new Traits.WaterPaletteRotation(worldActor)); + worldActor.traits.Add(new Traits.ChronoshiftPaletteEffect(worldActor)); Game.world.Add(worldActor); Rules.Map.InitOreDensity(); diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index d13fdbe492..68cfee2a41 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -198,6 +198,7 @@ + diff --git a/OpenRa.Game/Traits/ChronoshiftDeploy.cs b/OpenRa.Game/Traits/ChronoshiftDeploy.cs index 6208a7ef4e..cd02343320 100644 --- a/OpenRa.Game/Traits/ChronoshiftDeploy.cs +++ b/OpenRa.Game/Traits/ChronoshiftDeploy.cs @@ -1,21 +1,14 @@ using System.Collections.Generic; using System.Linq; using OpenRa.Game.Orders; -using System.Drawing; -using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { - class ChronoshiftDeploy : IOrder, ISpeedModifier, ITick, IPips, IPaletteModifier + class ChronoshiftDeploy : IOrder, ISpeedModifier, ITick, IPips { // Recharge logic int chargeTick = 0; // How long until we can chronoshift again? int chargeLength = (int)(Rules.Aftermath.ChronoTankDuration * 60 * 25); // How long between shifts? - - // Screen fade logic - int animationTick = 0; - int animationLength = 10; - bool animationStarted = false; public ChronoshiftDeploy(Actor self) { } @@ -23,19 +16,6 @@ namespace OpenRa.Game.Traits { if (chargeTick > 0) chargeTick--; - - if (animationStarted) - { - if (animationTick < animationLength) - animationTick++; - else - animationStarted = false; - } - if (!animationStarted) - { - if (animationTick > 0) - animationTick--; - } } public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) @@ -62,7 +42,9 @@ namespace OpenRa.Game.Traits self.QueueActivity(new Activities.Teleport(order.TargetLocation)); Sound.Play("chrotnk1.aud"); chargeTick = chargeLength; - animationStarted = true; + + foreach (var a in Game.world.Actors.Where(a => a.traits.Contains())) + a.traits.Get().DoChronoshift(); } } @@ -100,51 +82,5 @@ namespace OpenRa.Game.Traits } } } - - public void AdjustPalette(Bitmap bmp) - { - if (!animationStarted && animationTick == 0) - return; - - // saturation modifier - var f = 1 - (animationTick * 1.0f / animationLength); - - using (var bitmapCopy = new Bitmap(bmp)) - for (int j = 0; j < (int)PaletteType.Chrome; j++) - for (int i = 0; i < bmp.Width; i++) - { - var h = bitmapCopy.GetPixel(i, j).GetHue(); // 0-360 - var s = f * bitmapCopy.GetPixel(i, j).GetSaturation(); // 0-1.0 - var l = bitmapCopy.GetPixel(i, j).GetBrightness(); // 0-1.0 - var alpha = bitmapCopy.GetPixel(i, j).A; - - // Convert from HSL to RGB - // Refactor me! - var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s); - var p = 2 * l - q; - var hk = h / 360.0f; - - double[] trgb = { hk + 1 / 3.0f, - hk, - hk - 1/3.0f }; - double[] rgb = { 0, 0, 0 }; - - for (int k = 0; k < 3; k++) - { - // mod doesn't seem to work right... do it manually - while (trgb[k] < 0) trgb[k] += 1.0f; - while (trgb[k] > 1) trgb[k] -= 1.0f; - } - - for (int k = 0; k < 3; k++) - { - if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); } - else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; } - else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); } - else { rgb[k] = p; } - } - bmp.SetPixel(i, j, Color.FromArgb(alpha, (int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255))); - } - } } } diff --git a/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs new file mode 100644 index 0000000000..09efc58efb --- /dev/null +++ b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs @@ -0,0 +1,54 @@ +using System.Drawing; +using OpenRa.Game.Graphics; + +namespace OpenRa.Game.Traits +{ + class ChronoshiftPaletteEffect : IPaletteModifier, ITick + { + const int chronoEffectLength = 10; + int remainingFrames; + + public ChronoshiftPaletteEffect(Actor self) { } + + public void DoChronoshift() + { + remainingFrames = chronoEffectLength; + } + + public void Tick(Actor self) + { + if (remainingFrames > 0) + remainingFrames--; + } + + public void AdjustPalette(Bitmap b) + { + if (remainingFrames == 0) + return; + + var frac = (float)remainingFrames / chronoEffectLength; + for( var y = 0; y < (int)PaletteType.Chrome; y++ ) + for (var x = 0; x < 256; x++) + { + var orig = b.GetPixel(x, y); + var lum = (int)(255 * orig.GetBrightness()); + var desat = Color.FromArgb(orig.A, lum, lum, lum); + b.SetPixel(x, y, Lerp(frac, orig, desat)); + } + } + + static Color Lerp(float t, Color a, Color b) + { + return Color.FromArgb( + LerpChannel(t, a.A, b.A), + LerpChannel(t, a.R, b.R), + LerpChannel(t, a.G, b.G), + LerpChannel(t, a.B, b.B)); + } + + static int LerpChannel(float t, int a, int b) + { + return (int)((1 - t) * a + t * b); + } + } +} diff --git a/OpenRa.Game/Traits/Chronoshiftable.cs b/OpenRa.Game/Traits/Chronoshiftable.cs index 84f004a310..bbdbb88048 100644 --- a/OpenRa.Game/Traits/Chronoshiftable.cs +++ b/OpenRa.Game/Traits/Chronoshiftable.cs @@ -6,31 +6,16 @@ using System.Drawing; namespace OpenRa.Game.Traits { - class Chronoshiftable : IOrder, ISpeedModifier, ITick, IPaletteModifier + class Chronoshiftable : IOrder, ISpeedModifier, ITick { // Return-to-sender logic int2 chronoshiftOrigin; int chronoshiftReturnTicks = 0; - // Screen fade logic - int animationTick = 0; - int animationLength = 10; - bool animationStarted = false; - public Chronoshiftable(Actor self) { } public void Tick(Actor self) { - if (animationStarted) - { - if (animationTick < animationLength) - animationTick++; - else - animationStarted = false; - } - else if (animationTick > 0) - animationTick--; - if (chronoshiftReturnTicks <= 0) return; @@ -68,7 +53,9 @@ namespace OpenRa.Game.Traits self.CancelActivity(); self.QueueActivity(new Activities.Teleport(order.TargetLocation)); Sound.Play("chrono2.aud"); - animationStarted = true; + + foreach (var a in Game.world.Actors.Where(a => a.traits.Contains())) + a.traits.Get().DoChronoshift(); } } @@ -77,51 +64,5 @@ namespace OpenRa.Game.Traits // ARGH! You must not do this, it will desync! return (Game.controller.orderGenerator is ChronoshiftDestinationOrderGenerator) ? 0f : 1f; } - - public void AdjustPalette(Bitmap bmp) - { - if (!animationStarted && animationTick == 0) - return; - - // saturation modifier - var f = 1 - (animationTick * 1.0f / animationLength); - - using (var bitmapCopy = new Bitmap(bmp)) - for (int j = 0; j < 8; j++) - for (int i = 0; i < bmp.Width; i++) - { - var h = bitmapCopy.GetPixel(i, j).GetHue(); // 0-360 - var s = f * bitmapCopy.GetPixel(i, j).GetSaturation(); // 0-1.0 - var l = bitmapCopy.GetPixel(i, j).GetBrightness(); // 0-1.0 - var alpha = bitmapCopy.GetPixel(i, j).A; - - // Convert from HSL to RGB - // Refactor me! - var q = (l < 0.5f) ? l * (1 + s) : l + s - (l * s); - var p = 2 * l - q; - var hk = h / 360.0f; - - double[] trgb = { hk + 1 / 3.0f, - hk, - hk - 1/3.0f }; - double[] rgb = { 0, 0, 0 }; - - for (int k = 0; k < 3; k++) - { - // mod doesn't seem to work right... do it manually - while (trgb[k] < 0) trgb[k] += 1.0f; - while (trgb[k] > 1) trgb[k] -= 1.0f; - } - - for (int k = 0; k < 3; k++) - { - if (trgb[k] < 1 / 6.0f) { rgb[k] = (p + ((q - p) * 6 * trgb[k])); } - else if (trgb[k] >= 1 / 6.0f && trgb[k] < 0.5) { rgb[k] = q; } - else if (trgb[k] >= 0.5f && trgb[k] < 2.0f / 3) { rgb[k] = (p + ((q - p) * 6 * (2.0f / 3 - trgb[k]))); } - else { rgb[k] = p; } - } - bmp.SetPixel(i, j, Color.FromArgb(alpha, (int)(rgb[0] * 255), (int)(rgb[1] * 255), (int)(rgb[2] * 255))); - } - } } } From 326cda76cc232deed841de7c468c897e0ca97905 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 22:17:08 +1300 Subject: [PATCH 10/56] Select Target notification for chronosphere --- OpenRa.Game/Chrome.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 71e59fd0b7..c9d626ad38 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -258,7 +258,7 @@ namespace OpenRa.Game else { //repairButton.ReplaceAnim(Game.controller.orderGenerator is RepairOrderGenerator ? "pressed" : "normal"); - AddButton(chronoshiftRect, isLmb => Game.controller.ToggleInputMode()); + AddButton(chronoshiftRect, isLmb => HandleChronosphereButton()); } buildPaletteRenderer.DrawSprite(repairButton.Image, chronoshiftDrawPos, PaletteType.Chrome); @@ -291,6 +291,12 @@ namespace OpenRa.Game buildPaletteRenderer.Flush(); } + void HandleChronosphereButton() + { + Sound.Play("slcttgt1.aud"); + Game.controller.ToggleInputMode(); + } + void DrawChat() { var chatpos = new int2(400, Game.viewport.Height - 20); From f498dd15e2889685bfd76135a4752192ec368a90 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 22:19:51 +1300 Subject: [PATCH 11/56] oops; didnt mean to revert the anim length change --- OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs index 09efc58efb..fb5dff901c 100644 --- a/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs +++ b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs @@ -5,7 +5,7 @@ namespace OpenRa.Game.Traits { class ChronoshiftPaletteEffect : IPaletteModifier, ITick { - const int chronoEffectLength = 10; + const int chronoEffectLength = 20; int remainingFrames; public ChronoshiftPaletteEffect(Actor self) { } From c0509a6f2fa2cfa3fd0adf02b48cea90969beb8e Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 22:29:54 +1300 Subject: [PATCH 12/56] Use correct attack cursors --- OpenRa.Game/Cursor.cs | 1 + OpenRa.Game/Orders/UnitOrderGenerator.cs | 2 +- sequences.xml | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/OpenRa.Game/Cursor.cs b/OpenRa.Game/Cursor.cs index 23f380a32e..ee4115a229 100644 --- a/OpenRa.Game/Cursor.cs +++ b/OpenRa.Game/Cursor.cs @@ -19,6 +19,7 @@ namespace OpenRa.Game public static Cursor Select { get { return new Cursor("select"); } } public static Cursor MoveBlocked { get { return new Cursor("move-blocked"); } } public static Cursor Attack { get { return new Cursor("attack"); } } + public static Cursor AttackMove { get { return new Cursor("attackmove"); } } public static Cursor Deploy { get { return new Cursor("deploy"); } } public static Cursor Enter { get { return new Cursor("enter"); } } public static Cursor DeployBlocked { get { return new Cursor("deploy-blocked"); } } diff --git a/OpenRa.Game/Orders/UnitOrderGenerator.cs b/OpenRa.Game/Orders/UnitOrderGenerator.cs index c50379f4e4..ec64b5e9c6 100644 --- a/OpenRa.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRa.Game/Orders/UnitOrderGenerator.cs @@ -84,7 +84,7 @@ namespace OpenRa.Game.Orders case "Deliver": return Cursor.Enter; case "Infiltrate": return Cursor.Enter; case "Capture": return Cursor.Capture; - case "Harvest": return Cursor.Attack; // TODO: special harvest cursor? + case "Harvest": return Cursor.AttackMove; default: return null; } diff --git a/sequences.xml b/sequences.xml index 7e8d0a9378..f659cf186a 100644 --- a/sequences.xml +++ b/sequences.xml @@ -368,7 +368,7 @@ - + @@ -384,7 +384,7 @@ - + @@ -394,8 +394,8 @@ - - + + From 4427228c973098ba6a9603813b63c680bf6ef622 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 22:56:24 +1300 Subject: [PATCH 13/56] fixed settings Exists check --- OpenRa.Game/MainWindow.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index d4d570a4ff..ea0af1b54f 100755 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -75,13 +75,11 @@ namespace OpenRa.Game { Game.Settings = new UserSettings(); var settingsFile = settings.GetValue("settings", "settings.ini"); + FileSystem.MountTemporary(new Folder("./")); if (FileSystem.Exists(settingsFile)) - { - FileSystem.MountTemporary(new Folder("./")); FieldLoader.Load(Game.Settings, new IniFile(FileSystem.Open(settingsFile)).GetSection("Settings")); - FileSystem.UnmountTemporaryPackages(); - } + FileSystem.UnmountTemporaryPackages(); } internal void Run() From cf68f026a6443c6ddf67c0379b5d3aa461c866de Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 23:29:24 +1300 Subject: [PATCH 14/56] minimap sketch --- OpenRa.Game/Chat.cs | 2 +- OpenRa.Game/Chrome.cs | 2 ++ OpenRa.Game/Game.cs | 4 +++ OpenRa.Game/Graphics/Minimap.cs | 44 +++++++++++++++++++++++++++++++++ OpenRa.Game/OpenRa.Game.csproj | 1 + 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 OpenRa.Game/Graphics/Minimap.cs diff --git a/OpenRa.Game/Chat.cs b/OpenRa.Game/Chat.cs index adbac6dcde..f95b214172 100644 --- a/OpenRa.Game/Chat.cs +++ b/OpenRa.Game/Chat.cs @@ -34,7 +34,7 @@ namespace OpenRa.Game typing += c; } - static readonly Color[] paletteColors = + public static readonly Color[] paletteColors = { Color.FromArgb(228, 200, 112), Color.FromArgb(56, 72, 125), diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index c9d626ad38..e090d91897 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -143,6 +143,8 @@ namespace OpenRa.Game int paletteHeight = DrawBuildPalette(currentTab); DrawBuildTabs(paletteHeight); DrawChat(); + + Game.minimap.Draw(new float2(30,30)); } void AddButton(Rectangle r, Action b) { buttons.Add(Pair.New(r, b)); } diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index a068834f48..cb2e3fed1b 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -48,6 +48,7 @@ namespace OpenRa.Game static bool usingAftermath; static int2 clientSize; static HardwarePalette palette; + public static Minimap minimap; public static void ChangeMap(string mapName) { @@ -78,6 +79,7 @@ namespace OpenRa.Game Rules.Map.InitOreDensity(); worldRenderer = new WorldRenderer(renderer); + minimap = new Minimap(renderer); SequenceProvider.Initialize(usingAftermath); viewport = new Viewport(clientSize, Rules.Map.Offset, Rules.Map.Offset + Rules.Map.Size, renderer); @@ -169,6 +171,8 @@ namespace OpenRa.Game lastTime += Settings.Timestep; UpdatePalette(world.Actors.SelectMany( a => a.traits.WithInterface())); + minimap.Update(); + orderManager.TickImmediate(); if (orderManager.IsReadyForNextFrame) diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs new file mode 100644 index 0000000000..a7c3251e55 --- /dev/null +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -0,0 +1,44 @@ +using System.Drawing; + +namespace OpenRa.Game.Graphics +{ + class Minimap + { + Sheet sheet; + SpriteRenderer spriteRenderer; + Sprite sprite; + + public void Tick() { } + + public Minimap(Renderer r) + { + sheet = new Sheet(r, new Size(128, 128)); + spriteRenderer = new SpriteRenderer(r, true, r.RgbaSpriteShader); + sprite = new Sprite(sheet, new Rectangle(0, 0, 128, 128), TextureChannel.Alpha); + } + + public void Update() + { + var bitmap = new Bitmap(128, 128); + + for( var y = 0; y < 128; y++ ) + for (var x = 0; x < 128; x++) + { + // todo: use player color + var b = Game.BuildingInfluence.GetBuildingAt(new int2(x, y)); + if (b != null && b.Owner != null) + bitmap.SetPixel(x, y, Chat.paletteColors[ (int)b.Owner.Palette ]); + //else + // bitmap.SetPixel(x, y, Color.Red); + } + + sheet.Texture.SetData(bitmap); + } + + public void Draw(float2 pos) + { + spriteRenderer.DrawSprite(sprite, pos, PaletteType.Chrome); + spriteRenderer.Flush(); + } + } +} diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 68cfee2a41..844b6e167a 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -95,6 +95,7 @@ + From a269f0683d3a839285aeac4e0d289afcf7ca84e0 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 23:34:05 +1300 Subject: [PATCH 15/56] ugh --- OpenRa.Game/Graphics/Minimap.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index a7c3251e55..4a6ffdaff8 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -24,12 +24,9 @@ namespace OpenRa.Game.Graphics for( var y = 0; y < 128; y++ ) for (var x = 0; x < 128; x++) { - // todo: use player color var b = Game.BuildingInfluence.GetBuildingAt(new int2(x, y)); if (b != null && b.Owner != null) bitmap.SetPixel(x, y, Chat.paletteColors[ (int)b.Owner.Palette ]); - //else - // bitmap.SetPixel(x, y, Color.Red); } sheet.Texture.SetData(bitmap); From 1065f7e7557fe8f302a5938d3fcb9ff09b39ea3c Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 23:36:34 +1300 Subject: [PATCH 16/56] minimap --- OpenRa.Game/Graphics/Minimap.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index 4a6ffdaff8..0616404c20 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -24,6 +24,8 @@ namespace OpenRa.Game.Graphics for( var y = 0; y < 128; y++ ) for (var x = 0; x < 128; x++) { + // todo: terrain, units, perf. + var b = Game.BuildingInfluence.GetBuildingAt(new int2(x, y)); if (b != null && b.Owner != null) bitmap.SetPixel(x, y, Chat.paletteColors[ (int)b.Owner.Palette ]); From 8931a4c94f6774edcd45e2d84572eae5a53bcb43 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Sun, 3 Jan 2010 23:37:34 +1300 Subject: [PATCH 17/56] only say 'Select Target' when pushing chrono, not canceling it --- OpenRa.Game/Chrome.cs | 4 ++-- OpenRa.Game/Controller.cs | 8 +++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index c9d626ad38..06bf3bfd6c 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -293,8 +293,8 @@ namespace OpenRa.Game void HandleChronosphereButton() { - Sound.Play("slcttgt1.aud"); - Game.controller.ToggleInputMode(); + if (Game.controller.ToggleInputMode()) + Sound.Play("slcttgt1.aud"); } void DrawChat() diff --git a/OpenRa.Game/Controller.cs b/OpenRa.Game/Controller.cs index cbe2d35fa3..2653cc28d3 100644 --- a/OpenRa.Game/Controller.cs +++ b/OpenRa.Game/Controller.cs @@ -27,12 +27,18 @@ namespace OpenRa.Game orderGenerator = new UnitOrderGenerator(new Actor[] { }); } - public void ToggleInputMode() where T : IOrderGenerator, new() + public bool ToggleInputMode() where T : IOrderGenerator, new() { if (orderGenerator is T) + { CancelInputMode(); + return false; + } else + { orderGenerator = new T(); + return true; + } } List recentOrders = new List(); From 38ac11e9c75fd8775c5a1d395609f184562c5e18 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 23:54:46 +1300 Subject: [PATCH 18/56] Demotruck logic --- OpenRa.Game/OpenRa.Game.csproj | 1 + OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs | 2 +- OpenRa.Game/Traits/Chronoshiftable.cs | 2 +- OpenRa.Game/Traits/TraitsInterfaces.cs | 2 +- aftermathUnits.ini | 2 +- 5 files changed, 5 insertions(+), 4 deletions(-) diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 68cfee2a41..bcd3b94b09 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -200,6 +200,7 @@ + diff --git a/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs index ffc5ea7b09..ae7de0551f 100644 --- a/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs +++ b/OpenRa.Game/Orders/ChronosphereSelectOrderGenerator.cs @@ -24,7 +24,7 @@ namespace OpenRa.Game.Orders var loc = mi.Location + Game.viewport.Location; var underCursor = Game.FindUnits(loc, loc) .Where(a => a.Owner == Game.LocalPlayer - && a.traits.Contains() + && a.traits.WithInterface().Any() && a.Info.Selectable).FirstOrDefault(); var unit = underCursor != null ? underCursor.Info as UnitInfo : null; diff --git a/OpenRa.Game/Traits/Chronoshiftable.cs b/OpenRa.Game/Traits/Chronoshiftable.cs index 1427cb39d1..bf97b15542 100644 --- a/OpenRa.Game/Traits/Chronoshiftable.cs +++ b/OpenRa.Game/Traits/Chronoshiftable.cs @@ -6,7 +6,7 @@ using System.Drawing; namespace OpenRa.Game.Traits { - class Chronoshiftable : IOrder, ISpeedModifier, ITick + class Chronoshiftable : IOrder, ISpeedModifier, ITick, IChronoshiftable { // Return-to-sender logic int2 chronoshiftOrigin; diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index e66744cb4e..fdf5a05cbd 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -43,7 +43,7 @@ namespace OpenRa.Game.Traits bool IsCrushableBy(UnitMovementType umt, Player player); bool IsPathableCrush(UnitMovementType umt, Player player); } - + interface IChronoshiftable{} struct Renderable { public readonly Sprite Sprite; diff --git a/aftermathUnits.ini b/aftermathUnits.ini index f48554b9d7..d352dc379c 100755 --- a/aftermathUnits.ini +++ b/aftermathUnits.ini @@ -23,7 +23,7 @@ Voice=VehicleVoice [DTRK] Description=Demo Truck -Traits=Unit, Mobile, AttackBase, RenderUnit, Chronoshiftable +Traits=Unit, Mobile, AttackBase, RenderUnit, DemoTruck Voice=VehicleVoice [QTNK] From 3f97971deeea547e0ce6a121817fed8b3fac24b5 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 3 Jan 2010 23:56:48 +1300 Subject: [PATCH 19/56] Actually add the file --- OpenRa.Game/Traits/DemoTruck.cs | 59 +++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 OpenRa.Game/Traits/DemoTruck.cs diff --git a/OpenRa.Game/Traits/DemoTruck.cs b/OpenRa.Game/Traits/DemoTruck.cs new file mode 100644 index 0000000000..add4849cff --- /dev/null +++ b/OpenRa.Game/Traits/DemoTruck.cs @@ -0,0 +1,59 @@ +using OpenRa.Game.Effects; +using OpenRa.Game.Traits; +using System.Collections.Generic; +using System.Linq; +using OpenRa.Game.Orders; + +namespace OpenRa.Game.Traits +{ + class DemoTruck : IOrder, ISpeedModifier, INotifyDamage, IChronoshiftable + { + readonly Actor self; + public DemoTruck(Actor self) + { + this.self = self; + } + + // Fire primary on Chronoshift + public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) + { + return null; // Chronoshift order is issued through Chrome. + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "ChronosphereSelect") + Game.controller.orderGenerator = new ChronoshiftDestinationOrderGenerator(self); + + var movement = self.traits.WithInterface().FirstOrDefault(); + var chronosphere = Game.world.Actors.Where(a => a.Owner == order.Subject.Owner && a.traits.Contains()).FirstOrDefault(); + if (order.OrderString == "Chronoshift" && movement.CanEnterCell(order.TargetLocation)) + self.InflictDamage(chronosphere, self.Health, Rules.WarheadInfo["Super"]); + } + + // Fire primary on death + public void Damaged(Actor self, AttackInfo e) + { + if (e.DamageState == DamageState.Dead) + Detonate(self, e.Attacker); + } + + public void Detonate(Actor self, Actor detonatedBy) + { + self.InflictDamage(detonatedBy, self.Health, Rules.WarheadInfo["Super"]); + var unit = self.traits.GetOrDefault(); + var altitude = unit != null ? unit.Altitude : 0; + int2 detonateLocation = self.CenterLocation.ToInt2(); + + Game.world.AddFrameEndTask( + w => w.Add(new Bullet(self.Info.Primary, detonatedBy.Owner, detonatedBy, + detonateLocation, detonateLocation, altitude, altitude))); + } + + public float GetSpeedModifier() + { + // ARGH! You must not do this, it will desync! + return (Game.controller.orderGenerator is ChronoshiftDestinationOrderGenerator) ? 0f : 1f; + } + } +} From 4bb22a8de359fe179a5f8a0a394f5c26d77b7aa4 Mon Sep 17 00:00:00 2001 From: Alli Date: Mon, 4 Jan 2010 00:06:12 +1300 Subject: [PATCH 20/56] fixed powerbar scaling --- OpenRa.Game/Chrome.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index b22b900585..3381efdeed 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -232,7 +232,7 @@ namespace OpenRa.Game float2 bottom = powerOrigin + new float2(0, powerLevelTopSprite.size.Y + powerLevelBottomSprite.size.Y) - new float2(0, 50); var scale = 100; - while(Game.LocalPlayer.PowerProvided >= scale) scale += 100; + while(Math.Max(Game.LocalPlayer.PowerProvided, Game.LocalPlayer.PowerDrained) >= scale) scale *= 2; //draw bar float2 powerTop = new float2(bottom.X, bottom.Y + (top.Y - bottom.Y) * (Game.LocalPlayer.PowerProvided / (float)scale)); From 005e62e8c71f6141bbec17dd2b6f1fb5d9177a48 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 4 Jan 2010 00:09:01 +1300 Subject: [PATCH 21/56] in all its false-color glory... a working minimap for terrain --- OpenRa.Game/Chrome.cs | 2 +- OpenRa.Game/Graphics/Minimap.cs | 32 ++++++++++++++++++++++++++++---- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index b22b900585..a5835dfb67 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -144,7 +144,7 @@ namespace OpenRa.Game DrawBuildTabs(paletteHeight); DrawChat(); - Game.minimap.Draw(new float2(30,30)); + Game.minimap.Draw(new float2(Game.viewport.Width - 128,30)); } void AddButton(Rectangle r, Action b) { buttons.Add(Pair.New(r, b)); } diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index 0616404c20..79022d3c47 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -7,6 +7,7 @@ namespace OpenRa.Game.Graphics Sheet sheet; SpriteRenderer spriteRenderer; Sprite sprite; + Bitmap terrain; public void Tick() { } @@ -17,18 +18,41 @@ namespace OpenRa.Game.Graphics sprite = new Sprite(sheet, new Rectangle(0, 0, 128, 128), TextureChannel.Alpha); } + // todo: extract these from the palette + static readonly Color[] terrainTypeColors = { + Color.Green, + Color.Red, + Color.Blue, + Color.Yellow, + Color.Purple, + Color.Turquoise, + Color.Violet, + Color.Tomato, + Color.Teal, + }; + public void Update() { - var bitmap = new Bitmap(128, 128); + if (terrain == null) + { + terrain = new Bitmap(128, 128); + for (var y = 0; y < 128; y++) + for (var x = 0; x < 128; x++) + terrain.SetPixel(x, y, Rules.Map.IsInMap(x, y) + ? terrainTypeColors[Rules.TileSet.GetWalkability(Rules.Map.MapTiles[x, y])] + : Color.Black); + } + + var bitmap = new Bitmap(terrain); for( var y = 0; y < 128; y++ ) for (var x = 0; x < 128; x++) { - // todo: terrain, units, perf. + // todo: units, perf. var b = Game.BuildingInfluence.GetBuildingAt(new int2(x, y)); - if (b != null && b.Owner != null) - bitmap.SetPixel(x, y, Chat.paletteColors[ (int)b.Owner.Palette ]); + if (b != null) + bitmap.SetPixel(x, y, b.Owner != null ? Chat.paletteColors[(int)b.Owner.Palette] : Color.Gray); } sheet.Texture.SetData(bitmap); From 5f5a0a8e725bca8e7b81f736d7563376bab64e3c Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 4 Jan 2010 00:16:48 +1300 Subject: [PATCH 22/56] added units to minimap --- OpenRa.Game/Graphics/Minimap.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index 79022d3c47..a8dfcebf4c 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -1,4 +1,6 @@ using System.Drawing; +using System.Linq; +using OpenRa.Game.Traits; namespace OpenRa.Game.Graphics { @@ -48,13 +50,14 @@ namespace OpenRa.Game.Graphics for( var y = 0; y < 128; y++ ) for (var x = 0; x < 128; x++) { - // todo: units, perf. - var b = Game.BuildingInfluence.GetBuildingAt(new int2(x, y)); if (b != null) bitmap.SetPixel(x, y, b.Owner != null ? Chat.paletteColors[(int)b.Owner.Palette] : Color.Gray); } + foreach (var a in Game.world.Actors.Where(a => a.traits.Contains())) + bitmap.SetPixel(a.Location.X, a.Location.Y, Chat.paletteColors[(int)a.Owner.Palette]); + sheet.Texture.SetData(bitmap); } From 4410274e363360ffdc0934fb0e18f91893c688bd Mon Sep 17 00:00:00 2001 From: Alli Date: Mon, 4 Jan 2010 00:43:01 +1300 Subject: [PATCH 23/56] fixed powerbar colours,darkening, position. Moved lerping into Graphics.Util --- OpenRa.Game/Chrome.cs | 17 ++++++++++++++--- OpenRa.Game/Graphics/Util.cs | 15 +++++++++++++++ OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs | 16 +--------------- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 3381efdeed..9ec6bd0705 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -236,12 +236,23 @@ namespace OpenRa.Game //draw bar float2 powerTop = new float2(bottom.X, bottom.Y + (top.Y - bottom.Y) * (Game.LocalPlayer.PowerProvided / (float)scale)); - for(int i = 7; i < 11; i++) - lineRenderer.DrawLine(bottom + new float2(i, 0), powerTop + new float2(i, 0), Color.LimeGreen, Color.LimeGreen); + var color = Color.LimeGreen; + if (Game.LocalPlayer.GetPowerState() == PowerState.Low) + color = Color.Orange; + if (Game.LocalPlayer.GetPowerState() == PowerState.Critical) + color = Color.Red; + + var color2 = Graphics.Util.Lerp(0.25f, color, Color.Black); + + for(int i = 11; i < 13; i++) + lineRenderer.DrawLine(bottom + new float2(i, 0), powerTop + new float2(i, 0), color, color); + for (int i = 13; i < 15; i++) + lineRenderer.DrawLine(bottom + new float2(i, 0), powerTop + new float2(i, 0), color2, color2); + lineRenderer.Flush(); //draw indicator - float2 drainedPosition = new float2(bottom.X , bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale)); + float2 drainedPosition = new float2(bottom.X + 2 , bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale) + 2); buildPaletteRenderer.DrawSprite(powerIndicatorSprite, drainedPosition, PaletteType.Chrome); buildPaletteRenderer.Flush(); diff --git a/OpenRa.Game/Graphics/Util.cs b/OpenRa.Game/Graphics/Util.cs index d4d7ab60c7..97ad03da94 100644 --- a/OpenRa.Game/Graphics/Util.cs +++ b/OpenRa.Game/Graphics/Util.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Drawing.Imaging; using System.IO; +using System.Drawing; namespace OpenRa.Game.Graphics { @@ -111,5 +112,19 @@ namespace OpenRa.Game.Graphics bitmap.UnlockBits(bits); } } + + public static Color Lerp(float t, Color a, Color b) + { + return Color.FromArgb( + LerpChannel(t, a.A, b.A), + LerpChannel(t, a.R, b.R), + LerpChannel(t, a.G, b.G), + LerpChannel(t, a.B, b.B)); + } + + public static int LerpChannel(float t, int a, int b) + { + return (int)((1 - t) * a + t * b); + } } } diff --git a/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs index fb5dff901c..36a4f0e40c 100644 --- a/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs +++ b/OpenRa.Game/Traits/ChronoshiftPaletteEffect.cs @@ -33,22 +33,8 @@ namespace OpenRa.Game.Traits var orig = b.GetPixel(x, y); var lum = (int)(255 * orig.GetBrightness()); var desat = Color.FromArgb(orig.A, lum, lum, lum); - b.SetPixel(x, y, Lerp(frac, orig, desat)); + b.SetPixel(x, y, Graphics.Util.Lerp(frac, orig, desat)); } } - - static Color Lerp(float t, Color a, Color b) - { - return Color.FromArgb( - LerpChannel(t, a.A, b.A), - LerpChannel(t, a.R, b.R), - LerpChannel(t, a.G, b.G), - LerpChannel(t, a.B, b.B)); - } - - static int LerpChannel(float t, int a, int b) - { - return (int)((1 - t) * a + t * b); - } } } From eebb3026287bfb3d4f49d6b7644cad7903f47bfe Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 4 Jan 2010 00:50:31 +1300 Subject: [PATCH 24/56] vertical centering of power usage indicator at its value --- OpenRa.Game/Chrome.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 35bb4e61d1..cc0982604f 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -252,7 +252,7 @@ namespace OpenRa.Game lineRenderer.Flush(); //draw indicator - float2 drainedPosition = new float2(bottom.X + 2 , bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale) + 2); + float2 drainedPosition = new float2(bottom.X + 2 , bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale) + 2 - powerIndicatorSprite.size.Y /2); buildPaletteRenderer.DrawSprite(powerIndicatorSprite, drainedPosition, PaletteType.Chrome); buildPaletteRenderer.Flush(); From b2296a5014f2bc930c8fd924c19333af9a5eb51d Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 4 Jan 2010 01:00:57 +1300 Subject: [PATCH 25/56] power bar position blending --- OpenRa.Game/Chrome.cs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index cc0982604f..7c775fd7a2 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -219,6 +219,9 @@ namespace OpenRa.Game x -= 14; } } + + float? lastPowerProvidedPos; + float? lastPowerDrainedPos; void DrawPower() { @@ -234,7 +237,10 @@ namespace OpenRa.Game var scale = 100; while(Math.Max(Game.LocalPlayer.PowerProvided, Game.LocalPlayer.PowerDrained) >= scale) scale *= 2; //draw bar - float2 powerTop = new float2(bottom.X, bottom.Y + (top.Y - bottom.Y) * (Game.LocalPlayer.PowerProvided / (float)scale)); + + var powerTopY = bottom.Y + (top.Y - bottom.Y) * (Game.LocalPlayer.PowerProvided / (float)scale); + lastPowerProvidedPos = float2.Lerp(lastPowerProvidedPos.GetValueOrDefault(powerTopY), powerTopY, .3f); + float2 powerTop = new float2(bottom.X, lastPowerProvidedPos.Value); var color = Color.LimeGreen; if (Game.LocalPlayer.GetPowerState() == PowerState.Low) @@ -250,9 +256,11 @@ namespace OpenRa.Game lineRenderer.DrawLine(bottom + new float2(i, 0), powerTop + new float2(i, 0), color2, color2); lineRenderer.Flush(); - + + var drainedPositionY = bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale) - powerIndicatorSprite.size.Y /2; + lastPowerDrainedPos = float2.Lerp(lastPowerDrainedPos.GetValueOrDefault(drainedPositionY), drainedPositionY, .3f); //draw indicator - float2 drainedPosition = new float2(bottom.X + 2 , bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale) + 2 - powerIndicatorSprite.size.Y /2); + float2 drainedPosition = new float2(bottom.X + 2, lastPowerDrainedPos.Value); buildPaletteRenderer.DrawSprite(powerIndicatorSprite, drainedPosition, PaletteType.Chrome); buildPaletteRenderer.Flush(); From 512e56aec7554728d6301a8558e4bafff702eef3 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Mon, 4 Jan 2010 01:12:12 +1300 Subject: [PATCH 26/56] temporary hack to fix springy power bar; will vanish with some refactoring --- OpenRa.Game/Chrome.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 7c775fd7a2..10513861fb 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -238,9 +238,9 @@ namespace OpenRa.Game while(Math.Max(Game.LocalPlayer.PowerProvided, Game.LocalPlayer.PowerDrained) >= scale) scale *= 2; //draw bar - var powerTopY = bottom.Y + (top.Y - bottom.Y) * (Game.LocalPlayer.PowerProvided / (float)scale); + var powerTopY = bottom.Y + (top.Y - bottom.Y) * (Game.LocalPlayer.PowerProvided / (float)scale) - Game.viewport.Location.Y; lastPowerProvidedPos = float2.Lerp(lastPowerProvidedPos.GetValueOrDefault(powerTopY), powerTopY, .3f); - float2 powerTop = new float2(bottom.X, lastPowerProvidedPos.Value); + float2 powerTop = new float2(bottom.X, lastPowerProvidedPos.Value + Game.viewport.Location.Y); var color = Color.LimeGreen; if (Game.LocalPlayer.GetPowerState() == PowerState.Low) @@ -257,10 +257,10 @@ namespace OpenRa.Game lineRenderer.Flush(); - var drainedPositionY = bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale) - powerIndicatorSprite.size.Y /2; + var drainedPositionY = bottom.Y + (top.Y - bottom.Y)*(Game.LocalPlayer.PowerDrained/(float) scale) - powerIndicatorSprite.size.Y /2 - Game.viewport.Location.Y; lastPowerDrainedPos = float2.Lerp(lastPowerDrainedPos.GetValueOrDefault(drainedPositionY), drainedPositionY, .3f); //draw indicator - float2 drainedPosition = new float2(bottom.X + 2, lastPowerDrainedPos.Value); + float2 drainedPosition = new float2(bottom.X + 2, lastPowerDrainedPos.Value + Game.viewport.Location.Y); buildPaletteRenderer.DrawSprite(powerIndicatorSprite, drainedPosition, PaletteType.Chrome); buildPaletteRenderer.Flush(); From 3b0fd0e22cfa8e82bc04eb6c0a666876043bbf65 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 4 Jan 2010 13:42:53 +1300 Subject: [PATCH 27/56] Fix Damage spread --- OpenRa.Game/Combat.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/OpenRa.Game/Combat.cs b/OpenRa.Game/Combat.cs index ea855f1f38..b6cb373754 100644 --- a/OpenRa.Game/Combat.cs +++ b/OpenRa.Game/Combat.cs @@ -32,7 +32,7 @@ namespace OpenRa.Game var maxSpread = GetMaximumSpread(weapon, warhead); var hitActors = Game.FindUnitsInCircle(loc, maxSpread); - + foreach (var victim in hitActors) victim.InflictDamage(firedBy, (int)GetDamageToInflict(victim, loc, weapon, warhead), warhead); } @@ -46,11 +46,10 @@ namespace OpenRa.Game { if (!WeaponValidForTarget(weapon, target)) return 0f; - - var distance = (target.CenterLocation - loc).Length; + + 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); - return rawDamage * multiplier; } From 88c3e21ed091caed05b9aa289ce84b2305f93cab Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 4 Jan 2010 21:04:57 +1300 Subject: [PATCH 28/56] Selectively power-up/down buildings via chrome --- OpenRa.Game/Chrome.cs | 23 ++++++++- OpenRa.Game/Cursor.cs | 1 + OpenRa.Game/GameRules/UserSettings.cs | 1 + OpenRa.Game/Graphics/CursorSheetBuilder.cs | 12 ++++- OpenRa.Game/OpenRa.Game.csproj | 1 + OpenRa.Game/Orders/PowerDownOrderGenerator.cs | 47 +++++++++++++++++++ OpenRa.Game/Player.cs | 9 ++-- OpenRa.Game/Traits/AttackTurreted.cs | 7 +-- OpenRa.Game/Traits/Building.cs | 24 ++++++++++ sequences.xml | 3 ++ 10 files changed, 115 insertions(+), 13 deletions(-) create mode 100644 OpenRa.Game/Orders/PowerDownOrderGenerator.cs 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 @@ + + + From 5fdba51536599363595d70e6ae6ecb8e65885100 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 4 Jan 2010 21:12:35 +1300 Subject: [PATCH 29/56] Clarify method name --- OpenRa.Game/Traits/AttackTurreted.cs | 4 ++-- OpenRa.Game/Traits/Building.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenRa.Game/Traits/AttackTurreted.cs b/OpenRa.Game/Traits/AttackTurreted.cs index 5ccfbdaeb5..1d0007e223 100755 --- a/OpenRa.Game/Traits/AttackTurreted.cs +++ b/OpenRa.Game/Traits/AttackTurreted.cs @@ -26,8 +26,8 @@ namespace OpenRa.Game.Traits protected override void QueueAttack( Actor self, Order order ) { - var bi = self.traits.Get(); - if (bi != null && !bi.IsActive()) + var b = self.traits.Get(); + if (b != null && b.InsuffientPower()) return; const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */ diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs index ffdc657b17..e1c6215a88 100644 --- a/OpenRa.Game/Traits/Building.cs +++ b/OpenRa.Game/Traits/Building.cs @@ -23,9 +23,9 @@ namespace OpenRa.Game.Traits * ((float2)self.Location + .5f * (float2)unitInfo.Dimensions); } - public bool IsActive() + public bool InsuffientPower() { - return !(isPoweredDown || (unitInfo.Powered && self.Owner.GetPowerState() != PowerState.Normal)); + return (isPoweredDown || (unitInfo.Powered && self.Owner.GetPowerState() != PowerState.Normal)); } public int GetPowerUsage() From bfc797441911b3b9af7451dc6bed777301d331d4 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Mon, 4 Jan 2010 21:35:33 +1300 Subject: [PATCH 30/56] Tie Minimap to ProvidesRadar trait --- OpenRa.Game/Chrome.cs | 13 +++++++++---- OpenRa.Game/OpenRa.Game.csproj | 1 + OpenRa.Game/Traits/ProvidesRadar.cs | 28 ++++++++++++++++++++++++++++ units.ini | 2 +- 4 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 OpenRa.Game/Traits/ProvidesRadar.cs diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index b7010bbdbe..14a9484b76 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -143,16 +143,21 @@ namespace OpenRa.Game DrawPower(); chromeRenderer.Flush(); DrawButtons(); - + DrawMinimap(); int paletteHeight = DrawBuildPalette(currentTab); DrawBuildTabs(paletteHeight); DrawChat(); - - Game.minimap.Draw(new float2(Game.viewport.Width - 128,30)); } + void DrawMinimap() + { + var hasRadar = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains() && a.traits.Get().IsActive()); + if (hasRadar) + Game.minimap.Draw(new float2(Game.viewport.Width - 128, 30)); + } + void AddButton(Rectangle r, Action b) { buttons.Add(Pair.New(r, b)); } - + void DrawBuildTabs(int paletteHeight) { const int tabWidth = 24; diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 5aa72ea0c5..fef5cc01aa 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -214,6 +214,7 @@ + diff --git a/OpenRa.Game/Traits/ProvidesRadar.cs b/OpenRa.Game/Traits/ProvidesRadar.cs new file mode 100644 index 0000000000..41c3ced78c --- /dev/null +++ b/OpenRa.Game/Traits/ProvidesRadar.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + class ProvidesRadar + { + Actor self; + public ProvidesRadar(Actor self) + { + this.self = self; + } + + public bool IsActive() + { + // TODO: Check for nearby MRJ + + // Check if powered + var b = self.traits.Get(); + if (b != null && b.InsuffientPower()) + return false; + + return true; + } + } +} diff --git a/units.ini b/units.ini index 5b0d90121e..ad27a28435 100644 --- a/units.ini +++ b/units.ini @@ -407,7 +407,7 @@ SpawnOffset=0,-4 LongDesc=Produces and reloads helicopters [DOME] Description=Radar Dome -Traits=Building, RenderBuilding +Traits=Building, RenderBuilding, ProvidesRadar Dimensions=2,2 Footprint=xx xx SelectionPriority=3 From ac18d0ab449dedbaca943ae5d741e039c5de565d Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 5 Jan 2010 00:08:05 +1300 Subject: [PATCH 31/56] Temporarily hack in a powerdown effect until we do it properly --- OpenRa.Game/Traits/Building.cs | 29 ++++++++++++++++++++++++++++- sequences.xml | 3 +++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs index e1c6215a88..0b2da8e38d 100644 --- a/OpenRa.Game/Traits/Building.cs +++ b/OpenRa.Game/Traits/Building.cs @@ -5,10 +5,11 @@ using System.Collections.Generic; using System.Linq; using System.Text; using OpenRa.Game.Effects; +using OpenRa.Game.Graphics; namespace OpenRa.Game.Traits { - class Building : INotifyDamage, IOrder, ITick + class Building : INotifyDamage, IOrder, ITick, IRenderModifier { readonly Actor self; public readonly BuildingInfo unitInfo; @@ -39,6 +40,32 @@ namespace OpenRa.Game.Traits return unitInfo.Power; } + public Animation iconAnim; + public IEnumerable + ModifyRender(Actor self, IEnumerable rs) + { + if (!InsuffientPower()) + return rs; + + List nrs = new List(rs); + foreach(var r in rs) + { + // Need 2 shadows to make it dark enough + nrs.Add(r.WithPalette(PaletteType.Shadow)); + nrs.Add(r.WithPalette(PaletteType.Shadow)); + } + + if (isPoweredDown) + { + iconAnim = new Animation("powerdown"); + iconAnim.PlayRepeating("disabled"); + nrs.Add(new Renderable(iconAnim.Image, self.CenterLocation - 0.5f*iconAnim.Image.size, PaletteType.Chrome)); + } + + + return nrs; + } + public void Damaged(Actor self, AttackInfo e) { if (e.DamageState == DamageState.Dead) diff --git a/sequences.xml b/sequences.xml index 2abe5428ed..b27ced5362 100644 --- a/sequences.xml +++ b/sequences.xml @@ -404,6 +404,9 @@ + + + From b4f097c23c7bfa0e271f3661333232d6e633e7d2 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 5 Jan 2010 00:18:29 +1300 Subject: [PATCH 32/56] Audio feedback on powerdown/up --- OpenRa.Game/Traits/Building.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/OpenRa.Game/Traits/Building.cs b/OpenRa.Game/Traits/Building.cs index 0b2da8e38d..dfb870285c 100644 --- a/OpenRa.Game/Traits/Building.cs +++ b/OpenRa.Game/Traits/Building.cs @@ -93,6 +93,7 @@ namespace OpenRa.Game.Traits if (order.OrderString == "PowerDown") { isPoweredDown = !isPoweredDown; + Sound.Play((isPoweredDown) ? "bleep12.aud" : "bleep11.aud"); } } From 78de1e2b0416b0eb819501f6cb0b8b533989fb6b Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 12:21:51 +1300 Subject: [PATCH 33/56] fix unreferenced variable warning in SequenceProvider --- OpenRa.Game/Graphics/SequenceProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OpenRa.Game/Graphics/SequenceProvider.cs b/OpenRa.Game/Graphics/SequenceProvider.cs index 4915033531..756f523a8b 100644 --- a/OpenRa.Game/Graphics/SequenceProvider.cs +++ b/OpenRa.Game/Graphics/SequenceProvider.cs @@ -57,7 +57,7 @@ namespace OpenRa.Game.Graphics public static Sequence GetSequence(string unitName, string sequenceName) { try { return units[unitName][sequenceName]; } - catch (KeyNotFoundException e) + catch (KeyNotFoundException) { throw new InvalidOperationException( "Unit `{0}` does not have a sequence `{1}`".F(unitName, sequenceName)); From 52f99cb0554f92bc6b7b1d6b81d3ca2d465e9e7c Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 12:26:10 +1300 Subject: [PATCH 34/56] added 'self' to IPips.GetPips --- OpenRa.Game/Graphics/WorldRenderer.cs | 2 +- OpenRa.Game/Traits/ChronoshiftDeploy.cs | 2 +- OpenRa.Game/Traits/Harvester.cs | 2 +- OpenRa.Game/Traits/LimitedAmmo.cs | 2 +- OpenRa.Game/Traits/StoresOre.cs | 2 +- OpenRa.Game/Traits/TraitsInterfaces.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index 14bbff4afe..148cb979b4 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -211,7 +211,7 @@ namespace OpenRa.Game.Graphics foreach (var pips in selectedUnit.traits.WithInterface()) { - foreach (var pip in pips.GetPips()) + foreach (var pip in pips.GetPips(selectedUnit)) { var pipImages = new Animation("pips"); pipImages.PlayRepeating(pipStrings[(int)pip]); diff --git a/OpenRa.Game/Traits/ChronoshiftDeploy.cs b/OpenRa.Game/Traits/ChronoshiftDeploy.cs index cd02343320..7c4252fc97 100644 --- a/OpenRa.Game/Traits/ChronoshiftDeploy.cs +++ b/OpenRa.Game/Traits/ChronoshiftDeploy.cs @@ -55,7 +55,7 @@ namespace OpenRa.Game.Traits } // Display 5 pips indicating the current charge status - public IEnumerable GetPips() + public IEnumerable GetPips(Actor self) { const int numPips = 5; for (int i = 0; i < numPips; i++) diff --git a/OpenRa.Game/Traits/Harvester.cs b/OpenRa.Game/Traits/Harvester.cs index ef535cd876..f68f52f008 100644 --- a/OpenRa.Game/Traits/Harvester.cs +++ b/OpenRa.Game/Traits/Harvester.cs @@ -57,7 +57,7 @@ namespace OpenRa.Game.Traits } } - public IEnumerable GetPips() + public IEnumerable GetPips(Actor self) { const int numPips = 7; for (int i = 0; i < numPips; i++) diff --git a/OpenRa.Game/Traits/LimitedAmmo.cs b/OpenRa.Game/Traits/LimitedAmmo.cs index 2a1a938450..b5c18c55a2 100644 --- a/OpenRa.Game/Traits/LimitedAmmo.cs +++ b/OpenRa.Game/Traits/LimitedAmmo.cs @@ -23,7 +23,7 @@ namespace OpenRa.Game.Traits public void Attacking(Actor self) { --ammo; } - public IEnumerable GetPips() + public IEnumerable GetPips(Actor self) { return Graphics.Util.MakeArray(self.Info.Ammo, i => ammo > i ? PipType.Green : PipType.Transparent); diff --git a/OpenRa.Game/Traits/StoresOre.cs b/OpenRa.Game/Traits/StoresOre.cs index cd2d5210a8..25d16af2d0 100644 --- a/OpenRa.Game/Traits/StoresOre.cs +++ b/OpenRa.Game/Traits/StoresOre.cs @@ -11,7 +11,7 @@ namespace OpenRa.Game.Traits this.self = self; } - public IEnumerable GetPips() + public IEnumerable GetPips(Actor self) { for (int i = 0; i < self.Info.OrePips; i++) { diff --git a/OpenRa.Game/Traits/TraitsInterfaces.cs b/OpenRa.Game/Traits/TraitsInterfaces.cs index fdf5a05cbd..de5bc49c19 100644 --- a/OpenRa.Game/Traits/TraitsInterfaces.cs +++ b/OpenRa.Game/Traits/TraitsInterfaces.cs @@ -29,7 +29,7 @@ namespace OpenRa.Game.Traits interface IDamageModifier { float GetDamageModifier(); } interface ISpeedModifier { float GetSpeedModifier(); } interface IPaletteModifier { void AdjustPalette(Bitmap b); } - interface IPips { IEnumerable GetPips(); } + interface IPips { IEnumerable GetPips(Actor self); } interface ITags { IEnumerable GetTags(); } interface IMovement { From e74bcba69471fe03df06298a676b4905affd06f7 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 12:47:20 +1300 Subject: [PATCH 35/56] cargo: support for actors being removed from the world, but not dying --- OpenRa.Game/Actor.cs | 2 ++ OpenRa.Game/Orders/UnitOrderGenerator.cs | 2 +- OpenRa.Game/World.cs | 5 ++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 83b1ece4c6..e8a2e177ca 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -36,6 +36,7 @@ namespace OpenRa.Game Location = location; CenterLocation = Traits.Util.CenterOfCell(Location); Owner = owner; + IsInWorld = true; if (Info == null) return; @@ -123,6 +124,7 @@ namespace OpenRa.Game } public bool IsDead { get { return Health <= 0; } } + public bool IsInWorld { get; set; } public DamageState GetDamageState() { diff --git a/OpenRa.Game/Orders/UnitOrderGenerator.cs b/OpenRa.Game/Orders/UnitOrderGenerator.cs index ec64b5e9c6..9a35fca5d4 100644 --- a/OpenRa.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRa.Game/Orders/UnitOrderGenerator.cs @@ -27,7 +27,7 @@ namespace OpenRa.Game.Orders public void Tick() { - selection.RemoveAll(a => a.IsDead); + selection.RemoveAll(a => !a.IsInWorld); } public void Render() diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index dc55e86213..53dcfc9e37 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -11,7 +11,10 @@ namespace OpenRa.Game List> frameEndActions = new List>(); public void Add(Actor a) { actors.Add(a); ActorAdded(a); } - public void Remove(Actor a) { actors.Remove(a); ActorRemoved(a); } + public void Remove(Actor a) + { + a.IsInWorld = false; actors.Remove(a); ActorRemoved(a); + } public void Add(IEffect b) { effects.Add(b); } public void Remove(IEffect b) { effects.Remove(b); } From 323d4bd6716266b8da6bfb699ce602124ba4bb91 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 12:50:12 +1300 Subject: [PATCH 36/56] cargo: added cargo-related sequences for APC/LST/TRAN; moved Passengers onto UnitInfo for convenience (and to allow garrisoning without a big hack); added Cargo trait to all known transports --- OpenRa.Game/GameRules/UnitInfo.cs | 3 +- OpenRa.Game/OpenRa.Game.csproj | 2 + OpenRa.Game/Traits/Activities/UnloadCargo.cs | 34 +++++++++++ OpenRa.Game/Traits/Cargo.cs | 61 ++++++++++++++++++++ sequences.xml | 14 +++-- units.ini | 6 +- 6 files changed, 112 insertions(+), 8 deletions(-) create mode 100644 OpenRa.Game/Traits/Activities/UnloadCargo.cs create mode 100644 OpenRa.Game/Traits/Cargo.cs diff --git a/OpenRa.Game/GameRules/UnitInfo.cs b/OpenRa.Game/GameRules/UnitInfo.cs index 8401ae04ef..a1dc335a46 100755 --- a/OpenRa.Game/GameRules/UnitInfo.cs +++ b/OpenRa.Game/GameRules/UnitInfo.cs @@ -55,13 +55,14 @@ namespace OpenRa.Game.GameRules public readonly int OrePips = 0; public readonly string Icon = null; public readonly int[] SelectionSize = null; + public readonly int Passengers = 0; + public readonly int UnloadFacing = 0; public UnitInfo(string name) { Name = name; } } public class MobileInfo : UnitInfo { - public readonly int Passengers = 0; public readonly int Speed = 0; public readonly bool NoMovingFire = false; public readonly string Voice = "GenericVoice"; diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 72f4caec37..ef9bea264e 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -185,6 +185,7 @@ + @@ -198,6 +199,7 @@ + diff --git a/OpenRa.Game/Traits/Activities/UnloadCargo.cs b/OpenRa.Game/Traits/Activities/UnloadCargo.cs new file mode 100644 index 0000000000..3a620f8ab4 --- /dev/null +++ b/OpenRa.Game/Traits/Activities/UnloadCargo.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits.Activities +{ + class UnloadCargo : IActivity + { + public IActivity NextActivity { get; set; } + bool isCanceled; + + public IActivity Tick(Actor self) + { + if (isCanceled) return NextActivity; + + // if we're a thing that can turn, turn to the + // right facing for the unload animation + var unit = self.traits.GetOrDefault(); + if (unit != null && unit.Facing != self.Info.UnloadFacing) + return Util.SequenceActivities(new Turn(self.Info.UnloadFacing), this); + + // todo: play the `open` anim (or the `close` anim backwards) + // todo: unload all the cargo + // todo: play the `close` anim (or the `open` anim backwards) + + // as for open/close... the westwood guys suck at being consistent. + + return this; + } + + public void Cancel(Actor self) { NextActivity = null; isCanceled = true; } + } +} diff --git a/OpenRa.Game/Traits/Cargo.cs b/OpenRa.Game/Traits/Cargo.cs new file mode 100644 index 0000000000..a1202b5440 --- /dev/null +++ b/OpenRa.Game/Traits/Cargo.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.GameRules; + +namespace OpenRa.Game.Traits +{ + class Cargo : IPips, IOrder + { + List cargo = new List(); + + public Cargo(Actor self) { } + + public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) + { + // todo: check if there is an unoccupied `land` tile adjacent + if (mi.Button == MouseButton.Right && underCursor == self && cargo.Count > 0) + return new Order("Deploy", self, null, int2.Zero, null); + + return null; + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "Deploy") + { + // todo: eject the units + self.CancelActivity(); + } + } + + public bool IsFull(Actor self) + { + return cargo.Count == self.Info.Passengers; + } + + public IEnumerable GetPips( Actor self ) + { + for (var i = 0; i < self.Info.Passengers; i++) + if (i >= cargo.Count) + yield return PipType.Transparent; + else + yield return GetPipForPassenger(cargo[i]); + } + + static PipType GetPipForPassenger(Actor a) + { + // probably not actually right yet; fix to match real-ra + + if (a.traits.Contains()) + return PipType.Yellow; + if (!a.traits.WithInterface().Any()) + return PipType.Yellow; // noncombat [E6,SPY,THF] + if (a.traits.Contains()) + return PipType.Red; // E7 + + return PipType.Green; + } + } +} diff --git a/sequences.xml b/sequences.xml index f659cf186a..a56029f90d 100644 --- a/sequences.xml +++ b/sequences.xml @@ -283,6 +283,8 @@ + + @@ -376,7 +378,7 @@ - + @@ -536,6 +538,8 @@ + + @@ -572,6 +576,8 @@ + + @@ -1008,8 +1014,8 @@ - - - + + + \ No newline at end of file diff --git a/units.ini b/units.ini index 5b0d90121e..76c9ac4a54 100644 --- a/units.ini +++ b/units.ini @@ -56,7 +56,7 @@ Voice=VehicleVoice LongDesc=Fast scout & anti-infantry vehicle.\n Strong vs Infantry\n Weak vs Tanks, Aircraft [APC] Description=Armored Personnel Carrier -Traits=Unit, Mobile, AttackBase, RenderUnitMuzzleFlash, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, AttackBase, RenderUnitMuzzleFlash, AutoTarget, Repairable, Chronoshiftable, Cargo PrimaryOffset=0,0,0,-4 MuzzleFlash=yes Voice=VehicleVoice @@ -138,7 +138,7 @@ Recoil=3 [LST] Description=Transport WaterBound=yes -Traits=Unit, Mobile, RenderUnit +Traits=Unit, Mobile, RenderUnit, Cargo LongDesc=General-purpose naval transport.\nCan carry infantry and tanks.\n Unarmed [PT] Description=Gunboat @@ -179,7 +179,7 @@ Description=Transport Helicopter RotorOffset=0,14,0,-4 RotorOffset2=0,-14,0,-2 BuiltAt=hpad -Traits=Unit, Helicopter, RenderUnitRotor, WithShadow +Traits=Unit, Helicopter, RenderUnitRotor, WithShadow, Cargo InitialFacing=20 LongDesc=Fast Infantry Transport Helicopter.\n Unarmed [HELI] From 0b1ea48c09ff71de9a607c0c6edc8a35730099f5 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 13:40:06 +1300 Subject: [PATCH 37/56] cargo: unloading works --- OpenRa.Game/Traits/Activities/Turn.cs | 2 +- OpenRa.Game/Traits/Activities/UnloadCargo.cs | 43 +++++++++++++++++--- OpenRa.Game/Traits/Cargo.cs | 24 ++++++++++- session.ini | 2 +- units.ini | 1 + 5 files changed, 64 insertions(+), 8 deletions(-) diff --git a/OpenRa.Game/Traits/Activities/Turn.cs b/OpenRa.Game/Traits/Activities/Turn.cs index f07033d93e..1b81859e31 100755 --- a/OpenRa.Game/Traits/Activities/Turn.cs +++ b/OpenRa.Game/Traits/Activities/Turn.cs @@ -5,7 +5,7 @@ namespace OpenRa.Game.Traits.Activities { public IActivity NextActivity { get; set; } - public int desiredFacing; + int desiredFacing; public Turn( int desiredFacing ) { diff --git a/OpenRa.Game/Traits/Activities/UnloadCargo.cs b/OpenRa.Game/Traits/Activities/UnloadCargo.cs index 3a620f8ab4..705e97b473 100644 --- a/OpenRa.Game/Traits/Activities/UnloadCargo.cs +++ b/OpenRa.Game/Traits/Activities/UnloadCargo.cs @@ -10,6 +10,21 @@ namespace OpenRa.Game.Traits.Activities public IActivity NextActivity { get; set; } bool isCanceled; + int2? ChooseExitTile(Actor self) + { + if (!Game.IsCellBuildable(self.Location, UnitMovementType.Foot, self)) + return null; + + for (var i = -1; i < 2; i++) + for (var j = -1; j < 2; j++) + if ((i != 0 || j != 0) && + Game.IsCellBuildable(self.Location + new int2(i, j), + UnitMovementType.Foot)) + return self.Location + new int2(i, j); + + return null; + } + public IActivity Tick(Actor self) { if (isCanceled) return NextActivity; @@ -18,13 +33,31 @@ namespace OpenRa.Game.Traits.Activities // right facing for the unload animation var unit = self.traits.GetOrDefault(); if (unit != null && unit.Facing != self.Info.UnloadFacing) - return Util.SequenceActivities(new Turn(self.Info.UnloadFacing), this); + return new Turn(self.Info.UnloadFacing) { NextActivity = this }; - // todo: play the `open` anim (or the `close` anim backwards) - // todo: unload all the cargo - // todo: play the `close` anim (or the `open` anim backwards) + // todo: handle the BS of open/close sequences, which are inconsistent, + // for reasons that probably make good sense to the westwood guys. - // as for open/close... the westwood guys suck at being consistent. + var cargo = self.traits.Get(); + if (cargo.IsEmpty(self)) + return NextActivity; + + var ru = self.traits.WithInterface().FirstOrDefault(); + if (ru != null) + ru.PlayCustomAnimation(self, "unload", null); + + var exitTile = ChooseExitTile(self); + if (exitTile == null) + return this; + + var actor = cargo.UnloadOne(self); + Game.world.AddFrameEndTask(w => + { + w.Add(actor); + actor.traits.Get().TeleportTo(actor, self.Location); + actor.CancelActivity(); + actor.QueueActivity(new Move(exitTile.Value, 0)); + }); return this; } diff --git a/OpenRa.Game/Traits/Cargo.cs b/OpenRa.Game/Traits/Cargo.cs index a1202b5440..2f2bff52a8 100644 --- a/OpenRa.Game/Traits/Cargo.cs +++ b/OpenRa.Game/Traits/Cargo.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using OpenRa.Game.GameRules; +using OpenRa.Game.Traits.Activities; namespace OpenRa.Game.Traits { @@ -10,7 +11,15 @@ namespace OpenRa.Game.Traits { List cargo = new List(); - public Cargo(Actor self) { } + public Cargo(Actor self) + { + // hack: + cargo.Add(new Actor(Rules.UnitInfo["E1"], int2.Zero, self.Owner)); + cargo.Add(new Actor(Rules.UnitInfo["E1"], int2.Zero, self.Owner)); + cargo.Add(new Actor(Rules.UnitInfo["E1"], int2.Zero, self.Owner)); + cargo.Add(new Actor(Rules.UnitInfo["E6"], int2.Zero, self.Owner)); + cargo.Add(new Actor(Rules.UnitInfo["E7"], int2.Zero, self.Owner)); + } public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { @@ -27,6 +36,7 @@ namespace OpenRa.Game.Traits { // todo: eject the units self.CancelActivity(); + self.QueueActivity(new UnloadCargo()); } } @@ -35,6 +45,18 @@ namespace OpenRa.Game.Traits return cargo.Count == self.Info.Passengers; } + public bool IsEmpty(Actor self) + { + return cargo.Count == 0; + } + + public Actor UnloadOne(Actor self) + { + var a = cargo[0]; + cargo.RemoveAt(0); + return a; + } + public IEnumerable GetPips( Actor self ) { for (var i = 0; i < self.Info.Passengers; i++) diff --git a/session.ini b/session.ini index acafbf8481..d63ac62a10 100644 --- a/session.ini +++ b/session.ini @@ -10,4 +10,4 @@ s2=Multi1,mcv,600,12505,0,Guard,None ;s2=Multi1,e3,600,12505,0,Guard,None s3=Multi3,mcv,600,2910,0,Guard,None ;s4=Multi1,ctnk,600,12506,Gaurd,None -s5=Multi1,pdox,600,12510,Gaurd,None \ No newline at end of file +s5=Multi1,apc,600,12510,Gaurd,None \ No newline at end of file diff --git a/units.ini b/units.ini index 76c9ac4a54..b85b9faf0e 100644 --- a/units.ini +++ b/units.ini @@ -61,6 +61,7 @@ PrimaryOffset=0,0,0,-4 MuzzleFlash=yes Voice=VehicleVoice LongDesc=Tough infantry transport.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft +UnloadFacing=220 ;; non-combat vehicles [MRJ] From f2231997dc7d86380a2edd4622f684ab293790c3 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 13:45:51 +1300 Subject: [PATCH 38/56] cargo: support LST --- OpenRa.Game/Traits/Activities/UnloadCargo.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenRa.Game/Traits/Activities/UnloadCargo.cs b/OpenRa.Game/Traits/Activities/UnloadCargo.cs index 705e97b473..2f23dc7886 100644 --- a/OpenRa.Game/Traits/Activities/UnloadCargo.cs +++ b/OpenRa.Game/Traits/Activities/UnloadCargo.cs @@ -12,7 +12,8 @@ namespace OpenRa.Game.Traits.Activities int2? ChooseExitTile(Actor self) { - if (!Game.IsCellBuildable(self.Location, UnitMovementType.Foot, self)) + // is anyone still hogging this tile? + if (Game.UnitInfluence.GetUnitsAt(self.Location).Count() > 1) return null; for (var i = -1; i < 2; i++) From dc7c6d5cd66fc039c393a9abcb8f30d3bbdbde3e Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 13:51:51 +1300 Subject: [PATCH 39/56] minimap: add support for sprite scaling to SpriteRenderer/Graphics.Util --- OpenRa.Game/Graphics/SpriteRenderer.cs | 7 ++++++- OpenRa.Game/Graphics/TerrainRenderer.cs | 2 +- OpenRa.Game/Graphics/Util.cs | 10 +++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/OpenRa.Game/Graphics/SpriteRenderer.cs b/OpenRa.Game/Graphics/SpriteRenderer.cs index 87e28c693f..3074c43a0f 100644 --- a/OpenRa.Game/Graphics/SpriteRenderer.cs +++ b/OpenRa.Game/Graphics/SpriteRenderer.cs @@ -55,12 +55,17 @@ namespace OpenRa.Game.Graphics } public void DrawSprite(Sprite s, float2 location, PaletteType palette) + { + DrawSprite(s, location, palette, s.size); + } + + public void DrawSprite(Sprite s, float2 location, PaletteType palette, float2 size) { if (s.sheet != currentSheet) Flush(); currentSheet = s.sheet; - Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, (int) palette, nv, ni); + Util.FastCreateQuad(vertices, indices, location.ToInt2(), s, (int)palette, nv, ni, size); nv += 4; ni += 6; if (++sprites >= spritesPerBatch) Flush(); diff --git a/OpenRa.Game/Graphics/TerrainRenderer.cs b/OpenRa.Game/Graphics/TerrainRenderer.cs index 07d4263984..1032c3b0a0 100644 --- a/OpenRa.Game/Graphics/TerrainRenderer.cs +++ b/OpenRa.Game/Graphics/TerrainRenderer.cs @@ -34,7 +34,7 @@ namespace OpenRa.Game.Graphics for( int i = map.XOffset ; i < map.XOffset + map.Width; i++ ) { Sprite tile = tileMapping[map.MapTiles[i, j]]; - Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, 0, nv, ni); + Util.FastCreateQuad(vertices, indices, Game.CellSize * new float2(i, j), tile, 0, nv, ni, tile.size); nv += 4; ni += 6; } diff --git a/OpenRa.Game/Graphics/Util.cs b/OpenRa.Game/Graphics/Util.cs index 97ad03da94..85dada816d 100644 --- a/OpenRa.Game/Graphics/Util.cs +++ b/OpenRa.Game/Graphics/Util.cs @@ -57,14 +57,14 @@ namespace OpenRa.Game.Graphics static float[] channelSelect = { 0.75f, 0.25f, -0.25f, -0.75f }; - public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni) + public static void FastCreateQuad(Vertex[] vertices, ushort[] indices, float2 o, Sprite r, int palette, int nv, int ni, float2 size) { float2 attrib = new float2(palette / 16.0f, channelSelect[(int)r.channel]); - vertices[nv] = new Vertex(KLerp(o, r.size, 0), r.FastMapTextureCoords(0), attrib); - vertices[nv + 1] = new Vertex(KLerp(o, r.size, 1), r.FastMapTextureCoords(1), attrib); - vertices[nv + 2] = new Vertex(KLerp(o, r.size, 2), r.FastMapTextureCoords(2), attrib); - vertices[nv + 3] = new Vertex(KLerp(o, r.size, 3), r.FastMapTextureCoords(3), attrib); + vertices[nv] = new Vertex(KLerp(o, size, 0), r.FastMapTextureCoords(0), attrib); + vertices[nv + 1] = new Vertex(KLerp(o, size, 1), r.FastMapTextureCoords(1), attrib); + vertices[nv + 2] = new Vertex(KLerp(o, size, 2), r.FastMapTextureCoords(2), attrib); + vertices[nv + 3] = new Vertex(KLerp(o, size, 3), r.FastMapTextureCoords(3), attrib); indices[ni] = (ushort)(nv); indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1); From 46d5f642a0407436621238c457fc0e1e2f5a5c6f Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 13:56:50 +1300 Subject: [PATCH 40/56] minimap: double size --- OpenRa.Game/Chrome.cs | 4 ++-- OpenRa.Game/Graphics/Minimap.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index 10513861fb..5ebd186d6e 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -132,6 +132,8 @@ namespace OpenRa.Game PerfHistory.Render(renderer, Game.worldRenderer.lineRenderer); + Game.minimap.Draw(new float2(Game.viewport.Width - 256, 8)); + chromeRenderer.DrawSprite(specialBinSprite, float2.Zero, PaletteType.Chrome); chromeRenderer.DrawSprite(moneyBinSprite, new float2(Game.viewport.Width - 320, 0), PaletteType.Chrome); @@ -143,8 +145,6 @@ namespace OpenRa.Game int paletteHeight = DrawBuildPalette(currentTab); DrawBuildTabs(paletteHeight); DrawChat(); - - Game.minimap.Draw(new float2(Game.viewport.Width - 128,30)); } void AddButton(Rectangle r, Action b) { buttons.Add(Pair.New(r, b)); } diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index a8dfcebf4c..63b7c41af7 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -63,7 +63,7 @@ namespace OpenRa.Game.Graphics public void Draw(float2 pos) { - spriteRenderer.DrawSprite(sprite, pos, PaletteType.Chrome); + spriteRenderer.DrawSprite(sprite, pos, PaletteType.Chrome, new float2(256,256)); spriteRenderer.Flush(); } } From a8e49556ca41d0af6512be310a9797b2fe10c254 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 14:32:18 +1300 Subject: [PATCH 41/56] fixed false-color minimap --- OpenRa.Game/Graphics/Minimap.cs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index 63b7c41af7..21031eb6e5 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -1,6 +1,7 @@ using System.Drawing; using System.Linq; using OpenRa.Game.Traits; +using OpenRa.FileFormats; namespace OpenRa.Game.Graphics { @@ -21,20 +22,25 @@ namespace OpenRa.Game.Graphics } // todo: extract these from the palette - static readonly Color[] terrainTypeColors = { - Color.Green, - Color.Red, - Color.Blue, - Color.Yellow, - Color.Purple, - Color.Turquoise, - Color.Violet, - Color.Tomato, - Color.Teal, - }; + Color[] terrainTypeColors; public void Update() { + if (terrainTypeColors == null) + { + var pal = new Palette(FileSystem.Open(Rules.Map.Theater + ".pal")); + terrainTypeColors = new[] { + pal.GetColor(0x1a), + pal.GetColor(0x63), + pal.GetColor(0x2f), + pal.GetColor(0x1f), + pal.GetColor(0x14), + pal.GetColor(0x64), + pal.GetColor(0x1f), + pal.GetColor(0x68), + pal.GetColor(0x6b), + }; + } if (terrain == null) { terrain = new Bitmap(128, 128); @@ -52,7 +58,7 @@ namespace OpenRa.Game.Graphics { var b = Game.BuildingInfluence.GetBuildingAt(new int2(x, y)); if (b != null) - bitmap.SetPixel(x, y, b.Owner != null ? Chat.paletteColors[(int)b.Owner.Palette] : Color.Gray); + bitmap.SetPixel(x, y, b.Owner != null ? Chat.paletteColors[(int)b.Owner.Palette] : terrainTypeColors[4]); } foreach (var a in Game.world.Actors.Where(a => a.traits.Contains())) From e68547f9d0ecdab0de4f990a283f0389735b2c43 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 14:49:48 +1300 Subject: [PATCH 42/56] minimap: show ore/gems on minimap --- OpenRa.Game/Game.cs | 9 +++++---- OpenRa.Game/Graphics/Minimap.cs | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index cb2e3fed1b..22631abbf8 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -100,7 +100,7 @@ namespace OpenRa.Game chrome = new Chrome(renderer); - oreFrequency = (int)(Rules.General.GrowthRate * 60 * 1000); + oreFrequency = (int)(Rules.General.GrowthRate * 60 * 25); oreTicks = oreFrequency; } @@ -182,11 +182,12 @@ namespace OpenRa.Game controller.orderGenerator.Tick(); if (--oreTicks == 0) - { using (new PerfSample("ore")) + { Rules.Map.GrowOre(SharedRandom); - oreTicks = oreFrequency; - } + minimap.InvalidateOre(); + oreTicks = oreFrequency; + } world.Tick(); UnitInfluence.Tick(); diff --git a/OpenRa.Game/Graphics/Minimap.cs b/OpenRa.Game/Graphics/Minimap.cs index 21031eb6e5..fbb13f3ef9 100644 --- a/OpenRa.Game/Graphics/Minimap.cs +++ b/OpenRa.Game/Graphics/Minimap.cs @@ -10,7 +10,7 @@ namespace OpenRa.Game.Graphics Sheet sheet; SpriteRenderer spriteRenderer; Sprite sprite; - Bitmap terrain; + Bitmap terrain, oreLayer; public void Tick() { } @@ -24,6 +24,8 @@ namespace OpenRa.Game.Graphics // todo: extract these from the palette Color[] terrainTypeColors; + public void InvalidateOre() { oreLayer = null; } + public void Update() { if (terrainTypeColors == null) @@ -39,8 +41,10 @@ namespace OpenRa.Game.Graphics pal.GetColor(0x1f), pal.GetColor(0x68), pal.GetColor(0x6b), + pal.GetColor(0x6d), }; } + if (terrain == null) { terrain = new Bitmap(128, 128); @@ -51,7 +55,16 @@ namespace OpenRa.Game.Graphics : Color.Black); } - var bitmap = new Bitmap(terrain); + if (oreLayer == null) + { + oreLayer = new Bitmap(terrain); + for (var y = 0; y < 128; y++) + for (var x = 0; x < 128; x++) + if (Rules.Map.ContainsResource(new int2(x, y))) + oreLayer.SetPixel(x, y, terrainTypeColors[(int)TerrainMovementType.Ore]); + } + + var bitmap = new Bitmap(oreLayer); for( var y = 0; y < 128; y++ ) for (var x = 0; x < 128; x++) From 37a043bf961c1433fe23024e56e8efd977cda541 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 14:59:21 +1300 Subject: [PATCH 43/56] added PassengerTypes to rules --- OpenRa.Game/GameRules/UnitInfo.cs | 1 + OpenRa.Game/TerrainCosts.cs | 2 +- units.ini | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenRa.Game/GameRules/UnitInfo.cs b/OpenRa.Game/GameRules/UnitInfo.cs index a1dc335a46..63acbe1870 100755 --- a/OpenRa.Game/GameRules/UnitInfo.cs +++ b/OpenRa.Game/GameRules/UnitInfo.cs @@ -57,6 +57,7 @@ namespace OpenRa.Game.GameRules public readonly int[] SelectionSize = null; public readonly int Passengers = 0; public readonly int UnloadFacing = 0; + public readonly UnitMovementType[] PassengerTypes = null; public UnitInfo(string name) { Name = name; } } diff --git a/OpenRa.Game/TerrainCosts.cs b/OpenRa.Game/TerrainCosts.cs index 78f17a96ac..7c4ffc9dfb 100644 --- a/OpenRa.Game/TerrainCosts.cs +++ b/OpenRa.Game/TerrainCosts.cs @@ -2,7 +2,7 @@ using OpenRa.Game.Graphics; namespace OpenRa.Game { - enum UnitMovementType : byte + public enum UnitMovementType : byte { Foot = 0, Track = 1, diff --git a/units.ini b/units.ini index b85b9faf0e..ca2d4e49c9 100644 --- a/units.ini +++ b/units.ini @@ -62,6 +62,7 @@ MuzzleFlash=yes Voice=VehicleVoice LongDesc=Tough infantry transport.\n Strong vs Infantry, Light Vehicles\n Weak vs Tanks, Aircraft UnloadFacing=220 +PassengerTypes=Foot ;; non-combat vehicles [MRJ] @@ -141,6 +142,7 @@ Description=Transport WaterBound=yes Traits=Unit, Mobile, RenderUnit, Cargo LongDesc=General-purpose naval transport.\nCan carry infantry and tanks.\n Unarmed +PassengerTypes=Foot,Wheel,Track [PT] Description=Gunboat WaterBound=yes @@ -183,6 +185,7 @@ BuiltAt=hpad Traits=Unit, Helicopter, RenderUnitRotor, WithShadow, Cargo InitialFacing=20 LongDesc=Fast Infantry Transport Helicopter.\n Unarmed +PassengerTypes=Foot [HELI] Description=Longbow BuiltAt=hpad From 026a33d2e26249879cf740217b00e7775ba54ee7 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 15:10:17 +1300 Subject: [PATCH 44/56] cargo: Passenger trait for things that can enter transports --- OpenRa.Game/OpenRa.Game.csproj | 1 + OpenRa.Game/Orders/UnitOrderGenerator.cs | 1 + OpenRa.Game/Traits/Passenger.cs | 42 +++++++++++++++++++++ units.ini | 48 ++++++++++++------------ 4 files changed, 68 insertions(+), 24 deletions(-) create mode 100644 OpenRa.Game/Traits/Passenger.cs diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index ef9bea264e..752d599047 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -215,6 +215,7 @@ + diff --git a/OpenRa.Game/Orders/UnitOrderGenerator.cs b/OpenRa.Game/Orders/UnitOrderGenerator.cs index 9a35fca5d4..dc4019ceea 100644 --- a/OpenRa.Game/Orders/UnitOrderGenerator.cs +++ b/OpenRa.Game/Orders/UnitOrderGenerator.cs @@ -81,6 +81,7 @@ namespace OpenRa.Game.Orders else return Cursor.MoveBlocked; case "Enter": return Cursor.Enter; + case "EnterTransport": return Cursor.Enter; case "Deliver": return Cursor.Enter; case "Infiltrate": return Cursor.Enter; case "Capture": return Cursor.Capture; diff --git a/OpenRa.Game/Traits/Passenger.cs b/OpenRa.Game/Traits/Passenger.cs new file mode 100644 index 0000000000..a4092d63d9 --- /dev/null +++ b/OpenRa.Game/Traits/Passenger.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using OpenRa.Game.Traits.Activities; + +namespace OpenRa.Game.Traits +{ + class Passenger : IOrder + { + public Passenger(Actor self) { } + + public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) + { + if (mi.Button != MouseButton.Right) + return null; + + if (underCursor == null || underCursor.Owner != self.Owner) + return null; + + var cargo = underCursor.traits.GetOrDefault(); + if (cargo == null || cargo.IsFull(underCursor)) + return null; + + var umt = self.traits.WithInterface().First().GetMovementType(); + if (!underCursor.Info.PassengerTypes.Contains(umt)) + return null; + + return new Order("EnterTransport", self, underCursor, int2.Zero, null); + } + + public void ResolveOrder(Actor self, Order order) + { + if (order.OrderString == "EnterTransport") + { + self.CancelActivity(); + self.QueueActivity(new Move(order.TargetActor, 0)); + // todo: actually enter the transport + } + } + } +} diff --git a/units.ini b/units.ini index ca2d4e49c9..f8a62c64b1 100644 --- a/units.ini +++ b/units.ini @@ -16,47 +16,47 @@ MNLY.AT [V2RL] Description=V2 Rocket -Traits=Unit, Mobile, AttackBase, RenderUnitReload, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, AttackBase, RenderUnitReload, AutoTarget, Repairable, Chronoshiftable, Passenger Voice=VehicleVoice LongDesc=Long-range rocket artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft [1TNK] Description=Light Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable, Passenger Recoil=2 Voice=VehicleVoice LongDesc=Light Tank, good for scouting.\n Strong vs Light Vehicles\n Weak vs Tanks, Aircraft [2TNK] Description=Medium Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable, Passenger Recoil=3 Voice=VehicleVoice LongDesc=Allied Main Battle Tank.\n Strong vs Tanks, Light Vehicles\n Weak vs Infantry, Aircraft [3TNK] Description=Heavy Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable, Passenger Recoil=3 Voice=VehicleVoice LongDesc=Soviet Main Battle Tank, with dual cannons\n Strong vs Tanks, Light Vehicles\n Weak vs Infantry, Aircraft [4TNK] Description=Mammoth Tank -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable, Passenger Voice=VehicleVoice LongDesc=Big and slow tank, with anti-air capability.\n Strong vs Tanks, Aircraft\n Weak vs Infantry [ARTY] Description=Artillery -Traits=Unit, Mobile, AttackBase, RenderUnit, Explodes, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, AttackBase, RenderUnit, Explodes, AutoTarget, Repairable, Chronoshiftable, Passenger Voice=VehicleVoice LongDesc=Long-range artillery.\n Strong vs Infantry, Buildings\n Weak vs Tanks, Aircraft [JEEP] Description=Ranger -Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable +Traits=Unit, Mobile, Turreted, AttackTurreted, RenderUnitTurreted, AutoTarget, Repairable, Chronoshiftable, Passenger PrimaryOffset=0,0,0,-2 MuzzleFlash=yes Voice=VehicleVoice LongDesc=Fast scout & anti-infantry vehicle.\n Strong vs Infantry\n Weak vs Tanks, Aircraft [APC] Description=Armored Personnel Carrier -Traits=Unit, Mobile, AttackBase, RenderUnitMuzzleFlash, AutoTarget, Repairable, Chronoshiftable, Cargo +Traits=Unit, Mobile, AttackBase, RenderUnitMuzzleFlash, AutoTarget, Repairable, Chronoshiftable, Cargo, Passenger PrimaryOffset=0,0,0,-4 MuzzleFlash=yes Voice=VehicleVoice @@ -67,40 +67,40 @@ PassengerTypes=Foot ;; non-combat vehicles [MRJ] Description=Radar Jammer -Traits=Unit, Mobile, RenderUnitSpinner, Repairable, Chronoshiftable +Traits=Unit, Mobile, RenderUnitSpinner, Repairable, Chronoshiftable, Passenger PrimaryOffset=0,4,0,-6 SelectionPriority=3 Voice=VehicleVoice LongDesc=Hides nearby units on the enemy's minimap.\n Unarmed [MGG] Description=Mobile Gap Generator -Traits=Unit, Mobile, RenderUnitSpinner, Repairable, Chronoshiftable +Traits=Unit, Mobile, RenderUnitSpinner, Repairable, Chronoshiftable, Passenger PrimaryOffset=0,6,0,-3 SelectionPriority=3 Voice=VehicleVoice LongDesc=Regenerates Fog of War in a small area \naround the unit.\n Unarmed [HARV] Description=Ore Truck -Traits=Harvester, Unit, Mobile, RenderUnit, Repairable, Chronoshiftable +Traits=Harvester, Unit, Mobile, RenderUnit, Repairable, Chronoshiftable, Passenger SelectionPriority=7 Voice=VehicleVoice LongDesc=Collects Ore and Gems for processing.\n Unarmed [MCV] Description=Mobile Construction Vehicle -Traits=Unit, Mobile, McvDeploy, RenderUnit, Repairable, Chronoshiftable +Traits=Unit, Mobile, McvDeploy, RenderUnit, Repairable, Chronoshiftable, Passenger SelectionPriority=3 Voice=VehicleVoice LongDesc=Deploys into another Construction Yard.\n Unarmed [MNLY.AP] Description=Minelayer (Anti-Personnel) -Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo, Chronoshiftable +Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo, Chronoshiftable, Passenger Voice=VehicleVoice LongDesc=Lays mines to destroy unwary enemy units.\n Unarmed Primary=MINP ;; temporary hack [MNLY.AT] Description=Minelayer (Anti-Tank) -Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo, Chronoshiftable +Traits=Unit, Mobile, RenderUnit, Minelayer, MineImmune, Repairable, LimitedAmmo, Chronoshiftable, Passenger Voice=VehicleVoice LongDesc=Lays mines to destroy unwary enemy units.\n Unarmed Primary=MINV ;; temporary hack @@ -548,62 +548,62 @@ MEDI Description=Attack Dog BuiltAt=KENN Voice=DogVoice -Traits=Unit, Mobile, RenderInfantry ;; AttackBase, SquishByTank, AutoTarget, dog?? +Traits=Unit, Mobile, RenderInfantry, Passenger ;; AttackBase, SquishByTank, AutoTarget, dog?? LongDesc=Anti-infantry unit. Not fooled by the \nSpy's disguise.\n Strong vs Infantry\n Weak vs Vehicles SelectionSize=12,17,-1,-4 [E1] Description=Rifle Infantry -Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget +Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget, Passenger LongDesc=General-purpose infantry. Strong vs Infantry\n Weak vs Vehicles SelectionSize=12,17,0,-9 [E2] Description=Grenadier -Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget +Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget, Passenger FireDelay=15 PrimaryOffset=0,0,0,-13 LongDesc=Infantry armed with grenades. \n Strong vs Buildings, Infantry\n Weak vs Vehicles SelectionSize=12,17,0,-9 [E3] Description=Rocket Soldier -Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget +Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget, Passenger PrimaryOffset=0,0,0,-13 LongDesc=Anti-tank/Anti-aircraft infantry.\n Strong vs Tanks, Aircraft\n Weak vs Infantry SelectionSize=12,17,0,-9 [E4] Description=Flamethrower -Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget +Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, SquishByTank, AutoTarget, Passenger FireDelay=8 PrimaryOffset=0,0,0,-7 LongDesc=Advanced Anti-infantry unit.\n Strong vs Infantry, Buildings\n Weak vs Vehicles SelectionSize=12,17,0,-9 [E6] Description=Engineer -Traits=Unit, Mobile, EngineerCapture, RenderInfantry, TakeCover, SquishByTank +Traits=Unit, Mobile, EngineerCapture, RenderInfantry, TakeCover, SquishByTank, Passenger Voice=EngineerVoice LongDesc=Infiltrates and captures enemy structures.\n Strong vs Nothing\n Weak vs Everything SelectionSize=12,17,0,-9 [SPY] Description=Spy Voice=SpyVoice -Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank +Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank, Passenger LongDesc=Infiltrates enemy structures to gather \nintelligence. Exact effect depends on the \nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised SelectionSize=12,17,0,-9 [THF] Description=Thief Voice=ThiefVoice -Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank +Traits=Unit, Mobile, RenderInfantry, TakeCover, SquishByTank, Passenger LongDesc=Infiltrates enemy refineries & \nsilos, and steals money stored there.\n Unarmed SelectionSize=12,17,0,-9 [E7] Description=Tanya Voice=TanyaVoice -Traits=Unit, Mobile, RenderInfantry, C4Demolition, AttackBase, TakeCover, SquishByTank, AutoTarget +Traits=Unit, Mobile, RenderInfantry, C4Demolition, AttackBase, TakeCover, SquishByTank, AutoTarget, Passenger LongDesc=Elite commando infantry, armed with \ndual pistols and C4.\n Strong vs Infantry, Buildings\n Weak vs Vehicles\n Special Ability: Destroy Building with C4 SelectionSize=12,17,0,-9 [MEDI] Description=Medic Voice=MedicVoice -Traits=Unit, Mobile, RenderInfantry, AutoHeal, AttackBase, TakeCover, SquishByTank +Traits=Unit, Mobile, RenderInfantry, AutoHeal, AttackBase, TakeCover, SquishByTank, Passenger LongDesc=Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything SelectionSize=12,17,0,-9 From 8c9fbb8d6b1eeca46dd8364ff1692c9eb9449c6f Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 15:25:12 +1300 Subject: [PATCH 45/56] cargo: added EnterTransport activity; made things mostly work. still very WIP. --- OpenRa.Game/Actor.cs | 1 - OpenRa.Game/OpenRa.Game.csproj | 1 + .../Traits/Activities/EnterTransport.cs | 36 +++++++++++++++++++ OpenRa.Game/Traits/Activities/UnloadCargo.cs | 3 +- OpenRa.Game/Traits/Cargo.cs | 17 ++++----- OpenRa.Game/Traits/Passenger.cs | 4 +-- OpenRa.Game/World.cs | 12 +++++-- 7 files changed, 58 insertions(+), 16 deletions(-) create mode 100644 OpenRa.Game/Traits/Activities/EnterTransport.cs diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index e8a2e177ca..3d99808bbc 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -36,7 +36,6 @@ namespace OpenRa.Game Location = location; CenterLocation = Traits.Util.CenterOfCell(Location); Owner = owner; - IsInWorld = true; if (Info == null) return; diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 752d599047..296dae3aa4 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -118,6 +118,7 @@ + diff --git a/OpenRa.Game/Traits/Activities/EnterTransport.cs b/OpenRa.Game/Traits/Activities/EnterTransport.cs new file mode 100644 index 0000000000..daa875173d --- /dev/null +++ b/OpenRa.Game/Traits/Activities/EnterTransport.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits.Activities +{ + class EnterTransport : IActivity + { + public IActivity NextActivity { get; set; } + bool isCanceled; + public Actor transport; + + public EnterTransport(Actor self, Actor transport) + { + this.transport = transport; + } + + public IActivity Tick(Actor self) + { + if (isCanceled) return NextActivity; + if (transport == null || !transport.IsInWorld) return NextActivity; + + var cargo = transport.traits.Get(); + if (cargo.IsFull(transport)) + return NextActivity; + + cargo.Load(transport, self); + Game.world.AddFrameEndTask(w => w.Remove(self)); + + return this; + } + + public void Cancel(Actor self) { isCanceled = true; NextActivity = null; } + } +} diff --git a/OpenRa.Game/Traits/Activities/UnloadCargo.cs b/OpenRa.Game/Traits/Activities/UnloadCargo.cs index 2f23dc7886..b0af980ab5 100644 --- a/OpenRa.Game/Traits/Activities/UnloadCargo.cs +++ b/OpenRa.Game/Traits/Activities/UnloadCargo.cs @@ -51,7 +51,8 @@ namespace OpenRa.Game.Traits.Activities if (exitTile == null) return this; - var actor = cargo.UnloadOne(self); + var actor = cargo.Unload(self); + Game.world.AddFrameEndTask(w => { w.Add(actor); diff --git a/OpenRa.Game/Traits/Cargo.cs b/OpenRa.Game/Traits/Cargo.cs index 2f2bff52a8..c895c98bd9 100644 --- a/OpenRa.Game/Traits/Cargo.cs +++ b/OpenRa.Game/Traits/Cargo.cs @@ -11,15 +11,7 @@ namespace OpenRa.Game.Traits { List cargo = new List(); - public Cargo(Actor self) - { - // hack: - cargo.Add(new Actor(Rules.UnitInfo["E1"], int2.Zero, self.Owner)); - cargo.Add(new Actor(Rules.UnitInfo["E1"], int2.Zero, self.Owner)); - cargo.Add(new Actor(Rules.UnitInfo["E1"], int2.Zero, self.Owner)); - cargo.Add(new Actor(Rules.UnitInfo["E6"], int2.Zero, self.Owner)); - cargo.Add(new Actor(Rules.UnitInfo["E7"], int2.Zero, self.Owner)); - } + public Cargo(Actor self) {} public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { @@ -50,7 +42,7 @@ namespace OpenRa.Game.Traits return cargo.Count == 0; } - public Actor UnloadOne(Actor self) + public Actor Unload(Actor self) { var a = cargo[0]; cargo.RemoveAt(0); @@ -79,5 +71,10 @@ namespace OpenRa.Game.Traits return PipType.Green; } + + public void Load(Actor self, Actor a) + { + cargo.Add(a); + } } } diff --git a/OpenRa.Game/Traits/Passenger.cs b/OpenRa.Game/Traits/Passenger.cs index a4092d63d9..29521ecb09 100644 --- a/OpenRa.Game/Traits/Passenger.cs +++ b/OpenRa.Game/Traits/Passenger.cs @@ -34,8 +34,8 @@ namespace OpenRa.Game.Traits if (order.OrderString == "EnterTransport") { self.CancelActivity(); - self.QueueActivity(new Move(order.TargetActor, 0)); - // todo: actually enter the transport + self.QueueActivity(new Move(order.TargetActor.Location, 1)); + self.QueueActivity(new EnterTransport(self, order.TargetActor)); } } } diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index 53dcfc9e37..f8db600406 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -10,10 +10,18 @@ namespace OpenRa.Game List effects = new List(); List> frameEndActions = new List>(); - public void Add(Actor a) { actors.Add(a); ActorAdded(a); } + public void Add(Actor a) + { + a.IsInWorld = true; + actors.Add(a); + ActorAdded(a); + } + public void Remove(Actor a) { - a.IsInWorld = false; actors.Remove(a); ActorRemoved(a); + a.IsInWorld = false; + actors.Remove(a); + ActorRemoved(a); } public void Add(IEffect b) { effects.Add(b); } From 53386d8d869dadb00f9a36e1595309844f2019fb Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 15:30:08 +1300 Subject: [PATCH 46/56] cargo: ban unload while flying --- OpenRa.Game/Traits/Cargo.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenRa.Game/Traits/Cargo.cs b/OpenRa.Game/Traits/Cargo.cs index c895c98bd9..943fdcf8dd 100644 --- a/OpenRa.Game/Traits/Cargo.cs +++ b/OpenRa.Game/Traits/Cargo.cs @@ -15,6 +15,9 @@ namespace OpenRa.Game.Traits public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { + var unit = underCursor.traits.GetOrDefault(); + if (unit.Altitude > 0) return null; + // todo: check if there is an unoccupied `land` tile adjacent if (mi.Button == MouseButton.Right && underCursor == self && cargo.Count > 0) return new Order("Deploy", self, null, int2.Zero, null); From 30e769386252b1b0e3a694b671ae162bc659a48f Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 15:33:22 +1300 Subject: [PATCH 47/56] cargo: don't crash. --- OpenRa.Game/Traits/Cargo.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/OpenRa.Game/Traits/Cargo.cs b/OpenRa.Game/Traits/Cargo.cs index 943fdcf8dd..3d1f27cea0 100644 --- a/OpenRa.Game/Traits/Cargo.cs +++ b/OpenRa.Game/Traits/Cargo.cs @@ -15,12 +15,14 @@ namespace OpenRa.Game.Traits public Order IssueOrder(Actor self, int2 xy, MouseInput mi, Actor underCursor) { - var unit = underCursor.traits.GetOrDefault(); - if (unit.Altitude > 0) return null; - // todo: check if there is an unoccupied `land` tile adjacent if (mi.Button == MouseButton.Right && underCursor == self && cargo.Count > 0) + { + var unit = underCursor.traits.GetOrDefault(); + if (unit != null && unit.Altitude > 0) return null; + return new Order("Deploy", self, null, int2.Zero, null); + } return null; } From 02bff289048b7b2d19f718eeb8497a916020a0b1 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 15:57:19 +1300 Subject: [PATCH 48/56] updating progress --- doc/progress.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/doc/progress.txt b/doc/progress.txt index bcc268c1fb..cd612fc2cd 100644 --- a/doc/progress.txt +++ b/doc/progress.txt @@ -21,7 +21,7 @@ All tracked vehicles Light vehicles V2RL Works -APC Cargo doesn't work +APC Works MNLY Works MGG No gap MRJ No radar @@ -31,8 +31,7 @@ HARV Works ARTY Works Helicopters - - Return to base after attack doesnt work -TRAN Cargo doesn't work +TRAN Works HELI Works HIND Works @@ -47,5 +46,5 @@ CA Works SS Works DD depth charges don't work PT depth charges don't work -LST Cargo doesn't work +LST Works From 27b2d20cab78e3f00a78cb7a5528e0e977ba80d2 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 16:05:20 +1300 Subject: [PATCH 49/56] initial shroud support --- OpenRa.Game/OpenRa.Game.csproj | 1 + OpenRa.Game/Player.cs | 16 +++++++--------- OpenRa.Game/Shroud.cs | 17 +++++++++++++++++ 3 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 OpenRa.Game/Shroud.cs diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 72f4caec37..b3fa1b7e12 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -110,6 +110,7 @@ + diff --git a/OpenRa.Game/Player.cs b/OpenRa.Game/Player.cs index 5e40e92b32..90d6a9f57b 100644 --- a/OpenRa.Game/Player.cs +++ b/OpenRa.Game/Player.cs @@ -17,15 +17,17 @@ namespace OpenRa.Game public string InternalName; public Race Race; public readonly int Index; - public int Cash; - public int Ore; + public int Cash = 10000; + public int Ore = 0; public int OreCapacity; - public int DisplayCash; - public int PowerProvided; - public int PowerDrained; + public int DisplayCash = 0; + public int PowerProvided = 0; + public int PowerDrained = 0; public bool IsReady; + public Shroud Shroud = new Shroud(); + public Player( Actor playerActor, int index, PaletteType palette, string playerName, Race race, string internalName ) { this.PlayerActor = playerActor; @@ -34,10 +36,6 @@ namespace OpenRa.Game this.InternalName = internalName; this.PlayerName = playerName; this.Race = race; - this.Cash = 10000; - this.Ore = 0; - this.DisplayCash = 0; - this.PowerProvided = this.PowerDrained = 0; } void UpdatePower() diff --git a/OpenRa.Game/Shroud.cs b/OpenRa.Game/Shroud.cs new file mode 100644 index 0000000000..a194ecdb15 --- /dev/null +++ b/OpenRa.Game/Shroud.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using IjwFramework.Types; + +namespace OpenRa.Game +{ + class Shroud + { + bool[,] explored = new bool[128, 128]; + + public void Explore(Actor a) + { + } + } +} From 77da5c89de640fb64d8addca270bcc0f0ab0ca5d Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 22:12:22 +1300 Subject: [PATCH 50/56] shroud: it works. perf is pretty ugly, and there are a lot of small bugs. --- OpenRa.FileFormats/IPaletteRemap.cs | 9 +++ OpenRa.FileFormats/OpenRa.FileFormats.csproj | 2 + OpenRa.FileFormats/Palette.cs | 2 +- OpenRa.FileFormats/PaletteRemap.cs | 2 +- OpenRa.FileFormats/ShroudPaletteRemap.cs | 32 +++++++++ OpenRa.Game/Game.cs | 6 ++ OpenRa.Game/Graphics/HardwarePalette.cs | 8 ++- OpenRa.Game/Graphics/WorldRenderer.cs | 2 + OpenRa.Game/Shroud.cs | 70 ++++++++++++++++++++ OpenRa.Game/Traits/Mobile.cs | 11 ++- SequenceEditor/Program.cs | 3 +- 11 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 OpenRa.FileFormats/IPaletteRemap.cs create mode 100644 OpenRa.FileFormats/ShroudPaletteRemap.cs diff --git a/OpenRa.FileFormats/IPaletteRemap.cs b/OpenRa.FileFormats/IPaletteRemap.cs new file mode 100644 index 0000000000..321596490a --- /dev/null +++ b/OpenRa.FileFormats/IPaletteRemap.cs @@ -0,0 +1,9 @@ +using System; +using System.Drawing; +namespace OpenRa.FileFormats +{ + public interface IPaletteRemap + { + Color GetRemappedColor(Color original, int index); + } +} diff --git a/OpenRa.FileFormats/OpenRa.FileFormats.csproj b/OpenRa.FileFormats/OpenRa.FileFormats.csproj index ce057e867c..26f9983855 100644 --- a/OpenRa.FileFormats/OpenRa.FileFormats.csproj +++ b/OpenRa.FileFormats/OpenRa.FileFormats.csproj @@ -55,6 +55,7 @@ + @@ -62,6 +63,7 @@ + diff --git a/OpenRa.FileFormats/Palette.cs b/OpenRa.FileFormats/Palette.cs index 6244913786..5016372a8a 100644 --- a/OpenRa.FileFormats/Palette.cs +++ b/OpenRa.FileFormats/Palette.cs @@ -31,7 +31,7 @@ namespace OpenRa.FileFormats colors[4] = Color.FromArgb(140, 0, 0, 0); } - public Palette(Palette p, PaletteRemap r) + public Palette(Palette p, IPaletteRemap r) { for (int i = 0; i < 256; i++) colors.Add(r.GetRemappedColor(p.GetColor(i), i)); diff --git a/OpenRa.FileFormats/PaletteRemap.cs b/OpenRa.FileFormats/PaletteRemap.cs index ecd6de41cb..635c0d5653 100644 --- a/OpenRa.FileFormats/PaletteRemap.cs +++ b/OpenRa.FileFormats/PaletteRemap.cs @@ -4,7 +4,7 @@ using System.IO; namespace OpenRa.FileFormats { - public class PaletteRemap + public class PaletteRemap : IPaletteRemap { int offset; List remapColors = new List(); diff --git a/OpenRa.FileFormats/ShroudPaletteRemap.cs b/OpenRa.FileFormats/ShroudPaletteRemap.cs new file mode 100644 index 0000000000..be08298412 --- /dev/null +++ b/OpenRa.FileFormats/ShroudPaletteRemap.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Drawing; + +namespace OpenRa.FileFormats +{ + public class ShroudPaletteRemap : IPaletteRemap + { + public Color GetRemappedColor(Color original, int index) + { + // false-color version for debug + + //return new[] { + // Color.Orange, Color.Green, + // Color.Blue, Color.Yellow, + // Color.Black, + // Color.Red, + // Color.Purple, + // Color.Cyan}[index % 8]; + + return new[] { + Color.Transparent, Color.Green, + Color.Blue, Color.Yellow, + Color.Black, + Color.FromArgb(192,0,0,0), + Color.FromArgb(128,0,0,0), + Color.FromArgb(64,0,0,0)}[index % 8]; + } + } +} diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index cb2e3fed1b..777a0d8169 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -102,6 +102,12 @@ namespace OpenRa.Game oreFrequency = (int)(Rules.General.GrowthRate * 60 * 1000); oreTicks = oreFrequency; + + foreach (var a in Game.world.Actors) + if (a.Info != null && a.Owner == players[0]) + players[0].Shroud.Explore(a); + + Game.world.ActorAdded += a => players[0].Shroud.Explore(a); } public static void Initialize(string mapName, Renderer renderer, int2 clientSize, diff --git a/OpenRa.Game/Graphics/HardwarePalette.cs b/OpenRa.Game/Graphics/HardwarePalette.cs index 9c0538e61f..2092291dd0 100644 --- a/OpenRa.Game/Graphics/HardwarePalette.cs +++ b/OpenRa.Game/Graphics/HardwarePalette.cs @@ -3,7 +3,12 @@ using OpenRa.FileFormats; namespace OpenRa.Game.Graphics { - public enum PaletteType { Gold, Blue, Red, Orange, Teal, Salmon, Green, Gray, Shadow, Invuln, Chrome }; + public enum PaletteType + { + Gold, Blue, Red, Orange, Teal, Salmon, Green, Gray, + Shadow, Invuln, Chrome, Shroud, + }; + class HardwarePalette : Sheet { const int maxEntries = 16; @@ -21,6 +26,7 @@ namespace OpenRa.Game.Graphics AddPalette(new Palette(pal, new PaletteRemap(Color.FromArgb(140, 0, 0, 0)))); AddPalette(pal); // iron curtain. todo: remap! AddPalette(pal); // chrome (it's like gold, but we're not going to hax it in palettemods) + AddPalette(new Palette(pal, new ShroudPaletteRemap())); } int AddPalette(Palette p) diff --git a/OpenRa.Game/Graphics/WorldRenderer.cs b/OpenRa.Game/Graphics/WorldRenderer.cs index 14bbff4afe..0ababf0272 100644 --- a/OpenRa.Game/Graphics/WorldRenderer.cs +++ b/OpenRa.Game/Graphics/WorldRenderer.cs @@ -87,6 +87,8 @@ namespace OpenRa.Game.Graphics if (Game.controller.orderGenerator != null) Game.controller.orderGenerator.Render(); + Game.LocalPlayer.Shroud.Draw(spriteRenderer); + lineRenderer.Flush(); spriteRenderer.Flush(); } diff --git a/OpenRa.Game/Shroud.cs b/OpenRa.Game/Shroud.cs index a194ecdb15..01d353245e 100644 --- a/OpenRa.Game/Shroud.cs +++ b/OpenRa.Game/Shroud.cs @@ -3,15 +3,85 @@ using System.Collections.Generic; using System.Linq; using System.Text; using IjwFramework.Types; +using OpenRa.Game.Graphics; namespace OpenRa.Game { class Shroud { bool[,] explored = new bool[128, 128]; + Sprite[] shadowBits = SpriteSheetBuilder.LoadAllSprites("shadow"); + Sprite[,] sprites = new Sprite[128, 128]; + bool dirty; public void Explore(Actor a) { + foreach (var t in Game.FindTilesInCircle(a.Location, a.Info.Sight)) + explored[t.X, t.Y] = true; + + dirty = true; + } + + Sprite ChooseShroud(int i, int j) + { + // bits are for exploredness: left, right, up, down, self + var n = new[] { + 0xf,0xf,0xf,0xf, + 0xf,0x0f,0x0f,0xf, + 0xf,0x0f,0x0f,0xf, + 0xf,0xf,0xf,0xf, + 0,7,13,0, + 14,6,12,4, + 11,3,9,1, + 0,2,8,0, + }; + + var v = 0; + if (explored[i-1,j]) v |= 1; + if (explored[i+1,j]) v |= 2; + if (explored[i,j-1]) v |= 4; + if (explored[i,j+1]) v |= 8; + if (explored[i, j]) v |= 16; + + var x = n[v]; + + if (x == 0) + { + // bits are for exploredness: TL, TR, BR, BL + var m = new[] { + 46, 41, 42, 38, + 43, 45, 39, 35, + 40, 37, 44, 34, + 36, 33, 32, 47, + }; + + var u = 0; + if (explored[i - 1, j - 1]) u |= 1; + if (explored[i + 1, j - 1]) u |= 2; + if (explored[i + 1, j + 1]) u |= 4; + if (explored[i - 1, j + 1]) u |= 8; + return shadowBits[m[u]]; + } + + return shadowBits[x]; + } + + public void Draw(SpriteRenderer r) + { + if (dirty) + { + dirty = false; + for (int j = 1; j < 127; j++) + for (int i = 1; i < 127; i++) + sprites[i, j] = ChooseShroud(i, j); + } + + for (var j = 0; j < 128; j++) + for (var i = 0; i < 128; i++) + if (sprites[i,j] != null) + r.DrawSprite(sprites[i, j], + Game.CellSize * new float2(i, j), + PaletteType.Shroud); } } } diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs index 4bf3a76e1f..e917df2610 100644 --- a/OpenRa.Game/Traits/Mobile.cs +++ b/OpenRa.Game/Traits/Mobile.cs @@ -18,7 +18,16 @@ namespace OpenRa.Game.Traits public int2 toCell { get { return self.Location; } - set { Game.UnitInfluence.Remove(self, this); self.Location = value; Game.UnitInfluence.Add(self, this); } + set + { + if (self.Location != value) + { + Game.UnitInfluence.Remove(self, this); + self.Location = value; + self.Owner.Shroud.Explore(self); + } + Game.UnitInfluence.Add(self, this); + } } public Mobile(Actor self) diff --git a/SequenceEditor/Program.cs b/SequenceEditor/Program.cs index cdef4b4285..90d01db517 100644 --- a/SequenceEditor/Program.cs +++ b/SequenceEditor/Program.cs @@ -83,7 +83,8 @@ namespace SequenceEditor Doc = new XmlDocument(); Doc.Load(XmlFilename); - Pal = new Palette(FileSystem.Open("temperat.pal")); + var tempPal = new Palette(FileSystem.Open("temperat.pal")); + Pal = new Palette(tempPal, new ShroudPaletteRemap()); UnitName = args.FirstOrDefault( x => !x.EndsWith(".xml") ); if (UnitName == null) From 05b4517f2ee272fb3d8b7d50ff2627ed826f7214 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 22:17:49 +1300 Subject: [PATCH 51/56] fixing bad shroud behavior --- OpenRa.Game/Game.cs | 11 +++++------ OpenRa.Game/Shroud.cs | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index 777a0d8169..edc40517d0 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -59,6 +59,11 @@ namespace OpenRa.Game palette = new HardwarePalette(renderer, Rules.Map); world = new World(); + Game.world.ActorAdded += a => + { + if (a.Owner != null && a.Info != null) + a.Owner.Shroud.Explore(a); + }; for (int i = 0; i < 8; i++) { @@ -102,12 +107,6 @@ namespace OpenRa.Game oreFrequency = (int)(Rules.General.GrowthRate * 60 * 1000); oreTicks = oreFrequency; - - foreach (var a in Game.world.Actors) - if (a.Info != null && a.Owner == players[0]) - players[0].Shroud.Explore(a); - - Game.world.ActorAdded += a => players[0].Shroud.Explore(a); } public static void Initialize(string mapName, Renderer renderer, int2 clientSize, diff --git a/OpenRa.Game/Shroud.cs b/OpenRa.Game/Shroud.cs index 01d353245e..831af634a2 100644 --- a/OpenRa.Game/Shroud.cs +++ b/OpenRa.Game/Shroud.cs @@ -16,7 +16,7 @@ namespace OpenRa.Game public void Explore(Actor a) { - foreach (var t in Game.FindTilesInCircle(a.Location, a.Info.Sight)) + foreach (var t in Game.FindTilesInCircle((1f/Game.CellSize * a.CenterLocation).ToInt2(), a.Info.Sight)) explored[t.X, t.Y] = true; dirty = true; From 45b235b76cf2c8d9199aa6da73fd82a5efaf25a9 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 22:25:39 +1300 Subject: [PATCH 52/56] patch SequenceEditor palette back --- SequenceEditor/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SequenceEditor/Program.cs b/SequenceEditor/Program.cs index 90d01db517..1173636ce0 100644 --- a/SequenceEditor/Program.cs +++ b/SequenceEditor/Program.cs @@ -84,7 +84,7 @@ namespace SequenceEditor Doc.Load(XmlFilename); var tempPal = new Palette(FileSystem.Open("temperat.pal")); - Pal = new Palette(tempPal, new ShroudPaletteRemap()); + Pal = tempPal; //new Palette(tempPal, new ShroudPaletteRemap()); UnitName = args.FirstOrDefault( x => !x.EndsWith(".xml") ); if (UnitName == null) From 83b61de7c4a681f30b14167cda1c49c4105a18d9 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Tue, 5 Jan 2010 22:48:31 +1300 Subject: [PATCH 53/56] optimizing shroud renderer --- OpenRa.Game/Shroud.cs | 48 +++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/OpenRa.Game/Shroud.cs b/OpenRa.Game/Shroud.cs index 831af634a2..37b9815370 100644 --- a/OpenRa.Game/Shroud.cs +++ b/OpenRa.Game/Shroud.cs @@ -16,7 +16,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.Info.Sight)) explored[t.X, t.Y] = true; dirty = true; @@ -35,12 +35,12 @@ namespace OpenRa.Game 11,3,9,1, 0,2,8,0, }; - + var v = 0; - if (explored[i-1,j]) v |= 1; - if (explored[i+1,j]) v |= 2; - if (explored[i,j-1]) v |= 4; - if (explored[i,j+1]) v |= 8; + if (explored[i - 1, j]) v |= 1; + if (explored[i + 1, j]) v |= 2; + if (explored[i, j - 1]) v |= 4; + if (explored[i, j + 1]) v |= 8; if (explored[i, j]) v |= 16; var x = n[v]; @@ -76,12 +76,38 @@ namespace OpenRa.Game sprites[i, j] = ChooseShroud(i, j); } - for (var j = 0; j < 128; j++) - for (var i = 0; i < 128; i++) - if (sprites[i,j] != null) - r.DrawSprite(sprites[i, j], - Game.CellSize * new float2(i, j), + for (var j = 1; j < 127; j++) + { + var starti = 1; + for (var i = 1; i < 127; i++) + { + if (sprites[i, j] == shadowBits[0x0f]) + continue; + + if (starti != i) + { + r.DrawSprite(sprites[starti,j], + Game.CellSize * new float2(starti, j), + PaletteType.Shroud, + new float2(Game.CellSize * (i - starti), Game.CellSize)); + r.DrawSprite(sprites[i-1, j], + Game.CellSize * new float2(i-1, j), PaletteType.Shroud); + starti = i+1; + } + + r.DrawSprite(sprites[i, j], + Game.CellSize * new float2(i, j), + PaletteType.Shroud); + starti = i+1; + } + + if (starti < 127) + r.DrawSprite(sprites[starti, j], + Game.CellSize * new float2(starti, j), + PaletteType.Shroud, + new float2(Game.CellSize * (127 - starti), Game.CellSize)); + } } } } From 72605ebfc8f326e04d49f278c64dc69df88fb94f Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 6 Jan 2010 10:03:23 +1300 Subject: [PATCH 54/56] prep for fixing render glitches --- OpenRa.Game/Graphics/Util.cs | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/OpenRa.Game/Graphics/Util.cs b/OpenRa.Game/Graphics/Util.cs index 85dada816d..847ad9d505 100644 --- a/OpenRa.Game/Graphics/Util.cs +++ b/OpenRa.Game/Graphics/Util.cs @@ -8,18 +8,6 @@ namespace OpenRa.Game.Graphics { static class Util { - static float2 KLerp(float2 o, float2 d, int k) - { - switch (k) - { - case 0: return o; - case 1: return new float2(o.X + d.X, o.Y); - case 2: return new float2(o.X, o.Y + d.Y); - case 3: return new float2(o.X + d.X, o.Y + d.Y); - default: throw new InvalidOperationException(); - } - } - public static string[] ReadAllLines(Stream s) { List result = new List(); @@ -61,10 +49,14 @@ namespace OpenRa.Game.Graphics { float2 attrib = new float2(palette / 16.0f, channelSelect[(int)r.channel]); - vertices[nv] = new Vertex(KLerp(o, size, 0), r.FastMapTextureCoords(0), attrib); - vertices[nv + 1] = new Vertex(KLerp(o, size, 1), r.FastMapTextureCoords(1), attrib); - vertices[nv + 2] = new Vertex(KLerp(o, size, 2), r.FastMapTextureCoords(2), attrib); - vertices[nv + 3] = new Vertex(KLerp(o, size, 3), r.FastMapTextureCoords(3), attrib); + vertices[nv] = new Vertex(o, + r.FastMapTextureCoords(0), attrib); + vertices[nv + 1] = new Vertex(new float2(o.X + size.X, o.Y), + r.FastMapTextureCoords(1), attrib); + vertices[nv + 2] = new Vertex(new float2(o.X, o.Y + size.Y), + r.FastMapTextureCoords(2), attrib); + vertices[nv + 3] = new Vertex(new float2(o.X + size.X, o.Y + size.Y), + r.FastMapTextureCoords(3), attrib); indices[ni] = (ushort)(nv); indices[ni + 1] = indices[ni + 3] = (ushort)(nv + 1); From e82107b69b8e1ce55bbbc9c7958aa39082a094bb Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 6 Jan 2010 10:08:53 +1300 Subject: [PATCH 55/56] fixing a pile of stupid texel-offset-related bugs --- OpenRa.Game/Graphics/Sprite.cs | 8 ++++---- OpenRa.Game/Shroud.cs | 3 --- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/OpenRa.Game/Graphics/Sprite.cs b/OpenRa.Game/Graphics/Sprite.cs index a9f7247f37..3fb1a10971 100644 --- a/OpenRa.Game/Graphics/Sprite.cs +++ b/OpenRa.Game/Graphics/Sprite.cs @@ -19,10 +19,10 @@ namespace OpenRa.Game.Graphics this.channel = channel; uv = new RectangleF( - (float)(bounds.Left + 0.5f) / sheet.Size.Width, - (float)(bounds.Top + 0.5f) / sheet.Size.Height, - (float)(bounds.Width) / sheet.Size.Width, - (float)(bounds.Height) / sheet.Size.Height); + (float)(bounds.Left + .5f) / sheet.Size.Width, + (float)(bounds.Top + .5f) / sheet.Size.Height, + (float)(bounds.Width - .5f) / sheet.Size.Width, + (float)(bounds.Height - .5f) / sheet.Size.Height); uvhax = new float2[] { diff --git a/OpenRa.Game/Shroud.cs b/OpenRa.Game/Shroud.cs index 37b9815370..8f64f7365c 100644 --- a/OpenRa.Game/Shroud.cs +++ b/OpenRa.Game/Shroud.cs @@ -90,9 +90,6 @@ namespace OpenRa.Game Game.CellSize * new float2(starti, j), PaletteType.Shroud, new float2(Game.CellSize * (i - starti), Game.CellSize)); - r.DrawSprite(sprites[i-1, j], - Game.CellSize * new float2(i-1, j), - PaletteType.Shroud); starti = i+1; } From fe2320ac7c67ccaa5d4a10526d8d169e267d5b50 Mon Sep 17 00:00:00 2001 From: Chris Forbes Date: Wed, 6 Jan 2010 15:51:37 +1300 Subject: [PATCH 56/56] fix radar (merge worked, but broken semantics) --- OpenRa.Game/Chrome.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/OpenRa.Game/Chrome.cs b/OpenRa.Game/Chrome.cs index ed168a1675..dfa218f8c8 100644 --- a/OpenRa.Game/Chrome.cs +++ b/OpenRa.Game/Chrome.cs @@ -136,7 +136,7 @@ namespace OpenRa.Game PerfHistory.Render(renderer, Game.worldRenderer.lineRenderer); - Game.minimap.Draw(new float2(Game.viewport.Width - 256, 8)); + DrawMinimap(); chromeRenderer.DrawSprite(specialBinSprite, float2.Zero, PaletteType.Chrome); chromeRenderer.DrawSprite(moneyBinSprite, new float2(Game.viewport.Width - 320, 0), PaletteType.Chrome); @@ -145,7 +145,7 @@ namespace OpenRa.Game DrawPower(); chromeRenderer.Flush(); DrawButtons(); - DrawMinimap(); + int paletteHeight = DrawBuildPalette(currentTab); DrawBuildTabs(paletteHeight); DrawChat(); @@ -153,9 +153,12 @@ namespace OpenRa.Game void DrawMinimap() { - var hasRadar = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer && a.traits.Contains() && a.traits.Get().IsActive()); + var hasRadar = Game.world.Actors.Any(a => a.Owner == Game.LocalPlayer + && a.traits.Contains() + && a.traits.Get().IsActive()); + if (hasRadar) - Game.minimap.Draw(new float2(Game.viewport.Width - 128, 30)); + Game.minimap.Draw(new float2(Game.viewport.Width - 256, 8)); } void AddButton(Rectangle r, Action b) { buttons.Add(Pair.New(r, b)); }