Skip to content

Commit c10487d

Browse files
reaperrrabcdefg30
authored andcommitted
Move ClassicFacingFudge support to Mods.Cnc
This moves the TD/RA-specific re-mapping of sprite facings and coordinates to Mods.Cnc.
1 parent bc9b3be commit c10487d

File tree

12 files changed

+237
-51
lines changed

12 files changed

+237
-51
lines changed

OpenRA.Mods.Cnc/FileFormats/HvaReader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public HvaReader(Stream s, string fileName)
4949
Transforms[c + ids[k]] = s.ReadFloat();
5050

5151
Array.Copy(Transforms, 16 * (LimbCount * j + i), testMatrix, 0, 16);
52-
if (Util.MatrixInverse(testMatrix) == null)
52+
if (OpenRA.Graphics.Util.MatrixInverse(testMatrix) == null)
5353
throw new InvalidDataException(
5454
"The transformation matrix for HVA file `{0}` section {1} frame {2} is invalid because it is not invertible!"
5555
.F(fileName, i, j));
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#region Copyright & License Information
2+
/*
3+
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4+
* This file is part of OpenRA, which is free software. It is made
5+
* available to you under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of
7+
* the License, or (at your option) any later version. For more
8+
* information, see COPYING.
9+
*/
10+
#endregion
11+
12+
using System;
13+
using OpenRA.Graphics;
14+
using OpenRA.Mods.Common.Graphics;
15+
16+
namespace OpenRA.Mods.Cnc.Graphics
17+
{
18+
public class ClassicSpriteSequenceLoader : DefaultSpriteSequenceLoader
19+
{
20+
public ClassicSpriteSequenceLoader(ModData modData)
21+
: base(modData) { }
22+
23+
public override ISpriteSequence CreateSequence(ModData modData, TileSet tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info)
24+
{
25+
return new ClassicSpriteSequence(modData, tileSet, cache, this, sequence, animation, info);
26+
}
27+
}
28+
29+
public class ClassicSpriteSequence : DefaultSpriteSequence
30+
{
31+
readonly bool useClassicFacings;
32+
33+
public ClassicSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
34+
: base(modData, tileSet, cache, loader, sequence, animation, info)
35+
{
36+
var d = info.ToDictionary();
37+
useClassicFacings = LoadField(d, "UseClassicFacings", false);
38+
39+
if (useClassicFacings && Facings != 32)
40+
throw new InvalidOperationException(
41+
"{0}: Sequence {1}.{2}: UseClassicFacings is only valid for 32 facings"
42+
.F(info.Nodes[0].Location, sequence, animation));
43+
}
44+
45+
protected override int QuantizeFacing(int facing)
46+
{
47+
return OpenRA.Mods.Cnc.Util.ClassicQuantizeFacing(facing, Facings, useClassicFacings);
48+
}
49+
}
50+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#region Copyright & License Information
2+
/*
3+
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4+
* This file is part of OpenRA, which is free software. It is made
5+
* available to you under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of
7+
* the License, or (at your option) any later version. For more
8+
* information, see COPYING.
9+
*/
10+
#endregion
11+
12+
using System.Collections.Generic;
13+
using System.Linq;
14+
using OpenRA.Graphics;
15+
16+
namespace OpenRA.Mods.Cnc.Graphics
17+
{
18+
public class ClassicTilesetSpecificSpriteSequenceLoader : ClassicSpriteSequenceLoader
19+
{
20+
public readonly string DefaultSpriteExtension = ".shp";
21+
public readonly Dictionary<string, string> TilesetExtensions = new Dictionary<string, string>();
22+
public readonly Dictionary<string, string> TilesetCodes = new Dictionary<string, string>();
23+
24+
public ClassicTilesetSpecificSpriteSequenceLoader(ModData modData)
25+
: base(modData)
26+
{
27+
var metadata = modData.Manifest.Get<SpriteSequenceFormat>().Metadata;
28+
MiniYaml yaml;
29+
if (metadata.TryGetValue("DefaultSpriteExtension", out yaml))
30+
DefaultSpriteExtension = yaml.Value;
31+
32+
if (metadata.TryGetValue("TilesetExtensions", out yaml))
33+
TilesetExtensions = yaml.ToDictionary(kv => kv.Value);
34+
35+
if (metadata.TryGetValue("TilesetCodes", out yaml))
36+
TilesetCodes = yaml.ToDictionary(kv => kv.Value);
37+
}
38+
39+
public override ISpriteSequence CreateSequence(ModData modData, TileSet tileSet, SpriteCache cache, string sequence, string animation, MiniYaml info)
40+
{
41+
return new ClassicTilesetSpecificSpriteSequence(modData, tileSet, cache, this, sequence, animation, info);
42+
}
43+
}
44+
45+
public class ClassicTilesetSpecificSpriteSequence : ClassicSpriteSequence
46+
{
47+
public ClassicTilesetSpecificSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache, ISpriteSequenceLoader loader, string sequence, string animation, MiniYaml info)
48+
: base(modData, tileSet, cache, loader, sequence, animation, info) { }
49+
50+
string ResolveTilesetId(TileSet tileSet, Dictionary<string, MiniYaml> d)
51+
{
52+
var tsId = tileSet.Id;
53+
54+
MiniYaml yaml;
55+
if (d.TryGetValue("TilesetOverrides", out yaml))
56+
{
57+
var tsNode = yaml.Nodes.FirstOrDefault(n => n.Key == tsId);
58+
if (tsNode != null)
59+
tsId = tsNode.Value.Value;
60+
}
61+
62+
return tsId;
63+
}
64+
65+
protected override string GetSpriteSrc(ModData modData, TileSet tileSet, string sequence, string animation, string sprite, Dictionary<string, MiniYaml> d)
66+
{
67+
var loader = (ClassicTilesetSpecificSpriteSequenceLoader)Loader;
68+
69+
var spriteName = sprite ?? sequence;
70+
71+
if (LoadField(d, "UseTilesetCode", false))
72+
{
73+
string code;
74+
if (loader.TilesetCodes.TryGetValue(ResolveTilesetId(tileSet, d), out code))
75+
spriteName = spriteName.Substring(0, 1) + code + spriteName.Substring(2, spriteName.Length - 2);
76+
}
77+
78+
if (LoadField(d, "AddExtension", true))
79+
{
80+
var useTilesetExtension = LoadField(d, "UseTilesetExtension", false);
81+
82+
string tilesetExtension;
83+
if (useTilesetExtension && loader.TilesetExtensions.TryGetValue(ResolveTilesetId(tileSet, d), out tilesetExtension))
84+
return spriteName + tilesetExtension;
85+
86+
return spriteName + loader.DefaultSpriteExtension;
87+
}
88+
89+
return spriteName;
90+
}
91+
}
92+
}

