Unhardcoded SpriteSequence properties
To prepare them for documentation generation. Also added descriptions to SpriteSequence implementations and their properties. Also made a few code style fixes.
This commit is contained in:
@@ -26,24 +26,28 @@ namespace OpenRA.Mods.Cnc.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Desc("A sprite sequence that has the oddities that come with first-generation Westwood titles.")]
|
||||||
public class ClassicSpriteSequence : DefaultSpriteSequence
|
public class ClassicSpriteSequence : DefaultSpriteSequence
|
||||||
{
|
{
|
||||||
readonly bool useClassicFacings;
|
// This needs to be a public property for the documentation generation to work.
|
||||||
|
[Desc("Incorporate a compensation factor due to the distortion caused by 3D-Studio " +
|
||||||
|
"when it tried to render 45% angles which was used by Westwood Studios at that time.")]
|
||||||
|
public bool UseClassicFacings { get; }
|
||||||
|
|
||||||
public ClassicSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
|
public ClassicSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
|
||||||
: base(modData, tileSet, cache, loader, sequence, animation, info)
|
: base(modData, tileSet, cache, loader, sequence, animation, info)
|
||||||
{
|
{
|
||||||
var d = info.ToDictionary();
|
var d = info.ToDictionary();
|
||||||
useClassicFacings = LoadField(d, "UseClassicFacings", false);
|
UseClassicFacings = LoadField(d, nameof(UseClassicFacings), UseClassicFacings);
|
||||||
|
|
||||||
if (useClassicFacings && Facings != 32)
|
if (UseClassicFacings && Facings != 32)
|
||||||
throw new InvalidOperationException(
|
throw new InvalidOperationException(
|
||||||
$"{info.Nodes[0].Location}: Sequence {sequence}.{animation}: UseClassicFacings is only valid for 32 facings");
|
$"{info.Nodes[0].Location}: Sequence {sequence}.{animation}: UseClassicFacings is only valid for 32 facings");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override int GetFacingFrameOffset(WAngle facing)
|
protected override int GetFacingFrameOffset(WAngle facing)
|
||||||
{
|
{
|
||||||
return useClassicFacings ? Util.ClassicIndexFacing(facing, Facings) : Common.Util.IndexFacing(facing, Facings);
|
return UseClassicFacings ? Util.ClassicIndexFacing(facing, Facings) : Common.Util.IndexFacing(facing, Facings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,14 +41,32 @@ namespace OpenRA.Mods.Cnc.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Desc("A sprite sequence that can have tileset-specific variants and has the oddities " +
|
||||||
|
"that come with first-generation Westwood titles.")]
|
||||||
public class ClassicTilesetSpecificSpriteSequence : ClassicSpriteSequence
|
public class ClassicTilesetSpecificSpriteSequence : ClassicSpriteSequence
|
||||||
{
|
{
|
||||||
|
// These need to be public properties for the documentation generation to work.
|
||||||
|
[Desc("Dictionary of <string: string> with tileset name to override -> tileset name to use instead.")]
|
||||||
|
public static Dictionary<string, string> TilesetOverrides => null;
|
||||||
|
|
||||||
|
[Desc("Use `TilesetCodes` as defined in `mod.yaml` to add a letter as a second character " +
|
||||||
|
"into the sprite filename like the Westwood 2.5D titles did for tileset-specific variants.")]
|
||||||
|
public static bool UseTilesetCode => false;
|
||||||
|
|
||||||
|
[Desc("Append a tileset-specific extension to the file name " +
|
||||||
|
"- either as defined in `mod.yaml`'s `TilesetExtensions` (if `UseTilesetExtension` is used) " +
|
||||||
|
"or the default hardcoded one for this sequence type (.shp).")]
|
||||||
|
public static bool AddExtension => true;
|
||||||
|
|
||||||
|
[Desc("Whether `mod.yaml`'s `TilesetExtensions` should be used with the sequence's file name.")]
|
||||||
|
public static bool UseTilesetExtension { get; private set; }
|
||||||
|
|
||||||
public ClassicTilesetSpecificSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
|
public ClassicTilesetSpecificSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
|
||||||
: base(modData, tileSet, cache, loader, sequence, animation, info) { }
|
: base(modData, tileSet, cache, loader, sequence, animation, info) { }
|
||||||
|
|
||||||
string ResolveTilesetId(string tileSet, Dictionary<string, MiniYaml> d)
|
static string ResolveTilesetId(string tileSet, Dictionary<string, MiniYaml> d)
|
||||||
{
|
{
|
||||||
if (d.TryGetValue("TilesetOverrides", out var yaml))
|
if (d.TryGetValue(nameof(TilesetOverrides), out var yaml))
|
||||||
{
|
{
|
||||||
var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tileSet);
|
var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tileSet);
|
||||||
if (tsNode != null)
|
if (tsNode != null)
|
||||||
@@ -64,17 +82,16 @@ namespace OpenRA.Mods.Cnc.Graphics
|
|||||||
|
|
||||||
var spriteName = sprite ?? sequence;
|
var spriteName = sprite ?? sequence;
|
||||||
|
|
||||||
if (LoadField(d, "UseTilesetCode", false))
|
if (LoadField(d, nameof(UseTilesetCode), UseTilesetCode))
|
||||||
{
|
{
|
||||||
if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out var code))
|
if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out var code))
|
||||||
spriteName = spriteName.Substring(0, 1) + code + spriteName.Substring(2, spriteName.Length - 2);
|
spriteName = spriteName.Substring(0, 1) + code + spriteName.Substring(2, spriteName.Length - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LoadField(d, "AddExtension", true))
|
if (LoadField(d, nameof(AddExtension), AddExtension))
|
||||||
{
|
{
|
||||||
var useTilesetExtension = LoadField(d, "UseTilesetExtension", false);
|
UseTilesetExtension = LoadField(d, nameof(UseTilesetExtension), UseTilesetExtension);
|
||||||
|
if (UseTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out var tilesetExtension))
|
||||||
if (useTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out var tilesetExtension))
|
|
||||||
return spriteName + tilesetExtension;
|
return spriteName + tilesetExtension;
|
||||||
|
|
||||||
return spriteName + loader.DefaultSpriteExtension;
|
return spriteName + loader.DefaultSpriteExtension;
|
||||||
|
|||||||
@@ -122,32 +122,100 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
float ISpriteSequence.GetAlpha(int frame) { throw exception; }
|
float ISpriteSequence.GetAlpha(int frame) { throw exception; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Desc("Generic sprite sequence implementation, mostly unencumbered with game- or artwork-specific logic.")]
|
||||||
public class DefaultSpriteSequence : ISpriteSequence
|
public class DefaultSpriteSequence : ISpriteSequence
|
||||||
{
|
{
|
||||||
static readonly WDist DefaultShadowSpriteZOffset = new WDist(-5);
|
static readonly WDist DefaultShadowSpriteZOffset = new WDist(-5);
|
||||||
protected Sprite[] sprites;
|
protected Sprite[] sprites;
|
||||||
readonly bool reverseFacings, transpose;
|
readonly bool reverseFacings, transpose;
|
||||||
readonly string sequence;
|
readonly string sequence;
|
||||||
readonly float[] alpha;
|
|
||||||
|
|
||||||
protected readonly ISpriteSequenceLoader Loader;
|
protected readonly ISpriteSequenceLoader Loader;
|
||||||
|
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
public int Start { get; private set; }
|
|
||||||
public int Length { get; private set; }
|
|
||||||
public int Stride { get; private set; }
|
|
||||||
public int Facings { get; }
|
|
||||||
public int Tick { get; }
|
|
||||||
public int ZOffset { get; }
|
|
||||||
public float ZRamp { get; }
|
|
||||||
public int ShadowStart { get; }
|
|
||||||
public int ShadowZOffset { get; }
|
|
||||||
public int[] Frames { get; private set; }
|
|
||||||
public Rectangle Bounds { get; private set; }
|
|
||||||
public bool IgnoreWorldTint { get; }
|
|
||||||
public float Scale { get; }
|
|
||||||
|
|
||||||
public readonly uint[] EmbeddedPalette;
|
[Desc("Frame index to start from.")]
|
||||||
|
public int Start { get; private set; }
|
||||||
|
|
||||||
|
[Desc("Number of frames to use. Does not have to be the total amount the sprite sheet has.")]
|
||||||
|
public int Length { get; private set; } = 1;
|
||||||
|
|
||||||
|
[Desc("Multiplier for the number of facings.")]
|
||||||
|
public int Stride { get; private set; }
|
||||||
|
|
||||||
|
[Desc("The amount of directions the unit faces. Use negative values to rotate counter-clockwise.")]
|
||||||
|
public int Facings { get; } = 1;
|
||||||
|
|
||||||
|
[Desc("Time (in milliseconds) to wait until playing the next frame in the animation.")]
|
||||||
|
public int Tick { get; } = 40;
|
||||||
|
|
||||||
|
[Desc("Value controlling the Z-order. A higher values means rendering on top of other sprites at the same position. " +
|
||||||
|
"Use power of 2 values to avoid glitches.")]
|
||||||
|
public int ZOffset { get; }
|
||||||
|
|
||||||
|
[Desc("")]
|
||||||
|
public float ZRamp { get; }
|
||||||
|
|
||||||
|
[Desc("If the shadow is not part of the sprite, but baked into the same sprite sheet at a fixed offset, " +
|
||||||
|
"set this to the frame index where it starts.")]
|
||||||
|
public int ShadowStart { get; } = -1;
|
||||||
|
|
||||||
|
[Desc("Set Z-Offset for the separate shadow. Used by the later Westwood 2.5D titles. Defined in WDist units!")]
|
||||||
|
public int ShadowZOffset { get; }
|
||||||
|
|
||||||
|
[Desc("The individual frames to play instead of going through them sequentially from the `Start`.")]
|
||||||
|
public int[] Frames { get; private set; }
|
||||||
|
|
||||||
|
public Rectangle Bounds { get; }
|
||||||
|
|
||||||
|
[Desc("Don't apply terrain lighting or colored overlays.")]
|
||||||
|
public bool IgnoreWorldTint { get; }
|
||||||
|
|
||||||
|
[Desc("")]
|
||||||
|
public float Scale { get; } = 1f;
|
||||||
|
|
||||||
|
// These need to be public properties for the documentation generation to work.
|
||||||
|
[Desc("Play the sprite sequence back and forth.")]
|
||||||
|
public static bool Reverses => false;
|
||||||
|
|
||||||
|
[Desc("Support a frame order where each animation step is split per each direction.")]
|
||||||
|
public static bool Transpose => false;
|
||||||
|
|
||||||
|
[Desc("Mirror on the X axis.")]
|
||||||
|
public bool FlipX { get; }
|
||||||
|
|
||||||
|
[Desc("Mirror on the Y axis.")]
|
||||||
|
public bool FlipY { get; }
|
||||||
|
|
||||||
|
[Desc("Change the position in-game on X, Y, Z.")]
|
||||||
|
public float3 Offset { get; } = float3.Zero;
|
||||||
|
|
||||||
|
[Desc("Apply an OpenGL/Photoshop inspired blend mode.")]
|
||||||
|
public BlendMode BlendMode { get; } = BlendMode.Alpha;
|
||||||
|
|
||||||
|
[Desc("Allows to append multiple sequence definitions which are indented below this node " +
|
||||||
|
"like when offsets differ per frame or a sequence is spread across individual files.")]
|
||||||
|
public static object Combine => null;
|
||||||
|
|
||||||
|
[Desc("Sets transparency - use one value to set for all frames or provide a value for each frame.")]
|
||||||
|
public float[] Alpha { get; }
|
||||||
|
|
||||||
|
[Desc("Plays a fade out effect.")]
|
||||||
|
public static bool AlphaFade => false;
|
||||||
|
|
||||||
|
[Desc("Name of the file containing the depth data sprite.")]
|
||||||
|
public string DepthSprite { get; }
|
||||||
|
|
||||||
|
[Desc("Frame index containing the depth data.")]
|
||||||
|
public static int DepthSpriteFrame => 0;
|
||||||
|
|
||||||
|
[Desc("")]
|
||||||
|
public static float2 DepthSpriteOffset => float2.Zero;
|
||||||
|
|
||||||
|
[Desc("Use the palette embedded in the defined sprite. (Note: The name given here is actually irrelevant)")]
|
||||||
|
public static string EmbeddedPalette => null;
|
||||||
|
|
||||||
|
public readonly uint[] EmbeddedPaletteData;
|
||||||
|
|
||||||
protected virtual string GetSpriteSrc(ModData modData, string tileSet, string sequence, string animation, string sprite, Dictionary<string, MiniYaml> d)
|
protected virtual string GetSpriteSrc(ModData modData, string tileSet, string sequence, string animation, string sprite, Dictionary<string, MiniYaml> d)
|
||||||
{
|
{
|
||||||
@@ -181,39 +249,39 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Start = LoadField(d, "Start", 0);
|
Start = LoadField(d, nameof(Start), 0);
|
||||||
ShadowStart = LoadField(d, "ShadowStart", -1);
|
ShadowStart = LoadField(d, nameof(ShadowStart), ShadowStart);
|
||||||
ShadowZOffset = LoadField(d, "ShadowZOffset", DefaultShadowSpriteZOffset).Length;
|
ShadowZOffset = LoadField(d, nameof(ShadowZOffset), DefaultShadowSpriteZOffset).Length;
|
||||||
ZOffset = LoadField(d, "ZOffset", WDist.Zero).Length;
|
ZOffset = LoadField(d, nameof(ZOffset), WDist.Zero).Length;
|
||||||
ZRamp = LoadField(d, "ZRamp", 0f);
|
ZRamp = LoadField(d, nameof(ZRamp), 0f);
|
||||||
Tick = LoadField(d, "Tick", 40);
|
Tick = LoadField(d, nameof(Tick), Tick);
|
||||||
transpose = LoadField(d, "Transpose", false);
|
transpose = LoadField(d, nameof(Transpose), false);
|
||||||
Frames = LoadField<int[]>(d, "Frames", null);
|
Frames = LoadField<int[]>(d, nameof(Frames), null);
|
||||||
IgnoreWorldTint = LoadField(d, "IgnoreWorldTint", false);
|
IgnoreWorldTint = LoadField(d, nameof(IgnoreWorldTint), false);
|
||||||
Scale = LoadField(d, "Scale", 1f);
|
Scale = LoadField(d, nameof(Scale), Scale);
|
||||||
|
|
||||||
var flipX = LoadField(d, "FlipX", false);
|
FlipX = LoadField(d, nameof(FlipX), false);
|
||||||
var flipY = LoadField(d, "FlipY", false);
|
FlipY = LoadField(d, nameof(FlipY), false);
|
||||||
|
|
||||||
Facings = LoadField(d, "Facings", 1);
|
Facings = LoadField(d, nameof(Facings), Facings);
|
||||||
if (Facings < 0)
|
if (Facings < 0)
|
||||||
{
|
{
|
||||||
reverseFacings = true;
|
reverseFacings = true;
|
||||||
Facings = -Facings;
|
Facings = -Facings;
|
||||||
}
|
}
|
||||||
|
|
||||||
var offset = LoadField(d, "Offset", float3.Zero);
|
Offset = LoadField(d, nameof(Offset), Offset);
|
||||||
var blendMode = LoadField(d, "BlendMode", BlendMode.Alpha);
|
BlendMode = LoadField(d, nameof(BlendMode), BlendMode);
|
||||||
|
|
||||||
Func<int, IEnumerable<int>> getUsedFrames = frameCount =>
|
Func<int, IEnumerable<int>> getUsedFrames = frameCount =>
|
||||||
{
|
{
|
||||||
if (d.TryGetValue("Length", out var length) && length.Value == "*")
|
if (d.TryGetValue(nameof(Length), out var length) && length.Value == "*")
|
||||||
Length = Frames != null ? Frames.Length : frameCount - Start;
|
Length = Frames?.Length ?? frameCount - Start;
|
||||||
else
|
else
|
||||||
Length = LoadField(d, "Length", 1);
|
Length = LoadField(d, nameof(Length), Length);
|
||||||
|
|
||||||
// Plays the animation forwards, and then in reverse
|
// Plays the animation forwards, and then in reverse
|
||||||
if (LoadField(d, "Reverses", false))
|
if (LoadField(d, nameof(Reverses), false))
|
||||||
{
|
{
|
||||||
var frames = Frames != null ? Frames.Skip(Start).Take(Length).ToArray() : Exts.MakeArray(Length, i => Start + i);
|
var frames = Frames != null ? Frames.Skip(Start).Take(Length).ToArray() : Exts.MakeArray(Length, i => Start + i);
|
||||||
Frames = frames.Concat(frames.Skip(1).Take(Length - 2).Reverse()).ToArray();
|
Frames = frames.Concat(frames.Skip(1).Take(Length - 2).Reverse()).ToArray();
|
||||||
@@ -221,7 +289,7 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
Start = 0;
|
Start = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stride = LoadField(d, "Stride", Length);
|
Stride = LoadField(d, nameof(Stride), Length);
|
||||||
|
|
||||||
if (Length > Stride)
|
if (Length > Stride)
|
||||||
throw new YamlException($"Sequence {sequence}.{animation}: Length must be <= stride");
|
throw new YamlException($"Sequence {sequence}.{animation}: Length must be <= stride");
|
||||||
@@ -263,7 +331,7 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
return usedFrames;
|
return usedFrames;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (d.TryGetValue("Combine", out var combine))
|
if (d.TryGetValue(nameof(Combine), out var combine))
|
||||||
{
|
{
|
||||||
var combined = Enumerable.Empty<Sprite>();
|
var combined = Enumerable.Empty<Sprite>();
|
||||||
foreach (var sub in combine.Nodes)
|
foreach (var sub in combine.Nodes)
|
||||||
@@ -271,19 +339,19 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
var sd = sub.Value.ToDictionary();
|
var sd = sub.Value.ToDictionary();
|
||||||
|
|
||||||
// Allow per-sprite offset, flipping, start, and length
|
// Allow per-sprite offset, flipping, start, and length
|
||||||
var subStart = LoadField(sd, "Start", 0);
|
var subStart = LoadField(sd, nameof(Start), 0);
|
||||||
var subOffset = LoadField(sd, "Offset", float3.Zero);
|
var subOffset = LoadField(sd, nameof(Offset), Offset);
|
||||||
var subFlipX = LoadField(sd, "FlipX", false);
|
var subFlipX = LoadField(sd, nameof(FlipX), false);
|
||||||
var subFlipY = LoadField(sd, "FlipY", false);
|
var subFlipY = LoadField(sd, nameof(FlipY), false);
|
||||||
var subFrames = LoadField<int[]>(sd, "Frames", null);
|
var subFrames = LoadField<int[]>(sd, nameof(Frames), null);
|
||||||
var subLength = 0;
|
var subLength = 0;
|
||||||
|
|
||||||
Func<int, IEnumerable<int>> subGetUsedFrames = subFrameCount =>
|
Func<int, IEnumerable<int>> subGetUsedFrames = subFrameCount =>
|
||||||
{
|
{
|
||||||
if (sd.TryGetValue("Length", out var subLengthYaml) && subLengthYaml.Value == "*")
|
if (sd.TryGetValue(nameof(Length), out var subLengthYaml) && subLengthYaml.Value == "*")
|
||||||
subLength = subFrames != null ? subFrames.Length : subFrameCount - subStart;
|
subLength = subFrames != null ? subFrames.Length : subFrameCount - subStart;
|
||||||
else
|
else
|
||||||
subLength = LoadField(sd, "Length", 1);
|
subLength = LoadField(sd, nameof(Length), Length);
|
||||||
|
|
||||||
return subFrames != null ? subFrames.Skip(subStart).Take(subLength) : Enumerable.Range(subStart, subLength);
|
return subFrames != null ? subFrames.Skip(subStart).Take(subLength) : Enumerable.Range(subStart, subLength);
|
||||||
};
|
};
|
||||||
@@ -295,11 +363,11 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
return null;
|
return null;
|
||||||
|
|
||||||
var bounds = FlipRectangle(s.Bounds, subFlipX, subFlipY);
|
var bounds = FlipRectangle(s.Bounds, subFlipX, subFlipY);
|
||||||
var dx = subOffset.X + offset.X + (subFlipX ? -s.Offset.X : s.Offset.X);
|
var dx = subOffset.X + Offset.X + (subFlipX ? -s.Offset.X : s.Offset.X);
|
||||||
var dy = subOffset.Y + offset.Y + (subFlipY ? -s.Offset.Y : s.Offset.Y);
|
var dy = subOffset.Y + Offset.Y + (subFlipY ? -s.Offset.Y : s.Offset.Y);
|
||||||
var dz = subOffset.Z + offset.Z + s.Offset.Z + ZRamp * dy;
|
var dz = subOffset.Z + Offset.Z + s.Offset.Z + ZRamp * dy;
|
||||||
|
|
||||||
return new Sprite(s.Sheet, bounds, ZRamp, new float3(dx, dy, dz), s.Channel, blendMode);
|
return new Sprite(s.Sheet, bounds, ZRamp, new float3(dx, dy, dz), s.Channel, BlendMode);
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
var frames = subFrames != null ? subFrames.Skip(subStart).Take(subLength).ToArray() : Exts.MakeArray(subLength, i => subStart + i);
|
var frames = subFrames != null ? subFrames.Skip(subStart).Take(subLength).ToArray() : Exts.MakeArray(subLength, i => subStart + i);
|
||||||
@@ -319,39 +387,39 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
if (s == null)
|
if (s == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var bounds = FlipRectangle(s.Bounds, flipX, flipY);
|
var bounds = FlipRectangle(s.Bounds, FlipX, FlipY);
|
||||||
var dx = offset.X + (flipX ? -s.Offset.X : s.Offset.X);
|
var dx = Offset.X + (FlipX ? -s.Offset.X : s.Offset.X);
|
||||||
var dy = offset.Y + (flipY ? -s.Offset.Y : s.Offset.Y);
|
var dy = Offset.Y + (FlipY ? -s.Offset.Y : s.Offset.Y);
|
||||||
var dz = offset.Z + s.Offset.Z + ZRamp * dy;
|
var dz = Offset.Z + s.Offset.Z + ZRamp * dy;
|
||||||
|
|
||||||
return new Sprite(s.Sheet, bounds, ZRamp, new float3(dx, dy, dz), s.Channel, blendMode);
|
return new Sprite(s.Sheet, bounds, ZRamp, new float3(dx, dy, dz), s.Channel, BlendMode);
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
alpha = LoadField(d, "Alpha", (float[])null);
|
Alpha = LoadField(d, nameof(Alpha), (float[])null);
|
||||||
if (alpha != null)
|
if (Alpha != null)
|
||||||
{
|
{
|
||||||
if (alpha.Length == 1)
|
if (Alpha.Length == 1)
|
||||||
alpha = Exts.MakeArray(Length, _ => alpha[0]);
|
Alpha = Exts.MakeArray(Length, _ => Alpha[0]);
|
||||||
else if (alpha.Length != Length)
|
else if (Alpha.Length != Length)
|
||||||
throw new YamlException($"Sequence {sequence}.{animation} must define either 1 or {Length} Alpha values.");
|
throw new YamlException($"Sequence {sequence}.{animation} must define either 1 or {Length} Alpha values.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LoadField(d, "AlphaFade", false))
|
if (LoadField(d, nameof(AlphaFade), false))
|
||||||
{
|
{
|
||||||
if (alpha != null)
|
if (Alpha != null)
|
||||||
throw new YamlException($"Sequence {sequence}.{animation} cannot define both AlphaFade and Alpha.");
|
throw new YamlException($"Sequence {sequence}.{animation} cannot define both AlphaFade and Alpha.");
|
||||||
|
|
||||||
alpha = Exts.MakeArray(Length, i => float2.Lerp(1f, 0f, i / (Length - 1f)));
|
Alpha = Exts.MakeArray(Length, i => float2.Lerp(1f, 0f, i / (Length - 1f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
var depthSprite = LoadField<string>(d, "DepthSprite", null);
|
DepthSprite = LoadField<string>(d, nameof(DepthSprite), null);
|
||||||
if (!string.IsNullOrEmpty(depthSprite))
|
if (!string.IsNullOrEmpty(DepthSprite))
|
||||||
{
|
{
|
||||||
var depthSpriteFrame = LoadField(d, "DepthSpriteFrame", 0);
|
var depthSpriteFrame = LoadField(d, nameof(DepthSpriteFrame), 0);
|
||||||
var depthOffset = LoadField(d, "DepthSpriteOffset", float2.Zero);
|
var depthOffset = LoadField(d, nameof(DepthSpriteOffset), DepthSpriteOffset);
|
||||||
Func<int, IEnumerable<int>> getDepthFrame = _ => new int[] { depthSpriteFrame };
|
IEnumerable<int> GetDepthFrame(int _) => new[] { depthSpriteFrame };
|
||||||
var ds = cache[depthSprite, getDepthFrame][depthSpriteFrame];
|
var ds = cache[DepthSprite, GetDepthFrame][depthSpriteFrame];
|
||||||
|
|
||||||
sprites = sprites.Select(s =>
|
sprites = sprites.Select(s =>
|
||||||
{
|
{
|
||||||
@@ -368,15 +436,15 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
}).ToArray();
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var exportPalette = LoadField<string>(d, "EmbeddedPalette", null);
|
var exportPalette = LoadField<string>(d, nameof(EmbeddedPalette), null);
|
||||||
if (exportPalette != null)
|
if (exportPalette != null)
|
||||||
{
|
{
|
||||||
var src = GetSpriteSrc(modData, tileSet, sequence, animation, info.Value, d);
|
var src = GetSpriteSrc(modData, tileSet, sequence, animation, info.Value, d);
|
||||||
|
|
||||||
var metadata = cache.FrameMetadata(src);
|
var metadata = cache.FrameMetadata(src);
|
||||||
var i = Frames != null ? Frames[0] : Start;
|
var i = Frames != null ? Frames[0] : Start;
|
||||||
var palettes = metadata != null ? metadata.GetOrDefault<EmbeddedSpritePalette>() : null;
|
var palettes = metadata?.GetOrDefault<EmbeddedSpritePalette>();
|
||||||
if (palettes == null || !palettes.TryGetPaletteForFrame(i, out EmbeddedPalette))
|
if (palettes == null || !palettes.TryGetPaletteForFrame(i, out EmbeddedPaletteData))
|
||||||
throw new YamlException($"Cannot export palettes from {src}: frame {i} does not define an embedded palette");
|
throw new YamlException($"Cannot export palettes from {src}: frame {i} does not define an embedded palette");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -449,7 +517,7 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
|
|
||||||
public virtual float GetAlpha(int frame)
|
public virtual float GetAlpha(int frame)
|
||||||
{
|
{
|
||||||
return alpha?[frame] ?? 1f;
|
return Alpha?[frame] ?? 1f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,14 +41,31 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Desc("A sprite sequence that can have tileset-specific variants.")]
|
||||||
public class TilesetSpecificSpriteSequence : DefaultSpriteSequence
|
public class TilesetSpecificSpriteSequence : DefaultSpriteSequence
|
||||||
{
|
{
|
||||||
|
// These need to be public properties for the documentation generation to work.
|
||||||
|
[Desc("Dictionary of <string: string> with tileset name to override -> tileset name to use instead.")]
|
||||||
|
public static Dictionary<string, string> TilesetOverrides => null;
|
||||||
|
|
||||||
|
[Desc("Use `TilesetCodes` as defined in `mod.yaml` to add a letter as a second character " +
|
||||||
|
"into the sprite filename like the Westwood 2.5D titles did for tileset-specific variants.")]
|
||||||
|
public static bool UseTilesetCode => false;
|
||||||
|
|
||||||
|
[Desc("Append a tileset-specific extension to the file name " +
|
||||||
|
"- either as defined in `mod.yaml`'s `TilesetExtensions` (if `UseTilesetExtension` is used) " +
|
||||||
|
"or the default hardcoded one for this sequence type (.shp).")]
|
||||||
|
public static bool AddExtension => true;
|
||||||
|
|
||||||
|
[Desc("Whether `mod.yaml`'s `TilesetExtensions` should be used with the sequence's file name.")]
|
||||||
|
public static bool UseTilesetExtension { get; private set; }
|
||||||
|
|
||||||
public TilesetSpecificSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
|
public TilesetSpecificSpriteSequence(ModData modData, string tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
|
||||||
: base(modData, tileSet, cache, loader, sequence, animation, info) { }
|
: base(modData, tileSet, cache, loader, sequence, animation, info) { }
|
||||||
|
|
||||||
string ResolveTilesetId(string tileSet, Dictionary<string, MiniYaml> d)
|
static string ResolveTilesetId(string tileSet, Dictionary<string, MiniYaml> d)
|
||||||
{
|
{
|
||||||
if (d.TryGetValue("TilesetOverrides", out var yaml))
|
if (d.TryGetValue(nameof(TilesetOverrides), out var yaml))
|
||||||
{
|
{
|
||||||
var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tileSet);
|
var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tileSet);
|
||||||
if (tsNode != null)
|
if (tsNode != null)
|
||||||
@@ -64,17 +81,16 @@ namespace OpenRA.Mods.Common.Graphics
|
|||||||
|
|
||||||
var spriteName = sprite ?? sequence;
|
var spriteName = sprite ?? sequence;
|
||||||
|
|
||||||
if (LoadField(d, "UseTilesetCode", false))
|
if (LoadField(d, nameof(UseTilesetCode), UseTilesetCode))
|
||||||
{
|
{
|
||||||
if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out var code))
|
if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out var code))
|
||||||
spriteName = spriteName.Substring(0, 1) + code + spriteName.Substring(2, spriteName.Length - 2);
|
spriteName = spriteName.Substring(0, 1) + code + spriteName.Substring(2, spriteName.Length - 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LoadField(d, "AddExtension", true))
|
if (LoadField(d, nameof(AddExtension), AddExtension))
|
||||||
{
|
{
|
||||||
var useTilesetExtension = LoadField(d, "UseTilesetExtension", false);
|
UseTilesetExtension = LoadField(d, nameof(UseTilesetExtension), UseTilesetExtension);
|
||||||
|
if (UseTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out var tilesetExtension))
|
||||||
if (useTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out var tilesetExtension))
|
|
||||||
return spriteName + tilesetExtension;
|
return spriteName + tilesetExtension;
|
||||||
|
|
||||||
return spriteName + loader.DefaultSpriteExtension;
|
return spriteName + loader.DefaultSpriteExtension;
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
ImmutablePalette IProvidesCursorPaletteInfo.ReadPalette(IReadOnlyFileSystem fileSystem)
|
ImmutablePalette IProvidesCursorPaletteInfo.ReadPalette(IReadOnlyFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
var sequence = (DefaultSpriteSequence)Game.ModData.DefaultSequences.Values.First().GetSequence(Image, Sequence);
|
var sequence = (DefaultSpriteSequence)Game.ModData.DefaultSequences.Values.First().GetSequence(Image, Sequence);
|
||||||
return new ImmutablePalette(sequence.EmbeddedPalette);
|
return new ImmutablePalette(sequence.EmbeddedPaletteData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ namespace OpenRA.Mods.Common.Traits
|
|||||||
public void LoadPalettes(WorldRenderer wr)
|
public void LoadPalettes(WorldRenderer wr)
|
||||||
{
|
{
|
||||||
var sequence = (DefaultSpriteSequence)wr.World.Map.Rules.Sequences.GetSequence(info.Image, info.Sequence);
|
var sequence = (DefaultSpriteSequence)wr.World.Map.Rules.Sequences.GetSequence(info.Image, info.Sequence);
|
||||||
wr.AddPalette(info.Name, new ImmutablePalette(sequence.EmbeddedPalette), info.AllowModifiers);
|
wr.AddPalette(info.Name, new ImmutablePalette(sequence.EmbeddedPaletteData), info.AllowModifiers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> PaletteNames { get { yield return info.Name; } }
|
public IEnumerable<string> PaletteNames { get { yield return info.Name; } }
|
||||||
|
|||||||
Reference in New Issue
Block a user