diff --git a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs index 024d25ae86..97657a15dc 100644 --- a/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs +++ b/OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs @@ -75,7 +75,7 @@ namespace OpenRA.Mods.Common.Graphics { static readonly WDist DefaultShadowSpriteZOffset = new WDist(-5); readonly Sprite[] sprites; - readonly bool reverseFacings, transpose; + readonly bool reverseFacings, transpose, useClassicFacingFudge; protected readonly ISpriteSequenceLoader Loader; @@ -129,6 +129,8 @@ namespace OpenRA.Mods.Common.Graphics Tick = LoadField(d, "Tick", 40); transpose = LoadField(d, "Transpose", false); Frames = LoadField(d, "Frames", null); + useClassicFacingFudge = LoadField(d, "UseClassicFacingFudge", false); + var flipX = LoadField(d, "FlipX", false); var flipY = LoadField(d, "FlipY", false); @@ -139,6 +141,11 @@ namespace OpenRA.Mods.Common.Graphics Facings = -Facings; } + if (useClassicFacingFudge && Facings != 32) + throw new InvalidOperationException( + "{0}: Sequence {1}.{2}: UseClassicFacingFudge is only valid for 32 facings" + .F(info.Nodes[0].Location, sequence, animation)); + var offset = LoadField(d, "Offset", float2.Zero); var blendMode = LoadField(d, "BlendMode", BlendMode.Alpha); @@ -237,8 +244,7 @@ namespace OpenRA.Mods.Common.Graphics protected virtual Sprite GetSprite(int start, int frame, int facing) { - var f = Util.QuantizeFacing(facing, Facings); - + var f = Util.QuantizeFacing(facing, Facings, useClassicFacingFudge); if (reverseFacings) f = (Facings - f) % Facings; diff --git a/OpenRA.Mods.Common/Traits/BodyOrientation.cs b/OpenRA.Mods.Common/Traits/BodyOrientation.cs index 3418f4362f..5a1b3b47f9 100644 --- a/OpenRA.Mods.Common/Traits/BodyOrientation.cs +++ b/OpenRA.Mods.Common/Traits/BodyOrientation.cs @@ -24,6 +24,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Fudge the coordinate system angles like the early games.")] public readonly bool UseClassicPerspectiveFudge = true; + [Desc("Fudge the coordinate system angles like the early games.")] + public readonly bool UseClassicFacingFudge = false; + public WVec LocalToWorld(WVec vec) { // Rotate by 90 degrees @@ -50,7 +53,7 @@ namespace OpenRA.Mods.Common.Traits public int QuantizeFacing(int facing, int facings) { - return Util.QuantizeFacing(facing, facings) * (256 / facings); + return Util.QuantizeFacing(facing, facings, UseClassicFacingFudge) * (256 / facings); } public object Create(ActorInitializer init) { return new BodyOrientation(init, this); } diff --git a/OpenRA.Mods.Common/Util.cs b/OpenRA.Mods.Common/Util.cs index 032772049d..ecc31f5920 100644 --- a/OpenRA.Mods.Common/Util.cs +++ b/OpenRA.Mods.Common/Util.cs @@ -48,6 +48,30 @@ namespace OpenRA.Mods.Common return a / step; } + public static int QuantizeFacing(int facing, int numFrames, bool useClassicFacingFudge) + { + if (!useClassicFacingFudge || numFrames != 32) + return Util.QuantizeFacing(facing, numFrames); + + // TD and RA divided the facing artwork into 3 frames from (north|south) to (north|south)-(east|west) + // and then 5 frames from (north|south)-(east|west) to (east|west) + var quadrant = ((facing + 31) & 0xFF) / 64; + if (quadrant == 0 || quadrant == 2) + { + var frame = Util.QuantizeFacing(facing, 24); + if (frame > 18) + return frame + 6; + if (frame > 4) + return frame + 3; + return frame; + } + else + { + var frame = Util.QuantizeFacing(facing, 40); + return frame < 20 ? frame - 3 : frame - 8; + } + } + public static WPos BetweenCells(World w, CPos from, CPos to) { return WPos.Lerp(w.Map.CenterOfCell(from), w.Map.CenterOfCell(to), 1, 2);