OpenRA.Mods.Cnc/Graphics/Voxel.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@ public float[] TransformationMatrix(uint limb, uint frame)
7474
t[14] *= l.Scale * (l.Bounds[5] - l.Bounds[2]) / l.Size[2];
7575

7676
// Center, flip and scale
77-
t = Util.MatrixMultiply(t, Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2]));
78-
t = Util.MatrixMultiply(Util.ScaleMatrix(l.Scale, -l.Scale, l.Scale), t);
77+
t = OpenRA.Graphics.Util.MatrixMultiply(t, OpenRA.Graphics.Util.TranslationMatrix(l.Bounds[0], l.Bounds[1], l.Bounds[2]));
78+
t = OpenRA.Graphics.Util.MatrixMultiply(OpenRA.Graphics.Util.ScaleMatrix(l.Scale, -l.Scale, l.Scale), t);
7979

8080
return t;
8181
}
@@ -119,7 +119,7 @@ public float[] Bounds(uint frame)
119119
};
120120

121121
// Calculate limb bounding box
122-
var bb = Util.MatrixAABBMultiply(TransformationMatrix(j, frame), b);
122+
var bb = OpenRA.Graphics.Util.MatrixAABBMultiply(TransformationMatrix(j, frame), b);
123123
for (var i = 0; i < 3; i++)
124124
{
125125
ret[i] = Math.Min(ret[i], bb[i]);

OpenRA.Mods.Cnc/Graphics/VoxelLoader.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ Vertex[] GenerateSlicePlane(int su, int sv, Func<int, int, VxlElement> first, Fu
7777
var size = new Size(su, sv);
7878
var s = sheetBuilder.Allocate(size);
7979
var t = sheetBuilder.Allocate(size);
80-
Util.FastCopyIntoChannel(s, colors);
81-
Util.FastCopyIntoChannel(t, normals);
80+
OpenRA.Graphics.Util.FastCopyIntoChannel(s, colors);
81+
OpenRA.Graphics.Util.FastCopyIntoChannel(t, normals);
8282

8383
// s and t are guaranteed to use the same sheet because
8484
// of the custom voxel sheet allocation implementation
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#region Copyright & License Information
2+
/*
3+
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4+
* This file is part of OpenRA, which is free software. It is made
5+
* available to you under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of
7+
* the License, or (at your option) any later version. For more
8+
* information, see COPYING.
9+
*/
10+
#endregion
11+
12+
using OpenRA.Mods.Common.Traits;
13+
14+
namespace OpenRA.Mods.Cnc.Traits
15+
{
16+
[Desc("Fudge the coordinate system angles like the early games (for sprite sequences that use classic facing fudge).")]
17+
public class ClassicFacingBodyOrientationInfo : BodyOrientationInfo
18+
{
19+
public override int QuantizeFacing(int facing, int facings)
20+
{
21+
return OpenRA.Mods.Cnc.Util.ClassicQuantizeFacing(facing, facings, true) * (256 / facings);
22+
}
23+
24+
public override object Create(ActorInitializer init) { return new ClassicFacingBodyOrientation(init, this); }
25+
}
26+
27+
public class ClassicFacingBodyOrientation : BodyOrientation
28+
{
29+
public ClassicFacingBodyOrientation(ActorInitializer init, ClassicFacingBodyOrientationInfo info)
30+
: base(init, info) { }
31+
}
32+
}

OpenRA.Mods.Cnc/Traits/ResourcePurifier.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void INotifyResourceAccepted.OnResourceAccepted(Actor self, Actor refinery, int
6767
if (IsTraitDisabled)
6868
return;
6969

70-
var cash = Util.ApplyPercentageModifiers(amount, modifier);
70+
var cash = OpenRA.Mods.Common.Util.ApplyPercentageModifiers(amount, modifier);
7171
playerResources.GiveCash(cash);
7272

7373
if (Info.ShowTicks && self.Info.HasTraitInfo<IOccupySpaceInfo>())

OpenRA.Mods.Cnc/Traits/TDGunboat.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void Turn()
134134

135135
int MovementSpeed
136136
{
137-
get { return Util.ApplyPercentageModifiers(Info.Speed, speedModifiers); }
137+
get { return OpenRA.Mods.Common.Util.ApplyPercentageModifiers(Info.Speed, speedModifiers); }
138138
}
139139

140140
public Pair<CPos, SubCell>[] OccupiedCells() { return new[] { Pair.New(TopLeft, SubCell.FullCell) }; }

OpenRA.Mods.Cnc/Util.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#region Copyright & License Information
2+
/*
3+
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
4+
* This file is part of OpenRA, which is free software. It is made
5+
* available to you under the terms of the GNU General Public License
6+
* as published by the Free Software Foundation, either version 3 of
7+
* the License, or (at your option) any later version. For more
8+
* information, see COPYING.
9+
*/
10+
#endregion
11+
12+
namespace OpenRA.Mods.Cnc
13+
{
14+
public static class Util
15+
{
16+
public static int ClassicQuantizeFacing(int facing, int numFrames, bool useClassicFacingFudge)
17+
{
18+
if (!useClassicFacingFudge || numFrames != 32)
19+
return OpenRA.Mods.Common.Util.QuantizeFacing(facing, numFrames);
20+
21+
// TD and RA divided the facing artwork into 3 frames from (north|south) to (north|south)-(east|west)
22+
// and then 5 frames from (north|south)-(east|west) to (east|west)
23+
var quadrant = ((facing + 31) & 0xFF) / 64;
24+
if (quadrant == 0 || quadrant == 2)
25+
{
26+
var frame = OpenRA.Mods.Common.Util.QuantizeFacing(facing, 24);
27+
if (frame > 18)
28+
return frame + 6;
29+
if (frame > 4)
30+
return frame + 3;
31+
return frame;
32+
}
33+
else
34+
{
35+
var frame = OpenRA.Mods.Common.Util.QuantizeFacing(facing, 40);
36+
return frame < 20 ? frame - 3 : frame - 8;
37+
}
38+
}
39+
}
40+
}

OpenRA.Mods.Common/Graphics/DefaultSpriteSequence.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,11 @@ public class DefaultSpriteSequence : ISpriteSequence
9595
{
9696
static readonly WDist DefaultShadowSpriteZOffset = new WDist(-5);
9797
protected Sprite[] sprites;
98-
readonly bool reverseFacings, transpose, useClassicFacingFudge;
98+
readonly bool reverseFacings, transpose;
99+
readonly string sequence;
99100

100101
protected readonly ISpriteSequenceLoader Loader;
101102

102-
readonly string sequence;
103103
public string Name { get; private set; }
104104
public int Start { get; private set; }
105105
public int Length { get; private set; }
@@ -156,7 +156,6 @@ public DefaultSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache
156156
Tick = LoadField(d, "Tick", 40);
157157
transpose = LoadField(d, "Transpose", false);
158158
Frames = LoadField<int[]>(d, "Frames", null);
159-
useClassicFacingFudge = LoadField(d, "UseClassicFacingFudge", false);
160159

161160
var flipX = LoadField(d, "FlipX", false);
162161
var flipY = LoadField(d, "FlipY", false);
@@ -168,11 +167,6 @@ public DefaultSpriteSequence(ModData modData, TileSet tileSet, SpriteCache cache
168167
Facings = -Facings;
169168
}
170169

171-
if (useClassicFacingFudge && Facings != 32)
172-
throw new InvalidOperationException(
173-
"{0}: Sequence {1}.{2}: UseClassicFacingFudge is only valid for 32 facings"
174-
.F(info.Nodes[0].Location, sequence, animation));
175-
176170
var offset = LoadField(d, "Offset", float3.Zero);
177171
var blendMode = LoadField(d, "BlendMode", BlendMode.Alpha);
178172

@@ -384,7 +378,7 @@ public Sprite GetShadow(int frame, int facing)
384378

385379
protected virtual Sprite GetSprite(int start, int frame, int facing)
386380
{
387-
var f = Util.QuantizeFacing(facing, Facings, useClassicFacingFudge);
381+
var f = QuantizeFacing(facing);
388382
if (reverseFacings)
389383
f = (Facings - f) % Facings;
390384

@@ -398,5 +392,10 @@ protected virtual Sprite GetSprite(int start, int frame, int facing)
398392

399393
return sprites[j];
400394
}
395+
396+
protected virtual int QuantizeFacing(int facing)
397+
{
398+
return Util.QuantizeFacing(facing, Facings);
399+
}
401400
}
402401
}

OpenRA.Mods.Common/Traits/BodyOrientation.cs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,22 @@ namespace OpenRA.Mods.Common.Traits
1717
{
1818
public class BodyOrientationInfo : ITraitInfo
1919
{
20-
[Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from another trait")]
20+
[Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from another trait.")]
2121
public readonly int QuantizedFacings = -1;
2222

23-
[Desc("Camera pitch for rotation calculations")]
23+
[Desc("Camera pitch for rotation calculations.")]
2424
public readonly WAngle CameraPitch = WAngle.FromDegrees(40);
2525

26-
[Desc("Fudge the coordinate system angles like the early games.")]
26+
[Desc("Fudge the coordinate system angles to simulate non-top-down perspective in mods with square cells.")]
2727
public readonly bool UseClassicPerspectiveFudge = true;
2828

29-
[Desc("Fudge the coordinate system angles like the early games.")]
30-
public readonly bool UseClassicFacingFudge = false;
31-
3229
public WVec LocalToWorld(WVec vec)
3330
{
3431
// Rotate by 90 degrees
3532
if (!UseClassicPerspectiveFudge)
3633
return new WVec(vec.Y, -vec.X, vec.Z);
3734

38-
// RA's 2d perspective doesn't correspond to an orthonormal 3D
35+
// The 2d perspective of older games with square cells doesn't correspond to an orthonormal 3D
3936
// coordinate system, so fudge the y axis to make things look good
4037
return new WVec(vec.Y, -CameraPitch.Sin() * vec.X / 1024, vec.Z);
4138
}
@@ -53,12 +50,12 @@ public WRot QuantizeOrientation(WRot orientation, int facings)
5350
return new WRot(WAngle.Zero, WAngle.Zero, WAngle.FromFacing(facing));
5451
}
5552

56-
public int QuantizeFacing(int facing, int facings)
53+
public virtual int QuantizeFacing(int facing, int facings)
5754
{
58-
return Util.QuantizeFacing(facing, facings, UseClassicFacingFudge) * (256 / facings);
55+
return Util.QuantizeFacing(facing, facings) * (256 / facings);
5956
}
6057

61-
public object Create(ActorInitializer init) { return new BodyOrientation(init, this); }
58+
public virtual object Create(ActorInitializer init) { return new BodyOrientation(init, this); }
6259
}
6360

6461
public class BodyOrientation : ISync

0 commit comments

Comments
 (0)