diff --git a/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs b/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs index d0c6945d29..16340441a5 100644 --- a/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs +++ b/OpenRA.Mods.Cnc/Graphics/ClassicTilesetSpecificSpriteSequence.cs @@ -10,6 +10,7 @@ #endregion using System.Collections.Generic; +using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; @@ -33,11 +34,28 @@ namespace OpenRA.Mods.Cnc.Graphics [Desc("Dictionary of : filename to override the Filename key.")] static readonly SpriteSequenceField> TilesetFilenames = new(nameof(TilesetFilenames), null); + [Desc("Dictionary of : to override the FilenamePattern key.")] + static readonly SpriteSequenceField> TilesetFilenamesPattern = new(nameof(TilesetFilenamesPattern), null); + public ClassicTilesetSpecificSpriteSequence(SpriteCache cache, ISpriteSequenceLoader loader, string image, string sequence, MiniYaml data, MiniYaml defaults) : base(cache, loader, image, sequence, data, defaults) { } protected override IEnumerable ParseFilenames(ModData modData, string tileset, int[] frames, MiniYaml data, MiniYaml defaults) { + var tilesetFilenamesPatternNode = data.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key) ?? defaults.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key); + if (tilesetFilenamesPatternNode != null) + { + var tilesetNode = tilesetFilenamesPatternNode.Value.NodeWithKeyOrDefault(tileset); + if (tilesetNode != null) + { + var patternStart = LoadField("Start", 0, tilesetNode.Value); + var patternCount = LoadField("Count", 1, tilesetNode.Value); + + return Enumerable.Range(patternStart, patternCount).Select(i => + new ReservationInfo(tilesetNode.Value.Value.FormatInvariant(i), FirstFrame, FirstFrame, tilesetNode.Location)); + } + } + var node = data.NodeWithKeyOrDefault(TilesetFilenames.Key) ?? defaults.NodeWithKeyOrDefault(TilesetFilenames.Key); if (node != null) { diff --git a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs index 9dc819fb5b..6f99ed794a 100644 --- a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs +++ b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs @@ -120,6 +120,9 @@ namespace OpenRA.Mods.Common.Graphics [Desc("File name of the sprite to use for this sequence.")] protected static readonly SpriteSequenceField Filename = new(nameof(Filename), null); + [Desc("File name pattern to build the sprite to use for this sequence.")] + protected static readonly SpriteSequenceField FilenamePattern = new(nameof(FilenamePattern), null); + [Desc("Frame index to start from.")] protected static readonly SpriteSequenceField Start = new(nameof(Start), 0); @@ -199,6 +202,8 @@ namespace OpenRA.Mods.Common.Graphics protected static readonly SpriteSequenceField DepthSpriteOffset = new(nameof(DepthSpriteOffset), float2.Zero); protected static readonly MiniYaml NoData = new(null); + protected static readonly int[] FirstFrame = { 0 }; + protected readonly ISpriteSequenceLoader Loader; protected string image; @@ -330,10 +335,21 @@ namespace OpenRA.Mods.Common.Graphics protected virtual IEnumerable ParseFilenames(ModData modData, string tileset, int[] frames, MiniYaml data, MiniYaml defaults) { + var filenamePatternNode = data.NodeWithKeyOrDefault(FilenamePattern.Key) ?? defaults.NodeWithKeyOrDefault(FilenamePattern.Key); + if (!string.IsNullOrEmpty(filenamePatternNode?.Value.Value)) + { + var patternStart = LoadField("Start", 0, filenamePatternNode.Value); + var patternCount = LoadField("Count", 1, filenamePatternNode.Value); + + return Enumerable.Range(patternStart, patternCount).Select(i => + new ReservationInfo(filenamePatternNode.Value.Value.FormatInvariant(i), + FirstFrame, FirstFrame, filenamePatternNode.Location)); + } + var filename = LoadField(Filename, data, defaults, out var location); var loadFrames = CalculateFrameIndices(start, length, stride ?? length ?? 0, facings, frames, transpose, reverseFacings, shadowStart); - yield return new ReservationInfo(filename, loadFrames, frames, location); + return new[] { new ReservationInfo(filename, loadFrames, frames, location) }; } protected virtual IEnumerable ParseCombineFilenames(ModData modData, string tileset, int[] frames, MiniYaml data) diff --git a/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs b/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs index bbc2c3d4ad..9395048e72 100644 --- a/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs +++ b/OpenRA.Mods.Common/Graphics/TilesetSpecificSpriteSequence.cs @@ -10,6 +10,7 @@ #endregion using System.Collections.Generic; +using System.Linq; using OpenRA.Graphics; namespace OpenRA.Mods.Common.Graphics @@ -31,11 +32,28 @@ namespace OpenRA.Mods.Common.Graphics [Desc("Dictionary of : filename to override the Filename key.")] static readonly SpriteSequenceField> TilesetFilenames = new(nameof(TilesetFilenames), null); + [Desc("Dictionary of : to override the FilenamePattern key.")] + static readonly SpriteSequenceField> TilesetFilenamesPattern = new(nameof(TilesetFilenamesPattern), null); + public TilesetSpecificSpriteSequence(SpriteCache cache, ISpriteSequenceLoader loader, string image, string sequence, MiniYaml data, MiniYaml defaults) : base(cache, loader, image, sequence, data, defaults) { } protected override IEnumerable ParseFilenames(ModData modData, string tileset, int[] frames, MiniYaml data, MiniYaml defaults) { + var tilesetFilenamesPatternNode = data.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key) ?? defaults.NodeWithKeyOrDefault(TilesetFilenamesPattern.Key); + if (tilesetFilenamesPatternNode != null) + { + var tilesetNode = tilesetFilenamesPatternNode.Value.NodeWithKeyOrDefault(tileset); + if (tilesetNode != null) + { + var patternStart = LoadField("Start", 0, tilesetNode.Value); + var patternCount = LoadField("Count", 1, tilesetNode.Value); + + return Enumerable.Range(patternStart, patternCount).Select(i => + new ReservationInfo(tilesetNode.Value.Value.FormatInvariant(i), FirstFrame, FirstFrame, tilesetNode.Location)); + } + } + var node = data.NodeWithKeyOrDefault(TilesetFilenames.Key) ?? defaults.NodeWithKeyOrDefault(TilesetFilenames.Key); if (node != null) {