diff --git a/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs b/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs index 1d889cd83c..e6d2894db6 100644 --- a/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs +++ b/OpenRA.Mods.Common/Traits/World/WeatherOverlay.cs @@ -19,7 +19,7 @@ namespace OpenRA.Mods.Common.Traits { [Desc("Adds a particle-based overlay.")] [TraitLocation(SystemActors.World | SystemActors.EditorWorld)] - public class WeatherOverlayInfo : TraitInfo, ILobbyCustomRulesIgnore + public class WeatherOverlayInfo : ConditionalTraitInfo, ILobbyCustomRulesIgnore { [Desc("Average number of particles per 100x100 px square.")] public readonly int ParticleDensityFactor = 8; @@ -69,10 +69,19 @@ namespace OpenRA.Mods.Common.Traits [Desc("Works only with line enabled and can be used to fade out the tail of the line like a contrail.")] public readonly byte LineTailAlphaValue = 200; + [Desc("Time to fade out once the trait becomes disabled.")] + public readonly int FadeOutTicks = 1000; + + [Desc("Time to fade in once the trait becomes enabled.")] + public readonly int FadeInTicks = 1000; + + [Desc("Percentage of the initial particle when enabled and the game start.")] + public readonly int InitialParticlePercentage = 100; + public override object Create(ActorInitializer init) { return new WeatherOverlay(init.World, this); } } - public class WeatherOverlay : ITick, IRenderAboveWorld, INotifyViewportZoomExtentsChanged + public class WeatherOverlay : ConditionalTrait, ITick, IRenderAboveWorld, INotifyViewportZoomExtentsChanged { readonly struct Particle { @@ -133,8 +142,9 @@ namespace OpenRA.Mods.Common.Traits } } - readonly WeatherOverlayInfo info; readonly World world; + readonly int fadeInTick; + readonly int fadeOutTick; float windStrength; int targetWindStrengthIndex; @@ -142,14 +152,19 @@ namespace OpenRA.Mods.Common.Traits Particle[] particles; Size viewportSize; long lastRender; + bool initialTick = true; + int fadingInTick; + int fadingOutTick; public WeatherOverlay(World world, WeatherOverlayInfo info) + : base(info) { - this.info = info; this.world = world; targetWindStrengthIndex = info.ChangingWindLevel ? world.LocalRandom.Next(info.WindLevels.Length) : 0; windUpdateCountdown = world.LocalRandom.Next(info.WindTick[0], info.WindTick[1]); windStrength = info.WindLevels[targetWindStrengthIndex]; + fadeInTick = info.FadeInTicks > 0 ? info.FadeInTicks : 1; + fadeOutTick = info.FadeOutTicks > 0 ? info.FadeOutTicks : 1; } void INotifyViewportZoomExtentsChanged.ViewportZoomExtentsChanged(float minZoom, float maxZoom) @@ -159,30 +174,60 @@ namespace OpenRA.Mods.Common.Traits viewportSize = new Size(s.X, s.Y); // Randomly distribute particles within the initial viewport - var particleCount = viewportSize.Width * viewportSize.Height * info.ParticleDensityFactor / 10000; + var particleCount = viewportSize.Width * viewportSize.Height * Info.ParticleDensityFactor / 10000; particles = new Particle[particleCount]; var rect = new Rectangle(int2.Zero, viewportSize); for (var i = 0; i < particles.Length; i++) - particles[i] = new Particle(info, world.LocalRandom, rect); + particles[i] = new Particle(Info, world.LocalRandom, rect); + } + + protected override void TraitEnabled(Actor self) + { + if (!initialTick) + fadingInTick = (fadeOutTick - fadingOutTick) * 1000 * fadeInTick / fadeOutTick / 1000; + } + + protected override void TraitDisabled(Actor self) + { + if (!initialTick) + fadingOutTick = (fadeInTick - fadingInTick) * 1000 * fadeOutTick / fadeInTick / 1000; } void ITick.Tick(Actor self) { - if (!info.ChangingWindLevel || info.WindLevels.Length == 1) + if (initialTick) + { + initialTick = false; + var initialPercentage = Exts.Clamp(Info.InitialParticlePercentage, 0, 100); + if (IsTraitDisabled) + fadingOutTick = fadeOutTick * (100 - initialPercentage) / 100; + else + fadingInTick = fadeInTick * initialPercentage / 100; + } + + if (IsTraitDisabled) + { + if (fadingOutTick < fadeOutTick) + fadingOutTick++; + } + else if (fadingInTick < fadeInTick) + fadingInTick++; + + if (!Info.ChangingWindLevel || Info.WindLevels.Length == 1) return; if (--windUpdateCountdown <= 0) { - windUpdateCountdown = self.World.LocalRandom.Next(info.WindTick[0], info.WindTick[1]); + windUpdateCountdown = self.World.LocalRandom.Next(Info.WindTick[0], Info.WindTick[1]); if (targetWindStrengthIndex > 0 && self.World.LocalRandom.Next(2) == 1) targetWindStrengthIndex--; - else if (targetWindStrengthIndex < info.WindLevels.Length - 1) + else if (targetWindStrengthIndex < Info.WindLevels.Length - 1) targetWindStrengthIndex++; } // Fading the wind in little steps towards the TargetWindOffset - var targetWindLevel = info.WindLevels[targetWindStrengthIndex]; - if (info.InstantWindChanges) + var targetWindLevel = Info.WindLevels[targetWindStrengthIndex]; + if (Info.InstantWindChanges) windStrength = targetWindLevel; else if (Math.Abs(windStrength - targetWindLevel) > 0.01f) { @@ -205,7 +250,9 @@ namespace OpenRA.Mods.Common.Traits var tickFraction = Math.Min((runtime - lastRender) * 1f / world.Timestep, 1); lastRender = runtime; - for (var i = 0; i < particles.Length; i++) + var spawnNum = particles.Length * (IsTraitDisabled ? (fadeOutTick - fadingOutTick) * 1000 / fadeOutTick : fadingInTick * 1000 / fadeInTick) / 1000; + + for (var i = 0; i < spawnNum; i++) { // Simulate wind and gravity effects on the particle var p = particles[i]; @@ -238,7 +285,7 @@ namespace OpenRA.Mods.Common.Traits // Render the particle // We must provide a z coordinate to stop the GL near and far Z limits from culling the geometry var a = new float3(p.Pos.X, p.Pos.Y, p.Pos.Y); - if (info.UseSquares) + if (Info.UseSquares) { var b = a + new float2(p.Size, p.Size); wcr.FillRect(a, b, p.Color);