Files
OpenRA/OpenRA.Mods.Cnc/Traits/World/WithResourceAnimation.cs
2023-01-11 11:58:54 +02:00

107 lines
3.2 KiB
C#

#region Copyright & License Information
/*
* Copyright (c) The OpenRA Developers and Contributors
* 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<IResourceLayerInfo>
{
[FieldLoader.Require]
[Desc("Resource types to animate.")]
public readonly HashSet<string> 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<IResourceRenderer>()
.Single(r => info.Types.Overlaps(r.ResourceTypes));
}
void ITick.Tick(Actor self)
{
if (--ticks > 0)
return;
var cells = new HashSet<CPos>();
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);
}
}
}