diff --git a/OpenRA.Mods.RA/Effects/TeslaZap.cs b/OpenRA.Mods.RA/Effects/TeslaZap.cs index 9671d096b7..56dfbb32ed 100755 --- a/OpenRA.Mods.RA/Effects/TeslaZap.cs +++ b/OpenRA.Mods.RA/Effects/TeslaZap.cs @@ -30,7 +30,7 @@ namespace OpenRA.Mods.RA.Effects { readonly ProjectileArgs Args; readonly TeslaZapInfo Info; - IEnumerable renderables; + TeslaZapRenderable zap; int timeUntilRemove = 2; // # of frames bool doneDamage = false; bool initialized = false; @@ -41,27 +41,10 @@ namespace OpenRA.Mods.RA.Effects Info = info; } - public IEnumerable GenerateRenderables(WorldRenderer wr) - { - var bright = SequenceProvider.GetSequence(Info.Image, "bright"); - var dim = SequenceProvider.GetSequence(Info.Image, "dim"); - - var source = wr.ScreenPosition(Args.source); - var target = wr.ScreenPosition(Args.passiveTarget); - - for (var n = 0; n < Info.DimZaps; n++) - foreach (var z in DrawZapWandering(wr, source, target, dim)) - yield return z; - for (var n = 0; n < Info.BrightZaps; n++) - foreach (var z in DrawZapWandering(wr, source, target, bright)) - yield return z; - } - public void Tick(World world) { - if (timeUntilRemove <= 0) + if (timeUntilRemove-- <= 0) world.AddFrameEndTask(w => w.Remove(this)); - --timeUntilRemove; if (!doneDamage) { @@ -75,75 +58,10 @@ namespace OpenRA.Mods.RA.Effects { if (!initialized) { - renderables = GenerateRenderables(wr); - initialized = true; + var pos = Args.guidedTarget.IsValid ? Args.guidedTarget.CenterPosition : Args.passiveTarget; + zap = new TeslaZapRenderable(Args.source, 0, pos - Args.source, Info.Image, Info.BrightZaps, Info.DimZaps); } - - return renderables; + yield return zap; } - - static IEnumerable DrawZapWandering(WorldRenderer wr, float2 from, float2 to, Sequence s) - { - var z = float2.Zero; /* hack */ - var dist = to - from; - var norm = (1f / dist.Length) * new float2(-dist.Y, dist.X); - - var renderables = new List(); - if (Game.CosmeticRandom.Next(2) != 0) - { - var p1 = from + (1 / 3f) * dist + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; - var p2 = from + (2 / 3f) * dist + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; - - renderables.AddRange(DrawZap(wr, from, p1, s, out p1)); - renderables.AddRange(DrawZap(wr, p1, p2, s, out p2)); - renderables.AddRange(DrawZap(wr, p2, to, s, out z)); - } - else - { - var p1 = from + (1 / 2f) * dist + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; - - renderables.AddRange(DrawZap(wr, from, p1, s, out p1)); - renderables.AddRange(DrawZap(wr, p1, to, s, out z)); - } - - return renderables; - } - - static IEnumerable DrawZap(WorldRenderer wr, float2 from, float2 to, Sequence s, out float2 p) - { - var dist = to - from; - var q = new float2(-dist.Y, dist.X); - var c = -float2.Dot(from, q); - var rs = new List(); - var z = from; - - while ((to - z).X > 5 || (to - z).X < -5 || (to - z).Y > 5 || (to - z).Y < -5) - { - var step = steps.Where(t => (to - (z + new float2(t[0],t[1]))).LengthSquared < (to - z).LengthSquared ) - .OrderBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)).First(); - - rs.Add(new SpriteRenderable(s.GetSprite(step[4]), z + new float2(step[2], step[3]), - wr.Palette("effect"), (int)from.Y)); - z += new float2(step[0], step[1]); - if( rs.Count >= 1000 ) - break; - } - - p = z; - - return rs; - } - - static int[][] steps = new [] - { - new int[] { 8, 8, 4, 4, 0 }, - new int[] { -8, -8, -4, -4, 0 }, - new int[] { 8, 0, 4, 4, 1 }, - new int[] { -8, 0, -4, 4, 1 }, - new int[] { 0, 8, 4, 4, 2 }, - new int[] { 0, -8, 4, -4, 2 }, - new int[] { -8, 8, -4, 4, 3 }, - new int[] { 8, -8, 4, -4, 3 } - }; } } diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index bdc1ec10cf..54a3cfd217 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -462,6 +462,7 @@ + diff --git a/OpenRA.Mods.RA/TeslaZapRenderable.cs b/OpenRA.Mods.RA/TeslaZapRenderable.cs new file mode 100755 index 0000000000..0bdf0186ce --- /dev/null +++ b/OpenRA.Mods.RA/TeslaZapRenderable.cs @@ -0,0 +1,148 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Effects; +using OpenRA.GameRules; +using OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.RA +{ + struct TeslaZapRenderable : IRenderable + { + static int[][] steps = new[] + { + new int[] { 8, 8, 4, 4, 0 }, + new int[] { -8, -8, -4, -4, 0 }, + new int[] { 8, 0, 4, 4, 1 }, + new int[] { -8, 0, -4, 4, 1 }, + new int[] { 0, 8, 4, 4, 2 }, + new int[] { 0, -8, 4, -4, 2 }, + new int[] { -8, 8, -4, 4, 3 }, + new int[] { 8, -8, 4, -4, 3 } + }; + + readonly WPos pos; + readonly int zOffset; + readonly WVec length; + readonly string image; + readonly int brightZaps, dimZaps; + + WPos cachedPos; + WVec cachedLength; + IEnumerable cache; + + public TeslaZapRenderable(WPos pos, int zOffset, WVec length, string image, int brightZaps, int dimZaps) + { + this.pos = pos; + this.zOffset = zOffset; + this.length = length; + this.image = image; + this.brightZaps = brightZaps; + this.dimZaps = dimZaps; + + cachedPos = WPos.Zero; + cachedLength = WVec.Zero; + cache = new IRenderable[] { }; + } + + public WPos Pos { get { return pos; } } + public float Scale { get { return 1f; } } + public PaletteReference Palette { get { return null; } } + public int ZOffset { get { return zOffset; } } + + public IRenderable WithScale(float newScale) { return new TeslaZapRenderable(pos, zOffset, length, image, brightZaps, dimZaps); } + public IRenderable WithPalette(PaletteReference newPalette) { return new TeslaZapRenderable(pos, zOffset, length, image, brightZaps, dimZaps); } + public IRenderable WithZOffset(int newOffset) { return new TeslaZapRenderable(pos, zOffset, length, image, brightZaps, dimZaps); } + public IRenderable WithPos(WPos pos) { return new TeslaZapRenderable(pos, zOffset, length, image, brightZaps, dimZaps); } + + public void BeforeRender(WorldRenderer wr) { } + public void RenderDebugGeometry(WorldRenderer wr) { } + public void Render(WorldRenderer wr) + { + if (!cache.Any() || length != cachedLength || pos != cachedPos) + cache = GenerateRenderables(wr); + + cache.Do(c => c.Render(wr)); + } + + public IEnumerable GenerateRenderables(WorldRenderer wr) + { + var bright = SequenceProvider.GetSequence(image, "bright"); + var dim = SequenceProvider.GetSequence(image, "dim"); + + var source = wr.ScreenPosition(pos); + var target = wr.ScreenPosition(pos + length); + + for (var n = 0; n < dimZaps; n++) + foreach (var z in DrawZapWandering(wr, source, target, dim)) + yield return z; + for (var n = 0; n < brightZaps; n++) + foreach (var z in DrawZapWandering(wr, source, target, bright)) + yield return z; + } + + static IEnumerable DrawZapWandering(WorldRenderer wr, float2 from, float2 to, Sequence s) + { + var z = float2.Zero; /* hack */ + var dist = to - from; + var norm = (1f / dist.Length) * new float2(-dist.Y, dist.X); + + var renderables = new List(); + if (Game.CosmeticRandom.Next(2) != 0) + { + var p1 = from + (1 / 3f) * dist + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; + var p2 = from + (2 / 3f) * dist + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; + + renderables.AddRange(DrawZap(wr, from, p1, s, out p1)); + renderables.AddRange(DrawZap(wr, p1, p2, s, out p2)); + renderables.AddRange(DrawZap(wr, p2, to, s, out z)); + } + else + { + var p1 = from + (1 / 2f) * dist + Game.CosmeticRandom.Gauss1D(1) * .2f * dist.Length * norm; + + renderables.AddRange(DrawZap(wr, from, p1, s, out p1)); + renderables.AddRange(DrawZap(wr, p1, to, s, out z)); + } + + return renderables; + } + + static IEnumerable DrawZap(WorldRenderer wr, float2 from, float2 to, Sequence s, out float2 p) + { + var dist = to - from; + var q = new float2(-dist.Y, dist.X); + var c = -float2.Dot(from, q); + var rs = new List(); + var z = from; + + while ((to - z).X > 5 || (to - z).X < -5 || (to - z).Y > 5 || (to - z).Y < -5) + { + var step = steps.Where(t => (to - (z + new float2(t[0], t[1]))).LengthSquared < (to - z).LengthSquared) + .OrderBy(t => Math.Abs(float2.Dot(z + new float2(t[0], t[1]), q) + c)).First(); + + rs.Add(new SpriteRenderable(s.GetSprite(step[4]), z + new float2(step[2], step[3]), + wr.Palette("effect"), (int)from.Y)); + + z += new float2(step[0], step[1]); + if (rs.Count >= 1000) + break; + } + + p = z; + + return rs; + } + } +}