Compare commits

..

1 Commits

Author SHA1 Message Date
teinarss
857da21b0f Add support for dotnet core for Windows 2020-12-23 18:41:27 +01:00
127 changed files with 880 additions and 954 deletions

View File

@@ -39,11 +39,6 @@ jobs:
- name: Clone Repository
uses: actions/checkout@v2
- name: Install .NET 5
uses: actions/setup-dotnet@v1
with:
dotnet-version: '5.0.x'
- name: Prepare Environment
run: echo "GIT_TAG=${GITHUB_REF#refs/tags/}" >> ${GITHUB_ENV}

20
.vscode/launch.json vendored
View File

@@ -11,8 +11,9 @@
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/bin/OpenRA.exe",
"args": ["Game.Mod=cnc", "Engine.EngineDir=.."],
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=cnc"],
"preLaunchTask": "build",
},
{
@@ -25,8 +26,9 @@
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/bin/OpenRA.exe",
"args": ["Game.Mod=ra", "Engine.EngineDir=.."],
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=ra"],
"preLaunchTask": "build",
},
{
@@ -39,8 +41,9 @@
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/bin/OpenRA.exe",
"args": ["Game.Mod=d2k", "Engine.EngineDir=.."],
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=d2k"],
"preLaunchTask": "build",
},
{
@@ -53,8 +56,9 @@
"type": "mono"
},
"request": "launch",
"program": "${workspaceRoot}/bin/OpenRA.exe",
"args": ["Game.Mod=ts", "Engine.EngineDir=.."],
"program": "${workspaceRoot}/OpenRA.Game.exe",
"cwd": "${workspaceRoot}",
"args": ["Game.Mod=ts"],
"preLaunchTask": "build",
},
]

View File

@@ -25,6 +25,18 @@
# make help
#
############################## TOOLCHAIN ###############################
#
# List of .NET assemblies that we can guarantee exist
WHITELISTED_OPENRA_ASSEMBLIES = OpenRA.dll OpenRA.Utility.dll OpenRA.Server.dll OpenRA.Platforms.Default.dll OpenRA.Game.dll OpenRA.Mods.Common.dll OpenRA.Mods.Cnc.dll OpenRA.Mods.D2k.dll
# These are explicitly shipped alongside our core files by the packaging script
WHITELISTED_THIRDPARTY_ASSEMBLIES = ICSharpCode.SharpZipLib.dll FuzzyLogicLibrary.dll Eluant.dll BeaconLib.dll Open.Nat.dll SDL2-CS.dll OpenAL-CS.Core.dll DiscordRPC.dll Newtonsoft.Json.dll
# These are shipped in our custom minimal mono runtime and also available in the full system-installed .NET/mono stack
# This list *must* be kept in sync with the files packaged by the AppImageSupport and OpenRALauncherOSX repositories
WHITELISTED_CORE_ASSEMBLIES = mscorlib.dll System.dll System.Configuration.dll System.Core.dll System.Numerics.dll System.Security.dll System.Xml.dll Mono.Security.dll netstandard.dll Microsoft.Win32.Registry.dll System.Security.AccessControl.dll System.Security.Principal.Windows.dll System.Xml.Linq.dll System.Runtime.Serialization.dll
######################### UTILITIES/SETTINGS ###########################
#
# Install locations for local installs and downstream packaging
@@ -88,6 +100,9 @@ check:
@echo "Compiling in debug mode..."
@$(MSBUILD) -t:build -restore -p:Configuration=Debug -p:TargetPlatform=$(TARGETPLATFORM) -p:Mono=true -p:DefineConstants="MONO"
@echo
@echo "Checking runtime assemblies..."
@$(OPENRA_UTILITY) all --check-runtime-assemblies $(WHITELISTED_OPENRA_ASSEMBLIES) $(WHITELISTED_THIRDPARTY_ASSEMBLIES) $(WHITELISTED_CORE_ASSEMBLIES)
@echo
@echo "Checking for explicit interface violations..."
@$(OPENRA_UTILITY) all --check-explicit-interfaces
@echo

View File

@@ -74,7 +74,7 @@ namespace OpenRA.Activities
// drop valid activities queued after it. Walk the queue until we find a valid activity or
// (more likely) run out of activities.
while (first != null && first.State == ActivityState.Done)
first = first.nextActivity;
first = first.NextActivity;
return first;
}
@@ -120,8 +120,7 @@ namespace OpenRA.Activities
lastRun = Tick(self);
// Avoid a single tick delay if the childactivity was just queued.
var ca = ChildActivity;
if (ca != null && ca.State == ActivityState.Queued)
if (ChildActivity != null && ChildActivity.State == ActivityState.Queued)
{
if (ChildHasPriority)
lastRun = TickChild(self) && finishing;
@@ -207,18 +206,18 @@ namespace OpenRA.Activities
public void Queue(Activity activity)
{
var it = this;
while (it.nextActivity != null)
it = it.nextActivity;
it.nextActivity = activity;
if (NextActivity != null)
NextActivity.Queue(activity);
else
NextActivity = activity;
}
public void QueueChild(Activity activity)
{
if (childActivity != null)
childActivity.Queue(activity);
if (ChildActivity != null)
ChildActivity.Queue(activity);
else
childActivity = activity;
ChildActivity = activity;
}
/// <summary>
@@ -270,21 +269,15 @@ namespace OpenRA.Activities
public IEnumerable<T> ActivitiesImplementing<T>(bool includeChildren = true) where T : IActivityInterface
{
// Skips Done child and next activities
if (includeChildren)
{
var ca = ChildActivity;
if (ca != null)
foreach (var a in ca.ActivitiesImplementing<T>())
yield return a;
}
if (includeChildren && ChildActivity != null)
foreach (var a in ChildActivity.ActivitiesImplementing<T>())
yield return a;
if (this is T)
yield return (T)(object)this;
var na = NextActivity;
if (na != null)
foreach (var a in na.ActivitiesImplementing<T>())
if (NextActivity != null)
foreach (var a in NextActivity.ActivitiesImplementing<T>())
yield return a;
}
}

View File

@@ -66,11 +66,17 @@ namespace OpenRA
static readonly ConcurrentCache<Type, FieldLoadInfo[]> TypeLoadInfo =
new ConcurrentCache<Type, FieldLoadInfo[]>(BuildTypeLoadInfo);
static readonly ConcurrentCache<MemberInfo, bool> MemberHasTranslateAttribute =
new ConcurrentCache<MemberInfo, bool>(member => member.HasAttribute<TranslateAttribute>());
static readonly ConcurrentCache<string, BooleanExpression> BooleanExpressionCache =
new ConcurrentCache<string, BooleanExpression>(expression => new BooleanExpression(expression));
static readonly ConcurrentCache<string, IntegerExpression> IntegerExpressionCache =
new ConcurrentCache<string, IntegerExpression>(expression => new IntegerExpression(expression));
static readonly object TranslationsLock = new object();
static Dictionary<string, string> translations;
public static void Load(object self, MiniYaml my)
{
var loadInfo = TypeLoadInfo[self.GetType()];
@@ -207,7 +213,11 @@ namespace OpenRA
return InvalidValueAction(value, fieldType, fieldName);
}
else if (fieldType == typeof(string))
{
if (field != null && MemberHasTranslateAttribute[field] && value != null)
return Regex.Replace(value, "@[^@]+@", m => Translate(m.Value.Substring(1, m.Value.Length - 2)), RegexOptions.Compiled);
return value;
}
else if (fieldType == typeof(Color))
{
if (value != null && Color.TryParse(value, out var color))
@@ -684,8 +694,34 @@ namespace OpenRA
return null;
}
}
public static string Translate(string key)
{
if (string.IsNullOrEmpty(key))
return key;
lock (TranslationsLock)
{
if (translations == null)
return key;
if (!translations.TryGetValue(key, out var value))
return key;
return value;
}
}
public static void SetTranslations(IDictionary<string, string> translations)
{
lock (TranslationsLock)
FieldLoader.translations = new Dictionary<string, string>(translations);
}
}
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public sealed class TranslateAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Field)]
public sealed class FieldFromYamlKeyAttribute : FieldLoader.SerializeAttribute
{

View File

@@ -17,7 +17,6 @@ using System.Net;
using System.Text;
using ICSharpCode.SharpZipLib.Checksum;
using ICSharpCode.SharpZipLib.Zip.Compression.Streams;
using OpenRA.Graphics;
using OpenRA.Primitives;
namespace OpenRA.FileFormats
@@ -26,15 +25,12 @@ namespace OpenRA.FileFormats
{
static readonly byte[] Signature = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a };
public int Width { get; private set; }
public int Height { get; private set; }
public Color[] Palette { get; private set; }
public byte[] Data { get; private set; }
public SpriteFrameType Type { get; private set; }
public int Width { get; set; }
public int Height { get; set; }
public Color[] Palette { get; set; }
public byte[] Data { get; set; }
public Dictionary<string, string> EmbeddedData = new Dictionary<string, string>();
public int PixelStride { get { return Type == SpriteFrameType.Indexed8 ? 1 : Type == SpriteFrameType.Rgb24 ? 3 : 4; } }
public Png(Stream s)
{
if (!Verify(s))
@@ -42,8 +38,9 @@ namespace OpenRA.FileFormats
s.Position += 8;
var headerParsed = false;
var isPaletted = false;
var is24Bit = false;
var data = new List<byte>();
Type = SpriteFrameType.Rgba32;
while (true)
{
@@ -68,12 +65,14 @@ namespace OpenRA.FileFormats
var bitDepth = ms.ReadUInt8();
var colorType = (PngColorType)ms.ReadByte();
if (IsPaletted(bitDepth, colorType))
Type = SpriteFrameType.Indexed8;
else if (colorType == PngColorType.Color)
Type = SpriteFrameType.Rgb24;
isPaletted = IsPaletted(bitDepth, colorType);
is24Bit = colorType == PngColorType.Color;
Data = new byte[Width * Height * PixelStride];
var dataLength = Width * Height;
if (!isPaletted)
dataLength *= 4;
Data = new byte[dataLength];
var compression = ms.ReadByte();
/*var filter = */ms.ReadByte();
@@ -134,28 +133,39 @@ namespace OpenRA.FileFormats
{
using (var ds = new InflaterInputStream(ns))
{
var pxStride = PixelStride;
var rowStride = Width * pxStride;
var pxStride = isPaletted ? 1 : is24Bit ? 3 : 4;
var srcStride = Width * pxStride;
var destStride = Width * (isPaletted ? 1 : 4);
var prevLine = new byte[rowStride];
var prevLine = new byte[srcStride];
for (var y = 0; y < Height; y++)
{
var filter = (PngFilter)ds.ReadByte();
var line = ds.ReadBytes(rowStride);
var line = ds.ReadBytes(srcStride);
for (var i = 0; i < rowStride; i++)
for (var i = 0; i < srcStride; i++)
line[i] = i < pxStride
? UnapplyFilter(filter, line[i], 0, prevLine[i], 0)
: UnapplyFilter(filter, line[i], line[i - pxStride], prevLine[i], prevLine[i - pxStride]);
Array.Copy(line, 0, Data, y * rowStride, rowStride);
if (is24Bit)
{
// Fold alpha channel into RGB data
for (var i = 0; i < line.Length / 3; i++)
{
Array.Copy(line, 3 * i, Data, y * destStride + 4 * i, 3);
Data[y * destStride + 4 * i + 3] = 255;
}
}
else
Array.Copy(line, 0, Data, y * destStride, line.Length);
prevLine = line;
}
}
}
if (Type == SpriteFrameType.Indexed8 && Palette == null)
if (isPaletted && Palette == null)
throw new InvalidDataException("Non-Palette indexed PNG are not supported.");
return;
@@ -165,7 +175,7 @@ namespace OpenRA.FileFormats
}
}
public Png(byte[] data, SpriteFrameType type, int width, int height, Color[] palette = null,
public Png(byte[] data, int width, int height, Color[] palette = null,
Dictionary<string, string> embeddedData = null)
{
var expectLength = width * height;
@@ -175,46 +185,11 @@ namespace OpenRA.FileFormats
if (data.Length != expectLength)
throw new InvalidDataException("Input data does not match expected length");
Type = type;
Width = width;
Height = height;
switch (type)
{
case SpriteFrameType.Indexed8:
case SpriteFrameType.Rgba32:
case SpriteFrameType.Rgb24:
{
// Data is already in a compatible format
Data = data;
if (type == SpriteFrameType.Indexed8)
Palette = palette;
break;
}
case SpriteFrameType.Bgra32:
case SpriteFrameType.Bgr24:
{
// Convert to big endian
Data = new byte[data.Length];
var stride = PixelStride;
for (var i = 0; i < width * height; i++)
{
Data[stride * i] = data[stride * i + 2];
Data[stride * i + 1] = data[stride * i + 1];
Data[stride * i + 2] = data[stride * i + 0];
if (type == SpriteFrameType.Bgra32)
Data[stride * i + 3] = data[stride * i + 3];
}
break;
}
default:
throw new InvalidDataException("Unhandled SpriteFrameType {0}".F(type));
}
Palette = palette;
Data = data;
if (embeddedData != null)
EmbeddedData = embeddedData;
@@ -299,8 +274,9 @@ namespace OpenRA.FileFormats
header.Write(IPAddress.HostToNetworkOrder(Height));
header.WriteByte(8); // Bit depth
var colorType = Type == SpriteFrameType.Indexed8 ? PngColorType.Indexed | PngColorType.Color :
Type == SpriteFrameType.Rgb24 ? PngColorType.Color : PngColorType.Color | PngColorType.Alpha;
var colorType = Palette != null
? PngColorType.Indexed | PngColorType.Color
: PngColorType.Color | PngColorType.Alpha;
header.WriteByte((byte)colorType);
header.WriteByte(0); // Compression
@@ -310,7 +286,7 @@ namespace OpenRA.FileFormats
WritePngChunk(output, "IHDR", header);
}
var alphaPalette = false;
bool alphaPalette = false;
if (Palette != null)
{
using (var palette = new MemoryStream())
@@ -342,12 +318,12 @@ namespace OpenRA.FileFormats
{
using (var compressed = new DeflaterOutputStream(data))
{
var rowStride = Width * PixelStride;
var stride = Width * (Palette != null ? 1 : 4);
for (var y = 0; y < Height; y++)
{
// Write uncompressed scanlines for simplicity
compressed.WriteByte(0);
compressed.Write(Data, y * rowStride, rowStride);
compressed.Write(Data, y * stride, stride);
}
compressed.Flush();

View File

@@ -484,8 +484,6 @@ namespace OpenRA
ChromeMetrics.TryGet("ChatMessageColor", out chatMessageColor);
ChromeMetrics.TryGet("SystemMessageColor", out systemMessageColor);
if (!ChromeMetrics.TryGet("SystemMessageLabel", out systemMessageLabel))
systemMessageLabel = "Battlefield Control";
ModData.LoadScreen.StartGame(args);
}
@@ -555,8 +553,6 @@ namespace OpenRA
static volatile ActionQueue delayedActions = new ActionQueue();
static Color systemMessageColor = Color.White;
static Color chatMessageColor = Color.White;
static string systemMessageLabel;
public static void RunAfterTick(Action a) { delayedActions.Add(a, RunTime); }
public static void RunAfterDelay(int delayMilliseconds, Action a) { delayedActions.Add(a, RunTime + delayMilliseconds); }
@@ -888,7 +884,7 @@ namespace OpenRA
public static void AddSystemLine(string text)
{
AddSystemLine(systemMessageLabel, text);
AddSystemLine("Battlefield Control", text);
}
public static void AddSystemLine(string name, string text)

View File

@@ -15,6 +15,7 @@ namespace OpenRA
{
public class GameSpeed
{
[Translate]
public readonly string Name = "Default";
public readonly int Timestep = 40;
public readonly int OrderLatency = 3;

View File

@@ -69,16 +69,9 @@ namespace OpenRA.Graphics
// Hotspot is specified relative to the center of the frame
var hotspot = f.Offset.ToInt2() - kv.Value.Hotspot - new int2(f.Size) / 2;
// Resolve indexed data to real colours
var data = f.Data;
var type = f.Type;
if (type == SpriteFrameType.Indexed8)
{
data = ConvertIndexedToBgra(kv.Key, f, palette);
type = SpriteFrameType.Bgra32;
}
c.Sprites[c.Length++] = sheetBuilder.Add(data, type, f.Size, 0, hotspot);
// SheetBuilder expects data in BGRA
var data = FrameToBGRA(kv.Key, f, palette);
c.Sprites[c.Length++] = sheetBuilder.Add(data, f.Size, 0, hotspot);
// Bounds relative to the hotspot
c.Bounds = Rectangle.Union(c.Bounds, new Rectangle(hotspot, f.Size));
@@ -224,27 +217,33 @@ namespace OpenRA.Graphics
Update();
}
public static byte[] ConvertIndexedToBgra(string name, ISpriteFrame frame, ImmutablePalette palette)
public static byte[] FrameToBGRA(string name, ISpriteFrame frame, ImmutablePalette palette)
{
if (frame.Type != SpriteFrameType.Indexed8)
throw new ArgumentException("ConvertIndexedToBgra requires input frames to be indexed.", nameof(frame));
// Data is already in BGRA format
if (frame.Type == SpriteFrameType.BGRA)
return frame.Data;
// Cursors may be either native BGRA or Indexed.
// Indexed sprites are converted to BGRA using the referenced palette.
// All palettes must be explicitly referenced, even if they are embedded in the sprite.
if (palette == null)
if (frame.Type == SpriteFrameType.Indexed && palette == null)
throw new InvalidOperationException("Cursor sequence `{0}` attempted to load an indexed sprite but does not define Palette".F(name));
var width = frame.Size.Width;
var height = frame.Size.Height;
var data = new byte[4 * width * height];
unsafe
for (var j = 0; j < height; j++)
{
// Cast the data to an int array so we can copy the src data directly
fixed (byte* bd = &data[0])
for (var i = 0; i < width; i++)
{
var rgba = (uint*)bd;
for (var j = 0; j < height; j++)
for (var i = 0; i < width; i++)
rgba[j * width + i] = palette[frame.Data[j * width + i]];
var rgba = palette[frame.Data[j * width + i]];
var k = 4 * (j * width + i);
// Convert RGBA to BGRA
data[k] = (byte)(rgba >> 16);
data[k + 1] = (byte)(rgba >> 8);
data[k + 2] = (byte)(rgba >> 0);
data[k + 3] = (byte)(rgba >> 24);
}
}

View File

@@ -45,7 +45,6 @@ namespace OpenRA.Graphics
public interface IModelCache : IDisposable
{
IModel GetModel(string model);
IModel GetModelSequence(string model, string sequence);
bool HasModelSequence(string model, string sequence);
IVertexBuffer<Vertex> VertexBuffer { get; }
@@ -67,11 +66,6 @@ namespace OpenRA.Graphics
public void Dispose() { }
public IModel GetModel(string model)
{
throw new NotImplementedException();
}
public IModel GetModelSequence(string model, string sequence)
{
throw new NotImplementedException();

View File

@@ -79,17 +79,21 @@ namespace OpenRA.Graphics
public Png AsPng()
{
if (Type == SheetType.Indexed)
throw new InvalidOperationException("AsPng() cannot be called on Indexed sheets.");
var data = GetData();
return new Png(GetData(), SpriteFrameType.Bgra32, Size.Width, Size.Height);
// Convert BGRA to RGBA
for (var i = 0; i < Size.Width * Size.Height; i++)
{
var temp = data[i * 4];
data[i * 4] = data[i * 4 + 2];
data[i * 4 + 2] = temp;
}
return new Png(data, Size.Width, Size.Height);
}
public Png AsPng(TextureChannel channel, IPalette pal)
{
if (Type != SheetType.Indexed)
throw new InvalidOperationException("AsPng(TextureChannel, IPalette) can only be called on Indexed sheets.");
var d = GetData();
var plane = new byte[Size.Width * Size.Height];
var dataStride = 4 * Size.Width;
@@ -103,7 +107,7 @@ namespace OpenRA.Graphics
for (var i = 0; i < Palette.Size; i++)
palColors[i] = pal.GetColor(i);
return new Png(plane, SpriteFrameType.Bgra32, Size.Width, Size.Height, palColors);
return new Png(plane, Size.Width, Size.Height, palColors);
}
public void CreateBuffer()

View File

@@ -52,15 +52,8 @@ namespace OpenRA.Graphics
{
switch (t)
{
case SpriteFrameType.Indexed8:
return SheetType.Indexed;
// Util.FastCopyIntoChannel will automatically convert these to BGRA
case SpriteFrameType.Bgra32:
case SpriteFrameType.Bgr24:
case SpriteFrameType.Rgba32:
case SpriteFrameType.Rgb24:
return SheetType.BGRA;
case SpriteFrameType.Indexed: return SheetType.Indexed;
case SpriteFrameType.BGRA: return SheetType.BGRA;
default: throw new NotImplementedException("Unknown SpriteFrameType {0}".F(t));
}
}
@@ -81,16 +74,16 @@ namespace OpenRA.Graphics
this.margin = margin;
}
public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Type, frame.Size, 0, frame.Offset); }
public Sprite Add(byte[] src, SpriteFrameType type, Size size) { return Add(src, type, size, 0, float3.Zero); }
public Sprite Add(byte[] src, SpriteFrameType type, Size size, float zRamp, in float3 spriteOffset)
public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, 0, frame.Offset); }
public Sprite Add(byte[] src, Size size) { return Add(src, size, 0, float3.Zero); }
public Sprite Add(byte[] src, Size size, float zRamp, in float3 spriteOffset)
{
// Don't bother allocating empty sprites
if (size.Width == 0 || size.Height == 0)
return new Sprite(current, Rectangle.Empty, 0, spriteOffset, channel, BlendMode.Alpha);
var rect = Allocate(size, zRamp, spriteOffset);
Util.FastCopyIntoChannel(rect, src, type);
Util.FastCopyIntoChannel(rect, src);
current.CommitBufferedData();
return rect;
}
@@ -103,6 +96,15 @@ namespace OpenRA.Graphics
return rect;
}
public Sprite Add(Size size, byte paletteIndex)
{
var data = new byte[size.Width * size.Height];
for (var i = 0; i < data.Length; i++)
data[i] = paletteIndex;
return Add(data, size);
}
TextureChannel? NextChannel(TextureChannel t)
{
var nextChannel = (int)t + (int)Type;

View File

@@ -18,29 +18,7 @@ using OpenRA.Primitives;
namespace OpenRA.Graphics
{
/// <summary>
/// Describes the format of the pixel data in a ISpriteFrame.
/// Note that the channel order is defined for little-endian bytes, so BGRA corresponds
/// to a 32bit ARGB value, such as that returned by Color.ToArgb()!
/// </summary>
public enum SpriteFrameType
{
// 8 bit index into an external palette
Indexed8,
// 32 bit color such as returned by Color.ToArgb() or the bmp file format
// (remember that little-endian systems place the little bits in the first byte!)
Bgra32,
// Like BGRA, but without an alpha channel
Bgr24,
// 32 bit color in big-endian format, like png
Rgba32,
// Like RGBA, but without an alpha channel
Rgb24
}
public enum SpriteFrameType { Indexed, BGRA }
public interface ISpriteLoader
{
@@ -69,7 +47,7 @@ namespace OpenRA.Graphics
public class SpriteCache
{
public readonly Cache<SheetType, SheetBuilder> SheetBuilders;
public readonly Cache<SpriteFrameType, SheetBuilder> SheetBuilders;
readonly ISpriteLoader[] loaders;
readonly IReadOnlyFileSystem fileSystem;
@@ -79,7 +57,7 @@ namespace OpenRA.Graphics
public SpriteCache(IReadOnlyFileSystem fileSystem, ISpriteLoader[] loaders)
{
SheetBuilders = new Cache<SheetType, SheetBuilder>(t => new SheetBuilder(t));
SheetBuilders = new Cache<SpriteFrameType, SheetBuilder>(t => new SheetBuilder(SheetBuilder.FrameTypeToSheetType(t)));
this.fileSystem = fileSystem;
this.loaders = loaders;
@@ -125,7 +103,7 @@ namespace OpenRA.Graphics
{
if (unloaded[i] != null)
{
sprite[i] = SheetBuilders[SheetBuilder.FrameTypeToSheetType(unloaded[i].Type)].Add(unloaded[i]);
sprite[i] = SheetBuilders[unloaded[i].Type].Add(unloaded[i]);
unloaded[i] = null;
}
}

View File

@@ -107,13 +107,12 @@ namespace OpenRA.Graphics
throw new YamlException("Sprite type mismatch. Terrain sprites must all be either Indexed or RGBA.");
var s = sheetBuilder.Allocate(f.Size, zRamp, offset);
Util.FastCopyIntoChannel(s, f.Data, f.Type);
Util.FastCopyIntoChannel(s, f.Data);
if (tileset.EnableDepth)
{
var ss = sheetBuilder.Allocate(f.Size, zRamp, offset);
var depthFrame = allFrames[j + frameCount];
Util.FastCopyIntoChannel(ss, depthFrame.Data, depthFrame.Type);
Util.FastCopyIntoChannel(ss, allFrames[j + frameCount].Data);
// s and ss are guaranteed to use the same sheet
// because of the custom terrain sheet allocation
@@ -137,10 +136,7 @@ namespace OpenRA.Graphics
}
// 1x1px transparent tile
if (sheetBuilder.Type == SheetType.BGRA)
missingTile = sheetBuilder.Add(new byte[4], SpriteFrameType.Bgra32, new Size(1, 1));
else
missingTile = sheetBuilder.Add(new byte[1], SpriteFrameType.Indexed8, new Size(1, 1));
missingTile = sheetBuilder.Add(new byte[sheetBuilder.Type == SheetType.BGRA ? 4 : 1], new Size(1, 1));
Sheet.ReleaseBuffer();
}

View File

@@ -62,7 +62,7 @@ namespace OpenRA.Graphics
vertices[nv + 5] = new Vertex(a, r.Left, r.Top, sl, st, paletteTextureIndex, fAttribC, tint);
}
public static void FastCopyIntoChannel(Sprite dest, byte[] src, SpriteFrameType srcType)
public static void FastCopyIntoChannel(Sprite dest, byte[] src)
{
var destData = dest.Sheet.GetData();
var width = dest.Bounds.Width;
@@ -85,34 +85,12 @@ namespace OpenRA.Graphics
{
for (var i = 0; i < width; i++)
{
byte r, g, b, a;
switch (srcType)
{
case SpriteFrameType.Bgra32:
case SpriteFrameType.Bgr24:
{
b = src[k++];
g = src[k++];
r = src[k++];
a = srcType == SpriteFrameType.Bgra32 ? src[k++] : (byte)255;
break;
}
case SpriteFrameType.Rgba32:
case SpriteFrameType.Rgb24:
{
r = src[k++];
g = src[k++];
b = src[k++];
a = srcType == SpriteFrameType.Rgba32 ? src[k++] : (byte)255;
break;
}
default:
throw new InvalidOperationException("Unknown SpriteFrameType {0}".F(srcType));
}
var r = src[k++];
var g = src[k++];
var b = src[k++];
var a = src[k++];
var cc = Color.FromArgb(a, r, g, b);
data[(y + j) * destStride + x + i] = PremultiplyAlpha(cc).ToArgb();
}
}
@@ -161,29 +139,16 @@ namespace OpenRA.Graphics
for (var i = 0; i < width; i++)
{
Color cc;
switch (src.Type)
if (src.Palette == null)
{
case SpriteFrameType.Indexed8:
{
cc = src.Palette[src.Data[k++]];
break;
}
case SpriteFrameType.Rgba32:
case SpriteFrameType.Rgb24:
{
var r = src.Data[k++];
var g = src.Data[k++];
var b = src.Data[k++];
var a = src.Type == SpriteFrameType.Rgba32 ? src.Data[k++] : (byte)255;
cc = Color.FromArgb(a, r, g, b);
break;
}
// Pngs don't support BGR[A], so no need to include them here
default:
throw new InvalidOperationException("Unknown SpriteFrameType {0}".F(src.Type));
var r = src.Data[k++];
var g = src.Data[k++];
var b = src.Data[k++];
var a = src.Data[k++];
cc = Color.FromArgb(a, r, g, b);
}
else
cc = src.Palette[src.Data[k++]];
data[(y + j) * destStride + x + i] = PremultiplyAlpha(cc).ToArgb();
}

View File

@@ -60,7 +60,7 @@ namespace OpenRA
public readonly string[]
Rules, ServerTraits,
Sequences, ModelSequences, Cursors, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Notifications, Music, TileSets,
Weapons, Voices, Notifications, Music, Translations, TileSets,
ChromeMetrics, MapCompatibility, Missions, Hotkeys;
public readonly IReadOnlyDictionary<string, string> Packages;
@@ -128,6 +128,7 @@ namespace OpenRA
Voices = YamlList(yaml, "Voices");
Notifications = YamlList(yaml, "Notifications");
Music = YamlList(yaml, "Music");
Translations = YamlList(yaml, "Translations");
TileSets = YamlList(yaml, "TileSets");
ChromeMetrics = YamlList(yaml, "ChromeMetrics");
Missions = YamlList(yaml, "Missions");

View File

@@ -17,7 +17,6 @@ using System.Reflection;
using System.Text;
using OpenRA.FileFormats;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Support;
using OpenRA.Traits;
@@ -174,6 +173,7 @@ namespace OpenRA
new MapField("Voices", "VoiceDefinitions", required: false),
new MapField("Music", "MusicDefinitions", required: false),
new MapField("Notifications", "NotificationDefinitions", required: false),
new MapField("Translations", "TranslationDefinitions", required: false)
};
// Format versions
@@ -204,6 +204,7 @@ namespace OpenRA
public readonly MiniYaml VoiceDefinitions;
public readonly MiniYaml MusicDefinitions;
public readonly MiniYaml NotificationDefinitions;
public readonly MiniYaml TranslationDefinitions;
public readonly Dictionary<CPos, TerrainTile> ReplacedInvalidTerrainTiles = new Dictionary<CPos, TerrainTile>();
@@ -779,7 +780,7 @@ namespace OpenRA
}
}
var png = new Png(minimapData, SpriteFrameType.Bgra32, bitmapWidth, height);
var png = new Png(minimapData, bitmapWidth, height);
return png.Save();
}

View File

@@ -138,6 +138,42 @@ namespace OpenRA
public IEnumerable<string> Languages { get; private set; }
void LoadTranslations(Map map)
{
var selectedTranslations = new Dictionary<string, string>();
var defaultTranslations = new Dictionary<string, string>();
if (!Manifest.Translations.Any())
{
Languages = new string[0];
return;
}
var yaml = MiniYaml.Load(map, Manifest.Translations, map.TranslationDefinitions);
Languages = yaml.Select(t => t.Key).ToArray();
foreach (var y in yaml)
{
if (y.Key == Game.Settings.Graphics.Language)
selectedTranslations = y.Value.ToDictionary(my => my.Value ?? "");
else if (y.Key == Game.Settings.Graphics.DefaultLanguage)
defaultTranslations = y.Value.ToDictionary(my => my.Value ?? "");
}
var translations = new Dictionary<string, string>();
foreach (var tkv in defaultTranslations.Concat(selectedTranslations))
{
if (translations.ContainsKey(tkv.Key))
continue;
if (selectedTranslations.ContainsKey(tkv.Key))
translations.Add(tkv.Key, selectedTranslations[tkv.Key]);
else
translations.Add(tkv.Key, tkv.Value);
}
FieldLoader.SetTranslations(translations);
}
public Map PrepareMap(string uid)
{
LoadScreen?.Display();
@@ -149,6 +185,8 @@ namespace OpenRA
using (new Support.PerfTimer("Map"))
map = new Map(this, MapCache[uid].Package);
LoadTranslations(map);
// Reinitialize all our assets
InitializeLoaders(map);

View File

@@ -42,8 +42,14 @@ namespace OpenRA
var resolvedPath = FileSystem.FileSystem.ResolveAssemblyPath(path, manifest, mods);
if (resolvedPath == null)
throw new FileNotFoundException("Assembly `{0}` not found.".F(path));
#if !MONO
var loader = new AssemblyLoader(resolvedPath);
var platformType = loader.LoadDefaultAssembly();
assemblyList.Add(platformType);
#else
LoadAssembly(assemblyList, resolvedPath);
#endif
}
AppDomain.CurrentDomain.AssemblyResolve += ResolveAssembly;
@@ -60,7 +66,6 @@ namespace OpenRA
if (!ResolvedAssemblies.TryGetValue(hash, out var assembly))
{
#if MONO
assembly = Assembly.LoadFile(resolvedPath);
ResolvedAssemblies.Add(hash, assembly);
@@ -75,11 +80,6 @@ namespace OpenRA
LoadAssembly(assemblyList, depedencyPath);
}
}
#else
var loader = new AssemblyLoader(resolvedPath);
assembly = loader.LoadDefaultAssembly();
ResolvedAssemblies.Add(hash, assembly);
#endif
}
assemblyList.Add(assembly);

View File

@@ -34,7 +34,7 @@
<ItemGroup>
<PackageReference Include="OpenRA-Eluant" Version="1.0.17" />
<PackageReference Include="OpenRA-Open.NAT" Version="1.0.0" />
<PackageReference Include="SharpZipLib" Version="1.3.1" />
<PackageReference Include="SharpZipLib" Version="1.2.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" />
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
<AdditionalFiles Include="../stylecop.json" />

View File

@@ -431,15 +431,24 @@ namespace OpenRA
var srcWidth = screenSprite.Sheet.Size.Width;
var destWidth = screenSprite.Bounds.Width;
var destHeight = -screenSprite.Bounds.Height;
var channelOrder = new[] { 2, 1, 0, 3 };
ThreadPool.QueueUserWorkItem(_ =>
{
// Extract the screen rect from the (larger) backing surface
// Convert BGRA to RGBA
var dest = new byte[4 * destWidth * destHeight];
for (var y = 0; y < destHeight; y++)
Array.Copy(src, 4 * y * srcWidth, dest, 4 * y * destWidth, 4 * destWidth);
{
for (var x = 0; x < destWidth; x++)
{
var destOffset = 4 * (y * destWidth + x);
var srcOffset = 4 * (y * srcWidth + x);
for (var i = 0; i < 4; i++)
dest[destOffset + i] = src[srcOffset + channelOrder[i]];
}
}
new Png(dest, SpriteFrameType.Bgra32, destWidth, destHeight).Save(path);
new Png(dest, destWidth, destHeight).Save(path);
});
}

View File

