diff --git a/CHANGELOG b/CHANGELOG index 018f756dea..7d92929a72 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -16,8 +16,9 @@ NEW: Added a setting for team health bar colors. Asset Browser: Fixed crashes when trying to load invalid filenames or sprites with just 1 frame. - Added support for browsing the folders for R8 files. + Added support for all sprite types. Added palette chooser and colorpicker dropdown boxes. + Overhauled layout. Red Alert: Added MAD Tank. Fixed a crash in Monster Tank Madness. @@ -86,6 +87,10 @@ NEW: Fixed corrupted replays (which would immediately desync). Removed runtime mod merging. Added support for map scripting with Lua. + Overhauled sprite loading code. + Improved error message when loading corrupted sprites. + Rewritten shp(ts) parser makes more efficient use of texture space. + Added support for the dune 2 shp format. Build system and packages: Added GeoIP to Makefile so it is installed properly. Added desktop shortcut creation support to the Makefile and Windows installer. @@ -113,7 +118,13 @@ NEW: Added InvalidTargets property to weapons. Added modifier support for build palette hotkeys. The Requires: option for inheriting from a parent mod has been removed. Mods can directly reference the parent mod files instead. - Icons are now defined in Sequences not Rules. + Icons definitions have moved from the unit's rules to its sequence. + Mouse cursors (cursors.yaml) must now specify their file extension. + OpenRA.Utility --png will now generate a set of frames for any sprite type [shp(td)/shp(ts)/shp(d2)/r8/tmp(td)/tmp(ra)]. + OpenRA.Utility --shp now requires a list of frames to be combined into a shp. + Removed Utility --tmp-png, --r8, --fromd2 commands (use --png instead). + Removed Asset Browser file extraction / conversion (use the Utility instead). + Unified sprite loading allows any sprite type to be used anywhere: shp can now be used for terrain, and tmp for units. 20130915: All mods: diff --git a/Makefile b/Makefile index eb5c4a81fa..aec7f8ba0c 100644 --- a/Makefile +++ b/Makefile @@ -159,8 +159,8 @@ STD_MOD_DEPS = $(STD_MOD_LIBS) $(ralint_TARGET) mod_ra_SRCS := $(shell find OpenRA.Mods.RA/ -iname '*.cs') mod_ra_TARGET = mods/ra/OpenRA.Mods.RA.dll mod_ra_KIND = library -mod_ra_DEPS = $(STD_MOD_DEPS) $(utility_TARGET) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET) -mod_ra_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(utility_TARGET) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET) +mod_ra_DEPS = $(STD_MOD_DEPS) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET) +mod_ra_LIBS = $(COMMON_LIBS) $(STD_MOD_LIBS) $(geoip_TARGET) $(irc_TARGET) $(lua_TARGET) PROGRAMS += mod_ra mod_ra: $(mod_ra_TARGET) diff --git a/OpenRA.Editor/OpenRA.Editor.csproj b/OpenRA.Editor/OpenRA.Editor.csproj index 166adf6e68..be2dd5e5fa 100644 --- a/OpenRA.Editor/OpenRA.Editor.csproj +++ b/OpenRA.Editor/OpenRA.Editor.csproj @@ -165,6 +165,7 @@ Component + diff --git a/OpenRA.Editor/RenderUtils.cs b/OpenRA.Editor/RenderUtils.cs index f7b6871521..2d29595e8b 100644 --- a/OpenRA.Editor/RenderUtils.cs +++ b/OpenRA.Editor/RenderUtils.cs @@ -8,8 +8,10 @@ */ #endregion +using System.Collections; using System.Drawing; using System.Drawing.Imaging; +using System.Linq; using OpenRA.FileFormats; using OpenRA.Traits; @@ -17,11 +19,11 @@ namespace OpenRA.Editor { static class RenderUtils { - static Bitmap RenderShp(ShpReader shp, Palette p) + static Bitmap RenderShp(ISpriteSource shp, Palette p) { - var frame = shp[0]; + var frame = shp.Frames.First(); - var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); + var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed); bitmap.Palette = p.AsSystemPalette(); @@ -33,9 +35,9 @@ namespace OpenRA.Editor byte* q = (byte*)data.Scan0.ToPointer(); var stride2 = data.Stride; - for (var i = 0; i < shp.Width; i++) - for (var j = 0; j < shp.Height; j++) - q[j * stride2 + i] = frame.Image[i + shp.Width * j]; + for (var i = 0; i < frame.Size.Width; i++) + for (var j = 0; j < frame.Size.Height; j++) + q[j * stride2 + i] = frame.Data[i + frame.Size.Width * j]; } bitmap.UnlockBits(data); @@ -78,10 +80,11 @@ namespace OpenRA.Editor var image = info.SpriteNames[0]; using (var s = FileSystem.OpenWithExts(image, exts)) { - var shp = new ShpReader(s); - var frame = shp[shp.ImageCount - 1]; + // TODO: Do this properly + var shp = new ShpReader(s) as ISpriteSource; + var frame = shp.Frames.Last(); - var bitmap = new Bitmap(shp.Width, shp.Height, PixelFormat.Format8bppIndexed); + var bitmap = new Bitmap(frame.Size.Width, frame.Size.Height, PixelFormat.Format8bppIndexed); bitmap.Palette = p.AsSystemPalette(); var data = bitmap.LockBits(bitmap.Bounds(), ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); @@ -91,13 +94,13 @@ namespace OpenRA.Editor byte* q = (byte*)data.Scan0.ToPointer(); var stride = data.Stride; - for (var i = 0; i < shp.Width; i++) - for (var j = 0; j < shp.Height; j++) - q[j * stride + i] = frame.Image[i + shp.Width * j]; + for (var i = 0; i < frame.Size.Width; i++) + for (var j = 0; j < frame.Size.Height; j++) + q[j * stride + i] = frame.Data[i + frame.Size.Width * j]; } bitmap.UnlockBits(data); - return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.ImageCount - 1 }; + return new ResourceTemplate { Bitmap = bitmap, Info = info, Value = shp.Frames.Count() - 1 }; } } } diff --git a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs b/OpenRA.Editor/TileSetRenderer.cs similarity index 71% rename from OpenRA.FileFormats/Graphics/TileSetRenderer.cs rename to OpenRA.Editor/TileSetRenderer.cs index 98c7459438..c1b1482b1f 100644 --- a/OpenRA.FileFormats/Graphics/TileSetRenderer.cs +++ b/OpenRA.Editor/TileSetRenderer.cs @@ -11,9 +11,11 @@ using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; +using System.IO; using System.Linq; +using OpenRA.FileFormats; -namespace OpenRA.FileFormats +namespace OpenRA.Editor { public class TileSetRenderer { @@ -21,20 +23,31 @@ namespace OpenRA.FileFormats Dictionary> templates; public Size TileSize; - List LoadTemplate(string filename, string[] exts, Cache r8cache, int[] frames) + List LoadTemplate(string filename, string[] exts, Dictionary sourceCache, int[] frames) { - if (exts.Contains(".R8") && FileSystem.Exists(filename + ".R8")) + ISpriteSource source; + if (!sourceCache.ContainsKey(filename)) { - var data = new List(); + using (var s = FileSystem.OpenWithExts(filename, exts)) + source = SpriteSource.LoadSpriteSource(s, filename); - foreach (var f in frames) - data.Add(f >= 0 ? r8cache[filename][f].Image : null); + if (source.CacheWhenLoadingTileset) + sourceCache.Add(filename, source); + } + else + source = sourceCache[filename]; - return data; + if (frames != null) + { + var ret = new List(); + var srcFrames = source.Frames.ToArray(); + foreach (var i in frames) + ret.Add(srcFrames[i].Data); + + return ret; } - using (var s = FileSystem.OpenWithExts(filename, exts)) - return new Terrain(s).TileBitmapBytes; + return source.Frames.Select(f => f.Data).ToList(); } public TileSetRenderer(TileSet tileset, Size tileSize) @@ -43,9 +56,9 @@ namespace OpenRA.FileFormats this.TileSize = tileSize; templates = new Dictionary>(); - var r8cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8"))); + var sourceCache = new Dictionary(); foreach (var t in TileSet.Templates) - templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, r8cache, t.Value.Frames)); + templates.Add(t.Key, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames)); } public Bitmap RenderTemplate(ushort id, Palette p) diff --git a/OpenRA.FileFormats/Graphics/Dune2ShpReader.cs b/OpenRA.FileFormats/Graphics/Dune2ShpReader.cs deleted file mode 100644 index 3951a50458..0000000000 --- a/OpenRA.FileFormats/Graphics/Dune2ShpReader.cs +++ /dev/null @@ -1,144 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 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. For more information, - * see COPYING. - */ -#endregion - -using System.Collections; -using System.Collections.Generic; -using System.Drawing; -using System.IO; - -namespace OpenRA.FileFormats -{ - public enum Dune2ImageFlags : int - { - F80_F2 = 0, - F2 = 2, - L16_F80_F2_1 = 1, - L16_F80_F2_2 = 3, - Ln_F80_F2 = 5 - } - - public class Dune2ImageHeader - { - public readonly Dune2ImageFlags Flags; - public readonly int Width; - public readonly int Height; - public readonly int Slices; - public readonly int FileSize; - public readonly int DataSize; - - public readonly byte[] LookupTable; - public byte[] Image; - - public Dune2ImageHeader(Stream s) - { - Flags = (Dune2ImageFlags)s.ReadUInt16(); - Slices = s.ReadUInt8(); - Width = s.ReadUInt16(); - Height = s.ReadUInt8(); - FileSize = s.ReadUInt16(); - DataSize = s.ReadUInt16(); - - if (Flags == Dune2ImageFlags.L16_F80_F2_1 || - Flags == Dune2ImageFlags.L16_F80_F2_2 || - Flags == Dune2ImageFlags.Ln_F80_F2) - { - int n = Flags == Dune2ImageFlags.Ln_F80_F2 ? s.ReadUInt8() : (byte)16; - LookupTable = new byte[n]; - for (int i = 0; i < n; i++) - LookupTable[i] = s.ReadUInt8(); - } - else - { - LookupTable = new byte[256]; - for (int i = 0; i < 256; i++) - LookupTable[i] = (byte)i; - LookupTable[1] = 0x7f; - LookupTable[2] = 0x7e; - LookupTable[3] = 0x7d; - LookupTable[4] = 0x7c; - } - } - - public Size Size - { - get { return new Size(Width, Height); } - } - } - - public class Dune2ShpReader : IEnumerable - { - public readonly int ImageCount; - - List headers = new List(); - - public Dune2ShpReader(Stream s) - { - ImageCount = s.ReadUInt16(); - - //Last offset is pointer to end of file. - uint[] offsets = new uint[ImageCount + 1]; - - uint temp = s.ReadUInt32(); - - //If fourth byte in file is non-zero, the offsets are two bytes each. - bool twoByteOffsets = (temp & 0xFF0000) > 0; - if (twoByteOffsets) - { - offsets[0] = ((temp & 0xFFFF0000) >> 16) + 2; //Offset does not account for image count bytes - offsets[1] = (temp & 0xFFFF) + 2; - } - else - offsets[0] = temp + 2; - - for (int i = twoByteOffsets ? 2 : 1; i < ImageCount + 1; i++) - offsets[i] = (twoByteOffsets ? s.ReadUInt16() : s.ReadUInt32()) + 2; - - for (int i = 0; i < ImageCount; i++) - { - s.Seek(offsets[i], SeekOrigin.Begin); - Dune2ImageHeader header = new Dune2ImageHeader(s); - byte[] imgData = s.ReadBytes(header.FileSize); - header.Image = new byte[header.Height * header.Width]; - - //Decode image data - if (header.Flags != Dune2ImageFlags.F2) - { - byte[] tempData = new byte[header.DataSize]; - Format80.DecodeInto(imgData, tempData); - Format2.DecodeInto(tempData, header.Image); - } - else - Format2.DecodeInto(imgData, header.Image); - - //Lookup values in lookup table - if (header.LookupTable != null) - for (int j = 0; j < header.Image.Length; j++) - header.Image[j] = header.LookupTable[header.Image[j]]; - - headers.Add(header); - } - } - - public Dune2ImageHeader this[int index] - { - get { return headers[index]; } - } - - public IEnumerator GetEnumerator() - { - return headers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - } -} diff --git a/OpenRA.FileFormats/Graphics/R8Reader.cs b/OpenRA.FileFormats/Graphics/R8Reader.cs index 132c48a436..edc95b2cf2 100644 --- a/OpenRA.FileFormats/Graphics/R8Reader.cs +++ b/OpenRA.FileFormats/Graphics/R8Reader.cs @@ -12,17 +12,16 @@ using System.Collections; using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Linq; namespace OpenRA.FileFormats { - public class R8Image + class R8Image : ISpriteFrame { - public readonly Size Size; - public readonly int2 Offset; - public readonly byte[] Image; - - // Legacy variable. Can be removed when the utility command is made sensible. - public readonly Size FrameSize; + public Size Size { get; private set; } + public Size FrameSize { get; private set; } + public float2 Offset { get; private set; } + public byte[] Data { get; set; } public R8Image(Stream s) { @@ -52,7 +51,7 @@ namespace OpenRA.FileFormats // Skip alignment byte s.ReadUInt8(); - Image = s.ReadBytes(width*height); + Data = s.ReadBytes(width*height); // Ignore palette if (type == 1 && paletteOffset != 0) @@ -60,33 +59,20 @@ namespace OpenRA.FileFormats } } - public class R8Reader : IEnumerable + public class R8Reader : ISpriteSource { - readonly List headers = new List(); + readonly List frames = new List(); + public IEnumerable Frames { get { return frames.Cast(); } } + public bool CacheWhenLoadingTileset { get { return true; } } - public readonly int Frames; + public readonly int ImageCount; public R8Reader(Stream stream) { while (stream.Position < stream.Length) { - headers.Add(new R8Image(stream)); - Frames++; + frames.Add(new R8Image(stream)); + ImageCount++; } } - - public R8Image this[int index] - { - get { return headers[index]; } - } - - public IEnumerator GetEnumerator() - { - return headers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } } } diff --git a/OpenRA.FileFormats/Graphics/ShpD2Reader.cs b/OpenRA.FileFormats/Graphics/ShpD2Reader.cs new file mode 100644 index 0000000000..aa21efc521 --- /dev/null +++ b/OpenRA.FileFormats/Graphics/ShpD2Reader.cs @@ -0,0 +1,115 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 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. For more information, + * see COPYING. + */ +#endregion + +using System.Collections; +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; + +namespace OpenRA.FileFormats +{ + enum Dune2ImageFlags : int + { + F80_F2 = 0, + F2 = 2, + L16_F80_F2_1 = 1, + L16_F80_F2_2 = 3, + Ln_F80_F2 = 5 + } + + class Frame : ISpriteFrame + { + public Size Size { get; private set; } + public Size FrameSize { get { return Size; } } + public float2 Offset { get { return float2.Zero; } } + public byte[] Data { get; set; } + + public Frame(Stream s) + { + var flags = (Dune2ImageFlags)s.ReadUInt16(); + s.Position += 1; + var width = s.ReadUInt16(); + var height = s.ReadUInt8(); + Size = new Size(width, height); + + var frameSize = s.ReadUInt16(); + var dataSize = s.ReadUInt16(); + + byte[] table; + if (flags == Dune2ImageFlags.L16_F80_F2_1 || + flags == Dune2ImageFlags.L16_F80_F2_2 || + flags == Dune2ImageFlags.Ln_F80_F2) + { + var n = flags == Dune2ImageFlags.Ln_F80_F2 ? s.ReadUInt8() : (byte)16; + table = new byte[n]; + for (var i = 0; i < n; i++) + table[i] = s.ReadUInt8(); + } + else + { + table = new byte[256]; + for (var i = 0; i < 256; i++) + table[i] = (byte)i; + table[1] = 0x7f; + table[2] = 0x7e; + table[3] = 0x7d; + table[4] = 0x7c; + } + + // Subtract header size + var imgData = s.ReadBytes(frameSize - 10); + Data = new byte[width * height]; + + // Decode image data + if (flags != Dune2ImageFlags.F2) + { + var tempData = new byte[dataSize]; + Format80.DecodeInto(imgData, tempData); + Format2.DecodeInto(tempData, Data); + } + else + Format2.DecodeInto(imgData, Data); + + // Lookup values in lookup table + for (var j = 0; j < Data.Length; j++) + Data[j] = table[Data[j]]; + } + } + + public class ShpD2Reader : ISpriteSource + { + List headers = new List(); + public IEnumerable Frames { get { return headers.Cast(); } } + public bool CacheWhenLoadingTileset { get { return false; } } + + public ShpD2Reader(Stream s) + { + var imageCount = s.ReadUInt16(); + + // Last offset is pointer to end of file. + var offsets = new uint[imageCount + 1]; + var temp = s.ReadUInt32(); + + // If fourth byte in file is non-zero, the offsets are two bytes each. + var twoByteOffset = (temp & 0xFF0000) > 0; + s.Position = 2; + + for (var i = 0; i < imageCount + 1; i++) + offsets[i] = (twoByteOffset ? s.ReadUInt16() : s.ReadUInt32()) + 2; + + for (var i = 0; i < imageCount; i++) + { + s.Position = offsets[i]; + headers.Add(new Frame(s)); + } + } + } +} diff --git a/OpenRA.FileFormats/Graphics/ShpReader.cs b/OpenRA.FileFormats/Graphics/ShpReader.cs index 0795b2696a..b211b94751 100644 --- a/OpenRA.FileFormats/Graphics/ShpReader.cs +++ b/OpenRA.FileFormats/Graphics/ShpReader.cs @@ -1,6 +1,6 @@ #region Copyright & License Information /* - * Copyright 2007-2011 The OpenRA Developers (see AUTHORS) + * Copyright 2007-2013 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. For more information, @@ -15,153 +15,180 @@ using System.Linq; namespace OpenRA.FileFormats { - public class ImageHeader + enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 } + + class ImageHeader : ISpriteFrame { - public uint Offset; + public Size Size { get { return reader.Size; } } + public Size FrameSize { get { return reader.Size; } } + public float2 Offset { get { return float2.Zero; } } + public byte[] Data { get; set; } + + public uint FileOffset; public Format Format; public uint RefOffset; public Format RefFormat; public ImageHeader RefImage; - public byte[] Image; - + ShpReader reader; + // Used by ShpWriter public ImageHeader() { } - public ImageHeader( BinaryReader reader ) + public ImageHeader(Stream stream, ShpReader reader) { - var data = reader.ReadUInt32(); - Offset = data & 0xffffff; + this.reader = reader; + var data = stream.ReadUInt32(); + FileOffset = data & 0xffffff; Format = (Format)(data >> 24); - RefOffset = reader.ReadUInt16(); - RefFormat = (Format)reader.ReadUInt16(); + RefOffset = stream.ReadUInt16(); + RefFormat = (Format)stream.ReadUInt16(); } - public static readonly int SizeOnDisk = 8; - public void WriteTo(BinaryWriter writer) { - writer.Write(Offset | ((uint)Format << 24)); + writer.Write(FileOffset | ((uint)Format << 24)); writer.Write((ushort)RefOffset); writer.Write((ushort)RefFormat); } } - public enum Format { Format20 = 0x20, Format40 = 0x40, Format80 = 0x80 } - - public class ShpReader + public class ShpReader : ISpriteSource { - public readonly int ImageCount; - public readonly ushort Width; - public readonly ushort Height; - - public Size Size { get { return new Size(Width, Height); } } - readonly List headers = new List(); + public IEnumerable Frames { get { return headers.Cast(); } } + public bool CacheWhenLoadingTileset { get { return false; } } + public readonly Size Size; int recurseDepth = 0; + readonly int imageCount; public ShpReader(Stream stream) { - using (var reader = new BinaryReader(stream)) + imageCount = stream.ReadUInt16(); + stream.Position += 4; + var width = stream.ReadUInt16(); + var height = stream.ReadUInt16(); + Size = new Size(width, height); + + stream.Position += 4; + for (var i = 0; i < imageCount; i++) + headers.Add(new ImageHeader(stream, this)); + + // Skip eof and zero headers + stream.Position += 16; + + var offsets = headers.ToDictionary(h => h.FileOffset, h => h); + for (var i = 0; i < imageCount; i++) { - ImageCount = reader.ReadUInt16(); - reader.ReadUInt16(); - reader.ReadUInt16(); - Width = reader.ReadUInt16(); - Height = reader.ReadUInt16(); - reader.ReadUInt32(); + var h = headers[i]; + if (h.Format == Format.Format20) + h.RefImage = headers[i - 1]; - for (int i = 0 ; i < ImageCount ; i++) - headers.Add(new ImageHeader(reader)); - - new ImageHeader(reader); // end-of-file header - new ImageHeader(reader); // all-zeroes header - - var offsets = headers.ToDictionary(h => h.Offset, h =>h); - - for (int i = 0 ; i < ImageCount ; i++) - { - var h = headers[ i ]; - if (h.Format == Format.Format20) - h.RefImage = headers[i - 1]; - - else if (h.Format == Format.Format40) - if (!offsets.TryGetValue(h.RefOffset, out h.RefImage)) - throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.Offset, h.RefOffset)); - } - - foreach (ImageHeader h in headers) - Decompress(stream, h); + else if (h.Format == Format.Format40 && !offsets.TryGetValue(h.RefOffset, out h.RefImage)) + throw new InvalidDataException("Reference doesnt point to image data {0}->{1}".F(h.FileOffset, h.RefOffset)); } + + foreach (var h in headers) + Decompress(stream, h); } - public ImageHeader this[int index] + static byte[] ReadCompressedData(Stream stream, ImageHeader h) { - get { return headers[index]; } + stream.Position = h.FileOffset; + + // Actually, far too big. There's no length field with the correct length though :( + var compressedLength = (int)(stream.Length - stream.Position); + var compressedBytes = new byte[compressedLength]; + stream.Read(compressedBytes, 0, compressedLength); + + return compressedBytes; } void Decompress(Stream stream, ImageHeader h) { - if (recurseDepth > ImageCount) + if (recurseDepth > imageCount) throw new InvalidDataException("Format20/40 headers contain infinite loop"); - switch(h.Format) + switch (h.Format) { case Format.Format20: case Format.Format40: + { + if (h.RefImage.Data == null) { - if (h.RefImage.Image == null) - { - ++recurseDepth; - Decompress(stream, h.RefImage); - --recurseDepth; - } + ++recurseDepth; + Decompress(stream, h.RefImage); + --recurseDepth; + } + + h.Data = CopyImageData(h.RefImage.Data); + Format40.DecodeInto(ReadCompressedData(stream, h), h.Data); + break; + } - h.Image = CopyImageData(h.RefImage.Image); - Format40.DecodeInto(ReadCompressedData(stream, h), h.Image); - break; - } case Format.Format80: - { - var imageBytes = new byte[Width * Height]; - Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes); - h.Image = imageBytes; - break; - } + { + var imageBytes = new byte[Size.Width * Size.Height]; + Format80.DecodeInto(ReadCompressedData(stream, h), imageBytes); + h.Data = imageBytes; + break; + } + default: throw new InvalidDataException(); } } - static byte[] ReadCompressedData(Stream stream, ImageHeader h) - { - stream.Position = h.Offset; - // TODO: Actually, far too big. There's no length field with the correct length though :( - var compressedLength = (int)(stream.Length - stream.Position); - - var compressedBytes = new byte[ compressedLength ]; - stream.Read( compressedBytes, 0, compressedLength ); - - return compressedBytes; - } - byte[] CopyImageData(byte[] baseImage) { - var imageData = new byte[Width * Height]; - for (int i = 0 ; i < Width * Height ; i++) + var imageData = new byte[Size.Width * Size.Height]; + for (var i = 0; i < Size.Width * Size.Height; i++) imageData[i] = baseImage[i]; return imageData; } - public IEnumerable Frames { get { return headers; } } - public static ShpReader Load(string filename) { using (var s = File.OpenRead(filename)) return new ShpReader(s); } + + public static void Write(Stream s, Size size, IEnumerable frames) + { + var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray(); + + // note: end-of-file and all-zeroes headers + var dataOffset = 14 + (compressedFrames.Length + 2) * 8; + + using (var bw = new BinaryWriter(s)) + { + bw.Write((ushort)compressedFrames.Length); + bw.Write((ushort)0); + bw.Write((ushort)0); + bw.Write((ushort)size.Width); + bw.Write((ushort)size.Height); + bw.Write((uint)0); + + foreach (var f in compressedFrames) + { + var ih = new ImageHeader { Format = Format.Format80, FileOffset = (uint)dataOffset }; + dataOffset += f.Length; + + ih.WriteTo(bw); + } + + var eof = new ImageHeader { FileOffset = (uint)dataOffset }; + eof.WriteTo(bw); + + var allZeroes = new ImageHeader { }; + allZeroes.WriteTo(bw); + + foreach (var f in compressedFrames) + bw.Write(f); + } + } } } diff --git a/OpenRA.FileFormats/Graphics/ShpTSReader.cs b/OpenRA.FileFormats/Graphics/ShpTSReader.cs index 68cfbb918b..90c45aa85a 100644 --- a/OpenRA.FileFormats/Graphics/ShpTSReader.cs +++ b/OpenRA.FileFormats/Graphics/ShpTSReader.cs @@ -1,615 +1,112 @@ #region Copyright & License Information /* * Copyright 2007-2013 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made + * 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. For more information, - * see LICENSE. + * see COPYING. */ #endregion -using System; -using System.Collections; using System.Collections.Generic; using System.Drawing; using System.IO; +using System.Linq; namespace OpenRA.FileFormats { - - public struct Header + class FrameHeader : ISpriteFrame { - public ushort A; - // Unknown - // Width and Height of the images - public ushort Width; - public ushort Height; - public ushort NumImages; - } + public Size Size { get; private set; } + public Size FrameSize { get; private set; } + public float2 Offset { get; private set; } + public byte[] Data { get; set; } - public class HeaderImage - { - public ushort x; - public ushort y; - public ushort cx; - public ushort cy; - // cx and cy are width n height of stored image - public byte compression; - public byte[] align; - public byte[] transparent; - public int zero; - public int offset; - public byte[] Image; - } + public readonly uint FileOffset; + public readonly byte Format; - public struct SHPData - { - public HeaderImage HeaderImage; - public byte[] Databuffer; - public byte[] FrameImage; - } - - public struct SHP - { - public Header Header; - public SHPData[] Data; - } - - - public class ShpTSReader : IEnumerable - { - public readonly int ImageCount; - public readonly ushort Width; - public readonly ushort Height; - public readonly ushort Width2; - public readonly ushort Height2; - public int arroff = 0; - public int erri = 0; - public int errj = 0; - public int errk = 0; - public int errl = 0; - - public static int FindNextOffsetFrom(SHP SHP, int Init, int Last) + public FrameHeader(Stream stream, Size frameSize) { - int result; - result = 0; - Last++; - while ((result == 0) && (Init < Last)) - { - result = SHP.Data[Init].HeaderImage.offset; - Init++; - } - return result; + var x = stream.ReadUInt16(); + var y = stream.ReadUInt16(); + var width = stream.ReadUInt16(); + var height = stream.ReadUInt16(); + + Offset = new float2(x + 0.5f * (width - frameSize.Width), y + 0.5f * (height - frameSize.Height)); + Size = new Size(width, height); + FrameSize = frameSize; + + Format = stream.ReadUInt8(); + stream.Position += 11; + FileOffset = stream.ReadUInt32(); } + } - private readonly List headers = new List(); + public class ShpTSReader : ISpriteSource + { + readonly List frames = new List(); + public IEnumerable Frames { get { return frames.Cast(); } } + public bool CacheWhenLoadingTileset { get { return false; } } - public ShpTSReader(Stream s) + public ShpTSReader(Stream stream) { + stream.ReadUInt16(); + var width = stream.ReadUInt16(); + var height = stream.ReadUInt16(); + var size = new Size(width, height); + var frameCount = stream.ReadUInt16(); - SHP SHP = new SHP(); - int FileSize; - int x; - int k = 0; - int l = 0; + for (var i = 0; i < frameCount; i++) + frames.Add(new FrameHeader(stream, size)); - int ImageSize; - int NextOffset; + for (var i = 0; i < frameCount; i++) + { + var f = frames[i]; + if (f.FileOffset == 0) + continue; - byte[] FData; - byte cp; - byte[] Databuffer; + stream.Position = f.FileOffset; - FileSize = (int)s.Length; - // Get Header - SHP.Header.A = s.ReadUInt16(); - SHP.Header.Width = s.ReadUInt16(); - SHP.Header.Height = s.ReadUInt16(); - SHP.Header.NumImages = s.ReadUInt16(); + // Uncompressed + if (f.Format == 1 || f.Format == 0) + f.Data = stream.ReadBytes(f.Size.Width * f.Size.Height); - SHP.Data = new SHPData[SHP.Header.NumImages + 1]; - - ImageCount = SHP.Header.NumImages; - - for (x = 1; x <= SHP.Header.NumImages; x++) + // Uncompressed scanlines + else if (f.Format == 2) { - SHP.Data[x].HeaderImage = new HeaderImage(); - - SHP.Data[x].HeaderImage.x = s.ReadUInt16(); - SHP.Data[x].HeaderImage.y = s.ReadUInt16(); - SHP.Data[x].HeaderImage.cx = s.ReadUInt16(); - SHP.Data[x].HeaderImage.cy = s.ReadUInt16(); - - SHP.Data[x].HeaderImage.compression = s.ReadUInt8(); - SHP.Data[x].HeaderImage.align = s.ReadBytes(3); - s.ReadInt32(); - SHP.Data[x].HeaderImage.zero = s.ReadUInt8(); - SHP.Data[x].HeaderImage.transparent = s.ReadBytes(3); - - SHP.Data[x].HeaderImage.offset = s.ReadInt32(); - - } - - Width = SHP.Header.Width; - Height = SHP.Header.Height; - - for (int i = 0; i < ImageCount; i++) - { - headers.Add(SHP.Data[i+1].HeaderImage); - } - - // Read and decode each image from the file - for (x = 1; x <= SHP.Header.NumImages; x++) - { - headers[x - 1].Image = new byte[(Width * Height)]; - for (int i = 0; i < headers[x - 1].Image.Length; i++) - headers[x - 1].Image[i] = 0; - - FData = new byte[(Width * Height)]; - - // Does it really reads the frame? - if (SHP.Data[x].HeaderImage.offset != 0) + f.Data = new byte[f.Size.Width * f.Size.Height]; + for (var j = 0; j < f.Size.Height; j++) { - try + var length = stream.ReadUInt16() - 2; + stream.Read(f.Data, f.Size.Width * j, length); + } + } + + // RLE-zero compressed scanlines + else if (f.Format == 3) + { + f.Data = new byte[f.Size.Width * f.Size.Height]; + + for (var j = 0; j < f.Size.Height; j++) + { + var k = j * f.Size.Width; + var length = stream.ReadUInt16() - 2; + while (length > 0) { - // Now it checks the compression: - if ((SHP.Data[x].HeaderImage.compression == 3)) - { - // decode it - // Compression 3 - NextOffset = FindNextOffsetFrom(SHP, x + 1, SHP.Header.NumImages); - if (NextOffset != 0) + var b = stream.ReadUInt8(); + length--; + + if (b == 0) { - - ImageSize = NextOffset - SHP.Data[x].HeaderImage.offset; - Databuffer = new byte[ImageSize]; - for (int i = 0; i < ImageSize; i++) - { - s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin); - Databuffer[i] = s.ReadUInt8(); - } - SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)]; - Decode3(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref FileSize); - - k = 0; - l = 0; - for (int i = 0; i < Height; i++) - { - erri = i; - for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++) - { - errj = j; - errl = l; - errk = k; - arroff = i + j + l; - - if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy))) - cp = 0; - else - cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l]; - - FData[i + j + k] = cp; - - if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1)) - l = l + (SHP.Data[x].HeaderImage.cx - 1); - - if (j == (Width - 1)) - k = k + (Width - 1); - } - } - //FData = headers[x - 1].Image; - k = 0; - for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++) - { - for (int j = 0; j < Width; j++) - { - headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k]; - if (j == (Width - 1)) - { - k = k + (Width - 1); - } - } - } - + k += stream.ReadUInt8(); + length--; } else - { - - ImageSize = 0; - ImageSize = FileSize - SHP.Data[x].HeaderImage.offset; - Databuffer = new byte[ImageSize]; - for (int i = 0; i < ImageSize; i++) - { - s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin); - Databuffer[i] = s.ReadUInt8(); - } - SHP.Data[x].Databuffer = new byte[((SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy))]; - - Decode3(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize); - - k = 0; - l = 0; - for (int i = 0; i < Height; i++) - { - erri = i; - for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++) - { - errj = j; - errl = l; - errk = k; - arroff = i + j + l; - - if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy))) - cp = 0; - else - cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l]; - - FData[i + j + k] = cp; - - if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1)) - l = l + (SHP.Data[x].HeaderImage.cx - 1); - - if (j == (Width - 1)) - k = k + (Width - 1); - } - } - //FData = headers[x - 1].Image; - k = 0; - for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++) - { - for (int j = 0; j < Width; j++) - { - headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k]; - if (j == (Width - 1)) - { - k = k + (Width - 1); - } - } - } - } + f.Data[k++] = b; } - else if ((SHP.Data[x].HeaderImage.compression == 2)) - { - NextOffset = FindNextOffsetFrom(SHP, x + 1, SHP.Header.NumImages); - if (NextOffset != 0) - { - ImageSize = NextOffset - SHP.Data[x].HeaderImage.offset; - SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)]; - Databuffer = new byte[ImageSize]; - for (int i = 0; i < ImageSize; i++) - { - s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin); - Databuffer[i] = s.ReadUInt8(); - } - - Decode2(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize); - - k = 0; - l = 0; - for (int i = 0; i < Height; i++) - { - erri = i; - for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++) - { - errj = j; - errl = l; - errk = k; - arroff = i + j + l; - - if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy))) - cp = 0; - else - cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l]; - - FData[i + j + k] = cp; - - if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1)) - l = l + (SHP.Data[x].HeaderImage.cx - 1); - - if (j == (Width - 1)) - k = k + (Width - 1); - } - } - //FData = headers[x - 1].Image; - k = 0; - for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++) - { - for (int j = 0; j < Width; j++) - { - headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k]; - if (j == (Width - 1)) - { - k = k + (Width - 1); - } - } - } - - // Compression 2 - } - else - { - ImageSize = 0; - ImageSize = FileSize - SHP.Data[x].HeaderImage.offset; - Databuffer = new byte[ImageSize]; - for (int i = 0; i < ImageSize; i++) - { - s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin); - Databuffer[i] = s.ReadUInt8(); - } - SHP.Data[x].Databuffer = new byte[((SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy))]; - Decode2(Databuffer, ref SHP.Data[x].Databuffer, SHP.Data[x].HeaderImage.cx, SHP.Data[x].HeaderImage.cy, ref ImageSize); - - k = 0; - l = 0; - for (int i = 0; i < Height; i++) - { - erri = i; - for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++) - { - errj = j; - errl = l; - errk = k; - arroff = i + j + l; - - if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy))) - cp = 0; - else - cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l]; - - FData[i + j + k] = cp; - - if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1)) - l = l + (SHP.Data[x].HeaderImage.cx - 1); - - if (j == (Width - 1)) - k = k + (Width - 1); - } - } - //FData = headers[x - 1].Image; - k = 0; - for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++) - { - for (int j = 0; j < Width; j++) - { - headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k]; - if (j == (Width - 1)) - { - k = k + (Width - 1); - } - } - } - // Compression 2 - } - } - else - { - // Compression 1 - ImageSize = (int)(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy); - Databuffer = new byte[ImageSize]; - for (int i = 0; i < ImageSize; i++) - { - s.Seek(SHP.Data[x].HeaderImage.offset + i, SeekOrigin.Begin); - Databuffer[i] = s.ReadUInt8(); - } - SHP.Data[x].Databuffer = new byte[(SHP.Data[x].HeaderImage.cx * SHP.Data[x].HeaderImage.cy)]; - SHP.Data[x].Databuffer = Databuffer; - - k = 0; - l = 0; - for (int i = 0; i < Height; i++) - { - erri = i; - for (int j = SHP.Data[x].HeaderImage.x; j < Width; j++) - { - errj = j; - errl = l; - errk = k; - arroff = i + j + l; - - if (((j + 1) > (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x)) || ((i + 1) > (SHP.Data[x].HeaderImage.cy))) - cp = 0; - else - cp = SHP.Data[x].Databuffer[i + (j - SHP.Data[x].HeaderImage.x) + l]; - - FData[i + j + k] = cp; - - if (j == (SHP.Data[x].HeaderImage.cx + SHP.Data[x].HeaderImage.x - 1)) - l = l + (SHP.Data[x].HeaderImage.cx - 1); - - if (j == (Width - 1)) - k = k + (Width - 1); - } - } - //FData = headers[x - 1].Image; - k = 0; - for (int i = 0; i < (Height - SHP.Data[x].HeaderImage.y); i++) - { - for (int j = 0; j < Width; j++) - { - headers[x - 1].Image[i + j + k + (Width * SHP.Data[x].HeaderImage.y)] = FData[i + j + k]; - if (j == (Width - 1)) - { - k = k + (Width - 1); - } - } - } - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); } } - // Set the shp's databuffer to the result after decompression - } - //Width = Width2; - //Height = Height2; - } - - public HeaderImage this[int index] - { - get { return headers[index]; } - } - - public static void ReInterpretWordFromBytes(byte Byte1, byte Byte2, ref ushort FullValue) - { - FullValue = (ushort)((Byte2 * 256) + Byte1); - } - - public static void ReInterpretWordFromBytes(byte Byte1, byte Byte2, ref uint FullValue) - { - FullValue = (uint)((Byte2 * 256) + Byte1); - } - - // Compression 3: - public static void Decode3(byte[] Source, ref byte[] Dest, int cx, int cy, ref int max) - { - int SP; - int DP; - int x; - int y; - int Count; - int v; - int maxdp; - ushort Pos; - maxdp = cx * cy; - SP = 0; - DP = 0; - Pos = 0; - try - { - for (y = 1; y <= cy; y++) - { - ReInterpretWordFromBytes(Source[SP], Source[SP + 1], ref Pos); - - Count = Pos - 2; - - SP = SP + 2; - - x = 0; - while (Count > 0) - { - Count = Count - 1; - if ((SP > max) || (DP > maxdp)) - { - break; - } - else - { - // SP has reached max value, exit - v = Source[SP]; - SP++; - if (v != 0) - { - if ((SP > max) || (DP > maxdp)) - { - break; - } - else - { - x++; - Dest[DP] += (byte)v; - } - DP++; - } - else - { - Count -= 1; - v = Source[SP]; - - SP++; - if ((x + v) > cx) - { - v = cx - x; - } - x = x + v; - while (v > 0) - { - if ((SP > max) || (DP > maxdp)) - { - break; - } - else - { - v -= 1; - Dest[DP] = 0; - - } - DP++; - // SP has reached max value, exit - } - } - } - } - if ((SP >= max) || (DP >= maxdp)) - { - return; - } - // SP has reached max value, exit - } - } - - catch (Exception e) - { - Console.WriteLine(e.Message); - } - - } - - public static void Decode2(byte[] Source, ref byte[] Dest, int cx, int cy, ref int max) - { - int SP; - int DP; - int y; - int Count; - int maxdp; - ushort Pos; - maxdp = cx * cy; - SP = 0; - DP = 0; - Pos = 0; - try - { - for (y = 1; y <= cy; y++) - { - ReInterpretWordFromBytes(Source[SP], Source[SP + 1], ref Pos); - Count = Pos - 2; - SP += 2; - while (Count > 0) - { - Count -= 1; - if ((SP > max) || (DP > maxdp)) - { - return; - } - // SP has reached max value, exit - Dest[DP] = Source[SP]; - SP++; - DP++; - } - if ((SP >= max) || (DP >= maxdp)) - { - return; - } - // SP has reached max value, exit - } - } - catch (Exception e) - { - Console.WriteLine(e.Message); } } - - public IEnumerator GetEnumerator() - { - return headers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public Size Size { get { return new Size(Width, Height); } } } -} +} \ No newline at end of file diff --git a/OpenRA.FileFormats/Graphics/ShpWriter.cs b/OpenRA.FileFormats/Graphics/ShpWriter.cs deleted file mode 100644 index 9475f02c68..0000000000 --- a/OpenRA.FileFormats/Graphics/ShpWriter.cs +++ /dev/null @@ -1,56 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 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. For more information, - * see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace OpenRA.FileFormats.Graphics -{ - // format80-only SHP writer - - public static class ShpWriter - { - public static void Write(Stream s, int width, int height, IEnumerable frames) - { - var compressedFrames = frames.Select(f => Format80.Encode(f)).ToArray(); - - // note: end-of-file and all-zeroes headers - var dataOffset = 14 + (compressedFrames.Length + 2) * ImageHeader.SizeOnDisk; - - using (var bw = new BinaryWriter(s)) - { - bw.Write((ushort)compressedFrames.Length); - bw.Write((ushort)0); // unused - bw.Write((ushort)0); // unused - bw.Write((ushort)width); - bw.Write((ushort)height); - bw.Write((uint)0); // unused - - foreach (var f in compressedFrames) - { - var ih = new ImageHeader { Format = Format.Format80, Offset = (uint)dataOffset }; - dataOffset += f.Length; - - ih.WriteTo(bw); - } - - var eof = new ImageHeader { Offset = (uint)dataOffset }; - eof.WriteTo(bw); - - var allZeroes = new ImageHeader { }; - allZeroes.WriteTo(bw); - - foreach (var f in compressedFrames) - bw.Write(f); - } - } - } -} diff --git a/OpenRA.FileFormats/Graphics/SpriteSource.cs b/OpenRA.FileFormats/Graphics/SpriteSource.cs new file mode 100644 index 0000000000..9c7f25a672 --- /dev/null +++ b/OpenRA.FileFormats/Graphics/SpriteSource.cs @@ -0,0 +1,236 @@ +#region Copyright & License Information +/* + * Copyright 2007-2011 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. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; + +namespace OpenRA.FileFormats +{ + public interface ISpriteFrame + { + Size Size { get; } + Size FrameSize { get; } + float2 Offset { get; } + byte[] Data { get; } + } + + public interface ISpriteSource + { + IEnumerable Frames { get; } + bool CacheWhenLoadingTileset { get; } + } + + public enum SpriteType { Unknown, ShpTD, ShpTS, ShpD2, TmpTD, TmpRA, R8 } + public static class SpriteSource + { + static bool IsTmpRA(Stream s) + { + var start = s.Position; + + s.Position += 20; + var a = s.ReadUInt32(); + s.Position += 2; + var b = s.ReadUInt16(); + + s.Position = start; + return a == 0 && b == 0x2c73; + } + + static bool IsTmpTD(Stream s) + { + var start = s.Position; + + s.Position += 16; + var a = s.ReadUInt32(); + var b = s.ReadUInt32(); + + s.Position = start; + return a == 0 && b == 0x0D1AFFFF; + } + + static bool IsShpTS(Stream s) + { + var start = s.Position; + + // First word is zero + if (s.ReadUInt16() != 0) + { + s.Position = start; + return false; + } + + // Sanity Check the image count + s.Position += 4; + var imageCount = s.ReadUInt16(); + if (s.Position + 24 * imageCount > s.Length) + { + s.Position = start; + return false; + } + + // Check the size and format flag + // Some files define bogus frames, so loop until we find a valid one + s.Position += 4; + ushort w, h, f = 0; + byte type; + do + { + w = s.ReadUInt16(); + h = s.ReadUInt16(); + type = s.ReadUInt8(); + } + while (w == 0 && h == 0 && f++ < imageCount); + + s.Position = start; + return type < 4; + } + + static bool IsShpTD(Stream s) + { + var start = s.Position; + + // First word is the image count + var imageCount = s.ReadUInt16(); + if (imageCount == 0) + { + s.Position = start; + return false; + } + + // Last offset should point to the end of file + var finalOffset = start + 14 + 8 * imageCount; + if (finalOffset > s.Length) + { + s.Position = start; + return false; + } + + s.Position = finalOffset; + var eof = s.ReadUInt32(); + if (eof != s.Length) + { + s.Position = start; + return false; + } + + // Check the format flag on the first frame + s.Position = start + 17; + var b = s.ReadUInt8(); + + s.Position = start; + return b == 0x20 || b == 0x40 || b == 0x80; + } + + static bool IsShpD2(Stream s) + { + var start = s.Position; + + // First word is the image count + var imageCount = s.ReadUInt16(); + if (imageCount == 0) + { + s.Position = start; + return false; + } + + // Test for two vs four byte offset + var testOffset = s.ReadUInt32(); + var offsetSize = (testOffset & 0xFF0000) > 0 ? 2 : 4; + + // Last offset should point to the end of file + var finalOffset = start + 2 + offsetSize * imageCount; + if (finalOffset > s.Length) + { + s.Position = start; + return false; + } + + s.Position = finalOffset; + var eof = offsetSize == 2 ? s.ReadUInt16() : s.ReadUInt32(); + if (eof + 2 != s.Length) + { + s.Position = start; + return false; + } + + // Check the format flag on the first frame + var b = s.ReadUInt16(); + s.Position = start; + return b == 5 || b <= 3; + } + + static bool IsR8(Stream s) + { + var start = s.Position; + + // First byte is nonzero + if (s.ReadUInt8() == 0) + { + s.Position = start; + return false; + } + + // Check the format of the first frame + s.Position = start + 25; + var d = s.ReadUInt8(); + + s.Position = start; + return d == 8; + } + + public static SpriteType DetectSpriteType(Stream s) + { + if (IsShpTD(s)) + return SpriteType.ShpTD; + + if (IsShpTS(s)) + return SpriteType.ShpTS; + + if (IsR8(s)) + return SpriteType.R8; + + if (IsTmpRA(s)) + return SpriteType.TmpRA; + + if (IsTmpTD(s)) + return SpriteType.TmpTD; + + if (IsShpD2(s)) + return SpriteType.ShpD2; + + return SpriteType.Unknown; + } + + public static ISpriteSource LoadSpriteSource(Stream s, string filename) + { + var type = DetectSpriteType(s); + switch (type) + { + case SpriteType.ShpTD: + return new ShpReader(s); + case SpriteType.ShpTS: + return new ShpTSReader(s); + case SpriteType.R8: + return new R8Reader(s); + case SpriteType.TmpRA: + return new TmpRAReader(s); + case SpriteType.TmpTD: + return new TmpTDReader(s); + case SpriteType.ShpD2: + return new ShpD2Reader(s); + case SpriteType.Unknown: + default: + throw new InvalidDataException(filename + " is not a valid sprite file"); + } + } + } +} diff --git a/OpenRA.FileFormats/Graphics/TmpRAReader.cs b/OpenRA.FileFormats/Graphics/TmpRAReader.cs new file mode 100644 index 0000000000..ce627eacac --- /dev/null +++ b/OpenRA.FileFormats/Graphics/TmpRAReader.cs @@ -0,0 +1,50 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 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. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.IO; +using System.Linq; + +namespace OpenRA.FileFormats +{ + public class TmpRAReader : ISpriteSource + { + readonly List tiles = new List(); + public IEnumerable Frames { get { return tiles.Cast(); } } + public bool CacheWhenLoadingTileset { get { return false; } } + + public TmpRAReader(Stream s) + { + var width = s.ReadUInt16(); + var height = s.ReadUInt16(); + var size = new Size(width, height); + + s.Position += 12; + var imgStart = s.ReadUInt32(); + s.Position += 8; + var indexEnd = s.ReadInt32(); + s.Position += 4; + var indexStart = s.ReadInt32(); + + s.Position = indexStart; + foreach (byte b in s.ReadBytes(indexEnd - indexStart)) + { + if (b != 255) + { + s.Position = imgStart + b * width * height; + tiles.Add(new TmpTile(s.ReadBytes(width * height), size)); + } + else + tiles.Add(new TmpTile(null, size)); + } + } + } +} diff --git a/OpenRA.FileFormats/Graphics/TmpTDReader.cs b/OpenRA.FileFormats/Graphics/TmpTDReader.cs new file mode 100644 index 0000000000..fe73203966 --- /dev/null +++ b/OpenRA.FileFormats/Graphics/TmpTDReader.cs @@ -0,0 +1,68 @@ +#region Copyright & License Information +/* + * Copyright 2007-2013 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. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.IO; + +namespace OpenRA.FileFormats +{ + public class TmpTile : ISpriteFrame + { + public Size Size { get; private set; } + public Size FrameSize { get; private set; } + public float2 Offset { get { return float2.Zero; } } + public byte[] Data { get; set; } + + public TmpTile(byte[] data, Size size) + { + FrameSize = size; + Data = data; + + if (data == null) + Data = new byte[0]; + else + Size = size; + } + } + + public class TmpTDReader : ISpriteSource + { + readonly List tiles = new List(); + public IEnumerable Frames { get { return tiles.Cast(); } } + public bool CacheWhenLoadingTileset { get { return false; } } + + public TmpTDReader(Stream s) + { + var width = s.ReadUInt16(); + var height = s.ReadUInt16(); + var size = new Size(width, height); + + s.Position += 8; + var imgStart = s.ReadUInt32(); + s.Position += 8; + var indexEnd = s.ReadInt32(); + var indexStart = s.ReadInt32(); + + s.Position = indexStart; + foreach (byte b in s.ReadBytes(indexEnd - indexStart)) + { + if (b != 255) + { + s.Position = imgStart + b * width * height; + tiles.Add(new TmpTile(s.ReadBytes(width * height), size)); + } + else + tiles.Add(new TmpTile(null, size)); + } + } + } +} diff --git a/OpenRA.FileFormats/Map/Terrain.cs b/OpenRA.FileFormats/Map/Terrain.cs deleted file mode 100644 index 92fbacb2df..0000000000 --- a/OpenRA.FileFormats/Map/Terrain.cs +++ /dev/null @@ -1,77 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2011 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. For more information, - * see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.IO; - -namespace OpenRA.FileFormats -{ - public class Terrain - { - public readonly List TileBitmapBytes = new List(); - public readonly int Width; - public readonly int Height; - - public Terrain(Stream s) - { - // Try loading as a cnc .tem - Width = s.ReadUInt16(); - Height = s.ReadUInt16(); - - /*NumTiles = */s.ReadUInt16(); - /*Zero1 = */s.ReadUInt16(); - /*uint Size = */s.ReadUInt32(); - var imgStart = s.ReadUInt32(); - /*Zero2 = */s.ReadUInt32(); - - int indexEnd, indexStart; - - // ID1 = FFFFh for cnc - if (s.ReadUInt16() == 65535) - { - /*ID2 = */s.ReadUInt16(); - indexEnd = s.ReadInt32(); - indexStart = s.ReadInt32(); - } - else - { - // Load as a ra .tem - s.Position = 0; - Width = s.ReadUInt16(); - Height = s.ReadUInt16(); - - /*NumTiles = */s.ReadUInt16(); - s.ReadUInt16(); - /*XDim = */s.ReadUInt16(); - /*YDim = */s.ReadUInt16(); - /*uint FileSize = */s.ReadUInt32(); - imgStart = s.ReadUInt32(); - s.ReadUInt32(); - s.ReadUInt32(); - indexEnd = s.ReadInt32(); - s.ReadUInt32(); - indexStart = s.ReadInt32(); - } - - s.Position = indexStart; - - foreach (byte b in s.ReadBytes(indexEnd - indexStart)) - { - if (b != 255) - { - s.Position = imgStart + b * Width * Height; - TileBitmapBytes.Add(s.ReadBytes(Width * Height)); - } - else - TileBitmapBytes.Add(null); - } - } - } -} diff --git a/OpenRA.FileFormats/OpenRA.FileFormats.csproj b/OpenRA.FileFormats/OpenRA.FileFormats.csproj index f8f42f2b1c..e867a1dc03 100644 --- a/OpenRA.FileFormats/OpenRA.FileFormats.csproj +++ b/OpenRA.FileFormats/OpenRA.FileFormats.csproj @@ -90,19 +90,16 @@ - - - @@ -144,7 +141,6 @@ - @@ -153,6 +149,10 @@ + + + + diff --git a/OpenRA.Game/Graphics/SheetBuilder.cs b/OpenRA.Game/Graphics/SheetBuilder.cs index a2ba52d535..0cee8661ef 100644 --- a/OpenRA.Game/Graphics/SheetBuilder.cs +++ b/OpenRA.Game/Graphics/SheetBuilder.cs @@ -10,6 +10,7 @@ using System; using System.Drawing; +using OpenRA.FileFormats; using OpenRA.FileFormats.Graphics; namespace OpenRA.Graphics @@ -52,9 +53,14 @@ namespace OpenRA.Graphics this.allocateSheet = allocateSheet; } + public Sprite Add(ISpriteFrame frame) { return Add(frame.Data, frame.Size, frame.Offset); } public Sprite Add(byte[] src, Size size) { return Add(src, size, float2.Zero); } public Sprite Add(byte[] src, Size size, float2 spriteOffset) { + // Don't bother allocating empty sprites + if (size.Width == 0 || size.Height == 0) + return new Sprite(current, Rectangle.Empty, spriteOffset, channel, BlendMode.Alpha); + var rect = Allocate(size, spriteOffset); Util.FastCopyIntoChannel(rect, src); current.CommitData(); diff --git a/OpenRA.Game/Graphics/SpriteLoader.cs b/OpenRA.Game/Graphics/SpriteLoader.cs index ff14eca590..ad34831633 100644 --- a/OpenRA.Game/Graphics/SpriteLoader.cs +++ b/OpenRA.Game/Graphics/SpriteLoader.cs @@ -16,39 +16,25 @@ namespace OpenRA.Graphics { public class SpriteLoader { - public SpriteLoader(string[] exts, SheetBuilder sheetBuilder) - { - SheetBuilder = sheetBuilder; - this.exts = exts; - sprites = new Cache(LoadSprites); - } - readonly SheetBuilder SheetBuilder; readonly Cache sprites; readonly string[] exts; - Sprite[] LoadSprites(string filename) + public SpriteLoader(string[] exts, SheetBuilder sheetBuilder) { - // TODO: Cleanly abstract file type detection - if (filename.ToLower().EndsWith("r8")) - { - var r8 = new R8Reader(FileSystem.Open(filename)); - return r8.Select(a => SheetBuilder.Add(a.Image, a.Size, a.Offset)).ToArray(); - } + SheetBuilder = sheetBuilder; - BinaryReader reader = new BinaryReader(FileSystem.OpenWithExts(filename, exts)); + // Include extension-less version + this.exts = exts.Append("").ToArray(); + sprites = new Cache(CacheSpriteFrames); + } - var ImageCount = reader.ReadUInt16(); - if (ImageCount == 0) - { - var shp = new ShpTSReader(FileSystem.OpenWithExts(filename, exts)); - return shp.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray(); - } - else - { - var shp = new ShpReader(FileSystem.OpenWithExts(filename, exts)); - return shp.Frames.Select(a => SheetBuilder.Add(a.Image, shp.Size)).ToArray(); - } + Sprite[] CacheSpriteFrames(string filename) + { + var stream = FileSystem.OpenWithExts(filename, exts); + return SpriteSource.LoadSpriteSource(stream, filename).Frames + .Select(a => SheetBuilder.Add(a)) + .ToArray(); } public Sprite[] LoadAllSprites(string filename) { return sprites[filename]; } diff --git a/OpenRA.Game/Graphics/Theater.cs b/OpenRA.Game/Graphics/Theater.cs index 48bfc1451f..fdbb5908b8 100644 --- a/OpenRA.Game/Graphics/Theater.cs +++ b/OpenRA.Game/Graphics/Theater.cs @@ -11,6 +11,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.IO; using System.Linq; using OpenRA.FileFormats; @@ -22,27 +23,31 @@ namespace OpenRA.Graphics Dictionary templates; Sprite missingTile; - Sprite[] LoadTemplate(string filename, string[] exts, Cache r8Cache, int[] frames) + Sprite[] LoadTemplate(string filename, string[] exts, Dictionary sourceCache, int[] frames) { - if (exts.Contains(".R8") && FileSystem.Exists(filename+".R8")) + ISpriteSource source; + if (!sourceCache.ContainsKey(filename)) { - return frames.Select(f => - { - if (f < 0) - return null; + using (var s = FileSystem.OpenWithExts(filename, exts)) + source = SpriteSource.LoadSpriteSource(s, filename); - var image = r8Cache[filename][f]; - return sheetBuilder.Add(image.Image, new Size(image.Size.Width, image.Size.Height)); - }).ToArray(); + if (source.CacheWhenLoadingTileset) + sourceCache.Add(filename, source); + } + else + source = sourceCache[filename]; + + if (frames != null) + { + var ret = new List(); + var srcFrames = source.Frames.ToArray(); + foreach (var i in frames) + ret.Add(sheetBuilder.Add(srcFrames[i])); + + return ret.ToArray(); } - using (var s = FileSystem.OpenWithExts(filename, exts)) - { - var t = new Terrain(s); - return t.TileBitmapBytes - .Select(b => b != null ? sheetBuilder.Add(b, new Size(t.Width, t.Height)) : null) - .ToArray(); - } + return source.Frames.Select(f => sheetBuilder.Add(f)).ToArray(); } public Theater(TileSet tileset) @@ -57,11 +62,11 @@ namespace OpenRA.Graphics return new Sheet(new Size(tileset.SheetSize, tileset.SheetSize)); }; - var r8Cache = new Cache(s => new R8Reader(FileSystem.OpenWithExts(s, ".R8"))); + var sourceCache = new Dictionary(); templates = new Dictionary(); sheetBuilder = new SheetBuilder(SheetType.Indexed, allocate); foreach (var t in tileset.Templates) - templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, r8Cache, t.Value.Frames)); + templates.Add(t.Value.Id, LoadTemplate(t.Value.Image, tileset.Extensions, sourceCache, t.Value.Frames)); // 1x1px transparent tile missingTile = sheetBuilder.Add(new byte[1], new Size(1, 1)); @@ -70,11 +75,13 @@ namespace OpenRA.Graphics public Sprite TileSprite(TileReference r) { Sprite[] template; - if (templates.TryGetValue(r.Type, out template)) - if (template.Length > r.Index && template[r.Index] != null) - return template[r.Index]; + if (!templates.TryGetValue(r.Type, out template)) + return missingTile; - return missingTile; + if (r.Index >= template.Length) + return missingTile; + + return template[r.Index]; } public Sheet Sheet { get { return sheetBuilder.Current; } } diff --git a/OpenRA.Game/ModData.cs b/OpenRA.Game/ModData.cs index 1414d405de..48ae466e28 100755 --- a/OpenRA.Game/ModData.cs +++ b/OpenRA.Game/ModData.cs @@ -75,7 +75,7 @@ namespace OpenRA ChromeMetrics.Initialize(Manifest.ChromeMetrics); ChromeProvider.Initialize(Manifest.Chrome); SheetBuilder = new SheetBuilder(SheetType.Indexed); - SpriteLoader = new SpriteLoader(new string[] { ".shp" }, SheetBuilder); + SpriteLoader = new SpriteLoader(new string[0], SheetBuilder); VoxelLoader = new VoxelLoader(); CursorProvider.Initialize(Manifest.Cursors); } diff --git a/OpenRA.Game/Widgets/ShpImageWidget.cs b/OpenRA.Game/Widgets/ShpImageWidget.cs index 4c8cb912a7..5c1dabaa0b 100644 --- a/OpenRA.Game/Widgets/ShpImageWidget.cs +++ b/OpenRA.Game/Widgets/ShpImageWidget.cs @@ -56,6 +56,7 @@ namespace OpenRA.Widgets Sprite sprite = null; string cachedImage = null; int cachedFrame = -1; + float2 cachedOffset = float2.Zero; public override void Draw() { @@ -68,9 +69,10 @@ namespace OpenRA.Widgets sprite = Game.modData.SpriteLoader.LoadAllSprites(image)[frame]; cachedImage = image; cachedFrame = frame; + cachedOffset = 0.5f * (new float2(RenderBounds.Size) - sprite.size); } - Game.Renderer.SpriteRenderer.DrawSprite(sprite, RenderOrigin, worldRenderer.Palette(palette)); + Game.Renderer.SpriteRenderer.DrawSprite(sprite, RenderOrigin + cachedOffset, worldRenderer.Palette(palette)); } public int FrameCount diff --git a/OpenRA.Game/Widgets/WidgetUtils.cs b/OpenRA.Game/Widgets/WidgetUtils.cs index 0ab460b639..1cfbefb13f 100644 --- a/OpenRA.Game/Widgets/WidgetUtils.cs +++ b/OpenRA.Game/Widgets/WidgetUtils.cs @@ -29,14 +29,14 @@ namespace OpenRA.Widgets Game.Renderer.RgbaSpriteRenderer.DrawSprite(s,pos); } - public static void DrawSHP(Sprite s, float2 pos, WorldRenderer wr) + public static void DrawSHPCentered(Sprite s, float2 pos, WorldRenderer wr) { - Game.Renderer.SpriteRenderer.DrawSprite(s, pos, wr.Palette("chrome")); + Game.Renderer.SpriteRenderer.DrawSprite(s, pos - 0.5f * s.size, wr.Palette("chrome")); } - public static void DrawSHP(Sprite s, float2 pos, WorldRenderer wr, float2 size) + public static void DrawSHPCentered(Sprite s, float2 pos, WorldRenderer wr, float scale) { - Game.Renderer.SpriteRenderer.DrawSprite(s, pos, wr.Palette("chrome"), size); + Game.Renderer.SpriteRenderer.DrawSprite(s, pos - 0.5f * scale * s.size, wr.Palette("chrome"), scale * s.size); } public static void DrawPanel(string collection, Rectangle Bounds) diff --git a/OpenRA.Mods.Cnc/Widgets/ProductionPaletteWidget.cs b/OpenRA.Mods.Cnc/Widgets/ProductionPaletteWidget.cs index 8dea9c77eb..3e299090c8 100755 --- a/OpenRA.Mods.Cnc/Widgets/ProductionPaletteWidget.cs +++ b/OpenRA.Mods.Cnc/Widgets/ProductionPaletteWidget.cs @@ -197,11 +197,14 @@ namespace OpenRA.Mods.Cnc.Widgets public override void Draw() { + var iconSize = new float2(64, 48); + var iconOffset = 0.5f * iconSize; + overlayFont = Game.Renderer.Fonts["TinyBold"]; - timeOffset = new float2(32, 24) - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2; + timeOffset = iconOffset - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2; queuedOffset = new float2(4, 2); - holdOffset = new float2(32, 24) - overlayFont.Measure(HoldText) / 2; - readyOffset = new float2(32, 24) - overlayFont.Measure(ReadyText) / 2; + holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2; + readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2; if (CurrentQueue == null) return; @@ -215,7 +218,7 @@ namespace OpenRA.Mods.Cnc.Widgets // Icons foreach (var icon in icons.Values) { - WidgetUtils.DrawSHP(icon.Sprite, icon.Pos, worldRenderer); + WidgetUtils.DrawSHPCentered(icon.Sprite, icon.Pos + iconOffset, worldRenderer); // Build progress if (icon.Queued.Count > 0) @@ -225,10 +228,10 @@ namespace OpenRA.Mods.Cnc.Widgets () => (first.TotalTime - first.RemainingTime) * (clock.CurrentSequence.Length - 1) / first.TotalTime); clock.Tick(); - WidgetUtils.DrawSHP(clock.Image, icon.Pos, worldRenderer); + WidgetUtils.DrawSHPCentered(clock.Image, icon.Pos + iconOffset, worldRenderer); } else if (!buildableItems.Any(a => a.Name == icon.Name)) - WidgetUtils.DrawSHP(cantBuild.Image, icon.Pos, worldRenderer); + WidgetUtils.DrawSHPCentered(cantBuild.Image, icon.Pos + iconOffset, worldRenderer); } // Overlays diff --git a/OpenRA.Mods.Cnc/Widgets/SupportPowersWidget.cs b/OpenRA.Mods.Cnc/Widgets/SupportPowersWidget.cs index dec4cd1389..3a970da1b9 100755 --- a/OpenRA.Mods.Cnc/Widgets/SupportPowersWidget.cs +++ b/OpenRA.Mods.Cnc/Widgets/SupportPowersWidget.cs @@ -89,10 +89,13 @@ namespace OpenRA.Mods.Cnc.Widgets public override void Draw() { + var iconSize = new float2(64, 48); + var iconOffset = 0.5f * iconSize; + overlayFont = Game.Renderer.Fonts["TinyBold"]; - holdOffset = new float2(32, 24) - overlayFont.Measure(HoldText) / 2; - readyOffset = new float2(32, 24) - overlayFont.Measure(ReadyText) / 2; - timeOffset = new float2(32, 24) - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2; + holdOffset = iconOffset - overlayFont.Measure(HoldText) / 2; + readyOffset = iconOffset - overlayFont.Measure(ReadyText) / 2; + timeOffset = iconOffset - overlayFont.Measure(WidgetUtils.FormatTime(0)) / 2; // Background foreach (var rect in icons.Keys) @@ -101,14 +104,14 @@ namespace OpenRA.Mods.Cnc.Widgets // Icons foreach (var p in icons.Values) { - WidgetUtils.DrawSHP(p.Sprite, p.Pos, worldRenderer); + WidgetUtils.DrawSHPCentered(p.Sprite, p.Pos + iconOffset, worldRenderer); // Charge progress clock.PlayFetchIndex("idle", () => (p.Power.TotalTime - p.Power.RemainingTime) * (clock.CurrentSequence.Length - 1) / p.Power.TotalTime); clock.Tick(); - WidgetUtils.DrawSHP(clock.Image, p.Pos, worldRenderer); + WidgetUtils.DrawSHPCentered(clock.Image, p.Pos + iconOffset, worldRenderer); } // Overlay diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index eba63a2dde..8bfeee8316 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -33,9 +33,9 @@ true - true + True full - false + False bin\Debug\ DEBUG;TRACE prompt @@ -47,17 +47,17 @@ AllRules.ruleset - true + True pdbonly - true + True TRACE prompt 4 bin\Release\ AllRules.ruleset - true + True @@ -70,14 +70,13 @@ - - False - ..\thirdparty\ICSharpCode.SharpZipLib.dll - ..\thirdparty\Mono.Nat.dll False + + ..\thirdparty\ICSharpCode.SharpZipLib.dll + @@ -444,7 +443,6 @@ - @@ -481,7 +479,7 @@ - {e915a0a4-2641-4f7e-8a88-8f123fa88bf1} + {E915A0A4-2641-4F7E-8A88-8F123FA88BF1} LuaInterface @@ -495,13 +493,9 @@ False - {85b48234-8b31-4be6-af9c-665cc6866841} + {85B48234-8B31-4BE6-AF9C-665CC6866841} OpenRA.Irc - - {F33337BE-CB69-4B24-850F-07D23E408DDF} - OpenRA.Utility - {021DDD6A-A608-424C-9A9A-252D8A9989E0} GeoIP diff --git a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs index db0fe250f4..e6fd815b5c 100755 --- a/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs +++ b/OpenRA.Mods.RA/Widgets/BuildPaletteWidget.cs @@ -203,6 +203,7 @@ namespace OpenRA.Mods.RA.Widgets string paletteCollection = "palette-" + world.LocalPlayer.Country.Race; float2 origin = new float2(paletteOrigin.X + 9, paletteOrigin.Y + 9); + var iconOffset = 0.5f * new float2(IconWidth, IconHeight); var x = 0; var y = 0; @@ -233,7 +234,7 @@ namespace OpenRA.Mods.RA.Widgets var drawPos = new float2(rect.Location); var icon = new Animation(RenderSimple.GetImage(item)); icon.Play(item.Traits.Get().Icon); - WidgetUtils.DrawSHP(icon.Image, drawPos, worldRenderer); + WidgetUtils.DrawSHPCentered(icon.Image, drawPos + iconOffset, worldRenderer); var firstOfThis = queue.AllQueued().FirstOrDefault(a => a.Item == item.Name); @@ -248,7 +249,7 @@ namespace OpenRA.Mods.RA.Widgets () => (firstOfThis.TotalTime - firstOfThis.RemainingTime) * (clock.CurrentSequence.Length - 1) / firstOfThis.TotalTime); clock.Tick(); - WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); + WidgetUtils.DrawSHPCentered(clock.Image, drawPos + iconOffset, worldRenderer); if (queue.CurrentItem() == firstOfThis) textBits.Add(Pair.New(overlayPos, GetOverlayForItem(firstOfThis))); @@ -269,7 +270,7 @@ namespace OpenRA.Mods.RA.Widgets if (x != 0) y++; foreach (var ob in overlayBits) - WidgetUtils.DrawSHP(ob.First, ob.Second, worldRenderer); + WidgetUtils.DrawSHPCentered(ob.First, ob.Second + iconOffset, worldRenderer); var font = Game.Renderer.Fonts["TinyBold"]; foreach (var tb in textBits) diff --git a/OpenRA.Mods.RA/Widgets/Logic/AssetBrowserLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/AssetBrowserLogic.cs index 2c7adaaad3..44f88cbe9e 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/AssetBrowserLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/AssetBrowserLogic.cs @@ -35,6 +35,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic PaletteFromFile currentPalette; + static readonly string[] AllowedExtensions = { ".shp", ".r8", ".tem", ".des", ".sno", ".int" }; + [ObjectCreator.UseCtor] public AssetBrowserLogic(Widget widget, Action onExit, World world) { @@ -60,6 +62,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic var paletteDropDown = panel.Get("PALETTE_SELECTOR"); paletteDropDown.OnMouseDown = _ => ShowPaletteDropdown(paletteDropDown, world); + paletteDropDown.GetText = () => currentPalette.Name; var colorPreview = panel.Get("COLOR_MANAGER"); colorPreview.Color = Game.Settings.Player.Color; @@ -80,7 +83,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic frameSlider.OnChange += x => { spriteWidget.Frame = (int)Math.Round(x); }; frameSlider.GetValue = () => spriteWidget.Frame; - panel.Get("FRAME_COUNT").GetText = () => "{0}/{1}".F(spriteWidget.Frame, spriteWidget.FrameCount); + panel.Get("FRAME_COUNT").GetText = () => "{0} / {1}".F(spriteWidget.Frame + 1, spriteWidget.FrameCount + 1); playButton = panel.Get("BUTTON_PLAY"); playButton.OnClick = () => @@ -118,96 +121,15 @@ namespace OpenRA.Mods.RA.Widgets.Logic template = panel.Get("ASSET_TEMPLATE"); PopulateAssetList(); - var modID = Game.modData.Manifest.Mod.Id; - - // TODO: This should not invoke the OpenRA.Utility.exe, but use it's functions directly. - // TODO: Does not work with SHP(TS) yet?! - panel.Get("EXPORT_BUTTON").OnClick = () => - { - var ExtractGameFiles = new string[][] - { - new string[] { "--extract", modID, currentPalette.Filename, "--userdir" }, - new string[] { "--extract", modID, "{0}.shp".F(spriteWidget.Image), "--userdir" }, - }; - - var ExportToPng = new string[][] - { - new string[] { "--png", Platform.SupportDir + "{0}.shp".F(spriteWidget.Image), Platform.SupportDir + currentPalette.Filename }, - }; - - var ImportFromPng = new string[][] { }; - - var args = new WidgetArgs() - { - { "ExtractGameFiles", ExtractGameFiles }, - { "ExportToPng", ExportToPng }, - { "ImportFromPng", ImportFromPng } - }; - - Ui.OpenWindow("CONVERT_ASSETS_PANEL", args); - }; - - panel.Get("EXTRACT_BUTTON").OnClick = () => - { - var ExtractGameFilesList = new List(); - var ExportToPngList = new List(); - - ExtractGameFilesList.Add(new string[] { "--extract", modID, currentPalette.Filename, "--userdir" }); - - foreach (var shp in availableShps) - { - ExtractGameFilesList.Add(new string[] { "--extract", modID, shp, "--userdir" }); - ExportToPngList.Add(new string[] { "--png", Platform.SupportDir + shp, Platform.SupportDir + currentPalette.Filename }); - Console.WriteLine(Platform.SupportDir + shp); - } - - var ExtractGameFiles = ExtractGameFilesList.ToArray(); - var ExportToPng = ExportToPngList.ToArray(); - var ImportFromPng = new string[][] { }; - - var args = new WidgetArgs() - { - { "ExtractGameFiles", ExtractGameFiles }, - { "ExportToPng", ExportToPng }, - { "ImportFromPng", ImportFromPng } - }; - - Ui.OpenWindow("CONVERT_ASSETS_PANEL", args); - }; - - panel.Get("IMPORT_BUTTON").OnClick = () => - { - var imageSizeInput = panel.Get("IMAGE_SIZE_INPUT"); - var imageFilename = panel.Get("IMAGE_FILENAME_INPUT"); - - var ExtractGameFiles = new string[][] { }; - var ExportToPng = new string[][] { }; - var ImportFromPng = new string[][] - { - new string[] { "--shp", Platform.SupportDir + imageFilename.Text, imageSizeInput.Text }, - }; - - var args = new WidgetArgs() - { - { "ExtractGameFiles", ExtractGameFiles }, - { "ExportToPng", ExportToPng }, - { "ImportFromPng", ImportFromPng } - }; - - Ui.OpenWindow("CONVERT_ASSETS_PANEL", args); - }; - panel.Get("CLOSE_BUTTON").OnClick = () => { Ui.CloseWindow(); onExit(); }; } void AddAsset(ScrollPanelWidget list, string filepath, ScrollItemWidget template) { - var r8 = filepath.EndsWith(".r8", true, CultureInfo.InvariantCulture); - var filename = Path.GetFileName(filepath); - var sprite = r8 ? filename : Path.GetFileNameWithoutExtension(filepath); + var filename = Path.GetFileName(filepath); var item = ScrollItemWidget.Setup(template, - () => spriteWidget.Image == sprite, - () => {filenameInput.Text = filename; LoadAsset(filename); }); + () => spriteWidget.Image == filename, + () => { filenameInput.Text = filename; LoadAsset(filename); }); item.Get("TITLE").GetText = () => filepath; list.AddChild(item); @@ -221,11 +143,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic if (!FileSystem.Exists(filename)) return false; - var r8 = filename.EndsWith(".r8", true, CultureInfo.InvariantCulture); - var sprite = r8 ? filename : Path.GetFileNameWithoutExtension(filename); - spriteWidget.Frame = 0; - spriteWidget.Image = sprite; + spriteWidget.Image = filename; frameSlider.MaximumValue = (float)spriteWidget.FrameCount; frameSlider.Ticks = spriteWidget.FrameCount + 1; return true; @@ -265,7 +184,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic var files = assetSource.AllFileNames(); foreach (var file in files) { - if (file.EndsWith(".shp", true, CultureInfo.InvariantCulture) || file.EndsWith(".r8", true, CultureInfo.InvariantCulture)) + if (AllowedExtensions.Any(ext => file.EndsWith(ext, true, CultureInfo.InvariantCulture))) { AddAsset(assetList, file, template); availableShps.Add(file); @@ -278,8 +197,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic Func setupItem = (palette, itemTemplate) => { var item = ScrollItemWidget.Setup(itemTemplate, - () => currentPalette.Name == palette.Name, - () => { currentPalette = palette; spriteWidget.Palette = currentPalette.Name; }); + () => currentPalette.Name == palette.Name, + () => { currentPalette = palette; spriteWidget.Palette = currentPalette.Name; }); item.Get("LABEL").GetText = () => palette.Name; return item; }; diff --git a/OpenRA.Mods.RA/Widgets/Logic/ConvertGameFilesLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/ConvertGameFilesLogic.cs deleted file mode 100644 index 8cd8bfcc60..0000000000 --- a/OpenRA.Mods.RA/Widgets/Logic/ConvertGameFilesLogic.cs +++ /dev/null @@ -1,110 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2013 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. For more information, - * see COPYING. - */ -#endregion - -using System; -using System.IO; -using System.Linq; -using System.Threading; -using OpenRA.Utility; -using OpenRA.Widgets; - -namespace OpenRA.Mods.RA.Widgets.Logic -{ - public class ConvertGameFilesLogic - { - Widget panel; - ProgressBarWidget progressBar; - LabelWidget statusLabel; - ButtonWidget retryButton, backButton; - Widget extractingContainer; - - string[][] ExtractGameFiles, ExportToPng, ImportFromPng; - - [ObjectCreator.UseCtor] - public ConvertGameFilesLogic(Widget widget, string[][] ExtractGameFiles, string[][] ExportToPng, string[][] ImportFromPng) - { - panel = widget.Get("CONVERT_ASSETS_PANEL"); - progressBar = panel.Get("PROGRESS_BAR"); - statusLabel = panel.Get("STATUS_LABEL"); - - backButton = panel.Get("BACK_BUTTON"); - backButton.OnClick = Ui.CloseWindow; - - retryButton = panel.Get("RETRY_BUTTON"); - retryButton.OnClick = Extract; - - extractingContainer = panel.Get("EXTRACTING"); - - this.ExtractGameFiles = ExtractGameFiles; - this.ExportToPng = ExportToPng; - this.ImportFromPng = ImportFromPng; - - Extract(); - } - - void Extract() - { - backButton.IsDisabled = () => true; - retryButton.IsDisabled = () => true; - extractingContainer.IsVisible = () => true; - - var onError = (Action)(s => Game.RunAfterTick(() => - { - statusLabel.GetText = () => "Error: "+s; - backButton.IsDisabled = () => false; - retryButton.IsDisabled = () => false; - })); - - var t = new Thread( _ => - { - try - { - for (int i = 0; i < ExtractGameFiles.Length; i++) - { - progressBar.Percentage = i*100/ExtractGameFiles.Count(); - statusLabel.GetText = () => "Extracting..."; - Command.ExtractFiles(ExtractGameFiles[i]); - } - - for (int i = 0; i < ExportToPng.Length; i++) - { - progressBar.Percentage = i*100/ExportToPng.Count(); - statusLabel.GetText = () => "Exporting SHP to PNG..."; - Command.ConvertShpToPng(ExportToPng[i]); - } - - for (int i = 0; i < ImportFromPng.Length; i++) - { - progressBar.Percentage = i*100/ImportFromPng.Count(); - statusLabel.GetText = () => "Converting PNG to SHP..."; - Command.ConvertPngToShp(ImportFromPng[i]); - } - - Game.RunAfterTick(() => - { - progressBar.Percentage = 100; - statusLabel.GetText = () => "Done. Check {0}".F(Platform.SupportDir); - backButton.IsDisabled = () => false; - }); - } - catch (FileNotFoundException f) - { - onError(f.FileName+" not found."); - } - catch (Exception e) - { - onError(e.Message); - } - - }) { IsBackground = true }; - t.Start(); - } - } -} diff --git a/OpenRA.Mods.RA/Widgets/ObserverProductionIconsWidget.cs b/OpenRA.Mods.RA/Widgets/ObserverProductionIconsWidget.cs index af7ff43802..8bc0abc7d3 100644 --- a/OpenRA.Mods.RA/Widgets/ObserverProductionIconsWidget.cs +++ b/OpenRA.Mods.RA/Widgets/ObserverProductionIconsWidget.cs @@ -25,6 +25,10 @@ namespace OpenRA.Mods.RA.Widgets WorldRenderer worldRenderer; Dictionary clocks; + public int IconWidth = 32; + public int IconHeight = 24; + public int IconSpacing = 8; + [ObjectCreator.UseCtor] public ObserverProductionIconsWidget(World world, WorldRenderer worldRenderer) { @@ -59,6 +63,8 @@ namespace OpenRA.Mods.RA.Widgets clocks.Add(queue.Trait, new Animation("clock")); } } + + var iconSize = new float2(IconWidth, IconHeight); foreach (var queue in queues) { var current = queue.Trait.CurrentItem(); @@ -71,16 +77,15 @@ namespace OpenRA.Mods.RA.Widgets var icon = new Animation(RenderSimple.GetImage(actor)); icon.Play(actor.Traits.Get().Icon); - var size = icon.Image.size / new float2(2, 2); - var location = new float2(RenderBounds.Location) + new float2(queue.i * (int)size.Length, 0); - WidgetUtils.DrawSHP(icon.Image, location, worldRenderer, size); + var location = new float2(RenderBounds.Location) + new float2(queue.i * (IconWidth + IconSpacing), 0); + WidgetUtils.DrawSHPCentered(icon.Image, location + 0.5f * iconSize, worldRenderer, 0.5f); var clock = clocks[queue.Trait]; clock.PlayFetchIndex("idle", () => current.TotalTime == 0 ? 0 : ((current.TotalTime - current.RemainingTime) * (clock.CurrentSequence.Length - 1) / current.TotalTime)); clock.Tick(); - WidgetUtils.DrawSHP(clock.Image, location, worldRenderer, size); + WidgetUtils.DrawSHPCentered(clock.Image, location + 0.5f * iconSize, worldRenderer, 0.5f); var tiny = Game.Renderer.Fonts["Tiny"]; var text = GetOverlayForItem(current); diff --git a/OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs b/OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs index e192e162c1..408510763f 100644 --- a/OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs +++ b/OpenRA.Mods.RA/Widgets/ObserverSupportPowerIconsWidget.cs @@ -25,6 +25,10 @@ namespace OpenRA.Mods.RA.Widgets WorldRenderer worldRenderer; Dictionary clocks; + public int IconWidth = 32; + public int IconHeight = 24; + public int IconSpacing = 8; + [ObjectCreator.UseCtor] public ObserverSupportPowerIconsWidget(World world, WorldRenderer worldRenderer) { @@ -61,22 +65,24 @@ namespace OpenRA.Mods.RA.Widgets clocks.Add(power.a.Key, new Animation("clock")); } } + + var iconSize = new float2(IconWidth, IconHeight); foreach (var power in powers) { var item = power.a.Value; if (item == null || item.Info == null || item.Info.Icon == null) continue; + icon.Play(item.Info.Icon); - var size = icon.Image.size / new float2(2, 2); - var location = new float2(RenderBounds.Location) + new float2(power.i * (int)size.Length, 0); - WidgetUtils.DrawSHP(icon.Image, location, worldRenderer, size); + var location = new float2(RenderBounds.Location) + new float2(power.i * (IconWidth + IconSpacing), 0); + WidgetUtils.DrawSHPCentered(icon.Image, location + 0.5f * iconSize, worldRenderer, 0.5f); var clock = clocks[power.a.Key]; clock.PlayFetchIndex("idle", () => item.TotalTime == 0 ? 0 : ((item.TotalTime - item.RemainingTime) * (clock.CurrentSequence.Length - 1) / item.TotalTime)); clock.Tick(); - WidgetUtils.DrawSHP(clock.Image, location, worldRenderer, size); + WidgetUtils.DrawSHPCentered(clock.Image, location + 0.5f * iconSize, worldRenderer, 0.5f); var tiny = Game.Renderer.Fonts["Tiny"]; var text = GetOverlayForItem(item); diff --git a/OpenRA.Mods.RA/Widgets/SupportPowerBinWidget.cs b/OpenRA.Mods.RA/Widgets/SupportPowerBinWidget.cs index 27a4f32dbb..13436ab4f6 100755 --- a/OpenRA.Mods.RA/Widgets/SupportPowerBinWidget.cs +++ b/OpenRA.Mods.RA/Widgets/SupportPowerBinWidget.cs @@ -23,6 +23,9 @@ namespace OpenRA.Mods.RA.Widgets [Translate] public string ReadyText = ""; [Translate] public string HoldText = ""; + public int IconWidth = 64; + public int IconHeight = 48; + Animation icon; Animation clock; readonly List>> buttons = new List>>(); @@ -84,10 +87,11 @@ namespace OpenRA.Mods.RA.Widgets WidgetUtils.DrawRGBA(WidgetUtils.GetChromeImage(world, "specialbin-bottom"), new float2(rectBounds.X, rectBounds.Y + numPowers * 51)); // HACK: Hack Hack Hack - rectBounds.Width = 69; - rectBounds.Height = 10 + numPowers * 51 + 21; + rectBounds.Width = IconWidth + 5; + rectBounds.Height = 31 + numPowers * (IconHeight + 3); var y = rectBounds.Y + 10; + var iconSize = new float2(IconWidth, IconHeight); foreach (var kv in powers) { var sp = kv.Value; @@ -137,14 +141,14 @@ namespace OpenRA.Mods.RA.Widgets } } - WidgetUtils.DrawSHP(icon.Image, drawPos, worldRenderer); + WidgetUtils.DrawSHPCentered(icon.Image, drawPos + 0.5f * iconSize, worldRenderer); clock.PlayFetchIndex("idle", () => sp.TotalTime == 0 ? clock.CurrentSequence.Length - 1 : (sp.TotalTime - sp.RemainingTime) * (clock.CurrentSequence.Length - 1) / sp.TotalTime); clock.Tick(); - WidgetUtils.DrawSHP(clock.Image, drawPos, worldRenderer); + WidgetUtils.DrawSHPCentered(clock.Image, drawPos + 0.5f * iconSize, worldRenderer); var overlay = sp.Ready ? ReadyText : sp.Active ? null : HoldText; var font = Game.Renderer.Fonts["TinyBold"]; diff --git a/OpenRA.Utility/Command.cs b/OpenRA.Utility/Command.cs index 9d738ef85d..cc9bcea144 100644 --- a/OpenRA.Utility/Command.cs +++ b/OpenRA.Utility/Command.cs @@ -19,6 +19,7 @@ using System.Runtime.InteropServices; using OpenRA.FileFormats; using OpenRA.FileFormats.Graphics; using OpenRA.GameRules; +using OpenRA.Graphics; using OpenRA.Traits; namespace OpenRA.Utility @@ -42,46 +43,37 @@ namespace OpenRA.Utility public static void ConvertPngToShp(string[] args) { - var src = args[1]; - var dest = Path.ChangeExtension(src, ".shp"); - var width = int.Parse(args[2]); + var dest = args[1].Split('-').First() + ".shp"; + var frames = args.Skip(1).Select(a => PngLoader.Load(a)); - var srcImage = PngLoader.Load(src); - - if (srcImage.Width % width != 0) - throw new InvalidOperationException("Bogus width; not a whole number of frames"); + var size = frames.First().Size; + if (frames.Any(f => f.Size != size)) + throw new InvalidOperationException("All frames must be the same size"); using (var destStream = File.Create(dest)) - ShpWriter.Write(destStream, width, srcImage.Height, - srcImage.ToFrames(width)); + ShpReader.Write(destStream, size, frames.Select(f => f.ToBytes())); Console.WriteLine(dest + " saved."); } - static IEnumerable ToFrames(this Bitmap bitmap, int width) + static byte[] ToBytes(this Bitmap bitmap) { - for (var x = 0; x < bitmap.Width; x += width) - { - var data = bitmap.LockBits(new Rectangle(x, 0, width, bitmap.Height), ImageLockMode.ReadOnly, - PixelFormat.Format8bppIndexed); + var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, + PixelFormat.Format8bppIndexed); - var bytes = new byte[width * bitmap.Height]; - for (var i = 0; i < bitmap.Height; i++) - Marshal.Copy(new IntPtr(data.Scan0.ToInt64() + i * data.Stride), - bytes, i * width, width); + var bytes = new byte[bitmap.Width * bitmap.Height]; + for (var i = 0; i < bitmap.Height; i++) + Marshal.Copy(new IntPtr(data.Scan0.ToInt64() + i * data.Stride), + bytes, i * bitmap.Width, bitmap.Width); - bitmap.UnlockBits(data); + bitmap.UnlockBits(data); - yield return bytes; - } + return bytes; } public static void ConvertShpToPng(string[] args) { var src = args[1]; - var dest = Path.ChangeExtension(src, ".png"); - - var srcImage = ShpReader.Load(src); var shadowIndex = new int[] { }; if (args.Contains("--noshadow")) { @@ -93,134 +85,55 @@ namespace OpenRA.Utility var palette = Palette.Load(args[2], shadowIndex); - using (var bitmap = new Bitmap(srcImage.ImageCount * srcImage.Width, srcImage.Height, PixelFormat.Format8bppIndexed)) + ISpriteSource source; + using (var stream = File.OpenRead(src)) + source = SpriteSource.LoadSpriteSource(stream, src); + + // The r8 padding requires external information that we can't access here. + var usePadding = !(args.Contains("--nopadding") || source is R8Reader); + var count = 0; + var prefix = Path.GetFileNameWithoutExtension(src); + + foreach (var frame in source.Frames) { - var x = 0; - bitmap.Palette = palette.AsSystemPalette(); + var frameSize = usePadding ? frame.FrameSize : frame.Size; + var offset = usePadding ? (frame.Offset - 0.5f * new float2(frame.Size - frame.FrameSize)).ToInt2() : int2.Zero; - foreach (var frame in srcImage.Frames) + // shp(ts) may define empty frames + if (frameSize.Width == 0 && frameSize.Height == 0) { - var data = bitmap.LockBits(new Rectangle(x, 0, srcImage.Width, srcImage.Height), ImageLockMode.WriteOnly, - PixelFormat.Format8bppIndexed); + count++; + continue; + } - for (var i = 0; i < bitmap.Height; i++) - Marshal.Copy(frame.Image, i * srcImage.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), srcImage.Width); + using (var bitmap = new Bitmap(frameSize.Width, frameSize.Height, PixelFormat.Format8bppIndexed)) + { + bitmap.Palette = palette.AsSystemPalette(); + var data = bitmap.LockBits(new Rectangle(0, 0, frameSize.Width, frameSize.Height), + ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - x += srcImage.Width; + // Clear the frame + if (usePadding) + { + var clearRow = new byte[data.Stride]; + for (var i = 0; i < frameSize.Height; i++) + Marshal.Copy(clearRow, 0, new IntPtr(data.Scan0.ToInt64() + i * data.Stride), data.Stride); + } + + for (var i = 0; i < frame.Size.Height; i++) + { + var destIndex = new IntPtr(data.Scan0.ToInt64() + (i + offset.Y) * data.Stride + offset.X); + Marshal.Copy(frame.Data, i * frame.Size.Width, destIndex, frame.Size.Width); + } bitmap.UnlockBits(data); + + var filename = "{0}-{1:D4}.png".F(prefix, count++); + bitmap.Save(filename); } - - bitmap.Save(dest); - Console.WriteLine(dest + " saved"); - } - } - - public static void ConvertR8ToPng(string[] args) - { - var srcImage = new R8Reader(File.OpenRead(args[1])); - var shadowIndex = new int[] { }; - if (args.Contains("--noshadow")) - { - Array.Resize(ref shadowIndex, shadowIndex.Length + 1); - shadowIndex[shadowIndex.Length - 1] = 3; } - var palette = Palette.Load(args[2], shadowIndex); - var startFrame = int.Parse(args[3]); - var endFrame = int.Parse(args[4]) + 1; - var filename = args[5]; - var frameCount = endFrame - startFrame; - - var frame = srcImage[startFrame]; - var bitmap = new Bitmap(frame.FrameSize.Width * frameCount, frame.FrameSize.Height, PixelFormat.Format8bppIndexed); - bitmap.Palette = palette.AsSystemPalette(); - - frame = srcImage[startFrame]; - - if (args.Contains("--tileset")) - { - int f = 0; - var tileset = new Bitmap(frame.FrameSize.Width * 20, frame.FrameSize.Height * 40, PixelFormat.Format8bppIndexed); - tileset.Palette = palette.AsSystemPalette(); - - for (int h = 0; h < 40; h++) - { - for (int w = 0; w < 20; w++) - { - if (h * 20 + w < frameCount) - { - Console.WriteLine(f); - frame = srcImage[f]; - - var data = tileset.LockBits(new Rectangle(w * frame.Size.Width, h * frame.Size.Height, frame.Size.Width, frame.Size.Height), - ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed); - - for (var i = 0; i < frame.Size.Height; i++) - Marshal.Copy(frame.Image, i * frame.Size.Width, - new IntPtr(data.Scan0.ToInt64() + i * data.Stride), frame.Size.Width); - - tileset.UnlockBits(data); - f++; - } - } - } - - bitmap = tileset; - } - - bitmap.Save(filename + ".png"); - Console.WriteLine(filename + ".png saved"); - } - - public static void ConvertTmpToPng(string[] args) - { - var mod = args[1]; - var theater = args[2]; - var templateNames = args.Skip(3); - var shadowIndex = new int[] { 3, 4 }; - - var manifest = new Manifest(mod); - FileSystem.LoadFromManifest(manifest); - - var tileset = manifest.TileSets.Select(a => new TileSet(a)) - .FirstOrDefault(ts => ts.Name == theater); - - if (tileset == null) - throw new InvalidOperationException("No theater named '{0}'".F(theater)); - - var renderer = new TileSetRenderer(tileset, new Size(manifest.TileSize, manifest.TileSize)); - var palette = new Palette(FileSystem.Open(tileset.Palette), shadowIndex); - - foreach (var templateName in templateNames) - { - var template = tileset.Templates.FirstOrDefault(tt => tt.Value.Image == templateName); - if (template.Value == null) - throw new InvalidOperationException("No such template '{0}'".F(templateName)); - - using (var image = renderer.RenderTemplate(template.Value.Id, palette)) - image.Save(Path.ChangeExtension(templateName, ".png")); - } - } - - public static void ConvertFormat2ToFormat80(string[] args) - { - var src = args[1]; - var dest = args[2]; - - Dune2ShpReader srcImage = null; - using (var s = File.OpenRead(src)) - srcImage = new Dune2ShpReader(s); - - var size = srcImage.First().Size; - - if (!srcImage.All(im => im.Size == size)) - throw new InvalidOperationException("All the frames must be the same size to convert from Dune2 to RA"); - - using (var destStream = File.Create(dest)) - ShpWriter.Write(destStream, size.Width, size.Height, - srcImage.Select(im => im.Image)); + Console.WriteLine("Saved {0}-[0..{1}].png", prefix, count - 1); } public static void ExtractFiles(string[] args) @@ -233,16 +146,12 @@ namespace OpenRA.Utility foreach (var f in files) { - if (f == "--userdir") - break; - var src = FileSystem.Open(f); if (src == null) throw new InvalidOperationException("File not found: {0}".F(f)); var data = src.ReadAllBytes(); - var output = args.Contains("--userdir") ? Platform.SupportDir + f : f; - File.WriteAllBytes(output, data); - Console.WriteLine(output + " saved."); + File.WriteAllBytes(f, data); + Console.WriteLine(f + " saved."); } } @@ -300,8 +209,8 @@ namespace OpenRA.Utility var srcImage = ShpReader.Load(args[3]); using (var destStream = File.Create(args[4])) - ShpWriter.Write(destStream, srcImage.Width, srcImage.Height, - srcImage.Frames.Select(im => im.Image.Select(px => (byte)remap[px]).ToArray())); + ShpReader.Write(destStream, srcImage.Size, + srcImage.Frames.Select(im => im.Data.Select(px => (byte)remap[px]).ToArray())); } public static void TransposeShp(string[] args) @@ -323,8 +232,7 @@ namespace OpenRA.Utility } using (var destStream = File.Create(args[2])) - ShpWriter.Write(destStream, srcImage.Width, srcImage.Height, - destFrames.Select(f => f.Image)); + ShpReader.Write(destStream, srcImage.Size, destFrames.Select(f => f.Data)); } static string FriendlyTypeName(Type t) diff --git a/OpenRA.Utility/Program.cs b/OpenRA.Utility/Program.cs index f3c9edea08..89c4f453de 100644 --- a/OpenRA.Utility/Program.cs +++ b/OpenRA.Utility/Program.cs @@ -23,11 +23,8 @@ namespace OpenRA.Utility { "--settings-value", Command.Settings }, { "--shp", Command.ConvertPngToShp }, { "--png", Command.ConvertShpToPng }, - { "--fromd2", Command.ConvertFormat2ToFormat80 }, { "--extract", Command.ExtractFiles }, - { "--tmp-png", Command.ConvertTmpToPng }, { "--remap", Command.RemapShp }, - { "--r8", Command.ConvertR8ToPng }, { "--transpose", Command.TransposeShp }, { "--docs", Command.ExtractTraitDocs }, { "--map-hash", Command.GetMapHash }, @@ -58,13 +55,10 @@ namespace OpenRA.Utility Console.WriteLine("Usage: OpenRA.Utility.exe [OPTION] [ARGS]"); Console.WriteLine(); Console.WriteLine(" --settings-value KEY Get value of KEY from settings.yaml"); - Console.WriteLine(" --shp PNGFILE FRAMEWIDTH Convert a single PNG with multiple frames appended after another to a SHP"); - Console.WriteLine(" --png SHPFILE PALETTE [--noshadow] Convert a SHP to a PNG containing all of its frames, optionally removing the shadow"); - Console.WriteLine(" --fromd2 DUNE2SHP C&CSHP Convert a Dune II SHP (C&C mouse cursor) to C&C SHP format."); - Console.WriteLine(" --extract MOD[,MOD]* FILES [--userdir] Extract files from mod packages to the current (or user) directory"); - Console.WriteLine(" --tmp-png MOD[,MOD]* THEATER FILES Extract terrain tiles to PNG"); + Console.WriteLine(" --shp PNGFILE [PNGFILE ...] Combine a list of PNG images into a SHP"); + Console.WriteLine(" --png SPRITEFILE PALETTE [--noshadow] [--nopadding] Convert a shp/tmp/R8 to a series of PNGs, optionally removing shadow"); + Console.WriteLine(" --extract MOD[,MOD]* FILES Extract files from mod packages to the current directory"); Console.WriteLine(" --remap SRCMOD:PAL DESTMOD:PAL SRCSHP DESTSHP Remap SHPs to another palette"); - Console.WriteLine(" --r8 R8FILE PALETTE START END FILENAME [--noshadow] [--tileset] Convert Dune 2000 DATA.R8 to PNGs choosing start- and endframe as well as type to append multiple frames to one PNG named by filename optionally removing the shadow."); Console.WriteLine(" --transpose SRCSHP DESTSHP START N M [START N M ...] Transpose the N*M block of frames starting at START."); Console.WriteLine(" --docs MOD Generate trait documentation in MarkDown format."); Console.WriteLine(" --map-hash MAPFILE Generate hash of specified oramap file."); diff --git a/mods/cnc/chrome/dialogs.yaml b/mods/cnc/chrome/dialogs.yaml index 0dd2997576..ea64b03ece 100644 --- a/mods/cnc/chrome/dialogs.yaml +++ b/mods/cnc/chrome/dialogs.yaml @@ -30,8 +30,10 @@ Background@COLOR_CHOOSER: Width:144 Height:72 ShpImage@FACT: - X:160 - Y:13 + X:153 + Y:1 + Width:80 + Height:73 Image:fact Palette:colorpicker Button@RANDOM_BUTTON: diff --git a/mods/cnc/cursors.yaml b/mods/cnc/cursors.yaml index cad78974c9..b5e237e8ba 100644 --- a/mods/cnc/cursors.yaml +++ b/mods/cnc/cursors.yaml @@ -4,7 +4,7 @@ Cursors: - mouse2: cursor + mouse2.shp: cursor scroll-t: start:1 scroll-tr: @@ -114,7 +114,7 @@ Cursors: start:154 length:24 - mouse4:cursor + mouse4.shp:cursor move: start:0 length:8 @@ -125,7 +125,7 @@ Cursors: start:0 length: 8 - attackmove:cursor + attackmove.shp:cursor attackmove: start:0 length:8 @@ -138,7 +138,7 @@ Cursors: start:13 length:1 - mouse3: cursor2 + mouse3.shp: cursor2 enter-blocked: start:212 length:1 @@ -170,7 +170,7 @@ Cursors: start:213 length:1 - nopower: cursor + nopower.shp: cursor powerdown-blocked: start:0 length: 1 diff --git a/mods/d2k/chrome/assetbrowser.yaml b/mods/d2k/chrome/assetbrowser.yaml deleted file mode 100644 index 270cdec6cd..0000000000 --- a/mods/d2k/chrome/assetbrowser.yaml +++ /dev/null @@ -1,215 +0,0 @@ -Background@ASSETBROWSER_BG: - Logic:AssetBrowserLogic - X:(WINDOW_RIGHT - WIDTH)/2 - Y:(WINDOW_BOTTOM - HEIGHT)/2 - Width:700 - Height:410 - Children: - ColorPreviewManager@COLOR_MANAGER: - Label@ASSETBROWSER_TITLE: - X:0 - Y:10 - Width:PARENT_RIGHT - Height:25 - Text:Game Asset Viewer & Converter - Align:Center - Font:Bold - DropDownButton@SOURCE_SELECTOR: - X:40 - Y:45 - Width:160 - Height:25 - Font:Bold - Text:Folders - ScrollPanel@ASSET_LIST: - X:40 - Y:80 - Width:160 - Height:190 - Children: - ScrollItem@ASSET_TEMPLATE: - Width:PARENT_RIGHT-27 - Height:25 - X:2 - Y:0 - Visible:false - Children: - Label@TITLE: - X:10 - Width:PARENT_RIGHT-20 - Height:25 - TextField@FILENAME_INPUT: - X:40 - Y:280 - Width:140 - Height:25 - Text:mouse.r8 - Button@LOAD_BUTTON: - X:40 - Y:310 - Width:140 - Height:25 - Text:Load - Font:Bold - Key:return - DropDownButton@PALETTE_SELECTOR: - X:230 - Y:45 - Width:150 - Height:25 - Font:Bold - Text:Palette - DropDownButton@COLOR: - X:380 - Y:45 - Width:80 - Height:25 - Children: - ColorBlock@COLORBLOCK: - X:5 - Y:6 - Width:PARENT_RIGHT-35 - Height:PARENT_BOTTOM-12 - Background@SPRITE_BG: - X:220 - Y:80 - Width:250 - Height:250 - Background:dialog4 - Children: - ShpImage@SPRITE: - X:4 - Y:4 - Width:246 - Height:246 - Image:mouse.r8 - Label@ACTIONS_TITLE: - X:PARENT_RIGHT - 150 - Y:45 - Width:PARENT_RIGHT - Height:25 - Text:Actions - Font:Bold - Button@EXPORT_BUTTON: - X:PARENT_RIGHT - 200 - Y:80 - Width:160 - Height:25 - Text:Selected to PNG - Font:Bold - Button@EXTRACT_BUTTON: - X:PARENT_RIGHT - 200 - Y:115 - Width:160 - Height:25 - Text:Extract all to PNG - Font:Bold - TextField@IMAGE_FILENAME_INPUT: - X:PARENT_RIGHT - 200 - Y:PARENT_BOTTOM - 235 - Width:100 - Height:25 - Text:pixelart.png - TextField@IMAGE_SIZE_INPUT: - X:PARENT_RIGHT - 90 - Y:PARENT_BOTTOM - 235 - Width:50 - Height:25 - Text:width - Button@IMPORT_BUTTON: - X:PARENT_RIGHT - 200 - Y:PARENT_BOTTOM - 200 - Width:160 - Height:25 - Text:Import from PNG - Font:Bold - Button@CLOSE_BUTTON: - X:PARENT_RIGHT - 200 - Y:PARENT_BOTTOM - 115 - Width:160 - Height:25 - Text:Close - Font:Bold - Key:escape - Container@FRAME_SELECTOR: - X:45 - Y:360 - Children: - Button@BUTTON_PREV: - X:0 - Y:0 - Width:25 - Height:25 - Children: - Image@IMAGE_PREV: - X:0 - Y:0 - Width:25 - Height:25 - ImageCollection:music - ImageName:prev - Button@BUTTON_PLAY: - X:35 - Y:0 - Width:25 - Height:25 - Children: - Image@IMAGE_PLAY: - X:0 - Y:0 - Width:25 - Height:25 - ImageCollection:music - ImageName:play - Button@BUTTON_PAUSE: - Visible: no - X:35 - Y:0 - Width:25 - Height:25 - Children: - Image@IMAGE_PAUSE: - X:0 - Y:0 - Width:25 - Height:25 - ImageCollection:music - ImageName:pause - Button@BUTTON_STOP: - X:70 - Y:0 - Width:25 - Height:25 - Children: - Image@IMAGE_STOP: - X:0 - Y:0 - Width:25 - Height:25 - ImageCollection:music - ImageName:stop - Button@BUTTON_NEXT: - X:105 - Y:0 - Width:25 - Height:25 - Children: - Image@IMAGE_NEXT: - X:0 - Y:0 - Width:25 - Height:25 - ImageCollection:music - ImageName:next - Slider@FRAME_SLIDER: - X:160 - Y:0 - Width:410 - Height:20 - MinimumValue: 0 - Label@FRAME_COUNT: - X:585 - Y:0 - Width:25 - Height:25 - Font:Bold \ No newline at end of file diff --git a/mods/d2k/chrome/color-picker.yaml b/mods/d2k/chrome/color-picker.yaml index 5a099fff48..0d4991736e 100644 --- a/mods/d2k/chrome/color-picker.yaml +++ b/mods/d2k/chrome/color-picker.yaml @@ -30,8 +30,10 @@ Background@COLOR_CHOOSER: Width:144 Height:72 ShpImage@FACT: - X:160 - Y:8 + X:153 + Y:1 + Width:80 + Height:73 Image:DATA.R8 Frame:1936 Palette:colorpicker diff --git a/mods/d2k/chrome/ingame.yaml b/mods/d2k/chrome/ingame.yaml index 92876a52a9..d7a96bad48 100644 --- a/mods/d2k/chrome/ingame.yaml +++ b/mods/d2k/chrome/ingame.yaml @@ -150,6 +150,8 @@ Container@PLAYER_WIDGETS: SupportPowerBin@INGAME_POWERS_BIN: X:0 Y:25 + IconWidth: 60 + IconHeight: 48 ReadyText: READY HoldText: ON HOLD BuildPalette@INGAME_BUILD_PALETTE: diff --git a/mods/d2k/cursors.yaml b/mods/d2k/cursors.yaml index f3d920dcb8..758cd367ec 100644 --- a/mods/d2k/cursors.yaml +++ b/mods/d2k/cursors.yaml @@ -2,10 +2,10 @@ ShadowIndex: 1 Palettes: cursor: cursor.pal - mouse.r8: d2k.pal + mouse: d2k.pal Cursors: - mouse.r8: mouse.r8 + mouse.r8: mouse scroll-t: start:112 x: 24 @@ -252,7 +252,7 @@ Cursors: x: 24 y: 24 - nopower: cursor + nopower.shp: cursor powerdown-blocked: start:0 length: 1 diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 7fff8c53f6..bdccad9daa 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -76,8 +76,7 @@ ChromeLayout: mods/ra/chrome/cheats.yaml mods/ra/chrome/musicplayer.yaml mods/d2k/chrome/tooltips.yaml - mods/d2k/chrome/assetbrowser.yaml - mods/ra/chrome/convertassets.yaml + mods/ra/chrome/assetbrowser.yaml mods/ra/chrome/irc.yaml Weapons: diff --git a/mods/d2k/sequences/aircraft.yaml b/mods/d2k/sequences/aircraft.yaml index bdbf974858..4a4bffa6b3 100644 --- a/mods/d2k/sequences/aircraft.yaml +++ b/mods/d2k/sequences/aircraft.yaml @@ -1,27 +1,27 @@ carryall: - idle: DATA.R8 + idle: DATA Start: 1923 Facings: -32 - unload: DATA.R8 + unload: DATA Start: 1923 Facings: -32 - icon: DATA.R8 + icon: DATA Start: 4029 Offset: -30,-24 orni: - idle: DATA.R8 + idle: DATA Start: 1955 Facings: -32 Length: 3 Tick: 120 Transpose: true - icon: DATA.R8 + icon: DATA Start: 4031 Offset: -30,-24 frigate: - idle: DATA.R8 + idle: DATA Start: 2517 Facings: 1 \ No newline at end of file diff --git a/mods/d2k/sequences/infantry.yaml b/mods/d2k/sequences/infantry.yaml index 7747737bbe..c86c982526 100644 --- a/mods/d2k/sequences/infantry.yaml +++ b/mods/d2k/sequences/infantry.yaml @@ -1,441 +1,441 @@ rifle: - stand: DATA.R8 + stand: DATA Start: 206 Facings: -8 Transpose: true - stand2: DATA.R8 + stand2: DATA Start: 206 Facings: -8 Transpose: true - stand3: DATA.R8 + stand3: DATA Start: 206 Facings: -8 Transpose: true - run: DATA.R8 + run: DATA Start: 214 Length: 6 Facings: -8 Tick: 110 Transpose: true - shoot: DATA.R8 + shoot: DATA Start: 254 Length: 6 Facings: -8 Transpose: true - prone-stand: DATA.R8 + prone-stand: DATA Start: 302 Facings: -8 Transpose: true - prone-run: DATA.R8 + prone-run: DATA Start: 310 Length: 3 Facings: -8 Transpose: true Tick: 110 - standup-0: DATA.R8 + standup-0: DATA Start: 302 Facings: -8 Transpose: true Tick: 120 - prone-shoot: DATA.R8 + prone-shoot: DATA Start: 334 Length: 6 Facings: -8 Transpose: true - die1: DATA.R8 + die1: DATA Start: 382 Length: 5 - die2: DATA.R8 + die2: DATA Start: 387 Length: 7 Tick: 80 - die3: DATA.R8 + die3: DATA Start: 394 Length: 7 - die4: DATA.R8 + die4: DATA Start: 401 Length: 7 - die5: DATA.R8 + die5: DATA Start: 408 Length: 7 - die6: DATA.R8 + die6: DATA Start: 415 Length: 12 - die-crushed: DATA.R8 + die-crushed: DATA Start: 430 Length: 12 Tick: 1600 - icon: DATA.R8 + icon: DATA Start: 4011 Offset: -30,-24 bazooka: - stand: DATA.R8 + stand: DATA Start: 458 Facings: -8 Transpose: true - stand2: DATA.R8 + stand2: DATA Start: 458 Facings: -8 Transpose: true - stand3: DATA.R8 + stand3: DATA Start: 458 Facings: -8 Transpose: true - run: DATA.R8 + run: DATA Start: 466 Length: 6 Facings: -8 Tick: 120 Transpose: true - shoot: DATA.R8 + shoot: DATA Start: 506 Length: 6 Facings: -8 Transpose: true - prone-stand: DATA.R8 + prone-stand: DATA Start: 562 Length: 1 Facings: -8 Transpose: true - prone-run: DATA.R8 + prone-run: DATA Start: 570 Length: 3 Facings: -8 Transpose: true Tick: 120 - standup-0: DATA.R8 + standup-0: DATA Start: 554 Length: 1 Facings: -8 Transpose: true - prone-shoot: DATA.R8 + prone-shoot: DATA Start: 586 Length: 6 Facings: -8 Transpose: true - die1: DATA.R8 + die1: DATA Start: 634 Length: 5 - die2: DATA.R8 + die2: DATA Start: 639 Length: 7 - die3: DATA.R8 + die3: DATA Start: 646 Length: 7 - die4: DATA.R8 + die4: DATA Start: 653 Length: 7 - die5: DATA.R8 + die5: DATA Start: 660 Length: 7 - die6: DATA.R8 + die6: DATA Start: 660 Length: 7 - die-crushed: DATA.R8 + die-crushed: DATA Start: 668 Length: 26 Tick: 1600 - icon: DATA.R8 + icon: DATA Start: 4012 Offset: -30,-24 engineer: - stand: DATA.R8 + stand: DATA Start: 1166 Facings: -8 Transpose: true - stand2: DATA.R8 + stand2: DATA Start: 1166 Facings: -8 Transpose: true - run: DATA.R8 + run: DATA Start: 1174 Length: 6 Facings: -8 Transpose: true Tick: 120 - die1: DATA.R8 + die1: DATA Start: 1342 Length: 5 - die2: DATA.R8 + die2: DATA Start: 1347 Length: 7 - die3: DATA.R8 + die3: DATA Start: 1354 Length: 7 - die4: DATA.R8 + die4: DATA Start: 1361 Length: 7 - die5: DATA.R8 + die5: DATA Start: 1368 Length: 7 - die6: DATA.R8 + die6: DATA Start: 1368 Length: 7 - die-crushed: DATA.R8 + die-crushed: DATA Start: 1376 Length: 26 Tick: 1600 - icon: DATA.R8 + icon: DATA Start: 4013 Offset: -30,-24 medic: # actually thumper - stand: DATA.R8 + stand: DATA Start: 1402 Facings: -8 Transpose: true - stand2: DATA.R8 + stand2: DATA Start: 1402 Facings: -8 Transpose: true - run: DATA.R8 + run: DATA Start: 1410 Length: 6 Facings: -8 Transpose: true Tick: 120 - heal: DATA.R8 + heal: DATA Start: 1458 Length: 5 Tick: 480 - die1: DATA.R8 + die1: DATA Start: 1543 Length: 5 - die2: DATA.R8 + die2: DATA Start: 1548 Length: 7 - die3: DATA.R8 + die3: DATA Start: 1555 Length: 7 - die4: DATA.R8 + die4: DATA Start: 1562 Length: 7 - die5: DATA.R8 + die5: DATA Start: 1569 Length: 7 - die6: DATA.R8 + die6: DATA Start: 1569 Length: 7 - die-crushed: DATA.R8 + die-crushed: DATA Start: 1577 Length: 26 Tick: 1600 - icon: DATA.R8 + icon: DATA Start: 4014 Offset: -30,-24 thumping: - idle: DATA.R8 + idle: DATA Start: 1458 Length: 5 Tick: 150 - make: DATA.R8 + make: DATA Start: 1458 Length: 5 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 1458 Length: 5 Tick: 150 - icon: DATA.R8 + icon: DATA Frames: 4014 Offset: -30,-24 fremen: - stand: DATA.R8 + stand: DATA Start: 694 Facings: -8 Transpose: true - stand2: DATA.R8 + stand2: DATA Start: 694 Facings: -8 Transpose: true - run: DATA.R8 + run: DATA Start: 702 Length: 6 Facings: -8 Transpose: true Tick: 120 - shoot: DATA.R8 + shoot: DATA Start: 742 Length: 6 Facings: -8 Transpose: true - prone-stand: DATA.R8 + prone-stand: DATA Start: 798 Length: 1 Facings: -8 Transpose: true - prone-run: DATA.R8 + prone-run: DATA Start: 806 Length: 3 Facings: -8 Transpose: true Tick: 120 - standup-0: DATA.R8 + standup-0: DATA Start: 790 Length: 1 Facings: -8 Transpose: true Tick: 120 - prone-shoot: DATA.R8 + prone-shoot: DATA Start: 822 Length: 6 Facings: -8 Transpose: true - die1: DATA.R8 + die1: DATA Start: 870 Length: 5 - die2: DATA.R8 + die2: DATA Start: 875 Length: 7 - die3: DATA.R8 + die3: DATA Start: 882 Length: 7 - die4: DATA.R8 + die4: DATA Start: 889 Length: 7 - die5: DATA.R8 + die5: DATA Start: 896 Length: 7 - die6: DATA.R8 + die6: DATA Start: 896 Length: 7 - die-crushed: DATA.R8 + die-crushed: DATA Start: 904 Length: 26 Tick: 1600 - icon: DATA.R8 + icon: DATA Start: 4032 Offset: -30,-24 saboteur: - stand: DATA.R8 + stand: DATA Start: 2149 Facings: -8 Transpose: true - stand2: DATA.R8 + stand2: DATA Start: 2149 Facings: -8 Transpose: true - stand3: DATA.R8 + stand3: DATA Start: 2149 Facings: -8 Transpose: true - run: DATA.R8 + run: DATA Start: 2157 Length: 6 Facings: -8 Transpose: true Tick: 120 - prone-stand: DATA.R8 + prone-stand: DATA Start: 2253 Length: 1 Facings: -8 Transpose: true - prone-run: DATA.R8 + prone-run: DATA Start: 2261 Length: 3 Facings: -8 Transpose: true Tick: 120 - standup-0: DATA.R8 + standup-0: DATA Start: 2245 Length: 1 Facings: -8 Transpose: true Tick: 120 - die1: DATA.R8 + die1: DATA Start: 2325 Length: 5 - die2: DATA.R8 + die2: DATA Start: 2330 Length: 7 - die3: DATA.R8 + die3: DATA Start: 2337 Length: 7 - die4: DATA.R8 + die4: DATA Start: 2344 Length: 7 - die5: DATA.R8 + die5: DATA Start: 2351 Length: 7 - die6: DATA.R8 + die6: DATA Start: 2351 Length: 7 - die-crushed: DATA.R8 + die-crushed: DATA Start: 2359 Length: 26 Tick: 1600 - icon: DATA.R8 + icon: DATA Start: 4034 Offset: -30,-24 sardaukar: - stand: DATA.R8 + stand: DATA Start: 930 Facings: -8 Transpose: true - stand2: DATA.R8 + stand2: DATA Start: 930 Facings: -8 Transpose: true - run: DATA.R8 + run: DATA Start: 938 Length: 6 Facings: -8 Transpose: true Tick: 120 - shoot: DATA.R8 + shoot: DATA Start: 978 Length: 6 Facings: -8 Transpose: true - prone-stand: DATA.R8 + prone-stand: DATA Start: 1034 Length: 1 Facings: -8 Transpose: true - prone-run: DATA.R8 + prone-run: DATA Start: 1042 Length: 3 Facings: -8 Transpose: true Tick: 120 - standup-0: DATA.R8 + standup-0: DATA Start: 1026 Length: 1 Facings: -8 Transpose: true Tick: 120 - prone-shoot: DATA.R8 + prone-shoot: DATA Start: 1058 Length: 6 Facings: 8 Transpose: true - die1: DATA.R8 + die1: DATA Start: 1106 Length: 5 - die2: DATA.R8 + die2: DATA Start: 1111 Length: 7 - die3: DATA.R8 + die3: DATA Start: 1118 Length: 7 - die4: DATA.R8 + die4: DATA Start: 1125 Length: 7 - die5: DATA.R8 + die5: DATA Start: 1132 Length: 7 - die6: DATA.R8 + die6: DATA Start: 1132 Length: 7 - die-crushed: DATA.R8 + die-crushed: DATA Start: 1140 Length: 26 Tick: 1600 - icon: DATA.R8 + icon: DATA Start: 4015 Offset: -30,-24 diff --git a/mods/d2k/sequences/misc.yaml b/mods/d2k/sequences/misc.yaml index 50e14f4796..ceedd4c11b 100644 --- a/mods/d2k/sequences/misc.yaml +++ b/mods/d2k/sequences/misc.yaml @@ -1,87 +1,87 @@ explosion: - piff: DATA.R8 + piff: DATA Start: 3626 Length: 5 - piffs: DATA.R8 + piffs: DATA Start: 3429 Length: 4 Tick: 80 BlendMode: Additive - small_explosion: DATA.R8 + small_explosion: DATA Start: 3403 Length: 15 BlendMode: Additive - med_explosion: DATA.R8 + med_explosion: DATA Start: 3390 Length: 12 BlendMode: Additive - tiny_explosion: DATA.R8 + tiny_explosion: DATA Start: 3386 Length: 4 Tick: 80 BlendMode: Additive - nuke: DATA.R8 + nuke: DATA Start: 3965 Length: 14 Tick: 60 BlendMode: Additive - mini_explosion: DATA.R8 + mini_explosion: DATA Start: 3403 Length: 15 Tick: 60 BlendMode: Additive - self_destruct: DATA.R8 + self_destruct: DATA Start: 3433 Length: 15 BlendMode: Additive - building: DATA.R8 + building: DATA Start: 3448 Length: 22 BlendMode: Additive - large_explosion: DATA.R8 + large_explosion: DATA Start: 3988 Length: 22 BlendMode: Additive - artillery: DATA.R8 + artillery: DATA Start: 3988 Length: 22 BlendMode: Additive - small_artillery: DATA.R8 + small_artillery: DATA Start: 3390 Length: 12 Tick: 60 BlendMode: Additive - small_napalm: DATA.R8 + small_napalm: DATA Start: 3421 Length: 8 BlendMode: Additive - shockwave: DATA.R8 + shockwave: DATA Start: 3687 Length: 6 BlendMode: Additive Tick: 120 - deviator: DATA.R8 + deviator: DATA Start: 3512 Length: 23 BlendMode: Additive Tick: 60 laserfire: - idle: DATA.R8 + idle: DATA Start: 3386 Length: 4 Tick: 80 BlendMode: Additive pips: - groups: DATA.R8 + groups: DATA Start: 17 Length: 10 - tag-primary: DATA.R8 + tag-primary: DATA Start: 110 - pip-empty: DATA.R8 + pip-empty: DATA Start: 15 - pip-green: DATA.R8 + pip-green: DATA Start: 16 clock: @@ -105,19 +105,19 @@ rank: Length: * overlay: - build-valid-arrakis: DATA.R8 + build-valid-arrakis: DATA Start: 0 Offset: -16,-16 - build-invalid: DATA.R8 + build-invalid: DATA Start: 1 Offset: -16,-16 - target-select: DATA.R8 + target-select: DATA Start: 2 Offset: -16,-16 - target-valid-arrakis: DATA.R8 + target-valid-arrakis: DATA Start: 0 Offset: -16,-16 - target-invalid: DATA.R8 + target-invalid: DATA Start: 1 Offset: -16,-16 @@ -131,29 +131,29 @@ rallypoint: Length: * rpg: - idle: DATA.R8 + idle: DATA Start: 3015 Facings: -32 120mm: - idle: DATA.R8 + idle: DATA Start: 3014 Length: 1 BlendMode: Additive 155mm: - idle: DATA.R8 + idle: DATA Start: 3081 Length: 1 crate-effects: - dollar: DATA.R8 + dollar: DATA Start: 3679 Length: 8 - reveal-map: DATA.R8 + reveal-map: DATA Start: 3947 Length: 18 - hide-map: DATA.R8 + hide-map: DATA Start: 3911 Length: 36 levelup: levelup @@ -162,70 +162,70 @@ crate-effects: Tick: 200 allyrepair: - repair: DATA.R8 + repair: DATA Frames: 3, 39 Length: 2 Tick: 300 missile: - idle: DATA.R8 + idle: DATA Start: 3088 Facings: -32 missile2: - idle: DATA.R8 + idle: DATA Start: 3306 Facings: -32 atomic: - up: DATA.R8 + up: DATA Start: 2147 Length: 1 - down: DATA.R8 + down: DATA Start: 2148 Length: 1 fire: - 1: DATA.R8 + 1: DATA Start: 3712 Length: 10 Offset: 0,-3 BlendMode: Additive - 2: DATA.R8 + 2: DATA Start: 3723 Length: 11 Offset: 0,-3 BlendMode: Additive - 3: DATA.R8 + 3: DATA Start: 3885 Length: 13 Offset: 0,-3 BlendMode: Additive - 4: DATA.R8 + 4: DATA Start: 3712 Length: 10 Offset: 0,-3 BlendMode: Additive smoke_m: - idle: DATA.R8 + idle: DATA Start: 3418 Length: 2 BlendMode: Additive - loop: DATA.R8 + loop: DATA Start: 3418 Length: 2 BlendMode: Additive - end: DATA.R8 + end: DATA Start: 3418 Length: 3 BlendMode: Additive bombs: - open: DATA.R8 + open: DATA Start: 3280 Length: 4 - idle: DATA.R8 + idle: DATA Start: 3280 Length: 4 @@ -248,59 +248,59 @@ waypoint: Length: * sietch: - idle: DATA.R8 + idle: DATA Start: 2998 doubleblast: - idle: DATA.R8 + idle: DATA Start: 3279 Facings: -16 BlendMode: Additive doubleblastbullet: - idle: DATA.R8 + idle: DATA Start: 3248 Facings: -16 BlendMode: Additive icon: - paratroopers: DATA.R8 + paratroopers: DATA Start: 4029 Offset: -30,-24 - ornistrike: DATA.R8 + ornistrike: DATA Start: 4031 Offset: -30,-24 - deathhand: DATA.R8 + deathhand: DATA Start: 4035 Offset: -30,-24 crate: - idle: DATA.R8 + idle: DATA Start: 102 ZOffset: -511 Offset: -16,-16 - land: DATA.R8 + land: DATA Start: 102 ZOffset: -511 Offset: -16,-16 spicebloom: - make: DATA.R8 + make: DATA Start: 107 Length: 3 Offset: -16,-16 - active: DATA.R8 + active: DATA Start: 109 Length: 1 ZOffset: -511 Offset: -16,-16 - idle: DATA.R8 + idle: DATA Start: 109 ZOffset: -511 Offset: -16,-16 moveflsh: - idle: DATA.R8 + idle: DATA Start: 3621 Length: 5 Tick: 80 diff --git a/mods/d2k/sequences/structures.yaml b/mods/d2k/sequences/structures.yaml index 03825fad21..61995dceb0 100644 --- a/mods/d2k/sequences/structures.yaml +++ b/mods/d2k/sequences/structures.yaml @@ -1,1618 +1,1618 @@ walla: - idle: DATA.R8 + idle: DATA Frames: 2527, 2530, 2528, 2538, 2531, 2532, 2542, 2535, 2529, 2539, 2533, 2534, 2540, 2536, 2537, 2541 Length: 16 Offset: -16,16 - scratched-idle: DATA.R8 + scratched-idle: DATA Frames: 2527, 2530, 2528, 2538, 2531, 2532, 2542, 2535, 2529, 2539, 2533, 2534, 2540, 2536, 2537, 2541 Length: 16 Offset: -16,16 - damaged-idle: DATA.R8 + damaged-idle: DATA Frames: 2543, 2546, 2544, 2554, 2547, 2548, 2558, 2551, 2545, 2555, 2549, 2550, 2556, 2552, 2553, 2557 Length: 16 Offset: -16,16 - critical-idle: DATA.R8 + critical-idle: DATA Frames: 2543, 2546, 2544, 2554, 2547, 2548, 2558, 2551, 2545, 2555, 2549, 2550, 2556, 2552, 2553, 2557 Length: 16 Offset: -16,16 - icon: DATA.R8 + icon: DATA Start: 4063 Offset: -30,-24 wallh: - idle: DATA.R8 + idle: DATA Frames: 2687, 2690, 2688, 2698, 2691, 2692, 2702, 2695, 2689, 2699, 2693, 2694, 2700, 2696, 2697, 2701 Length: 16 Offset: -16,16 - scratched-idle: DATA.R8 + scratched-idle: DATA Frames: 2687, 2690, 2688, 2698, 2691, 2692, 2702, 2695, 2689, 2699, 2693, 2694, 2700, 2696, 2697, 2701 Length: 16 Offset: -16,16 - damaged-idle: DATA.R8 + damaged-idle: DATA Frames: 2703, 2706, 2704, 2714, 2707, 2708, 2718, 2711, 2705, 2715, 2709, 2710, 2716, 2712, 2713, 2717 Length: 16 Offset: -16,16 - critical-idle: DATA.R8 + critical-idle: DATA Frames: 2703, 2706, 2704, 2714, 2707, 2708, 2718, 2711, 2705, 2715, 2709, 2710, 2716, 2712, 2713, 2717 Length: 16 Offset: -16,16 - icon: DATA.R8 + icon: DATA Start: 4064 Offset: -30,-24 wallo: - idle: DATA.R8 + idle: DATA Frames: 2847, 2850, 2848, 2858, 2851, 2852, 2862, 2855, 2849, 2859, 2853, 2854, 2860, 2856, 2857, 2861 Length: 16 Offset: -16,16 - scratched-idle: DATA.R8 + scratched-idle: DATA Frames: 2847, 2850, 2848, 2858, 2851, 2852, 2862, 2855, 2849, 2859, 2853, 2854, 2860, 2856, 2857, 2861 Length: 16 Offset: -16,16 - damaged-idle: DATA.R8 + damaged-idle: DATA Frames: 2863, 2866, 2864, 2874, 2867, 2868, 2878, 2871, 2865, 2875, 2869, 2870, 2876, 2872, 2873, 2877 Length: 16 Offset: -16,16 - critical-idle: DATA.R8 + critical-idle: DATA Frames: 2863, 2866, 2864, 2874, 2867, 2868, 2878, 2871, 2865, 2875, 2869, 2870, 2876, 2872, 2873, 2877 Length: 16 Offset: -16,16 - icon: DATA.R8 + icon: DATA Start: 4065 Offset: -30,-24 guntowera: - idle: DATA.R8 + idle: DATA Start: 2573 Facings: 1 Offset: -24,24 - recoil: DATA.R8 + recoil: DATA Start: 2573 Facings: 1 Offset: -24,24 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2573 Facings: 1 Offset: -24,24 - damaged-recoil: DATA.R8 + damaged-recoil: DATA Start: 2573 Facings: 1 Offset: -24,24 - turret: DATA.R8 + turret: DATA Start: 2589 Facings: -32 Offset: -24,24 - muzzle: DATA.R8 + muzzle: DATA Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4069 Offset: -30,-24 guntowerh: - idle: DATA.R8 + idle: DATA Start: 2733 Facings: 1 Offset: -24,24 - recoil: DATA.R8 + recoil: DATA Start: 2733 Facings: 1 Offset: -24,24 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2733 Facings: 1 Offset: -24,24 - damaged-recoil: DATA.R8 + damaged-recoil: DATA Start: 2733 Facings: 1 Offset: -24,24 - turret: DATA.R8 + turret: DATA Start: 2749 Facings: -32 Offset: -24,24 - muzzle: DATA.R8 + muzzle: DATA Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Frames: 4070 Offset: -30,-24 guntowero: - idle: DATA.R8 + idle: DATA Start: 2893 Facings: 1 Offset: -24,24 - recoil: DATA.R8 + recoil: DATA Start: 2893 Facings: 1 Offset: -24,24 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2893 Facings: 1 Offset: -24,24 - damaged-recoil: DATA.R8 + damaged-recoil: DATA Start: 2893 Facings: 1 Offset: -24,24 - turret: DATA.R8 + turret: DATA Start: 2909 Facings: -32 Offset: -24,24 - muzzle: DATA.R8 + muzzle: DATA Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4071 Offset: -30,-24 rockettowera: - idle: DATA.R8 + idle: DATA Start: 2733 Facings: 1 Offset: -24,24 - recoil: DATA.R8 + recoil: DATA Start: 2733 Facings: 1 Offset: -24,24 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2733 Facings: 1 Offset: -24,24 - damaged-recoil: DATA.R8 + damaged-recoil: DATA Start: 2733 Facings: 1 Offset: -24,24 - turret: DATA.R8 + turret: DATA Start: 2637 Facings: -32 Offset: -24,24 - icon: DATA.R8 + icon: DATA Start: 4075 Offset: -30,-24 rockettowerh: - idle: DATA.R8 + idle: DATA Start: 2781 Facings: 1 Offset: -24,24 - recoil: DATA.R8 + recoil: DATA Start: 2781 Facings: 1 Offset: -24,24 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2781 Facings: 1 Offset: -24,24 - damaged-recoil: DATA.R8 + damaged-recoil: DATA Start: 2781 Facings: 1 Offset: -24,24 - turret: DATA.R8 + turret: DATA Start: 2797 Facings: -32 Offset: -24,24 - icon: DATA.R8 + icon: DATA Start: 4076 Offset: -30,-24 rockettowero: - idle: DATA.R8 + idle: DATA Start: 2941 Facings: 1 Offset: -24,24 - recoil: DATA.R8 + recoil: DATA Start: 2941 Facings: 1 Offset: -24,24 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2941 Facings: 1 Offset: -24,24 - damaged-recoil: DATA.R8 + damaged-recoil: DATA Start: 2941 Facings: 1 Offset: -24,24 - turret: DATA.R8 + turret: DATA Start: 2957 Facings: -32 Offset: -24,24 - icon: DATA.R8 + icon: DATA Start: 4077 Offset: -30,-24 conyarda: - idle: DATA.R8 + idle: DATA Start: 2559 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4109 Length: 30 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4139 Length: 12 Offset: -48,64 Tick: 170 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2560 Offset: -48,64 -# build: DATA.R8 # TODO: overlay +# build: DATA # TODO: overlay # Start: 4436 # Length: 14 # Offset: -48,64 -# damaged-build: DATA.R8 # TODO: overlay +# damaged-build: DATA # TODO: overlay # Start: 4436 # Length: 14 # Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4046 Offset: -30,-24 repaira: - make: DATA.R8 + make: DATA Start: 4370 Length: 10 Offset: -48,48 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4380 Length: 10 Offset: -48,48 Tick: 100 - idle: DATA.R8 + idle: DATA Start: 2571 Offset: -48,48 ZOffset: -1c511 -# active: DATA.R8 # TODO: overlay +# active: DATA # TODO: overlay # Start: 4746 # Length: 14 # Offset: -48,48 # ZOffset: -1c511 -# damaged-active: DATA.R8 # TODO: overlay +# damaged-active: DATA # TODO: overlay # Start: 4746 # Length: 14 # Tick: 60 # Offset: -48,48 # ZOffset: -1c511 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2572 Offset: -48,48 ZOffset: -1c511 - icon: DATA.R8 + icon: DATA Start: 4096 Offset: -30,-24 repairh: - make: DATA.R8 + make: DATA Start: 4370 Length: 10 Offset: -48,48 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4380 Length: 10 Offset: -48,48 Tick: 100 - idle: DATA.R8 + idle: DATA Start: 2731 Offset: -48,48 ZOffset: -1c511 -# active: DATA.R8 # TODO: overlay +# active: DATA # TODO: overlay # Start: 4746 # Length: 14 # Offset: -48,48 # ZOffset: -1c511 -# damaged-active: DATA.R8 # TODO: overlay +# damaged-active: DATA # TODO: overlay # Start: 4746 # Length: 14 # Tick: 60 # Offset: -48,48 # ZOffset: -1c511 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2732 Offset: -48,48 ZOffset: -1c511 - icon: DATA.R8 + icon: DATA Start: 4097 Offset: -30,-24 repairo: - make: DATA.R8 + make: DATA Start: 4370 Length: 10 Offset: -48,48 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4380 Length: 10 Offset: -48,48 Tick: 100 - idle: DATA.R8 + idle: DATA Start: 2891 Offset: -48,48 ZOffset: -1c511 -# active: DATA.R8 # TODO: overlay +# active: DATA # TODO: overlay # Start: 4746 # Length: 14 # Offset: -48,48 # ZOffset: -1c511 -# damaged-active: DATA.R8 # TODO: overlay +# damaged-active: DATA # TODO: overlay # Start: 4746 # Length: 14 # Tick: 60 # Offset: -48,48 # ZOffset: -1c511 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2892 Offset: -48,48 ZOffset: -1c511 - icon: DATA.R8 + icon: DATA Start: 4098 Offset: -30,-24 starporta: - idle: DATA.R8 + idle: DATA Start: 2671 ZOffset: -1c511 Offset: -48,64 - active: DATA.R8 + active: DATA Start: 2671 Length: 1 ZOffset: -1c511 Offset: -48,64 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2672 ZOffset: -1c511 Offset: -48,64 - damaged-active: DATA.R8 + damaged-active: DATA Start: 2672 ZOffset: -1c511 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4347 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4358 Length: 11 Offset: -48,64 Tick: 100 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4092 Offset: -30,-24 pwra: - idle: DATA.R8 + idle: DATA Start: 2523 Offset: -32,64 - make: DATA.R8 + make: DATA Start: 4151 Length: 12 Offset: -32,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4163 Length: 12 Offset: -32,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2524 Offset: -32,64 - idle-zaps: DATA.R8 + idle-zaps: DATA Start: 4492 Length: 10 Offset: -32,64 Tick: 200 - damaged-idle-zaps: DATA.R8 + damaged-idle-zaps: DATA Start: 4497 Length: 5 Offset: -32,64 Tick: 200 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 617, 618, 637, 638 Length: 4 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4056 Offset: -30,-24 barra: - idle: DATA.R8 + idle: DATA Start: 2525 Offset: -32,64 - make: DATA.R8 + make: DATA Start: 4213 Length: 8 Offset: -32,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4221 Length: 9 Offset: -32,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2526 Offset: -32,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 617, 618, 637, 638 Length: 4 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4059 Offset: -30,-24 radara: - idle: DATA.R8 + idle: DATA Start: 2521 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4254 Length: 9 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4263 Length: 10 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2522 Offset: -48,80 - idle-dish: DATA.R8 + idle-dish: DATA Start: 4522 Length: 30 Offset: -48,80 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4072 Offset: -30,-24 refa: - idle: DATA.R8 + idle: DATA Start: 2561 Length: 1 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4231 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4241 Length: 12 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2561 Offset: -48,64 - idle-top: DATA.R8 + idle-top: DATA Start: 2562 Offset: -48,64 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2563 Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4066 Offset: -30,-24 siloa: - idle: DATA.R8 + idle: DATA Start: 2566 Length: 4 Offset: -16,16 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2569 Length: 1 Offset: -16,16 - make: DATA.R8 + make: DATA Start: 4313 Length: 7 Offset: -16,16 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4320 Length: 7 Offset: -16,16 Tick: 200 - icon: DATA.R8 + icon: DATA Start: 4084 Offset: -30,-24 hightecha: - idle: DATA.R8 + idle: DATA Start: 2564 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4274 Length: 10 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4284 Length: 10 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2565 Offset: -48,80 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4614 Length: 30 Offset: -48,80 Tick: 500 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4078 Offset: -30,-24 researcha: - idle: DATA.R8 + idle: DATA Start: 2669 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4391 Length: 10 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4401 Length: 11 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2670 Offset: -48,80 - idle-lights: DATA.R8 + idle-lights: DATA Start: 4760 Length: 60 Tick: 80 Offset: -48,80 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4099 Offset: -30,-24 researchh: - idle: DATA.R8 + idle: DATA Start: 2829 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4391 Length: 10 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4401 Length: 11 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2830 Offset: -48,80 - idle-lights: DATA.R8 + idle-lights: DATA Start: 4760 Length: 60 Tick: 80 Offset: -48,80 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4100 Offset: -30,-24 researcho: - idle: DATA.R8 + idle: DATA Start: 2989 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4391 Length: 10 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4401 Length: 11 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2990 Offset: -48,80 - idle-lights: DATA.R8 + idle-lights: DATA Start: 4760 Length: 60 Tick: 80 Offset: -48,80 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4101 Offset: -30,-24 palacea: - idle: DATA.R8 + idle: DATA Start: 2676 Offset: -48,48 - make: DATA.R8 + make: DATA Start: 4413 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4424 Length: 11 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2677 Offset: -48,48 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4102 Offset: -30,-24 lighta: - idle: DATA.R8 + idle: DATA Start: 2673 Length: 1 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4295 Length: 8 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4303 Length: 9 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2673 Offset: -48,64 - build-top: DATA.R8 + build-top: DATA Start: 2674 Length: 1 Offset: -48,64 - damaged-build-top: DATA.R8 + damaged-build-top: DATA Start: 2675 Length: 1 Offset: -48,64 - idle-top: DATA.R8 + idle-top: DATA Start: 2674 Offset: -48,64 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2675 Offset: -48,64 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4644 Length: 30 Offset: -48,64 Tick: 200 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4081 Offset: -30,-24 heavya: - idle: DATA.R8 + idle: DATA Start: 2518 Length: 1 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4328 Length: 9 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4337 Length: 9 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2518 Offset: -48,80 - build-top: DATA.R8 + build-top: DATA Start: 2519 Length: 1 Offset: -48,80 - damaged-build-top: DATA.R8 + damaged-build-top: DATA Start: 2520 Length: 1 Offset: -48,80 - idle-top: DATA.R8 + idle-top: DATA Start: 2519 Offset: -48,80 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2520 Offset: -48,80 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4674 Length: 47 Offset: -48,80 Tick: 200 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4087 Offset: -30,-24 conyardh: - idle: DATA.R8 + idle: DATA Start: 2719 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4109 Length: 30 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4139 Length: 12 Offset: -48,64 Tick: 170 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2720 Offset: -48,64 -# build: DATA.R8 # TODO: overlay +# build: DATA # TODO: overlay # Start: 4450 # Length: 14 # Offset: -48,64 -# damaged-build: DATA.R8 # TODO: overlay +# damaged-build: DATA # TODO: overlay # Start: 4450 # Length: 14 # Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4047 Offset: -30,-24 starporth: - idle: DATA.R8 + idle: DATA Start: 2831 ZOffset: -1c511 Offset: -48,64 - active: DATA.R8 + active: DATA Start: 2831 Length: 1 Offset: -48,64 ZOffset: -1c511 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2832 Offset: -48,64 ZOffset: -1c511 - damaged-active: DATA.R8 + damaged-active: DATA Start: 2832 Offset: -48,64 ZOffset: -1c511 - make: DATA.R8 + make: DATA Start: 4347 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4358 Length: 11 Offset: -48,64 Tick: 100 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4093 Offset: -30,-24 pwrh: - idle: DATA.R8 + idle: DATA Start: 2683 Offset: -32,64 - make: DATA.R8 + make: DATA Start: 4151 Length: 12 Offset: -32,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4163 Length: 12 Offset: -32,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2684 Offset: -32,64 - idle-zaps: DATA.R8 + idle-zaps: DATA Start: 4502 Length: 10 Offset: -32,64 Tick: 200 - damaged-idle-zaps: DATA.R8 + damaged-idle-zaps: DATA Start: 4507 Length: 5 Offset: -32,64 Tick: 200 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 617, 618, 637, 638 Length: 4 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4057 Offset: -30,-24 barrh: - idle: DATA.R8 + idle: DATA Start: 2685 Offset: -32,64 - make: DATA.R8 + make: DATA Start: 4213 Length: 8 Offset: -32,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4221 Length: 9 Offset: -32,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2686 Offset: -32,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 617, 618, 637, 638 Length: 4 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4060 Offset: -30,-24 radarh: - idle: DATA.R8 + idle: DATA Start: 2681 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4254 Length: 9 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4263 Length: 10 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2682 Offset: -48,80 - idle-dish: DATA.R8 + idle-dish: DATA Start: 4553 Length: 30 Offset: -48,80 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4073 Offset: -30,-24 refh: - idle: DATA.R8 + idle: DATA Start: 2721 Length: 1 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4231 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4241 Length: 12 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2721 Offset: -48,64 - idle-top: DATA.R8 + idle-top: DATA Start: 2722 Offset: -48,64 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2723 Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4067 Offset: -30,-24 siloh: - idle: DATA.R8 + idle: DATA Start: 2726 Length: 4 Offset: -16,16 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2730 Length: 1 Offset: -16,16 - make: DATA.R8 + make: DATA Start: 4313 Length: 7 Offset: -16,16 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4320 Length: 7 Offset: -16,16 Tick: 200 - icon: DATA.R8 + icon: DATA Start: 4085 Offset: -30,-24 hightechh: - idle: DATA.R8 + idle: DATA Start: 2724 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4274 Length: 10 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4284 Length: 10 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2725 Offset: -48,80 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4614 Length: 30 Offset: -48,80 Tick: 500 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4079 Offset: -30,-24 palaceh: - idle: DATA.R8 + idle: DATA Start: 2836 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4413 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4424 Length: 11 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2837 Offset: -48,64 -# active: DATA.R8 # TODO: overlay +# active: DATA # TODO: overlay # Start: 4820 # Length: 20 # Offset: -48,64 - damaged-active: DATA.R8 + damaged-active: DATA Start: 4820 Length: 20 Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4103 Offset: -30,-24 lighth: - idle: DATA.R8 + idle: DATA Start: 2833 Length: 1 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4295 Length: 8 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4303 Length: 9 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2833 Offset: -48,64 - build-top: DATA.R8 + build-top: DATA Start: 2834 Length: 1 Offset: -48,64 - damaged-build-top: DATA.R8 + damaged-build-top: DATA Start: 2835 Length: 1 Offset: -48,64 - idle-top: DATA.R8 + idle-top: DATA Start: 2834 Offset: -48,64 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2835 Offset: -48,64 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4644 Length: 30 Offset: -48,64 Tick: 200 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4082 Offset: -30,-24 heavyh: - idle: DATA.R8 + idle: DATA Start: 2678 Length: 1 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4328 Length: 9 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4337 Length: 9 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2678 Offset: -48,80 - build-top: DATA.R8 + build-top: DATA Start: 2679 Length: 1 Offset: -48,80 - damaged-build-top: DATA.R8 + damaged-build-top: DATA Start: 2680 Length: 1 Offset: -48,80 - idle-top: DATA.R8 + idle-top: DATA Start: 2679 Offset: -48,80 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2680 Offset: -48,80 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4674 Length: 47 Offset: -48,80 Tick: 200 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4088 Offset: -30,-24 conyardo: - idle: DATA.R8 + idle: DATA Start: 2879 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4109 Length: 30 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4139 Length: 12 Offset: -48,64 Tick: 170 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2880 Offset: -48,64 -# build: DATA.R8 # TODO: overlay +# build: DATA # TODO: overlay # Start: 4464 # Length: 14 # Offset: -48,64 -# damaged-build: DATA.R8 # TODO: overlay +# damaged-build: DATA # TODO: overlay # Start: 4464 # Length: 14 # Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4048 Offset: -30,-24 starporto: - idle: DATA.R8 + idle: DATA Start: 2991 Offset: -48,64 ZOffset: -1c511 - active: DATA.R8 + active: DATA Start: 2991 Length: 1 Offset: -48,64 ZOffset: -1c511 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2992 Offset: -48,64 ZOffset: -1c511 - damaged-active: DATA.R8 + damaged-active: DATA Start: 2992 Offset: -48,64 ZOffset: -1c511 - make: DATA.R8 + make: DATA Start: 4347 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4358 Length: 11 Offset: -48,64 Tick: 100 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4094 Offset: -30,-24 pwro: - idle: DATA.R8 + idle: DATA Start: 2843 Length: 1 Offset: -32,64 - make: DATA.R8 + make: DATA Start: 4151 Length: 12 Offset: -32,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4163 Length: 12 Offset: -32,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2844 Offset: -32,64 - idle-zaps: DATA.R8 + idle-zaps: DATA Start: 4512 Length: 10 Offset: -32,64 Tick: 200 - damaged-idle-zaps: DATA.R8 + damaged-idle-zaps: DATA Start: 4517 Length: 5 Offset: -32,64 Tick: 200 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 617, 618, 637, 638 Length: 4 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4058 Offset: -30,-24 barro: - idle: DATA.R8 + idle: DATA Start: 2845 Offset: -32,64 - make: DATA.R8 + make: DATA Start: 4213 Length: 8 Offset: -32,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4221 Length: 9 Offset: -32,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2846 Offset: -32,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 617, 618, 637, 638 Length: 4 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4061 Offset: -30,-24 radaro: - idle: DATA.R8 + idle: DATA Start: 2841 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4254 Length: 9 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4263 Length: 10 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2842 Offset: -48,80 - idle-dish: DATA.R8 + idle-dish: DATA Start: 4583 Length: 30 Offset: -48,80 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4074 Offset: -30,-24 refo: - idle: DATA.R8 + idle: DATA Start: 2881 Length: 1 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4231 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4241 Length: 12 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2881 Offset: -48,64 - idle-top: DATA.R8 + idle-top: DATA Start: 2882 Offset: -48,64 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2883 Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4068 Offset: -30,-24 siloo: - idle: DATA.R8 + idle: DATA Start: 2886 Length: 4 Offset: -16,16 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2890 Length: 1 Offset: -16,16 - make: DATA.R8 + make: DATA Start: 4313 Length: 7 Offset: -16,16 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4320 Length: 7 Offset: -16,16 Tick: 200 - icon: DATA.R8 + icon: DATA Start: 4086 Offset: -30,-24 hightecho: - idle: DATA.R8 + idle: DATA Start: 2884 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4274 Length: 10 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4284 Length: 10 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2885 Offset: -48,80 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4614 Length: 30 Offset: -48,80 Tick: 500 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4080 Offset: -30,-24 palaceo: - idle: DATA.R8 + idle: DATA Start: 2996 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4413 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4424 Length: 11 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2997 Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4104 Offset: -30,-24 lighto: - idle: DATA.R8 + idle: DATA Start: 2993 Length: 1 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4295 Length: 8 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4303 Length: 9 Offset: -48,64 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2993 Offset: -48,64 - build-top: DATA.R8 + build-top: DATA Start: 2994 Length: 1 Offset: -48,64 - damaged-build-top: DATA.R8 + damaged-build-top: DATA Start: 2995 Length: 1 Offset: -48,64 - idle-top: DATA.R8 + idle-top: DATA Start: 2994 Offset: -48,64 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2995 Offset: -48,64 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4644 Length: 30 Offset: -48,64 Tick: 200 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4083 Offset: -30,-24 heavyo: - idle: DATA.R8 + idle: DATA Start: 2838 Length: 1 Offset: -48,80 - make: DATA.R8 + make: DATA Start: 4328 Length: 9 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4337 Length: 9 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 2838 Offset: -48,80 - build-top: DATA.R8 + build-top: DATA Start: 2839 Length: 1 Offset: -48,80 - damaged-build-top: DATA.R8 + damaged-build-top: DATA Start: 2840 Length: 1 Offset: -48,80 - idle-top: DATA.R8 + idle-top: DATA Start: 2839 Offset: -48,80 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 2840 Offset: -48,80 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4674 Length: 47 Offset: -48,80 Tick: 200 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4089 Offset: -30,-24 palacec: # TODO: unused - idle: DATA.R8 + idle: DATA Start: 3004 Offset: -48,64 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 3005 Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 icon: palacecicon Start: 0 - make: DATA.R8 + make: DATA Start: 4413 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4424 Length: 11 Offset: -48,64 Tick: 100 starportc: # TODO: unused - idle: DATA.R8 + idle: DATA Start: 2999 Offset: -48,64 ZOffset: -1c511 - active: DATA.R8 + active: DATA Start: 2999 Length: 1 Offset: -48,64 ZOffset: -1c511 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 3000 Offset: -48,64 ZOffset: -1c511 - damaged-active: DATA.R8 + damaged-active: DATA Start: 3000 Offset: -48,64 ZOffset: -1c511 - make: DATA.R8 + make: DATA Start: 4347 Length: 11 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4358 Length: 11 Offset: -48,64 Tick: 100 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 # TODO: blank + icon: DATA # TODO: blank Start: 4020 Offset: -30,-24 heavyc: # TODO: unused - idle: DATA.R8 + idle: DATA Start: 3001 Length: 1 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4328 Length: 9 Offset: -48,80 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4337 Length: 9 Offset: -48,80 Tick: 100 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 3001 Offset: -48,64 - build-top: DATA.R8 + build-top: DATA Start: 3002 Length: 1 Offset: -48,64 - damaged-build-top: DATA.R8 + damaged-build-top: DATA Start: 3003 Length: 1 Offset: -48,64 - idle-top: DATA.R8 + idle-top: DATA Start: 3002 Offset: -48,64 - damaged-idle-top: DATA.R8 + damaged-idle-top: DATA Start: 3003 Offset: -48,64 - idle-welding: DATA.R8 + idle-welding: DATA Start: 4674 Length: 47 Offset: -48,80 Tick: 200 BlendMode: Additive - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 # TODO: blank + icon: DATA # TODO: blank Start: 4020 Offset: -30,-24 conyardc: # TODO: unused - idle: DATA.R8 + idle: DATA Start: 3006 Offset: -48,64 - make: DATA.R8 + make: DATA Start: 4109 Length: 30 Offset: -48,64 - crumble-overlay: DATA.R8 + crumble-overlay: DATA Start: 4139 Length: 12 Offset: -48,64 Tick: 200 - damaged-idle: DATA.R8 + damaged-idle: DATA Start: 3007 Offset: -48,64 -# build: DATA.R8 # TODO: overlay +# build: DATA # TODO: overlay # Start: 4478 # Length: 14 # Offset: -48,64 -# damaged-build: DATA.R8 # TODO: overlay +# damaged-build: DATA # TODO: overlay # Start: 4478 # Length: 14 # Offset: -48,64 - bib: BLOXBASE.R8 + bib: BLOXBASE Frames: 611, 612, 613, 631, 632, 633 Length: 6 Offset: -16,-16 - icon: DATA.R8 + icon: DATA Start: 4049 Offset: -30,-24 plates: # TODO: unused - idle: DATA.R8 + idle: DATA Start: 3008 Length: 6 - 4-plates-icon: DATA.R8 + 4-plates-icon: DATA Start: 4050 Offset: -30,-24 - 6-plates-icon: DATA.R8 + 6-plates-icon: DATA Start: 4053 Offset: -30,-24 diff --git a/mods/d2k/sequences/vehicles.yaml b/mods/d2k/sequences/vehicles.yaml index 3d8fe4debf..c562658597 100644 --- a/mods/d2k/sequences/vehicles.yaml +++ b/mods/d2k/sequences/vehicles.yaml @@ -1,174 +1,174 @@ dmcv: - idle: DATA.R8 + idle: DATA Start: 1795 Facings: -32 - icon: DATA.R8 + icon: DATA Start: 4023 Offset: -30,-24 harvester: - idle: DATA.R8 + idle: DATA Start: 1699 Facings: -32 - harvest: DATA.R8 + harvest: DATA Start: 3631 Length: 6 Facings: -8 Tick: 80 ZOffset: 1 - dock: DATA.R8 + dock: DATA Start: 3370 Length: 10 - dock-loop: DATA.R8 + dock-loop: DATA Start: 3380 Length: 1 - icon: DATA.R8 + icon: DATA Start: 4019 Offset: -30,-24 trike: - idle: DATA.R8 + idle: DATA Start: 1635 Facings: -32 - unload: DATA.R8 + unload: DATA Start: 1635 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Frames: 3839, 3839, 3840, 3840, 3841, 3841, 3842, 3842, 3843, 3843, 3844, 3844, 3845, 3845, 3846, 3846, 3847, 3847, 3848, 3848, 3849, 3849, 3850, 3850, 3851, 3851, 3852, 3852, 3853, 3853, 3854, 3854, 3855, 3855, 3856, 3856, 3857, 3857, 3858, 3858, 3859, 3859, 3860, 3860, 3861, 3861, 3862, 3862, 3863, 3863, 3864, 3864, 3865, 3865, 3866, 3866, 3867, 3867, 3868, 3868, 3869, 3869, 3870, 3870 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4041 Offset: -30,-24 quad: - idle: DATA.R8 + idle: DATA Start: 1667 Facings: -32 - unload: DATA.R8 + unload: DATA Start: 1667 Facings: -32 - icon: DATA.R8 + icon: DATA Start: 4018 Offset: -30,-24 siegetank: - idle: DATA.R8 + idle: DATA Start: 1763 Facings: -32 - turret: DATA.R8 + turret: DATA Start: 1891 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Start: 3418 Length: 3 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4026 Offset: -30,-24 missiletank: - idle: DATA.R8 + idle: DATA Start: 1603 Facings: -32 - icon: DATA.R8 + icon: DATA Start: 4024 Offset: -30,-24 sonictank: - idle: DATA.R8 + idle: DATA Start: 1827 Facings: -32 - icon: DATA.R8 + icon: DATA Start: 4027 Offset: -30,-24 combata: - idle: DATA.R8 + idle: DATA Start: 1731 Facings: -32 - turret: DATA.R8 + turret: DATA Start: 1859 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4020 Offset: -30,-24 combath: - idle: DATA.R8 + idle: DATA Start: 2051 Facings: -32 - turret: DATA.R8 + turret: DATA Start: 2115 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4021 Offset: -30,-24 devast: - idle: DATA.R8 + idle: DATA Start: 2083 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Frames: 3807, 3807, 3808, 3808, 3809, 3809, 3810, 3810, 3810, 3811, 3811, 3812, 3812, 3813, 3813, 3814, 3814, 3815, 3816, 3816, 3817, 3817, 3818, 3819, 3819, 3820, 3820, 3821, 3821, 3822, 3822, 3823, 3823, 3824, 3824, 3825, 3825, 3826, 3826, 3827, 3827, 3828, 3828, 3829, 3829, 3830, 3830, 3831, 3831, 3832, 3832, 3832, 3833, 3833, 3834, 3834, 3835, 3835, 3836, 3836, 3837, 3837, 3838, 3838 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4028 Offset: -30,-24 combato: - idle: DATA.R8 + idle: DATA Start: 2453 Facings: -32 - turret: DATA.R8 + turret: DATA Start: 2485 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Frames: 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3780, 3781, 3781, 3782, 3782, 3783, 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3788, 3789, 3789, 3790, 3790, 3791, 3791, 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800, 3800, 3801, 3801, 3802, 3802, 3803, 3803, 3804, 3804, 3805, 3805, 3806, 3806 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4022 Offset: -30,-24 raider: - idle: DATA.R8 + idle: DATA Start: 2421 Facings: -32 - unload: DATA.R8 + unload: DATA Start: 2421 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Frames: 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3747, 3748, 3748, 3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3754, 3755, 3755, 3756, 3756, 3757, 3757, 3758, 3758, 3759, 3759, 3760, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765, 3766, 3766, 3767, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774, 3774 Facings: -32 Length: 2 BlendMode: Additive - icon: DATA.R8 + icon: DATA Start: 4017 Offset: -30,-24 stealthraider: - idle: DATA.R8 + idle: DATA Start: 2421 Facings: -32 - unload: DATA.R8 + unload: DATA Start: 2421 Facings: -32 - muzzle: DATA.R8 + muzzle: DATA Frames: 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3747, 3748, 3748, 3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3754, 3755, 3755, 3756, 3756, 3757, 3757, 3758, 3758, 3759, 3759, 3760, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765, 3766, 3766, 3767, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774, 3774 Facings: -32 Length: 2 @@ -177,9 +177,9 @@ stealthraider: Start: 0 deviatortank: - idle: DATA.R8 + idle: DATA Start: 2389 Facings: -32 - icon: DATA.R8 + icon: DATA Start: 4025 Offset: -30,-24 \ No newline at end of file diff --git a/mods/d2k/tilesets/arrakis.yaml b/mods/d2k/tilesets/arrakis.yaml index ddc8992a5a..54c531b82e 100644 --- a/mods/d2k/tilesets/arrakis.yaml +++ b/mods/d2k/tilesets/arrakis.yaml @@ -3,7 +3,7 @@ General: Id: ARRAKIS SheetSize: 1024 Palette: d2k.pal - Extensions: .R8, .shp + Extensions: .R8, .r8, .shp Terrain: TerrainType@Sand: diff --git a/mods/ra/chrome/assetbrowser.yaml b/mods/ra/chrome/assetbrowser.yaml index bf313b1c9b..ef5fea2547 100644 --- a/mods/ra/chrome/assetbrowser.yaml +++ b/mods/ra/chrome/assetbrowser.yaml @@ -3,29 +3,36 @@ Background@ASSETBROWSER_BG: X:(WINDOW_RIGHT - WIDTH)/2 Y:(WINDOW_BOTTOM - HEIGHT)/2 Width:700 - Height:410 + Height:500 Children: ColorPreviewManager@COLOR_MANAGER: Label@ASSETBROWSER_TITLE: - X:0 - Y:10 + Y:20 Width:PARENT_RIGHT Height:25 - Text:Game Asset Viewer & Converter - Align:Center Font:Bold + Align:Center + Text:Asset Browser + Label@SOURCE_SELECTOR_DESC: + X:20 + Y:35 + Width:160 + Height:25 + Font:TinyBold + Align:Center + Text:Select asset source DropDownButton@SOURCE_SELECTOR: - X:40 - Y:45 + X:20 + Y:60 Width:160 Height:25 Font:Bold Text:Folders ScrollPanel@ASSET_LIST: - X:40 - Y:80 + X:20 + Y:90 Width:160 - Height:190 + Height:275 Children: ScrollItem@ASSET_TEMPLATE: Width:PARENT_RIGHT-27 @@ -38,30 +45,45 @@ Background@ASSETBROWSER_BG: X:10 Width:PARENT_RIGHT-20 Height:25 + Label@FILENAME_DESC: + X:20 + Y:370 + Width:160 + Height:25 + Font:TinyBold + Align:Center + Text:Search for file TextField@FILENAME_INPUT: - X:40 - Y:280 - Width:140 + X:20 + Y:395 + Width:160 Height:25 Text:mouse.shp Button@LOAD_BUTTON: - X:40 - Y:310 - Width:140 + X:20 + Y:425 + Width:160 Height:25 Text:Load Font:Bold Key:return - DropDownButton@PALETTE_SELECTOR: - X:230 - Y:45 + Label@PALETTE_DESC: + X:PARENT_RIGHT-WIDTH-270 + Y:60 + Width:150 + Height:25 + Font:Bold + Align:Right + Text:Palette: + DropDownButton@PALETTE_SELECTOR: + X:PARENT_RIGHT-WIDTH-110 + Y:60 Width:150 Height:25 Font:Bold - Text:Palette DropDownButton@COLOR: - X:380 - Y:45 + X:PARENT_RIGHT-WIDTH-20 + Y:60 Width:80 Height:25 Children: @@ -71,69 +93,19 @@ Background@ASSETBROWSER_BG: Width:PARENT_RIGHT-35 Height:PARENT_BOTTOM-12 Background@SPRITE_BG: - X:220 - Y:80 - Width:250 - Height:250 - Background:dialog4 + X:190 + Y:90 + Width:490 + Height:330 + Background:dialog3 Children: ShpImage@SPRITE: - X:4 - Y:4 - Width:246 - Height:246 + Width:PARENT_RIGHT + Height:PARENT_BOTTOM Image:mouse - Label@ACTIONS_TITLE: - X:PARENT_RIGHT - 150 - Y:45 - Width:PARENT_RIGHT - Height:25 - Text:Actions - Font:Bold - Button@EXPORT_BUTTON: - X:PARENT_RIGHT - 200 - Y:80 - Width:160 - Height:25 - Text:Selected to PNG - Font:Bold - Button@EXTRACT_BUTTON: - X:PARENT_RIGHT - 200 - Y:115 - Width:160 - Height:25 - Text:Extract all to PNG - Font:Bold - TextField@IMAGE_FILENAME_INPUT: - X:PARENT_RIGHT - 200 - Y:PARENT_BOTTOM - 235 - Width:100 - Height:25 - Text:pixelart.png - TextField@IMAGE_SIZE_INPUT: - X:PARENT_RIGHT - 90 - Y:PARENT_BOTTOM - 235 - Width:50 - Height:25 - Text:width - Button@IMPORT_BUTTON: - X:PARENT_RIGHT - 200 - Y:PARENT_BOTTOM - 200 - Width:160 - Height:25 - Text:Import from PNG - Font:Bold - Button@CLOSE_BUTTON: - X:PARENT_RIGHT - 200 - Y:PARENT_BOTTOM - 115 - Width:160 - Height:25 - Text:Close - Font:Bold - Key:escape Container@FRAME_SELECTOR: - X:45 - Y:360 + X:190 + Y:425 Children: Button@BUTTON_PREV: X:0 @@ -202,14 +174,22 @@ Background@ASSETBROWSER_BG: ImageCollection:music ImageName:next Slider@FRAME_SLIDER: - X:160 - Y:0 - Width:410 + X:140 + Y:3 + Width:300 Height:20 MinimumValue: 0 Label@FRAME_COUNT: - X:585 - Y:0 - Width:25 + X:445 + Width:40 Height:25 - Font:Bold \ No newline at end of file + Font:TinyBold + Align:Left + Button@CLOSE_BUTTON: + Key:escape + X:PARENT_RIGHT-180 + Y:PARENT_BOTTOM-45 + Width:160 + Height:25 + Font:Bold + Text:Close \ No newline at end of file diff --git a/mods/ra/chrome/color-picker.yaml b/mods/ra/chrome/color-picker.yaml index 543e01b5c3..0daef841a9 100644 --- a/mods/ra/chrome/color-picker.yaml +++ b/mods/ra/chrome/color-picker.yaml @@ -30,8 +30,10 @@ Background@COLOR_CHOOSER: Width:144 Height:72 ShpImage@FACT: - X:156 + X:153 Y:1 + Width:80 + Height:73 Image:fact Palette:colorpicker Button@RANDOM_BUTTON: diff --git a/mods/ra/chrome/convertassets.yaml b/mods/ra/chrome/convertassets.yaml deleted file mode 100644 index ecd4cc73af..0000000000 --- a/mods/ra/chrome/convertassets.yaml +++ /dev/null @@ -1,47 +0,0 @@ -Background@CONVERT_ASSETS_PANEL: - Logic:ConvertGameFilesLogic - X:(WINDOW_RIGHT - WIDTH)/2 - Y:(WINDOW_BOTTOM - HEIGHT)/2 - Width:500 - Height:160 - Children: - Label@TITLE: - X:0 - Y:20 - Width:PARENT_RIGHT - Height:25 - Text:Extracting and Converting Gamefiles - Align:Center - Font:Bold - Container@EXTRACTING: - Width:PARENT_RIGHT - Height:PARENT_BOTTOM - Visible: false - Children: - ProgressBar@PROGRESS_BAR: - X:50 - Y:55 - Width:PARENT_RIGHT - 100 - Height:25 - Label@STATUS_LABEL: - X:50 - Y:80 - Width:PARENT_RIGHT - 100 - Height:25 - Align:Left - Button@RETRY_BUTTON: - X:PARENT_RIGHT - 280 - Y:PARENT_BOTTOM - 45 - Width:120 - Height:25 - Text:Retry - Font:Bold - Key:return - Button@BACK_BUTTON: - X:PARENT_RIGHT - 140 - Y:PARENT_BOTTOM - 45 - Width:120 - Height:25 - Text:Back - Font:Bold - Key:escape \ No newline at end of file diff --git a/mods/ra/chrome/modchooser.yaml b/mods/ra/chrome/modchooser.yaml index e11d52b424..9a9bcc7f91 100644 --- a/mods/ra/chrome/modchooser.yaml +++ b/mods/ra/chrome/modchooser.yaml @@ -7,14 +7,15 @@ Background@MODS_PANEL: Children: Label@TITLE: Text:Select Mod - Width:PARENT_RIGHT Y:20 + Width:PARENT_RIGHT + Height:25 Font:Bold Align:Center ScrollPanel@MOD_LIST: - X:15 + X:20 Y:70 - Width:710 + Width:700 Height:PARENT_BOTTOM - 125 Children: ScrollItem@MOD_TEMPLATE: diff --git a/mods/ra/cursors.yaml b/mods/ra/cursors.yaml index 0e3e4c0347..929db975b1 100644 --- a/mods/ra/cursors.yaml +++ b/mods/ra/cursors.yaml @@ -2,7 +2,7 @@ cursor: cursor.pal Cursors: - mouse: cursor + mouse.shp: cursor scroll-t: start:1 scroll-tr: @@ -163,7 +163,7 @@ Cursors: start:148 length: 12 - nopower: cursor + nopower.shp: cursor powerdown-blocked: start:0 length: 1 diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index e36a9a7edb..630f97383f 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -92,7 +92,6 @@ ChromeLayout: mods/ra/chrome/musicplayer.yaml mods/ra/chrome/tooltips.yaml mods/ra/chrome/assetbrowser.yaml - mods/ra/chrome/convertassets.yaml mods/ra/chrome/irc.yaml Weapons: diff --git a/mods/ts/chrome/color-picker.yaml b/mods/ts/chrome/color-picker.yaml index e7553cd415..6e33ea9771 100644 --- a/mods/ts/chrome/color-picker.yaml +++ b/mods/ts/chrome/color-picker.yaml @@ -30,8 +30,10 @@ Background@COLOR_CHOOSER: Width:144 Height:72 ShpImage@GTCNST: - X:121 - Y:0-68 + X:153 + Y:1-40 + Width:80 + Height:73 Image:gtcnstmk Palette:colorpicker Button@RANDOM_BUTTON: diff --git a/mods/ts/cursors.yaml b/mods/ts/cursors.yaml index 6ae5c78658..dcd50bde72 100644 --- a/mods/ts/cursors.yaml +++ b/mods/ts/cursors.yaml @@ -2,7 +2,7 @@ cursor: mousepal.pal Cursors: - mouse: cursor + mouse.shp: cursor scroll-t: #TODO start: 2 scroll-tr: #TODO diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index 0030ff7b92..ffb690c447 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -120,7 +120,6 @@ ChromeLayout: mods/ra/chrome/musicplayer.yaml mods/ra/chrome/tooltips.yaml mods/ra/chrome/assetbrowser.yaml - mods/ra/chrome/convertassets.yaml mods/ra/chrome/irc.yaml Weapons: