diff --git a/OpenRA.Mods.Cnc/Traits/World/WithResourceAnimation.cs b/OpenRA.Mods.Cnc/Traits/World/WithResourceAnimation.cs new file mode 100644 index 0000000000..4060cd64a7 --- /dev/null +++ b/OpenRA.Mods.Cnc/Traits/World/WithResourceAnimation.cs @@ -0,0 +1,106 @@ +#region Copyright & License Information +/* + * Copyright 2007-2021 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.Linq; +using OpenRA.Graphics; +using OpenRA.Mods.Common; +using OpenRA.Mods.Common.Effects; +using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; + +namespace OpenRA.Mods.Cnc.Traits +{ + [TraitLocation(SystemActors.World | SystemActors.EditorWorld)] + [Desc("Allows to play animations on resources.", "Attach this to the world actor.")] + public class WithResourceAnimationInfo : TraitInfo, Requires + { + [FieldLoader.Require] + [Desc("Resource types to animate.")] + public readonly HashSet Types = null; + + [Desc("The percentage of resource cells to play the animation on.", "Use two values to randomize between them.")] + public readonly int[] Ratio = { 1, 10 }; + + [Desc("Tick interval between two animation spawning.", "Use two values to randomize between them.")] + public readonly int[] Interval = { 200, 500 }; + + [FieldLoader.Require] + [Desc("Animation image.")] + public readonly string Image = null; + + [SequenceReference(nameof(Image))] + [Desc("Randomly select one of these sequences to render.")] + public readonly string[] Sequences = new string[] { "idle" }; + + [PaletteReference] + [Desc("Animation palette.")] + public readonly string Palette = null; + + public override object Create(ActorInitializer init) { return new WithResourceAnimation(init.Self, this); } + } + + public class WithResourceAnimation : IWorldLoaded, ITick + { + readonly WithResourceAnimationInfo info; + readonly World world; + + WorldRenderer worldRenderer; + IResourceRenderer resourceRenderer; + + int ticks; + + public WithResourceAnimation(Actor self, WithResourceAnimationInfo info) + { + world = self.World; + this.info = info; + + ticks = Common.Util.RandomInRange(world.LocalRandom, info.Interval); + } + + void IWorldLoaded.WorldLoaded(World w, WorldRenderer wr) + { + worldRenderer = wr; + + resourceRenderer = w.WorldActor.TraitsImplementing() + .Single(r => info.Types.Overlaps(r.ResourceTypes)); + } + + void ITick.Tick(Actor self) + { + if (--ticks > 0) + return; + + var cells = new HashSet(); + foreach (var uv in worldRenderer.Viewport.AllVisibleCells.CandidateMapCoords) + { + if (!world.Map.Contains(uv)) + return; + + var cell = uv.ToCPos(world.Map); + var type = resourceRenderer.GetRenderedResourceType(cell); + if (type != null && info.Types.Contains(type)) + cells.Add(cell); + } + + var ratio = Common.Util.RandomInRange(world.LocalRandom, info.Ratio); + var positions = cells.Shuffle(world.LocalRandom) + .Take(Math.Max(1, cells.Count * ratio / 100)) + .Select(x => world.Map.CenterOfCell(x)); + + foreach (var position in positions) + world.AddFrameEndTask(w => w.Add(new SpriteEffect(position, w, info.Image, info.Sequences.Random(w.LocalRandom), info.Palette))); + + ticks = Common.Util.RandomInRange(world.LocalRandom, info.Interval); + } + } +} diff --git a/mods/ra/rules/world.yaml b/mods/ra/rules/world.yaml index 74188f63d8..bbf1d32919 100644 --- a/mods/ra/rules/world.yaml +++ b/mods/ra/rules/world.yaml @@ -209,6 +209,11 @@ World: AllowedTerrainTypes: Clear, Road MaxDensity: 3 ResourceClaimLayer: + WithResourceAnimation@GEMS: + Types: Gems + Image: twinkle + Sequences: twinkle1, twinkle2, twinkle3 + Palette: effect WarheadDebugOverlay: SpawnMapActors: MapBuildRadius: diff --git a/mods/ra/sequences/misc.yaml b/mods/ra/sequences/misc.yaml index 8d45f35c9e..fbcac2a711 100644 --- a/mods/ra/sequences/misc.yaml +++ b/mods/ra/sequences/misc.yaml @@ -662,3 +662,10 @@ paradirection: X: -6 y: 5 Offset: -15, -15, 0 + +twinkle: + Defaults: + Length: * + twinkle1: twinkle1 + twinkle2: twinkle2 + twinkle3: twinkle3