@@ -660,28 +660,16 @@ namespace OpenRA.Server
}
}
byte[] CreateFrame(int client, int frame, byte[] data)
void DispatchOrdersToClient(Connection c, int client, int frame, byte[] data)
{
using (var ms = new MemoryStream(data.Length + 12))
try
{
var ms = new MemoryStream(data.Length + 12);
ms.WriteArray(BitConverter.GetBytes(data.Length + 4));
ms.WriteArray(BitConverter.GetBytes(client));
ms.WriteArray(BitConverter.GetBytes(frame));
ms.WriteArray(data);
return ms.GetBuffer();
}
}
void DispatchOrdersToClient(Connection c, int client, int frame, byte[] data)
{
DispatchFrameToClient(c, client, CreateFrame(client, frame, data));
}
void DispatchFrameToClient(Connection c, int client, byte[] frameData)
{
try
{
SendData(c.Socket, frameData);
SendData(c.Socket, ms.ToArray());
}
catch (Exception e)
{
@@ -789,9 +777,8 @@ namespace OpenRA.Server
public void DispatchOrdersToClients(Connection conn, int frame, byte[] data)
{
var from = conn != null ? conn.PlayerIndex : 0;
var frameData = CreateFrame(from, frame, data);
foreach (var c in Conns.Except(conn).ToList())
DispatchFrameToClient(c, from, frameData);
DispatchOrdersToClient(c, from, frame, data);
if (recorder != null)
{

View File

@@ -190,6 +190,9 @@ namespace OpenRA
public int BatchSize = 8192;
public int SheetSize = 2048;
public string Language = "english";
public string DefaultLanguage = "english";
}
public class SoundSettings

View File

@@ -9,8 +9,7 @@
*/
#endregion
// Not used/usable on Mono. Only used for Dotnet Core.
// Based on https://github.com/natemcmaster/DotNetCorePlugins and used under the terms of the Apache 2.0 license
// Not used/usable on Mono. Only used for Dotnet Core. Based on https://github.com/natemcmaster/DotNetCorePlugins
#if !MONO
using System;
using System.Collections.Generic;

View File

@@ -17,9 +17,11 @@ namespace OpenRA.Traits
[Desc("Required for shroud and fog visibility checks. Add this to the player actor.")]
public class ShroudInfo : TraitInfo, ILobbyOptions
{
[Translate]
[Desc("Descriptive label for the fog checkbox in the lobby.")]
public readonly string FogCheckboxLabel = "Fog of War";
[Translate]
[Desc("Tooltip description for the fog checkbox in the lobby.")]
public readonly string FogCheckboxDescription = "Line of sight is required to view enemy forces";
@@ -35,9 +37,11 @@ namespace OpenRA.Traits
[Desc("Display order for the fog checkbox in the lobby.")]
public readonly int FogCheckboxDisplayOrder = 0;
[Translate]
[Desc("Descriptive label for the explored map checkbox in the lobby.")]
public readonly string ExploredMapCheckboxLabel = "Explored Map";
[Translate]
[Desc("Tooltip description for the explored map checkbox in the lobby.")]
public readonly string ExploredMapCheckboxDescription = "Initial map shroud is revealed";

View File

@@ -28,6 +28,7 @@ namespace OpenRA.Traits
[Desc("The side that the faction belongs to. For example, England belongs to the 'Allies' side.")]
public readonly string Side = null;
[Translate]
public readonly string Description = null;
public readonly bool Selectable = true;

View File

@@ -65,9 +65,4 @@
<Analyzer Remove="@(Analyzer)" />
</ItemGroup>
</Target>
<ItemGroup>
<TrimmerRootAssembly Include="mscorlib" />
<TrimmerRootAssembly Include="netstandard" />
<TrimmerRootAssembly Include="System.IO.Pipes" />
</ItemGroup>
</Project>

View File

@@ -20,11 +20,15 @@ namespace OpenRA.Mods.Cnc.AudioLoaders
bool IsAud(Stream s)
{
var start = s.Position;
s.Position += 11;
s.Position += 10;
var readFlag = s.ReadByte();
var readFormat = s.ReadByte();
s.Position = start;
return readFormat == (int)SoundFormat.ImaAdpcm;
if (!Enum.IsDefined(typeof(SoundFlags), readFlag))
return false;
return Enum.IsDefined(typeof(SoundFormat), readFormat);
}
bool ISoundLoader.TryParseSound(Stream stream, out ISoundFormat sound)
@@ -49,8 +53,8 @@ namespace OpenRA.Mods.Cnc.AudioLoaders
public sealed class AudFormat : ISoundFormat
{
public int Channels { get { return channels; } }
public int SampleBits { get { return sampleBits; } }
public int Channels { get { return 1; } }
public int SampleBits { get { return 16; } }
public int SampleRate { get { return sampleRate; } }
public float LengthInSeconds { get { return AudReader.SoundLength(sourceStream); } }
public Stream GetPCMInputStream() { return audStreamFactory(); }
@@ -58,15 +62,13 @@ namespace OpenRA.Mods.Cnc.AudioLoaders
readonly Stream sourceStream;
readonly Func<Stream> audStreamFactory;
readonly int channels;
readonly int sampleBits;
readonly int sampleRate;
public AudFormat(Stream stream)
{
sourceStream = stream;
if (!AudReader.LoadSound(stream, out audStreamFactory, out sampleRate, out sampleBits, out channels))
if (!AudReader.LoadSound(stream, out audStreamFactory, out sampleRate))
throw new InvalidDataException();
}
}

View File

@@ -49,7 +49,7 @@ namespace OpenRA.Mods.Cnc.FileFormats
return (float)samples / sampleRate;
}
public static bool LoadSound(Stream s, out Func<Stream> result, out int sampleRate, out int sampleBits, out int channels)
public static bool LoadSound(Stream s, out Func<Stream> result, out int sampleRate)
{
result = null;
var startPosition = s.Position;
@@ -58,17 +58,15 @@ namespace OpenRA.Mods.Cnc.FileFormats
sampleRate = s.ReadUInt16();
var dataSize = s.ReadInt32();
var outputSize = s.ReadInt32();
var readFlag = s.ReadByte();
sampleBits = (readFlag & (int)SoundFlags._16Bit) == 0 ? 8 : 16;
channels = (readFlag & (int)SoundFlags.Stereo) == 0 ? 1 : 2;
if (!Enum.IsDefined(typeof(SoundFlags), readFlag))
return false;
var readFormat = s.ReadByte();
if (!Enum.IsDefined(typeof(SoundFormat), readFormat))
return false;
if (readFormat == (int)SoundFormat.WestwoodCompressed)
throw new NotImplementedException();
var offsetPosition = s.Position;
result = () =>

View File

@@ -35,10 +35,10 @@ namespace OpenRA.Mods.Cnc.Graphics
uint IModel.Frames { get { return frames; } }
uint IModel.Sections { get { return limbs; } }
public Voxel(VoxelLoader loader, VxlReader vxl, HvaReader hva, (string Vxl, string Hva) files)
public Voxel(VoxelLoader loader, VxlReader vxl, HvaReader hva)
{
if (vxl.LimbCount != hva.LimbCount)
throw new InvalidOperationException("{0}.vxl and {1}.hva limb counts don't match.".F(files.Vxl, files.Hva));
throw new InvalidOperationException("Voxel and hva limb counts don't match");
transforms = hva.Transforms;
frames = hva.FrameCount;

View File

@@ -77,8 +77,8 @@ namespace OpenRA.Mods.Cnc.Graphics
var size = new Size(su, sv);
var s = sheetBuilder.Allocate(size);
var t = sheetBuilder.Allocate(size);
OpenRA.Graphics.Util.FastCopyIntoChannel(s, colors, SpriteFrameType.Indexed8);
OpenRA.Graphics.Util.FastCopyIntoChannel(t, normals, SpriteFrameType.Indexed8);
OpenRA.Graphics.Util.FastCopyIntoChannel(s, colors);
OpenRA.Graphics.Util.FastCopyIntoChannel(t, normals);
// s and t are guaranteed to use the same sheet because
// of the custom voxel sheet allocation implementation
@@ -216,10 +216,9 @@ namespace OpenRA.Mods.Cnc.Graphics
HvaReader hva;
using (var s = fileSystem.Open(files.Vxl + ".vxl"))
vxl = new VxlReader(s);
using (var s = fileSystem.Open(files.Hva + ".hva"))
hva = new HvaReader(s, files.Hva + ".hva");
return new Voxel(this, vxl, hva, files);
return new Voxel(this, vxl, hva);
}
public Voxel Load(string vxl, string hva)

View File

@@ -86,11 +86,6 @@ namespace OpenRA.Mods.Cnc.Graphics
return loader.Load(vxl, hva);
}
public IModel GetModel(string model)
{
return loader.Load(model, model);
}
public IModel GetModelSequence(string model, string sequence)
{
try { return models[model][sequence]; }

View File

@@ -30,7 +30,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
class ShpD2Frame : ISpriteFrame
{
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
public Size Size { get; private set; }
public Size FrameSize { get { return Size; } }
public float2 Offset { get { return float2.Zero; } }

View File

@@ -77,7 +77,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
class ImageHeader : ISpriteFrame
{
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
public Size Size { get { return reader.Size; } }
public Size FrameSize { get { return reader.Size; } }
public float2 Offset { get { return float2.Zero; } }

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
{
class TmpRAFrame : ISpriteFrame
{
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
public Size Size { get; private set; }
public Size FrameSize { get; private set; }
public float2 Offset { get { return float2.Zero; } }

View File

@@ -19,7 +19,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
{
class TmpTDFrame : ISpriteFrame
{
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
public Size Size { get; private set; }
public Size FrameSize { get; private set; }
public float2 Offset { get { return float2.Zero; } }

View File

@@ -21,7 +21,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
{
readonly TmpTSFrame parent;
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
public Size Size { get { return parent.Size; } }
public Size FrameSize { get { return Size; } }
public float2 Offset { get { return parent.Offset; } }
@@ -36,7 +36,7 @@ namespace OpenRA.Mods.Cnc.SpriteLoaders
class TmpTSFrame : ISpriteFrame
{
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
public Size Size { get; private set; }
public Size FrameSize { get { return Size; } }
public float2 Offset { get; private set; }

View File

@@ -26,9 +26,11 @@ namespace OpenRA.Mods.Cnc.Traits
[Desc("The prerequisite type that this provides.")]
public readonly string Prerequisite = null;
[Translate]
[Desc("Label to display over the support power icon and in its tooltip while the power is active.")]
public readonly string ActiveText = "ACTIVE";
[Translate]
[Desc("Label to display over the support power icon and in its tooltip while the power is available but not active.")]
public readonly string AvailableText = "READY";

View File

@@ -14,7 +14,6 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.FileFormats;
using OpenRA.Graphics;
using OpenRA.Mods.Cnc.SpriteLoaders;
using OpenRA.Primitives;
@@ -36,7 +35,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands
var dest = inputFiles[0].Split('-').First() + ".shp";
var frames = inputFiles.Select(a => new Png(File.OpenRead(a))).ToList();
if (frames.Any(f => f.Type != SpriteFrameType.Indexed8))
if (frames.Any(f => f.Palette == null))
throw new InvalidOperationException("All frames must be paletted");
var size = new Size(frames[0].Width, frames[0].Height);

View File

@@ -62,7 +62,7 @@ namespace OpenRA.Mods.Common.Lint
if (!string.IsNullOrWhiteSpace(player.Faction) && !factions.Contains(player.Faction))
emitError("Invalid faction {0} chosen for player {1}.".F(player.Faction, player.Name));
if (worldActor.HasTraitInfo<MapStartingLocationsInfo>())
if (worldActor.HasTraitInfo<MPStartLocationsInfo>())
{
var playerCount = players.Count(p => p.Value.Playable);
var spawns = new List<CPos>();

View File

@@ -24,8 +24,6 @@ namespace OpenRA.Mods.Common.LoadScreens
public LaunchArguments Launch;
protected ModData ModData { get; private set; }
bool initialized;
public virtual void Init(ModData modData, Dictionary<string, string> info)
{
ModData = modData;
@@ -33,15 +31,12 @@ namespace OpenRA.Mods.Common.LoadScreens
public virtual void Display()
{
if (Game.Renderer == null || initialized)
if (Game.Renderer == null)
return;
// Draw a black screen
Game.Renderer.BeginUI();
Game.Renderer.EndFrame(new NullInputHandler());
// PERF: draw the screen only once
initialized = true;
}
public virtual void StartGame(Arguments args)

View File

@@ -61,22 +61,24 @@ namespace OpenRA.Mods.Common.SpriteLoaders
RegionsFromSlices(png, out frameRegions, out frameOffsets);
frames = new ISpriteFrame[frameRegions.Count];
var stride = png.PixelStride;
for (var i = 0; i < frames.Length; i++)
{
var frameStart = frameRegions[i].X + frameRegions[i].Y * png.Width;
var frameSize = new Size(frameRegions[i].Width, frameRegions[i].Height);
var pixelLength = png.Palette == null ? 4 : 1;
frames[i] = new PngSheetFrame()
{
Size = frameSize,
FrameSize = frameSize,
Offset = frameOffsets[i],
Data = new byte[frameRegions[i].Width * frameRegions[i].Height * stride],
Type = png.Type
Data = new byte[frameRegions[i].Width * frameRegions[i].Height * pixelLength],
Type = png.Palette == null ? SpriteFrameType.BGRA : SpriteFrameType.Indexed
};
for (var y = 0; y < frames[i].Size.Height; y++)
Array.Copy(png.Data, (frameStart + y * png.Width) * stride, frames[i].Data, y * frames[i].Size.Width * stride, frames[i].Size.Width * stride);
Array.Copy(png.Data, (frameStart + y * png.Width) * pixelLength, frames[i].Data, y * frames[i].Size.Width * pixelLength, frames[i].Size.Width * pixelLength);
}
metadata = new TypeDictionary

View File

@@ -20,7 +20,7 @@ namespace OpenRA.Mods.Common.SpriteLoaders
{
class ShpTSFrame : ISpriteFrame
{
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get { return SpriteFrameType.Indexed; } }
public Size Size { get; private set; }
public Size FrameSize { get; private set; }
public float2 Offset { get; private set; }

View File

@@ -54,6 +54,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Sort order for the production palette. Smaller numbers are presented earlier.")]
public readonly int BuildPaletteOrder = 9999;
[Translate]
[Desc("Text shown in the production tooltip.")]
public readonly string Description = "";

View File

@@ -21,6 +21,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Delay for the end game notification in milliseconds.")]
public readonly int NotificationDelay = 1500;
[Translate]
[Desc("Description of the objective.")]
public readonly string Objective = "Destroy all opposition!";

View File

@@ -19,9 +19,11 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Attach this to the player actor.")]
public class DeveloperModeInfo : TraitInfo, ILobbyOptions
{
[Translate]
[Desc("Descriptive label for the developer mode checkbox in the lobby.")]
public readonly string CheckboxLabel = "Debug Menu";
[Translate]
[Desc("Tooltip description for the developer mode checkbox in the lobby.")]
public readonly string CheckboxDescription = "Enables cheats and developer commands";

View File

@@ -18,9 +18,11 @@ namespace OpenRA.Mods.Common.Traits
{
public class PlayerResourcesInfo : TraitInfo, ILobbyOptions
{
[Translate]
[Desc("Descriptive label for the starting cash option in the lobby.")]
public readonly string DefaultCashDropdownLabel = "Starting Cash";
[Translate]
[Desc("Tooltip description for the starting cash option in the lobby.")]
public readonly string DefaultCashDropdownDescription = "Change the amount of cash that players start with";

View File

@@ -19,6 +19,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Internal id for this tech level.")]
public readonly string Id;
[Translate]
[Desc("Name shown in the lobby options.")]
public readonly string Name;

View File

@@ -36,6 +36,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Delay for the end game notification in milliseconds.")]
public readonly int NotificationDelay = 1500;
[Translate]
[Desc("Description of the objective")]
public readonly string Objective = "Hold all the strategic positions!";

View File

@@ -21,6 +21,7 @@ namespace OpenRA.Mods.Common.Traits.Render
[Desc("Displays a text overlay relative to the selection box.")]
public class WithTextDecorationInfo : WithDecorationBaseInfo
{
[Translate]
[FieldLoader.Require]
public readonly string Text = null;

View File

@@ -15,6 +15,7 @@ namespace OpenRA.Mods.Common.Traits
{
public abstract class TooltipInfoBase : ConditionalTraitInfo, Requires<IMouseBoundsInfo>
{
[Translate]
public readonly string Name = "";
}
@@ -27,6 +28,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Shown in the build palette widget.")]
public class TooltipInfo : TooltipInfoBase, ITooltipInfo
{
[Translate]
[Desc("An optional generic name (i.e. \"Soldier\" or \"Structure\")" +
"to be shown to chosen players.")]
public readonly string GenericName = null;
@@ -34,12 +36,15 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Prefix generic tooltip name with 'Ally/Neutral/EnemyPrefix'.")]
public readonly bool GenericStancePrefix = true;
[Translate]
[Desc("Prefix to display in the tooltip for allied units.")]
public readonly string AllyPrefix = "Allied";
[Translate]
[Desc("Prefix to display in the tooltip for neutral units.")]
public readonly string NeutralPrefix = null;
[Translate]
[Desc("Prefix to display in the tooltip for enemy units.")]
public readonly string EnemyPrefix = "Enemy";

View File

@@ -17,6 +17,7 @@ namespace OpenRA.Mods.Common.Traits
public class TooltipDescriptionInfo : ConditionalTraitInfo
{
[Desc("Text shown in tooltip.")]
[Translate]
public readonly string Description = "";
[Desc("Player relationships who can view the description.")]

View File

@@ -11,7 +11,6 @@
using System.Collections.Generic;
using System.Linq;
using OpenRA.Mods.Common;
using OpenRA.Primitives;
using OpenRA.Traits;
@@ -26,8 +25,8 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Maximum number of actors.")]
public readonly int Maximum = 4;
[Desc("Time (in ticks) between actor spawn. Supports 1 or 2 values.\nIf 2 values are provided they are used as a range from which a value is randomly selected.")]
public readonly int[] SpawnInterval = { 6000 };
[Desc("Time (in ticks) between actor spawn.")]
public readonly int SpawnInterval = 6000;
[FieldLoader.Require]
[ActorReference]
@@ -39,20 +38,6 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Type of ActorSpawner with which it connects.")]
public readonly HashSet<string> Types = new HashSet<string>() { };
public override void RulesetLoaded(Ruleset rules, ActorInfo ai)
{
base.RulesetLoaded(rules, ai);
if (SpawnInterval.Length == 0 || SpawnInterval.Length > 2)
throw new YamlException("{0}.{1} must be either 1 or 2 values".F(nameof(ActorSpawnManager), nameof(SpawnInterval)));
if (SpawnInterval.Length == 2 && SpawnInterval[0] >= SpawnInterval[1])
throw new YamlException("{0}.{1}'s first value must be less than the second value".F(nameof(ActorSpawnManager), nameof(SpawnInterval)));
if (SpawnInterval.Any(it => it < 0))
throw new YamlException("{0}.{1}'s value(s) must not be less than 0".F(nameof(ActorSpawnManager), nameof(SpawnInterval)));
}
public override object Create(ActorInitializer init) { return new ActorSpawnManager(init.Self, this); }
}
@@ -92,7 +77,7 @@ namespace OpenRA.Mods.Common.Traits
if (spawnPoint == null)
return;
spawnCountdown = Util.RandomDelay(self.World, info.SpawnInterval);
spawnCountdown = info.SpawnInterval;
do
{

View File

@@ -20,9 +20,11 @@ namespace OpenRA.Mods.Common.Traits
{
public class CrateSpawnerInfo : TraitInfo, ILobbyOptions
{
[Translate]
[Desc("Descriptive label for the crates checkbox in the lobby.")]
public readonly string CheckboxLabel = "Crates";
[Translate]
[Desc("Tooltip description for the crates checkbox in the lobby.")]
public readonly string CheckboxDescription = "Collect crates with units to receive random bonuses or penalties";

View File

@@ -19,7 +19,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Attach this to the world actor.")]
public class CreateMapPlayersInfo : TraitInfo<CreateMapPlayers>, ICreatePlayersInfo
public class CreateMPPlayersInfo : TraitInfo<CreateMPPlayers>, ICreatePlayersInfo
{
/// <summary>
/// Returns a list of GameInformation.Players that matches the indexing of ICreatePlayers.CreatePlayers.
@@ -80,7 +80,7 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class CreateMapPlayers : ICreatePlayers
public class CreateMPPlayers : ICreatePlayers
{
void ICreatePlayers.CreatePlayers(World w, MersenneTwister playerRandom)
{

View File

@@ -20,13 +20,15 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Allows the map to have working spawnpoints. Also controls the 'Separate Team Spawns' checkbox in the lobby options.")]
public class MapStartingLocationsInfo : TraitInfo, ILobbyOptions, IAssignSpawnPointsInfo
public class MPStartLocationsInfo : TraitInfo, ILobbyOptions, IAssignSpawnPointsInfo
{
public readonly WDist InitialExploreRange = WDist.FromCells(5);
[Translate]
[Desc("Descriptive label for the spawn positions checkbox in the lobby.")]
public readonly string SeparateTeamSpawnsCheckboxLabel = "Separate Team Spawns";
[Translate]
[Desc("Tooltip description for the spawn positions checkbox in the lobby.")]
public readonly string SeparateTeamSpawnsCheckboxDescription = "Players without assigned spawn points will start as far as possible from enemy players";
@@ -42,7 +44,7 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Display order for the spawn positions checkbox in the lobby.")]
public readonly int SeparateTeamSpawnsCheckboxDisplayOrder = 0;
public override object Create(ActorInitializer init) { return new MapStartingLocations(this); }
public override object Create(ActorInitializer init) { return new MPStartLocations(this); }
IEnumerable<LobbyOption> ILobbyOptions.LobbyOptions(Ruleset rules)
{
@@ -103,15 +105,15 @@ namespace OpenRA.Mods.Common.Traits
}
}
public class MapStartingLocations : IWorldLoaded, INotifyCreated, IAssignSpawnPoints
public class MPStartLocations : IWorldLoaded, INotifyCreated, IAssignSpawnPoints
{
readonly MapStartingLocationsInfo info;
readonly MPStartLocationsInfo info;
readonly Dictionary<int, Session.Client> occupiedSpawnPoints = new Dictionary<int, Session.Client>();
bool separateTeamSpawns;
CPos[] spawnLocations;
List<int> availableSpawnPoints;
public MapStartingLocations(MapStartingLocationsInfo info)
public MPStartLocations(MPStartLocationsInfo info)
{
this.info = info;
}

View File

@@ -14,8 +14,8 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Used by SpawnStartingUnits. Attach these to the world actor. You can have multiple variants by adding @suffixes.")]
public class StartingUnitsInfo : TraitInfo<StartingUnits>
[Desc("Used by SpawnMPUnits. Attach these to the world actor. You can have multiple variants by adding @suffixes.")]
public class MPStartUnitsInfo : TraitInfo<MPStartUnits>
{
[Desc("Internal class ID.")]
public readonly string Class = "none";
@@ -50,5 +50,5 @@ namespace OpenRA.Mods.Common.Traits
public readonly WAngle? SupportActorsFacing = null;
}
public class StartingUnits { }
public class MPStartUnits { }
}

View File

@@ -17,9 +17,11 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Controls the build radius checkboxes in the lobby options.")]
public class MapBuildRadiusInfo : TraitInfo, ILobbyOptions
{
[Translate]
[Desc("Descriptive label for the ally build radius checkbox in the lobby.")]
public readonly string AllyBuildRadiusCheckboxLabel = "Build off Allies";
[Translate]
[Desc("Tooltip description for the ally build radius checkbox in the lobby.")]
public readonly string AllyBuildRadiusCheckboxDescription = "Allow allies to place structures inside your build area";
@@ -35,9 +37,11 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Display order for the ally build radius checkbox in the lobby.")]
public readonly int AllyBuildRadiusCheckboxDisplayOrder = 0;
[Translate]
[Desc("Tooltip description for the build radius checkbox in the lobby.")]
public readonly string BuildRadiusCheckboxLabel = "Limit Build Area";
[Translate]
[Desc("Tooltip description for the build radius checkbox in the lobby.")]
public readonly string BuildRadiusCheckboxDescription = "Limits structure placement to areas around Construction Yards";

View File

@@ -17,9 +17,11 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Controls the 'Creeps' checkbox in the lobby options.")]
public class MapCreepsInfo : TraitInfo, ILobbyOptions
{
[Translate]
[Desc("Descriptive label for the creeps checkbox in the lobby.")]
public readonly string CheckboxLabel = "Creep Actors";
[Translate]
[Desc("Tooltip description for the creeps checkbox in the lobby.")]
public readonly string CheckboxDescription = "Hostile forces spawn on the battlefield";

View File

@@ -18,9 +18,11 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Controls the game speed, tech level, and short game lobby options.")]
public class MapOptionsInfo : TraitInfo, ILobbyOptions, IRulesetLoaded
{
[Translate]
[Desc("Descriptive label for the short game checkbox in the lobby.")]
public readonly string ShortGameCheckboxLabel = "Short Game";
[Translate]
[Desc("Tooltip description for the short game checkbox in the lobby.")]
public readonly string ShortGameCheckboxDescription = "Players are defeated when their bases are destroyed";
@@ -36,9 +38,11 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Display order for the short game checkbox in the lobby.")]
public readonly int ShortGameCheckboxDisplayOrder = 0;
[Translate]
[Desc("Descriptive label for the tech level option in the lobby.")]
public readonly string TechLevelDropdownLabel = "Tech Level";
[Translate]
[Desc("Tooltip description for the tech level option in the lobby.")]
public readonly string TechLevelDropdownDescription = "Change the units and abilities at your disposal";
@@ -54,9 +58,11 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Display order for the tech level option in the lobby.")]
public readonly int TechLevelDropdownDisplayOrder = 0;
[Translate]
[Desc("Tooltip description for the game speed option in the lobby.")]
public readonly string GameSpeedDropdownLabel = "Game Speed";
[Translate]
[Desc("Description of the game speed option in the lobby.")]
public readonly string GameSpeedDropdownDescription = "Change the rate at which time passes";

View File

@@ -21,10 +21,12 @@ namespace OpenRA.Mods.Common.Traits
[Desc("Internal id for this option.")]
public readonly string ID = null;
[Translate]
[FieldLoader.Require]
[Desc("Descriptive label for this option.")]
public readonly string Label = null;
[Translate]
[Desc("Tooltip description for this option.")]
public readonly string Description = null;

View File

@@ -19,13 +19,15 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Common.Traits
{
[Desc("Spawn base actor at the spawnpoint and support units in an annulus around the base actor. Both are defined at MPStartUnits. Attach this to the world actor.")]
public class SpawnStartingUnitsInfo : TraitInfo, Requires<StartingUnitsInfo>, ILobbyOptions
public class SpawnMPUnitsInfo : TraitInfo, Requires<MPStartUnitsInfo>, ILobbyOptions
{
public readonly string StartingUnitsClass = "none";
[Translate]
[Desc("Descriptive label for the starting units option in the lobby.")]
public readonly string DropdownLabel = "Starting Units";
[Translate]
[Desc("Tooltip description for the starting units option in the lobby.")]
public readonly string DropdownDescription = "Change the units that you start the game with";
@@ -43,7 +45,7 @@ namespace OpenRA.Mods.Common.Traits
var startingUnits = new Dictionary<string, string>();
// Duplicate classes are defined for different race variants
foreach (var t in rules.Actors["world"].TraitInfos<StartingUnitsInfo>())
foreach (var t in rules.Actors["world"].TraitInfos<MPStartUnitsInfo>())
startingUnits[t.Class] = t.ClassName;
if (startingUnits.Any())
@@ -51,14 +53,14 @@ namespace OpenRA.Mods.Common.Traits
new ReadOnlyDictionary<string, string>(startingUnits), StartingUnitsClass, DropdownLocked);
}
public override object Create(ActorInitializer init) { return new SpawnStartingUnits(this); }
public override object Create(ActorInitializer init) { return new SpawnMPUnits(this); }
}
public class SpawnStartingUnits : IWorldLoaded
public class SpawnMPUnits : IWorldLoaded
{
readonly SpawnStartingUnitsInfo info;
readonly SpawnMPUnitsInfo info;
public SpawnStartingUnits(SpawnStartingUnitsInfo info)
public SpawnMPUnits(SpawnMPUnitsInfo info)
{
this.info = info;
}
@@ -75,7 +77,7 @@ namespace OpenRA.Mods.Common.Traits
var spawnClass = p.PlayerReference.StartingUnitsClass ?? w.LobbyInfo.GlobalSettings
.OptionOrDefault("startingunits", info.StartingUnitsClass);
var unitGroup = w.Map.Rules.Actors["world"].TraitInfos<StartingUnitsInfo>()
var unitGroup = w.Map.Rules.Actors["world"].TraitInfos<MPStartUnitsInfo>()
.Where(g => g.Class == spawnClass && g.Factions != null && g.Factions.Contains(p.Faction.InternalName))
.RandomOrDefault(w.SharedRandom);

View File

@@ -1,38 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* 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.Collections.Generic;
namespace OpenRA.Mods.Common.UpdateRules.Rules
{
public class RenameMPTraits : UpdateRule
{
public override string Name { get { return "Several traits spawning map actors and players have been renamed."; } }
public override string Description
{
get
{
return "'SpawnMPUnits' was renamed to 'SpawnStartingUnits', 'MPStartUnits' to 'StartingUnits', 'MPStartLocations' to " +
"'MapStartingLocations', and 'CreateMPPlayers' to 'CreateMapPlayers'.";
}
}
public override IEnumerable<string> UpdateActorNode(ModData modData, MiniYamlNode actorNode)
{
actorNode.RenameChildrenMatching("SpawnMPUnits", "SpawnStartingUnits");
actorNode.RenameChildrenMatching("MPStartUnits", "StartingUnits");
actorNode.RenameChildrenMatching("MPStartLocations", "MapStartingLocations");
actorNode.RenameChildrenMatching("CreateMPPlayers", "CreateMapPlayers");
yield break;
}
}
}

View File

@@ -53,9 +53,9 @@ namespace OpenRA.Mods.Common.UpdateRules
new RenameRallyPointPath(),
}),
new UpdatePath("release-20200503", "playtest-20201213", new UpdateRule[]
new UpdatePath("release-20200503", new UpdateRule[]
{
// Prep only changes here
// Bleed only changes here
new AddPipDecorationTraits(),
new ModernizeDecorationTraits(),
new RenameHealCrateAction(),
@@ -79,12 +79,6 @@ namespace OpenRA.Mods.Common.UpdateRules
new RenameCircleContrast(),
new SplitDamagedByTerrain(),
new RemoveLaysTerrain(),
}),
new UpdatePath("playtest-20201213", new UpdateRule[]
{
// Bleed only changes here
new RenameMPTraits(),
})
};

View File

@@ -0,0 +1,58 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* 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.IO;
using System.Linq;
using System.Reflection;
namespace OpenRA.Mods.Common.UtilityCommands
{
public class CheckRuntimeAssembliesCommand : IUtilityCommand
{
string IUtilityCommand.Name { get { return "--check-runtime-assemblies"; } }
bool IUtilityCommand.ValidateArguments(string[] args)
{
return true;
}
[Desc("ASSEMBLY [ASSEMBLY ...]", "Check the runtime dependencies of the mod against a given whitelist of " +
"assembly (dll and exe) names and generate an error if any unlisted files are required.")]
void IUtilityCommand.Run(Utility utility, string[] args)
{
var whitelist = args
.Skip(1)
.Select(a => Path.GetFileName(a))
.ToArray();
// Load the renderer assembly so we can check its dependencies
Assembly.LoadFile(Path.Combine(Platform.BinDir, "OpenRA.Platforms.Default.dll"));
var missing = new List<string>();
foreach (var a in AppDomain.CurrentDomain.GetAssemblies())
{
var assemblyName = Path.GetFileName(a.Location);
if (!whitelist.Contains(assemblyName))
missing.Add(assemblyName);
}
if (missing.Any())
{
Console.WriteLine("error: The following assemblies are referenced but not whitelisted:");
foreach (var m in missing)
Console.WriteLine(" " + m);
Environment.Exit(1);
}
}
}
}

View File

@@ -78,8 +78,16 @@ namespace OpenRA.Mods.Common.UtilityCommands
frame.Size.Width);
}
var png = new Png(pngData, SpriteFrameType.Indexed8, frameSize.Width, frameSize.Height, palColors);
png.Save("{0}-{1:D4}.png".F(prefix, count++));
if (frame.Type == SpriteFrameType.BGRA)
{
var png = new Png(pngData, frameSize.Width, frameSize.Height);
png.Save("{0}-{1:D4}.png".F(prefix, count++));
}
else
{
var png = new Png(pngData, frameSize.Width, frameSize.Height, palColors);
png.Save("{0}-{1:D4}.png".F(prefix, count++));
}
}
Console.WriteLine("Saved {0}-[0..{1}].png", prefix, count - 1);

View File

@@ -45,7 +45,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
var count = 0;
var sb = sequences.SpriteCache.SheetBuilders[SheetType.Indexed];
var sb = sequences.SpriteCache.SheetBuilders[SpriteFrameType.Indexed];
foreach (var s in sb.AllSheets)
{
var max = s == sb.Current ? (int)sb.CurrentChannel + 1 : 4;
@@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.UtilityCommands
s.AsPng((TextureChannel)ChannelMasks[i], palette).Save("{0}.png".F(count++));
}
sb = sequences.SpriteCache.SheetBuilders[SheetType.BGRA];
sb = sequences.SpriteCache.SheetBuilders[SpriteFrameType.BGRA];
foreach (var s in sb.AllSheets)
s.AsPng().Save("{0}.png".F(count++));

View File

@@ -0,0 +1,79 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* 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.IO;
using System.Linq;
namespace OpenRA.Mods.Common.UtilityCommands
{
class ExtractLanguageStringsCommand : IUtilityCommand
{
string IUtilityCommand.Name { get { return "--extract-language-strings"; } }
bool IUtilityCommand.ValidateArguments(string[] args)
{
return true;
}
[Desc("Extract translatable strings that are not yet localized and update chrome layout.")]
void IUtilityCommand.Run(Utility utility, string[] args)
{
// HACK: The engine code assumes that Game.modData is set.
var modData = Game.ModData = utility.ModData;
var types = modData.ObjectCreator.GetTypes();
var translatableFields = types.SelectMany(t => t.GetFields())
.Where(f => f.HasAttribute<TranslateAttribute>()).Distinct();
foreach (var filename in modData.Manifest.ChromeLayout)
{
modData.ModFiles.TryGetPackageContaining(filename, out var package, out var name);
name = package.Name + "/" + name;
Console.WriteLine("# {0}:", filename);
var yaml = MiniYaml.FromFile(name, false);
FromChromeLayout(ref yaml, null,
translatableFields.Select(t => t.Name).Distinct(), null);
using (var file = new StreamWriter(name))
file.WriteLine(yaml.WriteToString());
}
// TODO: Properties can also be translated.
}
internal static void FromChromeLayout(ref List<MiniYamlNode> nodes, MiniYamlNode parent, IEnumerable<string> translatables, string container)
{
var parentNode = parent != null && parent.Key != null ? parent.Key.Split('@') : null;
var parentType = parent != null && parent.Key != null ? parentNode.First() : null;
var parentLabel = parent != null && parent.Key != null ? parentNode.Last() : null;
if ((parentType == "Background" || parentType == "Container") && parentLabel.IsUppercase())
container = parentLabel;
foreach (var node in nodes)
{
var alreadyTranslated = node.Value.Value != null && node.Value.Value.Contains('@');
if (translatables.Contains(node.Key) && !alreadyTranslated && parentLabel != null)
{
var translationKey = "{0}-{1}".F(parentLabel.Replace('_', '-'), node.Key.ToUpper());
if (container != null)
translationKey = "{0}-".F(container.Replace('_', '-')) + translationKey;
Console.WriteLine("\t{0}: {1}", translationKey, node.Value.Value);
node.Value.Value = "@{0}@".F(translationKey);
}
FromChromeLayout(ref node.Value.Nodes, node, translatables, container);
}
}
}
}

View File

@@ -26,6 +26,7 @@ namespace OpenRA.Mods.Common.Widgets
public bool DisableKeyRepeat = false;
public bool DisableKeySound = false;
[Translate]
public string Text = "";
public TextAlign Align = TextAlign.Center;
public int LeftMargin = 5;
@@ -57,9 +58,11 @@ namespace OpenRA.Mods.Common.Widgets
protected Lazy<TooltipContainerWidget> tooltipContainer;
[Translate]
public string TooltipText;
public Func<string> GetTooltipText;
[Translate]
public string TooltipDesc;
public Func<string> GetTooltipDesc;

View File

@@ -26,6 +26,7 @@ namespace OpenRA.Mods.Common.Widgets
public Func<string> GetImageName;
public Func<string> GetImageCollection;
[Translate]
public string TooltipText;
Lazy<TooltipContainerWidget> tooltipContainer;

View File

@@ -21,6 +21,7 @@ namespace OpenRA.Mods.Common.Widgets
public class LabelWidget : Widget
{
[Translate]
public string Text = null;
public TextAlign Align = TextAlign.Left;
public TextVAlign VAlign = TextVAlign.Middle;

View File

@@ -43,12 +43,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
string currentFilename;
IReadOnlyPackage currentPackage;
Sprite[] currentSprites;
IModel currentVoxel;
VqaPlayerWidget player = null;
bool isVideoLoaded = false;
bool isLoadError = false;
int currentFrame;
WRot modelOrientation;
[ObjectCreator.UseCtor]
public AssetBrowserLogic(Widget widget, Action onExit, ModData modData, World world, Dictionary<string, MiniYaml> logicArgs)
@@ -81,24 +79,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
spriteWidget.GetSprite = () => currentSprites != null ? currentSprites[currentFrame] : null;
currentPalette = spriteWidget.Palette;
spriteWidget.GetPalette = () => currentPalette;
spriteWidget.IsVisible = () => !isVideoLoaded && !isLoadError && currentSprites != null;
spriteWidget.IsVisible = () => !isVideoLoaded && !isLoadError;
}
var playerWidget = panel.GetOrNull<VqaPlayerWidget>("PLAYER");
if (playerWidget != null)
playerWidget.IsVisible = () => isVideoLoaded && !isLoadError;
var modelWidget = panel.GetOrNull<ModelWidget>("VOXEL");
if (modelWidget != null)
{
modelWidget.GetVoxel = () => currentVoxel;
currentPalette = modelWidget.Palette;
modelWidget.GetPalette = () => currentPalette;
modelWidget.GetPlayerPalette = () => currentPalette;
modelWidget.GetRotation = () => modelOrientation;
modelWidget.IsVisible = () => !isVideoLoaded && !isLoadError && currentVoxel != null;
}
var errorLabelWidget = panel.GetOrNull("ERROR");
if (errorLabelWidget != null)
errorLabelWidget.IsVisible = () => isLoadError;
@@ -223,46 +210,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
prevButton.IsVisible = () => !isVideoLoaded;
}
var voxelContainer = panel.GetOrNull("VOXEL_SELECTOR");
if (voxelContainer != null)
voxelContainer.IsVisible = () => currentVoxel != null;
var rollSlider = panel.GetOrNull<SliderWidget>("ROLL_SLIDER");
if (rollSlider != null)
{
rollSlider.OnChange += x =>
{
var roll = (int)x;
modelOrientation = modelOrientation.WithRoll(new WAngle(roll));
};
rollSlider.GetValue = () => modelOrientation.Roll.Angle;
}
var pitchSlider = panel.GetOrNull<SliderWidget>("PITCH_SLIDER");
if (pitchSlider != null)
{
pitchSlider.OnChange += x =>
{
var pitch = (int)x;
modelOrientation = modelOrientation.WithPitch(new WAngle(pitch));
};
pitchSlider.GetValue = () => modelOrientation.Pitch.Angle;
}
var yawSlider = panel.GetOrNull<SliderWidget>("YAW_SLIDER");
if (yawSlider != null)
{
yawSlider.OnChange += x =>
{
var yaw = (int)x;
modelOrientation = modelOrientation.WithYaw(new WAngle(yaw));
};
yawSlider.GetValue = () => modelOrientation.Yaw.Angle;
}
var assetBrowserModData = modData.Manifest.Get<AssetBrowser>();
allowedExtensions = assetBrowserModData.SupportedExtensions;
@@ -395,24 +342,12 @@ namespace OpenRA.Mods.Common.Widgets.Logic
return true;
}
if (Path.GetExtension(filename.ToLowerInvariant()) == ".vxl")
currentSprites = world.Map.Rules.Sequences.SpriteCache[prefix + filename];
currentFrame = 0;
if (frameSlider != null)
{
var voxelName = Path.GetFileNameWithoutExtension(filename);
currentVoxel = world.ModelCache.GetModel(voxelName);
currentSprites = null;
}
else
{
currentSprites = world.Map.Rules.Sequences.SpriteCache[prefix + filename];
currentFrame = 0;
if (frameSlider != null)
{
frameSlider.MaximumValue = (float)currentSprites.Length - 1;
frameSlider.Ticks = currentSprites.Length;
}
currentVoxel = null;
frameSlider.MaximumValue = (float)currentSprites.Length - 1;
frameSlider.Ticks = currentSprites.Length;
}
}
catch (Exception ex)

View File

@@ -101,8 +101,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
if (player == null || player.RelationshipWith(pp) == PlayerRelationship.Ally || player.WinState != WinState.Undefined)
{
flag.GetImageName = () => pp.Faction.InternalName;
var factionName = pp.Faction.Name != pp.DisplayFaction.Name ? "{0} ({1})".F(pp.DisplayFaction.Name, pp.Faction.Name) : pp.Faction.Name;
item.Get<LabelWidget>("FACTION").GetText = () => factionName;
item.Get<LabelWidget>("FACTION").GetText = () => pp.Faction.Name;
}
else
{

View File

@@ -247,6 +247,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
BindIntSliderPref(panel, "FRAME_LIMIT_SLIDER", ds, "MaxFramerate");
BindCheckboxPref(panel, "PLAYER_STANCE_COLORS_CHECKBOX", gs, "UsePlayerStanceColors");
var languageDropDownButton = panel.GetOrNull<DropDownButtonWidget>("LANGUAGE_DROPDOWNBUTTON");
if (languageDropDownButton != null)
{
languageDropDownButton.OnMouseDown = _ => ShowLanguageDropdown(languageDropDownButton, modData.Languages);
languageDropDownButton.GetText = () => FieldLoader.Translate(ds.Language);
}
var windowModeDropdown = panel.Get<DropDownButtonWidget>("MODE_DROPDOWN");
windowModeDropdown.OnMouseDown = _ => ShowWindowModeDropdown(windowModeDropdown, ds);
windowModeDropdown.GetText = () => ds.Mode == WindowMode.Windowed ?
@@ -381,6 +388,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{
ds.CapFramerate = dds.CapFramerate;
ds.MaxFramerate = dds.MaxFramerate;
ds.Language = dds.Language;
ds.GLProfile = dds.GLProfile;
ds.Mode = dds.Mode;
ds.VideoDisplay = dds.VideoDisplay;
@@ -820,6 +828,21 @@ namespace OpenRA.Mods.Common.Widgets.Logic
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, options.Keys, setupItem);
}
static void ShowLanguageDropdown(DropDownButtonWidget dropdown, IEnumerable<string> languages)
{
Func<string, ScrollItemWidget, ScrollItemWidget> setupItem = (o, itemTemplate) =>
{
var item = ScrollItemWidget.Setup(itemTemplate,
() => Game.Settings.Graphics.Language == o,
() => Game.Settings.Graphics.Language = o);
item.Get<LabelWidget>("LABEL").GetText = () => FieldLoader.Translate(o);
return item;
};
dropdown.ShowDropDown("LABEL_DROPDOWN_TEMPLATE", 500, languages, setupItem);
}
static void ShowStatusBarsDropdown(DropDownButtonWidget dropdown, GameSettings s)
{
var options = new Dictionary<string, StatusBarsType>()

View File

@@ -1,217 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
* 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 OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets
{
public class ModelWidget : Widget
{
public string Palette = "terrain";
public string PlayerPalette = "player";
public string NormalsPalette = "normals";
public string ShadowPalette = "shadow";
public float Scale = 12f;
public int LightPitch = 142;
public int LightYaw = 682;
public float[] LightAmbientColor = new float[] { 0.6f, 0.6f, 0.6f };
public float[] LightDiffuseColor = new float[] { 0.4f, 0.4f, 0.4f };
public WRot Rotation = WRot.None;
public WAngle CameraAngle = WAngle.FromDegrees(40);
public Func<string> GetPalette;
public Func<string> GetPlayerPalette;
public Func<string> GetNormalsPalette;
public Func<string> GetShadowPalette;
public Func<float[]> GetLightAmbientColor;
public Func<float[]> GetLightDiffuseColor;
public Func<float> GetScale;
public Func<int> GetLightPitch;
public Func<int> GetLightYaw;
public Func<IModel> GetVoxel;
public Func<WRot> GetRotation;
public Func<WAngle> GetCameraAngle;
public int2 IdealPreviewSize { get; private set; }
protected readonly WorldRenderer WorldRenderer;
IFinalizedRenderable renderable;
[ObjectCreator.UseCtor]
public ModelWidget(WorldRenderer worldRenderer)
{
GetPalette = () => Palette;
GetPlayerPalette = () => PlayerPalette;
GetNormalsPalette = () => NormalsPalette;
GetShadowPalette = () => ShadowPalette;
GetLightAmbientColor = () => LightAmbientColor;
GetLightDiffuseColor = () => LightDiffuseColor;
GetScale = () => Scale;
GetRotation = () => Rotation;
GetLightPitch = () => LightPitch;
GetLightYaw = () => LightYaw;
GetCameraAngle = () => CameraAngle;
WorldRenderer = worldRenderer;
}
protected ModelWidget(ModelWidget other)
: base(other)
{
Palette = other.Palette;
GetPalette = other.GetPalette;
GetVoxel = other.GetVoxel;
WorldRenderer = other.WorldRenderer;
}
public override Widget Clone()
{
return new ModelWidget(this);
}
IModel cachedVoxel;
string cachedPalette;
string cachedPlayerPalette;
string cachedNormalsPalette;
string cachedShadowPalette;
float cachedScale;
WRot cachedRotation;
float[] cachedLightAmbientColor = new float[] { 0, 0, 0 };
float[] cachedLightDiffuseColor = new float[] { 0, 0, 0 };
int cachedLightPitch;
int cachedLightYaw;
WAngle cachedCameraAngle;
PaletteReference paletteReference;
PaletteReference paletteReferencePlayer;
PaletteReference paletteReferenceNormals;
PaletteReference paletteReferenceShadow;
public override void Draw()
{
if (renderable == null)
return;
renderable.Render(WorldRenderer);
}
public override void PrepareRenderables()
{
var voxel = GetVoxel();
var palette = GetPalette();
var playerPalette = GetPlayerPalette();
var normalsPalette = GetNormalsPalette();
var shadowPalette = GetShadowPalette();
var scale = GetScale();
var rotation = GetRotation();
var lightAmbientColor = GetLightAmbientColor();
var lightDiffuseColor = GetLightDiffuseColor();
var lightPitch = GetLightPitch();
var lightYaw = GetLightYaw();
var cameraAngle = GetCameraAngle();
if (voxel == null || palette == null)
return;
if (voxel != cachedVoxel)
cachedVoxel = voxel;
if (palette != cachedPalette)
{
if (string.IsNullOrEmpty(palette) && string.IsNullOrEmpty(playerPalette))
return;
var paletteName = string.IsNullOrEmpty(palette) ? playerPalette : palette;
paletteReference = WorldRenderer.Palette(paletteName);
cachedPalette = paletteName;
}
if (playerPalette != cachedPlayerPalette)
{
paletteReferencePlayer = WorldRenderer.Palette(playerPalette);
cachedPlayerPalette = playerPalette;
}
if (normalsPalette != cachedNormalsPalette)
{
paletteReferenceNormals = WorldRenderer.Palette(normalsPalette);
cachedNormalsPalette = normalsPalette;
}
if (shadowPalette != cachedShadowPalette)
{
paletteReferenceShadow = WorldRenderer.Palette(shadowPalette);
cachedShadowPalette = shadowPalette;
}
if (scale != cachedScale)
cachedScale = scale;
if (rotation != cachedRotation)
cachedRotation = rotation;
if (lightPitch != cachedLightPitch)
cachedLightPitch = lightPitch;
if (lightYaw != cachedLightYaw)
cachedLightYaw = lightYaw;
if (cachedLightAmbientColor[0] != lightAmbientColor[0] || cachedLightAmbientColor[1] != lightAmbientColor[1] || cachedLightAmbientColor[2] != lightAmbientColor[2])
cachedLightAmbientColor = lightAmbientColor;
if (cachedLightDiffuseColor[0] != lightDiffuseColor[0] || cachedLightDiffuseColor[1] != lightDiffuseColor[1] || cachedLightDiffuseColor[2] != lightDiffuseColor[2])
cachedLightDiffuseColor = lightDiffuseColor;
if (cameraAngle != cachedCameraAngle)
cachedCameraAngle = cameraAngle;
if (cachedVoxel == null)
return;
var animation = new ModelAnimation(
cachedVoxel,
() => WVec.Zero,
() => cachedRotation,
() => false,
() => 0,
true);
var animations = new ModelAnimation[] { animation };
ModelPreview preview = new ModelPreview(
new ModelAnimation[] { animation }, WVec.Zero, 0,
cachedScale,
new WAngle(cachedLightPitch),
new WAngle(cachedLightYaw),
cachedLightAmbientColor,
cachedLightDiffuseColor,
cachedCameraAngle,
paletteReference,
paletteReferenceNormals,
paletteReferenceShadow);
var screenBounds = animation.ScreenBounds(WPos.Zero, WorldRenderer, scale);
IdealPreviewSize = new int2(screenBounds.Width, screenBounds.Height);
var origin = RenderOrigin + new int2(RenderBounds.Size.Width / 2, RenderBounds.Size.Height / 2);
var camera = new WRot(WAngle.Zero, cachedCameraAngle - new WAngle(256), new WAngle(256));
var modelRenderable = new UIModelRenderable(
animations, WPos.Zero, origin, 0, camera, scale,
WRot.None, cachedLightAmbientColor, cachedLightDiffuseColor,
paletteReferencePlayer, paletteReferenceNormals, paletteReferenceShadow);
renderable = modelRenderable.PrepareRender(WorldRenderer);
}
}
}

View File

@@ -70,10 +70,13 @@ namespace OpenRA.Mods.Common.Widgets
public readonly bool DrawTime = true;
[Translate]
public readonly string ReadyText = "";
[Translate]
public readonly string HoldText = "";
[Translate]
public readonly string InfiniteSymbol = "\u221E";
public int DisplayedIconCount { get; private set; }

View File

@@ -22,8 +22,10 @@ namespace OpenRA.Mods.Common.Widgets
{
public class SupportPowersWidget : Widget
{
[Translate]
public readonly string ReadyText = "";
[Translate]
public readonly string HoldText = "";
public readonly string OverlayFont = "TinyBold";

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.D2k.SpriteLoaders
{
class R8Frame : ISpriteFrame
{
public SpriteFrameType Type { get { return SpriteFrameType.Indexed8; } }
public SpriteFrameType Type { get; set; }
public Size Size { get; private set; }
public Size FrameSize { get; private set; }
public float2 Offset { get; private set; }

View File

@@ -40,9 +40,4 @@
<Analyzer Remove="@(Analyzer)" />
</ItemGroup>
</Target>
<ItemGroup>
<TrimmerRootAssembly Include="mscorlib" />
<TrimmerRootAssembly Include="netstandard" />
<TrimmerRootAssembly Include="System.IO.Pipes" />
</ItemGroup>
</Project>

View File

@@ -40,9 +40,4 @@
<Analyzer Remove="@(Analyzer)" />
</ItemGroup>
</Target>
<ItemGroup>
<TrimmerRootAssembly Include="mscorlib" />
<TrimmerRootAssembly Include="netstandard" />
<TrimmerRootAssembly Include="System.IO.Pipes" />
</ItemGroup>
</Project>

View File

@@ -58,9 +58,4 @@
<Analyzer Remove="@(Analyzer)" />
</ItemGroup>
</Target>
<ItemGroup>
<TrimmerRootAssembly Include="mscorlib" />
<TrimmerRootAssembly Include="netstandard" />
<TrimmerRootAssembly Include="System.IO.Pipes" />
</ItemGroup>
</Project>

View File

@@ -99,13 +99,13 @@ function Test-Command
Write-Host "Testing mods..." -ForegroundColor Cyan
Write-Host "Testing Tiberian Sun mod MiniYAML..." -ForegroundColor Cyan
InvokeCommand "$utilityPath ts --check-yaml"
Invoke-Expression "$utilityPath ts --check-yaml"
Write-Host "Testing Dune 2000 mod MiniYAML..." -ForegroundColor Cyan
InvokeCommand "$utilityPath d2k --check-yaml"
Invoke-Expression "$utilityPath d2k --check-yaml"
Write-Host "Testing Tiberian Dawn mod MiniYAML..." -ForegroundColor Cyan
InvokeCommand "$utilityPath cnc --check-yaml"
Invoke-Expression "$utilityPath cnc --check-yaml"
Write-Host "Testing Red Alert mod MiniYAML..." -ForegroundColor Cyan
InvokeCommand "$utilityPath ra --check-yaml"
Invoke-Expression "$utilityPath ra --check-yaml"
}
function Check-Command
@@ -120,10 +120,10 @@ function Check-Command
if ((CheckForUtility) -eq 0)
{
Write-Host "Checking for explicit interface violations..." -ForegroundColor Cyan
InvokeCommand "$utilityPath all --check-explicit-interfaces"
Invoke-Expression "$utilityPath all --check-explicit-interfaces"
Write-Host "Checking for incorrect conditional trait interface overrides..." -ForegroundColor Cyan
InvokeCommand "$utilityPath all --check-conditional-trait-interface-overrides"
Invoke-Expression "$utilityPath all --check-conditional-trait-interface-overrides"
}
}
@@ -201,20 +201,6 @@ function WaitForInput
}
}
function InvokeCommand
{
param($expression)
# $? is the return value of the called expression
# Invoke-Expression itself will always succeed, even if the invoked expression fails
# So temporarily store the return value in $success
$expression += '; $success = $?'
Invoke-Expression $expression
if ($success -eq $False)
{
exit 1
}
}
###############################################################
############################ Main #############################
###############################################################

View File

@@ -0,0 +1,3 @@
english:
english: English

View File

@@ -27,8 +27,8 @@ Actors:
Rules:
World:
-SpawnStartingUnits:
-MapStartingLocations:
-SpawnMPUnits:
-MPStartLocations:
-CrateSpawner:
MusicPlaylist:
BackgroundMusic: map1

View File

@@ -7,8 +7,8 @@ World:
SpawnInterval: 125
CrateActors: unitcrate
InitialSpawnDelay: 0
-SpawnStartingUnits:
-MapStartingLocations:
-SpawnMPUnits:
-MPStartLocations:
MapBuildRadius:
AllyBuildRadiusCheckboxLocked: True
AllyBuildRadiusCheckboxEnabled: False

View File

@@ -140,6 +140,9 @@ Notifications:
Music:
cnc|audio/music.yaml
Translations:
cnc|languages/english.yaml
Hotkeys:
common|hotkeys/game.yaml
common|hotkeys/observer.yaml

View File

@@ -1,6 +1,6 @@
World:
-SpawnStartingUnits:
-MapStartingLocations:
-SpawnMPUnits:
-MPStartLocations:
-CrateSpawner:
ObjectivesPanel:
PanelName: MISSION_OBJECTIVES

View File

@@ -668,8 +668,8 @@
ActorPreviewPlaceBuildingPreview:
OverridePalette: placebuilding
SoundOnDamageTransition:
DamagedSounds: xplobig4.aud
DestroyedSounds: crumble.aud, xplobig4.aud
DamagedSounds: xplos.aud
DestroyedSounds: crumble.aud
WithSpriteBody:
Explodes:
Type: Footprint

View File

@@ -193,51 +193,51 @@ World:
ShortGameCheckboxDisplayOrder: 2
TechLevelDropdownDisplayOrder: 2
GameSpeedDropdownDisplayOrder: 3
MapStartingLocations:
MPStartLocations:
SeparateTeamSpawnsCheckboxDisplayOrder: 6
CreateMapPlayers:
StartingUnits@mcvonly:
CreateMPPlayers:
MPStartUnits@mcvonly:
Class: none
ClassName: MCV Only
Factions: gdi, nod
BaseActor: mcv
StartingUnits@defaultgdia:
MPStartUnits@defaultgdia:
Class: light
ClassName: Light Support
Factions: gdi
BaseActor: mcv
SupportActors: e1,e1,e1,e1,e1,e3,e3,jeep
StartingUnits@defaultnoda:
MPStartUnits@defaultnoda:
Class: light
ClassName: Light Support
Factions: nod
BaseActor: mcv
SupportActors: e1,e1,e1,e1,e1,e1,e3,e3,bggy
StartingUnits@heavynoda:
MPStartUnits@heavynoda:
Class: heavy
ClassName: Heavy Support
Factions: nod
BaseActor: mcv
SupportActors: e1,e1,e1,e1,e3,e3,ltnk,ltnk,ftnk
StartingUnits@heavynodb:
MPStartUnits@heavynodb:
Class: heavy
ClassName: Heavy Support
Factions: nod
BaseActor: mcv
SupportActors: e1,e1,e1,e1,e1,e3,e3,e3,ftnk,ftnk
StartingUnits@heavygdia:
MPStartUnits@heavygdia:
Class: heavy
ClassName: Heavy Support
Factions: gdi
BaseActor: mcv
SupportActors: e1,e1,e1,e1,e3,e3,jeep,mtnk,mtnk
StartingUnits@heavygdib:
MPStartUnits@heavygdib:
Class: heavy
ClassName: Heavy Support
Factions: gdi
BaseActor: mcv
SupportActors: e1,e1,e1,e1,e1,e2,e2,e2,e3,e3,apc,mtnk
SpawnStartingUnits:
SpawnMPUnits:
DropdownDisplayOrder: 0
CrateSpawner:
Minimum: 1

View File

@@ -40,7 +40,6 @@
120mm:
Inherits: ^BallisticWeapon
Report: tnkfire4.aud
120mmDual:
Inherits: ^BallisticWeapon

View File

@@ -103,11 +103,6 @@ Background@ASSETBROWSER_PANEL:
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
AspectRatio: 1
Model@VOXEL:
Width: PARENT_RIGHT
Height: PARENT_BOTTOM
Palette: colorpicker
PlayerPalette: colorpicker
Label@ERROR:
Y: 1
X: 5
@@ -194,55 +189,6 @@ Background@ASSETBROWSER_PANEL:
Height: 25
Font: TinyBold
Align: Left
Container@VOXEL_SELECTOR:
X: 60
Y: 425
Children:
Label@ROLL:
X: 140
Y: 1
Width: 40
Height: 25
Font: TinyBold
Align: Left
Text: Roll
Slider@ROLL_SLIDER:
X: 165
Y: 3
Width: 100
Height: 20
MinimumValue: 1
MaximumValue: 1023
Label@PITCH:
X: 310
Y: 1
Width: 40
Height: 25
Font: TinyBold
Align: Left
Text: Pitch
Slider@PITCH_SLIDER:
X: 335
Y: 3
Width: 100
Height: 20
MinimumValue: 1
MaximumValue: 1023
Label@YAW:
X: 480
Y: 1
Width: 40
Height: 25
Font: TinyBold
Align: Left
Text: Yaw
Slider@YAW_SLIDER:
X: 505
Y: 3
Width: 100
Height: 20
MinimumValue: 1
MaximumValue: 1023
Button@CLOSE_BUTTON:
Key: escape
X: PARENT_RIGHT - 180

View File

@@ -0,0 +1,2 @@
english:
english: English

View File

@@ -4,8 +4,8 @@ Player:
World:
-CrateSpawner:
-SpawnStartingUnits:
-MapStartingLocations:
-SpawnMPUnits:
-MPStartLocations:
ResourceType@Spice:
ValuePerUnit: 0
ActorSpawnManager:

View File

@@ -7,4 +7,3 @@ Metrics:
FactionSuffix-smuggler: ordos
FactionSuffix-mercenary: ordos
TextfieldColorHighlight: 7f4d29
SystemMessageLabel: Mentat

View File

@@ -127,6 +127,9 @@ Notifications:
Music:
d2k|audio/music.yaml
Translations:
d2k|languages/english.yaml
Hotkeys:
common|hotkeys/game.yaml
common|hotkeys/observer.yaml

View File

@@ -16,8 +16,8 @@ Player:
World:
-CrateSpawner:
-SpawnStartingUnits:
-MapStartingLocations:
-SpawnMPUnits:
-MPStartLocations:
ObjectivesPanel:
PanelName: MISSION_OBJECTIVES
ActorSpawnManager:

View File

@@ -166,15 +166,15 @@ World:
ShortGameCheckboxDisplayOrder: 2
TechLevelDropdownDisplayOrder: 2
GameSpeedDropdownDisplayOrder: 3
CreateMapPlayers:
MapStartingLocations:
CreateMPPlayers:
MPStartLocations:
SeparateTeamSpawnsCheckboxDisplayOrder: 6
StartingUnits@mcv:
MPStartUnits@mcv:
Class: none
ClassName: MCV Only
BaseActor: mcv
Factions: atreides, ordos, harkonnen
StartingUnits@lightatreides:
MPStartUnits@lightatreides:
Class: light
ClassName: Light Support
Factions: atreides
@@ -182,7 +182,7 @@ World:
SupportActors: light_inf, light_inf, light_inf, trooper, grenadier, trike, quad
InnerSupportRadius: 3
OuterSupportRadius: 5
StartingUnits@lightharkonnen:
MPStartUnits@lightharkonnen:
Class: light
ClassName: Light Support
Factions: harkonnen
@@ -190,7 +190,7 @@ World:
SupportActors: light_inf, light_inf, light_inf, trooper, trooper, trike, quad
InnerSupportRadius: 3
OuterSupportRadius: 5
StartingUnits@lightordos:
MPStartUnits@lightordos:
Class: light
ClassName: Light Support
Factions: ordos
@@ -198,7 +198,7 @@ World:
SupportActors: light_inf, light_inf, light_inf, trooper, engineer, raider, quad
InnerSupportRadius: 3
OuterSupportRadius: 5
StartingUnits@heavyatreides:
MPStartUnits@heavyatreides:
Class: heavy
ClassName: Heavy Support
Factions: atreides
@@ -206,7 +206,7 @@ World:
SupportActors: light_inf, light_inf, light_inf, trooper, grenadier, trike, combat_tank_a, missile_tank
InnerSupportRadius: 3
OuterSupportRadius: 5
StartingUnits@heavyharkonnen:
MPStartUnits@heavyharkonnen:
Class: heavy
ClassName: Heavy Support
Factions: harkonnen
@@ -214,7 +214,7 @@ World:
SupportActors: light_inf, light_inf, light_inf, trooper, engineer, quad, combat_tank_h, siege_tank
InnerSupportRadius: 3
OuterSupportRadius: 5
StartingUnits@heavyordos:
MPStartUnits@heavyordos:
Class: heavy
ClassName: Heavy Support
Factions: ordos
@@ -222,7 +222,7 @@ World:
SupportActors: light_inf, light_inf, light_inf, trooper, engineer, raider, combat_tank_o, missile_tank
InnerSupportRadius: 3
OuterSupportRadius: 5
SpawnStartingUnits:
SpawnMPUnits:
DropdownDisplayOrder: 1
PathFinder:
ValidateOrder:

View File

@@ -46,9 +46,9 @@ MedicVoice:
MechanicVoice:
Voices:
Select: mhuh1,mhowdy1,mlaff1
Move: mboss1,mhear1,myes1,mrise1
Action: mhotdig1,mwrench1,myeehaw1
Select: mhuh1,mhowdy1,myes1,mrise1
Move: mboss1,mhear1
Action: mhotdig1,mwrench1
Die: dedman1,dedman2,dedman3,dedman4,dedman5,dedman7,dedman8
Burned: dedman10
Zapped: dedman6
@@ -117,8 +117,8 @@ EinsteinVoice:
ShokVoice:
Voices:
Select: jjuice1,jjump1,jyes1
Move: jdance1,jchrge1,jpower1
Select: jchrge1,jjuice1,jjump1,jpower1
Move: jdance1,jyes1
Attack: jburn1,jcrisp1,jshock1,jlight1
Die: dedman1,dedman2,dedman3,dedman4,dedman5,dedman7,dedman8
Burned: dedman10

View File

@@ -0,0 +1,2 @@
english:
english: English

View File

@@ -3,7 +3,7 @@ World:
CheckboxEnabled: False
CheckboxLocked: True
CheckboxVisible: False
-SpawnStartingUnits:
-SpawnMPUnits:
MapBuildRadius:
AllyBuildRadiusCheckboxLocked: True
AllyBuildRadiusCheckboxEnabled: False
@@ -15,7 +15,7 @@ World:
TechLevelDropdownLocked: True
TechLevelDropdownVisible: False
TechLevel: unrestricted
MapStartingLocations:
MPStartLocations:
SeparateTeamSpawnsCheckboxVisible: false
Locomotor@LIGHTTRACKED:
WaitAverage: 1

Some files were not shown because too many files have changed in this diff Show More