From 88768031a5080fd62ad6d97f158b8e1093684c0c Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 00:36:02 +0100 Subject: [PATCH 01/14] Add BecameVisible and BecameHidden methods to ChromeLogic. --- OpenRA.Game/Widgets/Widget.cs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/Widgets/Widget.cs b/OpenRA.Game/Widgets/Widget.cs index 0c58992546..f6dc0a8e2a 100644 --- a/OpenRA.Game/Widgets/Widget.cs +++ b/OpenRA.Game/Widgets/Widget.cs @@ -33,9 +33,23 @@ namespace OpenRA.Widgets public static void CloseWindow() { if (WindowList.Count > 0) - Root.RemoveChild(WindowList.Pop()); + { + var hidden = WindowList.Pop(); + Root.RemoveChild(hidden); + if (hidden.LogicObjects != null) + foreach (var l in hidden.LogicObjects) + l.BecameHidden(); + } + if (WindowList.Count > 0) - Root.AddChild(WindowList.Peek()); + { + var restore = WindowList.Peek(); + Root.AddChild(restore); + + if (restore.LogicObjects != null) + foreach (var l in restore.LogicObjects) + l.BecameVisible(); + } } public static Widget OpenWindow(string id) @@ -148,6 +162,8 @@ namespace OpenRA.Widgets { public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public virtual void Tick() { } + public virtual void BecameHidden() { } + public virtual void BecameVisible() { } protected virtual void Dispose(bool disposing) { } } From 90468974ce611e2ee973cdecf7a573bc930dc905 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 00:36:14 +0100 Subject: [PATCH 02/14] Add tooltip support to ImageWidget. --- OpenRA.Mods.Common/Widgets/ImageWidget.cs | 33 +++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/OpenRA.Mods.Common/Widgets/ImageWidget.cs b/OpenRA.Mods.Common/Widgets/ImageWidget.cs index ace095e384..2838ee6055 100644 --- a/OpenRA.Mods.Common/Widgets/ImageWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ImageWidget.cs @@ -17,16 +17,27 @@ namespace OpenRA.Mods.Common.Widgets { public class ImageWidget : Widget { + public readonly string TooltipTemplate; + public readonly string TooltipContainer; + public string ImageCollection = ""; public string ImageName = ""; public bool ClickThrough = true; public Func GetImageName; public Func GetImageCollection; + [Translate] public string TooltipText; + + Lazy tooltipContainer; + public Func GetTooltipText; + public ImageWidget() { GetImageName = () => ImageName; GetImageCollection = () => ImageCollection; + GetTooltipText = () => TooltipText; + tooltipContainer = Exts.Lazy(() => + Ui.Root.Get(TooltipContainer)); } protected ImageWidget(ImageWidget other) @@ -37,6 +48,12 @@ namespace OpenRA.Mods.Common.Widgets GetImageName = other.GetImageName; ImageCollection = other.ImageCollection; GetImageCollection = other.GetImageCollection; + + TooltipTemplate = other.TooltipTemplate; + TooltipContainer = other.TooltipContainer; + GetTooltipText = other.GetTooltipText; + tooltipContainer = Exts.Lazy(() => + Ui.Root.Get(TooltipContainer)); } public override Widget Clone() { return new ImageWidget(this); } @@ -57,5 +74,21 @@ namespace OpenRA.Mods.Common.Widgets { return !ClickThrough && RenderBounds.Contains(mi.Location); } + + public override void MouseEntered() + { + if (TooltipContainer == null || GetTooltipText == null) + return; + + tooltipContainer.Value.SetTooltip(TooltipTemplate, new WidgetArgs() { { "getText", GetTooltipText } }); + } + + public override void MouseExited() + { + if (TooltipContainer == null) + return; + + tooltipContainer.Value.RemoveTooltip(); + } } } From 67d6de91e34c9d6b5005004b95bef497797dc855 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 00:36:29 +0100 Subject: [PATCH 03/14] Allow custom BorderWidths on ScrollPanelWidget. --- OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs b/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs index 4493e59e0e..ba23b09600 100644 --- a/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs +++ b/OpenRA.Mods.Common/Widgets/ScrollPanelWidget.cs @@ -34,6 +34,7 @@ namespace OpenRA.Mods.Common.Widgets { readonly Ruleset modRules; public int ScrollbarWidth = 24; + public int BorderWidth = 1; public int TopBottomSpacing = 2; public int ItemSpacing = 0; public int ButtonDepth = ChromeMetrics.Get("ButtonDepth"); @@ -165,7 +166,7 @@ namespace OpenRA.Mods.Common.Widgets WidgetUtils.DrawRGBA(ChromeProvider.GetImage("scrollbar", downPressed || downDisabled ? "down_pressed" : "down_arrow"), new float2(downButtonRect.Left + downOffset, downButtonRect.Top + downOffset)); - var drawBounds = backgroundRect.InflateBy(-1, -1, -1, -1); + var drawBounds = backgroundRect.InflateBy(-BorderWidth, -BorderWidth, -BorderWidth, -BorderWidth); Game.Renderer.EnableScissor(drawBounds); drawBounds.Offset((-ChildOrigin).ToPoint()); From 92ea404b0b20a79eee90cd38946a895ffc8c62ce Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 29 Apr 2016 18:20:15 +0100 Subject: [PATCH 04/14] Add command to dump InstallShield contents. --- .../FileSystem/InstallShieldPackage.cs | 4 +- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 + .../ListInstallShieldContentsCommand.cs | 46 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 OpenRA.Mods.Common/UtilityCommands/ListInstallShieldContentsCommand.cs diff --git a/OpenRA.Game/FileSystem/InstallShieldPackage.cs b/OpenRA.Game/FileSystem/InstallShieldPackage.cs index a479f7ae40..5089edd74b 100644 --- a/OpenRA.Game/FileSystem/InstallShieldPackage.cs +++ b/OpenRA.Game/FileSystem/InstallShieldPackage.cs @@ -18,7 +18,7 @@ namespace OpenRA.FileSystem { public sealed class InstallShieldPackage : IReadOnlyPackage { - struct Entry + public struct Entry { public readonly uint Offset; public readonly uint Length; @@ -124,6 +124,8 @@ namespace OpenRA.FileSystem return index.ContainsKey(filename); } + public IReadOnlyDictionary Index { get { return new ReadOnlyDictionary(index); } } + public void Dispose() { s.Dispose(); diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 867149f46c..dbc816b25a 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -751,6 +751,7 @@ + diff --git a/OpenRA.Mods.Common/UtilityCommands/ListInstallShieldContentsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ListInstallShieldContentsCommand.cs new file mode 100644 index 0000000000..52678b81aa --- /dev/null +++ b/OpenRA.Mods.Common/UtilityCommands/ListInstallShieldContentsCommand.cs @@ -0,0 +1,46 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Linq; +using OpenRA.FileSystem; + +namespace OpenRA.Mods.Common.UtilityCommands +{ + class ListInstallShieldContents : IUtilityCommand + { + public string Name { get { return "--list-installshield"; } } + + public bool ValidateArguments(string[] args) + { + return args.Length == 2; + } + + [Desc("ARCHIVE.Z", "Lists the content ranges for a InstallShield V3 file")] + public void Run(ModData modData, string[] args) + { + var filename = Path.GetFileName(args[1]); + var path = Path.GetDirectoryName(args[1]); + + var fs = new OpenRA.FileSystem.FileSystem(); + fs.Mount(path, "parent"); + var package = new InstallShieldPackage(fs, "parent|" + filename); + + foreach (var kv in package.Index) + { + Console.WriteLine("{0}:", kv.Key); + Console.WriteLine("\tOffset: {0}", 255 + kv.Value.Offset); + Console.WriteLine("\tLength: {0}", kv.Value.Length); + } + } + } +} From bd3096f21ba3e18f3b9ffadfb63a1d6e3c639925 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 19:16:28 +0100 Subject: [PATCH 05/14] Add command to dump Mix contents. --- OpenRA.Game/FileSystem/MixFile.cs | 9 ++++ OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 + .../UtilityCommands/ListMixContentsCommand.cs | 50 +++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 OpenRA.Mods.Common/UtilityCommands/ListMixContentsCommand.cs diff --git a/OpenRA.Game/FileSystem/MixFile.cs b/OpenRA.Game/FileSystem/MixFile.cs index fee7538b2e..7a36fb7e15 100644 --- a/OpenRA.Game/FileSystem/MixFile.cs +++ b/OpenRA.Game/FileSystem/MixFile.cs @@ -205,6 +205,15 @@ namespace OpenRA.FileSystem return GetContent(e); } + public IReadOnlyDictionary Index + { + get + { + var absoluteIndex = index.ToDictionary(e => e.Key, e => new PackageEntry(e.Value.Hash, (uint)(e.Value.Offset + dataStart), e.Value.Length)); + return new ReadOnlyDictionary(absoluteIndex); + } + } + public bool Contains(string filename) { return index.ContainsKey(filename); diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index dbc816b25a..2a137026fc 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -752,6 +752,7 @@ + diff --git a/OpenRA.Mods.Common/UtilityCommands/ListMixContentsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ListMixContentsCommand.cs new file mode 100644 index 0000000000..39063b5605 --- /dev/null +++ b/OpenRA.Mods.Common/UtilityCommands/ListMixContentsCommand.cs @@ -0,0 +1,50 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Linq; +using OpenRA.FileSystem; + +namespace OpenRA.Mods.Common.UtilityCommands +{ + class ListMixContents : IUtilityCommand + { + public string Name { get { return "--list-mix"; } } + + public bool ValidateArguments(string[] args) + { + return args.Length == 2; + } + + [Desc("ARCHIVE.Z", "Lists the content ranges for a mix file")] + public void Run(ModData modData, string[] args) + { + var filename = Path.GetFileName(args[1]); + var path = Path.GetDirectoryName(args[1]); + + var fs = new OpenRA.FileSystem.FileSystem(); + + // Needed to access the global mix database + fs.LoadFromManifest(modData.Manifest); + + fs.Mount(path, "parent"); + var package = new MixFile(fs, "parent|" + filename); + + foreach (var kv in package.Index.OrderBy(kv => kv.Value.Offset)) + { + Console.WriteLine("{0}:", kv.Key); + Console.WriteLine("\tOffset: {0}", kv.Value.Offset); + Console.WriteLine("\tLength: {0}", kv.Value.Length); + } + } + } +} From 054b3a43a4610500a58c6c8a06f73d3b40cc40f1 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 14 Jun 2016 01:45:51 +0100 Subject: [PATCH 06/14] Add a lightweight MSCab parser. --- .../FileFormats/MSCabCompression.cs | 131 ++++++++++++++++++ OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 2 + .../ListMSCabContentsCommand.cs | 35 +++++ 3 files changed, 168 insertions(+) create mode 100644 OpenRA.Mods.Common/FileFormats/MSCabCompression.cs create mode 100644 OpenRA.Mods.Common/UtilityCommands/ListMSCabContentsCommand.cs diff --git a/OpenRA.Mods.Common/FileFormats/MSCabCompression.cs b/OpenRA.Mods.Common/FileFormats/MSCabCompression.cs new file mode 100644 index 0000000000..998b8e9992 --- /dev/null +++ b/OpenRA.Mods.Common/FileFormats/MSCabCompression.cs @@ -0,0 +1,131 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using ICSharpCode.SharpZipLib.Zip.Compression; +using ICSharpCode.SharpZipLib.Zip.Compression.Streams; + +namespace OpenRA.Mods.Common.FileFormats +{ + public sealed class MSCabCompression + { + class CabFolder + { + public readonly uint BlockOffset; + public readonly ushort BlockCount; + public readonly ushort CompressionType; + + public CabFolder(Stream stream) + { + BlockOffset = stream.ReadUInt32(); + BlockCount = stream.ReadUInt16(); + CompressionType = stream.ReadUInt16(); + } + } + + class CabFile + { + public readonly string FileName; + public readonly uint DecompressedLength; + public readonly uint DecompressedOffset; + public readonly ushort FolderIndex; + + public CabFile(Stream stream) + { + DecompressedLength = stream.ReadUInt32(); + DecompressedOffset = stream.ReadUInt32(); + FolderIndex = stream.ReadUInt16(); + stream.Position += 6; + FileName = stream.ReadASCIIZ(); + } + } + + readonly CabFolder[] folders; + readonly CabFile[] files; + readonly Stream stream; + + public MSCabCompression(Stream stream) + { + this.stream = stream; + + var signature = stream.ReadASCII(4); + if (signature != "MSCF") + throw new InvalidDataException("Not a Microsoft CAB package!"); + + stream.Position += 12; + var filesOffset = stream.ReadUInt32(); + stream.Position += 6; + var folderCount = stream.ReadUInt16(); + var fileCount = stream.ReadUInt16(); + if (stream.ReadUInt16() != 0) + throw new InvalidDataException("Only plain packages (without reserved header space or prev/next archives) are supported!"); + + stream.Position += 4; + + folders = new CabFolder[folderCount]; + for (var i = 0; i < folderCount; i++) + { + folders[i] = new CabFolder(stream); + if (folders[i].CompressionType != 1) + throw new InvalidDataException("Compression type is not supported"); + } + + files = new CabFile[fileCount]; + stream.Seek(filesOffset, SeekOrigin.Begin); + for (var i = 0; i < fileCount; i++) + files[i] = new CabFile(stream); + } + + public byte[] ExtractFile(string filename, Action onProgress = null) + { + var file = files.FirstOrDefault(f => f.FileName == filename); + if (file == null) + return null; + + var folder = folders[file.FolderIndex]; + stream.Seek(folder.BlockOffset, SeekOrigin.Begin); + + using (var outputStream = new MemoryStream()) + { + var inflater = new Inflater(true); + var buffer = new byte[4096]; + for (var i = 0; i < folder.BlockCount; i++) + { + if (onProgress != null) + onProgress((int)(100 * outputStream.Position / file.DecompressedLength)); + + // Ignore checksums + stream.Position += 4; + var blockLength = stream.ReadUInt16(); + stream.Position += 4; + + using (var batch = new MemoryStream(stream.ReadBytes(blockLength - 2))) + using (var inflaterStream = new InflaterInputStream(batch, inflater)) + { + int n; + while ((n = inflaterStream.Read(buffer, 0, buffer.Length)) > 0) + outputStream.Write(buffer, 0, n); + } + + inflater.Reset(); + } + + outputStream.Seek(file.DecompressedOffset, SeekOrigin.Begin); + return outputStream.ReadBytes((int)file.DecompressedLength); + } + } + + public IEnumerable Contents { get { return files.Select(f => f.FileName); } } + } +} diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 2a137026fc..260b39f710 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -753,6 +753,8 @@ + + diff --git a/OpenRA.Mods.Common/UtilityCommands/ListMSCabContentsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ListMSCabContentsCommand.cs new file mode 100644 index 0000000000..c5d90d7a7f --- /dev/null +++ b/OpenRA.Mods.Common/UtilityCommands/ListMSCabContentsCommand.cs @@ -0,0 +1,35 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.IO; +using OpenRA.Mods.Common.FileFormats; + +namespace OpenRA.Mods.Common.UtilityCommands +{ + class ListMSCabContentsCommand : IUtilityCommand + { + public string Name { get { return "--list-mscab"; } } + + public bool ValidateArguments(string[] args) + { + return args.Length == 2; + } + + [Desc("ARCHIVE.CAB", "Lists the filenames contained within a MSCAB file")] + public void Run(ModData modData, string[] args) + { + var package = new MSCabCompression(File.OpenRead(args[1])); + foreach (var file in package.Contents) + Console.WriteLine("{0}", file); + } + } +} From ff147f39b907e4fda9f5a5d7a187be059deaa07c Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Fri, 29 Apr 2016 17:58:05 +0100 Subject: [PATCH 07/14] Add new content installer framework. --- OpenRA.Game/ContentInstaller.cs | 2 + OpenRA.Game/ModContent.cs | 118 +++++ OpenRA.Game/ModMetadata.cs | 4 + OpenRA.Game/OpenRA.Game.csproj | 1 + OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 5 + .../Installation/DownloadPackageLogic.cs | 234 ++++++++++ .../Installation/InstallFromDiscLogic.cs | 422 ++++++++++++++++++ .../Logic/Installation/InstallLogic.cs | 1 + .../ModContentDiscTooltipLogic.cs | 53 +++ .../Logic/Installation/ModContentLogic.cs | 127 ++++++ .../Installation/ModContentPromptLogic.cs | 72 +++ .../Widgets/Logic/ModBrowserLogic.cs | 53 ++- mods/modchooser/chrome.png | Bin 65044 -> 82267 bytes mods/modchooser/chrome.yaml | 109 +++-- mods/modchooser/content.yaml | 370 +++++++++++++++ mods/modchooser/install.yaml | 47 -- mods/modchooser/mod.yaml | 1 + mods/modchooser/modchooser.yaml | 33 +- 18 files changed, 1533 insertions(+), 119 deletions(-) create mode 100644 OpenRA.Game/ModContent.cs create mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs create mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs create mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentDiscTooltipLogic.cs create mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs create mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentPromptLogic.cs create mode 100644 mods/modchooser/content.yaml diff --git a/OpenRA.Game/ContentInstaller.cs b/OpenRA.Game/ContentInstaller.cs index 1d4c388939..7847ccfbdd 100644 --- a/OpenRA.Game/ContentInstaller.cs +++ b/OpenRA.Game/ContentInstaller.cs @@ -10,6 +10,8 @@ #endregion using System.Collections.Generic; +using System.IO; +using System.Linq; namespace OpenRA { diff --git a/OpenRA.Game/ModContent.cs b/OpenRA.Game/ModContent.cs new file mode 100644 index 0000000000..acb8f65d5d --- /dev/null +++ b/OpenRA.Game/ModContent.cs @@ -0,0 +1,118 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace OpenRA +{ + public class ModContent : IGlobalModData + { + public class ModPackage + { + public readonly string Title; + public readonly string[] TestFiles = { }; + public readonly string[] Discs = { }; + public readonly bool Required; + public readonly string Download; + + public ModPackage(MiniYaml yaml) + { + Title = yaml.Value; + FieldLoader.Load(this, yaml); + } + + public bool IsInstalled() + { + return TestFiles.All(file => File.Exists(Path.GetFullPath(Platform.ResolvePath(file)))); + } + } + + public class ModDisc + { + public readonly string Title; + public readonly Dictionary IDFiles; + + [FieldLoader.Ignore] public readonly List Install; + + public ModDisc(MiniYaml yaml) + { + Title = yaml.Value; + var installNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Install"); + if (installNode != null) + Install = installNode.Value.Nodes; + + FieldLoader.Load(this, yaml); + } + } + + public class ModDownload + { + public readonly string Title; + public readonly string URL; + public readonly string MirrorList; + public readonly Dictionary Extract; + + public ModDownload(MiniYaml yaml) + { + Title = yaml.Value; + FieldLoader.Load(this, yaml); + } + } + + public readonly string InstallPromptMessage; + public readonly string QuickDownload; + public readonly string HeaderMessage; + + [FieldLoader.LoadUsing("LoadPackages")] + public readonly Dictionary Packages = new Dictionary(); + + static object LoadPackages(MiniYaml yaml) + { + var packages = new Dictionary(); + var packageNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Packages"); + if (packageNode != null) + foreach (var node in packageNode.Value.Nodes) + packages.Add(node.Key, new ModPackage(node.Value)); + + return packages; + } + + [FieldLoader.LoadUsing("LoadDownloads")] + public readonly Dictionary Downloads; + + static object LoadDownloads(MiniYaml yaml) + { + var downloads = new Dictionary(); + var downloadNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Downloads"); + if (downloadNode != null) + foreach (var node in downloadNode.Value.Nodes) + downloads.Add(node.Key, new ModDownload(node.Value)); + + return downloads; + } + + [FieldLoader.LoadUsing("LoadDiscs")] + public readonly Dictionary Discs; + + static object LoadDiscs(MiniYaml yaml) + { + var discs = new Dictionary(); + var discNode = yaml.Nodes.FirstOrDefault(n => n.Key == "Discs"); + if (discNode != null) + foreach (var node in discNode.Value.Nodes) + discs.Add(node.Key, new ModDisc(node.Value)); + + return discs; + } + } +} diff --git a/OpenRA.Game/ModMetadata.cs b/OpenRA.Game/ModMetadata.cs index f0f271e098..12c95206b5 100644 --- a/OpenRA.Game/ModMetadata.cs +++ b/OpenRA.Game/ModMetadata.cs @@ -31,6 +31,7 @@ namespace OpenRA public Dictionary RequiresMods; public ContentInstaller Content; + public ModContent ModContent; public IReadOnlyPackage Package; static Dictionary ValidateMods() @@ -81,6 +82,9 @@ namespace OpenRA if (nd.ContainsKey("ContentInstaller")) metadata.Content = FieldLoader.Load(nd["ContentInstaller"]); + if (nd.ContainsKey("ModContent")) + metadata.ModContent = FieldLoader.Load(nd["ModContent"]); + // Mods in the support directory and oramod packages (which are listed later // in the CandidateMods list) override mods in the main install. ret[pair.First] = metadata; diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index ae3b220ae1..3679465ac8 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -249,6 +249,7 @@ + diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 260b39f710..89ad221f3e 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -752,6 +752,11 @@ + + + + + diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs new file mode 100644 index 0000000000..4ec8588251 --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackageLogic.cs @@ -0,0 +1,234 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Net; +using System.Text; +using ICSharpCode.SharpZipLib; +using ICSharpCode.SharpZipLib.Zip; +using OpenRA.Support; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Widgets.Logic +{ + public class DownloadPackageLogic : ChromeLogic + { + static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; + readonly ModContent.ModDownload download; + readonly Action onSuccess; + + readonly Widget panel; + readonly ProgressBarWidget progressBar; + + Func getStatusText = () => ""; + string downloadHost; + + [ObjectCreator.UseCtor] + public DownloadPackageLogic(Widget widget, ModContent.ModDownload download, Action onSuccess) + { + this.download = download; + this.onSuccess = onSuccess; + + Log.AddChannel("install", "install.log"); + + panel = widget.Get("PACKAGE_DOWNLOAD_PANEL"); + progressBar = panel.Get("PROGRESS_BAR"); + + var statusLabel = panel.Get("STATUS_LABEL"); + var statusFont = Game.Renderer.Fonts[statusLabel.Font]; + var status = new CachedTransform(s => WidgetUtils.TruncateText(s, statusLabel.Bounds.Width, statusFont)); + statusLabel.GetText = () => status.Update(getStatusText()); + + var text = "Downloading {0}".F(download.Title); + panel.Get("TITLE").Text = text; + + ShowDownloadDialog(); + } + + void ShowDownloadDialog() + { + getStatusText = () => "Fetching list of mirrors..."; + progressBar.Indeterminate = true; + + var retryButton = panel.Get("RETRY_BUTTON"); + retryButton.IsVisible = () => false; + + var cancelButton = panel.Get("CANCEL_BUTTON"); + + var file = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + + Action deleteTempFile = () => + { + Log.Write("install", "Deleting temporary file " + file); + File.Delete(file); + }; + + Action onDownloadProgress = i => + { + var dataReceived = 0.0f; + var dataTotal = 0.0f; + var mag = 0; + var dataSuffix = ""; + + if (i.TotalBytesToReceive < 0) + { + dataTotal = float.NaN; + dataReceived = i.BytesReceived; + dataSuffix = SizeSuffixes[0]; + } + else + { + mag = (int)Math.Log(i.TotalBytesToReceive, 1024); + dataTotal = i.TotalBytesToReceive / (float)(1L << (mag * 10)); + dataReceived = i.BytesReceived / (float)(1L << (mag * 10)); + dataSuffix = SizeSuffixes[mag]; + } + + progressBar.Indeterminate = false; + progressBar.Percentage = i.ProgressPercentage; + + getStatusText = () => "Downloading from {4} {1:0.00}/{2:0.00} {3} ({0}%)".F(i.ProgressPercentage, + dataReceived, dataTotal, dataSuffix, + downloadHost ?? "unknown host"); + }; + + Action onExtractProgress = s => Game.RunAfterTick(() => getStatusText = () => s); + + Action onError = s => Game.RunAfterTick(() => + { + Log.Write("install", "Download failed: " + s); + + progressBar.Indeterminate = false; + progressBar.Percentage = 100; + getStatusText = () => "Error: " + s; + retryButton.IsVisible = () => true; + }); + + Action onDownloadComplete = (i, cancelled) => + { + if (i.Error != null) + { + onError(Download.FormatErrorMessage(i.Error)); + return; + } + + if (cancelled) + { + onError("Download cancelled"); + return; + } + + // Automatically extract + getStatusText = () => "Extracting..."; + progressBar.Indeterminate = true; + + var extracted = new List(); + try + { + using (var stream = File.OpenRead(file)) + using (var z = new ZipFile(stream)) + { + foreach (var kv in download.Extract) + { + var entry = z.GetEntry(kv.Value); + if (!entry.IsFile) + continue; + + onExtractProgress("Extracting " + entry.Name); + Log.Write("install", "Extracting " + entry.Name); + var targetPath = Platform.ResolvePath(kv.Key); + Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); + extracted.Add(targetPath); + + using (var zz = z.GetInputStream(entry)) + using (var f = File.Create(targetPath)) + zz.CopyTo(f); + } + + z.Close(); + } + + Game.RunAfterTick(() => { Ui.CloseWindow(); onSuccess(); }); + } + catch (Exception) + { + Log.Write("install", "Extraction failed"); + + foreach (var f in extracted) + { + Log.Write("install", "Deleting " + f); + File.Delete(f); + } + + onError("Invalid archive"); + } + finally + { + deleteTempFile(); + } + }; + + Action downloadUrl = url => + { + Log.Write("install", "Downloading " + url); + + downloadHost = new Uri(url).Host; + var dl = new Download(url, file, onDownloadProgress, onDownloadComplete); + cancelButton.OnClick = () => { dl.Cancel(); deleteTempFile(); Ui.CloseWindow(); }; + retryButton.OnClick = () => { dl.Cancel(); ShowDownloadDialog(); }; + }; + + if (download.MirrorList != null) + { + Log.Write("install", "Fetching mirrors from " + download.MirrorList); + + Action onFetchMirrorsComplete = (i, cancelled) => + { + progressBar.Indeterminate = true; + + if (i.Error != null) + { + onError(Download.FormatErrorMessage(i.Error)); + return; + } + + if (cancelled) + { + onError("Download cancelled"); + return; + } + + try + { + var data = Encoding.UTF8.GetString(i.Result); + var mirrorList = data.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); + downloadUrl(mirrorList.Random(new MersenneTwister())); + } + catch (Exception e) + { + Log.Write("install", "Mirror selection failed with error:"); + Log.Write("install", e.ToString()); + onError("Online mirror is not available. Please install from an original disc."); + } + }; + + var updateMirrors = new Download(download.MirrorList, onDownloadProgress, onFetchMirrorsComplete); + cancelButton.OnClick = () => { updateMirrors.Cancel(); Ui.CloseWindow(); }; + retryButton.OnClick = () => { updateMirrors.Cancel(); ShowDownloadDialog(); }; + } + else + downloadUrl(download.URL); + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs new file mode 100644 index 0000000000..b451812e6e --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromDiscLogic.cs @@ -0,0 +1,422 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Threading.Tasks; +using OpenRA.FileFormats; +using OpenRA.Mods.Common.FileFormats; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Widgets.Logic +{ + public class InstallFromDiscLogic : ChromeLogic + { + enum Mode { Progress, Message, List } + + readonly ModContent content; + + readonly Widget panel; + readonly LabelWidget titleLabel; + readonly ButtonWidget primaryButton; + readonly ButtonWidget secondaryButton; + + // Progress panel + readonly Widget progressContainer; + readonly ProgressBarWidget progressBar; + readonly LabelWidget progressLabel; + + // Message panel + readonly Widget messageContainer; + readonly LabelWidget messageLabel; + + // List Panel + readonly Widget listContainer; + readonly ScrollPanelWidget listPanel; + readonly LabelWidget listTemplate; + readonly LabelWidget listLabel; + + Mode visible = Mode.Progress; + + [ObjectCreator.UseCtor] + public InstallFromDiscLogic(Widget widget, ModContent content, Action afterInstall) + { + this.content = content; + + Log.AddChannel("install", "install.log"); + + // this.afterInstall = afterInstall; + panel = widget.Get("DISC_INSTALL_PANEL"); + + titleLabel = panel.Get("TITLE"); + + primaryButton = panel.Get("PRIMARY_BUTTON"); + secondaryButton = panel.Get("SECONDARY_BUTTON"); + + // Progress view + progressContainer = panel.Get("PROGRESS"); + progressContainer.IsVisible = () => visible == Mode.Progress; + progressBar = panel.Get("PROGRESS_BAR"); + progressLabel = panel.Get("PROGRESS_MESSAGE"); + progressLabel.IsVisible = () => visible == Mode.Progress; + + // Message view + messageContainer = panel.Get("MESSAGE"); + messageContainer.IsVisible = () => visible == Mode.Message; + messageLabel = messageContainer.Get("MESSAGE_MESSAGE"); + + // List view + listContainer = panel.Get("LIST"); + listContainer.IsVisible = () => visible == Mode.List; + + listPanel = listContainer.Get("LIST_PANEL"); + listTemplate = listPanel.Get("LIST_TEMPLATE"); + listPanel.RemoveChildren(); + + listLabel = listContainer.Get("LIST_MESSAGE"); + + DetectContentDisks(); + } + + void DetectContentDisks() + { + var message = "Detecting drives"; + ShowProgressbar("Checking Discs", () => message); + ShowBackRetry(DetectContentDisks); + + new Task(() => + { + var volumes = DriveInfo.GetDrives() + .Where(v => v.DriveType == DriveType.CDRom && v.IsReady) + .Select(v => v.RootDirectory.FullName); + + foreach (var kv in content.Discs) + { + message = "Searching for " + kv.Value.Title; + + foreach (var volume in volumes) + { + if (PathIsDiscMount(volume, kv.Value)) + { + var packages = content.Packages.Values + .Where(p => p.Discs.Contains(kv.Key) && !p.IsInstalled()) + .Select(p => p.Title); + + // Ignore disc if content is already installed + if (packages.Any()) + { + Game.RunAfterTick(() => + { + ShowList(kv.Value.Title, "The following content packages will be installed:", packages); + ShowContinueCancel(() => InstallFromDisc(volume, kv.Value)); + }); + + return; + } + } + } + } + + var discTitles = content.Packages.Values + .Where(p => !p.IsInstalled()) + .SelectMany(p => p.Discs) + .Select(d => content.Discs[d].Title) + .Distinct(); + + Game.RunAfterTick(() => + { + ShowList("Disc Content Not Found", "Please insert or mount one of the following discs and try again", discTitles); + ShowBackRetry(DetectContentDisks); + }); + }).Start(); + } + + void InstallFromDisc(string path, ModContent.ModDisc disc) + { + var message = ""; + ShowProgressbar("Installing Content", () => message); + ShowDisabledCancel(); + + new Task(() => + { + var extracted = new List(); + + try + { + foreach (var i in disc.Install) + { + switch (i.Key) + { + case "copy": + { + var sourceDir = Path.Combine(path, i.Value.Value); + foreach (var node in i.Value.Nodes) + { + var sourcePath = Path.Combine(sourceDir, node.Value.Value); + var targetPath = Platform.ResolvePath(node.Key); + if (File.Exists(targetPath)) + { + Log.Write("install", "Ignoring installed file " + targetPath); + continue; + } + + Log.Write("install", "Copying {0} -> {1}".F(sourcePath, targetPath)); + message = "Copying " + Path.GetFileName(sourcePath); + extracted.Add(targetPath); + Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); + File.Copy(sourcePath, targetPath); + } + + break; + } + + case "extract-raw": + { + ExtractFromPackage(ExtractionType.Raw, path, i.Value, extracted, ref message); + break; + } + + case "extract-blast": + { + ExtractFromPackage(ExtractionType.Blast, path, i.Value, extracted, ref message); + break; + } + + case "extract-mscab": + { + ExtractFromMSCab(path, i.Value, extracted, m => message = m); + break; + } + + default: + Game.Debug("debug", "Unknown installation command {0} - ignoring", i.Key); + break; + } + } + + Game.RunAfterTick(Ui.CloseWindow); + } + catch (Exception e) + { + Log.Write("install", e.ToString()); + + foreach (var f in extracted) + { + Log.Write("install", "Deleting " + f); + File.Delete(f); + } + + Game.RunAfterTick(() => + { + ShowMessage("Installation Failed", "Refer to install.log in the logs directory for details."); + ShowBackRetry(() => InstallFromDisc(path, disc)); + }); + } + }).Start(); + } + + enum ExtractionType { Raw, Blast } + + static void ExtractFromPackage(ExtractionType type, string path, MiniYaml actionYaml, List extractedFiles, ref string progressMessage) + { + var sourcePath = Path.Combine(path, actionYaml.Value); + using (var source = File.OpenRead(sourcePath)) + { + foreach (var node in actionYaml.Nodes) + { + var targetPath = Platform.ResolvePath(node.Key); + + if (File.Exists(targetPath)) + { + Log.Write("install", "Skipping installed file " + targetPath); + continue; + } + + var offsetNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Offset"); + if (offsetNode == null) + { + Log.Write("install", "Skipping entry with missing Offset definition " + targetPath); + continue; + } + + var lengthNode = node.Value.Nodes.FirstOrDefault(n => n.Key == "Length"); + if (lengthNode == null) + { + Log.Write("install", "Skipping entry with missing Length definition " + targetPath); + continue; + } + + var length = FieldLoader.GetValue("Length", lengthNode.Value.Value); + + source.Position = FieldLoader.GetValue("Offset", offsetNode.Value.Value); + + extractedFiles.Add(targetPath); + Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); + using (var target = File.OpenWrite(targetPath)) + { + // This is a bit dumb memory-wise, but we load the whole thing when running the game anyway + Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath)); + progressMessage = "Extracting " + Path.GetFileName(Path.GetFileName(targetPath)); + + var data = source.ReadBytes(length); + if (type == ExtractionType.Blast) + data = Blast.Decompress(data); + + target.Write(data); + } + } + } + } + + static void ExtractFromMSCab(string path, MiniYaml actionYaml, List extractedFiles, Action updateMessage) + { + var sourcePath = Path.Combine(path, actionYaml.Value); + using (var source = File.OpenRead(sourcePath)) + { + var reader = new MSCabCompression(source); + foreach (var node in actionYaml.Nodes) + { + var targetPath = Platform.ResolvePath(node.Key); + + if (File.Exists(targetPath)) + { + Log.Write("install", "Skipping installed file " + targetPath); + continue; + } + + extractedFiles.Add(targetPath); + Directory.CreateDirectory(Path.GetDirectoryName(targetPath)); + using (var target = File.OpenWrite(targetPath)) + { + // This is a bit dumb memory-wise, but we load the whole thing when running the game anyway + Log.Write("install", "Extracting {0} -> {1}".F(sourcePath, targetPath)); + + var displayFilename = Path.GetFileName(Path.GetFileName(targetPath)); + Action onProgress = percent => updateMessage("Extracting {0} ({1}%)".F(displayFilename, percent)); + target.Write(reader.ExtractFile(node.Value.Value, onProgress)); + } + } + } + } + + bool PathIsDiscMount(string path, ModContent.ModDisc disc) + { + try + { + foreach (var kv in disc.IDFiles) + { + var filePath = Path.Combine(path, kv.Key); + if (!File.Exists(filePath)) + return false; + + using (var fileStream = File.OpenRead(filePath)) + using (var csp = SHA1.Create()) + { + var hash = new string(csp.ComputeHash(fileStream).SelectMany(a => a.ToString("x2")).ToArray()); + if (hash != kv.Value) + return false; + } + } + } + catch (Exception) + { + return false; + } + + return true; + } + + void ShowMessage(string title, string message) + { + visible = Mode.Message; + titleLabel.Text = title; + messageLabel.Text = message; + + primaryButton.Bounds.Y += messageContainer.Bounds.Height - panel.Bounds.Height; + secondaryButton.Bounds.Y += messageContainer.Bounds.Height - panel.Bounds.Height; + panel.Bounds.Y -= (messageContainer.Bounds.Height - panel.Bounds.Height) / 2; + panel.Bounds.Height = messageContainer.Bounds.Height; + } + + void ShowProgressbar(string title, Func getMessage) + { + visible = Mode.Progress; + titleLabel.Text = title; + progressBar.IsIndeterminate = () => true; + + var font = Game.Renderer.Fonts[progressLabel.Font]; + var status = new CachedTransform(s => WidgetUtils.TruncateText(s, progressLabel.Bounds.Width, font)); + progressLabel.GetText = () => status.Update(getMessage()); + + primaryButton.Bounds.Y += progressContainer.Bounds.Height - panel.Bounds.Height; + secondaryButton.Bounds.Y += progressContainer.Bounds.Height - panel.Bounds.Height; + panel.Bounds.Y -= (progressContainer.Bounds.Height - panel.Bounds.Height) / 2; + panel.Bounds.Height = progressContainer.Bounds.Height; + } + + void ShowList(string title, string message, IEnumerable items) + { + visible = Mode.List; + titleLabel.Text = title; + listLabel.Text = message; + + listPanel.RemoveChildren(); + foreach (var i in items) + { + var item = i; + var labelWidget = (LabelWidget)listTemplate.Clone(); + labelWidget.GetText = () => item; + listPanel.AddChild(labelWidget); + } + + primaryButton.Bounds.Y += listContainer.Bounds.Height - panel.Bounds.Height; + secondaryButton.Bounds.Y += listContainer.Bounds.Height - panel.Bounds.Height; + panel.Bounds.Y -= (listContainer.Bounds.Height - panel.Bounds.Height) / 2; + panel.Bounds.Height = listContainer.Bounds.Height; + } + + void ShowContinueCancel(Action continueAction) + { + primaryButton.OnClick = continueAction; + primaryButton.Text = "Continue"; + primaryButton.Visible = true; + + secondaryButton.OnClick = Ui.CloseWindow; + secondaryButton.Text = "Cancel"; + secondaryButton.Visible = true; + secondaryButton.Disabled = false; + Game.RunAfterTick(Ui.ResetTooltips); + } + + void ShowBackRetry(Action retryAction) + { + primaryButton.OnClick = retryAction; + primaryButton.Text = "Retry"; + primaryButton.Visible = true; + + secondaryButton.OnClick = Ui.CloseWindow; + secondaryButton.Text = "Back"; + secondaryButton.Visible = true; + secondaryButton.Disabled = false; + Game.RunAfterTick(Ui.ResetTooltips); + } + + void ShowDisabledCancel() + { + primaryButton.Visible = false; + secondaryButton.Disabled = true; + Game.RunAfterTick(Ui.ResetTooltips); + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs index 3e5d47fb87..3d2d693901 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs @@ -9,6 +9,7 @@ */ #endregion +using System; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentDiscTooltipLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentDiscTooltipLogic.cs new file mode 100644 index 0000000000..4f679567b6 --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentDiscTooltipLogic.cs @@ -0,0 +1,53 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Linq; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Widgets.Logic +{ + public class ModContentDiscTooltipLogic : ChromeLogic + { + [ObjectCreator.UseCtor] + public ModContentDiscTooltipLogic(Widget widget, Func getText) + { + var discs = widget.Get("DISCS"); + var template = discs.Get("DISC_TEMPLATE"); + discs.RemoveChildren(); + + var desc = widget.Get("DESCRIPTION"); + + var font = Game.Renderer.Fonts[template.Font]; + var discTitles = getText().Split('\n'); + + var maxWidth = 0; + var sideMargin = desc.Bounds.X; + var bottomMargin = discs.Bounds.Height; + foreach (var disc in discTitles) + { + var label = (LabelWidget)template.Clone(); + var title = disc; + label.GetText = () => title; + label.Bounds.Y = discs.Bounds.Height; + label.Bounds.Width = font.Measure(disc).X; + + maxWidth = Math.Max(maxWidth, label.Bounds.Width + label.Bounds.X); + discs.AddChild(label); + discs.Bounds.Height += label.Bounds.Height; + } + + widget.Bounds.Width = 2 * sideMargin + maxWidth; + widget.Bounds.Height = discs.Bounds.Y + bottomMargin + discs.Bounds.Height; + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs new file mode 100644 index 0000000000..2b5ca3cf04 --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentLogic.cs @@ -0,0 +1,127 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using System.IO; +using System.Linq; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Widgets.Logic +{ + public class ModContentLogic : ChromeLogic + { + readonly ModContent content; + readonly ScrollPanelWidget scrollPanel; + readonly Widget template; + bool discAvailable; + + [ObjectCreator.UseCtor] + public ModContentLogic(Widget widget, string modId, Action onCancel) + { + var panel = widget.Get("CONTENT_PANEL"); + + content = ModMetadata.AllMods[modId].ModContent; + scrollPanel = panel.Get("PACKAGES"); + template = scrollPanel.Get("PACKAGE_TEMPLATE"); + + var headerTemplate = panel.Get("HEADER_TEMPLATE"); + var headerLines = !string.IsNullOrEmpty(content.HeaderMessage) ? content.HeaderMessage.Replace("\\n", "\n").Split('\n') : new string[0]; + var headerHeight = 0; + foreach (var l in headerLines) + { + var line = (LabelWidget)headerTemplate.Clone(); + line.GetText = () => l; + line.Bounds.Y += headerHeight; + panel.AddChild(line); + + headerHeight += headerTemplate.Bounds.Height; + } + + panel.Bounds.Height += headerHeight; + panel.Bounds.Y -= headerHeight / 2; + scrollPanel.Bounds.Y += headerHeight; + + var discButton = panel.Get("CHECK_DISC_BUTTON"); + discButton.Bounds.Y += headerHeight; + discButton.IsVisible = () => discAvailable; + + discButton.OnClick = () => Ui.OpenWindow("DISC_INSTALL_PANEL", new WidgetArgs + { + { "afterInstall", () => { } }, + { "content", content } + }); + + var backButton = panel.Get("BACK_BUTTON"); + backButton.Bounds.Y += headerHeight; + backButton.OnClick = () => { Ui.CloseWindow(); onCancel(); }; + + PopulateContentList(); + Game.RunAfterTick(Ui.ResetTooltips); + } + + public override void BecameVisible() + { + PopulateContentList(); + } + + void PopulateContentList() + { + scrollPanel.RemoveChildren(); + + foreach (var p in content.Packages) + { + var container = template.Clone(); + var titleWidget = container.Get("TITLE"); + var title = p.Value.Title; + titleWidget.GetText = () => title; + + var requiredWidget = container.Get("REQUIRED"); + requiredWidget.IsVisible = () => p.Value.Required; + + var discWidget = container.Get("DISC"); + var discs = p.Value.Discs.Select(s => content.Discs[s].Title).Distinct(); + var discList = discs.JoinWith("\n"); + var discAvailable = discs.Any(); + discWidget.GetTooltipText = () => discList; + discWidget.IsVisible = () => discAvailable; + + var installed = p.Value.IsInstalled(); + var downloadButton = container.Get("DOWNLOAD"); + var downloadEnabled = !installed && p.Value.Download != null; + downloadButton.IsVisible = () => downloadEnabled; + + if (downloadEnabled) + { + var download = content.Downloads[p.Value.Download]; + var widgetArgs = new WidgetArgs + { + { "download", download }, + { "onSuccess", () => { } } + }; + + downloadButton.OnClick = () => Ui.OpenWindow("PACKAGE_DOWNLOAD_PANEL", widgetArgs); + } + + var installedWidget = container.Get("INSTALLED"); + installedWidget.IsVisible = () => installed; + + var requiresDiscWidget = container.Get("REQUIRES_DISC"); + requiresDiscWidget.IsVisible = () => !installed && !downloadEnabled; + if (!discAvailable) + requiresDiscWidget.GetText = () => "Manual Install"; + + scrollPanel.AddChild(container); + } + + discAvailable = content.Packages.Values.Any(p => p.Discs.Any() && !p.IsInstalled()); + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentPromptLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentPromptLogic.cs new file mode 100644 index 0000000000..63d41c0e15 --- /dev/null +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/ModContentPromptLogic.cs @@ -0,0 +1,72 @@ +#region Copyright & License Information +/* + * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System; +using OpenRA.Widgets; + +namespace OpenRA.Mods.Common.Widgets.Logic +{ + public class ModContentPromptLogic : ChromeLogic + { + [ObjectCreator.UseCtor] + public ModContentPromptLogic(Widget widget, string modId, Action continueLoading) + { + var panel = widget.Get("CONTENT_PROMPT_PANEL"); + + var mod = ModMetadata.AllMods[modId]; + var content = ModMetadata.AllMods[modId].ModContent; + + var headerTemplate = panel.Get("HEADER_TEMPLATE"); + var headerLines = !string.IsNullOrEmpty(content.InstallPromptMessage) ? content.InstallPromptMessage.Replace("\\n", "\n").Split('\n') : new string[0]; + var headerHeight = 0; + foreach (var l in headerLines) + { + var line = (LabelWidget)headerTemplate.Clone(); + line.GetText = () => l; + line.Bounds.Y += headerHeight; + panel.AddChild(line); + + headerHeight += headerTemplate.Bounds.Height; + } + + panel.Bounds.Height += headerHeight; + panel.Bounds.Y -= headerHeight / 2; + + var advancedButton = panel.Get("ADVANCED_BUTTON"); + advancedButton.Bounds.Y += headerHeight; + advancedButton.OnClick = () => + { + Ui.OpenWindow("CONTENT_PANEL", new WidgetArgs + { + { "modId", modId }, + { "onCancel", Ui.CloseWindow } + }); + }; + + var quickButton = panel.Get("QUICK_BUTTON"); + quickButton.IsVisible = () => !string.IsNullOrEmpty(content.QuickDownload); + quickButton.Bounds.Y += headerHeight; + quickButton.OnClick = () => + { + Ui.OpenWindow("PACKAGE_DOWNLOAD_PANEL", new WidgetArgs + { + { "download", content.Downloads[content.QuickDownload] }, + { "onSuccess", continueLoading } + }); + }; + + var backButton = panel.Get("BACK_BUTTON"); + backButton.Bounds.Y += headerHeight; + backButton.OnClick = Ui.CloseWindow; + Game.RunAfterTick(Ui.ResetTooltips); + } + } +} diff --git a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs index c766f1d4cc..aed538ce94 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs @@ -27,8 +27,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic readonly ModMetadata[] allMods; readonly Dictionary previews = new Dictionary(); readonly Dictionary logos = new Dictionary(); - readonly Cache modInstallStatus; - readonly Cache modPrerequisitesFulfilled; readonly Widget modChooserPanel; readonly ButtonWidget loadButton; readonly SheetBuilder sheetBuilder; @@ -40,14 +38,24 @@ namespace OpenRA.Mods.Common.Widgets.Logic [ObjectCreator.UseCtor] public ModBrowserLogic(Widget widget, ModData modData) { - modInstallStatus = new Cache(IsModInstalled); - modPrerequisitesFulfilled = new Cache(Game.IsModInstalled); - modChooserPanel = widget; loadButton = modChooserPanel.Get("LOAD_BUTTON"); loadButton.OnClick = () => LoadMod(selectedMod); loadButton.IsDisabled = () => selectedMod.Id == modData.Manifest.Mod.Id; + var contentButton = modChooserPanel.Get("CONFIGURE_BUTTON"); + contentButton.IsDisabled = () => selectedMod.ModContent == null; + contentButton.OnClick = () => + { + var widgetArgs = new WidgetArgs + { + { "modId", selectedMod.Id }, + { "onCancel", () => { } } + }; + + Ui.OpenWindow("CONTENT_PANEL", widgetArgs); + }; + modChooserPanel.Get("QUIT_BUTTON").OnClick = Game.Exit; modList = modChooserPanel.Get("MOD_LIST"); @@ -160,14 +168,11 @@ namespace OpenRA.Mods.Common.Widgets.Logic var selectedIndex = Array.IndexOf(allMods, mod); if (selectedIndex - modOffset > 4) modOffset = selectedIndex - 4; - - loadButton.Text = !modPrerequisitesFulfilled[mod.Id] ? "Install mod" : - modInstallStatus[mod] ? "Load Mod" : "Install Assets"; } void LoadMod(ModMetadata mod) { - if (!modPrerequisitesFulfilled[mod.Id]) + if (!Game.IsModInstalled(mod.Id)) { var widgetArgs = new WidgetArgs { @@ -178,17 +183,31 @@ namespace OpenRA.Mods.Common.Widgets.Logic return; } - if (!modInstallStatus[mod]) + if (!IsModInstalled(mod)) { - var widgetArgs = new WidgetArgs + if (mod.ModContent != null) { - { "continueLoading", () => - Game.RunAfterTick(() => Game.InitializeMod(Game.Settings.Game.Mod, new Arguments())) }, - { "mirrorListUrl", mod.Content.PackageMirrorList }, - { "modId", mod.Id } - }; + var widgetArgs = new WidgetArgs + { + { "continueLoading", () => + Game.RunAfterTick(() => Game.InitializeMod(mod.Id, new Arguments())) }, + { "modId", mod.Id } + }; - Ui.OpenWindow("INSTALL_PANEL", widgetArgs); + Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs); + } + else + { + var widgetArgs = new WidgetArgs + { + { "continueLoading", () => + Game.RunAfterTick(() => Game.InitializeMod(Game.Settings.Game.Mod, new Arguments())) }, + { "mirrorListUrl", mod.Content.PackageMirrorList }, + { "modId", mod.Id } + }; + + Ui.OpenWindow("INSTALL_PANEL", widgetArgs); + } return; } diff --git a/mods/modchooser/chrome.png b/mods/modchooser/chrome.png index ce09238bdaab866373d5993994b1f9e2c3efbc9c..7659af598a962a83c2c0b6776536b932ba2952cf 100644 GIT binary patch literal 82267 zcmeEtbzD>Z|LEDqMt3(NjY_9Th=6pLw4`)N#|S}CKn0{jK)OWf8XzDbt#phMkQ&|F z-SfNm`+V=e_y4=s+3W1=ljmKZcgE>xsSpz|5C8x`tornc9suBAf8qdmFzhXynLp~E zC!fcv26)&{2%g<*>@&XSQ&S&o|LK3epvOE}0oXt3eU(gn^*tPX{cXJM0e^r02QS=R zd~9tz?H_n}J7(?6FaQ7>p!!6?ARv3U-QR!y$HZPcW1N&~17~c8&mWod+uZZurQ@Fg z4l)h)Lj*scE*`M9+Dr)J!*z*H&EBX}C{eJ{jTzRvq=Bv3@FM?nb*rw)oRj?bIkGmG z1N5IpY%fPR2Y{nM_J6JwqIWp(|F&j>J^=q|QXq>Kk*5IuojB4H_7p7t-_{X875MKm z-Slkuz`xTfNJ9SqqF8ABzk(O}Q}>MhU!Z1-e*h$Xo;?_Q=O6JO9CZ)e{j{7h=@rp% zy%2oo->$n12hINS0kR>ze>*|Q@9?mFW{Q8Y>=(lWjHD+L7R7WnK7sycrby3;r(opU z?Iwf)#Aa|A`XA&)PbyIWj%qzNgz_oi_prYt$N|ZJF&mxyKaKtN$UFx0FXf-Wzr(cX zRe|g~4`z<#a(r$H_4Dr@!2X>vS?O_yNYNg+PY0bx&XB(fP``luOGuKc93ama->RGN z+$WH@Z=iqQDf=Gw^+ovNQ_*GU%kcLfU;LLAOX4|zk+;>36}N;Gz+_4?@b{?tzY|Jv z{Caqo3f=&TCX5V+Cj-y#yZv87Ut@>9{zxe490&%Gn7IeZ(0@t1dmH%(%RASFYZI4N zSsRV``uQs$Oivm!O5I&%O8!#KGEsz8DBH+L$>zAj3=;A~R)lep~Vqu4GLHl%g zbPYp8?wr2?sa_5JANS$>p;AKf5w-h?lRzh@8DC@x@-RQ_kTz7~VmLuB&; zu?>)gHw6E~(z&mUNyZH1y^9E4wLzZnnhzkd=qeq2co4JGFL+QwM9}k!(`4T8(e)dC z{n|h0=7?j^C?v=bxdCky$pH6|3w+_hNd&(#1wWP4{Y!#!0Tz@lZ!yQBG62Da$lP`{ z{y#9Tg~x!yyx_P#ZTRr`=is$=Sohsfl1S9T1qX$ayFqq(~E4`wj;Y zw+39u8Cs{Lcz}Lv!4QfB3u-X!e@N=APaSuQ7ir0gVIPK$y@WGribb*E4dI96Putg9 z@n#-q_N*mO;i7-O7F3OhRY86VZyI>xqeua8YfVF|Ly%@oSD`x(kgW(zwU^cZaD)*z zfXW&g#FYK`vlG7ube6nw>x=aKXaGj`LdTqit#dU@50_8)5nepQ{!ED&eG;G-Y(oPb zX(V&fER=U^V$CwzXNDS7$crJ*_E{rZaaD0-B(SXFg=R+eJbZT7XNxbNb_~~=ed5u| zSgFOFNJj0u-FpJ}ltDV~E5k<5LkNpL2vLi#8OM?g-%>uy;njf(iXym8wehF`woO zsom=tCf&N{=-XnTiJFZ?9VOtZp#l@_3<{<8+*uu0KrVbrvmCzW(U`m zb1LM5bh=W48T*#c4q8MxE2rTO2?L<2Dr1FjnaAPn1izd$*cU>eeaVY^ji|d=oas`* zG5R1bUcp7=kUTGv9YDvySKqXe-K`)ESeHFkPjntFhlsf^x zju~y2=x#>BGys_n+z%h@nG{UmV3Y@~d>pd5IQ`zmBPhvzZYx7Xr#hFAbo@0Y?H*q= zW&bgJx`ro1!0hxqG+%cuH1;mTpM=DxEHzYPl|I=vi)uIA`av+N#Ts4Pi8VCn;z+X% zWPi%0;f>QN-EwDd_*Xhc zuP<0CZkP9`^6*gEbUie$x?b;*q&>=?T=k*X{>V@F78GNfdB<<=1ovWd^0-kdn_XCO z2WPwKhOF1@XQc`+t1%hLhX9->p)mXYbuIxW?y#u%Xo6i)5_?Tzn5_Gfsf{Ubb1`=@%TIDewT)8+lkR>U3D8jZY@V9YgI;M$~E}nUKP+Cmrs>|p1Th_oTR>uV~$Nda7Mr{=O0nxl{_vaF>lYG zvyp*uN%gDP!y-VQK0{s+-G2WFc3pqC6$B|;KtC$pj0c~mYNF&#^en}$d`p0LAeH8D zhoICi9q;M)NVVD~7GS!=|D&BYHC!zz0)twUJ=c;{sFT0!TF|?s=Hk5>)WB)mC5jKkr$CTnumcWYNfUeq4QiLVBN2ZzaIXLJj?h zl#ZxDVsOL@9+YZ(v>F``MLnixt!@k5D{zpvb>-<3S zTUO!0E?t4<#du~&Ac%wVY@nQewAl>iLPGnk#OM82cFXvXb2ccelsac# z7}_dny-;eDN`C0mxXn_DaIiD;!^b)wX}g8qLowCK0^{d0(ks`p$-v;3J~%%Ic$E&X zM1#Y3UcRx{PBCCT4(=-Ryrh>L?$vf7={$@N8t$tcer!Ve&ubZX4CBd41y5PzQv%d! z0v80!5^^g%4d8`19C=B*54;ew>0x|4Vu9Zz!7W2iTPkSfcZeaq+i;K#McqdJguPir zq$Up2YP<#LH_KR1|GJ6{G(Q7TdU_!<@j5O+QL&lm$jsv+lb-m=T`rG_cbc#2)zSB| z#&k)NrCy}Sjf_@+-Ba)1-6%%v-jHbcEB1a)~&$gHG#x{ro>*O;Qvy;QX=> z@vD~Dx>9NrE95B65^5~|;C_>arjX(gvxS(TJqPXU+ve=+*jQ}+8pPp=5x-#XQpFp0 z0v2Kw@r$Eq@)XDZbSNwCHzr2-c9&3oDu)lSTXqtdANy+bhr+@)W#6XRIuV*g9ns~UIvlKx!t5hANS#+rWn?!FHgj&t*KDk zI3r&vd%VI)j`A8o9+M5ps&x0-`*7w7Bg8hRvHheI|%;EN%xPbGiU z1^<23(2u~}fx;NJN{H6yS#;{#Z$DFj;`t)44LkC2R-~SC8O>FDgZ*v$TVK*6NAm`D z8jiA+iL!@`j=x&Z6%i@B2)G(PnzJ%otnysm5ol)BUFLdBAY0F6|MF2n`pLz<7kn|8 zNpin(xL|GrOE`QF23aI*)1$p)%IV?I;?Vesa7u_*;$AwVV1)3+ySxkXXo@zkrY$~U zG$GZP4nnR)Qn!}aycTYqRnU+KA|$hjO}%}rDBoK@@RWwGJL2dsv|{uY+=!`UVC|Df z4ws)~%vuyPq{kpa^CCigWXa!EBmMFMah{yq-TLMTIuYUm_ff(wX)Vyq0w!Rm;rSD3 zk-{gRn6Q)r%EVeja2qZ8>b>lh#Qx@1#d&?n352clMvOSQP7&T1tTdR(%79~=GTO1% zq+(Hxc5LNHq)dxmu(eBrgyow_#0Yq-z9CO|YYHDZUw&1+ahlkF>uz~`;AEXl&L3v- zbsP5LM}MU+UCK_tbv#fr_(bV$@@1@Fr-aj|r+0zG(*QbjK%0v|sURM%$yHSu)x1=9 z|IHbh0*`_^NPx*2z8Z$ER6>TSY#Kvhvlh5bdI)~pExxnAR?=-9RRLM$nHd*ubq_x+ zIt-(8V_{>uuA!1}E)Io@2rb5dmjhwwx(}g+^!Zwfu(K*Ih}m*snFW^*X%#!0RyvN; zFZ!R{Sjqa+oL!#Rg=Xf@ri2Vd-s;=!l>WT}msEf-(cf>kh1puvvXX`@Oj#kmNoCY5 zk9$iYPJn$GG$$*l5s`G5B+yX-CrsPJDFgNKlHI>#6MJ;F6Z+0I%ah0#-7AZ(?Yt3B z9JTgBMJRM)l~0L>QQRdeA=Kuqo-T0OTE6x-9Y=j)$+U+~LlG@K9|0(GCF#CQ?sJdO zdKIZKhwo|JhgPX-vG{M$R$q4(;59BXKRt-?Gc`hFZo(vGNxF4c0qlVuSYLW&Wn9^Z zv3$PZj)faF&|AZsFxxA0nGp#2?P`4hA4Jd*)lv487Y)Tmxtz~~reVCLPt)B|<3xxx zLE+w{Nuz~>^P_P}lGkd$%{8sH43vxUXQhF&I5Fa!#|qNUR6 z;OX5n*h3by;v&&Dm!;i`Mf0F)s|i+X)6~x2cHSGe%Wpy<(X3dL>HQina?Y{VQn{ms zSo`XJS_cr-Od1Ee1zqtPf|*@t(w`sFDoxrx>>>}1#oJU9{>)@vG8BB6kW1h3D#=LA zJpt!sT@FiFp<^;+K`JoR$ZeTUX*OJVHo|-vm5!5;XU1vNb-2qBDIv-s%A3qKVAm>( zZ<$*Drb|vv)_v!G_@6RqrX+m$O8*-D9uLz!0cO~u(*9Y7>5}6xdC(9Z!Y`6A78F8r z0x|#949JZ6umL(C2&SC)ro@{4Il+=#7E#gOL0r2mxZ?EFimk=mDWavSfj8aU>0vKE z9LGT7FL47m-u(Ca;&9bLwd3LuKvZ@^VnVhIWKuC0TlNf9Xto9~U)9VTO>azVK@9G8FaVXYQ?QN_HZB>2*TJ z5XR5%hf$kIU})N32!abdb)$1hJb2Rh*(4x-oT&2a6x{G)U|6mQC!E_Bms-aSvewF) zq*Om-%e?W^WiSQ*Fr9!{VFn%#wtPs`G-Pn12v~h=6Jr*{3tvMWfatOv4R7u_<#k4D zKOm1kU*m;+rGe-6Jn0V5OzyykCyKc6|Cs06bz>bqOjMxKik+^h++O||rJhrd`{e7F zuy&I0BwMsxwmOce%Rf7j0TWf4T0gDVZiSw>hKJHsEpaw^^id*?ovvv6-w-CNs&UGf zJE}r#gs?)(yE>Fj%b0bbL}3!qqArGz$Ak!LckT3N{zez~?}j$qHx^Pr@#rzG&^_fM z0+{;;f2MtMTfTUmiV1jZE4{Igz#HKLPm~$5`kFBNXM4wlYL|5)*Va|%C3;Vr67*DI zy?)U@-;Q|&nir0{Yo12Z7>g7pecfS7`i-&sP}6{NaiydSA=~b(6*^$5sOG=mF?M@} zjA ztS1Zgt(x4f=ZG*--`UX7M&)O90o6P^q2AscOjte7dpcgmz5-DgXij&Q5 zCB%l;+U@g??PzWJE4-RYV4g#@x!phn*}m%~4Hp+_yuMaJFDlk6)y{DgfvHt1?Wk#GGVB zl9(BYi`U&%Xp5-O`IBeNIV}{7&~#4Ne$4Ru@+G=`GW6SB92=lh^#CkUt9O}A8a!rK z%bZv{IhQXaL!zB?8j+C|ek_KZGm7wZnung%X6n@T=aXt2I8Nhg?iH;W z$~h?aoC^S!T4X$Epw;)GbkLCOU>E89hnO9WeUJFX<8#%s>=u%FCL==*4WdUxOzTO~ zziRd4UHK6aeH`8RKDY6AZ(!=)-BqxP)9SB5faR0SIiX1M1VBV3{Ii2TG?xq9Moa}# z8;?c4qXhNUG9&A7*8$ z^Wt%jy2Pr&*{3m;6zC+h5ScpE3x;o#BDMRXIapz3UciH2cn2@wEb_(&u`dHMg;Vp#q@XW&xt2u0}V{PZu6~j3(pzd ziXsqPpcpAt0MP(-azOKozY*XAR(J$6)6^t7g{$-tRi1WMqP3~E`XQZF2Oh=|5v$NZ!9`6A#jFYB$1%tP_1=RMI0b0(UGdvtE=nqGRedg} z5X|Obd?Z$WeB{qNeA={;|L~hCTub30fDmYiaL}G0%)9%R1D}lvI*?N5S(AC-;Gt*K zIJxbr6*^{DAF#Z(Qb!*7;%Cv5J@2VvB#fzycF*Z7K~MDYiA%`-pp9I+*(U-vmN}YN zj^^|R4?{xxtQ@BU#je<&L`9y((EvSP!Xs-z1PFl#$?HnDdoO#B|HMMM+Nuj;5x%j% zF%4h_qq5o;_q%9_$LrVdA@eLIDT&$X8ENwG@8pwm5wVbR0OVR(ma!2b;i_6qzwJ(M zC(Zj!m?n8@c5?I zdHcug)jbq0oTKhHdOU3IPCTkyBl2W3=b9R8Wl!_u-s?ONo|IQGiAp1ZT!(e3jzO>I zJVaI29`%AC+hp^s5hV!cmO_*EbM^GY)H^U%QouRCt<&)lxDF%735_b$iVJ-Th#DKv z<8@0*l2l-lJ-w_=%Yb?U)Omle$hN-b*Opin*r#RY>qify8k+s4Gbb=St6{+`;e3iB zT|czQUQ0+Ca^wFd2FBb0+DAL&sGo6w?L}JZJgecTc(v}(PP>! z4*p$hORHcpv1;fU_v)Qw?pR@V?b&Hh@1f`?%6lJDZ)=l2*SxQrz?2k6MApJGY%!(L z`r-3~OP%W>q2|&=zKxfvKD!N{;GOymWX`VDz>gp0=sPBh5t9#Us586Ozu zHrDw9C8zyCkoP$eHHh|6*3%GWkhR@Bvvd7M6;Q=RDO>sRNYpL|rCL9;K)AS!s7IP%TQYt-VBUxfyGD!=T2F(TRrmZz zTxTs_95$264Oja>@-II+L`!pjJ7m=O^D_%Z(4E;<56)mOY>8iWy(Wdmv~e5o6IOq7Pw{?U4TIpZ26T$rrAjS&ZCIEjGV0_AU7)b?FlZ>xODj;hS^hIVk=%iecckZE zUn>5EsK~)@kX+USB9GR$gb$h7y8R-3a4WlAfbbWviTl0q5UU8^=K{<-q=L&=WVYhu zpGv9O>XU@J&Qh?v=QRuYo7($3wBPTTQra@;=c@Mk2}~TzPaESYP6q5F8QNgq zHt&DX>00!j8D!k}0nND;;Lwt$aoNa-lE!B{*A@>GY->aleRNLy`_}1QC%DXSi&(IE z@wS72JAn|Hqb`um{z#|C2r2hKDoxs&QDL-!BARfiyE>Ffg}RZ!E@}45+8H`ipV?fJ zsAcWZ;C6kx9U6Ar@A5pL-S!9)Oe|aS5hC+r_3;dQBBZUkpm~YCxoHjcZ8gvcyljsN zY}Yyu|2&wqH0dDTA)p0UPE9<^b)h6wF))5gv4ab5E&~N?;bGnl&(%dQ4rtOit~xsz|Eh&ub$hmldG6443G4H3SUN~}n? zOz{h=lYJuK##!_DD#lVq`vniIBk?(zx!v`4WGZG12$$1c?*;zm*OBq0Y0SW8z4JGL z!sa~&PfQC*UhvY2hWuA0sC8Sb1@*{Vtv8_Ex+QewsO;OBdDc0vkdA&1`5Hy2LaWk1 z^UgU)gB>~SSNn9 z9Gu8l7nln1bi-{yRu>_Ksk)?CI9a3=)hFiPM5naN6u$0F7@gijzQFDyG`EM%BN-hl0v^cfRv`ZPNm9%m{4**K|Yhk=|( z4I|wkCT~KIiM6x~89v+iSP?`DxVzQMcxdF8m|W)3A@iVn0lX#(64qmTQ4yzHJHEK` zn$+sYww^cE(=5rZ%f(2a%JQ4_m@jFG?VXjIuiUUQpcpU0G-f_T*8OnFQ;kycR#uS2`+yHoZ2TanHCmLCTcZCkQJ_cyZZ+g_2dIq9 z9|mZw=M`qZck!-Xq^t&uaVe+hcN^%AUkI>(l0CjwL~-eatEynyiqt+UrS@+f8|6lN zcJK%~B@svM%KVMr93>^>TK`5(jKf{r#MAKx=Q$i_d-IVIHJ(&_we$#mQ@2lVJ12#q3g=CX_i;&cLRlN z3B_0$vx@PxDW^`A;8S<848g5$mtQFWowmG#FMHPShi>mAbArDWvm=Goab|WJG>gGb zVoeDpJU{|${=o<{Hs=OOrJFu*Y|gJc6dB;(g<%fPalstST-!|#AEVYG`Y$7jaYNKA zS8_894~@~TpNY@{AxPP0*`FCXG{oBuBRbVG^O8hSVxZ~}E{4HUT$~kCx=@%j1~!q+ z0Z*J29&36|2p>NS>lAve>3stbndDS|3&@)z!v%>zElsdA*8FDI`J5@6mx;9Gu5AcEg1aqdqJ>ES~&#tyu9wb~~- z=e*|xrDG_^n>)KC=x*_SR*Cj#J(tz2T3@KnNG1OJD5(&Znn_OpKJzJZW51JgI<<2* zwVAGGlT1mz*KxIQ8pOg9;XyjjI_!Tg->XD+lP!pE+u$s^(|eam8=F9b?1wL8V6ewu zF7(6{QJsr(I3#GT$q!>-`%=aGS>)(MD%`|0Z z)IGv_IzpZsK%v1iQ1q!MlM%8%Sd!RL7VLGj#_?9apDvLE>((Bbzn?#E)7rDQc!qVT z56WVmoo?d5r(CC<8aY9pDfsXB+n+7(AbBRdvA>2(H=wRj09zNr|<}|xVZ=UBD zywvl{`M?SOncO+q+)2wxqQ=QiluGQlG#twCwzH0p^_Nf305RuQJz)@tLm&20!NutJ z$XyoU0i9Mr*$Nv=q{I#Uy`$evT>6nN1YnqE>N5Ey3lfBDmmp4T{Bn#x<0{Um>`SwuoUEEiz8 zLM%R_yqh&~a4cl8>8PYaCp^2>vgrm3zydHH(smlCm*XfqGZOiAmz7~^ld!T@uIl?v z^YtnmA_awEItW8vH+WQ@&uxl#N0M5nA6;~wMV#9-uTe81)m_a%AG`^3>+A;LO5qQE zjHP|fz5a;Cn|kx8i`sSCk!El*T|LBb^Y58nsJw zkDQM&UzR+N`SCg0oiSh+vMjEF z^OmbEoD=BN#tHZ8o^D>0@eqI)Y5*EyDB0%}`G0B!9!W>tO9YP{m04drgBJ2iAlFSgsgM5|J-A@G8A0Cq8$E$ArbvWU zier3R$+>Y2f{C1x2P$7#2jz8UKD9k-lcNwIAU!%`X>*A>EV+=e_ta{J47U=kt>MMCq$671Ivf}* zVT5P$73b_uj=QBK;*A(TMjM})n{lD!>*P5t@y#D$sdxU_&$H|TtKf2e`7Kmhw4dS1 zISPd+nGkIp9QjFxJF+CM?AF63pX7j+sys@dPjGfp#zzE!g$W>Yh-TJ}3EKwQ_Ld)& zt@6OK)y6|S=H0K-SX6FKZCh^B6d2DIPGyin_RountSFFHpnekNSibrncY^OTWxb|n zUGX7P6KnysK>NbD?8mIa2Z|!JTnQDDy-y3QW$C|sSPoFqM@&8BBm7uK61E^2yu{B8 z>pCtDxX!82AS!GEr*upxWb3D~B*>|h-8xx=!-P1e?;`5}b2IXSX6 z+qi+VipS}k+J5_uIY#8~luBtOgVsvFC1$hua|7)SM5b6wEQM61Z{Qm4vSXa?1<74BuzFIA}tsCxzY~#&@}<3%~BPypt+AesaH* z)#hrz2c9^p^dlG_t+e_5j8p`>MEe>YS0sI64X<)Ox6Q>Lb!NsDG0>`h_T zTD=YpNlbZaDJ?yQx3+Fs;?nk3_%eKU@+rKh98F4meSCZWQ7&j&B2Amdn{>+MlW8qt zGChH8VM-RiM7vPg^y0zhB;jQM%e-Iy zAC%=KpUbzAY6G1Ly^50085K<T6kZOTRXJQs!9Bc^1F?;5(*|mA;`vNsP#@3`) zn^P&acEw@T*e&ZM+8`IN#S^>vg|>6v0sLo;7wN8-T8HLiZSWO=Na zNM+Rgh&zQoMX(LaML2$hV)T39KJ$HY%(MY(`h9YX`IY&^g7x~KL6)eOn1yA@9)svVpo#)(hu!{VrXWE@_#cn$9b{=V6J#F^uL zJuI;>ZLtEw=1Wl0Y!eiowDFlSD@&ZnJT2ZR!dR|3UUsa364Dl8+sZqPKZC7Lns34g zx+#LhFMcwr;tG0J@xw5ILazvo%7(r(i@8W&sBZETlp!ON=y^ zibPeW_9W~#yek{hPweNY`%$#loelSn>nIFeI~7@!f(TTAgMULvSNw?>bONFx0| z6*{$*)Y|m^=>elqc1kv3_(2W$4HGP(3Ztach1pbF3oQ|v=jf@M` z#d>7X(2M-p#nNc=&QIyz1Tx8V&ay4*yD*NAcHYQ|c9`TvUC}`Hl}KM!1TMrkB+q?} z;NSdC)7(8(W@!3CcGJuA`Y|udfqU%jZ4Wu>Iu9Y27coF^8g2N4#s574TYQA`t14jg z$G{^u2vT3e5$p1OAK3p9XCxBy$)P@Qe)Gl+7XzGo6+{p=-emC!BiJ4-Jkcyhz)vk_ z&VDGZyrv7^;OiPyr=2%~&tZe>0O##MN|zJ4GUSk~v=cchYHBgTN__G4^nsk|7m{I# zsS<1W(Xv{675P9qU!3c%4ZWMy=Ptj9z{`$hNYq2 z_&?!!>TT`BbU**(2=I$vU<%$)5{$;d%qX4zZXW)u_;CJPaM>G4?ds^-bQT=wU14sM zWl&LxBM`JK)lVbC#FMC47Fsg|zs6=39t0zgrx*DJzBy2^ndoF|P*fOIKIl1mFx(w?v^Z1q z(PK9)x>8c2+HpETRu{dW`tFZo^+ke<^~DPZxN(piF~p(qXie5t?Up*~V4JT?&IwV% z#HGV9O|&&+u-?u<4HRmB-ARFnTA6K!kEEqBqJ*!$&2F-@aeedfyrkN(LVFevf9mSMbbK=5o*r?oNw0A}YB6 z%T>4Sw2TE^Oq(IYmm!V**M{bAx#6wWvkpX*IH}Bjnk>THSpcv#hL$aGai4ayzkN6G zfjWuTkf@dI8%!$8VVl-QULazKnj8ECR?0HwqVFHk&`|YXTkI zvHIr4lg;ab7hw98cd9XJjCAw7I2BK?60ksa8l58-|1?oteurVKw)S44BlCsa{H+dC zut~IcKxfI(?Ug!OV32;QlFBM?zyj?HDDXr;5^u9IpHEK5tUgz-9~J#_`T zQNSmvgEK`r4DtZ9UkaPc`EhlVFUkqWP#(rsH}}HC<2Hl$lN2>87yAyLLS_ zQ`0kg+|P*Y3K?@&w0SzEm-m`mB2lL({|Q$_U%9~sTvL;~rtQxKc;*`mN~;+BJg+;kyS z*?{#3a-fR`9jn` z4X`>R^NkVb1-p1Q4j&hY%NH5DKms)Oo+2DWBwFG>g!3Rr-z{PNe3a4+zi)!V#N=`X z$=u9m`H2K?eu~3|_tDEG1m=@60$Glo1hYTd`*wcM;R!P(S%RhitW`!@;aZnkJDDG% z1M6;yB=UovOA0I-%aFYIF*I>ozeiEXSk8vcXROQjvO799B1maJA9e->_rPibJHW&D zAMPAP;p|R^dz7&GGRr2_mH0#Wc%`A*H%mdnqHl;mT}JRU5>IP&xs{9oa8Ntaccn$1 zt}guM)(WvE{|g}0l^3&)Ec%_lfKKX6m!$tlcC#17Q@jw4m5G|P*N|+8<9p!8g#+he z>^h;&m$i)!&g&{k6>G)ZmkOCQ3U+xH4~jqNjr=xm*-nS%nzuN_1WaIq{Gp)K)s&5wspQLMiJNB#pi zw?BHc*~`x=R&kh(G#(q7vZh>u5Z^LW7-1Qy)wpQ2_k>|32 z%Ho>O!MxX-G91j~J272VW;(;uaaF5U!@t050-VM8c3EG#{6D)zZIP=$s;_wCs=Tar z+%CUF4)Z4>32`@=t~=Le*w7IK;2JIMDB-#A&Mvov&Gl<{;Fl$;dDHOpmVpv)O@M#5 zg6$p`q3j#Js|R$y!oK|8H!S66^T?4AL$o`f4&V5+xt~EGH@OpxpNi9e@f_j)2s*D( zU)W#z`HN~uFh9=LVT%V3Kn4#5PgulG90n@e8a1le4lay(#k8$~6JQVwqU6&uR(x7@ zjvHch@Ow7y1K7ybX5afMQ5Z&}D_q$w8K^FxuwkSFz8Hd1 z>`OCV&!p)Vg7Z9vKd-EAGHaNVX{FmetIlLiGO4d=M=r~0Q1ZNgIf+k}l<_1zptoP++(6!rfEKs zjuaOWvS=om+Vk+|@zjq$so44-?`5EVu|rq(9`8A$1a?zi1^vT@v!6 z{Yl>>t$ZTqej|6@H*@w+f*>hF z+CN1gTSmGnkUU&r=CRK2RJPA)r|wkz36=si3u%CV1$~vhaYCr;cv~CEtgQXA8dE{k z2&G#=3#Gb8J;vxf>BAsSZAA+mKbtxN7YH7aDCfB%b3dMt)E?bB{aE{;yDd2Tp8pot z?A`}_GTG{ef4GG|mbFn;LB~orB`@4k#3x$nOEgcJE2kX;6Z#@D#CbSk3&(f^1(Li3%#9@kfD5_ z+>$ZbRM96MN&)9*x@Qd;`FE@ji7ZHJ8ur8B5~dlPhyJvCrT#Cm;8 zX9dw7aL=oNkyRR?zhjw(7x<&9&j*qX1w|6fgSEuo{bHbd>l9;B0mfWXH|;WOPbiiQ zg)WPZDE1zvK=2;r<%Owj`rGsOTnpneaqXss(*pI70M5S5fp;y9mrdVIj-Tw-c;4gA zG`zIXed&0M4p%Za!0%Rm66$hhELbeS@a3`P-l0cM?et>Bs1ak}R!S9cYMe5yn8w6= zapLuykAlHiu7QFF*9p^Iq%3NA>lMW{4C|5A2_A6UqL^T?-?(0@k%L_g^H)zLXNL~V z-QjAiNZ_H0hVlT@BvB&;K8lJ$1EH-7U@3)5sEJWXMP+BRqe29=KP_C&zbu6aL7e{f zMXDf9+ZVTJrA9(xLO=-(?%rN&dQ&lDs*_a$q?gD6=nKm97*V{+yjljf#E4i~K^74Z zYQ84>t>;$Ji$pLYdw(aj9~7MvtKh`n{odwPfK}p&DFrf(I2m|}dtr>QL~GI&?Z$cp zF=;nFm`(f3$MuHNY-8pXLH;&~n6&AASh&snTlWBmL+`$mj1=M1tD%f%)QTgLj*JvC1NEkQYKgl(h z#B5Ibr|%m16{7lWy&LDyShdnplE^>>>JdH)%a91F=R@l&$0X_hYR!G0zE=M1A+RKc zz-%5J$@!!$Ga0R<(boZo>Y|59X-=$3RkzU+zM^g zmT!YPhOlK;?D<||t?m~Y39l_Pi~t>@1EYZJ?I=T*%ELPe$}&C@)owMRkn}TSkH0?V zX0I@Vpbdj6YBeJoZM)xRv7v(vzvCTI8-7IRm2)A^MfNZIZKGNNn!ibYSxp zDT&}U_!Zy9{DVg>l!&Gbz~3y8Zh!_QwtQwCZBg5t*5%f1-MmqA@YAYq zb;wjH^Lo-6-Ng=TImp>C6KB7!{j^z?f(xX47g<1fGupWo>-qX=vvnVSC#S^P9s9hd z9e_F9=S3*}pLtL@r)5SiAvR8+uD5}Y6>wht&QJwCB+>T8sl&s((%*QlLc3@3vbL;3kV;}v?c zGy~qvSj`X)d>=ewymZV8_>O2kiwtMXk}>&QBFCf~#wzM|tq_&eOyPXyW53Z70j8m*%l~o4>&Edw4G{3fZm4{o45&&D36C>utRh=r6v{_-K<5ixEC()WqQe z^~G%N=k^SRxX6Qps4SR<9{Z{HZ(mPZtQ@+FS&bIhsk)lMs*SQuII>|u%o%^Ttx{A+dQO_ngycAfgcl$xqs;(>;?%(D4_OPC6mv4J=>w19c=lIrFi*1SW)Zq zTBs?8q1p!qN-JY&d#|DPpwn;Wj7!wM>1P&JYN-3IUS?bt$Y`dLxLBjgM4ncy z3AljRu8^pK?Piu?3*~&UJbiflG>_t&`Do8`#xx~iS{6$k35$WfR55HvImi&6X(5tg z^RBcJ5^15vwF|$Y`y+1JKg30$Cwv1LJmFf63#OpMu)?l)zCu6tWs& zDEUYZ>EIcWij(31-mLYAoJ&n@DvP?wX00 zi(hfONpFqK}{PmHS5&dQ7Yf=A2{l0o6**5 z#9SaWk((YRO97IO%oe~F(zdCgKz=`XWXK461h)zR& zxV{M=1PCd9Al&I#Ow)LiD1j^}WG)cCmTp-nl@GiCZ1}jWas&7x!GmGBELXK1uqJ-I z#4qL{1kQ>yf;VBleDXBEEW=2V%9;3Mo_pYUI&i%*0n5DHtshZG zG`qVu`Wj2+RVX<bjQCa@Eui|;#&%=ZcBA22jE_{C%2!k>ms5Oyg5Tp;aVNU? zrPbWsqXbWNZW}UAO*$bAv%#ATm-~&AEOzcq*c4%AUUt@F>=Pb`H5>M06lAD`huh=C zd3bWtwpOk5G_O@bN!}i7_{NDY=hxtLmhd^qGp;br>tL@-?DQyJCP~Q=SCx0fY83(W z6(kgZNhryIb9|#CO6?xJqHV?e*~c?47(k5O=P$^=f@8)xh(mzRy#*e-NA21)+lpTn z!_k=SXO`4!Vo8Y$S76Zlh8@e3YkK&Wj>k||Ns8R2{(+UheO#)MedQBJ&5B>F?sK)T z&ukkx^W5sLX=m|$JNkagf^|SU2M@ia-(30jNy_vO;LiA=bne+8lLy(C)V`RBXl`)& zVRLX+T*TZIQK=ylti!#q@!*+=>fz@RXS(0p@B-iT;AIEm`~%$Kzw~ckR^$T(KniMR zO7g!z-lH!~S;7a-U26S)KQQ)#=h9cxstH+5R|BKA=YhV=Y~CKBXXNB7@NyqDj}b29 zt;3CsT%q^349$*Y5lt{Ofa~!hfLT!k|0p>h5*|agviRU#L<-iPH6h=F9kKv$>7SD_ zKis64Xk zymhQVrdcL7o=#Ia_B`iDUb`S`-Y2M1KcYC`%t9T3o^%&``Dk|t_?=Wp=|1rZcecxn_wh%&RL(1HOUiRTxMtef_KLestG!Plzf=8K&Y$>zFHTpC-#b)}WT$A!9pC=p zqd_W$e}_qq;dpLIjpbt;d_;Ak(M&DvzmD1Y2~hK^G&shO?3B0(WhCN-ciz7A$f`LH~K-}x~TuO=o(*}t6N0* z5O;)#tylKT!^Yuga{*WE*2@HJLwKHL&JSZjH;X%&b0Ym|u6mi`2BN;Oy6eIf8^46m zw=T1nNa20YSEioZOnhmXZVJ93tqYHAod##(O;Lu0o_>Q{?Vd*8m& z7Y8+jCjWKmixpNS1X%VsO6k)%vlm-J0)4BCCD&8aEIGOIOuzY-9OkEq=m~0Bd6V`q zGeAE-gyVq>hlm?e_6sz&U$Is4xvnBw(}TC5@=5Jx+VOM#^@I%K0S{cV8TpI z|8Zkrjp>e%)IX}By7f&&vO$QXgYE{^2%(AZ;%UOTh+q3<^QZ0SDcts)GOZnNB+}_O zj{RkqwCybCS2_3YxGcl+fuJT-I2t@**PKEyxNNW0@?pJ_8DdgP<4(ry=j=+eQHRSg zxoTtiSL#i|pZaG3Gp|hi-`{9{JN=Ey@hy_+tv`7+FXL`^N1Z~AELePPv=4YG5ufeM z*~x$)8n1(SFpUl+tZ!Hl+Gj&`a%firTmLFS|#a`W$F;>U?Z5O|(SKXV_CLE7lYK zdB@)dlWy@6a6!~obJWi3$4TLK!E=C;>PDDm)*b5xbnr=~3UtZmEVgVsPO8+n|0_O) zqffe=iz8sydH>G?w50)SQ!ux?_a}4@c@o-t zLQHnwo6QhE9HRF8;Tv_X%1xuId zqy@y)iit0=7cP=?6%aSJCg#|c&yF&NoCjh8uvf-+7?B%39$rN(3ahLZmhfL;2YM6s z0kM}`3_lDXBXy;hFBZ=!d)_4-I3ZLQbvfe3Z+C(A>LYr}KXd`JXPw%wcLj{M-yNSMSF2;)qgi55 zJ3+;Fn$_8~ zTwJa``S76R$zooA;!P_|93)cMt5u2W*-JRowLoJTIY!=$_?e>SL5nvCL}`{&Z`o-{ z(|T`!n_@SyPPvZ&40Ez)TqRsrT}d~sy5)_N2#Zi^_H{SapE{9m7xF$2X0m%2 zO39_f|L8yok&HnzQiyQgD@ z8+KJh$%pD;Ti2H!3gKIB{vbjIA~{j&Ad8G^$!3P{>Q^uyTG!2BKgwFI>?RTqn6l#a zXZ{jK^t?6W1mKrgMG}}=e(=G^eW@Jm-@7rtbxEP3AOA^sN$sYU*XU2e@NZ9FMsvlh zqsEbciiK07{us%~fl@rL3z&-{h&v)a_qN`oUrPeI}s(!r+j=R zl7Q}yPR*3C2*OUcwl4eeKYUZ*3Z0ILmwRwMAagVnDgKz(rCqwN^lh@fkHF1QL z`N?ZXuUfBXBo%!gC2wkD3rrz|s^!btL^`)&&%S9rYW0LNBcdJS_~`Mo7UV*Hrj$wx zh?K0Kvz&M3w(l!?_$(3FN_gLuf_WhM}%hCezmYbKsp-kay#RaR2+^mpITvp2pLaphoLX zTrq>0No`pA=WUDQ7l;C8_%6{3cuycnGRc*2Db_`;tfrUQTT>{_J!CO)Nnx(->#VkC zTqu>aeHLeS0iO%nXAXk>Sg$c8d!4QCkDtxnVpNCa+dq>XuPJ))U2_|HHQ%F8Xb#6O`m1V{ePL!6}Ma5tj zUPW7Cz@+>A({5mHsd9+T%NP~4k~xgW?N5|&oeslrSGumsMyMEpg4+I_{_yCqx;!i! z;l|7{mtVcqGQQ3;dL}TU_X%im^!juWwI(*H);ZdJ=&K(`ZGaj)d#Nr!fbg3W@CZ$H z!i7|SLpv>8hFui^9t?kuvhck^TUeT|-krbRUK1Nh@B@vTTodA6@-%q0x#mShDV{NT z0uRB1P{_1kCAkrJ)jL*80Dx_?3KT^CohFXTOMW*Dbh=T0r-1&@=&+RGu92X2#Dm() z)c`WeRvLOQms$u%y_P%klvPwMdYKWY*Cyp6<4Rhl_w!%$k8sYq=$K)Hquy=A!6Z7P z6|qRkKrQEPawkrVmYLxHMXOm_!oOms@LQ&yT7-<&{&aW9IrE5n{*h}D`Lf0lv(XB< zu7KmS%KdbPCS*k{w>Wbr(SiC8pFp@e!%hfDGI>$-dl9v1ker)Nhdr+04e_VuURDpE)nz z1&j}A0UAheb@PnvxAkA!$6AzfUB~FP*NN*??+a3Jkse$d&?|?ZB9~C_m^Z99D0rR% zlmz51m_%oU&s%4Zkqa7-+QVvh?Wf?P+{F6pahXrA;N07Hd0|73&Pm4 zrs;8m;kyK-LK$=HmUc$Bn%(!D=h)C&la1Tfkhc#7p(#x*SPc%xY>NEL^n5REPyU;PVXBt(`>ZYzc!b(;bdDiq0 zDc#RNJT@%+uZMV57ed}b)Wp-YWEH7Xb0V=p86m_eTTjM_mU&(X!r8AEWvE7}@BRz; zwg!Hu-kWqYde@GJNuCYA8#tVeoJ2m?7CTL`Q2RlM+I940gZxDWM znz1BL!>PY5Qt1vbSWLhgWLpWH^2z-^jy+E!b(eJ>B|Ls;a3}XF0#r!nF;rKSu42`G zUdSkuO~L5uoFsml^m{a}UJaa9S=?UJ8+}IXUJZ-V-_fK6;^{A@Vjx!RQDHnerKyv3 zU$Zg)7`_fPLsiVxjNXsJ|K0n(Y6Wtm8UuhswNP7fzqWt!Nh`Z33T@|O-2InE>>V0; zaSuUGF98cMx=>V*V*V(a5x_^h^R)pK#;U_d+#6PuQOWVO=YU)6oM%Kl660v+ zrkn&Bei%0g?m?#ht}7);jvwE>r6}J<-c7XJ-|N5ShC1s)bbLN;3Ue3|(yp}9K>zV% zM6a`Z9xDxY!B`K@?>!9|S{mxJ1y%SapgwdSz|tXOWv5cwJIQ}onOo*GZPO#m;!rI;(G&;kxs>xYp?cWg4?GUww|0{loEyVws#pXE|i_9XNz@mG5g7guFCg5 z1k6`4`3Mm-eBjx^FOFEdAL&Qe2moH>3=v<1aJJy0NKp(~>HS%_4*jnin%> z_ltp4zL(r%oRULAS57Xc7A}5~|6R+4+{rv=ck;s~M~%Qm(P1TRN7< zeZPxVTvf+W3a)lZ(E_ktTjCK(l_F;g6di?D;CKHYFNvFbBu604V?=P{>JJMFM( zCq!%LqpjNfbZD-SxtDU-wx^5aSxVt@@4Ylnr-gTI;V^uler0d^DFmh!5a{)GTfOt4~db~o>e-_($ zj_MV<9?Dz5OzLD$2kKqLQ2z|0b!AU4ddKXrrkejHw=Xsa;J3ha^!R`r2hb})^PR9e zR+8G;Zo-q1(A&$Tnk(0Dt_G!#7=E2t*Xrt|-VQYNcQuyE(b>RY+(nKd6B6HiCKlBH{SY4(j37lbMXoZ40SJEn@}_rem2xxF7RQ;H>z|p<~nhG-PBt%My>S z!=^tNcrM@Vc|wlEgEgCHhAKenRz~yo=S3o~X9S-h8cIB-LZI{@1O1s}EaEis0+rSh zUE(!(5UjQ6ef0xJ6n?OM=GRHJsPTLNPG5(%V7#!_X~?vG%Je!!N$bxeFk$>9&OYW; z$jAHG;9|KEl%Cz0W5>jYtOj%*a`{6nTiPYlF5+3HYqqWQHz7MS+cP|m7n=X)|+ zU`0t*p=E$QsO#7IC8(iJOwfFaz8{3v0S-{fPj@&VBDY%CgH4>sCpL5Xo>D*h3)41> zLn{9Ugw1E&i%7b)mzj~s)m>~@-27_3RpO8IJR%D3R-soC5dDJmc5^n0Dfs)*KdSbv zAWM{$NAADQaf4Mj8*olRZf+Jr@LxV3>vTiYXNUKiWscvj`B&HSYw zU;ajjZ+$TI6eI-xP{Q6%++6=vsK$)Vfy}87c!QWU1e5*gA7i))ufdzonL`q6<7*^vP8ZKezN`WXfMchYa{nw&qb6776Px>VMm6YC>i|zCh0?ev!*@)hmA4P=-wUfJQX}iAH!Fu@E`@Hu}-Sy#keO6C2Ri5 z=J@>S$kH#wkw5#XYXiWERr^z%avl;Fh5&Pw%|iFi#E;JRzlE_f03K@4f^S~*j-0MsdArtu zqmGcz^<;hU)e=UcJCTG%AzT!aQMKr!)%v~-cGRh7{7$`lcy(`VQxYCA8#O$+dB4m> z6H1SSH69W8$UA*&r%JEH8 zL3)VK50YW1WY4i*9+@6)w&K{h)iKS}HvaNfZh0zlBn2SzWyGt>30_L~PSj~wYd~#AV9Fwu-}buR{6$6) zJAdX5@75oEW2bq9<{0C88Ic zqg90mwK7?-tUCI{PYX&@Mr%hKqR?vB4xh=vfh`}phb}EZY?aZa$lz8vz%1=Wa6xhp zFw{$#H~SQY^|)`m{Qc^^xaf#qb<~l6fnHvPDRC$yuTFCIUc_Sf8)sm`bjwpwpE|2m z1M7M5(ZG4S7QvE-WKEbGQ)RjFV=pcMDgGDVYo!0;LT#&C%ZqP6&y5^4J;4UGJ2EWa zvj)DY$laJ0$Y7jk2qjRRvlvlGrvA}7df25X7B#E!E70tO4B<-6d!F06vt7T^}%ozXeF{5UpZ9EsYqW%5Fpn`_03vN2V=82M};_DLn9nWJ)OiHik zPn*2Nn8Wc`q`*EJr!+&#t(TrTeN;J+)Fr0CR1VZw(e@ob0xsIT_pmv8bVHs8Ok54i zc;0`PHIRFWJjOxVbzzLu6#o=v^AIO{=$iL>a_Jk~Ye#I&((bm~ZsJD990#mL`b{`+ zXD#{`?U<<@{;?zK<_$0(!(SfUb;ckaIZz+BuMuhpY~DJQr+Gh`gzSo)c|#$bUj;4^ zgSjU;ec(lloqWxjjwaI?yRq*VVc^r$XSqA{x)#BQKg)Jw)}IOh%P+1B)v>#soPI5} zO=4QoRwT{vF(c3ZN`dud&^f4O6bVU!aMpUyp5+|m3YYq&{=4&lM{9vmE|f7+>$~8z zG%jE$=*xOsk;7~hXX$}s?cqctfWC&`-sD6N&A;B1((G?k2Uwk{d0)g=j7C=USEn){ z);&44Cltlw*C9`a#1HE}4zMF;X2~8MJ&<@JV91X6f%QC2!ck`A|Bf7y_cpV{IH$fR zW9m+STV9KAXu&XP^-vFe$W=dI#A1mkLczCC>@OmpIfR zPH&a5mGl^U#WDVNd$9cQUgjBfoyx7w@_bR%Lmvt;`-aqfr;gLl(qcm_pqpKP`3IM` z6!7qC66o3SOE&hz0fXN`~>XZt%5&Wrb_&sMCvyU64O0aHT0tVOC3zKVry_^NJYXz2PQ ze8N;LOJSum0pk%7OfLiI0e#f{x7X>{kLxHqFJ%O1c?r|UZY|?`wwE~pZN^Is!cB{S zcLcQmu4cxe2Yw{f_cJTnh!1A) zI4WW+4)#1bHFgu>*-5R@0n+1m{JA(CE|x+A(LfWYRyRO*{|<_=Rp0m&#Vt4^Bqe91}2`H=BLfx z*+Pvf!YWSnt?RGw2vkS;**&~p_Qb(Q?0Lbf8uZ3{0SMe{?Dz38{pAxN*Dr_56csq2D|n7d2k;LK)B*=?Nx(qv+9jc6`M8E7KT zk-IU(;CO%yu?va!w}awsTdF8gJUpk3TZD2n!k=>uu;~sBzuF9ox{!V#0_BdXBzCZ( zFB_ayX{n_jJ;pg+O&)5_oB)j|S_{#wA2Bems;;3eKm8U5jssCIC8EH8@RYZhki1AC z5eS{hyH?^vn(LUZQVVRwW_i`?2&IPJ^DaafJM*iA2T2LYD_Qu+UF;vGN%sjcYw0a#^=*6X8{HYSSVU zwPFOz&3t2QBN6>IG+6^Qg^8r3FNG!x0M;SbW;>KUw0tbNryG{lk4dvZs~b zwR>2dt{BTiQqV=87^?$gD}wIalq_(-t*Oc;t!tBEWq}U*Ix2j;F>N;vx(BN#)Z9Wqj#h^b4 z^Z^@7JnUvi>;^ zKpL;ds)^XMer+}-TJQ?iUP|bEG6izX`7u==r}j#t;OgHIp|82I5rf2k?YAZ_-69+* zp7jk5U~{p8!2QoX8O{%WM663W@JxX+@1Oh;HxKVT?;i;Ik=HVNYhzoxz$eyl-~N@A z^G#j3JtOQ()Iomw@ zDQeJx7SxI5qnCIxQ7t^h6I`pr=KDPZOJ@REaU6wod5DU*w5X--slbBW2Ju4pS^!QY zPeScXaIWc2*IKO_62f%$u+7P;u26$LoM_&mlZ5SUacl{1hcf*7(<7@yp0-wh%hb8E z;#-6DjycTm)kT9QZX@C}9zmHRYkd?M7XYB-T3m~0#sDl-kEZs-X2q$DlBuK(ewnW= z40@H-dMxbiqzftk#71Y+m2&h#-IJAaEqmWN4^Nmv>6y@xu@(L#a zFHcBLHKJY?Q5NQ&(M8!I#B9Ihx=YERE2fULuOC+Ho+v#HtCBX~PM1&y9Qx2rdy$7h z?ZCSLq&X#^nWgI9S7WrG7~p(DIOcT?SCaT!G1zBu^Mp)R{JD-intaCjgJuU^W{l#m zrZQa?L3mP0j0GvbEvS4ldIKh?*5K6ji?Qi{@DxaMkBla^%5Qv3WI}NgPjEy_ed^Mrk%qnI_6VWy{fDoBcgOL=zd2(V2N`szD8vBM_5E9* zCMGLiy|kDO93#1`4wu(O-35(S)$r87U?hi8;R1o+q$x{K<8?vL_7gT9`8qW$w^hvb zBo5Vofr=$TDY801mzAKhcMvGY() z2Kaj!=HEeodg~g&yoZ8pasYQAaBIq_pQtX;rPT`i14iRQ!bcDD4tUyv;D-$*uHpH+ zR#}JBXRtdT7&7AsVO#78?-##^u7bIyi?dif^>sHKJ7B}6%p!RVdBe|Ag)oICR zx+GF#Yi!gzb!ABD0;$QgjcJ@(mwv2U?sc@bxvPB;P1}pv>gaS~s`#->Y{JNM4Cyw| z0Q&)o9M<*Zp(Ug5)bq#KNCHcoE_MuvouS1U6_*~12pnTeYEVhDy?4{e4fTPE86Kou zr%oJ8<;KoO>NWOXF6F+O2;W#_SN1(w7t!tZ@JCt*@%<5JH!A#Rt0Q-wPMAvK?z-}g zy!hIoFHxnAHFM2tc_qR%JesQZCpZ9Yz)*jmN}deLXiWsBSX7Rjtm-YaXj3VE6>r6x zx8@gth^bHaUaOxUxC^YGMFu#2L)&lXYOs9+u#)uXNqZ)fE3f0GEi)@Q{F?-gj;`jV zg(k=If}o5YC61>v>$aS?%m~$+rLx|ClcppUqT0hL>)c4RM z0qnRN;aWoX+Ke*qMeb{Pz!%QuJnh(Nfl|Su&)7~aiv2vTqai;<`ZdnxPrgd=4b4&m z;pluTfg}Skd-#PZ&2C5+KU`@};A3CFZ#IKYf19b8Nm$JSfIlqD++MGoDQ-~ih=5H; zvC}GH-vXlA+N-G3ajVbqLex8R3We_+zJ&b^+1_~pM6{$llgaB5YvtR!b0*{W_Kr9f zRKBT8P&18~on8-g%nB)GsjKh!ja2|U;?WOU!oOYo*63vFQy)#xg)*v#)w&|#{N{e9 zyYrGbG@JNRW91|!=XX+a_r z{b+b1$gCXOvN$Gr%e$J4iE64VMEY;7-eEN7i(XDUR|UjyW&uuuHVFx3z-IDMd3tgS zQ3Cy~xzRf@p8`53ok^4dnSd=E6a??j4$1yM7@l|Tg>{LqH zCi&)Y#cl+ML$gkM{or(g9*kgsu{S4Sd;k-1e<5{3rLK&vC={E67o5)caok6kDC9Ji ze>$R6*?iocark_Jk^FLpoBqR=Rl3UO#`jYwVFaR2kfm%G{6$oLGo_tSsMequz*rDS z=Q?7tgPO8}@E%{j4JS-993+G^#l+==q2k-xj@z8JWhS_T*1|+xhv?FO$1v^UK}&eh zWA>_$u88HaH`vQBbirmG?`DVTBF5&(c06^(^I>~ONwiyEI0y3~>D{tdxSOAE9P-e1 z7x4$YNuo^hadHtFZn0doh9L#@!5$lM_p8Es?x@-dc@lKBsxaMl;;MC(GuK->88TEC zRnoRd{8S5@u$tly4}^*6p&D1kh~o>P*C)qSnaGCRsVTqZnQ^;}E$tP;$Yxabhauo} zpU6OpJe)3c&QwwUs6(B!AVxa6t3RTA%MMZ}`*voK7R~iZ`N7f2hK5@VTRCou#!N-4 z{EX)Dij-1^73|jqzA^`%c^RabQ_z6ZAd4KQDD4F(opne9y(U@qP7fItTutFIwt*3` zGnsyl^*_!Z-mLgq?yTb+BaxVxLp_Lex%&9%1Jr}o>! z6mo8`5;E?AxdEEt*wKlvo3|JdcQb|n=~3R)HHu!BE+Bc6c=;SkhQWUuyMbpOJbThp z>0*#GSKZ->K#_q19w&LuYYbCh@GEMw3Cif~ED|AFceey34=;7id^(U$!pw_rC~R94 z3lJAVq&Q+*fUMHMD#V`;^B3ziiL*2ZMYE&>Xw`!E#;&YS{YsOhLlI3=l_J{DQxg)iV7b>0* zKCQ}Hr6&v2%wsG^srZsS%3T5xa}$uPPSj^^-TBJJ` zd#O46RX&%-^_gx1+t z2COL!F7R~VRZ`(vUnLX&CXRIO8%Q;X4~!I5-UOjtTn%iG>`E6V;_vp1vE(7M@to21px$_+%e)&ra) z2Ta~T8%+&@O&_Ol475FS9B-9&(qgX+h-V7(?$%;4`h%mqYRjAR1HzEp`#Qor&p|Y| zXYr~&SOpJWX^w-vUvS}PSr)?2M4kqeT#$N_6`rJwD*JYeE`_eh`_Q<4|E$o&X|nk( z;_s2k8rdI6MNkE+xlw^%?5ZmA*ULisTwL^K2QR4xOuY0%vNQ(jX5UB1ZzE*F>uzRP zxHS*^3g!iAp22976&P-yXiI=PhRKr>c^S<$z!6JgGdo&j zr+po%40tfz5G`;$}ssxV%qx{ey&EAC+bd}qDW00)Y(Qj8U z?%{*tuQZRztvE*OmkdC!&xgVQz z8u#`s$^ zJzmFHJ6HeMmEXE7#vBfJAlm0l_mH=lYf1npPL_FIDVtjm31KMxt-I6%juu~Eto3n= zN)zzJVhki4-vVI#Z6c(Dc~|=Dwgc`x`jFGZh3yha-H)XwMmxMoN=i~ebB%0h<)Etj zq@yFCr*xHBwtbOh;Dv#fAGnh$wZ}|&^R~%{4y+1^s!>avIv!d`xPomMhg@BMvmo#e z9RA>f@;Yxv!I1$=-b0jcy&`(@yp%WSv&;7=#4q`Qc#Um0PQ(Ecg+u>Y1iVKvLP=sdT{FlEk}X&_;1 z*%1~{lv{lf=rd-X|YCtYtyy&+16f`SbWI2j)`UC{AJ*<5m!HI0c z2Wmuay~+1+VZMy1F?ozAt_+t`)aEmhGng?q*NKUM-v(90S`mKbSWX!3NeU7=*i-Yu zSKMc@)ACH?j%`c=@x!_V8c0-$O<-ckZnDe3)kxF?nip-gQTuDY3&qM{j{QnYy?0l8~T~!SmRnAkAurgfNV02^-&J&&9$_7BDO z4g-{6Bx!eE;w854AWw)}*v8JFH#hdjpKW$!kkTDGgQB1MOmhD`HO zv5Ll^-oZT-0P8?yYzQsj-yufqz65M;Mf@>P z2^YP?WBZY=?p~nO5b|ax1|w4W$K@r&Xj*Wf;#zZ3sp>LvSAcm2lYU4rHOt4U=|+cJ z}=9x-x0A=ZMf%*S!__*z5cC40GG|yoLV0dum-WYyU1o6X`%YrBC z=_gzC`)eNmQz|X{p8r=Uq`)P7g<)t(VhsFi+<}_i9UMO@0skp+0RK#haF5N`#1R;z z+o}UxI?3n%9r4ABbYpfPLUXrO<=+LDIg{@q_dhj`r|}h(d;jmBEZBd0&FnY31sL_8 zit{WAAgTYUBohpN2^{-RSzQowCI9ow1!RH$6uoGMY8}yzaCH?h zi~HY}Y{ zE}-ExJ7Wg`u1iTNc9a1jsRkhylrZ4@V`SLO$v=c!fung|H}#d8$h7?b%y-8-F{ZUs za{*isn9DlAjcwtORO>Ki$6h(bhP?*=uI^;5jN(^cQWJQ@vm1@t^gjv~>!wTj&@j`Y z;1?eVrKo!VWS|7YgYS_ip3aP%C{n?Tty%1dw;$iVCxAg=BcYbW3}80+yS775JL zS&;oAMT@%AeQ(tGu9yPJHGB&OS7l?p+fjZl{o%wL#rTVcOk7Wub-3FXWw*73m-z%ni zP?bk&LC088{D;GFsgD!r$Cwa8OQ0PS*Cy}$0dr|!JU8ERa*;kT8MBx7l9Q6et4EHH z98SJpjdoOKxd~~s{IdD(JqPwAS~Z>?%Jh|my$Tfv#7KKayNg1)utzWbfZ;0eTdRdH zda&I?!u^yXkW5ux0>}lrb_!?I1D(Qz88NEQXmF#(jeYsZlUMA0IXd&Z`Uao6vT2$5s@vv zNoXRRId1WZl(^1hyKit=h)e3(9|YflI0$thvGSTU$0-4ndCFPlj(D(@&ry;9Bg2U~ z(sM7SQ#7Gz2ZP{1siz=4KVqjy;<_ns-fJN-w@GmK6iteFn?W#vQCle9jF?}Hl$dDA zz`D4A?w#ekgdPT2Z#zyEXjQj(hV@9FUNq&Qgm$tdCYe~m1O3CdF>C)a>?WvVJu}QN zNVJkq$;br%C>BiO3aoF5->3t=9><&g!$N=e4+j=9;1BBWi`M)zG!+fVA|bSfY5vLu-lj52esy=l)|yTM(g59`rXJrmTu%W{& zkBNWH163LFuFR~;+f^=}KYcDWK-4+XzN>AD5+Gqw#$oUPd|Me#!@&$9oGgWdNsi*` zM73O}?yy#zwsB3^H-C6Hr9_~>${BFNOwTg`11Q}DnWl$)}FT6Kaw zkCH%4Kt8^F8Y&&!<7k_)dPg9cp#Xyxt*sXiYdD^%CB&5h`JBX?DF#(s>lo14!R3;* ze0JkNM`?TcY-HS04StvLRzlW*5Cxa$pQ@VoAiCzQN9)D3GZ`MR-)4dMZ>nl-B z9JgKQjQc!wUkz!`fOcSAPFeh}rBrWtG5%WB$>&+8Izxy@@_k0fBGyEqls51P_ti|= zoh8u%9YRy1K&y{aO-;qdxHw%N#(fH-*rAdX+ZTZP1FK>!17yanysIzGAEqQW^QKA4 zKxo#Fni$I&+`o!J7M$4skEZYbr}}^Yf1cskduD_(B6}0gQS{1+vPbrcjAYMaWF%zI zP>F0Il68y-SqaHHw#;K59Os;>pZUOe%%N0&ZF`FFQy=$qQYz| zhn|Io!}^jqdQq*W>y*TGd4un%hnnq=K@#7%{c@dAZhdS~T3%+5unW2{BZnu~r6FiV zc(0=c##%P)LXDhGoY7WDx^{kLEfzE`jbcFIZeA4#k$)n|i9rA5Z0qOXDQ+X?p|wP) z%v<9h%Rx+FSCCKZ_uji6N;H@!;FHs@_*+nbfW2qi=Q#ZoRr&VL$V9K#=GY$Ci-Un1?dx>|Dg@{gG~>9}po*Q#?rO(_X4n;$^Zw2IDu5uJ^Q z;>c#QPBxUCq*-$jOEuUHFb|+BAi44M19a^r+9?_eEB65|P;10{rx_Xp;y{kOT3XDp z%nG{mSyI$D2!jQm9KwL~25C?td8A=M1eTzXZXjX`XfAxu8&}QkgGO{X=CC6oQBDX! z7cGRH1*_D7*Pw4Rt(-fed_)0UL!CJw01G9Odj%_pP129!d{Bw?X^yGz`g5EJD)#~kBD=I-0IYdY^FVnkFsnbD=w?ghK@OPOQlFFOlCmi#_nV(P?kYrWmk_7v^7A5O1+ zIAW5>ZivD0skFjdL~FtXBRe@F}m)~?|%9ZqY6`ZMP<>grjVKiE4DbXi`2Uh z|1F*LU6yMiKw({Bs-!G2vAhyf;1V+h;f258d;ddvhXehRtTyR;`8tdy z)0-Rf?*Vw-R(yCkTTr1gZjU~4ZJ5MR%WeRTzYiIT_?h+c85omXAm{y~fMI z55f3E7-Ic3L>R|=77~18nDptiQJu)}%|1dd(kRECOZr>#bYR{|qNNk>qH|_w{?>Un zGncZb2(NvR&HxNXqmpFNRu+st0-$cOQP7gaEGK50%xBsm3DwS@hzBu?N)|T`tsI4P z&D?Gf2L)UL9z!ul8b?eUJu;kwmO2TY+CG zk3~;Pw~+X{tX^1$AkOMM2>saoXZWw!&3Nn099njG1r?VbmE}-E} zH1ls)Nh0PhqF#-5cNQ|uqVw|ux&jvx;e`c64Cyu6D_Fd;t(9_uhq_(+S$nKYD#<^* z8UB_ii})5r?UYc2O%X&<@frEn<`s%FJ-B^mNl$`)GnTA z?qj$3`A4^hHQxu-V|0N3e1|TZ#?xfcV@CHy5TAksBQyKpm!iiDh(s4H2qB( zpD`iTGe3Yn8Wr)%&r3KyH_exweltNpbywGPv(#v#25o^6%k)MoBN1;rSIp@mWjQ+I9b{q8`)6-oC`;9=%W7UQ79?_V^OCuo-QBU>YTPf(jF}WVR1$DVwgGNHnMa5xT|Li*W-#kyU^(HNm zjzv953(gZ;I>YaP!Htq)qU@)!@bP`%Do;v;*NW~WNo=X8?hxex`VB!pegUN9{|_>b zu@WXyM-wfx)OMF7qEc3>ARwdnI^kL0IwAJ!h%Yht)$4Nf zv;^;#3yl@^_E@gngUj}}s>|2U`JkdtigY0Hc@*`GbzK+H#Nv}6cP}x+Jz(m^BKs_q zJm*ysCt~&5co67ME)n*$7#o=eu>fnDlmv|K*nX_+HaGQMVYKvlvBuu_K&BMZ2<*7bmDI+}*Hi)_&mzeJ-wYoGU{YJ6#Mz3A4E~&~HOmitL z{Ajb-q%Qk$`fDhT`m4wWKE6OS?k_(*`(?zrPo13%pIn%&g-HD^(r4Tk1(GsU-*qEF zXC$(}`E+Cl-#K|0#yuCh)fD{Z&AiG-111vXz0O14lnRP{0CmcA_bKRvAM~c-7e{4$QLXEdl9#7q zDDu*5vfAt2SaEWaanl!J8lTO#^WO^bOOGJA*7#$57TtKr2zkli$Px0q-0s^5YAUWh zJG}Th*YKQohs$iFN};L5&&N)B=1R8L9)=$r02Kxd|4(L%> zFX=%0vb~EHZ=x(sS;EY?P!o^A=%OO{@>86?_k{rAy`2v{50g_iwN~NJadgsY&6-=P z2i0Q|qPEl@ecNh43I%ovs9gX?M^j`;_ge!z|A7m!VIs9nwgGe1+)5iG6h}cFM|jMz z&iu_T&VxOw#AwfYk`sVgmjdB6YsRrz$Kir)IQvL^N|8EE> zlKNx4**9x%S!=5VyD%92x+poOd_tEi1ny@prf?$>%Exej6Oj$_C7{A$p3T=t0@8|2 zMVxQY1sy3Ni2nAP82oj9AA7q&>mA5O6D4IE{)WU< zAUj1)0UaxwCzf=bHMW4s@GB&${v~SRlJnjA98SgWj*bpcUBLwLwmFIoZ|Htqth%{b zF4DCToRdhl$x#AnVFEce!F0!~qp`N*`>C#EU|DDKVv6^^BJjoP?Qf4mwD?^{)`VcoGC7Z{GVZ@}(o< z8?AFFO3B`5$@4{mErZm!I8|q7r~R*Y0afxPxu5qP)5MB}!1*Jqx}>|K!EnjL?=6qw z-a0yboZP@>?tXTD=}^7tOq;PzeNx3{Zj4KB=HJuVHguk^G^04 z0D)aXurEkHPaqfc(@1d9@6_;L?^iO&6C;h-D>T`wE-- zK6#N;Sl)T@#{kQFNR06b{dh21NA;6=X(wWNcxNF%fn3h!QW<)Ov<)Q7VAoRd%rc)z zl_9!TH=IA(D0Zl_*EC<(Jvb=dgf%T;PT$wiE3EjRk#sc*hodFca5L2#FGDCW^JM(XPNt6K2A~mw@sqZ_4{bA)IyHw#Tl0u9m>oO%T zRW>-Bv?7t-rp%!8uJ;iUI{_(Tj3f{zziMihm7|ro^D!9krKluic6QxW4xN+25M{i# z=s04#8mZRWh_JV|FE+d44qHewCKAV?oQ)+npEpI1*-SK} zPSaaKH*OF1Bk=P%abp*relI2QUbqJDfw3yJ<)?=V!Yes3rwy@`aqc;TFf>8K)xzS< zK3ZF6FithfTuzxN;aDz9S@{I;QZch<_hdL0!kV=`b9~@MTBvt!-`qPs)}k|BAWbIY zb7*MiGxAU80;rN)qP6oHIobWVV^H-nNb{M62;YDfC6bkt)P7u!8nIJp@-~x!3-gUB zlMz>5w;Y7YqYPL-A_Zz5-?Ic;a=JV<8E-}}YQqw6_ zAlTgdN?>6*eW|=sa*!DM5Z3t=sR*)y#-&ic4Bu>iEEPO{QhtnmO6fz`DYPOrM;F)r zz!>t^W08FDS`6q@2B7M9$%D zf^W+LN?9^U6t1mI*)?Y$+$K*GCQQjp0vux&n(HWTy*ho^*%+2j;dW^srGaXxnRKX^ ze7V}y`~BL%2MfwPF~`Rrt`;@V_I?69@Nw^nx->GgrSRLxHmkB>Un2FeO#5Py0_0~# z%zA`LFCRf&97Gvr1!ike$!wXCM*&G@6tAiUND7I-VC}BqV9UbG!Hd~9-Ct+}j4a2v zP7{%z;obW_N=2U|63|ri{UbT;olhQC2abBPnfrv0WU~F#XXnIQ#|PeBKO?gn!if88 zgbiIAU0-b7?%o)!lA;|ZkGOGzdBo%M-SnV#r-*r3*~vW~QJ^g5bbmZ`|`1ytLjhrwfZ^NdCGIZkKSa=a5&@ zqfa4u9kbIo1cu94mlobbbI&olZ?+ft4&cS?lX+W)k0Jr&>Mq#qid$d~d7Ig)uFRRB z9eGjT;dwdH`FxeQ(Ej!NATeWcWhln?MGt0jzs|%7@)lWjb!jzvDo9qfKbqYH0U}HS zyP z>z#Gc1%AK%R)(ksw@=_y75vxHo7yGX58kuo_#??_&5?Nzvb5i=)-T3MThY>0 zHTKhQ&#m}p#a#WONf?%o)?e)Rfu39zM%&iOYB0uKIes2pJxtX^(8&#HB7)2lk;`vt z7^fdrfxT{1nSxHp+s8BmYV48a+2v=$5o<$iQElaO@0Kq+oC_e=|L$cY8|AIQ{dOyS z3Q6#Ri=3lQl{auT-=7U>l63>olTQb*W-60k0%sGVnx)&s8@osi8;f$xJSqHyQA?$R zR1dJ$HWg3$m4Eq~T!+L}q2a6Kb?r!*6YMbLYFTts?gZWt^8Ru9JJIg!gLYO zkLQjHSs`XK)qNi4e5w>P2V=Gye{iT~gGz4)saXG$ zAhf@I61dL{n)O?WG%h}?6^87Jo!2&nVR&Wi0tg}L>dZIk!`*G3HeTAF_+K{H!{lr+ zoSU8zfEO)oSQl=GWp-Ta$9DH}${mki(YJ~D5ktg=E-|w6=OajQ5(dDnAP8(o!GiD( zDrv-8B?rTcv)-$czse7{yS};9TUXVK^3ik$!{-W_eLRxwR^nMxhH|8(I6Wi4Hl(In zQ6H*F{)Y5_qF4W0^y;9kp>XicL@qY%N3H4?RoVkd5fA$C*{cDEGro3|PXb!vl0eIG zWyO0QkIwJX|CqZEu8kQ)rmQn(fg3YG*Umede;%pzv@ZMSc+hDnq$dYQ^BA)mU?pWt zL2DWR-gKI%d*@iIcN9r&oU)2Q4xdP8PaX~n^p%czD8*`D*eA16!u9tR5x8Xdg}G1H zPcF_|zDODpJxZ7;$@!~=cKsD9u2^y0ik}jVN;P6aV?;nw|CN7F#C2Rd_Iqv5x3nYs z)mCdo_zX)X`L{RN6k#rP&Btr@ zhLndL`o{%UyfpbaC?t0@6f@Q@Ey%oOZz2!8~qM;$w_&f%g4M}`kCyf8T0qWo4C4L z^L?bkmwwC0phcfS@#DoP$W77J?Acl;m7P+)+HHiBk$0HMZbRa^NpDVzuF$THIqcWm zrHQBk;VnIZ$NaO@pB2yf4HPos_0v0=d0}6}d9!%UYFVxQ#6|w7*pD26l5Xg>hW#bJ z70l(j#a1EtrG-Z3i8}3dcG~Q@9GS_k<2hwi`C%4YhGL9WN3O=tcd<#PtYE}EDa`9Y zjZWwte*>zK0@0mu5&qncWJ)4U3AesUIetc&E#3 zEJxuxnJ4UIF%!ccLY&+3LXf*%_kHH(AORJ6&^0pML&-fkxZ^;{rVCUBng$3Qw+6p0$9@>ytTM<9eYjSwKDdlocR|l5CKUT0ZYnb>VK^ zhWKJabq`<6X@G^awsRMlo?Fo^E`^KLH8GGzzQ%Gm#^Y?`x$?|hmWK2HU>4mU?BPYb z4;f^oCqr>BN|quZsOM74stRlKv4r^Ic-SlMPvgMY3{<3-30mx`@3RK6<9}<4zWDk@>1KT`XJl8d&HEj;!TkRgp zP$I9DPRqjL1zv%m+IA*W)fO<4f>ApdZbyO<9;eQ17}&KG?%3V}8+#xdyEPHbb$9k= zMUfA=FmXwF{O)p-^+3C#h_ht+uNGr6!rbeF7*I1K_b1b6pP|FvzOPg^8yGue$9b9) zrg&k~{B)B&kF_>^x0RkI<)mQV_NF!~@P_w~Fj_tEd+H>!T>eEG4Vvpe_x8otlI40F za(~5j`uRoLyt$>%=bI@Pt?p5T@Sf9e;|+g@>TSj13(0aze9>Q?mfSb8rxW8`4yk+i z28@^kTT{E`BVMdvy<>%fAnto z&0XCwbcvV?m@m%Br~S<}&prl0@7oAIoKCO@h^M#9Z@ex$C;0uHFSeD4yehumNO3>| z`#?{&WMGwihRb|d_w9}ySJcOTqLz`@YULRSNtE>MQ|v}BjcoHQ$NEzS-@51RkJsuM1Ht)$%dDlm^>1?5!G{i06)%hpMlx^Jfp*(=%yx@2`06 zZIZ%w$A1KG&7Pumru;|q26_t_hom=B4d*Vv9m6B*7Q-GLpSe+?*`0M1#qEmMP-s8o z(n}T@xIljh? zd55yPOnrp|XGb}C)pq83eJ3QgYS-(>+T4&&yg;uEE8nZ&H(O2R!W44( z4HUp;@^UYRGOl3RL7P$)9t|=YM?Qs4}Q% zFw3m2>&u=DG{U~Ry6;+(e18x)o|u`QR}E`Q9TRGTyV+I}&+Aij6{eU!kG%?07~x~@ z7SK7rk~t5w)JaTZzH)8R4db~wU`&FM{PeL6pis61*Qig%#5ab$nn0<;3b79Sd-rU( zs6mf47RPihZ0(8W(mC55yOC9Rcl>kILn_rAv9c#xq)~z*eeL6l2Eg3)$@Y6vRVVRD zpOb^u$~rEK?F!#}kQ+2seieCi@Z_E_AhgwValdX@P@QDT<)Tq%C<>Y^Jg+aSyN?}Q zs5&3J5xSSsn-&&%)lj5~$oExstUGoDBXpYWPyE1$MuGoy)NKVcNJV?@8@Cf_aJroH z{EH%L;0=0@%dVcjUG>r5Xq~9xLUbgPEjUtF2a{^7+p8M?b~jkCpSt2bt{fv8=|`MUQnUOTo4 z1}Sb>*P>w6^wS4q-Bx!$A=HE3r}y|FNj*TCy`uSdY_0J1VPO7+5Yw+hyxUak5^tAS z7e2qno@!`t$AN%U!~OT_`Q`&L8v?vaz_lCags>nJi|M$$M;S(G#ucVOi~a$=Bzta{ z3I4#L)OhQkVJ>Y){2`HTfS%tmeoaz|QGVO=RlBUZp{vmT<+I-sGe}{al=jgS6-7S3XrOpt6b(8ZKpDMjlCRUi(jCJka0$rK((7wbVO zFkckKQ=G1ZEuT>LmyH_%EGdveZctH67kNr$TB+Pxl0&}absni(^u6o2=SX|I(b3l%6`@Z~D~PfmE|(bf7&2=JiclPZdHf63;^DR9IAR?JbpQTAvUSCHg3>A~G@8$K9yXC_{gF@LYm^T3VDb zLUejLgh5U^&WQ9Ea75O1Qut+zuF5YiGDnJXd-LiDZ=8(xN>4Q?h5Dqc-d8dsZ0RLU zd2jg6ljOQaPB{k}@)L&KU|V)16lS|QXR0rlX2&2_Qn(`s`8*hV-uXx|Dw}qG05$cB zI==rBbY76|9V3Si%b6i5)8QQR+NdqBP1+-!i?56_PTL*YMcttnsXj+)pf+4 zy}b2)_CXoNIiCGeYJO4D>|JCC?4bdmXJG~fkqpIVLcnia9)7Ew!B>>bKSQ>(Wk|l= z7k*lCoglM`62n=`caNt54{3yW+1?6BrR#b5eGh6{YJ{pVxq*J{Olx;Thu#528V3NW zDDSuE0ZOzwxN?3$q8S_-tzJbSKya6DquIcSU`i!pMj8nVGJ~EYZNOe?){v~HQzttU z!9mlH4<*RyRr0>7cjx}{o2YtWhuDc8d)u<4S1|N?bIe=U`4ILsF?dnAg%nO$_f^z} zbz7)vLs5ExKnf>97V|{NZ!AQ9cDjwK`2G*-eD{<2kvw;v=+nk~-nqbkw-shiY@RW_ z1q_?4Vej+z4j076!It9RPO)m}?U2uXKaT;WJN93QUj`5ykNBnbA~{FI^v3;0bG}Cf z8DSIxWtqsp)rC0~1lN`^0fNc$A0XwsFNym#v#wi7ab37`$4ms%M)`Y+=*sw@1QtRW zR{e|a*RGHZ8ElCob6|P5^GEibAdSk4wLSEW6*!f{)#=W^gac{l1giG45 zU0npQa>jw=sgMLWW$KR4~xjk1)tBlbgu+=uMOS;xeNI`o7}3S z!Ag(IK2=bfPwS~-FfQPT7N=iKsgtJ)+gyT`X;XfqgSI3wAZlQ8nUxK2V4s)G%(+yA znL>VZfG9{g747BN>N(vm{_yo@knQ#6bb{@AE=E2}T7Lo>_4+4JFY4Fl9!-3m27PA8 zn#LGK$zsM*T&+47zW4;yh4^q0^}`Xl|Mkad5uIB8F@lzGe}8hfzQWCXlT(Rm1j~rj>q?~uhprXS?B|(A2^WowD9a+C_;{- ztyRC*{m2vJHRSohMflJNeefm`Su{e}4KHz)J|{BON}jjG>g0=^D=}3Qus=VGJkP_; z4;U-#_K3{MoVTV&7dJkkCxG4p0P5Q5W3YXe>5Ml8KQe@8%RkDLnIi?+r4F){h)V04 zcMQFkVo-QL*O07aBJ=r$o?Z@vOBKgOh!+ankvdL61Jjb^VIt-s#!0kD&Amf zU(v$k?-<;$$P0g<^uD&Wm(vw=Hho9PcGB)UsJtSC&_zzvtrhQyU9=K@v3pz|`(J9v z_oedu!L+2Clvg~Nl7EePNEc9rdh{CqjJs0muGEF^__{f2(-l3IifXBvs*rByUspNH zgy?Y}U3`})<(0S60+h_~m%)wyK&EFPmD$Y+rfQ#@cl=x9p-O>y2P~=vLec6|t_mZf4;*3DrWv4Ju@%Ou@%?MW>~v6-iR;I22|lPfWpUG1 z&%hKrn_n>q4pN6SZDa7_Z*_Y-{vz7FoJ>HS`TFVgmeyPNi@TlhG_gvy|EeD zxN-429LKqEwJG&R!l2U=0*>} z_IguJ9nF6?fA8|fi=K<66I>nfwXR43yqnuS4TwZRw?eN7pRW+xIaYC4xXMm zCJT&!o}>{~ndbk?d-UOcqZ|POF)PoCY$Ki5iHYF$z@lqGjNtntGwZ6K@xW~3!sd+( zUkfKPRAm6a(O22Hz{feN_!;HZuyXK3WKun{xvnQ^v*5;(qL?Vdihbu!*OVQTvyVl@ z9r@5+M{pPw$Vj_oghz$9DeK+xWJ#B13?ID#7>renDM6JF zw%MK#yw9ZWhaFP_lfbjh0gJ=@DaSd#MfldyfwvhdQXNchU@TRe)SbW#v&kqkeyZ?= z9w|i5g-RoBCbt~7sbEzGWWrMxQTra-?s{lv9kVM@->gc7B37~bzN+Gk`A=_6S^oT& z9v8LAS}W=n@VZ;@<5uw0m7I%R!D&AP8Ayu&OcPC!0*3gj1CCo<(_uBh(;flM4#l&Z z=7Mo#O-r&qlClkw_snVf<7WzUfk&gSy|crX)Es{^t)GxnWoXAQd$wxExJX_Tu|;xZ z`pmJW1~rsSGU(ZydziBq*rA1Iw^ujike`e^N%YK>X(Pn!+x@SNJ>$d;yBmq73 z6!6EiKT^wSGou~iqi;f}n>=)D7iEg+4mJ{73N7yV`E+Tjdc8#ARh4p4sbaSW9F*+B zpN`Z4%3scVd#*{JdlzB6^MKylAru^fLk{oC=Y2wHay@fEe*gApqEL=+RCA(BD7yP% zS@dLnK37z#dH$ty`cYZ9Af4Of8ZNKr1~;E#$aCw{qJ^9#(-9jcU9=;`iIK@fjrm9A zRewwumE*$GSocVTl!!z1IrlXoYf1mjKVxH*`dnrm;z?)@8bbJ&;^|X$<0!>q!0opM zSy6zx`z=QmSMtz=N>rdDJf}Z`R~=N`b%fPl!C4#S8PPp>uJRE4RIcu66<@pCpa&9! zc`F8ww-H$?bEq03zAdG+nF`J{R%f|(n&mv*tE!tX#r9HxseK_0v~^YFB1q$XZTyaM zy0pl(z8QM+Qy2#-&Sns4{RR9xbO`PB0}*sxTzA@aDP-UNYS5%3 zP(P#BjY7b=l<04I*g<*GDRs{A+2G6fpSbD%4453}E#AC@o7>h&_*2#d`K}By;$5jN zv7>92*$>ECDma9BOto`=<^Y(-UX#rkvieE5RrNCL-3Ew9opTWByC1M;P@)|!z4oLW z^0n3!lG!bFs{+1@ciUxu_VlMiq0ery{5m?le{v2Y#|fz>;L=TERjs>q&KJ1TJ6I;^ zQDE-R*jrI^JidjkdU;>B5|2J0ZH$DPzv_rcin%NQSZp~~jLe>_hUPs^@sjWNB2GR4 zo32=~pI>(gGNZApVZys;f3l>MKrSce-<5JLwp2n7)*Lh2iM3YN@&cz4`nZjMQ?g=1 z81kILH^5-*ea4=WBYQubjK#R>a_0|EUWV;X?0h`u2sD)va%ax2IGlC*!~!E}g6R^8 zztFpuh8StKU3SEYsAX)wP~AFan*$mWscAD3--qvFi~9>~Ij4AF@paO)*SR}wKD&Ds zAnIg8OXsZyq?CION`^~^@Ha7=OQ_Q)@-%EQK9?%DO!31ilqJCWRi_-+STQc7F>BARw_|(}k2kqh{z*r8IQhpW`^3MmZl-gV|sPvPWjK;MU&K zvpib6{6tJ1yvwcToc3tlS0}m(H7AOwIOLH^CS|GWGH>9`gP$ud9l0EM&WZ>93MZyZ0QX z@_pRJ4h%{rfZR_Tn;a*DvA)=iLnR;H1tT82oO2i5PZi+p=GoY&V77tB4S1B_t+&PO zy=DJwxkqjF$81)&iYQ~tG;*apCFHFNFZO_$+!7PVi+0Wl0x;=?2f6E33S@A0<-KP88Hu^u}dQg2fh4>|u^tzughYPtJ|h*!>XM@6DLhuyfPuQ6^s zAd-FcjxP6QhRJysv2Y&*a2XL6<}o3iE;2wzY76_7tELVm9~AptG(k`he_R+q{%>V3 z=J>Hce|lk{5!wD6jm5jk`D2>nRl>Xee>!mrs|p>pECCdyd5Va+;f zzrRS{@e$%GyPed4afv6xeNm9qdWTNNp{vFRW#e?h`&XTmLV(v}(+`{7tQRg(_b63M zRS`rN!{quTRh?!sRc+Iqw)a7*hSP14ral3jmCuu$Szr)t@96%N{r~j8V-B7+n>p>W z)0xu-{=LHCU{@P(&_h4?pke0@Vs0) z^!zB<7i*c^jcM9GQs;*Z_RO zc3X7!_KlmDk6DV>9@l?C6qZQNRxC0v&E=Gk^ z6ZvqEvTe=x8E#e3h!JdmQXsodTFfg4tJ8T!F_b>KE!Xvu8dcIG^j(v`E;(9DA_KMh}dBwCItk z`_AOa2v2FIzQ+kw*p%B|5G*bI(8cSky7G_F?!a(LbwnE|^(8VZ z<@*+1yHY(T+gZ%_{nlkI2ooXa=5T(?sDD0@OHUL8Zw6VDh*Nc+mAFt2m9nKlLXcm5?4xDkGbvTb7@WYli zC%AV0_tHEBIQpNN1=H9c2ID6TWqzQ!LtudSU{~WoDGYKDICW>DB=IY6EHN;Y z@Y^Y*NYmR6GL4;LpEOcAsnGp64mp-3$4!%U{&!`8^2n;*_%B>NexX#vt|rU-u9APK z#?!8+kea~NotJ~pqn@_sCKgSadcq*h44RM-b{2jb*kNx$&MOGE`j4t1hu-zqUdQDS zH@O$S%n;j~m*A$Fk)~wlJpewE2bCg=A$$XhZXg~II-YU$I`-hl8?vi@jD^l{OwRmE z;*;9Pc9|Shq~HhI|2e;5xDfX`Ztl`z#QdZ72`B$bTL~%~DOzF=;|&Tcd%RLkZBs~< zGo9|&A0o0q%NpYn&V9S(@1yR(MJCk=n~&eGgMx!96>DGjcExUgv|71PAl;QK{&7qdS9<6l%K%lN3BcW(YRHJ0i%5sGAU`>ALylN=^I+qTHG zZoSLAn+-<)u(KsJ`ff)SepM|+g@x=6PE-0w7+9LshJ8v-ZG<|AyJ-iMK;e7aSiWkqZ^p|?Nm?B#mM zAysqqE3&G8k5}&p_GLH8taLM!!D%BY#(P{|ZR8uqXf&Q)aAZ|snHnuv$Y7WW^)beH zKR`=!wy^39Iw5cVd0fBSu&m-DQ|c(54b8>Q<&7F{kH$D-@afS9#pO7B`BC!>oQw+T zOmPpr3fG|>H_iZ`1$hrpVoqp+t`9&7hqqZ7vhLai#Fo!6cxS(m4oDpPAQ9y7&1Pb7 zP2(3!oy~hr9>|}MwKqU6NB5>4Ga6VkVLZ%T6eA3P%<~AHde#z&ujhlk8LAgN2Zz!Y zjT*la_6Y&9w%NQ@pCf9H5B(PfA^+Ofx&_|JuvYtD6sEN0{+7zva-F-=64PnNb(a*c zu&4x%)*yWCJh(N6oKTy)DU&b!>_3VZe;G6t+%ZKsqYoB0^CVG5L#>A+w7ItQ4k!Z- zlwvveLu<%+P5<$V(aGwC^doKLH*{>2a|W<<12)0q(K!vC%!`F@FbfWYE5 z4>xk)JJ}I%Rd8ga%g6RPvTf?~vt6bL3RSfU?!zmV^9wb!@tQpKC-<)VAGSoUMLd%K z3*0`PsT^t-g)yCH9+mzziP~w3@r4q+bBuwi(p}}SPb}nGl~k1bxZZS64o-dkPAZpU z8W0FJ7?APL$AIvETmYFsqzQgP9J2CQ4PQx0n>TrdRAzxr-r9ay_;O(_yyJEVSD(g( z&DFsXe(uoU^z9y_*00F6ioe2Mu1ohnSnx9yUW;S}(Pnf4JN-!mI>o8b7v-0D|7Ccw;#=SWwK`9gB|A)q z)`tjul^FNh3mgj;HL*g;{zpb2$ohn|hksDxmpa~hpAqX#Pwkh>%l3c>(m90)+S|%^ zLe+(K9lfd1Z!XQ4V5AtamJ1J+jVs&kGU_M zdtSAM_PZ-e)yA?5(#xbLL`Cit9);S=NZBNibpmnv5cPvs8g2ILW_!ZYoHq+ zVE*{Cg~Q^p<#w>H2(4WH)ZwQvke>WwuZ5ag8=6>A%5fPaR>8*sgwL%3YYnGq9yRl1 z+yv)nM6ZJGWkGL+>}7Y~OoDIDkR+Zr)8Ad&)i1w-d^~6;?_{rXAYqkJ}S`lZ(?R zP@630OVIP&27|?rDNZTyIOF%@{i+_(>HB#Ou0>CZfv?(8agS7=^2<7^j%x!Wq6t~= z-mY%AUVPvuE~%QD{YYHX7<{R*cGx$i#92W3ii}M>IPcJ+CD4-FF;|G$1jlqc9F(F? zQ)Kgy%Z>ZUe^ZDNiuE|RUUWr#u#mpFPW=WMzCkiFf)Co=pd6RGbwR(eHJ$ialq^Ij zgM9c+G$`QpiU9J%8u3^Mv#G{f5Ix92p+g{7ku=Z$-xuK8+7naW>;E&3{w}%~E;r)Q z*8Z$brqiqEO`YQFKWvy`+@1j3rRD|AqiWd1F1voW-M0sqk_e;L&_Nyiw=}!ED-XfN z%tiB-+pjq)2^TRuN;cK*W+RSZrNIwt5n^&ssCS^l?n4JHqvvsoG(V3;j~>hXso|CK zA-55t9}k`Ft3>4e1+q$YCR?P+Fd>{4& z#84|7gq(TG<W_fM$z#I9UzaN81$pO?-G$k{&XXouE ze1cNkpT$v+JwdL*1+w>>errhP1t3TU6^bu`O%zVBVX_vTxbH<>oC=_FGFi9dR32WW zPi?pOqHW|rz&OLW1nF%|&(taE$a-68Au01wbHUw^6P_ecy4K+zbx?e=Olt)#O!pO}=$x3>zL@JaGncD;PrV_!OFJ$t*(IuO+FP zQiv+%--xsq0tMN%X?c*JRk@H;;3`#Y?MB%{c0EWk(}RY=8147`F)JIC|839epUvht zn|jaFa}0$Oqp%hJ7n~%Id1diSHmJesj=P$W*sFAkfPkd|-?5Jq&l2KeS)b3LGm)aW zP%_GJvQf`Vu-Lu#=|I}m1bw%3o&bkLy^jo)sy11!PelPLhvMtR1?pw+Bqj2EiltEd zS0*fA=e`blgYNt)%N^+zC_C2X+0cySgFZ|}W_&nRFLpjudmCUU{hBmdHZCavDNx8x zyK@zQ25$}f9&gVKesHIBs~C#pQ_3bwVMUcS60w!8G#(8R-U`GA7;FF z@eeYywq8rdW{5z}`=yydK+JZ1T{^j7m)0^MwNpJ#KGyF2??LI>p1Z_tENP{Drgbx) zF}u6+#qW24%AKS205;YUdVHTD-+wXSsFPFwCFXH66j6V}%j8@@M#qgW$bQn?=UM|} zVw4WpsXx*`CN44QO`x0%*|`5#7a|7`-r;5YiYiiX#(-OvuTbco!Q+x<4U0}isCpO} z2I1Uj-49vUG(kjrf)*K+wrU4n@b@;m{vdYCTUIwFct^i*)-(D&w#1-1Yi*)w7Eo2V zr~f%ucfZU+YgB+M@w~n-l&{+q87JfWvp2(-o4ey*<9iq9(nqa_5r+v4#OaH3k}e0- z{x(B3SF^18y<)0`eNM&pl;l0iiJFf>Tr`~x3jjDlSBLmg!=z{H?4ubnw7)$0zYDB? zK5DDBeGGZOk?ihNyt>{snmZn*43fRKHr6}tHO@Q#Pz9-;etVJ>UmH&rbNnp%nA1w% zhC)!E1F~??CFdPdaZ^z6-=yAoI#jA=g!AO12xc$e9hifLJb~5XQh0qjeEsS>H|uNu z9Yylz0#v7e9S;6g+FaiF*G0Lwf8Qjv3e{I%{g&^|vv;Ic*Mb})kP}HC#}t(P{V0Mm zLV?bt?ImgF@FCuJ6(0?Xar!TLP}}hmWIl4Vnjj;qjy3+m`1^Q((S=1H!~n~n{BWn4 zO-WpoMdyxxYna*x+@XK-@Qme&(!&f=fQXKI-u*_k$A;MvTo9h57yqh;r0jK31_~K_ z!+fBycxF z)gg-sj>q%;8!h&eG>|Nexe+eLQMTfk^PUf$*_|HQ(GMLUBxhzsT(7kQaE6~V^tAdY zK5~4*x4ZFqR=vXGU)h{|2`RkaeFh!kIIZ-q`=W_`dr9}#lh0`i>cTO!OE<&q$IqoCg1CFjt|Bq|WB;ah zSptW0YinO`SB9t@I>093cdFYZhxKW$=4{(9=>hrGb<1*RQY#aelrym{MDx@S3`8g` z>>B8pzV@(s001kZMa*Af?$?R4uyY}fuDdtdz()fe@BCm32#LOKKi=>`D-MLjJw8 zbR@m)(&sJHgh1)w8mqrmbckjKz!OTTsFi_u+=tEL)`W)njNrH1L(%Sj7{kcxBV4isSh=k&H5 zwEjMU)Sa}Rl#Y6dway-Wwe(9G)Pm}9JMC8}C!lhNhQlxW^_WxABDuDx564A2;Vxk| z6sS6oZ{|C>p3X@eES>ix*Xy&&>59Nh8-I4PWQ=SpVjIzLk1p>h@rO&vIjR8+1J4AiHBRK(+qD@l6JBqdU+>@LvGbhA z=bg+8_Og1t1(P9ru)xW}uT#oTB$iLzq1eONUZjeecAmYam~7dN=ik|`yt}9%4CE!G zg+72WSC5Fp2^D1Ff!f8l5D!N^;j@p3MurCHayh?t(w z2V6W3T0b1(if9yU96ZCET64`Xth;GpM`U(p3zrS{Z+g^ma^=75qoEBwKEL3B;8$^?;%^xB5}6s8q8n-T~oN#r+J-sqoQLxLXiIF*_9-z4vE#>!A)*7v0ZO8CStd-FGM3yI=t zQ|>PqJR30gBSn(CWCd@2fiOVNx`05*FEx$c9x6U5WcB?OPswxwQJb4VDs1PIE*+9; zLp^zXQL01^;-85w%lu`_L#BOFW~D@pOx1|n4Hh_r-=!SEzIYg*nIDVXqF!RHR9Ny1 zjSB6!yIO;n{y?b6J5@jl0NGBn~D3aPqbMmv#EJAv!|52V};{N7fOTV?HhN}fR^{hS5K;1CW#kT zBK=h8QO_~nb4GdqSu`=Qd*jPjpIkSc6PmbW!nrXpmbi*GR~%@(DIr7!aMJH&vA7J}%A2n0j?%&RN^l8X{de}XD`vB4_$=oD@d z%_lt(X!4E(g7}WgS`rDsB#E{eU(HdW6QiDRdYffre+K5GTO?4D#5>=bc}}?L)VZYN z-XIifNk$$WA4whhU0CHBoPu|E^P&Xb4bQlEG)27Fa&Un=JjTU)p7rr2l>qQS4gU?& zknjHSCtRcAN4Q!ga*^D^F~YAKwUq7Tmr6%Jmy#=*H@r<3*jM?K%n;|CY!fUcGNf&M zp6fxP*|7n|fP=EWN|a%);6zjlSD7h@T4~|)=7K2N=O@=eYW2IkPcL7z^BQ-^7zi7w+{7dK89mA1Hm>3ab%YLxJQ`*&);Z2#Ze?-jo>iE z_T#J|TY0FVRT&x2gOHBavE{3!MBmnT+E<@GvS|o{sMIYp_aPiZ&x+$AYxl&Mum6ml zvD-Xt!kN%+>F_qaR_NLx&x((GUI?z{kq%1`WBeGb)F$s&=dR>3p(Saam8j9wuO}Pb zLoEzslF4*#h5m^kp!uYv4gwrOjrA*7Z`WFAl>BDj*$D<`bmOl`&o0H>USoKD3M5?^ zLA0rKy@7e6G(`@k$HFjR_|=r|9s|3yGn&sh+0K*VU+%SLQnA|r5llfdAVaEyqYz%0 zOTGV`7TfZ|cR@jojovbsaXVkZU^U8qFra1=uhiVsj&d}3XHU(9s=*95$(uMBhJ5-y z%fG&nMjYyT>g2R=^Tfy9G{r?TQRF=^plA7}pQ7#F)B8FCKw-hp({{+Q`Mba?BV!44 zokibiIB_HQ5yg+vO%snfue{Ir%&Tq*u(Sv9zUPVnv*AUR1N}?G4XN2jYQd!E6o+?z zeSG4T?uNIM44oT`>ac5WGS95JHCvHDlBZzl_#glxgp{_?_J4{+Mj-OP}H6*~9hVhOKqO ze_s97t9w_&33ykQ_{zhILij$xLyo?)tfG`jJlKxCQ2@sQJMO+di`Qt`BYn(3H;d9I zs~e=#`tFnA89JSOheJH`UZK^&)^s)9_tUg>FN_?Bl5Gb{`MYo5SntsU%EWkF=@qBp ztzq(n9!i9TSr2w?!`DPCvrh;}l=8%S;5k}uc%olhhe3-=Z%4dr@7rrr!!Q902P)@8 zSOWhhcuvZA^UA9c#Y&CyfbxiN=DHfr$Tmwv&FIIYpiF4q>JV0F+=jzX*$g1;J5~@% zrM6VOtSWSWUHXyTI2c#c(Rb!pvw&{`iz`I*)sWn31d1$@-UstX6Z`jl9@de>J*mFP z&gM;f5o=>#lY=u=QtajRzq0gi5l2Kcq#R>7U}TqNo21F{_QlGv!p3ddR9uA5Ze}x3 zVy?%?3Yw6qfbnvtn{G1xbFE7eqsxvAv;S$`9!lV`zC{}xb~;US#2lx)uuGW$l{T)v zYncudq?dzvk)(Nqo%A}lzVi1H^}J~S6pw+Zjsy#J+o)SYL>c_9Mm%6(^XK8;R$ioZ ze#vtK0dloI-ira|066Yc2*Nbr}SdLY7Xz=5wsWkKImHx1_YtqS!DHRl*N*U zPBY$ogs;8yHPZC76Zd=c4G1h9Uf+>{;z*E-B-)#aaNM;obz8rg#2U+POi+s7`AIf1 z@tnxpL5%457yE+{HNePrN-D&>k7p!>7x_Cz5-I$`poRBS(g;>rA9&I#uMNBN^eM^@ zz@2x4Bg7t`mO0%DW(68fqn#s5yBXpNsYRHwh$C!20F!*z3@D8_uNvU*p++WTWoyq( zrqc;ptXrv516VYQCF}36LWcQ=NrZLuu0{F7#4~l_n6hqJf?)r35n)%Rm`X;|IM{m4 zcL){94t?m3ICLZ-3d)Y`X3s5k5*9>rKHU3h51}8R;(~NCrOoc12Kf6}#M)?60)x&A zMv)vRI1=eUF3d&E)Z&C#CSAHW3vRy_z&2JI1XpH^(r?y<_R@i%@NDxc^-aW(SnzP^ z)pan%Yd0Q0H$WwKJcSVcODc9SwIr{_UM0Yi<2{&@TKB{112J;Kf4=Co{|JKzS{zwv z)Yb4oxw2Ycq^rdH#lGY3 z9v=1lVJxpk)20I2vJNms!`nplphYQ4mlE`DJnIo=Pj^8{@pG`1Xu|HK; zFa+Ku6N}G>9qAA4s<|AZ#=JXyp5goc6deiMl{ojk9eWezQO9Iw{&50L<*jrQGf|Ws zxs;w3I=I^4NUPRqh`h+|@TVRnw9MRCEZL9H*GbXJHm0Ql(xgWHPWvsV^(i$=af}Em zF72x>785;ZFXlG02H#?nzDRMASKkz(%aW~=qxtz2E|J=t%I`(_H$lzA)4f3HH5O%83 zV^ifyXG&q#rO$(v%}cVJb2bli-Sm+e_ttbv*>p#O3h)o{Cpb&4J*8Ca6U7O?(g#;} zPUB~Cd_vAS&C4kiS#)bA0>|Y)a3@U`votzQIFKsbIu5=TQKg)KbluP?(IufpDpfT4j z_Z7kqjjjlgr`KXnefi!>v{E&>jf=*8TORy2`X|1!SUx@pV#auWZ~9I;Tv{@n zXi{o3gaeDSh6bghgEFvJsIlGJYtJK^cbOK^4_+3~Q8}sV&Qtm00y|zaF8p=TtLL>7 zcVuUQ;5bw_R|pRN-$f3gj-fWC4{3)Lw4|xQPRSBPsHnwu9dtW{TM3c~{IKGgBqO5T z9r&dXGl6@_Y4?Bb`(33I2N#fZF>Wb_unP4ahxsEP1DcDtM4B!8`+<~I zr?|!kyudtR1V`Si;BF(Uav!0k5@Bi&&Z+jnXkN#k*?Sf}AAd0!;%)D#)DDhAopB9# z(?W+>Q#WX@3Zh-?q-SA(28}`NWkG&*Tn{|GBNU%>vsjL@F!67#2Lo*ebe&$@^s1FW zt&M!)7mrk7)$KF-ril)e%`92v`N~hy<#*qHBp5`|9{16r+XFmS~kw z5>8ey8G-wjJ^f`^|E39WQ__u9hy^P}j<_^`Kr9EqiIagITDO`tHKeg9v5r`ir^Y8x zQeECa!G2EYeUDns1Et(xn~e4ot^Jjx2xJB6kxW+(;NI!+z3?}XbBVOqG6IKyQzFoR zlN>`vt#}zj?t~Le+jK7N?Dyd9PvYsA4vmBsxnvW{B64@mhN}eVj_^)<$8u^2e7`mBf*)Yv`DsCvPI8*MwcnlfgD~Wj`mG9;4N_0ok;!B|AQUHQfAUT*nnhHKls3%? z(%L}37jJ$~B>}i1lCDc9m^8AP5A@njwv$fsa&!@9YK=y@Nf zBIeWGg=>O(Bq9WR(FO3w#1lLN_jGLxL5D3pn01KM(lC7HknZORuQ)BG<%>VlG<%Cw zlq!mqq;=0yrchju>BK8TQc0Oup}UyipeqD6R{?1;2P;zbzm@?Fg`AeMdsp-C%$J(D zY<;9dl;Ybl6GxfP$c42QR(Jl%LKdI(?^W7tQg7fcsw9n*VoI6RcJ9D@550zy$m(u^hAG#!J^hgq?7fu! z-UHc(TohP2^Wh-4+2H_9K)ZE*p70EQ2Bs>`hqVVj2QNO#4U@Q3o?h0xT!fZ8fm`65 z<8?_u941VVbIX?;yG@P|>b0O%ry4qNHcdVxcZRe4d}6^1Eda$UhAMi41A#^>N=knjjrJ}+ zCVC(4Jv%^=e*=3sw|F6v?8Dc$6!;F4(Zq7{Np`t8u^qEk#;@`5zl1)WY15FB?T1jnx@GquTWQk)fKTH0UAX12zzN%!w0(m*}Bnj`Fwf=$E zHLNG(ZxuT1he30WArXjUEATU%a89E+c?yT+4a2fe&OAdk@=h5qcakm7or}MIktE`- zIUcae`JsAuBnX0bfpk#yz`)BZ0*x(qdb($E6TS3s$Ry$+G@gB^K6u^%?E#l_DoArd zK=qZ$Zd_bj*}r#2NX1xrs+0|_fXr0bo6O6|H0YxLUOCmu-Jv&a(ORf#ICtiY-mM+M z%Mhg{3BU%J-amhulv4DP@9=-H0BO=Tp92nVgr(rL%_BI_jDk`J81W4u;e#ThQ>{=I zn3UJiqoG!_zIy0)sf($j37A-nPDmwZSA*w5^OL`~!mTcJQ3rgS)O@WP7?!Dpp|J;#C;=0*zo75KaJ zJf*!wtmZ-umXZVznX}vkD>EJjiGx<3vh9R;z29t;)bo(thMgKDgz$z0>#Fn1 z;wpKQ@MKi}LRV0$hscp2_DRW)!%iRUh~V+!Lw+ARayeN_nu>aswp1ES^Q1NCu85LJ z!iEJBUOx2%!LXb^jc(F$4G^_CvW?Mu4+M%nLVEVHNtAj|yq{^agF9ajd?0}&D1i(* zsc%TVyDeR~XR&$yEez7eVdF>hiyVP}0L3hBpF|pei1c7Y`wq2yg=1ibrL**Fmh-kP z=*zcQJ=HVWs6&fe$2&Sk$WNUE-TfI1>jMv_YRp5`)(5Jr{4CnpaSt zJ5wY&3Ut~)LK4SmnM!*I8%59O>IJ)xkrnPg#zWk6z}OOHJP&@t?j*(bwucbIaGF7@ zfWf(iXEO0s`n$LI63ERH-+@E8oyytV>LD`^$M;Bpj?1bNs&QM6D;cQh*t+47 z)oR)j<^Y?lK6`2O#j^34mY^$-t@F=>em|DW`FV?F?#+fSp7b2xQ3?gRxf@au>H?1N zZkICq?V71rtF{r8*Mqa?YBcOHd%~wkg81Eo2<>#XLf*sgGlbx+h0!JF!S^Sy0J?|d z5l+n4q0S2R{iF`f+3{Mr-mCzk2-dx3a{1rtslO9zoakz{(6X(-APO{ODR@Gu1@tu| z(>kR5UByM6^4z}%;^dSRN;{lCI57^{og`4B8{P)&u8FA}ebvf5x!*3{Y;rqa7j|To zlN{t>{9fTJU6~N$_EYG3iAWg8h+Tu}4z|_9xIbwf{=D=HjIW#yCM2eClw31|x|JHQ zE+tA;vw&32xD2>=&|t~=R?eY5^h%x_hS9zoRjGa^U;3vqF{!eA?31Z{i=b?S2LD76 z%3+4tX46rfdcd2f;$N5zX11+1{btzAceyoj zvXia}GQ^Jp@-mLju$xMNL~;od7X9wsBWOX20*8mWCfYeE$-)m(A>q`K*H#$CmTH+z z_1T~K`LpaF2}!|$Jujf&Zy?j$EK+Xkk^p|;h%SbYRKV*YR=1aC)7BQ}TNFV_HD=(P zvyg?8K-uZL$z;jjw{wg`GZ)AcJgZmG?&GeCKIs`LAXN*DO?-cu<=TdXdJ}K_$*g_I>Kux zKcf}TEC%DOr(SWtG;H7tqSj+5_lG?=P6j@rXKVUISm7F1^??!3u`4cYgQFQQu?j&_ zV9(0y7~VQy#BThjFoAp+I-`rX0l-AxhsuTb`)&Qy;58V5IM7ArtAvEUBUbuCY^Jxv zH+DtUo7>JHmi_54cT4QHVh`ei__RmvJMZw2IFdUc#Qcs7M3~!1itM3D`Nq|nyQclc zKKsfB1&w{smS?vW-dyYeVsU$uz?_9L<{h6?R^?U`%Eu^R8WHH*^Rmk_Ld&PTn>H3> zaV~EsUfXD}Wc}=x#eqNvaHRWME!lD3mN0K-|n29mTq2 z@Z;!dapwWH+giS(VZi}%?!;CMOc9B%rnT?xTP90O?)A%7C|`(C$E5a3MojxLNIHo7 zJObu9L#IFP-%S+#(f{%+i_?&M$$65}*dfKjNO%&T2@T@X%+a^h5=(9d;`B#8*|jZ@ z?96YGe7y_8F6n2hn_U_XTyK&YmwWwQ+CrqIteN;kD1?mRtMDVsn0reY>9ysHHs^&! z>uIFQVRsdQ&~pNqAtcYb`j*0@UCZ)tqa>5)$?dnr=sJ4qwge zO0@Dgx64C{0U%TjBGc!ZL^RWF^Um4yHW&)p)j(Y3>KXnhH6ImI#6(nm*N3U9;ZgP* zC>z@Z@$p)R^Ff>_@|HpQ`>r1&2R(~f-XhKk0T366a9IsB zU>J~J%q%OZ?Arimb|QveH`?HsMp}iF(AEzrU>aBRCB`r53j5;opbq6p+|-NuDWnc5+?!+1iwlS3Bu4>Yc27s}~yJtXvKbOfZ-K zG0@;)C$5pWwymHh_mUtF%(uI|(Pjl~qe9TaU}qKYdnd${hz0Yia<<;PH|Qka6U-Ul z-T<+yi-wEPuww9!Lc(6&gQ#qO#2! zh(2_z{I+=^-hh3mw$);0SbNX4)}T(@n$7uX%044v`UXR6TAJ?%Jt%{R`Q~wTCwmKL z^(%;$T^Jp=__7J1z|FIbkZHMe_RE{l^}43HGwj!Aqa@-j-*j|E1rvpwwL7R@VDeni zTna86Ut{l#o0Pkd^!=&STk!0GS{VVh2r3EX7e%QDlIJzZ;zX5NkB`@N6kZ~8R^hAm zoy9<+)V0l}>qGhh{t?PeC@?8(e^hg^n=>@5ux@oCrCc?}cG8^;wtkU{0&4*Z^#WfkT8)*fl-H0_nG`0|16MN(f%L!F|z{D#Xo75n;p zT9gkJT^pw?4T$na^QUr!kv7bY?FAY0=p{$GYh#$}!bkLzmsB^uS?aKKX*#@of7-J) zW&SYwmH&??L4gVLn0foduK^b|K6(!Za0xz3Omtl!xCyvM=j8H=(;~$EfZaHh+5%}1 zq)O1`)BV=qJAALUH$ac`s*;#X1~(<*5vn4lqU$m*t@9W!7WYil+IrqTegOYcwEdbT zG;e%S4R_9pW6jI3*a|TRe7b`?sf7Qg6$Ud5Fn+d%I#cb{JEd45xq>PP==jI#JbG$ zk>dVGCV57WdZ8HqzHtU}?7&tj*p)Pi70Th^*f%)CKCMSSaO7Wr_0+scw=z z86=k1;3TU&bS)Zgy?#vqVc0+TST}Fv*eH|THUOaK@1GY7-h|bp#0{?S`>7YwuJQmxvVAoACO-9Gb?hkwSXrX<1=-3D)V!!lIu+oOFn* zdevW%1=`AlaG!{33n-2$>JebI4F2xI8WYh5BxI7?_Eo%2fI^180JXpy2dEv-21@>o z-3c^9n9+O-s`gldJr>fR|HLA%1Z)4j9w}Z}Y#H$!_Sfr({>R}>;Vn(JBktb_@XTsz z0jjhs_^h}@qbJ9?$|MVF0bPEyuzfpH2S8)bLw@7ifI8TwhGyx`(rl<8a98$`R!VTr zk`6f=eBpBI@`18QLocPK?#w;Gxt871@!-%oV>8OILv04TrWC9cgJ#apBrME{Vx6b9 z3uBS4IBaJa8}IJX`Xx;c9%`@WG_DrN8C*fKyv6&)`3s>@ z);n8vrhSmC>qMsBi1Q*_5EO8s0>eI0-rvChRqa1~D#F3p7qR@6tZsgkpNHvZd#v!8 zae-ewrJXp#5r0l{B%^6ANk<=+w-i@P_ZiKWj|q0<)%&BBqy4^f@i{4RYQXp3Cx~s1 zhSM?|i|i3&FX1J*Om)N7EeXS4EzAq6h661YBDyv4sA+n98yN|3); z)CbpEaRDk2;qA5gN}KorDwMf>L(qV4lX~#H7Gl^ZxDAdE;z8z5I_+YuNg5Z3rTw10 zOEbW}`E#Mu?nFNsX)i;_JGHO#$9qUO>YZPk!_YRPu5SDMc{nlhsTz<0BvLdMWs?Y( zJ6LRu2w5H-E#bM`Gxe{X{XVuR=yi)7$XvP06}nG{E^-qaIa7qPD)BPM3Ha`M_r8ew zbi4#B6hC1s_TRRtFrOWB<8TT= z72Rzpb1Ry8(Tuakw%h=d(U%{W@_GV9_M-UC2M|JD6zEuUM?1-fs=&>X%GMulg`au% zGY3Y~OcRz9@5sn=mWpZrvg1|V3MoW(SPg!chy3y_`>lO~g^9zrukL#&R_y1J|7t;x z_EZ<=frg9-fc0YbjvLQ~3#V|j7ntt5Ht1h>r9+1gs2{K)I?3THW?50FQnNH6LjXK$ zVyVQfvbMQcG+%0O7T1F0B!loC-Px+z(%Omz3YtoeMd8bKM4TDV&Y64Iap#GmS8DuV zEn}qyK0nbSdq$WX?a_p9Hxmg4-S8wY1gz&H$?I{e$|?REUA^>FM{gR{JdQ1D*Z3LH z4RgitPNhI-{v0gi4lx|O(MKhNy}*ESnbeoevWuWtAZU8&T=6zKk>ITN;);U7;Z{d3 zpI}0}G8j#U5p_(Rs1j~poEmEb zo>QI)h2pYg-(IZTA9%jU3QxhR%8V9GLAfSLDEt4gyw;M~AQ4QFcWBC670}s&mcO>% zN#m$2{R$yk*oOhVXw;$D0FazbRk0)*ymxk=5pOR}Wjg7k=4U?Y`<2%K|Flt^oJ~;z z-KHR5fHM|rL z_UrkAam#E7+W^|;gNI;$T8CxG(JsR4UZ&PqsVyRIq%YxHSlrd9o%nn)Bii+v8*9Zl z8HQ3(BX+j*1$YxUQ%N^8mWO&f%{A2YG#~+|;359F$AHs2UuJ2A=ZXpkK6gz1)`J{1 z>_xJ@d>^o^XM=L-ZKW*RY00YphF|?1(iI258FZxK8u?U!$wQ)(o?NDbSh@?c)iq+I zKys2#|3~6n%ChEof5g(0PlE1E4p>K~tX@RVBIa4_1aU`C%q@8rY1@(KBTEa#+L3tW zdhLQKI5`CCkn;M&gwstUH}T=fuq!;nK$a5G?Jey?>#NR}$EYf^1%S@H)=aTrxOKsZ zP_fV5yT7IsB+lOm_9%}P)=Od@a|a0{JfmDco)le&D-sBkF~C{goZFnq3zJk0$y#N; zS!vMnB~R~e+_g|g{MCJBmY|Ny`O0QY>zXxddl0Aw<-Fr}F-rF~smmYEPin`j4Rig0 zw&=f-XhCOm^c^UbP-Gh1PR0dkY)t13w?6G-xTFz)f$h3rasj5tv<~93@pq8mgo(g9 zEM03eaU<CO_J&pIBheHbQak|wORc2R*JQmr2_)R&I9N+ z3v6z0F!;N+Z})bp6+Dd+Ex0%*h>pXK#d;^_Jkxe)h`?iuiJA zL6cJ)kk&7{?O^A6?oZD89J#9&Ml1^^~@l0%VOGMe5gtEkmh|GUH2p(TD16u zx4+F^?z%yf4TT#zrmfJIQx}Zd+nMX^LI%Xxyq9l%Lvxv1BNYv#@$z&%)?Zf+1F=V2byH#S}ix_C)HPJ?yLC9+v)X z>#<9gN^JqZ3~smF;L7%io&#Vqq$rXu_HN{Ba8U{|^#B&sE!SR{D3%h`Wxg4?8M5l{ z{wa{FtiF=N-jxAqA6s@#Kj=xnAK*)AfLS#E%s6z*ll=doX*R)z(H#R<=d9 z);Z||=JGhx$R@`pM{Moqjhgx0*Mp~JrUZZaMlS*_ z8hL$kCXI&REj{50oN5J@*a%^ldv+ENQK%D%_{c&-1ZYDR#A7XP-GTG^`r` zDEx~5OUjEOOZfFIjO>l!mja1);=($#!$^u}D88c?awxkPK3F#%3P`tig3e#?q8)4B+{YIY&M6=BVB&GY+@y zP=uw3w7%=@AW;^zamj39*i*)rOOhNfm06x)kpU7_VEmQtRq2Q>(uwb7*7L4t;~VM> zlORc5b)|+IX83C(zmB`cF-(SL*K;gB*ud)~K7)OZm*YSj>6NBFBT7^)>61#0zx>Or zJnI`}rf{>;%~=ln55mP&I0X~W34GI7TN;7g8Gr9*xCXbq8v5)3P0M3jfGkQGxUH7N zpjH7h6bu{hwU1U*gY_Zo20lsPmNIoan$MXx1iz}7+iLdn6-snOXxVRc^_gDON+?Du zM3yv>=l!FcIHL}p=V;yLcdMMLkh&h7p?hsySG@p z7lOyeOr>oHvs1^%)gmJ)DMCH`u&Bk5*>_);Fesqal8sSfY4_x8q*LhX zL#3lV)?|&Z6JdHNS-CK==Y=!JX+qY|1<1uO&KRf0j4WnH#>YL4i5A@~jVwnyO)xO8 zaLNi-S69^Hmx8#Gi``MM9Q~bBZhS^4TkZX}OHt7S(icDG{ij~BlpMKm#G!_R@TEtW z@thJ+DuBEK%ZhgP`n~b!?HXV*UaY~fqV_;;DY1#dbb4OR_Jap5kv(Q$KN3xEo9*s^ zT2f%??%B`KBVN?E9N{^3{v>d_yE6O)J0TQ&f_v*S~s@988vig?TS0PW@#G+;dFa%K)o%KN0+yV4ZWh z9Bo?7G~L)Qt!$UMTu#OWlGBYYMV=i`)k-N`ft=}kk9v)jmWX_%<-CS@KU@R(f0dkDgZ5PLGa z*z>Yw*~>JG>X>xxATurCk%Rs$F*2^u23J2de!PSE;(b*cKl*!YYROnI>nRpJX!7An zkzi~I^Qyf2W688!5=R_l#-)h4U4A?i|B+4_KirfnI{Ns3umE_uuSb(pwz;Ps-Tr&I zVd(RJ8yvsSI@-OO;dFA%(q?}$gg7}}!Jap|M~jVhynH@cR7BKcg~W#6$tS8fHPht1GHINO*Ql1% z2i4e)pm(n+?i~$z9L&dw|GnoIBuFLt+Sa9`X1w0l%l@I(v#(KR=Kh(QG3N=re<^Qe z`2U<^&CC+3l|K`CCN=kI&W!0vskwKYkHW>Z>QX*d(I(~>@|To~o+H%t(&vZAJ9A&W zFFNsD4Nk`W^-4t=w6c9_D#7|A6tQYpiOaa6BM#F!g%y zZlxcV6-k`ow2C0<*xhuZI(2TnOYwLt3M!omuWSmsEkmuRJCw#;g15YpP&xmC`cL@~mDb>Yt$_usn9bgnPaix(JI}UeS=Dp{(g8a++3hMN((kpKv+={Uur=qlt3U0D^C3N~cXzYq zu{L~)(`P?zqethAY_l3|$7%WP8D;ku|J3i#h&htVkg6dcO$x+evUUAYZ?IGElGBe9 zlj$0!Xpc9xiR`AGG;9KvIcvi2w683=zBIB3@E~NzG*-Fq*i9Z<4uTG8nqoB7C#9I21T7E+x+0tg{X*GEW`fu zKRLU4TVS8lY~I#<_eEw=Mb8lj?t@PDz!SQluM<6V6VW1b3|6Mst+3`XA|~IyPIXG~ zkvNx0Sh$&(Og|^X%;N=mVi`{dJIt9Lc;7fPvV5XYBtUSDh+R%*5>w0uqwMkj+ajUf zotb|oJ0v6BZ$I=PeqSSrApsAFHzqv)klidJcMxeUTK&9-6&mTWTod`^izmvm^OK0j z8fqq~exKi1Z{6Y559@gY865HSU+KafY#L+3xl^}mOThlhazcN5X+*yQdFzL|Hwzq! z0;7=>f~I2aL)}G=jh+v!MKivYNDI)iz={jY<-;j=xC4y%cw5_UNQ;NLVRYn`k~n+e zilNbo_cmuEFNpobPtKND*p*Jr`p=UK$7{t3{(Mdni9qLnUdpZ8GWXaRwaaYX+G@^? zMCVJGHd{<>Ju7TU%QcxZoc&IB%CwM@`?7Ybc*@DsfoKr~q%a@gH69Ro0lP5uhUy;> z)ksR5^sf`pj?x6z4v2w2DU+#O5U&t1@u0b_$$KVD#>;kDKrmyG^2KDkbl?Na8Ct8L z+dmow>Nm|1;JZNNDCDh3J#=L%5jD0~?Um9NXcpt{Tr4eBn|pdN<#e({$oyt#B=nk$ zoxP*u);q(YB>|r-w#9*LVG}pdDTVO%O^|9A~?f$~8uCDH&sQc4|D6|TW<{uF)M$uWhYxMQ2 zt|;AB(^aCoMD43@nmkfV@Go@df~|kcrNADxReHC4kM5C#Gx()r2D3qsWX|%h^@QU>K5cZ~mXv?7$vJ*A z+OT@Y2dIdy7<#b^LKfDDLY7(YrC3*{2v5)gQb{2O)O0QSiZ=1L!-gzwW1~nWupY>I z)!7`sohkYU(pF#ohEYDAevP>&8(E+Y8ciI%|Hu*gR*gedI&S3vfb?>LQsDIm(ymqD ziNxFm|7*PzQcD^K8|QJV1<=Pa0~gKpt$&-F{#}}YLwPf+Rm|EpOXn@K|^Q zB!%<%hE+D?r{LYXOi0Np#lmj5AdFw+;6m5a4 zKQpFbs!$^+1+1SmKJrD3(RaFeF;Isxli_ZwjWqwD2a-Oi_k|wjYvP5Rt#)fLjW%?@ znI*$t1WwShfQz?^5(5|Yp3D}4ZvSmuY6FyMy@)C5q0=t)QUJGV@(&rvO$w3jcWA-S zkw_Go(rClY-z4D^E!}k7;gqT5O4C*|y;|GvIj>SCNJ(Ch5Dd`f|Nx zy~f@u`b$NLh!m-+eoX>W$?DKzr53ZVvvB!|Qw?Zmw37SS-u91>@PGT(l$eg2H!^V? z@I)TdTFnrif!#xeo-Tm0?DIqg^n3pEL*MgJ^r?zMESUke?nWv%G2!;kX=k*SNcXHt zgHaNveVGX8cWu&IIYG^hJiVnof%VezHqzXwsuwY}!6wM#i@VOEZW=M}S;HIeIn@}V z87|TU)pUhgpvmgyDC!5^{*4S2>~geL{@2r=O6&7Wdr!CpbT@N_?QvGQw_UQUC3VaH z+Zgrt+IajZk-y4$9CRE4y2lIz{{-Z-N)2FX;rxscbkOXn(?P%aeTgb`L5pLL9$Y3b zII1EEt{CI4H(oYCXbhQ=g|d2R=l}gkFVa1ry6_s5VEs-|9>MKbBmZ|!h>?_?uhFEp zBe?*M>Qn4aczyJ0IAsofFeVZ79f_&H{ncHexlsM6XyKF95RbM6ead1@y*61kwP&SR zdg+?wW5!_8h;uQOf+0(-ik6*bfy~TIK@J*Dr(&<5h$)AK_zca}$xsUU$qd>gP6^@v zyR`Y(c`vy95;@F&^^2o}Lo<^%qm|HEq)->VdRbDx`PBjgzpnk?&+^j0lK~tLFYpRrB#A>HY_G@n6!f;o(*6nN?Ujym zw{5u2T=%nN;KxhRo-j%mYo|fDF*#PU+uNy4_Lf@GW@+&pa{_1i`@Y?`yVtFlSRdH2 zYFdeOyQ5vKBPTN9=ng_wEZJV1?9o56LeLqUZ8^4}0@%EGyZ?&wYJ&l+~CR?{zYAmKl?|w=kvpOP~(5`{}f!tKV=(mF1DASG@*0{-Z)MRVC@)dYqh4t z-Z2sVgx4JJj0*P?q^mAWoL9_DrIr6F_Vof;G8Xyos0VC(rBaNkUR{vxPKTV(=lyM# ze*Rz-GNpMUf2#+QC43SRgmenivRXb%7?|_w3@e0f&VnMZ&-$P8^C9y7ynOu9GV*?1 zEtN3%2whlYKXNqouZx{Jr>kTauAU2^S57|oUK;Og)$i-|5Y&e9|Kc3HB<$bmmYC79 z8rOD7f0kDln@{7zDgPwMNRg3@;<%w@P7aHSv641V9T`Q!e7&5F!|5_+s-v7OGE`00 z9FS`Hcl;2E2FE*D;4w2B{KuA}2~p(zx@yA;JVoM8@m{=BoruPCcWl!FD_aCQsoq_# zX7OiID3dXY1>~eJs1hVAos0{ok$Rd!umE#>nW`WPcJ*=H_$U;*i zB~FOwx!gcg3P2QgGkOVAZhC)vyUcN3MQMAR6IH{^6N8fRx*uQsC+j<%RQZLN)eITW zJru05<@c7Vu~!GG+ItOUIz`v>qFM=5p8)983JsQeQEb|oFAjfMz5YiDfTY)yv<=SE z`{-$O(<%8^Ne8}oxdLWAOHB$2uZnx#i3qgCv&$O~NU(=pTVS=0w6OTr(_XQCJWuMZ z4hmb!Kf^Wgr`hq267wuQlw1zy&F$mD-=5j@#{HhG7_SXKAHCIb_sG6bOOaeRvtR10 zk!W|L&9=dr+0@pUgsDlOi;oGYk{E7t0Ssm_QomYAkEvXKt|@(sQ|SH~D=;-fPCXt{ zIp1E^!+cO}vsvOPX9sy3GejIAm`u%(ef6iyTD_#s?(EI*`l3h=QWY6X^=EjJ{xLGw< zH)B9hoDPQBr>cSF*s1M#T*+Lj%6a+%tjKG<NdvkA7T{2(}hGU6nmYs;@Y z28%r>8B6-kqw7nk_*6Y0Q1#-*1Gk&WfQK?Q$5Ol2%$L&iUgaR^=(ir0arzzQz|p%ebaMxcJN1RY_!*PprlZ|RBc z-qx`e5;gI2@KE%b69_1~jH=FQ_`4b`0Bwa9X&1O1| zV2NA}L~B+?P;zuM_b9IXkBhP$gqr&!;#Zx+3%4h7sxzCR_cp`c)GK=&

@=gbjTg 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 bC@kn+fJ)5z$JXA%F^sO8U#rq}dHjC>+@-I& literal 65044 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 diff --git a/mods/modchooser/chrome.yaml b/mods/modchooser/chrome.yaml index 632e84ca8a..cea14509ba 100644 --- a/mods/modchooser/chrome.yaml +++ b/mods/modchooser/chrome.yaml @@ -31,6 +31,17 @@ panel-thinborder: chrome.png corner-bl: 1,573,2,2 corner-br: 61,573,2,2 +panel-thinborder-light: chrome.png + background: 643,515,58,58 + border-r: 701,515,2,58 + border-l: 641,515,2,58 + border-b: 643,573,58,2 + border-t: 643,513,58,2 + corner-tl: 641,513,2,2 + corner-tr: 701,513,2,2 + corner-bl: 641,573,2,2 + corner-br: 701,573,2,2 + button: chrome.png background: 138,522,44,44 border-r: 182,522,10,44 @@ -53,19 +64,9 @@ button-hover: chrome.png corner-bl: 192,566,10,10 corner-br: 246,566,10,10 -# Copy of button button-disabled: chrome.png - background: 138,522,44,44 - border-r: 182,522,10,44 - border-l: 128,522,10,44 - border-b: 138,566,44,10 - border-t: 138,512,44,10 - corner-tl: 128,512,10,10 - corner-tr: 182,512,10,10 - corner-bl: 128,566,10,10 - corner-br: 182,566,10,10 + Inherits: button -# Copy of button-highlighted-hover button-pressed: chrome.png background: 330,522,44,44 border-r: 374,522,10,44 @@ -89,40 +90,42 @@ button-highlighted: chrome.png corner-br: 310,566,10,10 button-highlighted-hover: chrome.png - background: 330,522,44,44 - border-r: 374,522,10,44 - border-l: 320,522,10,44 - border-b: 330,566,44,10 - border-t: 330,512,44,10 - corner-tl: 320,512,10,10 - corner-tr: 374,512,10,10 - corner-bl: 320,566,10,10 - corner-br: 374,566,10,10 + Inherits: button-pressed -# Copy of button-mod-highlighted-hover button-highlighted-pressed: chrome.png - background: 330,522,44,44 - border-r: 374,522,10,44 - border-l: 320,522,10,44 - border-b: 330,566,44,10 - border-t: 330,512,44,10 - corner-tl: 320,512,10,10 - corner-tr: 374,512,10,10 - corner-bl: 320,566,10,10 - corner-br: 374,566,10,10 + Inherits: button-pressed - -# Copy of button-mod-highlighted button-highlighted-disabled: chrome.png - background: 266,522,44,44 - border-r: 310,522,10,44 - border-l: 256,522,10,44 - border-b: 266,566,44,10 - border-t: 266,512,44,10 - corner-tl: 256,512,10,10 - corner-tr: 310,512,10,10 - corner-bl: 256,566,10,10 - corner-br: 310,566,10,10 + Inherits: button-highlighted + +button-highlighted-thin: chrome.png + background: 522,522,44,44 + border-r: 566,522,10,44 + border-l: 512,522,10,44 + border-b: 522,566,44,10 + border-t: 522,512,44,10 + corner-tl: 512,512,10,10 + corner-tr: 566,512,10,10 + corner-bl: 512,566,10,10 + corner-br: 566,566,10,10 + +button-highlighted-thin-hover: chrome.png + Inherits: button-highlighted-thin-pressed + +button-highlighted-thin-pressed: chrome.png + background: 586,522,44,44 + border-r: 630,522,10,44 + border-l: 576,522,10,44 + border-b: 586,566,44,10 + border-t: 586,512,44,10 + corner-tl: 576,512,10,10 + corner-tr: 630,512,10,10 + corner-bl: 576,566,10,10 + corner-br: 630,566,10,10 + +button-highlighted-thin-disabled: chrome.png + Inherits: button-highlighted-thin + progressbar-bg: chrome.png background: 453,565,56,6 @@ -155,4 +158,26 @@ background: chrome.png modchooser: chrome.png logo: 0,576,280,128 leftarrow:384,512,20,64 - rightarrow:404,512,20,64 \ No newline at end of file + rightarrow:404,512,20,64 + cdicon: 448,512,20,20 + +scrollpanel-bg: chrome.png + Inherits: panel-thinborder + +scrollpanel-button: chrome.png + Inherits: panel-thinborder + +scrollpanel-button-hover: chrome.png + Inherits: panel-thinborder-light + +scrollpanel-button-disabled: chrome.png + Inherits: panel-thinborder + +scrollpanel-button-pressed: chrome.png + Inherits: panel-thinborder-light + +scrollbar: chrome.png + down_arrow: 480,512,16,16 + down_pressed: 480,512,16,16 + up_arrow: 480,528,16,16 + up_pressed: 480,528,16,16 diff --git a/mods/modchooser/content.yaml b/mods/modchooser/content.yaml new file mode 100644 index 0000000000..541b713e8b --- /dev/null +++ b/mods/modchooser/content.yaml @@ -0,0 +1,370 @@ +Background@CONTENT_PANEL: + Logic: ModContentLogic + X: (WINDOW_RIGHT - WIDTH)/2 + Y: (WINDOW_BOTTOM - HEIGHT)/2 + Width: 500 + Height: 268 + Background: panel-bg + Children: + Background@RULE: + X: 30 + Y: 50 + Width: 440 + Height:150 + Background:panel-rule + Label@TITLE: + X: 0 + Y: 12 + Width: PARENT_RIGHT + Height: 25 + Text: Manage Content + Align: Center + Font: MediumBold + Label@HEADER_TEMPLATE: + Y: 65 + Width: PARENT_RIGHT + Height: 16 + Align: Center + ScrollPanel@PACKAGES: + X: 30 + Y: 84 + Width: PARENT_RIGHT - 60 + Height: 115 + TopBottomSpacing: 4 + ItemSpacing: 2 + BorderWidth: 2 + Children: + Container@PACKAGE_TEMPLATE: + X: 6 + Width: PARENT_RIGHT - 16 + Height: 23 + Children: + Label@TITLE: + Width: 275 + Height: 23 + Label@REQUIRED: + X: 185 + Y: 0-2 + Width: 90 + Height: 23 + Align: Center + Font: Bold + TextColor: CC0000 + Text: Required + Image@DISC: + X: 275 + Y: 1 + Width: 20 + Height: 20 + ImageCollection: modchooser + ImageName: cdicon + TooltipContainer: TOOLTIP_CONTAINER + TooltipTemplate: DISC_TOOLTIP + Button@DOWNLOAD: + X: 304 + Y: 0 + Width: 100 + Height: 23 + Background: button-highlighted-thin + Text: Download + Label@INSTALLED: + X: 304 + Y: 0-2 + Width: 100 + Height: 23 + Align: Center + Font: Bold + TextColor: 00CC00 + Text: Installed + Label@REQUIRES_DISC: + X: 304 + Y: 0-2 + Width: 100 + Height: 23 + Align: Center + Font: Bold + TextColor: DDDDDD + Text: Requires Disc + Button@CHECK_DISC_BUTTON: + X: 30 + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 110 + Height: 32 + Text: Detect Disc + Font: Bold + Button@BACK_BUTTON: + X: PARENT_RIGHT - 140 + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 110 + Height: 32 + Text: Back + Font: Bold + Key: escape + TooltipContainer@TOOLTIP_CONTAINER: + +Background@DISC_TOOLTIP: + Logic: ModContentDiscTooltipLogic + Background: panel-thinborder + Height: 25 + Children: + Label@DESCRIPTION: + X: 5 + Height: 23 + Font: Bold + Text: Content available from: + Container@DISCS: + Y: 15 + Width: PARENT_RIGHT - 10 + Height: 7 # used as bottom margin + Children: + Label@DISC_TEMPLATE: + X: 20 + Height: 14 + Font: TinyBold + +Container@PACKAGE_DOWNLOAD_PANEL: + Logic: DownloadPackageLogic + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 + Width: 500 + Height: 177 + Children: + Background: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Background: panel-bg + Background@RULE: + X: 30 + Y: 50 + Width: 440 + Height: 150 + Background: panel-rule + Label@TITLE: + X: 0 + Y: 12 + Width: PARENT_RIGHT + Height: 25 + Align: Center + Font: MediumBold + ProgressBar@PROGRESS_BAR: + X: 30 + Y: 64 + Width: PARENT_RIGHT - 60 + Height: 16 + BarMargin: 0, 0 + Label@STATUS_LABEL: + X: 30 + Y: 85 + Width: PARENT_RIGHT - 60 + Height: 25 + Align: Left + Button@RETRY_BUTTON: + X: 30 + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 120 + Height: 32 + Visible: false + Text: Retry + Font: Bold + Key: return + Button@CANCEL_BUTTON: + X: PARENT_RIGHT - 30 - WIDTH + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 110 + Height: 32 + Text: Cancel + Font: Bold + Key: escape + +Background@DISC_INSTALL_PANEL: + Logic: InstallFromDiscLogic + X: (WINDOW_RIGHT - WIDTH)/2 + Y: (WINDOW_BOTTOM - HEIGHT)/2 + Width: 500 + Height: 177 + Background: panel-bg + Children: + Background@RULE: + X: 30 + Y: 50 + Width: 440 + Height:150 + Background:panel-rule + Label@TITLE: + Y: 12 + Width: PARENT_RIGHT + Height: 25 + Align: Center + Font: MediumBold + Container@PROGRESS: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Visible: false + Children: + ProgressBar@PROGRESS_BAR: + X: 30 + Y: 60 + Width: PARENT_RIGHT - 60 + Height: 16 + BarMargin: 0, 0 + Label@PROGRESS_MESSAGE: + X: 30 + Y: 80 + Width: PARENT_RIGHT - 60 + Height: 25 + Align: Left + Container@MESSAGE: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Height: 157 + Visible: false + Children: + Label@MESSAGE_MESSAGE: + Y: 65 + Width: PARENT_RIGHT + Height: 25 + Align: Center + Container@LIST: + Width: PARENT_RIGHT + Height: 268 + Visible: false + Children: + Label@LIST_MESSAGE: + Y: 65 + Width: PARENT_RIGHT + Height: 16 + Align: Center + ScrollPanel@LIST_PANEL: + X: 30 + Y: 99 + Width: PARENT_RIGHT - 60 + Height: 100 + TopBottomSpacing: 4 + ItemSpacing: 2 + BorderWidth: 2 + Children: + Label@LIST_TEMPLATE: + X: 6 + Width: PARENT_RIGHT - 16 + Height: 23 + Button@PRIMARY_BUTTON: + X: 30 + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 110 + Height: 32 + Font: Bold + Key: return + Button@SECONDARY_BUTTON: + X: PARENT_RIGHT - 140 + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 110 + Height: 32 + Font: Bold + Key: escape + +Background@CONTENT_PROMPT_PANEL: + Logic: ModContentPromptLogic + X: (WINDOW_RIGHT - WIDTH)/2 + Y: (WINDOW_BOTTOM - HEIGHT)/2 + Width: 500 + Height: 140 + Background: panel-bg + Children: + Background@RULE: + X: 30 + Y: 50 + Width: 440 + Height:150 + Background:panel-rule + Label@TITLE: + X: 0 + Y: 12 + Width: PARENT_RIGHT + Height: 25 + Text: Install Content + Align: Center + Font: MediumBold + Label@HEADER_TEMPLATE: + Y: 65 + Width: PARENT_RIGHT + Height: 16 + Align: Center + Button@ADVANCED_BUTTON: + X: 30 + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 140 + Height: 32 + Text: Advanced Install + Font: Bold + Button@QUICK_BUTTON: + X: 185 + Y: PARENT_BOTTOM - 52 + Background: button-highlighted + Width: 110 + Height: 32 + Text: Quick Install + Font: Bold + Button@BACK_BUTTON: + X: PARENT_RIGHT - WIDTH - 30 + Y: PARENT_BOTTOM - 52 + Background:button-highlighted + Width: 110 + Height: 32 + Text: Back + Font: Bold + Key: escape + +Container@INSTALL_MOD_PANEL: + Logic: InstallModLogic + X: (WINDOW_RIGHT - WIDTH)/2 + Y: (WINDOW_BOTTOM - HEIGHT)/2 + Width: 500 + Height: 177 + Children: + Background: + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Background: panel-bg + Background@RULE: + X: 30 + Y: 50 + Width: 440 + Height: 150 + Background: panel-rule + Label@TITLE: + X: 0 + Y: 12 + Width: PARENT_RIGHT + Height: 25 + Text: Missing dependencies + Align: Center + Font: MediumBold + Label@DESC: + X: 0 + Y: 65 + Width: PARENT_RIGHT + Height: 25 + Align: Center + Text: Please fully install the following mods then try again: + Label@MOD_LIST: + X: 0 + Y: 85 + Width: PARENT_RIGHT + Height: 25 + Align: Center + Button@BACK_BUTTON: + X: PARENT_RIGHT - 130 + Y: PARENT_BOTTOM - 52 + Background: button-highlighted + Width: 110 + Height: 32 + Text: Back + Font: Bold + Key: escape diff --git a/mods/modchooser/install.yaml b/mods/modchooser/install.yaml index 92921272d2..7f8d32093d 100644 --- a/mods/modchooser/install.yaml +++ b/mods/modchooser/install.yaml @@ -260,50 +260,3 @@ Container@INSTALL_MUSIC_PANEL: Text: Back Font: Bold Key: escape -Container@INSTALL_MOD_PANEL: - Logic: InstallModLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 500 - Height: 177 - Children: - Background: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Background: panel-bg - Background@RULE: - X: 30 - Y: 50 - Width: 440 - Height: 150 - Background: panel-rule - Label@TITLE: - X: 0 - Y: 12 - Width: PARENT_RIGHT - Height: 25 - Text: Missing dependencies - Align: Center - Font: MediumBold - Label@DESC: - X: 0 - Y: 65 - Width: PARENT_RIGHT - Height: 25 - Align: Center - Text: Please fully install the following mods then try again: - Label@MOD_LIST: - X: 0 - Y: 85 - Width: PARENT_RIGHT - Height: 25 - Align: Center - Button@BACK_BUTTON: - X: PARENT_RIGHT - 130 - Y: PARENT_BOTTOM - 52 - Background: button-highlighted - Width: 110 - Height: 32 - Text: Back - Font: Bold - Key: escape diff --git a/mods/modchooser/mod.yaml b/mods/modchooser/mod.yaml index 96ce3e0d00..b18a2cdd6c 100644 --- a/mods/modchooser/mod.yaml +++ b/mods/modchooser/mod.yaml @@ -23,6 +23,7 @@ Assemblies: ChromeLayout: modchooser|modchooser.yaml modchooser|install.yaml + modchooser|content.yaml Notifications: modchooser|notifications.yaml diff --git a/mods/modchooser/modchooser.yaml b/mods/modchooser/modchooser.yaml index a4d83bc54e..c52557ead6 100644 --- a/mods/modchooser/modchooser.yaml +++ b/mods/modchooser/modchooser.yaml @@ -78,34 +78,34 @@ Background@MODCHOOSER_DIALOG: ImageCollection:modchooser ImageName:rightarrow Background@RULE: - X:53 + X:30 Y:PARENT_BOTTOM - 249 - Width:PARENT_RIGHT-106 + Width:PARENT_RIGHT-30 Height:150 Background:panel-rule Label@MOD_TITLE: - X:PARENT_RIGHT - 53 - 140 - 170 + X:PARENT_RIGHT - 400 Y:PARENT_BOTTOM-220 Align:Left Font:Bold Label@MOD_AUTHOR: - X:PARENT_RIGHT - 53 - 140 - 170 + X:PARENT_RIGHT - 400 Y:PARENT_BOTTOM-205 Align:Left Font:TinyBold Label@MOD_VERSION: - X:PARENT_RIGHT - 53 - 140 - 170 + X:PARENT_RIGHT - 400 Y:PARENT_BOTTOM-192 Align:Left Font:Tiny Label@MOD_DESC: - X:PARENT_RIGHT - 53 - 140 - 170 + X:PARENT_RIGHT - 400 Y:PARENT_BOTTOM-175 Align:Left VAlign:Top Font:Tiny Background@PREVIEW: - X:53 + X:30 Y:PARENT_BOTTOM - 25 - HEIGHT Width:300 Height:200 @@ -120,20 +120,27 @@ Background@MODCHOOSER_DIALOG: X:2 Y:2 Button@LOAD_BUTTON: + X:PARENT_RIGHT - 300 - WIDTH + Y:PARENT_BOTTOM - 25 - HEIGHT + Width:100 + Height:32 + Text:Play Background:button-highlighted Key:return - X:PARENT_RIGHT - 53 - WIDTH - 170 + Button@CONFIGURE_BUTTON: + X:PARENT_RIGHT - 145 - WIDTH Y:PARENT_BOTTOM - 25 - HEIGHT Width:140 Height:32 - Text:Load Mod - Button@QUIT_BUTTON: + Text:Manage Content Background:button-highlighted - X:PARENT_RIGHT - 53 - WIDTH + Button@QUIT_BUTTON: + X:PARENT_RIGHT - 30 - WIDTH Y:PARENT_BOTTOM - 25 - HEIGHT - Width:140 + Width:100 Height:32 Text:Quit + Background:button-highlighted Background@DIALOG_HEADER: Width:PARENT_RIGHT Height:72 @@ -157,6 +164,6 @@ Background@BUTTON_TOOLTIP: Height:23 Font:Bold Label@HOTKEY: - TextColor:255,255,0 + TextColor:FFFF00 Height:23 Font:Bold \ No newline at end of file From 009bdf98e6e156e9db44496d8912d22e85300196 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 00:39:48 +0100 Subject: [PATCH 08/14] Add new content installer metadata to TD. --- mods/cnc/mod.yaml | 166 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 153 insertions(+), 13 deletions(-) diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 6ef4201c25..721e30dd2d 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -24,6 +24,7 @@ Packages: ~movies.mix ~scores.mix ~scores2.mix + ~scores-covertops.mix ~transit.mix cnc|bits/snow.mix cnc|bits @@ -143,19 +144,6 @@ LoadScreen: CncLoadScreen Image: cnc|uibits/chrome.png Text: Loading -ContentInstaller: - TestFiles: ^Content/cnc/conquer.mix, ^Content/cnc/desert.mix, ^Content/cnc/sounds.mix, ^Content/cnc/speech.mix, ^Content/cnc/temperat.mix, ^Content/cnc/tempicnh.mix, ^Content/cnc/winter.mix - PackageMirrorList: http://www.openra.net/packages/cnc-mirrors.txt - DiskTestFiles: conquer.mix, desert.mix, install/setup.z - PackageToExtractFromCD: install/setup.z - ExtractFilesFromCD: - .: C&C95\SPEECH.MIX, C&C95\TEMPICNH.MIX, C&C95\TRANSIT.MIX - CopyFilesFromCD: - .: conquer.mix, desert.mix, general.mix, scores.mix, sounds.mix, temperat.mix, winter.mix - ShippedSoundtracks: 4 - MusicPackageMirrorList: http://www.openra.net/packages/cnc-music-mirrors.txt - InstallShieldCABFileIds: 66, 45, 42, 65, 68, 67, 71, 47, 49, 60, 75, 73, 53 - ServerTraits: LobbyCommands PlayerPinger @@ -232,3 +220,155 @@ GameSpeeds: OrderLatency: 6 ColorValidator: + +ModContent: + InstallPromptMessage: Tiberian Dawn requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2007 C&C Gold freeware release.\n\nAdvanced Install includes options for downloading the music and for\ncopying the videos and other content from an original game disc. + QuickDownload: basefiles + HeaderMessage: The original game content may be copied from an original game disc,\nor downloaded from an online mirror of the 2007 freeware release. + Packages: + base: Base Game Files + TestFiles: ^Content/cnc/conquer.mix, ^Content/cnc/desert.mix, ^Content/cnc/sounds.mix, ^Content/cnc/speech.mix, ^Content/cnc/temperat.mix, ^Content/cnc/tempicnh.mix, ^Content/cnc/winter.mix + Discs: gdi95, gdi95-linux, nod95, nod95-linux + Required: true + Download: basefiles + music: Base Game Music + TestFiles: ^Content/cnc/scores.mix + Discs: gdi95, gdi95-linux, nod95, nod95-linux + Download: music + movies-gdi: GDI Campaign Briefings + TestFiles: ^Content/cnc/movies-gdi.mix + Discs: gdi95, gdi95-linux + movies-nod: Nod Campaign Briefings + TestFiles: ^Content/cnc/movies-nod.mix + Discs: nod95, nod95-linux + music-covertops: Covert Operations Music + TestFiles: ^Content/cnc/scores-covertops.mix + Discs: covertops, covertops-linux + Downloads: + basefiles: Base Freeware Content + MirrorList: http://www.openra.net/packages/cnc-mirrors.txt + Extract: + ^Content/cnc/conquer.mix: conquer.mix + ^Content/cnc/desert.mix: desert.mix + ^Content/cnc/general.mix: general.mix + ^Content/cnc/sounds.mix: sounds.mix + ^Content/cnc/speech.mix: speech.mix + ^Content/cnc/temperat.mix: temperat.mix + ^Content/cnc/tempicnh.mix: tempicnh.mix + ^Content/cnc/transit.mix: transit.mix + ^Content/cnc/winter.mix: winter.mix + music: Freeware Music + MirrorList: http://www.openra.net/packages/cnc-music-mirrors.txt + Extract: + ^Content/cnc/scores.mix: scores.mix + Discs: + gdi95: C&C Gold (GDI Disc, English) + IDFiles: + DISK.WAV: 8bef9a6687c0fe0afd57c6561df58fa6e64f145d + CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 + Install: + copy: . + ^Content/cnc/conquer.mix: CONQUER.MIX + ^Content/cnc/desert.mix: DESERT.MIX + ^Content/cnc/general.mix: GENERAL.MIX + ^Content/cnc/scores.mix: SCORES.MIX + ^Content/cnc/sounds.mix: SOUNDS.MIX + ^Content/cnc/temperat.mix: TEMPERAT.MIX + ^Content/cnc/winter.mix: WINTER.MIX + ^Content/cnc/movies-gdi.mix: MOVIES.MIX + extract-blast: INSTALL/SETUP.Z + ^Content/cnc/speech.mix: + Offset: 10203213 + Length: 603293 + ^Content/cnc/tempicnh.mix: + Offset: 10925941 + Length: 119096 + ^Content/cnc/transit.mix: + Offset: 11078017 + Length: 3724462 + gdi95-linux: C&C Gold (GDI Disc, English) + IDFiles: + disk.wav: 8bef9a6687c0fe0afd57c6561df58fa6e64f145d + conquer.mix: 833e02a09aae694659eb312d3838367f681d1b30 + Install: + copy: . + ^Content/cnc/conquer.mix: conquer.mix + ^Content/cnc/desert.mix: desert.mix + ^Content/cnc/general.mix: general.mix + ^Content/cnc/scores.mix: scores.mix + ^Content/cnc/sounds.mix: sounds.mix + ^Content/cnc/temperat.mix: temperat.mix + ^Content/cnc/winter.mix: winter.mix + ^Content/cnc/movies-gdi.mix: movies.mix + extract-blast: install/setup.z + ^Content/cnc/speech.mix: + Offset: 10203213 + Length: 603293 + ^Content/cnc/tempicnh.mix: + Offset: 10925941 + Length: 119096 + ^Content/cnc/transit.mix: + Offset: 11078017 + Length: 3724462 + nod95: C&C Gold (Nod Disc, English) + IDFiles: + DISK.WAV: 83a0235525afa5cd6096f2967e3eae032996e38c + CONQUER.MIX: 833e02a09aae694659eb312d3838367f681d1b30 + Install: + copy: . + ^Content/cnc/conquer.mix: CONQUER.MIX + ^Content/cnc/desert.mix: DESERT.MIX + ^Content/cnc/general.mix: GENERAL.MIX + ^Content/cnc/scores.mix: SCORES.MIX + ^Content/cnc/sounds.mix: SOUNDS.MIX + ^Content/cnc/temperat.mix: TEMPERAT.MIX + ^Content/cnc/winter.mix: WINTER.MIX + ^Content/cnc/movies-nod.mix: MOVIES.MIX + extract-blast: INSTALL/SETUP.Z + ^Content/cnc/speech.mix: + Offset: 10203213 + Length: 603293 + ^Content/cnc/tempicnh.mix: + Offset: 10925941 + Length: 119096 + ^Content/cnc/transit.mix: + Offset: 11078017 + Length: 3724462 + nod95-linux: C&C Gold (Nod Disc, English) + IDFiles: + disk.wav: 83a0235525afa5cd6096f2967e3eae032996e38c + conquer.mix: 833e02a09aae694659eb312d3838367f681d1b30 + Install: + copy: . + ^Content/cnc/conquer.mix: conquer.mix + ^Content/cnc/desert.mix: desert.mix + ^Content/cnc/general.mix: general.mix + ^Content/cnc/scores.mix: scores.mix + ^Content/cnc/sounds.mix: sounds.mix + ^Content/cnc/temperat.mix: temperat.mix + ^Content/cnc/winter.mix: winter.mix + ^Content/cnc/movies-nod.mix: movies.mix + extract-blast: install/setup.z + ^Content/cnc/speech.mix: + Offset: 10203213 + Length: 603293 + ^Content/cnc/tempicnh.mix: + Offset: 10925941 + Length: 119096 + ^Content/cnc/transit.mix: + Offset: 11078017 + Length: 3724462 + covertops: Covert Operations Expansion (English) + IDFiles: + GAME/GAME.DAT: be5a6c4c0a581da09e8f34a3bbf7bd17e525085c + CONQUER.MIX: 713b53fa4c188ca9619c6bbeadbfc86513704266 + Install: + copy: . + ^Content/cnc/scores-covertops.mix: SCORES.MIX + covertops-linux: Covert Operations Expansion (English) + IDFiles: + game/game.dat: be5a6c4c0a581da09e8f34a3bbf7bd17e525085c + conquer.mix: 713b53fa4c188ca9619c6bbeadbfc86513704266 + Install: + copy: . + ^Content/cnc/scores-covertops.mix: scores.mix From 6f4d168d9e937447d438b5baee527dbc8f3bcf63 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 18:04:17 +0100 Subject: [PATCH 09/14] Add new content installer metadata to D2k. --- mods/d2k/mod.yaml | 2001 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 1984 insertions(+), 17 deletions(-) diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 293205472d..2047101b7e 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -131,23 +131,7 @@ Translations: LoadScreen: LogoStripeLoadScreen Image: d2k|uibits/loadscreen.png - Text: Filling Crates..., Breeding Sandworms..., Fuelling carryalls..., Deploying harvesters..., Preparing 'thopters..., Summoning mentats... - -ContentInstaller: - OutputFilenameCase: ForceUpper -# TODO: check if DATA.R8 is at 1.03 patch level with 4840 frames - TestFiles: ^Content/d2k/BLOXBASE.R8, ^Content/d2k/BLOXBAT.R8, ^Content/d2k/BLOXBGBS.R8, ^Content/d2k/BLOXICE.R8, ^Content/d2k/BLOXTREE.R8, ^Content/d2k/BLOXWAST.R8, ^Content/d2k/DATA.R8, ^Content/d2k/SOUND.RS, ^Content/d2k/PALETTE.BIN - PackageMirrorList: http://www.openra.net/packages/d2k-103-mirrors.txt - DiskTestFiles: music/ambush.aud, setup/setup.z - PackageToExtractFromCD: setup/setup.z - OverwriteFiles: False - ExtractFilesFromCD: - .: DUNE\Data\GAMESFX\SOUND.RS, DUNE\Data\DATA.R8, DUNE\Data\MOUSE.R8, DUNE\Data\BLOXBASE.R8, DUNE\Data\BLOXBAT.R8, DUNE\Data\BLOXBGBS.R8, DUNE\Data\BLOXICE.R8, DUNE\Data\BLOXTREE.R8, DUNE\Data\BLOXWAST.R8, DUNE\Data\bin\PALETTE.BIN - GAMESFX: DUNE\Data\GAMESFX\A_ECONF1.AUD, DUNE\Data\GAMESFX\A_ECONF2.AUD, DUNE\Data\GAMESFX\A_ECONF3.AUD, DUNE\Data\GAMESFX\A_ESEL1.AUD, DUNE\Data\GAMESFX\A_ESEL2.AUD, DUNE\Data\GAMESFX\A_ESEL3.AUD, DUNE\Data\GAMESFX\A_FCONF1.AUD, DUNE\Data\GAMESFX\A_FCONF2.AUD, DUNE\Data\GAMESFX\A_FCONF3.AUD, DUNE\Data\GAMESFX\A_FCONF4.AUD, DUNE\Data\GAMESFX\A_FSEL1.AUD, DUNE\Data\GAMESFX\A_FSEL2.AUD, DUNE\Data\GAMESFX\A_FSEL3.AUD, DUNE\Data\GAMESFX\A_FSEL4.AUD, DUNE\Data\GAMESFX\AI_1MIN.AUD, DUNE\Data\GAMESFX\AI_2MIN.AUD, DUNE\Data\GAMESFX\AI_3MIN.AUD, DUNE\Data\GAMESFX\AI_4MIN.AUD, DUNE\Data\GAMESFX\AI_5MIN.AUD, DUNE\Data\GAMESFX\AI_ABORT.AUD, DUNE\Data\GAMESFX\AI_ATACK.AUD, DUNE\Data\GAMESFX\AI_BDRDY.AUD, DUNE\Data\GAMESFX\AI_BLOST.AUD, DUNE\Data\GAMESFX\AI_BUILD.AUD, DUNE\Data\GAMESFX\AI_CANCL.AUD, DUNE\Data\GAMESFX\AI_CAPT.AUD, DUNE\Data\GAMESFX\A_ICONF1.AUD, DUNE\Data\GAMESFX\A_ICONF2.AUD, DUNE\Data\GAMESFX\A_ICONF3.AUD, DUNE\Data\GAMESFX\AI_DHRDY.AUD, DUNE\Data\GAMESFX\AI_DPLOY.AUD, DUNE\Data\GAMESFX\AI_ENEMY.AUD, DUNE\Data\GAMESFX\AI_GANEW.AUD, DUNE\Data\GAMESFX\AI_GLOAD.AUD, DUNE\Data\GAMESFX\AI_GSAVE.AUD, DUNE\Data\GAMESFX\AI_GUARD.AUD, DUNE\Data\GAMESFX\AI_HATTK.AUD, DUNE\Data\GAMESFX\AI_HOLD.AUD, DUNE\Data\GAMESFX\AI_LAUNC.AUD, DUNE\Data\GAMESFX\AI_MAP1A.AUD, DUNE\Data\GAMESFX\AI_MAP1B.AUD, DUNE\Data\GAMESFX\AI_MAP1C.AUD, DUNE\Data\GAMESFX\AI_MAP2A.AUD, DUNE\Data\GAMESFX\AI_MAP2B.AUD, DUNE\Data\GAMESFX\AI_MAP2C.AUD, DUNE\Data\GAMESFX\AI_MAP3A.AUD, DUNE\Data\GAMESFX\AI_MAP4A.AUD, DUNE\Data\GAMESFX\AI_MAP5A.AUD, DUNE\Data\GAMESFX\AI_MAP6A.AUD, DUNE\Data\GAMESFX\AI_MAP7A.AUD, DUNE\Data\GAMESFX\AI_MAP8A.AUD, DUNE\Data\GAMESFX\AI_MAP9A.AUD, DUNE\Data\GAMESFX\AI_MEND.AUD, DUNE\Data\GAMESFX\AI_MFAIL.AUD, DUNE\Data\GAMESFX\AI_MONEY.AUD, DUNE\Data\GAMESFX\AI_MWIN.AUD, DUNE\Data\GAMESFX\AI_NEWOP.AUD, DUNE\Data\GAMESFX\AI_NROOM.AUD, DUNE\Data\GAMESFX\AI_ORDER.AUD, DUNE\Data\GAMESFX\AI_PLACE.AUD, DUNE\Data\GAMESFX\AI_POWER.AUD, DUNE\Data\GAMESFX\AI_PREP.AUD, DUNE\Data\GAMESFX\AI_PRMRY.AUD, DUNE\Data\GAMESFX\AI_REINF.AUD, DUNE\Data\GAMESFX\AI_RUN.AUD, DUNE\Data\GAMESFX\A_ISEL1.AUD, DUNE\Data\GAMESFX\A_ISEL2.AUD, DUNE\Data\GAMESFX\A_ISEL3.AUD, DUNE\Data\GAMESFX\AI_SELL.AUD, DUNE\Data\GAMESFX\AI_SILOS.AUD, DUNE\Data\GAMESFX\AI_SPORT.AUD, DUNE\Data\GAMESFX\AI_TRAIN.AUD, DUNE\Data\GAMESFX\AI_ULOST.AUD, DUNE\Data\GAMESFX\AI_UNRDY.AUD, DUNE\Data\GAMESFX\AI_UPGOP.AUD, DUNE\Data\GAMESFX\AI_UPGRD.AUD, DUNE\Data\GAMESFX\AI_WATTK.AUD, DUNE\Data\GAMESFX\AI_WSIGN.AUD, DUNE\Data\GAMESFX\A_VCONF1.AUD, DUNE\Data\GAMESFX\A_VCONF2.AUD, DUNE\Data\GAMESFX\A_VCONF3.AUD, DUNE\Data\GAMESFX\A_VSEL1.AUD, DUNE\Data\GAMESFX\A_VSEL2.AUD, DUNE\Data\GAMESFX\A_VSEL3.AUD, DUNE\Data\GAMESFX\G_SCONF1.AUD, DUNE\Data\GAMESFX\G_SCONF2.AUD, DUNE\Data\GAMESFX\G_SCONF3.AUD, DUNE\Data\GAMESFX\G_SSEL1.AUD, DUNE\Data\GAMESFX\G_SSEL2.AUD, DUNE\Data\GAMESFX\G_SSEL3.AUD, DUNE\Data\GAMESFX\H_ECONF1.AUD, DUNE\Data\GAMESFX\H_ECONF2.AUD, DUNE\Data\GAMESFX\H_ECONF3.AUD, DUNE\Data\GAMESFX\H_ESEL1.AUD, DUNE\Data\GAMESFX\H_ESEL2.AUD, DUNE\Data\GAMESFX\H_ESEL3.AUD, DUNE\Data\GAMESFX\HI_1MIN.AUD, DUNE\Data\GAMESFX\HI_2MIN.AUD, DUNE\Data\GAMESFX\HI_3MIN.AUD, DUNE\Data\GAMESFX\HI_4MIN.AUD, DUNE\Data\GAMESFX\HI_5MIN.AUD, DUNE\Data\GAMESFX\HI_ABORT.AUD, DUNE\Data\GAMESFX\HI_ATACK.AUD, DUNE\Data\GAMESFX\HI_BDRDY.AUD, DUNE\Data\GAMESFX\HI_BLOST.AUD, DUNE\Data\GAMESFX\HI_BUILD.AUD, DUNE\Data\GAMESFX\HI_CANCL.AUD, DUNE\Data\GAMESFX\HI_CAPT.AUD, DUNE\Data\GAMESFX\H_ICONF1.AUD, DUNE\Data\GAMESFX\H_ICONF2.AUD, DUNE\Data\GAMESFX\H_ICONF3.AUD, DUNE\Data\GAMESFX\HI_DHRDY.AUD, DUNE\Data\GAMESFX\HI_DPLOY.AUD, DUNE\Data\GAMESFX\HI_ENEMY.AUD, DUNE\Data\GAMESFX\HI_GANEW.AUD, DUNE\Data\GAMESFX\HI_GLOAD.AUD, DUNE\Data\GAMESFX\HI_GSAVE.AUD, DUNE\Data\GAMESFX\HI_GUARD.AUD, DUNE\Data\GAMESFX\HI_HATTK.AUD, DUNE\Data\GAMESFX\HI_HOLD.AUD, DUNE\Data\GAMESFX\HI_LAUNC.AUD, DUNE\Data\GAMESFX\HI_MAP1A.AUD, DUNE\Data\GAMESFX\HI_MAP1B.AUD, DUNE\Data\GAMESFX\HI_MAP1C.AUD, DUNE\Data\GAMESFX\HI_MAP2A.AUD, DUNE\Data\GAMESFX\HI_MAP2B.AUD, DUNE\Data\GAMESFX\HI_MAP2C.AUD, DUNE\Data\GAMESFX\HI_MAP3A.AUD, DUNE\Data\GAMESFX\HI_MAP3B.AUD, DUNE\Data\GAMESFX\HI_MAP4A.AUD, DUNE\Data\GAMESFX\HI_MAP4B.AUD, DUNE\Data\GAMESFX\HI_MAP5A.AUD, DUNE\Data\GAMESFX\HI_MAP6A.AUD, DUNE\Data\GAMESFX\HI_MAP6B.AUD, DUNE\Data\GAMESFX\HI_MAP7A.AUD, DUNE\Data\GAMESFX\HI_MAP9A.AUD, DUNE\Data\GAMESFX\HI_MAP9.AUD, DUNE\Data\GAMESFX\HI_MEND.AUD, DUNE\Data\GAMESFX\HI_MFAIL.AUD, DUNE\Data\GAMESFX\HI_MONEY.AUD, DUNE\Data\GAMESFX\HI_MWIN.AUD, DUNE\Data\GAMESFX\HI_NEWOP.AUD, DUNE\Data\GAMESFX\HI_NROOM.AUD, DUNE\Data\GAMESFX\HI_ORDER.AUD, DUNE\Data\GAMESFX\HI_PLACE.AUD, DUNE\Data\GAMESFX\HI_POWER.AUD, DUNE\Data\GAMESFX\HI_PREP.AUD, DUNE\Data\GAMESFX\HI_PRMRY.AUD, DUNE\Data\GAMESFX\HI_REINF.AUD, DUNE\Data\GAMESFX\HI_RUN.AUD, DUNE\Data\GAMESFX\H_ISEL1.AUD, DUNE\Data\GAMESFX\H_ISEL2.AUD, DUNE\Data\GAMESFX\H_ISEL3.AUD, DUNE\Data\GAMESFX\HI_SELL.AUD, DUNE\Data\GAMESFX\HI_SILOS.AUD, DUNE\Data\GAMESFX\HI_SPORT.AUD, DUNE\Data\GAMESFX\HI_TRAIN.AUD, DUNE\Data\GAMESFX\HI_ULOST.AUD, DUNE\Data\GAMESFX\HI_UNRDY.AUD, DUNE\Data\GAMESFX\HI_UPGOP.AUD, DUNE\Data\GAMESFX\HI_UPGRD.AUD, DUNE\Data\GAMESFX\HI_WATTK.AUD, DUNE\Data\GAMESFX\HI_WSIGN.AUD, DUNE\Data\GAMESFX\H_VCONF1.AUD, DUNE\Data\GAMESFX\H_VCONF2.AUD, DUNE\Data\GAMESFX\H_VCONF3.AUD, DUNE\Data\GAMESFX\H_VSEL1.AUD, DUNE\Data\GAMESFX\H_VSEL2.AUD, DUNE\Data\GAMESFX\H_VSEL3.AUD, DUNE\Data\GAMESFX\O_ECONF1.AUD, DUNE\Data\GAMESFX\O_ECONF2.AUD, DUNE\Data\GAMESFX\O_ECONF3.AUD, DUNE\Data\GAMESFX\O_ESEL1.AUD, DUNE\Data\GAMESFX\O_ESEL2.AUD, DUNE\Data\GAMESFX\O_ESEL3.AUD, DUNE\Data\GAMESFX\OI_1MIN.AUD, DUNE\Data\GAMESFX\OI_2MIN.AUD, DUNE\Data\GAMESFX\OI_3MIN.AUD, DUNE\Data\GAMESFX\OI_4MIN.AUD, DUNE\Data\GAMESFX\OI_5MIN.AUD, DUNE\Data\GAMESFX\OI_ABORT.AUD, DUNE\Data\GAMESFX\OI_ATACK.AUD, DUNE\Data\GAMESFX\OI_BDRDY.AUD, DUNE\Data\GAMESFX\OI_BLOST.AUD, DUNE\Data\GAMESFX\OI_BUILD.AUD, DUNE\Data\GAMESFX\OI_CANCL.AUD, DUNE\Data\GAMESFX\OI_CAPT.AUD, DUNE\Data\GAMESFX\O_ICONF1.AUD, DUNE\Data\GAMESFX\O_ICONF2.AUD, DUNE\Data\GAMESFX\O_ICONF3.AUD, DUNE\Data\GAMESFX\OI_DHRDY.AUD, DUNE\Data\GAMESFX\OI_DPLOY.AUD, DUNE\Data\GAMESFX\OI_ENEMY.AUD, DUNE\Data\GAMESFX\OI_GANEW.AUD, DUNE\Data\GAMESFX\OI_GLOAD.AUD, DUNE\Data\GAMESFX\OI_GSAVE.AUD, DUNE\Data\GAMESFX\OI_GUARD.AUD, DUNE\Data\GAMESFX\OI_HATTK.AUD, DUNE\Data\GAMESFX\OI_HOLD.AUD, DUNE\Data\GAMESFX\OI_LAUNC.AUD, DUNE\Data\GAMESFX\OI_MAP1A.AUD, DUNE\Data\GAMESFX\OI_MAP1B.AUD, DUNE\Data\GAMESFX\OI_MAP1C.AUD, DUNE\Data\GAMESFX\OI_MAP2A.AUD, DUNE\Data\GAMESFX\OI_MAP2B.AUD, DUNE\Data\GAMESFX\OI_MAP2C.AUD, DUNE\Data\GAMESFX\OI_MAP3A.AUD, DUNE\Data\GAMESFX\OI_MAP4A.AUD, DUNE\Data\GAMESFX\OI_MAP5A.AUD, DUNE\Data\GAMESFX\OI_MAP6A.AUD, DUNE\Data\GAMESFX\OI_MAP7A.AUD, DUNE\Data\GAMESFX\OI_MAP8A.AUD, DUNE\Data\GAMESFX\OI_MAP9A.AUD, DUNE\Data\GAMESFX\OI_MEND.AUD, DUNE\Data\GAMESFX\OI_MFAIL.AUD, DUNE\Data\GAMESFX\OI_MONEY.AUD, DUNE\Data\GAMESFX\OI_MWIN.AUD, DUNE\Data\GAMESFX\OI_NEWOP.AUD, DUNE\Data\GAMESFX\OI_NROOM.AUD, DUNE\Data\GAMESFX\OI_ORDER.AUD, DUNE\Data\GAMESFX\OI_PLACE.AUD, DUNE\Data\GAMESFX\OI_POWER.AUD, DUNE\Data\GAMESFX\OI_PREP.AUD, DUNE\Data\GAMESFX\OI_PRMRY.AUD, DUNE\Data\GAMESFX\OI_REINF.AUD, DUNE\Data\GAMESFX\OI_RUN.AUD, DUNE\Data\GAMESFX\O_ISEL1.AUD, DUNE\Data\GAMESFX\O_ISEL2.AUD, DUNE\Data\GAMESFX\O_ISEL3.AUD, DUNE\Data\GAMESFX\OI_SELL.AUD, DUNE\Data\GAMESFX\OI_SILOS.AUD, DUNE\Data\GAMESFX\OI_SPORT.AUD, DUNE\Data\GAMESFX\OI_TRAIN.AUD, DUNE\Data\GAMESFX\OI_ULOST.AUD, DUNE\Data\GAMESFX\OI_UNRDY.AUD, DUNE\Data\GAMESFX\OI_UPGOP.AUD, DUNE\Data\GAMESFX\OI_UPGRD.AUD, DUNE\Data\GAMESFX\OI_WATTK.AUD, DUNE\Data\GAMESFX\OI_WSIGN.AUD, DUNE\Data\GAMESFX\O_SCONF1.AUD, DUNE\Data\GAMESFX\O_SCONF2.AUD, DUNE\Data\GAMESFX\O_SCONF3.AUD, DUNE\Data\GAMESFX\O_SSEL1.AUD, DUNE\Data\GAMESFX\O_SSEL2.AUD, DUNE\Data\GAMESFX\O_SSEL3.AUD, DUNE\Data\GAMESFX\O_VCONF1.AUD, DUNE\Data\GAMESFX\O_VCONF2.AUD, DUNE\Data\GAMESFX\O_VCONF3.AUD, DUNE\Data\GAMESFX\O_VSEL1.AUD, DUNE\Data\GAMESFX\O_VSEL2.AUD, DUNE\Data\GAMESFX\O_VSEL3.AUD - CopyFilesFromCD: - Movies: movies/a_br01_e.vqa, movies/a_br02_e.vqa, movies/a_br03_e.vqa, movies/a_br04_e.vqa, movies/a_br05_e.vqa, movies/a_br06_e.vqa, movies/a_br07_e.vqa, movies/a_br08_e.vqa, movies/a_br09_e.vqa, movies/a_finl_e.vqa, movies/a_lose_e.vqa, movies/a_mntg_e.vqa, movies/h_br01_e.vqa, movies/h_br02_e.vqa, movies/h_br03_e.vqa, movies/h_br04_e.vqa, movies/h_br05_e.vqa, movies/h_br06_e.vqa, movies/h_br07_e.vqa, movies/h_br08_e.vqa, movies/h_br09_e.vqa, movies/h_finl_e.vqa, movies/h_lose_e.vqa, movies/h_mntg_e.vqa, movies/o_br01_e.vqa, movies/o_br02_e.vqa, movies/o_br03_e.vqa, movies/o_br04_e.vqa, movies/o_br05_e.vqa, movies/o_br06_e.vqa, movies/o_br07_e.vqa, movies/o_br08_e.vqa, movies/o_br09_e.vqa, movies/o_finl_e.vqa, movies/o_lose_e.vqa, movies/o_mntg_e.vqa, movies/g_int1_e.vqa, movies/g_int2_e.vqa, movies/g_maps_e.vqa, movies/g_pln2_e.vqa, movies/g_plnt_e.vqa, movies/t_titl_e.vqa - Music: music/ambush.aud, music/arakatak.aud, music/atregain.aud, music/entordos.aud, music/fightpwr.aud, music/fremen.aud, music/hark_bat.aud, music/landsand.aud, music/options.aud, music/plotting.aud, music/risehark.aud, music/robotix.aud, music/score.aud, music/soldappr.aud, music/spicesct.aud, music/undercon.aud, music/waitgame.aud - ShippedSoundtracks: 1 + Text: Filling Crates..., Breeding Sandworms..., Fuelling carryalls..., Deploying harvesters..., Preparing thopters..., Summoning mentats... ServerTraits: LobbyCommands @@ -215,3 +199,1986 @@ GameSpeeds: OrderLatency: 6 ColorValidator: + +ModContent: + InstallPromptMessage: Dune 2000 requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without\nmusic or videos) from an online mirror of the game files.\n\nAdvanced Install includes options for copying the music, videos,\nand other content from an original game disc. + QuickDownload: basefiles + HeaderMessage: The original game content may be copied from an original game disc,\nor downloaded from an online mirror of the game files. + Packages: + base: Base Game Files + TestFiles: ^Content/d2k/BLOXBASE.R8, ^Content/d2k/BLOXBAT.R8, ^Content/d2k/BLOXBGBS.R8, ^Content/d2k/BLOXICE.R8, ^Content/d2k/BLOXTREE.R8, ^Content/d2k/BLOXWAST.R8, ^Content/d2k/DATA.R8, ^Content/d2k/SOUND.RS, ^Content/d2k/PALETTE.BIN + Discs: d2k, d2k-linux + Required: true + Download: basefiles + music: Game Music + TestFiles: ^Content/d2k/Music/AMBUSH.AUD + Discs: d2k, d2k-linux + movies: Campaign Briefings + TestFiles: ^Content/d2k/Movies/A_BR01_E.VQA + Discs: d2k, d2k-linux + Downloads: + basefiles: Base Content + MirrorList: http://www.openra.net/packages/d2k-103-mirrors.txt + Extract: + ^Content/d2k/BLOXBASE.R8: BLOXBASE.R8 + ^Content/d2k/BLOXBAT.R8: BLOXBAT.R8 + ^Content/d2k/BLOXBGBS.R8: BLOXBGBS.R8 + ^Content/d2k/BLOXICE.R8: BLOXICE.R8 + ^Content/d2k/BLOXTREE.R8: BLOXTREE.R8 + ^Content/d2k/BLOXWAST.R8: BLOXWAST.R8 + ^Content/d2k/DATA.R8: DATA.R8 + ^Content/d2k/MOUSE.R8: MOUSE.R8 + ^Content/d2k/PALETTE.BIN: PALETTE.BIN + ^Content/d2k/SOUND.RS: SOUND.RS + ^Content/d2k/GAMESFX/AI_1MIN.AUD: GAMESFX/AI_1MIN.AUD + ^Content/d2k/GAMESFX/AI_2MIN.AUD: GAMESFX/AI_2MIN.AUD + ^Content/d2k/GAMESFX/AI_3MIN.AUD: GAMESFX/AI_3MIN.AUD + ^Content/d2k/GAMESFX/AI_4MIN.AUD: GAMESFX/AI_4MIN.AUD + ^Content/d2k/GAMESFX/AI_5MIN.AUD: GAMESFX/AI_5MIN.AUD + ^Content/d2k/GAMESFX/AI_ABORT.AUD: GAMESFX/AI_ABORT.AUD + ^Content/d2k/GAMESFX/AI_ATACK.AUD: GAMESFX/AI_ATACK.AUD + ^Content/d2k/GAMESFX/AI_BDRDY.AUD: GAMESFX/AI_BDRDY.AUD + ^Content/d2k/GAMESFX/AI_BLOST.AUD: GAMESFX/AI_BLOST.AUD + ^Content/d2k/GAMESFX/AI_BUILD.AUD: GAMESFX/AI_BUILD.AUD + ^Content/d2k/GAMESFX/AI_CANCL.AUD: GAMESFX/AI_CANCL.AUD + ^Content/d2k/GAMESFX/AI_CAPT.AUD: GAMESFX/AI_CAPT.AUD + ^Content/d2k/GAMESFX/AI_DHRDY.AUD: GAMESFX/AI_DHRDY.AUD + ^Content/d2k/GAMESFX/AI_DPLOY.AUD: GAMESFX/AI_DPLOY.AUD + ^Content/d2k/GAMESFX/AI_ENEMY.AUD: GAMESFX/AI_ENEMY.AUD + ^Content/d2k/GAMESFX/AI_GANEW.AUD: GAMESFX/AI_GANEW.AUD + ^Content/d2k/GAMESFX/AI_GLOAD.AUD: GAMESFX/AI_GLOAD.AUD + ^Content/d2k/GAMESFX/AI_GSAVE.AUD: GAMESFX/AI_GSAVE.AUD + ^Content/d2k/GAMESFX/AI_GUARD.AUD: GAMESFX/AI_GUARD.AUD + ^Content/d2k/GAMESFX/AI_HATTK.AUD: GAMESFX/AI_HATTK.AUD + ^Content/d2k/GAMESFX/AI_HOLD.AUD: GAMESFX/AI_HOLD.AUD + ^Content/d2k/GAMESFX/AI_LAUNC.AUD: GAMESFX/AI_LAUNC.AUD + ^Content/d2k/GAMESFX/AI_MAP1A.AUD: GAMESFX/AI_MAP1A.AUD + ^Content/d2k/GAMESFX/AI_MAP1B.AUD: GAMESFX/AI_MAP1B.AUD + ^Content/d2k/GAMESFX/AI_MAP1C.AUD: GAMESFX/AI_MAP1C.AUD + ^Content/d2k/GAMESFX/AI_MAP2A.AUD: GAMESFX/AI_MAP2A.AUD + ^Content/d2k/GAMESFX/AI_MAP2B.AUD: GAMESFX/AI_MAP2B.AUD + ^Content/d2k/GAMESFX/AI_MAP2C.AUD: GAMESFX/AI_MAP2C.AUD + ^Content/d2k/GAMESFX/AI_MAP3A.AUD: GAMESFX/AI_MAP3A.AUD + ^Content/d2k/GAMESFX/AI_MAP4A.AUD: GAMESFX/AI_MAP4A.AUD + ^Content/d2k/GAMESFX/AI_MAP5A.AUD: GAMESFX/AI_MAP5A.AUD + ^Content/d2k/GAMESFX/AI_MAP6A.AUD: GAMESFX/AI_MAP6A.AUD + ^Content/d2k/GAMESFX/AI_MAP7A.AUD: GAMESFX/AI_MAP7A.AUD + ^Content/d2k/GAMESFX/AI_MAP8A.AUD: GAMESFX/AI_MAP8A.AUD + ^Content/d2k/GAMESFX/AI_MAP9A.AUD: GAMESFX/AI_MAP9A.AUD + ^Content/d2k/GAMESFX/AI_MEND.AUD: GAMESFX/AI_MEND.AUD + ^Content/d2k/GAMESFX/AI_MFAIL.AUD: GAMESFX/AI_MFAIL.AUD + ^Content/d2k/GAMESFX/AI_MONEY.AUD: GAMESFX/AI_MONEY.AUD + ^Content/d2k/GAMESFX/AI_MWIN.AUD: GAMESFX/AI_MWIN.AUD + ^Content/d2k/GAMESFX/AI_NEWOP.AUD: GAMESFX/AI_NEWOP.AUD + ^Content/d2k/GAMESFX/AI_NROOM.AUD: GAMESFX/AI_NROOM.AUD + ^Content/d2k/GAMESFX/AI_ORDER.AUD: GAMESFX/AI_ORDER.AUD + ^Content/d2k/GAMESFX/AI_PLACE.AUD: GAMESFX/AI_PLACE.AUD + ^Content/d2k/GAMESFX/AI_POWER.AUD: GAMESFX/AI_POWER.AUD + ^Content/d2k/GAMESFX/AI_PREP.AUD: GAMESFX/AI_PREP.AUD + ^Content/d2k/GAMESFX/AI_PRMRY.AUD: GAMESFX/AI_PRMRY.AUD + ^Content/d2k/GAMESFX/AI_REINF.AUD: GAMESFX/AI_REINF.AUD + ^Content/d2k/GAMESFX/AI_RUN.AUD: GAMESFX/AI_RUN.AUD + ^Content/d2k/GAMESFX/AI_SELL.AUD: GAMESFX/AI_SELL.AUD + ^Content/d2k/GAMESFX/AI_SILOS.AUD: GAMESFX/AI_SILOS.AUD + ^Content/d2k/GAMESFX/AI_SPORT.AUD: GAMESFX/AI_SPORT.AUD + ^Content/d2k/GAMESFX/AI_TRAIN.AUD: GAMESFX/AI_TRAIN.AUD + ^Content/d2k/GAMESFX/AI_ULOST.AUD: GAMESFX/AI_ULOST.AUD + ^Content/d2k/GAMESFX/AI_UNRDY.AUD: GAMESFX/AI_UNRDY.AUD + ^Content/d2k/GAMESFX/AI_UPGOP.AUD: GAMESFX/AI_UPGOP.AUD + ^Content/d2k/GAMESFX/AI_UPGRD.AUD: GAMESFX/AI_UPGRD.AUD + ^Content/d2k/GAMESFX/AI_WATTK.AUD: GAMESFX/AI_WATTK.AUD + ^Content/d2k/GAMESFX/AI_WSIGN.AUD: GAMESFX/AI_WSIGN.AUD + ^Content/d2k/GAMESFX/A_ECONF1.AUD: GAMESFX/A_ECONF1.AUD + ^Content/d2k/GAMESFX/A_ECONF2.AUD: GAMESFX/A_ECONF2.AUD + ^Content/d2k/GAMESFX/A_ECONF3.AUD: GAMESFX/A_ECONF3.AUD + ^Content/d2k/GAMESFX/A_ESEL1.AUD: GAMESFX/A_ESEL1.AUD + ^Content/d2k/GAMESFX/A_ESEL2.AUD: GAMESFX/A_ESEL2.AUD + ^Content/d2k/GAMESFX/A_ESEL3.AUD: GAMESFX/A_ESEL3.AUD + ^Content/d2k/GAMESFX/A_FCONF1.AUD: GAMESFX/A_FCONF1.AUD + ^Content/d2k/GAMESFX/A_FCONF2.AUD: GAMESFX/A_FCONF2.AUD + ^Content/d2k/GAMESFX/A_FCONF3.AUD: GAMESFX/A_FCONF3.AUD + ^Content/d2k/GAMESFX/A_FCONF4.AUD: GAMESFX/A_FCONF4.AUD + ^Content/d2k/GAMESFX/A_FSEL1.AUD: GAMESFX/A_FSEL1.AUD + ^Content/d2k/GAMESFX/A_FSEL2.AUD: GAMESFX/A_FSEL2.AUD + ^Content/d2k/GAMESFX/A_FSEL3.AUD: GAMESFX/A_FSEL3.AUD + ^Content/d2k/GAMESFX/A_FSEL4.AUD: GAMESFX/A_FSEL4.AUD + ^Content/d2k/GAMESFX/A_ICONF1.AUD: GAMESFX/A_ICONF1.AUD + ^Content/d2k/GAMESFX/A_ICONF2.AUD: GAMESFX/A_ICONF2.AUD + ^Content/d2k/GAMESFX/A_ICONF3.AUD: GAMESFX/A_ICONF3.AUD + ^Content/d2k/GAMESFX/A_ISEL1.AUD: GAMESFX/A_ISEL1.AUD + ^Content/d2k/GAMESFX/A_ISEL2.AUD: GAMESFX/A_ISEL2.AUD + ^Content/d2k/GAMESFX/A_ISEL3.AUD: GAMESFX/A_ISEL3.AUD + ^Content/d2k/GAMESFX/A_VCONF1.AUD: GAMESFX/A_VCONF1.AUD + ^Content/d2k/GAMESFX/A_VCONF2.AUD: GAMESFX/A_VCONF2.AUD + ^Content/d2k/GAMESFX/A_VCONF3.AUD: GAMESFX/A_VCONF3.AUD + ^Content/d2k/GAMESFX/A_VSEL1.AUD: GAMESFX/A_VSEL1.AUD + ^Content/d2k/GAMESFX/A_VSEL2.AUD: GAMESFX/A_VSEL2.AUD + ^Content/d2k/GAMESFX/A_VSEL3.AUD: GAMESFX/A_VSEL3.AUD + ^Content/d2k/GAMESFX/G_SCONF1.AUD: GAMESFX/G_SCONF1.AUD + ^Content/d2k/GAMESFX/G_SCONF2.AUD: GAMESFX/G_SCONF2.AUD + ^Content/d2k/GAMESFX/G_SCONF3.AUD: GAMESFX/G_SCONF3.AUD + ^Content/d2k/GAMESFX/G_SSEL1.AUD: GAMESFX/G_SSEL1.AUD + ^Content/d2k/GAMESFX/G_SSEL2.AUD: GAMESFX/G_SSEL2.AUD + ^Content/d2k/GAMESFX/G_SSEL3.AUD: GAMESFX/G_SSEL3.AUD + ^Content/d2k/GAMESFX/HI_1MIN.AUD: GAMESFX/HI_1MIN.AUD + ^Content/d2k/GAMESFX/HI_2MIN.AUD: GAMESFX/HI_2MIN.AUD + ^Content/d2k/GAMESFX/HI_3MIN.AUD: GAMESFX/HI_3MIN.AUD + ^Content/d2k/GAMESFX/HI_4MIN.AUD: GAMESFX/HI_4MIN.AUD + ^Content/d2k/GAMESFX/HI_5MIN.AUD: GAMESFX/HI_5MIN.AUD + ^Content/d2k/GAMESFX/HI_ABORT.AUD: GAMESFX/HI_ABORT.AUD + ^Content/d2k/GAMESFX/HI_ATACK.AUD: GAMESFX/HI_ATACK.AUD + ^Content/d2k/GAMESFX/HI_BDRDY.AUD: GAMESFX/HI_BDRDY.AUD + ^Content/d2k/GAMESFX/HI_BLOST.AUD: GAMESFX/HI_BLOST.AUD + ^Content/d2k/GAMESFX/HI_BUILD.AUD: GAMESFX/HI_BUILD.AUD + ^Content/d2k/GAMESFX/HI_CANCL.AUD: GAMESFX/HI_CANCL.AUD + ^Content/d2k/GAMESFX/HI_CAPT.AUD: GAMESFX/HI_CAPT.AUD + ^Content/d2k/GAMESFX/HI_DHRDY.AUD: GAMESFX/HI_DHRDY.AUD + ^Content/d2k/GAMESFX/HI_DPLOY.AUD: GAMESFX/HI_DPLOY.AUD + ^Content/d2k/GAMESFX/HI_ENEMY.AUD: GAMESFX/HI_ENEMY.AUD + ^Content/d2k/GAMESFX/HI_GANEW.AUD: GAMESFX/HI_GANEW.AUD + ^Content/d2k/GAMESFX/HI_GLOAD.AUD: GAMESFX/HI_GLOAD.AUD + ^Content/d2k/GAMESFX/HI_GSAVE.AUD: GAMESFX/HI_GSAVE.AUD + ^Content/d2k/GAMESFX/HI_GUARD.AUD: GAMESFX/HI_GUARD.AUD + ^Content/d2k/GAMESFX/HI_HATTK.AUD: GAMESFX/HI_HATTK.AUD + ^Content/d2k/GAMESFX/HI_HOLD.AUD: GAMESFX/HI_HOLD.AUD + ^Content/d2k/GAMESFX/HI_LAUNC.AUD: GAMESFX/HI_LAUNC.AUD + ^Content/d2k/GAMESFX/HI_MAP1A.AUD: GAMESFX/HI_MAP1A.AUD + ^Content/d2k/GAMESFX/HI_MAP1B.AUD: GAMESFX/HI_MAP1B.AUD + ^Content/d2k/GAMESFX/HI_MAP1C.AUD: GAMESFX/HI_MAP1C.AUD + ^Content/d2k/GAMESFX/HI_MAP2A.AUD: GAMESFX/HI_MAP2A.AUD + ^Content/d2k/GAMESFX/HI_MAP2B.AUD: GAMESFX/HI_MAP2B.AUD + ^Content/d2k/GAMESFX/HI_MAP2C.AUD: GAMESFX/HI_MAP2C.AUD + ^Content/d2k/GAMESFX/HI_MAP3A.AUD: GAMESFX/HI_MAP3A.AUD + ^Content/d2k/GAMESFX/HI_MAP3B.AUD: GAMESFX/HI_MAP3B.AUD + ^Content/d2k/GAMESFX/HI_MAP4A.AUD: GAMESFX/HI_MAP4A.AUD + ^Content/d2k/GAMESFX/HI_MAP4B.AUD: GAMESFX/HI_MAP4B.AUD + ^Content/d2k/GAMESFX/HI_MAP5A.AUD: GAMESFX/HI_MAP5A.AUD + ^Content/d2k/GAMESFX/HI_MAP6A.AUD: GAMESFX/HI_MAP6A.AUD + ^Content/d2k/GAMESFX/HI_MAP6B.AUD: GAMESFX/HI_MAP6B.AUD + ^Content/d2k/GAMESFX/HI_MAP7A.AUD: GAMESFX/HI_MAP7A.AUD + ^Content/d2k/GAMESFX/HI_MAP9.AUD: GAMESFX/HI_MAP9.AUD + ^Content/d2k/GAMESFX/HI_MAP9A.AUD: GAMESFX/HI_MAP9A.AUD + ^Content/d2k/GAMESFX/HI_MEND.AUD: GAMESFX/HI_MEND.AUD + ^Content/d2k/GAMESFX/HI_MFAIL.AUD: GAMESFX/HI_MFAIL.AUD + ^Content/d2k/GAMESFX/HI_MONEY.AUD: GAMESFX/HI_MONEY.AUD + ^Content/d2k/GAMESFX/HI_MWIN.AUD: GAMESFX/HI_MWIN.AUD + ^Content/d2k/GAMESFX/HI_NEWOP.AUD: GAMESFX/HI_NEWOP.AUD + ^Content/d2k/GAMESFX/HI_NROOM.AUD: GAMESFX/HI_NROOM.AUD + ^Content/d2k/GAMESFX/HI_ORDER.AUD: GAMESFX/HI_ORDER.AUD + ^Content/d2k/GAMESFX/HI_PLACE.AUD: GAMESFX/HI_PLACE.AUD + ^Content/d2k/GAMESFX/HI_POWER.AUD: GAMESFX/HI_POWER.AUD + ^Content/d2k/GAMESFX/HI_PREP.AUD: GAMESFX/HI_PREP.AUD + ^Content/d2k/GAMESFX/HI_PRMRY.AUD: GAMESFX/HI_PRMRY.AUD + ^Content/d2k/GAMESFX/HI_REINF.AUD: GAMESFX/HI_REINF.AUD + ^Content/d2k/GAMESFX/HI_RUN.AUD: GAMESFX/HI_RUN.AUD + ^Content/d2k/GAMESFX/HI_SELL.AUD: GAMESFX/HI_SELL.AUD + ^Content/d2k/GAMESFX/HI_SILOS.AUD: GAMESFX/HI_SILOS.AUD + ^Content/d2k/GAMESFX/HI_SPORT.AUD: GAMESFX/HI_SPORT.AUD + ^Content/d2k/GAMESFX/HI_TRAIN.AUD: GAMESFX/HI_TRAIN.AUD + ^Content/d2k/GAMESFX/HI_ULOST.AUD: GAMESFX/HI_ULOST.AUD + ^Content/d2k/GAMESFX/HI_UNRDY.AUD: GAMESFX/HI_UNRDY.AUD + ^Content/d2k/GAMESFX/HI_UPGOP.AUD: GAMESFX/HI_UPGOP.AUD + ^Content/d2k/GAMESFX/HI_UPGRD.AUD: GAMESFX/HI_UPGRD.AUD + ^Content/d2k/GAMESFX/HI_WATTK.AUD: GAMESFX/HI_WATTK.AUD + ^Content/d2k/GAMESFX/HI_WSIGN.AUD: GAMESFX/HI_WSIGN.AUD + ^Content/d2k/GAMESFX/H_ECONF1.AUD: GAMESFX/H_ECONF1.AUD + ^Content/d2k/GAMESFX/H_ECONF2.AUD: GAMESFX/H_ECONF2.AUD + ^Content/d2k/GAMESFX/H_ECONF3.AUD: GAMESFX/H_ECONF3.AUD + ^Content/d2k/GAMESFX/H_ESEL1.AUD: GAMESFX/H_ESEL1.AUD + ^Content/d2k/GAMESFX/H_ESEL2.AUD: GAMESFX/H_ESEL2.AUD + ^Content/d2k/GAMESFX/H_ESEL3.AUD: GAMESFX/H_ESEL3.AUD + ^Content/d2k/GAMESFX/H_ICONF1.AUD: GAMESFX/H_ICONF1.AUD + ^Content/d2k/GAMESFX/H_ICONF2.AUD: GAMESFX/H_ICONF2.AUD + ^Content/d2k/GAMESFX/H_ICONF3.AUD: GAMESFX/H_ICONF3.AUD + ^Content/d2k/GAMESFX/H_ISEL1.AUD: GAMESFX/H_ISEL1.AUD + ^Content/d2k/GAMESFX/H_ISEL2.AUD: GAMESFX/H_ISEL2.AUD + ^Content/d2k/GAMESFX/H_ISEL3.AUD: GAMESFX/H_ISEL3.AUD + ^Content/d2k/GAMESFX/H_VCONF1.AUD: GAMESFX/H_VCONF1.AUD + ^Content/d2k/GAMESFX/H_VCONF2.AUD: GAMESFX/H_VCONF2.AUD + ^Content/d2k/GAMESFX/H_VCONF3.AUD: GAMESFX/H_VCONF3.AUD + ^Content/d2k/GAMESFX/H_VSEL1.AUD: GAMESFX/H_VSEL1.AUD + ^Content/d2k/GAMESFX/H_VSEL2.AUD: GAMESFX/H_VSEL2.AUD + ^Content/d2k/GAMESFX/H_VSEL3.AUD: GAMESFX/H_VSEL3.AUD + ^Content/d2k/GAMESFX/OI_1MIN.AUD: GAMESFX/OI_1MIN.AUD + ^Content/d2k/GAMESFX/OI_2MIN.AUD: GAMESFX/OI_2MIN.AUD + ^Content/d2k/GAMESFX/OI_3MIN.AUD: GAMESFX/OI_3MIN.AUD + ^Content/d2k/GAMESFX/OI_4MIN.AUD: GAMESFX/OI_4MIN.AUD + ^Content/d2k/GAMESFX/OI_5MIN.AUD: GAMESFX/OI_5MIN.AUD + ^Content/d2k/GAMESFX/OI_ABORT.AUD: GAMESFX/OI_ABORT.AUD + ^Content/d2k/GAMESFX/OI_ATACK.AUD: GAMESFX/OI_ATACK.AUD + ^Content/d2k/GAMESFX/OI_BDRDY.AUD: GAMESFX/OI_BDRDY.AUD + ^Content/d2k/GAMESFX/OI_BLOST.AUD: GAMESFX/OI_BLOST.AUD + ^Content/d2k/GAMESFX/OI_BUILD.AUD: GAMESFX/OI_BUILD.AUD + ^Content/d2k/GAMESFX/OI_CANCL.AUD: GAMESFX/OI_CANCL.AUD + ^Content/d2k/GAMESFX/OI_CAPT.AUD: GAMESFX/OI_CAPT.AUD + ^Content/d2k/GAMESFX/OI_DHRDY.AUD: GAMESFX/OI_DHRDY.AUD + ^Content/d2k/GAMESFX/OI_DPLOY.AUD: GAMESFX/OI_DPLOY.AUD + ^Content/d2k/GAMESFX/OI_ENEMY.AUD: GAMESFX/OI_ENEMY.AUD + ^Content/d2k/GAMESFX/OI_GANEW.AUD: GAMESFX/OI_GANEW.AUD + ^Content/d2k/GAMESFX/OI_GLOAD.AUD: GAMESFX/OI_GLOAD.AUD + ^Content/d2k/GAMESFX/OI_GSAVE.AUD: GAMESFX/OI_GSAVE.AUD + ^Content/d2k/GAMESFX/OI_GUARD.AUD: GAMESFX/OI_GUARD.AUD + ^Content/d2k/GAMESFX/OI_HATTK.AUD: GAMESFX/OI_HATTK.AUD + ^Content/d2k/GAMESFX/OI_HOLD.AUD: GAMESFX/OI_HOLD.AUD + ^Content/d2k/GAMESFX/OI_LAUNC.AUD: GAMESFX/OI_LAUNC.AUD + ^Content/d2k/GAMESFX/OI_MAP1A.AUD: GAMESFX/OI_MAP1A.AUD + ^Content/d2k/GAMESFX/OI_MAP1B.AUD: GAMESFX/OI_MAP1B.AUD + ^Content/d2k/GAMESFX/OI_MAP1C.AUD: GAMESFX/OI_MAP1C.AUD + ^Content/d2k/GAMESFX/OI_MAP2A.AUD: GAMESFX/OI_MAP2A.AUD + ^Content/d2k/GAMESFX/OI_MAP2B.AUD: GAMESFX/OI_MAP2B.AUD + ^Content/d2k/GAMESFX/OI_MAP2C.AUD: GAMESFX/OI_MAP2C.AUD + ^Content/d2k/GAMESFX/OI_MAP3A.AUD: GAMESFX/OI_MAP3A.AUD + ^Content/d2k/GAMESFX/OI_MAP4A.AUD: GAMESFX/OI_MAP4A.AUD + ^Content/d2k/GAMESFX/OI_MAP5A.AUD: GAMESFX/OI_MAP5A.AUD + ^Content/d2k/GAMESFX/OI_MAP6A.AUD: GAMESFX/OI_MAP6A.AUD + ^Content/d2k/GAMESFX/OI_MAP7A.AUD: GAMESFX/OI_MAP7A.AUD + ^Content/d2k/GAMESFX/OI_MAP8A.AUD: GAMESFX/OI_MAP8A.AUD + ^Content/d2k/GAMESFX/OI_MAP9A.AUD: GAMESFX/OI_MAP9A.AUD + ^Content/d2k/GAMESFX/OI_MEND.AUD: GAMESFX/OI_MEND.AUD + ^Content/d2k/GAMESFX/OI_MFAIL.AUD: GAMESFX/OI_MFAIL.AUD + ^Content/d2k/GAMESFX/OI_MONEY.AUD: GAMESFX/OI_MONEY.AUD + ^Content/d2k/GAMESFX/OI_MWIN.AUD: GAMESFX/OI_MWIN.AUD + ^Content/d2k/GAMESFX/OI_NEWOP.AUD: GAMESFX/OI_NEWOP.AUD + ^Content/d2k/GAMESFX/OI_NROOM.AUD: GAMESFX/OI_NROOM.AUD + ^Content/d2k/GAMESFX/OI_ORDER.AUD: GAMESFX/OI_ORDER.AUD + ^Content/d2k/GAMESFX/OI_PLACE.AUD: GAMESFX/OI_PLACE.AUD + ^Content/d2k/GAMESFX/OI_POWER.AUD: GAMESFX/OI_POWER.AUD + ^Content/d2k/GAMESFX/OI_PREP.AUD: GAMESFX/OI_PREP.AUD + ^Content/d2k/GAMESFX/OI_PRMRY.AUD: GAMESFX/OI_PRMRY.AUD + ^Content/d2k/GAMESFX/OI_REINF.AUD: GAMESFX/OI_REINF.AUD + ^Content/d2k/GAMESFX/OI_RUN.AUD: GAMESFX/OI_RUN.AUD + ^Content/d2k/GAMESFX/OI_SELL.AUD: GAMESFX/OI_SELL.AUD + ^Content/d2k/GAMESFX/OI_SILOS.AUD: GAMESFX/OI_SILOS.AUD + ^Content/d2k/GAMESFX/OI_SPORT.AUD: GAMESFX/OI_SPORT.AUD + ^Content/d2k/GAMESFX/OI_TRAIN.AUD: GAMESFX/OI_TRAIN.AUD + ^Content/d2k/GAMESFX/OI_ULOST.AUD: GAMESFX/OI_ULOST.AUD + ^Content/d2k/GAMESFX/OI_UNRDY.AUD: GAMESFX/OI_UNRDY.AUD + ^Content/d2k/GAMESFX/OI_UPGOP.AUD: GAMESFX/OI_UPGOP.AUD + ^Content/d2k/GAMESFX/OI_UPGRD.AUD: GAMESFX/OI_UPGRD.AUD + ^Content/d2k/GAMESFX/OI_WATTK.AUD: GAMESFX/OI_WATTK.AUD + ^Content/d2k/GAMESFX/OI_WSIGN.AUD: GAMESFX/OI_WSIGN.AUD + ^Content/d2k/GAMESFX/O_ECONF1.AUD: GAMESFX/O_ECONF1.AUD + ^Content/d2k/GAMESFX/O_ECONF2.AUD: GAMESFX/O_ECONF2.AUD + ^Content/d2k/GAMESFX/O_ECONF3.AUD: GAMESFX/O_ECONF3.AUD + ^Content/d2k/GAMESFX/O_ESEL1.AUD: GAMESFX/O_ESEL1.AUD + ^Content/d2k/GAMESFX/O_ESEL2.AUD: GAMESFX/O_ESEL2.AUD + ^Content/d2k/GAMESFX/O_ESEL3.AUD: GAMESFX/O_ESEL3.AUD + ^Content/d2k/GAMESFX/O_ICONF1.AUD: GAMESFX/O_ICONF1.AUD + ^Content/d2k/GAMESFX/O_ICONF2.AUD: GAMESFX/O_ICONF2.AUD + ^Content/d2k/GAMESFX/O_ICONF3.AUD: GAMESFX/O_ICONF3.AUD + ^Content/d2k/GAMESFX/O_ISEL1.AUD: GAMESFX/O_ISEL1.AUD + ^Content/d2k/GAMESFX/O_ISEL2.AUD: GAMESFX/O_ISEL2.AUD + ^Content/d2k/GAMESFX/O_ISEL3.AUD: GAMESFX/O_ISEL3.AUD + ^Content/d2k/GAMESFX/O_SCONF1.AUD: GAMESFX/O_SCONF1.AUD + ^Content/d2k/GAMESFX/O_SCONF2.AUD: GAMESFX/O_SCONF2.AUD + ^Content/d2k/GAMESFX/O_SCONF3.AUD: GAMESFX/O_SCONF3.AUD + ^Content/d2k/GAMESFX/O_SSEL1.AUD: GAMESFX/O_SSEL1.AUD + ^Content/d2k/GAMESFX/O_SSEL2.AUD: GAMESFX/O_SSEL2.AUD + ^Content/d2k/GAMESFX/O_SSEL3.AUD: GAMESFX/O_SSEL3.AUD + ^Content/d2k/GAMESFX/O_VCONF1.AUD: GAMESFX/O_VCONF1.AUD + ^Content/d2k/GAMESFX/O_VCONF2.AUD: GAMESFX/O_VCONF2.AUD + ^Content/d2k/GAMESFX/O_VCONF3.AUD: GAMESFX/O_VCONF3.AUD + ^Content/d2k/GAMESFX/O_VSEL1.AUD: GAMESFX/O_VSEL1.AUD + ^Content/d2k/GAMESFX/O_VSEL2.AUD: GAMESFX/O_VSEL2.AUD + ^Content/d2k/GAMESFX/O_VSEL3.AUD: GAMESFX/O_VSEL3.AUD + Discs: + d2k: Dune 2000 (English) + IDFiles: + MUSIC/AMBUSH.AUD: bd5926a56a83bc0e49f96037e1f909014ac0772a + SETUP/SETUP.Z: 937f5ceb1236bf3f3d4e43929305ffe5004078e7 + Install: + copy: MOVIES + ^Content/d2k/Movies/A_BR01_E.VQA: A_BR01_E.VQA + ^Content/d2k/Movies/A_BR02_E.VQA: A_BR02_E.VQA + ^Content/d2k/Movies/A_BR03_E.VQA: A_BR03_E.VQA + ^Content/d2k/Movies/A_BR04_E.VQA: A_BR04_E.VQA + ^Content/d2k/Movies/A_BR05_E.VQA: A_BR05_E.VQA + ^Content/d2k/Movies/A_BR06_E.VQA: A_BR06_E.VQA + ^Content/d2k/Movies/A_BR07_E.VQA: A_BR07_E.VQA + ^Content/d2k/Movies/A_BR08_E.VQA: A_BR08_E.VQA + ^Content/d2k/Movies/A_BR09_E.VQA: A_BR09_E.VQA + ^Content/d2k/Movies/A_FINL_E.VQA: A_FINL_E.VQA + ^Content/d2k/Movies/A_LOSE_E.VQA: A_LOSE_E.VQA + ^Content/d2k/Movies/A_MNTG_E.VQA: A_MNTG_E.VQA + ^Content/d2k/Movies/H_BR01_E.VQA: H_BR01_E.VQA + ^Content/d2k/Movies/H_BR02_E.VQA: H_BR02_E.VQA + ^Content/d2k/Movies/H_BR03_E.VQA: H_BR03_E.VQA + ^Content/d2k/Movies/H_BR04_E.VQA: H_BR04_E.VQA + ^Content/d2k/Movies/H_BR05_E.VQA: H_BR05_E.VQA + ^Content/d2k/Movies/H_BR06_E.VQA: H_BR06_E.VQA + ^Content/d2k/Movies/H_BR07_E.VQA: H_BR07_E.VQA + ^Content/d2k/Movies/H_BR08_E.VQA: H_BR08_E.VQA + ^Content/d2k/Movies/H_BR09_E.VQA: H_BR09_E.VQA + ^Content/d2k/Movies/H_FINL_E.VQA: H_FINL_E.VQA + ^Content/d2k/Movies/H_LOSE_E.VQA: H_LOSE_E.VQA + ^Content/d2k/Movies/H_MNTG_E.VQA: H_MNTG_E.VQA + ^Content/d2k/Movies/O_BR01_E.VQA: O_BR01_E.VQA + ^Content/d2k/Movies/O_BR02_E.VQA: O_BR02_E.VQA + ^Content/d2k/Movies/O_BR03_E.VQA: O_BR03_E.VQA + ^Content/d2k/Movies/O_BR04_E.VQA: O_BR04_E.VQA + ^Content/d2k/Movies/O_BR05_E.VQA: O_BR05_E.VQA + ^Content/d2k/Movies/O_BR06_E.VQA: O_BR06_E.VQA + ^Content/d2k/Movies/O_BR07_E.VQA: O_BR07_E.VQA + ^Content/d2k/Movies/O_BR08_E.VQA: O_BR08_E.VQA + ^Content/d2k/Movies/O_BR09_E.VQA: O_BR09_E.VQA + ^Content/d2k/Movies/O_FINL_E.VQA: O_FINL_E.VQA + ^Content/d2k/Movies/O_LOSE_E.VQA: O_LOSE_E.VQA + ^Content/d2k/Movies/O_MNTG_E.VQA: O_MNTG_E.VQA + ^Content/d2k/Movies/G_INT1_E.VQA: G_INT1_E.VQA + ^Content/d2k/Movies/G_INT2_E.VQA: G_INT2_E.VQA + ^Content/d2k/Movies/G_MAPS_E.VQA: G_MAPS_E.VQA + ^Content/d2k/Movies/G_PLN2_E.VQA: G_PLN2_E.VQA + ^Content/d2k/Movies/G_PLNT_E.VQA: G_PLNT_E.VQA + ^Content/d2k/Movies/T_TITL_E.VQA: T_TITL_E.VQA + copy: MUSIC + ^Content/d2k/Music/AMBUSH.AUD: AMBUSH.AUD + ^Content/d2k/Music/ARAKATAK.AUD: ARAKATAK.AUD + ^Content/d2k/Music/ATREGAIN.AUD: ATREGAIN.AUD + ^Content/d2k/Music/ENTORDOS.AUD: ENTORDOS.AUD + ^Content/d2k/Music/FIGHTPWR.AUD: FIGHTPWR.AUD + ^Content/d2k/Music/FREMEN.AUD: FREMEN.AUD + ^Content/d2k/Music/HARK_BAT.AUD: HARK_BAT.AUD + ^Content/d2k/Music/LANDSAND.AUD: LANDSAND.AUD + ^Content/d2k/Music/OPTIONS.AUD: OPTIONS.AUD + ^Content/d2k/Music/PLOTTING.AUD: PLOTTING.AUD + ^Content/d2k/Music/RISEHARK.AUD: RISEHARK.AUD + ^Content/d2k/Music/ROBOTIX.AUD: ROBOTIX.AUD + ^Content/d2k/Music/SCORE.AUD: SCORE.AUD + ^Content/d2k/Music/SOLDAPPR.AUD: SOLDAPPR.AUD + ^Content/d2k/Music/SPICESCT.AUD: SPICESCT.AUD + ^Content/d2k/Music/UNDERCON.AUD: UNDERCON.AUD + ^Content/d2k/Music/WAITGAME.A: WAITGAME.AUD + extract-blast: SETUP/SETUP.Z + ^Content/d2k/BLOXBAT.R8: + Offset: 1156652 + Length: 512750 + ^Content/d2k/BLOXBASE.R8: + Offset: 1669402 + Length: 497092 + ^Content/d2k/BLOXBGBS.R8: + Offset: 4055223 + Length: 499135 + ^Content/d2k/BLOXICE.R8: + Offset: 5524509 + Length: 514963 + ^Content/d2k/BLOXTREE.R8: + Offset: 6994370 + Length: 509867 + ^Content/d2k/BLOXWAST.R8: + Offset: 8455018 + Length: 508567 + ^Content/d2k/DATA.R8: + Offset: 11940547 + Length: 2044557 + ^Content/d2k/MOUSE.R8: + Offset: 14012491 + Length: 16996 + ^Content/d2k/PALETTE.BIN: + Offset: 22938401 + Length: 815 + ^Content/d2k/GAMESFX/A_ECONF2.AUD: + Offset: 15560305 + Length: 9647 + ^Content/d2k/GAMESFX/A_ECONF1.AUD: + Offset: 15569952 + Length: 8676 + ^Content/d2k/GAMESFX/A_ECONF3.AUD: + Offset: 15578628 + Length: 9641 + ^Content/d2k/GAMESFX/A_ESEL1.AUD: + Offset: 15588269 + Length: 7371 + ^Content/d2k/GAMESFX/A_ESEL2.AUD: + Offset: 15595640 + Length: 11326 + ^Content/d2k/GAMESFX/A_ESEL3.AUD: + Offset: 15606966 + Length: 11329 + ^Content/d2k/GAMESFX/A_FCONF1.AUD: + Offset: 15618295 + Length: 8964 + ^Content/d2k/GAMESFX/A_FCONF2.AUD: + Offset: 15627259 + Length: 11336 + ^Content/d2k/GAMESFX/A_FCONF3.AUD: + Offset: 15638595 + Length: 14606 + ^Content/d2k/GAMESFX/OI_ENEMY.AUD: + Offset: 15653201 + Length: 27230 + ^Content/d2k/GAMESFX/AI_POWER.AUD: + Offset: 15680431 + Length: 19621 + ^Content/d2k/GAMESFX/AI_PREP.AUD: + Offset: 15700052 + Length: 28781 + ^Content/d2k/GAMESFX/AI_PRMRY.AUD: + Offset: 15728833 + Length: 29703 + ^Content/d2k/GAMESFX/AI_REINF.AUD: + Offset: 15758536 + Length: 29555 + ^Content/d2k/GAMESFX/AI_GANEW.AUD: + Offset: 15788091 + Length: 27961 + ^Content/d2k/GAMESFX/HI_SPORT.AUD: + Offset: 15816052 + Length: 20925 + ^Content/d2k/GAMESFX/OI_GSAVE.AUD: + Offset: 15836977 + Length: 10925 + ^Content/d2k/GAMESFX/OI_GUARD.AUD: + Offset: 15847902 + Length: 8125 + ^Content/d2k/GAMESFX/HI_MAP3B.AUD: + Offset: 15856027 + Length: 26212 + ^Content/d2k/GAMESFX/HI_MAP4A.AUD: + Offset: 15882239 + Length: 27166 + ^Content/d2k/GAMESFX/HI_MAP5A.AUD: + Offset: 15909405 + Length: 31126 + ^Content/d2k/GAMESFX/HI_MAP6A.AUD: + Offset: 15940531 + Length: 33481 + ^Content/d2k/GAMESFX/O_ECONF3.AUD: + Offset: 15974012 + Length: 17265 + ^Content/d2k/GAMESFX/O_SCONF3.AUD: + Offset: 15991277 + Length: 14523 + ^Content/d2k/GAMESFX/O_SSEL1.AUD: + Offset: 16005800 + Length: 18266 + ^Content/d2k/GAMESFX/O_SSEL2.AUD: + Offset: 16024066 + Length: 8467 + ^Content/d2k/GAMESFX/O_SSEL3.AUD: + Offset: 16032533 + Length: 9748 + ^Content/d2k/GAMESFX/O_VCONF1.AUD: + Offset: 16042281 + Length: 14264 + ^Content/d2k/GAMESFX/O_VCONF2.AUD: + Offset: 16056545 + Length: 12087 + ^Content/d2k/GAMESFX/O_VCONF3.AUD: + Offset: 16068632 + Length: 14428 + ^Content/d2k/GAMESFX/OI_MWIN.AUD: + Offset: 16083060 + Length: 16985 + ^Content/d2k/GAMESFX/O_ECONF1.AUD: + Offset: 16100045 + Length: 12638 + ^Content/d2k/GAMESFX/O_ECONF2.AUD: + Offset: 16112683 + Length: 13229 + ^Content/d2k/GAMESFX/OI_NROOM.AUD: + Offset: 16125912 + Length: 26572 + ^Content/d2k/GAMESFX/O_ESEL1.AUD: + Offset: 16152484 + Length: 12085 + ^Content/d2k/GAMESFX/O_ESEL2.AUD: + Offset: 16164569 + Length: 18232 + ^Content/d2k/GAMESFX/O_ESEL3.AUD: + Offset: 16182801 + Length: 8328 + ^Content/d2k/GAMESFX/O_ICONF1.AUD: + Offset: 16191129 + Length: 12497 + ^Content/d2k/GAMESFX/O_ICONF2.AUD: + Offset: 16203626 + Length: 9546 + ^Content/d2k/GAMESFX/O_ICONF3.AUD: + Offset: 16213172 + Length: 17135 + ^Content/d2k/GAMESFX/HI_MAP4B.AUD: + Offset: 16230307 + Length: 26937 + ^Content/d2k/GAMESFX/O_ISEL2.AUD: + Offset: 16257244 + Length: 17940 + ^Content/d2k/GAMESFX/HI_BLOST.AUD: + Offset: 16275184 + Length: 14985 + ^Content/d2k/GAMESFX/HI_BUILD.AUD: + Offset: 16290169 + Length: 9089 + ^Content/d2k/GAMESFX/HI_MAP6B.AUD: + Offset: 16299258 + Length: 28401 + ^Content/d2k/GAMESFX/HI_MAP7A.AUD: + Offset: 16327659 + Length: 23949 + ^Content/d2k/GAMESFX/HI_MAP9.AUD: + Offset: 16351608 + Length: 29489 + ^Content/d2k/GAMESFX/A_VSEL3.AUD: + Offset: 16381097 + Length: 11016 + ^Content/d2k/GAMESFX/AI_1MIN.AUD: + Offset: 16392113 + Length: 27566 + ^Content/d2k/GAMESFX/AI_2MIN.AUD: + Offset: 16419679 + Length: 26539 + ^Content/d2k/GAMESFX/AI_3MIN.AUD: + Offset: 16446218 + Length: 30821 + ^Content/d2k/GAMESFX/O_VSEL1.AUD: + Offset: 16477039 + Length: 7978 + ^Content/d2k/GAMESFX/HI_RUN.AUD: + Offset: 16485017 + Length: 11880 + ^Content/d2k/GAMESFX/A_FSEL1.AUD: + Offset: 16496897 + Length: 8995 + ^Content/d2k/GAMESFX/A_FSEL2.AUD: + Offset: 16505892 + Length: 10120 + ^Content/d2k/GAMESFX/A_FSEL3.AUD: + Offset: 16516012 + Length: 8999 + ^Content/d2k/GAMESFX/A_FSEL4.AUD: + Offset: 16525011 + Length: 6593 + ^Content/d2k/GAMESFX/OI_MAP8A.AUD: + Offset: 16531604 + Length: 34790 + ^Content/d2k/GAMESFX/OI_MAP9A.AUD: + Offset: 16566394 + Length: 35606 + ^Content/d2k/GAMESFX/OI_MEND.AUD: + Offset: 16602000 + Length: 10303 + ^Content/d2k/GAMESFX/OI_MFAIL.AUD: + Offset: 16612303 + Length: 22969 + ^Content/d2k/GAMESFX/AI_4MIN.AUD: + Offset: 16635272 + Length: 31816 + ^Content/d2k/GAMESFX/AI_CANCL.AUD: + Offset: 16667088 + Length: 19585 + ^Content/d2k/GAMESFX/OI_ULOST.AUD: + Offset: 16686673 + Length: 14563 + ^Content/d2k/GAMESFX/OI_UNRDY.AUD: + Offset: 16701236 + Length: 13353 + ^Content/d2k/GAMESFX/O_VSEL3.AUD: + Offset: 16714589 + Length: 9671 + ^Content/d2k/GAMESFX/OI_1MIN.AUD: + Offset: 16724260 + Length: 15031 + ^Content/d2k/GAMESFX/OI_MAP7A.AUD: + Offset: 16739291 + Length: 28368 + ^Content/d2k/GAMESFX/HI_TRAIN.AUD: + Offset: 16767659 + Length: 9649 + ^Content/d2k/GAMESFX/HI_ULOST.AUD: + Offset: 16777308 + Length: 17157 + ^Content/d2k/GAMESFX/HI_UNRDY.AUD: + Offset: 16794465 + Length: 13407 + ^Content/d2k/GAMESFX/OI_MAP2A.AUD: + Offset: 16807872 + Length: 29910 + ^Content/d2k/GAMESFX/HI_REINF.AUD: + Offset: 16837782 + Length: 22890 + ^Content/d2k/GAMESFX/OI_MAP2C.AUD: + Offset: 16860672 + Length: 22923 + ^Content/d2k/GAMESFX/OI_MAP3A.AUD: + Offset: 16883595 + Length: 34017 + ^Content/d2k/GAMESFX/OI_MAP4A.AUD: + Offset: 16917612 + Length: 56714 + ^Content/d2k/GAMESFX/OI_SPORT.AUD: + Offset: 16974326 + Length: 27200 + ^Content/d2k/GAMESFX/OI_UPGOP.AUD: + Offset: 17001526 + Length: 19828 + ^Content/d2k/GAMESFX/OI_UPGRD.AUD: + Offset: 17021354 + Length: 13869 + ^Content/d2k/GAMESFX/OI_WATTK.AUD: + Offset: 17035223 + Length: 14197 + ^Content/d2k/GAMESFX/AI_MONEY.AUD: + Offset: 17049420 + Length: 29136 + ^Content/d2k/GAMESFX/AI_SELL.AUD: + Offset: 17078556 + Length: 26204 + ^Content/d2k/GAMESFX/HI_NEWOP.AUD: + Offset: 17104760 + Length: 24264 + ^Content/d2k/GAMESFX/AI_5MIN.AUD: + Offset: 17129024 + Length: 43921 + ^Content/d2k/GAMESFX/OI_HATTK.AUD: + Offset: 17172945 + Length: 22151 + ^Content/d2k/GAMESFX/H_VSEL2.AUD: + Offset: 17195096 + Length: 12300 + ^Content/d2k/GAMESFX/OI_MAP1B.AUD: + Offset: 17207396 + Length: 21971 + ^Content/d2k/GAMESFX/OI_MAP1C.AUD: + Offset: 17229367 + Length: 22041 + ^Content/d2k/GAMESFX/AI_GSAVE.AUD: + Offset: 17251408 + Length: 21545 + ^Content/d2k/GAMESFX/AI_GUARD.AUD: + Offset: 17272953 + Length: 14344 + ^Content/d2k/GAMESFX/AI_HATTK.AUD: + Offset: 17287297 + Length: 28156 + ^Content/d2k/GAMESFX/AI_HOLD.AUD: + Offset: 17315453 + Length: 16983 + ^Content/d2k/GAMESFX/HI_UPGOP.AUD: + Offset: 17332436 + Length: 19583 + ^Content/d2k/GAMESFX/HI_UPGRD.AUD: + Offset: 17352019 + Length: 12875 + ^Content/d2k/GAMESFX/OI_MAP2B.AUD: + Offset: 17364894 + Length: 20974 + ^Content/d2k/GAMESFX/HI_WSIGN.AUD: + Offset: 17385868 + Length: 14699 + ^Content/d2k/GAMESFX/HI_HATTK.AUD: + Offset: 17400567 + Length: 20919 + ^Content/d2k/GAMESFX/O_SCONF2.AUD: + Offset: 17421486 + Length: 18984 + ^Content/d2k/GAMESFX/HI_HOLD.AUD: + Offset: 17440470 + Length: 11779 + ^Content/d2k/GAMESFX/A_VSEL2.AUD: + Offset: 17452249 + Length: 13980 + ^Content/d2k/GAMESFX/AI_ATACK.AUD: + Offset: 17466229 + Length: 33483 + ^Content/d2k/GAMESFX/AI_BDRDY.AUD: + Offset: 17499712 + Length: 26566 + ^Content/d2k/GAMESFX/AI_BLOST.AUD: + Offset: 17526278 + Length: 25237 + ^Content/d2k/GAMESFX/AI_BUILD.AUD: + Offset: 17551515 + Length: 16072 + ^Content/d2k/GAMESFX/HI_GLOAD.AUD: + Offset: 17567587 + Length: 12037 + ^Content/d2k/GAMESFX/AI_CAPT.AUD: + Offset: 17579624 + Length: 30243 + ^Content/d2k/GAMESFX/AI_DHRDY.AUD: + Offset: 17609867 + Length: 31710 + ^Content/d2k/GAMESFX/AI_DPLOY.AUD: + Offset: 17641577 + Length: 27450 + ^Content/d2k/GAMESFX/AI_ENEMY.AUD: + Offset: 17669027 + Length: 30854 + ^Content/d2k/GAMESFX/A_VCONF1.AUD: + Offset: 17699881 + Length: 10860 + ^Content/d2k/GAMESFX/HI_PLACE.AUD: + Offset: 17710741 + Length: 19337 + ^Content/d2k/GAMESFX/HI_POWER.AUD: + Offset: 17730078 + Length: 15004 + ^Content/d2k/GAMESFX/HI_PREP.AUD: + Offset: 17745082 + Length: 23023 + ^Content/d2k/GAMESFX/HI_PRMRY.AUD: + Offset: 17768105 + Length: 22321 + ^Content/d2k/GAMESFX/OI_MONEY.AUD: + Offset: 17790426 + Length: 21698 + ^Content/d2k/GAMESFX/O_ISEL1.AUD: + Offset: 17812124 + Length: 10282 + ^Content/d2k/GAMESFX/OI_NEWOP.AUD: + Offset: 17822406 + Length: 28615 + ^Content/d2k/GAMESFX/A_VCONF3.AUD: + Offset: 17851021 + Length: 12771 + ^Content/d2k/GAMESFX/A_VSEL1.AUD: + Offset: 17863792 + Length: 9917 + ^Content/d2k/GAMESFX/OI_PLACE.AUD: + Offset: 17873709 + Length: 18502 + ^Content/d2k/GAMESFX/OI_POWER.AUD: + Offset: 17892211 + Length: 12832 + ^Content/d2k/GAMESFX/OI_PREP.AUD: + Offset: 17905043 + Length: 22413 + ^Content/d2k/GAMESFX/OI_PRMRY.AUD: + Offset: 17927456 + Length: 29577 + ^Content/d2k/GAMESFX/OI_REINF.AUD: + Offset: 17957033 + Length: 24798 + ^Content/d2k/GAMESFX/OI_RUN.AUD: + Offset: 17981831 + Length: 14784 + ^Content/d2k/GAMESFX/OI_CAPT.AUD: + Offset: 17996615 + Length: 18526 + ^Content/d2k/GAMESFX/H_ECONF1.AUD: + Offset: 18015141 + Length: 12390 + ^Content/d2k/GAMESFX/O_VSEL2.AUD: + Offset: 18027531 + Length: 11851 + ^Content/d2k/GAMESFX/H_VSEL3.AUD: + Offset: 18039382 + Length: 9867 + ^Content/d2k/GAMESFX/HI_1MIN.AUD: + Offset: 18049249 + Length: 16907 + ^Content/d2k/GAMESFX/HI_2MIN.AUD: + Offset: 18066156 + Length: 17659 + ^Content/d2k/GAMESFX/HI_3MIN.AUD: + Offset: 18083815 + Length: 20337 + ^Content/d2k/GAMESFX/HI_4MIN.AUD: + Offset: 18104152 + Length: 18877 + ^Content/d2k/GAMESFX/HI_5MIN.AUD: + Offset: 18123029 + Length: 30788 + ^Content/d2k/GAMESFX/HI_ABORT.AUD: + Offset: 18153817 + Length: 18322 + ^Content/d2k/GAMESFX/HI_ATACK.AUD: + Offset: 18172139 + Length: 22178 + ^Content/d2k/GAMESFX/HI_NROOM.AUD: + Offset: 18194317 + Length: 24878 + ^Content/d2k/GAMESFX/OI_SILOS.AUD: + Offset: 18219195 + Length: 15741 + ^Content/d2k/GAMESFX/A_FCONF4.AUD: + Offset: 18234936 + Length: 14892 + ^Content/d2k/GAMESFX/OI_MAP5A.AUD: + Offset: 18249828 + Length: 23026 + ^Content/d2k/GAMESFX/OI_MAP6A.AUD: + Offset: 18272854 + Length: 43938 + ^Content/d2k/GAMESFX/HI_CANCL.AUD: + Offset: 18316792 + Length: 10992 + ^Content/d2k/GAMESFX/HI_CAPT.AUD: + Offset: 18327784 + Length: 19514 + ^Content/d2k/GAMESFX/HI_DHRDY.AUD: + Offset: 18347298 + Length: 23895 + ^Content/d2k/GAMESFX/HI_DPLOY.AUD: + Offset: 18371193 + Length: 18626 + ^Content/d2k/GAMESFX/HI_ENEMY.AUD: + Offset: 18389819 + Length: 22564 + ^Content/d2k/GAMESFX/HI_GANEW.AUD: + Offset: 18412383 + Length: 18445 + ^Content/d2k/GAMESFX/OI_DHRDY.AUD: + Offset: 18430828 + Length: 19492 + ^Content/d2k/GAMESFX/HI_GSAVE.AUD: + Offset: 18450320 + Length: 14194 + ^Content/d2k/GAMESFX/HI_GUARD.AUD: + Offset: 18464514 + Length: 8310 + ^Content/d2k/GAMESFX/H_VSEL1.AUD: + Offset: 18472824 + Length: 8332 + ^Content/d2k/GAMESFX/OI_ORDER.AUD: + Offset: 18481156 + Length: 15789 + ^Content/d2k/GAMESFX/G_SCONF1.AUD: + Offset: 18496945 + Length: 9791 + ^Content/d2k/GAMESFX/G_SCONF2.AUD: + Offset: 18506736 + Length: 15099 + ^Content/d2k/GAMESFX/G_SCONF3.AUD: + Offset: 18521835 + Length: 14863 + ^Content/d2k/GAMESFX/G_SSEL1.AUD: + Offset: 18536698 + Length: 9753 + ^Content/d2k/GAMESFX/G_SSEL2.AUD: + Offset: 18546451 + Length: 9329 + ^Content/d2k/GAMESFX/G_SSEL3.AUD: + Offset: 18555780 + Length: 9449 + ^Content/d2k/GAMESFX/OI_SELL.AUD: + Offset: 18565229 + Length: 15600 + ^Content/d2k/GAMESFX/H_ECONF2.AUD: + Offset: 18580829 + Length: 16157 + ^Content/d2k/GAMESFX/H_ECONF3.AUD: + Offset: 18596986 + Length: 13149 + ^Content/d2k/GAMESFX/H_ESEL1.AUD: + Offset: 18610135 + Length: 13928 + ^Content/d2k/GAMESFX/H_ESEL2.AUD: + Offset: 18624063 + Length: 16430 + ^Content/d2k/GAMESFX/AI_MAP2C.AUD: + Offset: 18640493 + Length: 41640 + ^Content/d2k/GAMESFX/AI_MAP3A.AUD: + Offset: 18682133 + Length: 41809 + ^Content/d2k/GAMESFX/AI_MAP4A.AUD: + Offset: 18723942 + Length: 29117 + ^Content/d2k/GAMESFX/AI_MAP5A.AUD: + Offset: 18753059 + Length: 36982 + ^Content/d2k/GAMESFX/AI_MAP6A.AUD: + Offset: 18790041 + Length: 60681 + ^Content/d2k/GAMESFX/HI_BDRDY.AUD: + Offset: 18850722 + Length: 21396 + ^Content/d2k/GAMESFX/AI_MAP8A.AUD: + Offset: 18872118 + Length: 37995 + ^Content/d2k/GAMESFX/AI_MAP9A.AUD: + Offset: 18910113 + Length: 32674 + ^Content/d2k/GAMESFX/AI_MEND.AUD: + Offset: 18942787 + Length: 18399 + ^Content/d2k/GAMESFX/AI_MFAIL.AUD: + Offset: 18961186 + Length: 26359 + ^Content/d2k/GAMESFX/AI_GLOAD.AUD: + Offset: 18987545 + Length: 21335 + ^Content/d2k/GAMESFX/HI_MAP9A.AUD: + Offset: 19008880 + Length: 28418 + ^Content/d2k/GAMESFX/HI_MEND.AUD: + Offset: 19037298 + Length: 9269 + ^Content/d2k/GAMESFX/HI_MFAIL.AUD: + Offset: 19046567 + Length: 19854 + ^Content/d2k/GAMESFX/HI_MONEY.AUD: + Offset: 19066421 + Length: 20038 + ^Content/d2k/GAMESFX/HI_MWIN.AUD: + Offset: 19086459 + Length: 16073 + ^Content/d2k/GAMESFX/HI_WATTK.AUD: + Offset: 19102532 + Length: 14873 + ^Content/d2k/GAMESFX/AI_MAP1A.AUD: + Offset: 19117405 + Length: 41683 + ^Content/d2k/GAMESFX/AI_MAP1B.AUD: + Offset: 19159088 + Length: 34475 + ^Content/d2k/GAMESFX/AI_MAP1C.AUD: + Offset: 19193563 + Length: 34903 + ^Content/d2k/GAMESFX/AI_MAP2A.AUD: + Offset: 19228466 + Length: 59613 + ^Content/d2k/GAMESFX/AI_ABORT.AUD: + Offset: 19288079 + Length: 22150 + ^Content/d2k/GAMESFX/H_ESEL3.AUD: + Offset: 19310229 + Length: 9090 + ^Content/d2k/GAMESFX/AI_SILOS.AUD: + Offset: 19319319 + Length: 21350 + ^Content/d2k/GAMESFX/AI_SPORT.AUD: + Offset: 19340669 + Length: 31478 + ^Content/d2k/GAMESFX/AI_TRAIN.AUD: + Offset: 19372147 + Length: 19876 + ^Content/d2k/GAMESFX/AI_ULOST.AUD: + Offset: 19392023 + Length: 22359 + ^Content/d2k/GAMESFX/AI_MAP7A.AUD: + Offset: 19414382 + Length: 28902 + ^Content/d2k/GAMESFX/AI_UPGOP.AUD: + Offset: 19443284 + Length: 26855 + ^Content/d2k/GAMESFX/AI_UPGRD.AUD: + Offset: 19470139 + Length: 19104 + ^Content/d2k/GAMESFX/AI_WATTK.AUD: + Offset: 19489243 + Length: 24655 + ^Content/d2k/GAMESFX/AI_WSIGN.AUD: + Offset: 19513898 + Length: 23032 + ^Content/d2k/GAMESFX/AI_MAP2B.AUD: + Offset: 19536930 + Length: 35588 + ^Content/d2k/GAMESFX/A_ICONF1.AUD: + Offset: 19572518 + Length: 8945 + ^Content/d2k/GAMESFX/A_ICONF2.AUD: + Offset: 19581463 + Length: 9005 + ^Content/d2k/GAMESFX/A_ICONF3.AUD: + Offset: 19590468 + Length: 9606 + ^Content/d2k/GAMESFX/A_ISEL1.AUD: + Offset: 19600074 + Length: 11671 + ^Content/d2k/GAMESFX/OI_CANCL.AUD: + Offset: 19611745 + Length: 10644 + ^Content/d2k/GAMESFX/H_ISEL2.AUD: + Offset: 19622389 + Length: 10387 + ^Content/d2k/GAMESFX/H_ISEL3.AUD: + Offset: 19632776 + Length: 17225 + ^Content/d2k/GAMESFX/H_VCONF1.AUD: + Offset: 19650001 + Length: 10077 + ^Content/d2k/GAMESFX/H_VCONF2.AUD: + Offset: 19660078 + Length: 13616 + ^Content/d2k/GAMESFX/H_VCONF3.AUD: + Offset: 19673694 + Length: 11251 + ^Content/d2k/GAMESFX/OI_TRAIN.AUD: + Offset: 19684945 + Length: 8144 + ^Content/d2k/GAMESFX/HI_ORDER.AUD: + Offset: 19693089 + Length: 14865 + ^Content/d2k/GAMESFX/OI_WSIGN.AUD: + Offset: 19707954 + Length: 11912 + ^Content/d2k/GAMESFX/OI_BLOST.AUD: + Offset: 19719866 + Length: 19540 + ^Content/d2k/GAMESFX/OI_BUILD.AUD: + Offset: 19739406 + Length: 10246 + ^Content/d2k/GAMESFX/AI_LAUNC.AUD: + Offset: 19749652 + Length: 31148 + ^Content/d2k/GAMESFX/A_ISEL3.AUD: + Offset: 19780800 + Length: 8307 + ^Content/d2k/GAMESFX/A_VCONF2.AUD: + Offset: 19789107 + Length: 14331 + ^Content/d2k/GAMESFX/OI_HOLD.AUD: + Offset: 19803438 + Length: 11295 + ^Content/d2k/GAMESFX/OI_LAUNC.AUD: + Offset: 19814733 + Length: 20437 + ^Content/d2k/GAMESFX/OI_MAP1A.AUD: + Offset: 19835170 + Length: 27739 + ^Content/d2k/GAMESFX/HI_LAUNC.AUD: + Offset: 19862909 + Length: 22200 + ^Content/d2k/GAMESFX/H_ICONF1.AUD: + Offset: 19885109 + Length: 9620 + ^Content/d2k/GAMESFX/H_ICONF2.AUD: + Offset: 19894729 + Length: 13368 + ^Content/d2k/GAMESFX/H_ICONF3.AUD: + Offset: 19908097 + Length: 15612 + ^Content/d2k/GAMESFX/H_ISEL1.AUD: + Offset: 19923709 + Length: 8279 + ^Content/d2k/GAMESFX/A_ISEL2.AUD: + Offset: 19931988 + Length: 11383 + ^Content/d2k/GAMESFX/AI_RUN.AUD: + Offset: 19943371 + Length: 18511 + ^Content/d2k/GAMESFX/HI_SILOS.AUD: + Offset: 19961882 + Length: 14244 + ^Content/d2k/GAMESFX/HI_MAP1A.AUD: + Offset: 19976126 + Length: 24075 + ^Content/d2k/GAMESFX/HI_MAP1B.AUD: + Offset: 20000201 + Length: 26716 + ^Content/d2k/GAMESFX/HI_MAP1C.AUD: + Offset: 20026917 + Length: 21716 + ^Content/d2k/GAMESFX/HI_MAP2A.AUD: + Offset: 20048633 + Length: 32417 + ^Content/d2k/GAMESFX/HI_MAP2B.AUD: + Offset: 20081050 + Length: 33724 + ^Content/d2k/GAMESFX/HI_MAP2C.AUD: + Offset: 20114774 + Length: 21828 + ^Content/d2k/GAMESFX/HI_MAP3A.AUD: + Offset: 20136602 + Length: 30404 + ^Content/d2k/GAMESFX/O_ISEL3.AUD: + Offset: 20167006 + Length: 9862 + ^Content/d2k/GAMESFX/O_SCONF1.AUD: + Offset: 20176868 + Length: 18149 + ^Content/d2k/GAMESFX/OI_2MIN.AUD: + Offset: 20195017 + Length: 14697 + ^Content/d2k/GAMESFX/OI_3MIN.AUD: + Offset: 20209714 + Length: 17316 + ^Content/d2k/GAMESFX/OI_4MIN.AUD: + Offset: 20227030 + Length: 14869 + ^Content/d2k/GAMESFX/OI_5MIN.AUD: + Offset: 20241899 + Length: 29873 + ^Content/d2k/GAMESFX/OI_ABORT.AUD: + Offset: 20271772 + Length: 16335 + ^Content/d2k/GAMESFX/OI_ATACK.AUD: + Offset: 20288107 + Length: 20565 + ^Content/d2k/GAMESFX/OI_BDRDY.AUD: + Offset: 20308672 + Length: 25497 + ^Content/d2k/GAMESFX/HI_SELL.AUD: + Offset: 20334169 + Length: 17142 + ^Content/d2k/GAMESFX/OI_DPLOY.AUD: + Offset: 20351311 + Length: 20120 + ^Content/d2k/GAMESFX/AI_PLACE.AUD: + Offset: 20371431 + Length: 29921 + ^Content/d2k/GAMESFX/OI_GANEW.AUD: + Offset: 20401352 + Length: 14467 + ^Content/d2k/GAMESFX/OI_GLOAD.AUD: + Offset: 20415819 + Length: 10906 + ^Content/d2k/GAMESFX/AI_MWIN.AUD: + Offset: 20426725 + Length: 25959 + ^Content/d2k/GAMESFX/AI_NEWOP.AUD: + Offset: 20452684 + Length: 34175 + ^Content/d2k/GAMESFX/AI_NROOM.AUD: + Offset: 20486859 + Length: 30124 + ^Content/d2k/GAMESFX/AI_ORDER.AUD: + Offset: 20516983 + Length: 21881 + ^Content/d2k/GAMESFX/AI_UNRDY.AUD: + Offset: 20538864 + Length: 20567 + ^Content/d2k/SOUND.RS: + Offset: 20559431 + Length: 1929247 + d2k-linux: Dune 2000 (English) + IDFiles: + music/ambush.aud: bd5926a56a83bc0e49f96037e1f909014ac0772a + setup/setup.z: 937f5ceb1236bf3f3d4e43929305ffe5004078e7 + Install: + copy: movies + ^Content/d2k/Movies/A_BR01_E.VQA: a_br01_e.vqa + ^Content/d2k/Movies/A_BR02_E.VQA: a_br02_e.vqa + ^Content/d2k/Movies/A_BR03_E.VQA: a_br03_e.vqa + ^Content/d2k/Movies/A_BR04_E.VQA: a_br04_e.vqa + ^Content/d2k/Movies/A_BR05_E.VQA: a_br05_e.vqa + ^Content/d2k/Movies/A_BR06_E.VQA: a_br06_e.vqa + ^Content/d2k/Movies/A_BR07_E.VQA: a_br07_e.vqa + ^Content/d2k/Movies/A_BR08_E.VQA: a_br08_e.vqa + ^Content/d2k/Movies/A_BR09_E.VQA: a_br09_e.vqa + ^Content/d2k/Movies/A_FINL_E.VQA: a_finl_e.vqa + ^Content/d2k/Movies/A_LOSE_E.VQA: a_lose_e.vqa + ^Content/d2k/Movies/A_MNTG_E.VQA: a_mntg_e.vqa + ^Content/d2k/Movies/H_BR01_E.VQA: h_br01_e.vqa + ^Content/d2k/Movies/H_BR02_E.VQA: h_br02_e.vqa + ^Content/d2k/Movies/H_BR03_E.VQA: h_br03_e.vqa + ^Content/d2k/Movies/H_BR04_E.VQA: h_br04_e.vqa + ^Content/d2k/Movies/H_BR05_E.VQA: h_br05_e.vqa + ^Content/d2k/Movies/H_BR06_E.VQA: h_br06_e.vqa + ^Content/d2k/Movies/H_BR07_E.VQA: h_br07_e.vqa + ^Content/d2k/Movies/H_BR08_E.VQA: h_br08_e.vqa + ^Content/d2k/Movies/H_BR09_E.VQA: h_br09_e.vqa + ^Content/d2k/Movies/H_FINL_E.VQA: h_finl_e.vqa + ^Content/d2k/Movies/H_LOSE_E.VQA: h_lose_e.vqa + ^Content/d2k/Movies/H_MNTG_E.VQA: h_mntg_e.vqa + ^Content/d2k/Movies/O_BR01_E.VQA: o_br01_e.vqa + ^Content/d2k/Movies/O_BR02_E.VQA: o_br02_e.vqa + ^Content/d2k/Movies/O_BR03_E.VQA: o_br03_e.vqa + ^Content/d2k/Movies/O_BR04_E.VQA: o_br04_e.vqa + ^Content/d2k/Movies/O_BR05_E.VQA: o_br05_e.vqa + ^Content/d2k/Movies/O_BR06_E.VQA: o_br06_e.vqa + ^Content/d2k/Movies/O_BR07_E.VQA: o_br07_e.vqa + ^Content/d2k/Movies/O_BR08_E.VQA: o_br08_e.vqa + ^Content/d2k/Movies/O_BR09_E.VQA: o_br09_e.vqa + ^Content/d2k/Movies/O_FINL_E.VQA: o_finl_e.vqa + ^Content/d2k/Movies/O_LOSE_E.VQA: o_lose_e.vqa + ^Content/d2k/Movies/O_MNTG_E.VQA: o_mntg_e.vqa + ^Content/d2k/Movies/G_INT1_E.VQA: g_int1_e.vqa + ^Content/d2k/Movies/G_INT2_E.VQA: g_int2_e.vqa + ^Content/d2k/Movies/G_MAPS_E.VQA: g_maps_e.vqa + ^Content/d2k/Movies/G_PLN2_E.VQA: g_pln2_e.vqa + ^Content/d2k/Movies/G_PLNT_E.VQA: g_plnt_e.vqa + ^Content/d2k/Movies/T_TITL_E.VQA: t_titl_e.vqa + copy: music + ^Content/d2k/Music/AMBUSH.AUD: ambush.aud + ^Content/d2k/Music/ARAKATAK.AUD: arakatak.aud + ^Content/d2k/Music/ATREGAIN.AUD: atregain.aud + ^Content/d2k/Music/ENTORDOS.AUD: entordos.aud + ^Content/d2k/Music/FIGHTPWR.AUD: fightpwr.aud + ^Content/d2k/Music/FREMEN.AUD: fremen.aud + ^Content/d2k/Music/HARK_BAT.AUD: hark_bat.aud + ^Content/d2k/Music/LANDSAND.AUD: landsand.aud + ^Content/d2k/Music/OPTIONS.AUD: options.aud + ^Content/d2k/Music/PLOTTING.AUD: plotting.aud + ^Content/d2k/Music/RISEHARK.AUD: risehark.aud + ^Content/d2k/Music/ROBOTIX.AUD: robotix.aud + ^Content/d2k/Music/SCORE.AUD: score.aud + ^Content/d2k/Music/SOLDAPPR.AUD: soldappr.aud + ^Content/d2k/Music/SPICESCT.AUD: spicesct.aud + ^Content/d2k/Music/UNDERCON.AUD: undercon.aud + ^Content/d2k/Music/WAITGAME.A: waitgame.aud + extract-blast: setup/setup.z + ^Content/d2k/BLOXBAT.R8: + Offset: 1156652 + Length: 512750 + ^Content/d2k/BLOXBASE.R8: + Offset: 1669402 + Length: 497092 + ^Content/d2k/BLOXBGBS.R8: + Offset: 4055223 + Length: 499135 + ^Content/d2k/BLOXICE.R8: + Offset: 5524509 + Length: 514963 + ^Content/d2k/BLOXTREE.R8: + Offset: 6994370 + Length: 509867 + ^Content/d2k/BLOXWAST.R8: + Offset: 8455018 + Length: 508567 + ^Content/d2k/DATA.R8: + Offset: 11940547 + Length: 2044557 + ^Content/d2k/MOUSE.R8: + Offset: 14012491 + Length: 16996 + ^Content/d2k/PALETTE.BIN: + Offset: 22938401 + Length: 815 + ^Content/d2k/GAMESFX/A_ECONF2.AUD: + Offset: 15560305 + Length: 9647 + ^Content/d2k/GAMESFX/A_ECONF1.AUD: + Offset: 15569952 + Length: 8676 + ^Content/d2k/GAMESFX/A_ECONF3.AUD: + Offset: 15578628 + Length: 9641 + ^Content/d2k/GAMESFX/A_ESEL1.AUD: + Offset: 15588269 + Length: 7371 + ^Content/d2k/GAMESFX/A_ESEL2.AUD: + Offset: 15595640 + Length: 11326 + ^Content/d2k/GAMESFX/A_ESEL3.AUD: + Offset: 15606966 + Length: 11329 + ^Content/d2k/GAMESFX/A_FCONF1.AUD: + Offset: 15618295 + Length: 8964 + ^Content/d2k/GAMESFX/A_FCONF2.AUD: + Offset: 15627259 + Length: 11336 + ^Content/d2k/GAMESFX/A_FCONF3.AUD: + Offset: 15638595 + Length: 14606 + ^Content/d2k/GAMESFX/OI_ENEMY.AUD: + Offset: 15653201 + Length: 27230 + ^Content/d2k/GAMESFX/AI_POWER.AUD: + Offset: 15680431 + Length: 19621 + ^Content/d2k/GAMESFX/AI_PREP.AUD: + Offset: 15700052 + Length: 28781 + ^Content/d2k/GAMESFX/AI_PRMRY.AUD: + Offset: 15728833 + Length: 29703 + ^Content/d2k/GAMESFX/AI_REINF.AUD: + Offset: 15758536 + Length: 29555 + ^Content/d2k/GAMESFX/AI_GANEW.AUD: + Offset: 15788091 + Length: 27961 + ^Content/d2k/GAMESFX/HI_SPORT.AUD: + Offset: 15816052 + Length: 20925 + ^Content/d2k/GAMESFX/OI_GSAVE.AUD: + Offset: 15836977 + Length: 10925 + ^Content/d2k/GAMESFX/OI_GUARD.AUD: + Offset: 15847902 + Length: 8125 + ^Content/d2k/GAMESFX/HI_MAP3B.AUD: + Offset: 15856027 + Length: 26212 + ^Content/d2k/GAMESFX/HI_MAP4A.AUD: + Offset: 15882239 + Length: 27166 + ^Content/d2k/GAMESFX/HI_MAP5A.AUD: + Offset: 15909405 + Length: 31126 + ^Content/d2k/GAMESFX/HI_MAP6A.AUD: + Offset: 15940531 + Length: 33481 + ^Content/d2k/GAMESFX/O_ECONF3.AUD: + Offset: 15974012 + Length: 17265 + ^Content/d2k/GAMESFX/O_SCONF3.AUD: + Offset: 15991277 + Length: 14523 + ^Content/d2k/GAMESFX/O_SSEL1.AUD: + Offset: 16005800 + Length: 18266 + ^Content/d2k/GAMESFX/O_SSEL2.AUD: + Offset: 16024066 + Length: 8467 + ^Content/d2k/GAMESFX/O_SSEL3.AUD: + Offset: 16032533 + Length: 9748 + ^Content/d2k/GAMESFX/O_VCONF1.AUD: + Offset: 16042281 + Length: 14264 + ^Content/d2k/GAMESFX/O_VCONF2.AUD: + Offset: 16056545 + Length: 12087 + ^Content/d2k/GAMESFX/O_VCONF3.AUD: + Offset: 16068632 + Length: 14428 + ^Content/d2k/GAMESFX/OI_MWIN.AUD: + Offset: 16083060 + Length: 16985 + ^Content/d2k/GAMESFX/O_ECONF1.AUD: + Offset: 16100045 + Length: 12638 + ^Content/d2k/GAMESFX/O_ECONF2.AUD: + Offset: 16112683 + Length: 13229 + ^Content/d2k/GAMESFX/OI_NROOM.AUD: + Offset: 16125912 + Length: 26572 + ^Content/d2k/GAMESFX/O_ESEL1.AUD: + Offset: 16152484 + Length: 12085 + ^Content/d2k/GAMESFX/O_ESEL2.AUD: + Offset: 16164569 + Length: 18232 + ^Content/d2k/GAMESFX/O_ESEL3.AUD: + Offset: 16182801 + Length: 8328 + ^Content/d2k/GAMESFX/O_ICONF1.AUD: + Offset: 16191129 + Length: 12497 + ^Content/d2k/GAMESFX/O_ICONF2.AUD: + Offset: 16203626 + Length: 9546 + ^Content/d2k/GAMESFX/O_ICONF3.AUD: + Offset: 16213172 + Length: 17135 + ^Content/d2k/GAMESFX/HI_MAP4B.AUD: + Offset: 16230307 + Length: 26937 + ^Content/d2k/GAMESFX/O_ISEL2.AUD: + Offset: 16257244 + Length: 17940 + ^Content/d2k/GAMESFX/HI_BLOST.AUD: + Offset: 16275184 + Length: 14985 + ^Content/d2k/GAMESFX/HI_BUILD.AUD: + Offset: 16290169 + Length: 9089 + ^Content/d2k/GAMESFX/HI_MAP6B.AUD: + Offset: 16299258 + Length: 28401 + ^Content/d2k/GAMESFX/HI_MAP7A.AUD: + Offset: 16327659 + Length: 23949 + ^Content/d2k/GAMESFX/HI_MAP9.AUD: + Offset: 16351608 + Length: 29489 + ^Content/d2k/GAMESFX/A_VSEL3.AUD: + Offset: 16381097 + Length: 11016 + ^Content/d2k/GAMESFX/AI_1MIN.AUD: + Offset: 16392113 + Length: 27566 + ^Content/d2k/GAMESFX/AI_2MIN.AUD: + Offset: 16419679 + Length: 26539 + ^Content/d2k/GAMESFX/AI_3MIN.AUD: + Offset: 16446218 + Length: 30821 + ^Content/d2k/GAMESFX/O_VSEL1.AUD: + Offset: 16477039 + Length: 7978 + ^Content/d2k/GAMESFX/HI_RUN.AUD: + Offset: 16485017 + Length: 11880 + ^Content/d2k/GAMESFX/A_FSEL1.AUD: + Offset: 16496897 + Length: 8995 + ^Content/d2k/GAMESFX/A_FSEL2.AUD: + Offset: 16505892 + Length: 10120 + ^Content/d2k/GAMESFX/A_FSEL3.AUD: + Offset: 16516012 + Length: 8999 + ^Content/d2k/GAMESFX/A_FSEL4.AUD: + Offset: 16525011 + Length: 6593 + ^Content/d2k/GAMESFX/OI_MAP8A.AUD: + Offset: 16531604 + Length: 34790 + ^Content/d2k/GAMESFX/OI_MAP9A.AUD: + Offset: 16566394 + Length: 35606 + ^Content/d2k/GAMESFX/OI_MEND.AUD: + Offset: 16602000 + Length: 10303 + ^Content/d2k/GAMESFX/OI_MFAIL.AUD: + Offset: 16612303 + Length: 22969 + ^Content/d2k/GAMESFX/AI_4MIN.AUD: + Offset: 16635272 + Length: 31816 + ^Content/d2k/GAMESFX/AI_CANCL.AUD: + Offset: 16667088 + Length: 19585 + ^Content/d2k/GAMESFX/OI_ULOST.AUD: + Offset: 16686673 + Length: 14563 + ^Content/d2k/GAMESFX/OI_UNRDY.AUD: + Offset: 16701236 + Length: 13353 + ^Content/d2k/GAMESFX/O_VSEL3.AUD: + Offset: 16714589 + Length: 9671 + ^Content/d2k/GAMESFX/OI_1MIN.AUD: + Offset: 16724260 + Length: 15031 + ^Content/d2k/GAMESFX/OI_MAP7A.AUD: + Offset: 16739291 + Length: 28368 + ^Content/d2k/GAMESFX/HI_TRAIN.AUD: + Offset: 16767659 + Length: 9649 + ^Content/d2k/GAMESFX/HI_ULOST.AUD: + Offset: 16777308 + Length: 17157 + ^Content/d2k/GAMESFX/HI_UNRDY.AUD: + Offset: 16794465 + Length: 13407 + ^Content/d2k/GAMESFX/OI_MAP2A.AUD: + Offset: 16807872 + Length: 29910 + ^Content/d2k/GAMESFX/HI_REINF.AUD: + Offset: 16837782 + Length: 22890 + ^Content/d2k/GAMESFX/OI_MAP2C.AUD: + Offset: 16860672 + Length: 22923 + ^Content/d2k/GAMESFX/OI_MAP3A.AUD: + Offset: 16883595 + Length: 34017 + ^Content/d2k/GAMESFX/OI_MAP4A.AUD: + Offset: 16917612 + Length: 56714 + ^Content/d2k/GAMESFX/OI_SPORT.AUD: + Offset: 16974326 + Length: 27200 + ^Content/d2k/GAMESFX/OI_UPGOP.AUD: + Offset: 17001526 + Length: 19828 + ^Content/d2k/GAMESFX/OI_UPGRD.AUD: + Offset: 17021354 + Length: 13869 + ^Content/d2k/GAMESFX/OI_WATTK.AUD: + Offset: 17035223 + Length: 14197 + ^Content/d2k/GAMESFX/AI_MONEY.AUD: + Offset: 17049420 + Length: 29136 + ^Content/d2k/GAMESFX/AI_SELL.AUD: + Offset: 17078556 + Length: 26204 + ^Content/d2k/GAMESFX/HI_NEWOP.AUD: + Offset: 17104760 + Length: 24264 + ^Content/d2k/GAMESFX/AI_5MIN.AUD: + Offset: 17129024 + Length: 43921 + ^Content/d2k/GAMESFX/OI_HATTK.AUD: + Offset: 17172945 + Length: 22151 + ^Content/d2k/GAMESFX/H_VSEL2.AUD: + Offset: 17195096 + Length: 12300 + ^Content/d2k/GAMESFX/OI_MAP1B.AUD: + Offset: 17207396 + Length: 21971 + ^Content/d2k/GAMESFX/OI_MAP1C.AUD: + Offset: 17229367 + Length: 22041 + ^Content/d2k/GAMESFX/AI_GSAVE.AUD: + Offset: 17251408 + Length: 21545 + ^Content/d2k/GAMESFX/AI_GUARD.AUD: + Offset: 17272953 + Length: 14344 + ^Content/d2k/GAMESFX/AI_HATTK.AUD: + Offset: 17287297 + Length: 28156 + ^Content/d2k/GAMESFX/AI_HOLD.AUD: + Offset: 17315453 + Length: 16983 + ^Content/d2k/GAMESFX/HI_UPGOP.AUD: + Offset: 17332436 + Length: 19583 + ^Content/d2k/GAMESFX/HI_UPGRD.AUD: + Offset: 17352019 + Length: 12875 + ^Content/d2k/GAMESFX/OI_MAP2B.AUD: + Offset: 17364894 + Length: 20974 + ^Content/d2k/GAMESFX/HI_WSIGN.AUD: + Offset: 17385868 + Length: 14699 + ^Content/d2k/GAMESFX/HI_HATTK.AUD: + Offset: 17400567 + Length: 20919 + ^Content/d2k/GAMESFX/O_SCONF2.AUD: + Offset: 17421486 + Length: 18984 + ^Content/d2k/GAMESFX/HI_HOLD.AUD: + Offset: 17440470 + Length: 11779 + ^Content/d2k/GAMESFX/A_VSEL2.AUD: + Offset: 17452249 + Length: 13980 + ^Content/d2k/GAMESFX/AI_ATACK.AUD: + Offset: 17466229 + Length: 33483 + ^Content/d2k/GAMESFX/AI_BDRDY.AUD: + Offset: 17499712 + Length: 26566 + ^Content/d2k/GAMESFX/AI_BLOST.AUD: + Offset: 17526278 + Length: 25237 + ^Content/d2k/GAMESFX/AI_BUILD.AUD: + Offset: 17551515 + Length: 16072 + ^Content/d2k/GAMESFX/HI_GLOAD.AUD: + Offset: 17567587 + Length: 12037 + ^Content/d2k/GAMESFX/AI_CAPT.AUD: + Offset: 17579624 + Length: 30243 + ^Content/d2k/GAMESFX/AI_DHRDY.AUD: + Offset: 17609867 + Length: 31710 + ^Content/d2k/GAMESFX/AI_DPLOY.AUD: + Offset: 17641577 + Length: 27450 + ^Content/d2k/GAMESFX/AI_ENEMY.AUD: + Offset: 17669027 + Length: 30854 + ^Content/d2k/GAMESFX/A_VCONF1.AUD: + Offset: 17699881 + Length: 10860 + ^Content/d2k/GAMESFX/HI_PLACE.AUD: + Offset: 17710741 + Length: 19337 + ^Content/d2k/GAMESFX/HI_POWER.AUD: + Offset: 17730078 + Length: 15004 + ^Content/d2k/GAMESFX/HI_PREP.AUD: + Offset: 17745082 + Length: 23023 + ^Content/d2k/GAMESFX/HI_PRMRY.AUD: + Offset: 17768105 + Length: 22321 + ^Content/d2k/GAMESFX/OI_MONEY.AUD: + Offset: 17790426 + Length: 21698 + ^Content/d2k/GAMESFX/O_ISEL1.AUD: + Offset: 17812124 + Length: 10282 + ^Content/d2k/GAMESFX/OI_NEWOP.AUD: + Offset: 17822406 + Length: 28615 + ^Content/d2k/GAMESFX/A_VCONF3.AUD: + Offset: 17851021 + Length: 12771 + ^Content/d2k/GAMESFX/A_VSEL1.AUD: + Offset: 17863792 + Length: 9917 + ^Content/d2k/GAMESFX/OI_PLACE.AUD: + Offset: 17873709 + Length: 18502 + ^Content/d2k/GAMESFX/OI_POWER.AUD: + Offset: 17892211 + Length: 12832 + ^Content/d2k/GAMESFX/OI_PREP.AUD: + Offset: 17905043 + Length: 22413 + ^Content/d2k/GAMESFX/OI_PRMRY.AUD: + Offset: 17927456 + Length: 29577 + ^Content/d2k/GAMESFX/OI_REINF.AUD: + Offset: 17957033 + Length: 24798 + ^Content/d2k/GAMESFX/OI_RUN.AUD: + Offset: 17981831 + Length: 14784 + ^Content/d2k/GAMESFX/OI_CAPT.AUD: + Offset: 17996615 + Length: 18526 + ^Content/d2k/GAMESFX/H_ECONF1.AUD: + Offset: 18015141 + Length: 12390 + ^Content/d2k/GAMESFX/O_VSEL2.AUD: + Offset: 18027531 + Length: 11851 + ^Content/d2k/GAMESFX/H_VSEL3.AUD: + Offset: 18039382 + Length: 9867 + ^Content/d2k/GAMESFX/HI_1MIN.AUD: + Offset: 18049249 + Length: 16907 + ^Content/d2k/GAMESFX/HI_2MIN.AUD: + Offset: 18066156 + Length: 17659 + ^Content/d2k/GAMESFX/HI_3MIN.AUD: + Offset: 18083815 + Length: 20337 + ^Content/d2k/GAMESFX/HI_4MIN.AUD: + Offset: 18104152 + Length: 18877 + ^Content/d2k/GAMESFX/HI_5MIN.AUD: + Offset: 18123029 + Length: 30788 + ^Content/d2k/GAMESFX/HI_ABORT.AUD: + Offset: 18153817 + Length: 18322 + ^Content/d2k/GAMESFX/HI_ATACK.AUD: + Offset: 18172139 + Length: 22178 + ^Content/d2k/GAMESFX/HI_NROOM.AUD: + Offset: 18194317 + Length: 24878 + ^Content/d2k/GAMESFX/OI_SILOS.AUD: + Offset: 18219195 + Length: 15741 + ^Content/d2k/GAMESFX/A_FCONF4.AUD: + Offset: 18234936 + Length: 14892 + ^Content/d2k/GAMESFX/OI_MAP5A.AUD: + Offset: 18249828 + Length: 23026 + ^Content/d2k/GAMESFX/OI_MAP6A.AUD: + Offset: 18272854 + Length: 43938 + ^Content/d2k/GAMESFX/HI_CANCL.AUD: + Offset: 18316792 + Length: 10992 + ^Content/d2k/GAMESFX/HI_CAPT.AUD: + Offset: 18327784 + Length: 19514 + ^Content/d2k/GAMESFX/HI_DHRDY.AUD: + Offset: 18347298 + Length: 23895 + ^Content/d2k/GAMESFX/HI_DPLOY.AUD: + Offset: 18371193 + Length: 18626 + ^Content/d2k/GAMESFX/HI_ENEMY.AUD: + Offset: 18389819 + Length: 22564 + ^Content/d2k/GAMESFX/HI_GANEW.AUD: + Offset: 18412383 + Length: 18445 + ^Content/d2k/GAMESFX/OI_DHRDY.AUD: + Offset: 18430828 + Length: 19492 + ^Content/d2k/GAMESFX/HI_GSAVE.AUD: + Offset: 18450320 + Length: 14194 + ^Content/d2k/GAMESFX/HI_GUARD.AUD: + Offset: 18464514 + Length: 8310 + ^Content/d2k/GAMESFX/H_VSEL1.AUD: + Offset: 18472824 + Length: 8332 + ^Content/d2k/GAMESFX/OI_ORDER.AUD: + Offset: 18481156 + Length: 15789 + ^Content/d2k/GAMESFX/G_SCONF1.AUD: + Offset: 18496945 + Length: 9791 + ^Content/d2k/GAMESFX/G_SCONF2.AUD: + Offset: 18506736 + Length: 15099 + ^Content/d2k/GAMESFX/G_SCONF3.AUD: + Offset: 18521835 + Length: 14863 + ^Content/d2k/GAMESFX/G_SSEL1.AUD: + Offset: 18536698 + Length: 9753 + ^Content/d2k/GAMESFX/G_SSEL2.AUD: + Offset: 18546451 + Length: 9329 + ^Content/d2k/GAMESFX/G_SSEL3.AUD: + Offset: 18555780 + Length: 9449 + ^Content/d2k/GAMESFX/OI_SELL.AUD: + Offset: 18565229 + Length: 15600 + ^Content/d2k/GAMESFX/H_ECONF2.AUD: + Offset: 18580829 + Length: 16157 + ^Content/d2k/GAMESFX/H_ECONF3.AUD: + Offset: 18596986 + Length: 13149 + ^Content/d2k/GAMESFX/H_ESEL1.AUD: + Offset: 18610135 + Length: 13928 + ^Content/d2k/GAMESFX/H_ESEL2.AUD: + Offset: 18624063 + Length: 16430 + ^Content/d2k/GAMESFX/AI_MAP2C.AUD: + Offset: 18640493 + Length: 41640 + ^Content/d2k/GAMESFX/AI_MAP3A.AUD: + Offset: 18682133 + Length: 41809 + ^Content/d2k/GAMESFX/AI_MAP4A.AUD: + Offset: 18723942 + Length: 29117 + ^Content/d2k/GAMESFX/AI_MAP5A.AUD: + Offset: 18753059 + Length: 36982 + ^Content/d2k/GAMESFX/AI_MAP6A.AUD: + Offset: 18790041 + Length: 60681 + ^Content/d2k/GAMESFX/HI_BDRDY.AUD: + Offset: 18850722 + Length: 21396 + ^Content/d2k/GAMESFX/AI_MAP8A.AUD: + Offset: 18872118 + Length: 37995 + ^Content/d2k/GAMESFX/AI_MAP9A.AUD: + Offset: 18910113 + Length: 32674 + ^Content/d2k/GAMESFX/AI_MEND.AUD: + Offset: 18942787 + Length: 18399 + ^Content/d2k/GAMESFX/AI_MFAIL.AUD: + Offset: 18961186 + Length: 26359 + ^Content/d2k/GAMESFX/AI_GLOAD.AUD: + Offset: 18987545 + Length: 21335 + ^Content/d2k/GAMESFX/HI_MAP9A.AUD: + Offset: 19008880 + Length: 28418 + ^Content/d2k/GAMESFX/HI_MEND.AUD: + Offset: 19037298 + Length: 9269 + ^Content/d2k/GAMESFX/HI_MFAIL.AUD: + Offset: 19046567 + Length: 19854 + ^Content/d2k/GAMESFX/HI_MONEY.AUD: + Offset: 19066421 + Length: 20038 + ^Content/d2k/GAMESFX/HI_MWIN.AUD: + Offset: 19086459 + Length: 16073 + ^Content/d2k/GAMESFX/HI_WATTK.AUD: + Offset: 19102532 + Length: 14873 + ^Content/d2k/GAMESFX/AI_MAP1A.AUD: + Offset: 19117405 + Length: 41683 + ^Content/d2k/GAMESFX/AI_MAP1B.AUD: + Offset: 19159088 + Length: 34475 + ^Content/d2k/GAMESFX/AI_MAP1C.AUD: + Offset: 19193563 + Length: 34903 + ^Content/d2k/GAMESFX/AI_MAP2A.AUD: + Offset: 19228466 + Length: 59613 + ^Content/d2k/GAMESFX/AI_ABORT.AUD: + Offset: 19288079 + Length: 22150 + ^Content/d2k/GAMESFX/H_ESEL3.AUD: + Offset: 19310229 + Length: 9090 + ^Content/d2k/GAMESFX/AI_SILOS.AUD: + Offset: 19319319 + Length: 21350 + ^Content/d2k/GAMESFX/AI_SPORT.AUD: + Offset: 19340669 + Length: 31478 + ^Content/d2k/GAMESFX/AI_TRAIN.AUD: + Offset: 19372147 + Length: 19876 + ^Content/d2k/GAMESFX/AI_ULOST.AUD: + Offset: 19392023 + Length: 22359 + ^Content/d2k/GAMESFX/AI_MAP7A.AUD: + Offset: 19414382 + Length: 28902 + ^Content/d2k/GAMESFX/AI_UPGOP.AUD: + Offset: 19443284 + Length: 26855 + ^Content/d2k/GAMESFX/AI_UPGRD.AUD: + Offset: 19470139 + Length: 19104 + ^Content/d2k/GAMESFX/AI_WATTK.AUD: + Offset: 19489243 + Length: 24655 + ^Content/d2k/GAMESFX/AI_WSIGN.AUD: + Offset: 19513898 + Length: 23032 + ^Content/d2k/GAMESFX/AI_MAP2B.AUD: + Offset: 19536930 + Length: 35588 + ^Content/d2k/GAMESFX/A_ICONF1.AUD: + Offset: 19572518 + Length: 8945 + ^Content/d2k/GAMESFX/A_ICONF2.AUD: + Offset: 19581463 + Length: 9005 + ^Content/d2k/GAMESFX/A_ICONF3.AUD: + Offset: 19590468 + Length: 9606 + ^Content/d2k/GAMESFX/A_ISEL1.AUD: + Offset: 19600074 + Length: 11671 + ^Content/d2k/GAMESFX/OI_CANCL.AUD: + Offset: 19611745 + Length: 10644 + ^Content/d2k/GAMESFX/H_ISEL2.AUD: + Offset: 19622389 + Length: 10387 + ^Content/d2k/GAMESFX/H_ISEL3.AUD: + Offset: 19632776 + Length: 17225 + ^Content/d2k/GAMESFX/H_VCONF1.AUD: + Offset: 19650001 + Length: 10077 + ^Content/d2k/GAMESFX/H_VCONF2.AUD: + Offset: 19660078 + Length: 13616 + ^Content/d2k/GAMESFX/H_VCONF3.AUD: + Offset: 19673694 + Length: 11251 + ^Content/d2k/GAMESFX/OI_TRAIN.AUD: + Offset: 19684945 + Length: 8144 + ^Content/d2k/GAMESFX/HI_ORDER.AUD: + Offset: 19693089 + Length: 14865 + ^Content/d2k/GAMESFX/OI_WSIGN.AUD: + Offset: 19707954 + Length: 11912 + ^Content/d2k/GAMESFX/OI_BLOST.AUD: + Offset: 19719866 + Length: 19540 + ^Content/d2k/GAMESFX/OI_BUILD.AUD: + Offset: 19739406 + Length: 10246 + ^Content/d2k/GAMESFX/AI_LAUNC.AUD: + Offset: 19749652 + Length: 31148 + ^Content/d2k/GAMESFX/A_ISEL3.AUD: + Offset: 19780800 + Length: 8307 + ^Content/d2k/GAMESFX/A_VCONF2.AUD: + Offset: 19789107 + Length: 14331 + ^Content/d2k/GAMESFX/OI_HOLD.AUD: + Offset: 19803438 + Length: 11295 + ^Content/d2k/GAMESFX/OI_LAUNC.AUD: + Offset: 19814733 + Length: 20437 + ^Content/d2k/GAMESFX/OI_MAP1A.AUD: + Offset: 19835170 + Length: 27739 + ^Content/d2k/GAMESFX/HI_LAUNC.AUD: + Offset: 19862909 + Length: 22200 + ^Content/d2k/GAMESFX/H_ICONF1.AUD: + Offset: 19885109 + Length: 9620 + ^Content/d2k/GAMESFX/H_ICONF2.AUD: + Offset: 19894729 + Length: 13368 + ^Content/d2k/GAMESFX/H_ICONF3.AUD: + Offset: 19908097 + Length: 15612 + ^Content/d2k/GAMESFX/H_ISEL1.AUD: + Offset: 19923709 + Length: 8279 + ^Content/d2k/GAMESFX/A_ISEL2.AUD: + Offset: 19931988 + Length: 11383 + ^Content/d2k/GAMESFX/AI_RUN.AUD: + Offset: 19943371 + Length: 18511 + ^Content/d2k/GAMESFX/HI_SILOS.AUD: + Offset: 19961882 + Length: 14244 + ^Content/d2k/GAMESFX/HI_MAP1A.AUD: + Offset: 19976126 + Length: 24075 + ^Content/d2k/GAMESFX/HI_MAP1B.AUD: + Offset: 20000201 + Length: 26716 + ^Content/d2k/GAMESFX/HI_MAP1C.AUD: + Offset: 20026917 + Length: 21716 + ^Content/d2k/GAMESFX/HI_MAP2A.AUD: + Offset: 20048633 + Length: 32417 + ^Content/d2k/GAMESFX/HI_MAP2B.AUD: + Offset: 20081050 + Length: 33724 + ^Content/d2k/GAMESFX/HI_MAP2C.AUD: + Offset: 20114774 + Length: 21828 + ^Content/d2k/GAMESFX/HI_MAP3A.AUD: + Offset: 20136602 + Length: 30404 + ^Content/d2k/GAMESFX/O_ISEL3.AUD: + Offset: 20167006 + Length: 9862 + ^Content/d2k/GAMESFX/O_SCONF1.AUD: + Offset: 20176868 + Length: 18149 + ^Content/d2k/GAMESFX/OI_2MIN.AUD: + Offset: 20195017 + Length: 14697 + ^Content/d2k/GAMESFX/OI_3MIN.AUD: + Offset: 20209714 + Length: 17316 + ^Content/d2k/GAMESFX/OI_4MIN.AUD: + Offset: 20227030 + Length: 14869 + ^Content/d2k/GAMESFX/OI_5MIN.AUD: + Offset: 20241899 + Length: 29873 + ^Content/d2k/GAMESFX/OI_ABORT.AUD: + Offset: 20271772 + Length: 16335 + ^Content/d2k/GAMESFX/OI_ATACK.AUD: + Offset: 20288107 + Length: 20565 + ^Content/d2k/GAMESFX/OI_BDRDY.AUD: + Offset: 20308672 + Length: 25497 + ^Content/d2k/GAMESFX/HI_SELL.AUD: + Offset: 20334169 + Length: 17142 + ^Content/d2k/GAMESFX/OI_DPLOY.AUD: + Offset: 20351311 + Length: 20120 + ^Content/d2k/GAMESFX/AI_PLACE.AUD: + Offset: 20371431 + Length: 29921 + ^Content/d2k/GAMESFX/OI_GANEW.AUD: + Offset: 20401352 + Length: 14467 + ^Content/d2k/GAMESFX/OI_GLOAD.AUD: + Offset: 20415819 + Length: 10906 + ^Content/d2k/GAMESFX/AI_MWIN.AUD: + Offset: 20426725 + Length: 25959 + ^Content/d2k/GAMESFX/AI_NEWOP.AUD: + Offset: 20452684 + Length: 34175 + ^Content/d2k/GAMESFX/AI_NROOM.AUD: + Offset: 20486859 + Length: 30124 + ^Content/d2k/GAMESFX/AI_ORDER.AUD: + Offset: 20516983 + Length: 21881 + ^Content/d2k/GAMESFX/AI_UNRDY.AUD: + Offset: 20538864 + Length: 20567 + ^Content/d2k/SOUND.RS: + Offset: 20559431 + Length: 1929247 From d2d15f6980eda32820de26fcd34e1a8d0ecccf72 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 19:15:06 +0100 Subject: [PATCH 10/14] Add new content installer metadata to RA. --- mods/ra/mod.yaml | 214 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 200 insertions(+), 14 deletions(-) diff --git a/mods/ra/mod.yaml b/mods/ra/mod.yaml index 1a82d24cf8..1a8407fb10 100644 --- a/mods/ra/mod.yaml +++ b/mods/ra/mod.yaml @@ -145,20 +145,6 @@ LoadScreen: LogoStripeLoadScreen Image: ra|uibits/loadscreen.png Text: Filling Crates..., Charging Capacitors..., Reticulating Splines..., Planting Trees..., Building Bridges..., Aging Empires..., Compiling EVA..., Constructing Pylons..., Activating Skynet..., Splitting Atoms... -ContentInstaller: - TestFiles: ^Content/ra/allies.mix, ^Content/ra/conquer.mix, ^Content/ra/interior.mix, ^Content/ra/redalert.mix, ^Content/ra/russian.mix, ^Content/ra/snow.mix, ^Content/ra/sounds.mix, ^Content/ra/temperat.mix - PackageMirrorList: http://www.openra.net/packages/ra-mirrors.txt - DiskTestFiles: MAIN.MIX, INSTALL/REDALERT.MIX - PackageToExtractFromCD: MAIN.MIX - ExtractFilesFromCD: - .: conquer.mix, russian.mix, allies.mix, sounds.mix, scores.mix, snow.mix, interior.mix, temperat.mix, general.mix - CopyFilesFromCD: - .: INSTALL/REDALERT.MIX - ShippedSoundtracks: 2 - MusicPackageMirrorList: http://www.openra.net/packages/ra-music-mirrors.txt - InstallShieldCABFilePackageIds: 105 - InstallShieldCABFileIds: 116 - ServerTraits: LobbyCommands PlayerPinger @@ -234,3 +220,203 @@ GameSpeeds: OrderLatency: 6 ColorValidator: + +ModContent: + InstallPromptMessage: Red Alert requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2008 Red Alert freeware release.\n\nAdvanced Install includes options for downloading the music and for\ncopying the videos and other content from an original game disc. + QuickDownload: basefiles + HeaderMessage: The original game content may be copied from an original game disc,\nor downloaded from an online mirror of the 2008 freeware release. + Packages: + base: Base Game Files + TestFiles: ^Content/ra/allies.mix, ^Content/ra/conquer.mix, ^Content/ra/interior.mix, ^Content/ra/redalert.mix, ^Content/ra/russian.mix, ^Content/ra/snow.mix, ^Content/ra/sounds.mix, ^Content/ra/temperat.mix + Discs: allied, allied-linux, soviet, soviet-linux + Required: true + Download: basefiles + music: Base Game Music + TestFiles: ^Content/ra/scores.mix + Discs: allied, allied-linux, soviet, soviet-linux + Download: music + movies-allied: Allied Campaign Briefings + TestFiles: ^Content/ra/movies1.mix + Discs: allied, allied-linux + movies-soviet: Soviet Campaign Briefings + TestFiles: ^Content/ra/movies2.mix + Discs: soviet, soviet-linux + music-covertops: Counterstrike Music + TestFiles: ^Content/ra/scores-counterstrike.mix + Discs: counterstrike, counterstrike-linux + Downloads: + basefiles: Base Freeware Content + MirrorList: http://www.openra.net/packages/ra-mirrors.txt + Extract: + ^Content/ra/allies.mix: allies.mix + ^Content/ra/conquer.mix: conquer.mix + ^Content/ra/general.mix: general.mix + ^Content/ra/interior.mix: interior.mix + ^Content/ra/redalert.mix: redalert.mix + ^Content/ra/russian.mix: russian.mix + ^Content/ra/snow.mix: snow.mix + ^Content/ra/sounds.mix: sounds.mix + ^Content/ra/temperat.mix: temperat.mix + music: Freeware Music + MirrorList: http://www.openra.net/packages/ra-music-mirrors.txt + Extract: + ^Content/ra/scores.mix: scores.mix + Discs: + allied: Red Alert 95 (Allied Disc, English) + IDFiles: + eahelp.GID: 13a8a4a1e7d9d6d893c38df5a39262c4689aeba5 + INSTALL/REDALERT.MIX: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef + Install: + copy: INSTALL + ^Content/ra/redalert.mix: REDALERT.MIX + extract-raw: MAIN.MIX + ^Content/ra/conquer.mix: + Offset: 236 + Length: 2177047 + ^Content/ra/interior.mix: + Offset: 17172192 + Length: 247425 + ^Content/ra/movies1.mix: + Offset: 17419617 + Length: 369362336 + ^Content/ra/scores.mix: + Offset: 386781953 + Length: 64171360 + ^Content/ra/snow.mix: + Offset: 450953313 + Length: 1030861 + ^Content/ra/sounds.mix: + Offset: 451984174 + Length: 1006778 + ^Content/ra/russian.mix: + Offset: 452990952 + Length: 266077 + ^Content/ra/allies.mix: + Offset: 453257029 + Length: 309406 + ^Content/ra/temperat.mix: + Offset: 453566435 + Length: 1038859 + allied-linux: Red Alert 95 (Allied Disc, English) + IDFiles: + eahelp.gid: 13a8a4a1e7d9d6d893c38df5a39262c4689aeba5 + install/redalert.mix: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef + Install: + copy: install + ^Content/ra/redalert.mix: redalert.mix + extract-raw: main.mix + ^Content/ra/conquer.mix: + Offset: 236 + Length: 2177047 + ^Content/ra/interior.mix: + Offset: 17172192 + Length: 247425 + ^Content/ra/movies1.mix: + Offset: 17419617 + Length: 369362336 + ^Content/ra/scores.mix: + Offset: 386781953 + Length: 64171360 + ^Content/ra/snow.mix: + Offset: 450953313 + Length: 1030861 + ^Content/ra/sounds.mix: + Offset: 451984174 + Length: 1006778 + ^Content/ra/russian.mix: + Offset: 452990952 + Length: 266077 + ^Content/ra/allies.mix: + Offset: 453257029 + Length: 309406 + ^Content/ra/temperat.mix: + Offset: 453566435 + Length: 1038859 + soviet: Red Alert 95 (Soviet Disc, English) + IDFiles: + automenu.apm: bb61132a492bfb37069a0139f95671da3655d916 + INSTALL/REDALERT.MIX: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef + Install: + copy: INSTALL + ^Content/cnc/redalert.mix: REDALERT.MIX + extract-raw: MAIN.MIX + ^Content/ra/conquer.mix: + Offset: 236 + Length: 2177047 + ^Content/ra/interior.mix: + Offset: 17172192 + Length: 247425 + ^Content/ra/movies2.mix: + Offset: 17419617 + Length: 415334456 + ^Content/ra/scores.mix: + Offset: 432754073 + Length: 64171360 + ^Content/ra/snow.mix: + Offset: 496925433 + Length: 1030861 + ^Content/ra/russian.mix: + Offset: 497956294 + Length: 266077 + ^Content/ra/allies.mix: + Offset: 498222371 + Length: 309406 + ^Content/ra/sounds.mix: + Offset: 498531777 + Length: 1006778 + ^Content/ra/temperat.mix: + Offset: 499538555 + Length: 1038859 + soviet-linux: Red Alert 95 (Soviet Disc, English) + IDFiles: + automenu.apm: bb61132a492bfb37069a0139f95671da3655d916 + install/redalert.mix: 0e58f4b54f44f6cd29fecf8cf379d33cf2d4caef + Install: + copy: install + ^Content/cnc/redalert.mix: redalert.mix + extract-raw: main.mix + ^Content/ra/conquer.mix: + Offset: 236 + Length: 2177047 + ^Content/ra/interior.mix: + Offset: 17172192 + Length: 247425 + ^Content/ra/movies2.mix: + Offset: 17419617 + Length: 415334456 + ^Content/ra/scores.mix: + Offset: 432754073 + Length: 64171360 + ^Content/ra/snow.mix: + Offset: 496925433 + Length: 1030861 + ^Content/ra/russian.mix: + Offset: 497956294 + Length: 266077 + ^Content/ra/allies.mix: + Offset: 498222371 + Length: 309406 + ^Content/ra/sounds.mix: + Offset: 498531777 + Length: 1006778 + ^Content/ra/temperat.mix: + Offset: 499538555 + Length: 1038859 + counterstrike: Counterstrike Expansion (English) + IDFiles: + README.TXT: 0efe8087383f0b159a9633f891fb5f53c6097cd4 + SETUP/INSTALL/CSTRIKE.RTP: fae8ba82db71574f6ecd8fb4ff4026fcb65d2adc + Install: + extract-raw: MAIN.MIX + ^Content/ra/scores-counterstrike.mix: + Offset: 144899491 + Length: 87483135 + counterstrike-linux: Counterstrike Expansion (English) + IDFiles: + readme.txt: 0efe8087383f0b159a9633f891fb5f53c6097cd4 + setup/install/cstrike.rtp: fae8ba82db71574f6ecd8fb4ff4026fcb65d2adc + Install: + extract-raw: main.mix + ^Content/ra/scores-counterstrike.mix: + Offset: 144899491 + Length: 87483135 From 27699ce3d732ff448a15dde771c5aab5c38542b3 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Tue, 31 May 2016 22:44:16 +0100 Subject: [PATCH 11/14] Add new content installer metadata to TS. --- mods/ts/mod.yaml | 154 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 139 insertions(+), 15 deletions(-) diff --git a/mods/ts/mod.yaml b/mods/ts/mod.yaml index b4c4fd00d6..9224d242fd 100644 --- a/mods/ts/mod.yaml +++ b/mods/ts/mod.yaml @@ -1,4 +1,4 @@ -Metadata: + Metadata: Title: Tiberian Sun Description: Developer stub, not yet ready for release! Version: {DEV_VERSION} @@ -189,20 +189,6 @@ LoadScreen: LogoStripeLoadScreen Image: ts|uibits/loadscreen.png Text: Updating EVA installation..., Changing perspective... -ContentInstaller: - TestFiles: ^Content/ts/cache.mix, ^Content/ts/conquer.mix, ^Content/ts/isosnow.mix, ^Content/ts/isotemp.mix, ^Content/ts/local.mix, ^Content/ts/sidec01.mix, ^Content/ts/sidec02.mix, ^Content/ts/sno.mix, ^Content/ts/snow.mix, ^Content/ts/sounds.mix, ^Content/ts/speech01.mix, ^Content/ts/tem.mix, ^Content/ts/temperat.mix - PackageMirrorList: http://www.openra.net/packages/ts-mirrors.txt - DiskTestFiles: MULTI.MIX, INSTALL/TIBSUN.MIX - CopyFilesFromCD: - .: INSTALL/TIBSUN.MIX, SCORES.MIX, MULTI.MIX - PackageToExtractFromCD: INSTALL/TIBSUN.MIX - ExtractFilesFromCD: - .: cache.mix, conquer.mix, isosnow.mix, isotemp.mix, local.mix, sidec01.mix, sidec02.mix, sno.mix, snow.mix, sounds.mix, speech01.mix, tem.mix, temperat.mix - ShippedSoundtracks: 2 - MusicPackageMirrorList: http://www.openra.net/packages/ts-music-mirrors.txt - InstallShieldCABFilePackageIds: 332 - InstallShieldCABFileIds: 323, 364 - ServerTraits: LobbyCommands PlayerPinger @@ -272,3 +258,141 @@ GameSpeeds: OrderLatency: 6 ColorValidator: + +ModContent: + InstallPromptMessage: Tiberian Sun requires artwork and audio from the original game.\n\nQuick Install will automatically download this content (without music\nor videos) from a mirror of the 2012 Tiberian Sun freeware release.\n\nAdvanced Install includes options for downloading the music and for\ncopying the videos and other content from an original game disc. + QuickDownload: basefiles + HeaderMessage: The original game content may be copied from an original game disc,\nor downloaded from an online mirror of the 2012 freeware release. + Packages: + base: Base Game Files + TestFiles: ^Content/ts/cache.mix, ^Content/ts/conquer.mix, ^Content/ts/isosnow.mix, ^Content/ts/isotemp.mix, ^Content/ts/local.mix, ^Content/ts/sidec01.mix, ^Content/ts/sidec02.mix, ^Content/ts/sno.mix, ^Content/ts/snow.mix, ^Content/ts/sounds.mix, ^Content/ts/speech01.mix, ^Content/ts/tem.mix, ^Content/ts/temperat.mix + Discs: tibsun, tibsun-linux + Required: true + Download: basefiles + music: Base Game Music + TestFiles: ^Content/ts/scores.mix + Discs: tibsun, tibsun-linux + Download: music + Downloads: + basefiles: Base Freeware Content + MirrorList: http://www.openra.net/packages/ts-mirrors.txt + Extract: + ^Content/ts/cache.mix: cache.mix + ^Content/ts/conquer.mix: conquer.mix + ^Content/ts/isosnow.mix: isosnow.mix + ^Content/ts/isotemp.mix: isotemp.mix + ^Content/ts/local.mix: local.mix + ^Content/ts/sidec01.mix: sidec01.mix + ^Content/ts/sidec02.mix: sidec02.mix + ^Content/ts/sno.mix: sno.mix + ^Content/ts/snow.mix: snow.mix + ^Content/ts/sounds.mix: sounds.mix + ^Content/ts/speech01.mix: speech01.mix + ^Content/ts/speech02.mix: speech02.mix + ^Content/ts/tem.mix: tem.mix + ^Content/ts/temperat.mix: temperat.mix + music: Freeware Music + MirrorList: http://www.openra.net/packages/ts-music-mirrors.txt + Extract: + ^Content/ts/scores.mix: scores.mix + Discs: + tibsun: Tiberan Sun (GDI or Nod Disc, English) + IDFiles: + README.TXT: 45745c4a0c888317ec900208a426472779c42bf7 + AUTOPLAY.WAV: 2dfce5d00f98b641849c29942b651f4e98d30e30 + Install: + copy: . + ^Content/ts/scores.mix: SCORES.MIX + extract-raw: INSTALL/TIBSUN.MIX + ^Content/ts/cache.mix: + Offset: 300 + Length: 169176 + ^Content/ts/conquer.mix: + Offset: 169484 + Length: 5700088 + ^Content/ts/isosnow.mix: + Offset: 5869580 + Length: 7624750 + ^Content/ts/isotemp.mix: + Offset: 13494332 + Length: 8617646 + ^Content/ts/local.mix: + Offset: 22111980 + Length: 18044736 + ^Content/ts/sidec01.mix: + Offset: 40156716 + Length: 998476 + ^Content/ts/sidec02.mix: + Offset: 41155196 + Length: 1039996 + ^Content/ts/snow.mix: + Offset: 56104508 + Length: 2087806 + ^Content/ts/sno.mix: + Offset: 58192316 + Length: 7826 + ^Content/ts/sounds.mix: + Offset: 58200156 + Length: 3224136 + ^Content/ts/speech01.mix: + Offset: 61424300 + Length: 6028236 + ^Content/ts/speech02.mix: + Offset: 67452540 + Length: 5596628 + ^Content/ts/tem.mix: + Offset: 73049180 + Length: 7746 + ^Content/ts/temperat.mix: + Offset: 73056940 + Length: 2037606 + tibsun-linux: Tiberan Sun (GDI or Nod Disc, English) + IDFiles: + readme.txt: 45745c4a0c888317ec900208a426472779c42bf7 + autoplay.wav: 2dfce5d00f98b641849c29942b651f4e98d30e30 + Install: + copy: . + ^Content/ts/scores.mix: scores.mix + extract-raw: install/tibsun.mix + ^Content/ts/cache.mix: + Offset: 300 + Length: 169176 + ^Content/ts/conquer.mix: + Offset: 169484 + Length: 5700088 + ^Content/ts/isosnow.mix: + Offset: 5869580 + Length: 7624750 + ^Content/ts/isotemp.mix: + Offset: 13494332 + Length: 8617646 + ^Content/ts/local.mix: + Offset: 22111980 + Length: 18044736 + ^Content/ts/sidec01.mix: + Offset: 40156716 + Length: 998476 + ^Content/ts/sidec02.mix: + Offset: 41155196 + Length: 1039996 + ^Content/ts/snow.mix: + Offset: 56104508 + Length: 2087806 + ^Content/ts/sno.mix: + Offset: 58192316 + Length: 7826 + ^Content/ts/sounds.mix: + Offset: 58200156 + Length: 3224136 + ^Content/ts/speech01.mix: + Offset: 61424300 + Length: 6028236 + ^Content/ts/speech02.mix: + Offset: 67452540 + Length: 5596628 + ^Content/ts/tem.mix: + Offset: 73049180 + Length: 7746 + ^Content/ts/temperat.mix: + Offset: 73056940 + Length: 2037606 From 0b97a81616a8f9e7c87220ab93e99f92eed46c0c Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 01:34:22 +0100 Subject: [PATCH 12/14] Remove legacy music installer. --- .../LoadScreens/ModChooserLoadScreen.cs | 9 +- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 1 - .../Logic/Installation/InstallMusicLogic.cs | 60 ----------- .../Widgets/Logic/MusicPlayerLogic.cs | 12 --- mods/cnc/chrome/lobby-music.yaml | 20 ++-- mods/cnc/chrome/music.yaml | 100 +++++------------- mods/modchooser/install.yaml | 66 ------------ mods/ra/chrome/lobby-music.yaml | 20 ++-- mods/ra/chrome/musicplayer.yaml | 92 +++++----------- 9 files changed, 84 insertions(+), 296 deletions(-) delete mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/InstallMusicLogic.cs diff --git a/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs b/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs index 4ac0df895e..99c24ee948 100644 --- a/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs +++ b/OpenRA.Mods.Common/LoadScreens/ModChooserLoadScreen.cs @@ -50,14 +50,7 @@ namespace OpenRA.Mods.Common.LoadScreens var widgetArgs = new WidgetArgs(); Ui.LoadWidget("MODCHOOSER_BACKGROUND", Ui.Root, widgetArgs); - - if (args != null && args.Contains("installMusic")) - { - widgetArgs.Add("modId", args.GetValue("installMusic", "")); - Ui.OpenWindow("INSTALL_MUSIC_PANEL", widgetArgs); - } - else - Ui.OpenWindow("MODCHOOSER_DIALOG", widgetArgs); + Ui.OpenWindow("MODCHOOSER_DIALOG", widgetArgs); } public void Dispose() diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 89ad221f3e..cfd2d52455 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -614,7 +614,6 @@ - diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallMusicLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallMusicLogic.cs deleted file mode 100644 index d8efc53be5..0000000000 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallMusicLogic.cs +++ /dev/null @@ -1,60 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using OpenRA.Widgets; - -namespace OpenRA.Mods.Common.Widgets.Logic -{ - public class InstallMusicLogic : ChromeLogic - { - [ObjectCreator.UseCtor] - public InstallMusicLogic(Widget widget, string modId) - { - var installMusicContainer = widget.Get("INSTALL_MUSIC_PANEL"); - - Action loadDefaultMod = () => Game.RunAfterTick(() => Game.InitializeMod(modId, null)); - - var cancelButton = installMusicContainer.GetOrNull("BACK_BUTTON"); - if (cancelButton != null) - cancelButton.OnClick = loadDefaultMod; - - var copyFromDiscButton = installMusicContainer.GetOrNull("INSTALL_MUSIC_BUTTON"); - if (copyFromDiscButton != null) - { - copyFromDiscButton.OnClick = () => - { - Ui.OpenWindow("INSTALL_FROMCD_PANEL", new WidgetArgs - { - { "afterInstall", loadDefaultMod }, - { "modId", modId } - }); - }; - } - - var downloadButton = installMusicContainer.GetOrNull("DOWNLOAD_MUSIC_BUTTON"); - if (downloadButton != null) - { - var installData = ModMetadata.AllMods[modId].Content; - downloadButton.IsDisabled = () => string.IsNullOrEmpty(installData.MusicPackageMirrorList); - downloadButton.OnClick = () => - { - Ui.OpenWindow("INSTALL_DOWNLOAD_PANEL", new WidgetArgs - { - { "afterInstall", loadDefaultMod }, - { "mirrorListUrl", installData.MusicPackageMirrorList }, - { "modId", modId } - }); - }; - } - } - } -} diff --git a/OpenRA.Mods.Common/Widgets/Logic/MusicPlayerLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/MusicPlayerLogic.cs index 3274f9a060..80b35f227b 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/MusicPlayerLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/MusicPlayerLogic.cs @@ -103,18 +103,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic musicSlider.OnChange += x => Game.Sound.MusicVolume = x; musicSlider.Value = Game.Sound.MusicVolume; - var installButton = widget.GetOrNull("INSTALL_BUTTON"); - if (installButton != null) - { - installButton.IsDisabled = () => world.Type != WorldType.Shellmap; - var args = new[] { "installMusic={0}".F(modData.Manifest.Mod.Id) }; - installButton.OnClick = () => - Game.RunAfterTick(() => Game.InitializeMod("modchooser", new Arguments(args))); - - var installData = modData.Manifest.Get(); - installButton.IsVisible = () => modData.DefaultRules.InstalledMusic.ToArray().Length <= installData.ShippedSoundtracks; - } - var songWatcher = widget.GetOrNull("SONG_WATCHER"); if (songWatcher != null) { diff --git a/mods/cnc/chrome/lobby-music.yaml b/mods/cnc/chrome/lobby-music.yaml index 8ec356ded0..0786683670 100644 --- a/mods/cnc/chrome/lobby-music.yaml +++ b/mods/cnc/chrome/lobby-music.yaml @@ -170,21 +170,27 @@ Container@LOBBY_MUSIC_BIN: Visible: false Children: Label@TITLE: - Y: 75 + Y: 65 Width: PARENT_RIGHT-24 Height: 25 Font: Bold Align: Center - Text: No Music Available + Text: Music Not Installed Label@DESCA: - Y: 95 + Y: 85 Width: PARENT_RIGHT-24 Height: 25 Align: Center - Text: Music can be installed from the - Label@DESCA: - Y: 115 + Text: The game music can be installed + Label@DESCB: + Y: 105 Width: PARENT_RIGHT-24 Height: 25 Align: Center - Text: game Extras menu. + Text: from the "Manage Content" menu + Label@DESCC: + Y: 125 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: in the mod chooser. diff --git a/mods/cnc/chrome/music.yaml b/mods/cnc/chrome/music.yaml index a2225bb305..f9c8931b21 100644 --- a/mods/cnc/chrome/music.yaml +++ b/mods/cnc/chrome/music.yaml @@ -154,15 +154,37 @@ Container@MUSIC_PANEL: Height: 20 Font: Regular Text: Loop - Label@NO_MUSIC_LABEL: + Container@NO_MUSIC_LABEL: X: 15 - Y: 147 + Y: 120 Width: 330 - Height: 25 - Font: Bold - Align: Center + Height: 80 Visible: false - Text: No Music Installed + Children: + Label@TITLE: + Width: PARENT_RIGHT-24 + Height: 25 + Font: Bold + Align: Center + Text: Music Not Installed + Label@DESCA: + Y: 20 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: The game music can be installed + Label@DESCB: + Y: 40 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: from the "Manage Content" menu + Label@DESCC: + Y: 60 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: in the mod chooser. Button@BACK_BUTTON: Key: escape X: 0 @@ -170,73 +192,9 @@ Container@MUSIC_PANEL: Width: 140 Height: 35 Text: Back - Button@INSTALL_BUTTON: - X: 220 - Y: 399 - Width: 140 - Height: 35 - Text: Install Music Label@MUTE_LABEL: X: 165 Y: 399 Width: 300 Height: 20 - Font: Small - -Container@INSTALL_MUSIC_PANEL: - Logic: InstallMusicLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - 150)/2 - Width: 640 - Height: 150 - Children: - Label@TITLE: - Width: PARENT_RIGHT - Y: 0-25 - Font: BigBold - Contrast: true - Align: Center - Text: Install Music - Background@bg: - Width: 640 - Height: 150 - Background: panel-black - Children: - Image@INSTALL: - X: 11 - Y: 11 - ImageCollection: logos - ImageName: install - Label@INFO: - X: 170 - Y: 35 - Width: PARENT_RIGHT-30 - Height: 25 - Text: The soundtrack is currently unavailable. - Font: Bold - Label@INFO2: - X: 170 - Y: 70 - Width: PARENT_RIGHT-185 - Height: 25 - WordWrap: true - Text: OpenRA can download the music files from the internet, or you can install from the original C&C CDs. - Font: Bold - Button@CANCEL_BUTTON: - Key: escape - Y: 149 - Width: 140 - Height: 35 - Text: Back - Button@DOWNLOAD_BUTTON: - X: 350 - Y: 149 - Width: 140 - Height: 35 - Text: Download - Button@COPY_FROM_CD_BUTTON: - X: 500 - Y: 149 - Width: 140 - Height: 35 - Text: Use CD + Font: Small \ No newline at end of file diff --git a/mods/modchooser/install.yaml b/mods/modchooser/install.yaml index 7f8d32093d..655c9ea1b1 100644 --- a/mods/modchooser/install.yaml +++ b/mods/modchooser/install.yaml @@ -194,69 +194,3 @@ Container@INSTALL_FROMCD_PANEL: Text: Back Font: Bold Key: escape - - -Container@INSTALL_MUSIC_PANEL: - Logic: InstallMusicLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 500 - Height: 177 - Children: - Background: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Background: panel-bg - Background@RULE: - X: 30 - Y: 50 - Width: 440 - Height:150 - Background:panel-rule - Label@TITLE: - X: 0 - Y: 12 - Width: PARENT_RIGHT - Height: 25 - Text: Install Music - Align: Center - Font: MediumBold - Label@DESC1: - X: 0 - Y: 65 - Width: PARENT_RIGHT - Height: 25 - Text: OpenRA can download the music files from the internet (if available), - Align: Center - Label@DESC2: - X: 0 - Y: 85 - Width: PARENT_RIGHT - Height: 25 - Text: or you can install them from an original CD. - Align: Center - Button@DOWNLOAD_MUSIC_BUTTON: - X: 20 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Download - Font: Bold - Button@INSTALL_MUSIC_BUTTON: - X: 140 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Use CD - Font: Bold - Button@BACK_BUTTON: - X: PARENT_RIGHT - 130 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Back - Font: Bold - Key: escape diff --git a/mods/ra/chrome/lobby-music.yaml b/mods/ra/chrome/lobby-music.yaml index eeb7d95377..864c9ce5bf 100644 --- a/mods/ra/chrome/lobby-music.yaml +++ b/mods/ra/chrome/lobby-music.yaml @@ -160,21 +160,27 @@ Container@LOBBY_MUSIC_BIN: Visible: false Children: Label@TITLE: - Y: 75 + Y: 65 Width: PARENT_RIGHT-24 Height: 25 Font: Bold Align: Center - Text: No Music Available + Text: Music Not Installed Label@DESCA: - Y: 95 + Y: 85 Width: PARENT_RIGHT-24 Height: 25 Align: Center - Text: Music can be installed from the - Label@DESCA: - Y: 115 + Text: The game music can be installed + Label@DESCB: + Y: 105 Width: PARENT_RIGHT-24 Height: 25 Align: Center - Text: game Extras menu. + Text: from the "Manage Content" menu + Label@DESCC: + Y: 125 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: in the mod chooser. diff --git a/mods/ra/chrome/musicplayer.yaml b/mods/ra/chrome/musicplayer.yaml index 04a29cd8cc..fc6290bf01 100644 --- a/mods/ra/chrome/musicplayer.yaml +++ b/mods/ra/chrome/musicplayer.yaml @@ -141,22 +141,37 @@ Background@MUSIC_PANEL: Width: 70 Height: 20 Text: Loop - Label@NO_MUSIC_LABEL: + Container@NO_MUSIC_LABEL: X: 15 - Y: 147 + Y: 135 Width: 330 - Height: 25 - Font: Bold - Align: Center + Height: 80 Visible: false - Text: No Music Installed - Button@INSTALL_BUTTON: - X: 20 - Y: PARENT_BOTTOM - 45 - Width: 120 - Height: 25 - Text: Install Music - Font: Bold + Children: + Label@TITLE: + Width: PARENT_RIGHT-24 + Height: 25 + Font: Bold + Align: Center + Text: Music Not Installed + Label@DESCA: + Y: 20 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: The game music can be installed + Label@DESCB: + Y: 40 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: from the "Manage Content" menu + Label@DESCC: + Y: 60 + Width: PARENT_RIGHT-24 + Height: 25 + Align: Center + Text: in the mod chooser. Button@BACK_BUTTON: X: PARENT_RIGHT - 140 Y: PARENT_BOTTOM - 45 @@ -171,54 +186,3 @@ Background@MUSIC_PANEL: Width: 300 Height: 20 Font: Small - -Background@INSTALL_MUSIC_PANEL: - Logic: InstallMusicLogic - 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: Install Music - Align: Center - Font: Bold - Label@DESC1: - X: 0 - Y: 50 - Width: PARENT_RIGHT - Height: 25 - Text: The soundtrack is currently unavailable. - Align: Center - Label@DESC2: - X: 0 - Y: 70 - Width: PARENT_RIGHT - Height: 25 - Text: Please choose an installation method. - Align: Center - Button@COPY_FROM_CD_BUTTON: - X: 20 - Y: PARENT_BOTTOM - 45 - Width: 110 - Height: 25 - Text: Use CD - Font: Bold - Button@DOWNLOAD_BUTTON: - X: 140 - Y: PARENT_BOTTOM - 45 - Width: 110 - Height: 25 - Text: Download - Font: Bold - Button@CANCEL_BUTTON: - X: PARENT_RIGHT - 130 - Y: PARENT_BOTTOM - 45 - Width: 110 - Height: 25 - Text: Back - Font: Bold From 3585d8afd47b9bd18452b98c01f15b936d2021a2 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 12:46:32 +0100 Subject: [PATCH 13/14] Remove legacy installation logic. --- OpenRA.Game/ContentInstaller.cs | 43 ---- OpenRA.Game/Game.cs | 6 +- OpenRA.Game/ModMetadata.cs | 4 - OpenRA.Game/OpenRA.Game.csproj | 1 - OpenRA.Mods.Common/InstallUtils.cs | 189 --------------- OpenRA.Mods.Common/OpenRA.Mods.Common.csproj | 4 - .../Traits/World/MusicPlaylist.cs | 6 +- .../Installation/DownloadPackagesLogic.cs | 159 ------------- .../Logic/Installation/InstallFromCDLogic.cs | 218 ------------------ .../Logic/Installation/InstallLogic.cs | 44 ---- .../Widgets/Logic/ModBrowserLogic.cs | 31 +-- mods/modchooser/install.yaml | 196 ---------------- mods/modchooser/mod.yaml | 1 - 13 files changed, 15 insertions(+), 887 deletions(-) delete mode 100644 OpenRA.Game/ContentInstaller.cs delete mode 100644 OpenRA.Mods.Common/InstallUtils.cs delete mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackagesLogic.cs delete mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs delete mode 100644 OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs delete mode 100644 mods/modchooser/install.yaml diff --git a/OpenRA.Game/ContentInstaller.cs b/OpenRA.Game/ContentInstaller.cs deleted file mode 100644 index 7847ccfbdd..0000000000 --- a/OpenRA.Game/ContentInstaller.cs +++ /dev/null @@ -1,43 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System.Collections.Generic; -using System.IO; -using System.Linq; - -namespace OpenRA -{ - // Referenced from ModMetadata, so needs to be in OpenRA.Game :( - public class ContentInstaller : IGlobalModData - { - public enum FilenameCase { Input, ForceLower, ForceUpper } - - public readonly string[] TestFiles = { }; - public readonly string[] DiskTestFiles = { }; - public readonly string PackageToExtractFromCD = null; - public readonly bool OverwriteFiles = true; - - public readonly FilenameCase OutputFilenameCase = FilenameCase.ForceLower; - public readonly Dictionary CopyFilesFromCD = new Dictionary(); - public readonly Dictionary ExtractFilesFromCD = new Dictionary(); - - public readonly string PackageMirrorList = null; - - public readonly string MusicPackageMirrorList = null; - public readonly int ShippedSoundtracks = 0; - - ///

InstallShield .CAB file IDs, used to extract Mod-specific files. - public readonly HashSet InstallShieldCABFileIds = new HashSet(); - - /// InstallShield .CAB file IDs, used to extract Mod-specific archives and extract contents of ExtractFilesFromCD. - public readonly HashSet InstallShieldCABFilePackageIds = new HashSet(); - } -} diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 0e669f5c74..ea17fed72d 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -344,8 +344,10 @@ namespace OpenRA using (new PerfTimer("LoadMaps")) ModData.MapCache.LoadMaps(); - var installData = ModData.Manifest.Get(); - var isModContentInstalled = installData.TestFiles.All(f => File.Exists(Platform.ResolvePath(f))); + var content = ModData.Manifest.Get(); + var isModContentInstalled = content.Packages + .Where(p => p.Value.Required) + .All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f)))); // Mod assets are missing! if (!isModContentInstalled) diff --git a/OpenRA.Game/ModMetadata.cs b/OpenRA.Game/ModMetadata.cs index 12c95206b5..a85728d426 100644 --- a/OpenRA.Game/ModMetadata.cs +++ b/OpenRA.Game/ModMetadata.cs @@ -30,7 +30,6 @@ namespace OpenRA public bool Hidden; public Dictionary RequiresMods; - public ContentInstaller Content; public ModContent ModContent; public IReadOnlyPackage Package; @@ -79,9 +78,6 @@ namespace OpenRA else metadata.RequiresMods = new Dictionary(); - if (nd.ContainsKey("ContentInstaller")) - metadata.Content = FieldLoader.Load(nd["ContentInstaller"]); - if (nd.ContainsKey("ModContent")) metadata.ModContent = FieldLoader.Load(nd["ModContent"]); diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index 3679465ac8..060a15d2ab 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -103,7 +103,6 @@ - diff --git a/OpenRA.Mods.Common/InstallUtils.cs b/OpenRA.Mods.Common/InstallUtils.cs deleted file mode 100644 index 8486133cb4..0000000000 --- a/OpenRA.Mods.Common/InstallUtils.cs +++ /dev/null @@ -1,189 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using ICSharpCode.SharpZipLib; -using ICSharpCode.SharpZipLib.Zip; -using OpenRA.FileSystem; - -namespace OpenRA.Mods.Common -{ - public static class InstallUtils - { - static IEnumerable GetEntries(this ZipInputStream z) - { - for (;;) - { - var e = z.GetNextEntry(); - if (e != null) yield return e; else break; - } - } - - public static string GetMountedDisk(Func isValidDisk) - { - var volumes = DriveInfo.GetDrives() - .Where(v => v.DriveType == DriveType.CDRom && v.IsReady) - .Select(v => v.RootDirectory.FullName); - - return volumes.FirstOrDefault(isValidDisk); - } - - static string GetFileName(string path, ContentInstaller.FilenameCase caseModifier) - { - // Gets the file path, splitting on both / and \ - var index = path.LastIndexOfAny(new[] { '\\', '/' }); - var output = path.Substring(index + 1); - - switch (caseModifier) - { - case ContentInstaller.FilenameCase.ForceLower: - return output.ToLowerInvariant(); - case ContentInstaller.FilenameCase.ForceUpper: - return output.ToUpperInvariant(); - default: - return output; - } - } - - // TODO: The package should be mounted into its own context to avoid name collisions with installed files - public static bool ExtractFromPackage(FileSystem.FileSystem fileSystem, string srcPath, string package, Dictionary filesByDirectory, - string destPath, bool overwrite, ContentInstaller.FilenameCase caseModifier, Action onProgress, Action onError) - { - Directory.CreateDirectory(destPath); - - Log.Write("debug", "Mounting {0}".F(srcPath)); - fileSystem.Mount(srcPath); - Log.Write("debug", "Mounting {0}".F(package)); - fileSystem.Mount(package); - - foreach (var directory in filesByDirectory) - { - var targetDir = directory.Key; - - foreach (var file in directory.Value) - { - var containingDir = Path.Combine(destPath, targetDir); - var dest = Path.Combine(containingDir, GetFileName(file, caseModifier)); - if (File.Exists(dest)) - { - if (overwrite) - File.Delete(dest); - else - { - Log.Write("debug", "Skipping {0}".F(dest)); - continue; - } - } - - Directory.CreateDirectory(containingDir); - - using (var sourceStream = fileSystem.Open(file)) - using (var destStream = File.Create(dest)) - { - Log.Write("debug", "Extracting {0} to {1}".F(file, dest)); - onProgress("Extracting " + file); - destStream.Write(sourceStream.ReadAllBytes()); - } - } - } - - return true; - } - - public static bool CopyFiles(string srcPath, Dictionary files, string destPath, - bool overwrite, ContentInstaller.FilenameCase caseModifier, Action onProgress, Action onError) - { - Directory.CreateDirectory(destPath); - - foreach (var folder in files) - { - var targetDir = folder.Key; - - foreach (var file in folder.Value) - { - var sourcePath = Path.Combine(srcPath, file); - if (!File.Exists(sourcePath)) - { - onError("Cannot find " + file); - return false; - } - - var destFile = GetFileName(file, caseModifier); - var containingDir = Path.Combine(destPath, targetDir); - var dest = Path.Combine(containingDir, destFile); - if (File.Exists(dest) && !overwrite) - { - Log.Write("debug", "Skipping {0}".F(dest)); - continue; - } - - Directory.CreateDirectory(containingDir); - - onProgress("Copying " + destFile); - Log.Write("debug", "Copy {0} to {1}".F(sourcePath, dest)); - File.Copy(sourcePath, dest, true); - } - } - - return true; - } - - public static bool ExtractZip(string zipFile, string dest, Action onProgress, Action onError) - { - if (!File.Exists(zipFile)) - { - onError("Invalid path: " + zipFile); - return false; - } - - var extracted = new List(); - try - { - using (var stream = File.OpenRead(zipFile)) - using (var z = new ZipInputStream(stream)) - z.ExtractZip(dest, extracted, s => onProgress("Extracting " + s)); - } - catch (SharpZipBaseException) - { - foreach (var f in extracted) - File.Delete(f); - - onError("Invalid archive"); - return false; - } - - return true; - } - - // TODO: this belongs in FileSystem/ZipFile - static void ExtractZip(this ZipInputStream z, string destPath, List extracted, Action onProgress) - { - foreach (var entry in z.GetEntries()) - { - if (!entry.IsFile) continue; - - onProgress(entry.Name); - - Directory.CreateDirectory(Path.Combine(destPath, Path.GetDirectoryName(entry.Name))); - var path = Path.Combine(destPath, entry.Name); - extracted.Add(path); - - using (var f = File.Create(path)) - z.CopyTo(f); - } - - z.Close(); - } - } -} diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index cfd2d52455..b101e1b150 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -610,10 +610,7 @@ - - - @@ -661,7 +658,6 @@ - diff --git a/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs b/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs index ab6122f3a8..3510b733b8 100644 --- a/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs +++ b/OpenRA.Mods.Common/Traits/World/MusicPlaylist.cs @@ -74,10 +74,8 @@ namespace OpenRA.Mods.Common.Traits } else { - // Start playback with a random song, but only if the player has installed more music - var installData = Game.ModData.Manifest.Get(); - if (playlist.Length > installData.ShippedSoundtracks) - currentSong = random.FirstOrDefault(); + // Start playback with a random song + currentSong = random.FirstOrDefault(); } if (SongExists(info.StartingMusic)) diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackagesLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackagesLogic.cs deleted file mode 100644 index 0101ddb27c..0000000000 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/DownloadPackagesLogic.cs +++ /dev/null @@ -1,159 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.ComponentModel; -using System.IO; -using System.Net; -using System.Text; -using OpenRA.Support; -using OpenRA.Widgets; - -namespace OpenRA.Mods.Common.Widgets.Logic -{ - public class DownloadPackagesLogic : ChromeLogic - { - static readonly string[] SizeSuffixes = { "bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" }; - readonly Widget panel; - readonly string modId; - readonly string mirrorListUrl; - readonly ProgressBarWidget progressBar; - readonly LabelWidget statusLabel; - readonly Action afterInstall; - string mirror; - - [ObjectCreator.UseCtor] - public DownloadPackagesLogic(Widget widget, Action afterInstall, string mirrorListUrl, string modId) - { - this.mirrorListUrl = mirrorListUrl; - this.afterInstall = afterInstall; - this.modId = modId; - - panel = widget.Get("INSTALL_DOWNLOAD_PANEL"); - progressBar = panel.Get("PROGRESS_BAR"); - statusLabel = panel.Get("STATUS_LABEL"); - - var text = "Downloading {0} assets...".F(ModMetadata.AllMods[modId].Title); - panel.Get("TITLE").Text = text; - - ShowDownloadDialog(); - } - - void ShowDownloadDialog() - { - statusLabel.GetText = () => "Fetching list of mirrors..."; - progressBar.Indeterminate = true; - - var retryButton = panel.Get("RETRY_BUTTON"); - retryButton.IsVisible = () => false; - - var cancelButton = panel.Get("CANCEL_BUTTON"); - - var file = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - var dest = Platform.ResolvePath("^", "Content", modId); - - Action onDownloadProgress = i => - { - var dataReceived = 0.0f; - var dataTotal = 0.0f; - var mag = 0; - var dataSuffix = ""; - - if (i.TotalBytesToReceive < 0) - { - dataTotal = float.NaN; - dataReceived = i.BytesReceived; - dataSuffix = SizeSuffixes[0]; - } - else - { - mag = (int)Math.Log(i.TotalBytesToReceive, 1024); - dataTotal = i.TotalBytesToReceive / (float)(1L << (mag * 10)); - dataReceived = i.BytesReceived / (float)(1L << (mag * 10)); - dataSuffix = SizeSuffixes[mag]; - } - - progressBar.Indeterminate = false; - progressBar.Percentage = i.ProgressPercentage; - - statusLabel.GetText = () => "Downloading from {4} {1:0.00}/{2:0.00} {3} ({0}%)".F(i.ProgressPercentage, - dataReceived, dataTotal, dataSuffix, - mirror != null ? new Uri(mirror).Host : "unknown host"); - }; - - Action onExtractProgress = s => Game.RunAfterTick(() => statusLabel.GetText = () => s); - - Action onError = s => Game.RunAfterTick(() => - { - statusLabel.GetText = () => "Error: " + s; - retryButton.IsVisible = () => true; - }); - - Action onDownloadComplete = (i, cancelled) => - { - if (i.Error != null) - { - onError(Download.FormatErrorMessage(i.Error)); - return; - } - - if (cancelled) - { - onError("Download cancelled"); - return; - } - - // Automatically extract - statusLabel.GetText = () => "Extracting..."; - progressBar.Indeterminate = true; - if (InstallUtils.ExtractZip(file, dest, onExtractProgress, onError)) - { - Game.RunAfterTick(() => - { - Ui.CloseWindow(); - afterInstall(); - }); - } - }; - - Action onFetchMirrorsComplete = (i, cancelled) => - { - progressBar.Indeterminate = true; - - if (i.Error != null) - { - onError(Download.FormatErrorMessage(i.Error)); - return; - } - - if (cancelled) - { - onError("Download cancelled"); - return; - } - - var data = Encoding.UTF8.GetString(i.Result); - var mirrorList = data.Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries); - mirror = mirrorList.Random(new MersenneTwister()); - - // Save the package to a temp file - var dl = new Download(mirror, file, onDownloadProgress, onDownloadComplete); - cancelButton.OnClick = () => { dl.Cancel(); Ui.CloseWindow(); }; - retryButton.OnClick = () => { dl.Cancel(); ShowDownloadDialog(); }; - }; - - // Get the list of mirrors - var updateMirrors = new Download(mirrorListUrl, onDownloadProgress, onFetchMirrorsComplete); - cancelButton.OnClick = () => { updateMirrors.Cancel(); Ui.CloseWindow(); }; - retryButton.OnClick = () => { updateMirrors.Cancel(); ShowDownloadDialog(); }; - } - } -} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs deleted file mode 100644 index e1de4d41fb..0000000000 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs +++ /dev/null @@ -1,218 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using System.IO; -using System.Linq; -using System.Threading; -using OpenRA.FileSystem; -using OpenRA.Widgets; - -namespace OpenRA.Mods.Common.Widgets.Logic -{ - public class InstallFromCDLogic : ChromeLogic - { - readonly ModData modData; - readonly string modId; - readonly Widget panel; - readonly ProgressBarWidget progressBar; - readonly LabelWidget statusLabel; - readonly Action afterInstall; - readonly ButtonWidget retryButton, backButton; - readonly Widget installingContainer, insertDiskContainer; - readonly ContentInstaller installData; - - [ObjectCreator.UseCtor] - public InstallFromCDLogic(Widget widget, ModData modData, Action afterInstall, string modId) - { - this.modData = modData; - this.modId = modId; - installData = ModMetadata.AllMods[modId].Content; - this.afterInstall = afterInstall; - panel = widget.Get("INSTALL_FROMCD_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 = CheckForDisk; - - installingContainer = panel.Get("INSTALLING"); - insertDiskContainer = panel.Get("INSERT_DISK"); - CheckForDisk(); - } - - bool IsValidDisk(string diskRoot) - { - return installData.DiskTestFiles.All(f => File.Exists(Path.Combine(diskRoot, f))); - } - - bool IsTFD(string diskpath) - { - var test = File.Exists(Path.Combine(diskpath, "data1.hdr")); - var i = 0; - - while (test && i < 14) - test &= File.Exists(Path.Combine(diskpath, "data{0}.cab".F(++i))); - - return test; - } - - void CheckForDisk() - { - var path = InstallUtils.GetMountedDisk(IsValidDisk); - - if (path != null) - Install(path); - else if ((installData.InstallShieldCABFileIds.Count != 0 || installData.InstallShieldCABFilePackageIds.Count != 0) - && (path = InstallUtils.GetMountedDisk(IsTFD)) != null) - InstallTFD(Platform.ResolvePath(path, "data1.hdr")); - else - { - var text = "Please insert a {0} install CD and click Retry.".F(ModMetadata.AllMods[modId].Title); - insertDiskContainer.Get("INFO2").Text = text; - - insertDiskContainer.IsVisible = () => true; - installingContainer.IsVisible = () => false; - } - } - - void InstallTFD(string source) - { - backButton.IsDisabled = () => true; - retryButton.IsDisabled = () => true; - insertDiskContainer.IsVisible = () => false; - installingContainer.IsVisible = () => true; - progressBar.Percentage = 0; - - new Thread(() => - { - using (var cabExtractor = new InstallShieldCABExtractor(modData.ModFiles, source)) - { - var denom = installData.InstallShieldCABFileIds.Count; - var extractFiles = installData.ExtractFilesFromCD; - - if (installData.InstallShieldCABFilePackageIds.Count > 0) - denom += extractFiles.SelectMany(x => x.Value).Count(); - - var installPercent = 100 / denom; - - foreach (uint index in installData.InstallShieldCABFileIds) - { - var filename = cabExtractor.FileName(index); - statusLabel.GetText = () => "Extracting {0}".F(filename); - var dest = Platform.ResolvePath("^", "Content", modId, filename.ToLowerInvariant()); - cabExtractor.ExtractFile(index, dest); - progressBar.Percentage += installPercent; - } - - var ArchivesToExtract = installData.InstallShieldCABFilePackageIds.Select(x => x.Split(':')); - var destDir = Platform.ResolvePath("^", "Content", modId); - var onError = (Action)(s => { }); - var overwrite = installData.OverwriteFiles; - - var onProgress = (Action)(s => Game.RunAfterTick(() => - { - progressBar.Percentage += installPercent; - - statusLabel.GetText = () => s; - })); - - foreach (var archive in ArchivesToExtract) - { - var filename = cabExtractor.FileName(uint.Parse(archive[0])); - statusLabel.GetText = () => "Extracting {0}".F(filename); - var destFile = Platform.ResolvePath("^", "Content", modId, filename.ToLowerInvariant()); - cabExtractor.ExtractFile(uint.Parse(archive[0]), destFile); - InstallUtils.ExtractFromPackage(modData.ModFiles, source, destFile, extractFiles, destDir, overwrite, installData.OutputFilenameCase, onProgress, onError); - progressBar.Percentage += installPercent; - } - } - - Game.RunAfterTick(() => - { - Ui.CloseWindow(); - afterInstall(); - }); - }) { IsBackground = true }.Start(); - } - - void Install(string source) - { - backButton.IsDisabled = () => true; - retryButton.IsDisabled = () => true; - insertDiskContainer.IsVisible = () => false; - installingContainer.IsVisible = () => true; - var dest = Platform.ResolvePath("^", "Content", modId); - var copyFiles = installData.CopyFilesFromCD; - - var packageToExtract = installData.PackageToExtractFromCD.Split(':'); - var extractPackage = packageToExtract.First(); - - var extractFiles = installData.ExtractFilesFromCD; - - var overwrite = installData.OverwriteFiles; - var installCounter = 0; - var installTotal = copyFiles.SelectMany(x => x.Value).Count() + extractFiles.SelectMany(x => x.Value).Count(); - var onProgress = (Action)(s => Game.RunAfterTick(() => - { - progressBar.Percentage = installCounter * 100 / installTotal; - installCounter++; - - statusLabel.GetText = () => s; - })); - - var onError = (Action)(s => Game.RunAfterTick(() => - { - statusLabel.GetText = () => "Error: " + s; - backButton.IsDisabled = () => false; - retryButton.IsDisabled = () => false; - })); - - new Thread(() => - { - try - { - if (!InstallUtils.CopyFiles(source, copyFiles, dest, overwrite, installData.OutputFilenameCase, onProgress, onError)) - { - onError("Copying files from CD failed."); - return; - } - - if (!string.IsNullOrEmpty(extractPackage)) - { - if (!InstallUtils.ExtractFromPackage(modData.ModFiles, source, extractPackage, extractFiles, dest, - overwrite, installData.OutputFilenameCase, onProgress, onError)) - { - onError("Extracting files from CD failed."); - return; - } - } - - Game.RunAfterTick(() => - { - statusLabel.GetText = () => "Game assets have been extracted."; - Ui.CloseWindow(); - afterInstall(); - }); - } - catch (Exception e) - { - onError("Installation failed.\n{0}".F(e.Message)); - Log.Write("debug", e.ToString()); - return; - } - }) { IsBackground = true }.Start(); - } - } -} diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs deleted file mode 100644 index 3d2d693901..0000000000 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallLogic.cs +++ /dev/null @@ -1,44 +0,0 @@ -#region Copyright & License Information -/* - * Copyright 2007-2016 The OpenRA Developers (see AUTHORS) - * This file is part of OpenRA, which is free software. It is made - * available to you under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or (at your option) any later version. For more - * information, see COPYING. - */ -#endregion - -using System; -using OpenRA.Widgets; - -namespace OpenRA.Mods.Common.Widgets.Logic -{ - public class InstallLogic : ChromeLogic - { - [ObjectCreator.UseCtor] - public InstallLogic(Widget widget, string mirrorListUrl, string modId) - { - var panel = widget.Get("INSTALL_PANEL"); - var widgetArgs = new WidgetArgs - { - { "afterInstall", () => { Game.InitializeMod(modId, new Arguments()); } }, - { "mirrorListUrl", mirrorListUrl }, - { "modId", modId } - }; - - var mod = ModMetadata.AllMods[modId]; - var text = "OpenRA requires the original {0} game content.".F(mod.Title); - panel.Get("DESC1").Text = text; - - var downloadButton = panel.Get("DOWNLOAD_BUTTON"); - downloadButton.OnClick = () => Ui.OpenWindow("INSTALL_DOWNLOAD_PANEL", widgetArgs); - downloadButton.IsDisabled = () => string.IsNullOrEmpty(mod.Content.PackageMirrorList); - - panel.Get("INSTALL_BUTTON").OnClick = () => - Ui.OpenWindow("INSTALL_FROMCD_PANEL", widgetArgs); - - panel.Get("BACK_BUTTON").OnClick = Ui.CloseWindow; - } - } -} diff --git a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs index aed538ce94..7a74dbd966 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/ModBrowserLogic.cs @@ -185,29 +185,14 @@ namespace OpenRA.Mods.Common.Widgets.Logic if (!IsModInstalled(mod)) { - if (mod.ModContent != null) + var widgetArgs = new WidgetArgs { - var widgetArgs = new WidgetArgs - { - { "continueLoading", () => - Game.RunAfterTick(() => Game.InitializeMod(mod.Id, new Arguments())) }, - { "modId", mod.Id } - }; + { "continueLoading", () => + Game.RunAfterTick(() => Game.InitializeMod(mod.Id, new Arguments())) }, + { "modId", mod.Id } + }; - Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs); - } - else - { - var widgetArgs = new WidgetArgs - { - { "continueLoading", () => - Game.RunAfterTick(() => Game.InitializeMod(Game.Settings.Game.Mod, new Arguments())) }, - { "mirrorListUrl", mod.Content.PackageMirrorList }, - { "modId", mod.Id } - }; - - Ui.OpenWindow("INSTALL_PANEL", widgetArgs); - } + Ui.OpenWindow("CONTENT_PROMPT_PANEL", widgetArgs); return; } @@ -222,7 +207,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic static bool IsModInstalled(ModMetadata mod) { - return mod.Content.TestFiles.All(file => File.Exists(Path.GetFullPath(Platform.ResolvePath(file)))); + return mod.ModContent.Packages + .Where(p => p.Value.Required) + .All(p => p.Value.TestFiles.All(f => File.Exists(Platform.ResolvePath(f)))); } } } diff --git a/mods/modchooser/install.yaml b/mods/modchooser/install.yaml deleted file mode 100644 index 655c9ea1b1..0000000000 --- a/mods/modchooser/install.yaml +++ /dev/null @@ -1,196 +0,0 @@ -Container@INSTALL_PANEL: - Logic: InstallLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 500 - Height: 177 - Children: - Background: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Background: panel-bg - Background@RULE: - X: 30 - Y: 50 - Width: 440 - Height:150 - Background:panel-rule - Label@TITLE: - X: 0 - Y: 12 - Width: PARENT_RIGHT - Height: 25 - Text: Install Assets - Align: Center - Font: MediumBold - Label@DESC1: - X: 0 - Y: 65 - Width: PARENT_RIGHT - Height: 25 - Align: Center - Label@DESC2: - X: 0 - Y: 85 - Width: PARENT_RIGHT - Height: 25 - Text: Content can be downloaded (if available), or copied from the install CD. - Align: Center - Button@DOWNLOAD_BUTTON: - X: 20 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Download - Font: Bold - Button@INSTALL_BUTTON: - X: 140 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Use CD - Font: Bold - Button@BACK_BUTTON: - X: PARENT_RIGHT - 130 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Back - Font: Bold - Key: escape - -Container@INSTALL_DOWNLOAD_PANEL: - Logic: DownloadPackagesLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 500 - Height: 177 - Children: - Background: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Background: panel-bg - Background@RULE: - X: 30 - Y: 50 - Width: 440 - Height:150 - Background:panel-rule - Label@TITLE: - X: 0 - Y: 12 - Width: PARENT_RIGHT - Height: 25 - Align: Center - Font: MediumBold - ProgressBar@PROGRESS_BAR: - X: 50 - Y: 64 - Width: PARENT_RIGHT - 100 - Height: 16 - BarMargin: 0, 0 - Label@STATUS_LABEL: - X: 36 - Y: 85 - Width: PARENT_RIGHT - 100 - Height: 25 - Align: Left - Button@RETRY_BUTTON: - X: PARENT_RIGHT - 280 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 120 - Height: 32 - Visible: false - Text: Retry - Font: Bold - Key: return - Button@CANCEL_BUTTON: - X: PARENT_RIGHT - 130 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Cancel - Font: Bold - Key: escape - -Container@INSTALL_FROMCD_PANEL: - Logic: InstallFromCDLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 - Width: 500 - Height: 177 - Children: - Background: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Background: panel-bg - Background@RULE: - X: 30 - Y: 50 - Width: 440 - Height:150 - Background:panel-rule - Label@TITLE: - X: 0 - Y: 12 - Width: PARENT_RIGHT - Height: 25 - Text: Fetching assets from CD... - Align: Center - Font: MediumBold - Container@INSTALLING: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Visible: false - Children: - ProgressBar@PROGRESS_BAR: - X: 50 - Y: 60 - Width: PARENT_RIGHT - 100 - Height: 16 - BarMargin: 0, 0 - Label@STATUS_LABEL: - X: 36 - Y: 80 - Width: PARENT_RIGHT - 100 - Height: 25 - Align: Left - Container@INSERT_DISK: - Width: PARENT_RIGHT - Height: PARENT_BOTTOM - Visible: false - Children: - Label@INFO1: - Y: 65 - Width: PARENT_RIGHT - Height: 25 - Text: Disk not found. - Align: Center - Label@INFO2: - Y: 85 - Width: PARENT_RIGHT - Height: 25 - Align: Center - Button@RETRY_BUTTON: - X: 20 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Retry - Font: Bold - Key: return - Button@BACK_BUTTON: - X: PARENT_RIGHT - 130 - Y: PARENT_BOTTOM - 52 - Background:button-highlighted - Width: 110 - Height: 32 - Text: Back - Font: Bold - Key: escape diff --git a/mods/modchooser/mod.yaml b/mods/modchooser/mod.yaml index b18a2cdd6c..148466d6ac 100644 --- a/mods/modchooser/mod.yaml +++ b/mods/modchooser/mod.yaml @@ -22,7 +22,6 @@ Assemblies: ChromeLayout: modchooser|modchooser.yaml - modchooser|install.yaml modchooser|content.yaml Notifications: From 8f412e255d38d5aaa589b806db42dc5085ad5969 Mon Sep 17 00:00:00 2001 From: Paul Chote Date: Sun, 29 May 2016 15:52:38 +0100 Subject: [PATCH 14/14] Formatting fixes. --- mods/modchooser/content.yaml | 30 ++-- mods/modchooser/modchooser.yaml | 246 ++++++++++++++++---------------- 2 files changed, 138 insertions(+), 138 deletions(-) diff --git a/mods/modchooser/content.yaml b/mods/modchooser/content.yaml index 541b713e8b..7c35ad2e3a 100644 --- a/mods/modchooser/content.yaml +++ b/mods/modchooser/content.yaml @@ -1,7 +1,7 @@ Background@CONTENT_PANEL: Logic: ModContentLogic - X: (WINDOW_RIGHT - WIDTH)/2 - Y: (WINDOW_BOTTOM - HEIGHT)/2 + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - HEIGHT) / 2 Width: 500 Height: 268 Background: panel-bg @@ -10,8 +10,8 @@ Background@CONTENT_PANEL: X: 30 Y: 50 Width: 440 - Height:150 - Background:panel-rule + Height: 150 + Background: panel-rule Label@TITLE: X: 0 Y: 12 @@ -88,7 +88,7 @@ Background@CONTENT_PANEL: Button@CHECK_DISC_BUTTON: X: 30 Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 110 Height: 32 Text: Detect Disc @@ -96,7 +96,7 @@ Background@CONTENT_PANEL: Button@BACK_BUTTON: X: PARENT_RIGHT - 140 Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 110 Height: 32 Text: Back @@ -163,7 +163,7 @@ Container@PACKAGE_DOWNLOAD_PANEL: Button@RETRY_BUTTON: X: 30 Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 120 Height: 32 Visible: false @@ -173,7 +173,7 @@ Container@PACKAGE_DOWNLOAD_PANEL: Button@CANCEL_BUTTON: X: PARENT_RIGHT - 30 - WIDTH Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 110 Height: 32 Text: Cancel @@ -193,7 +193,7 @@ Background@DISC_INSTALL_PANEL: Y: 50 Width: 440 Height:150 - Background:panel-rule + Background: panel-rule Label@TITLE: Y: 12 Width: PARENT_RIGHT @@ -254,7 +254,7 @@ Background@DISC_INSTALL_PANEL: Button@PRIMARY_BUTTON: X: 30 Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 110 Height: 32 Font: Bold @@ -262,7 +262,7 @@ Background@DISC_INSTALL_PANEL: Button@SECONDARY_BUTTON: X: PARENT_RIGHT - 140 Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 110 Height: 32 Font: Bold @@ -280,8 +280,8 @@ Background@CONTENT_PROMPT_PANEL: X: 30 Y: 50 Width: 440 - Height:150 - Background:panel-rule + Height: 150 + Background: panel-rule Label@TITLE: X: 0 Y: 12 @@ -298,7 +298,7 @@ Background@CONTENT_PROMPT_PANEL: Button@ADVANCED_BUTTON: X: 30 Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 140 Height: 32 Text: Advanced Install @@ -314,7 +314,7 @@ Background@CONTENT_PROMPT_PANEL: Button@BACK_BUTTON: X: PARENT_RIGHT - WIDTH - 30 Y: PARENT_BOTTOM - 52 - Background:button-highlighted + Background: button-highlighted Width: 110 Height: 32 Text: Back diff --git a/mods/modchooser/modchooser.yaml b/mods/modchooser/modchooser.yaml index c52557ead6..c4ce98d92f 100644 --- a/mods/modchooser/modchooser.yaml +++ b/mods/modchooser/modchooser.yaml @@ -1,169 +1,169 @@ Background@MODCHOOSER_BACKGROUND: Background: background - Width:WINDOW_RIGHT - Height:WINDOW_BOTTOM + Width: WINDOW_RIGHT + Height: WINDOW_BOTTOM Background@MODCHOOSER_DIALOG: - Logic:ModBrowserLogic + Logic: ModBrowserLogic Children: Container: - X:(WINDOW_RIGHT - WIDTH)/2 - Y:(WINDOW_BOTTOM - 500)/2 - Width:750 - Height:550-4-32 + X: (WINDOW_RIGHT - WIDTH) / 2 + Y: (WINDOW_BOTTOM - 500) / 2 + Width: 750 + Height: 514 Children: Background@DIALOG_BACKGROUND: - Y:69 - Width:PARENT_RIGHT - Height:PARENT_BOTTOM - 69 - Background:panel-bg + Y: 69 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM - 69 + Background: panel-bg Children: Label: - X:53 - Y:30 - Align:Left - Font:MediumBold - Text:Choose your Battlefield: + X: 53 + Y: 30 + Align: Left + Font: MediumBold + Text: Choose your Battlefield: Container@MOD_LIST: - X:53 - Y:60 - Width:PARENT_RIGHT-106 - Height:150 + X: 53 + Y: 60 + Width: PARENT_RIGHT-106 + Height: 150 Children: Button@MOD_TEMPLATE: - X:16 - Width:114 - Height:114 - TooltipContainer:TOOLTIP_CONTAINER - IgnoreChildMouseOver:true + X: 16 + Width: 114 + Height: 114 + TooltipContainer: TOOLTIP_CONTAINER + IgnoreChildMouseOver: true Children: Container@MOD_NO_LOGO: - Width:PARENT_RIGHT - Height:PARENT_BOTTOM + Width: PARENT_RIGHT + Height: PARENT_BOTTOM Children: Label@A: - Width:PARENT_RIGHT - Height:PARENT_BOTTOM-20 - Text:Missing or - Align:center + Width: PARENT_RIGHT + Height: PARENT_BOTTOM-20 + Text: Missing or + Align: Center Label@B: - Y:20 - Width:PARENT_RIGHT - Height:PARENT_BOTTOM-20 - Text:invalid logo - Align:center + Y: 20 + Width: PARENT_RIGHT + Height: PARENT_BOTTOM-20 + Text: invalid logo + Align: Center RGBASprite@MOD_LOGO: - X:9 - Y:9 + X: 9 + Y: 9 Button@PREV_MOD: - X:15 - Y:60+41-16 - Width:25 - Height:64 - IgnoreChildMouseOver:true + X: 15 + Y: 85 + Width: 25 + Height: 64 + IgnoreChildMouseOver: true Children: Image: - X:2 - ImageCollection:modchooser - ImageName:leftarrow + X: 2 + ImageCollection: modchooser + ImageName: leftarrow Button@NEXT_MOD: - X:PARENT_RIGHT - WIDTH - 20 - Y:60+41-16 - Width:25 - Height:64 - IgnoreChildMouseOver:true + X: PARENT_RIGHT - WIDTH - 20 + Y: 85 + Width: 25 + Height: 64 + IgnoreChildMouseOver: true Children: Image: - X:3 - ImageCollection:modchooser - ImageName:rightarrow + X: 3 + ImageCollection: modchooser + ImageName: rightarrow Background@RULE: - X:30 - Y:PARENT_BOTTOM - 249 - Width:PARENT_RIGHT-30 - Height:150 - Background:panel-rule + X: 30 + Y: PARENT_BOTTOM - 249 + Width: PARENT_RIGHT - 60 + Height: 150 + Background: panel-rule Label@MOD_TITLE: - X:PARENT_RIGHT - 400 - Y:PARENT_BOTTOM-220 - Align:Left - Font:Bold + X: PARENT_RIGHT - 400 + Y: PARENT_BOTTOM-220 + Align: Left + Font: Bold Label@MOD_AUTHOR: - X:PARENT_RIGHT - 400 - Y:PARENT_BOTTOM-205 - Align:Left - Font:TinyBold + X: PARENT_RIGHT - 400 + Y: PARENT_BOTTOM-205 + Align: Left + Font: TinyBold Label@MOD_VERSION: - X:PARENT_RIGHT - 400 - Y:PARENT_BOTTOM-192 - Align:Left - Font:Tiny + X: PARENT_RIGHT - 400 + Y: PARENT_BOTTOM-192 + Align: Left + Font: Tiny Label@MOD_DESC: - X:PARENT_RIGHT - 400 - Y:PARENT_BOTTOM-175 - Align:Left - VAlign:Top - Font:Tiny + X: PARENT_RIGHT - 400 + Y: PARENT_BOTTOM-175 + Align: Left + VAlign: Top + Font: Tiny Background@PREVIEW: - X:30 - Y:PARENT_BOTTOM - 25 - HEIGHT - Width:300 - Height:200 - Background:panel-thinborder + X: 30 + Y: PARENT_BOTTOM - 25 - HEIGHT + Width: 300 + Height: 200 + Background: panel-thinborder Children: Label: - Width:PARENT_RIGHT - Height:PARENT_BOTTOM - Text:Missing or invalid preview - Align:Center + Width: PARENT_RIGHT + Height: PARENT_BOTTOM + Text: Missing or invalid preview + Align: Center RGBASprite@MOD_PREVIEW: - X:2 - Y:2 + X: 2 + Y: 2 Button@LOAD_BUTTON: - X:PARENT_RIGHT - 300 - WIDTH - Y:PARENT_BOTTOM - 25 - HEIGHT - Width:100 - Height:32 - Text:Play - Background:button-highlighted - Key:return + X: PARENT_RIGHT - 300 - WIDTH + Y: PARENT_BOTTOM - 25 - HEIGHT + Width: 100 + Height: 32 + Text: Play + Background: button-highlighted + Key: return Button@CONFIGURE_BUTTON: - X:PARENT_RIGHT - 145 - WIDTH - Y:PARENT_BOTTOM - 25 - HEIGHT - Width:140 - Height:32 - Text:Manage Content - Background:button-highlighted + X: PARENT_RIGHT - 145 - WIDTH + Y: PARENT_BOTTOM - 25 - HEIGHT + Width: 140 + Height: 32 + Text: Manage Content + Background: button-highlighted Button@QUIT_BUTTON: - X:PARENT_RIGHT - 30 - WIDTH - Y:PARENT_BOTTOM - 25 - HEIGHT - Width:100 - Height:32 - Text:Quit - Background:button-highlighted + X: PARENT_RIGHT - 30 - WIDTH + Y: PARENT_BOTTOM - 25 - HEIGHT + Width: 100 + Height: 32 + Text: Quit + Background: button-highlighted Background@DIALOG_HEADER: - Width:PARENT_RIGHT - Height:72 - Background:panel-header + Width: PARENT_RIGHT + Height: 72 + Background: panel-header Children: Image: - X:(PARENT_RIGHT - WIDTH)/2 - Y:0-28 - Width:280 - ImageCollection:modchooser - ImageName:logo + X: (PARENT_RIGHT - WIDTH) / 2 + Y: 0-28 + Width: 280 + ImageCollection: modchooser + ImageName: logo TooltipContainer@TOOLTIP_CONTAINER: Background@BUTTON_TOOLTIP: - Logic:ButtonTooltipLogic - Background:panel-thinborder - Height:25 + Logic: ButtonTooltipLogic + Background: panel-thinborder + Height: 25 Children: Label@LABEL: - X:5 - Height:23 - Font:Bold + X: 5 + Height: 23 + Font: Bold Label@HOTKEY: - TextColor:FFFF00 - Height:23 - Font:Bold \ No newline at end of file + TextColor: FFFF00 + Height: 23 + Font: Bold \ No newline at end of file