diff --git a/OpenRA.Game/ContentInstaller.cs b/OpenRA.Game/ContentInstaller.cs index 49763093d2..34d096f172 100644 --- a/OpenRA.Game/ContentInstaller.cs +++ b/OpenRA.Game/ContentInstaller.cs @@ -15,11 +15,14 @@ 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(); diff --git a/OpenRA.Game/FileSystem/BagFile.cs b/OpenRA.Game/FileSystem/BagFile.cs index 2c24d232ac..6fe5287a31 100644 --- a/OpenRA.Game/FileSystem/BagFile.cs +++ b/OpenRA.Game/FileSystem/BagFile.cs @@ -21,19 +21,15 @@ namespace OpenRA.FileSystem { public sealed class BagFile : IReadOnlyPackage { - static readonly uint[] Nothing = { }; - readonly string bagFilename; readonly Stream s; readonly int bagFilePriority; - readonly Dictionary index; - readonly FileSystem context; + readonly Dictionary index; public BagFile(FileSystem context, string filename, int priority) { bagFilename = filename; bagFilePriority = priority; - this.context = context; // A bag file is always accompanied with an .idx counterpart // For example: audio.bag requires the audio.idx file @@ -44,7 +40,7 @@ namespace OpenRA.FileSystem using (var indexStream = context.Open(indexFilename)) entries = new IdxReader(indexStream).Entries; - index = entries.ToDictionaryWithConflictLog(x => x.Hash, + index = entries.ToDictionaryWithConflictLog(x => x.Filename, "{0} (bag format)".F(filename), null, x => "(offs={0}, len={1})".F(x.Offset, x.Length)); @@ -54,10 +50,10 @@ namespace OpenRA.FileSystem public int Priority { get { return 1000 + bagFilePriority; } } public string Name { get { return bagFilename; } } - public Stream GetContent(uint hash) + public Stream GetContent(string filename) { IdxEntry entry; - if (!index.TryGetValue(hash, out entry)) + if (!index.TryGetValue(filename, out entry)) return null; s.Seek(entry.Offset, SeekOrigin.Begin); @@ -120,59 +116,14 @@ namespace OpenRA.FileSystem return mergedStream; } - uint? FindMatchingHash(string filename) - { - var hash = IdxEntry.HashFilename(filename, PackageHashType.CRC32); - if (index.ContainsKey(hash)) - return hash; - - // Maybe we were given a raw hash? - uint raw; - if (!uint.TryParse(filename, NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out raw)) - return null; - - if ("{0:X}".F(raw) == filename && index.ContainsKey(raw)) - return raw; - - return null; - } - - public Stream GetContent(string filename) - { - var hash = FindMatchingHash(filename); - return hash.HasValue ? GetContent(hash.Value) : null; - } - public bool Exists(string filename) { - return FindMatchingHash(filename).HasValue; - } - - public IEnumerable ClassicHashes() - { - return Nothing; - } - - public IEnumerable CrcHashes() - { - return index.Keys; + return index.ContainsKey(filename); } public IEnumerable AllFileNames() { - var lookup = new Dictionary(); - if (context.Exists("global mix database.dat")) - { - var db = new XccGlobalDatabase(context.Open("global mix database.dat")); - foreach (var e in db.Entries) - { - var hash = IdxEntry.HashFilename(e, PackageHashType.CRC32); - if (!lookup.ContainsKey(hash)) - lookup.Add(hash, e); - } - } - - return index.Keys.Select(k => lookup.ContainsKey(k) ? lookup[k] : "{0:X}".F(k)); + return index.Keys; } public void Dispose() diff --git a/OpenRA.Game/FileSystem/BigFile.cs b/OpenRA.Game/FileSystem/BigFile.cs index 8d8dc559ef..8bb6b69025 100644 --- a/OpenRA.Game/FileSystem/BigFile.cs +++ b/OpenRA.Game/FileSystem/BigFile.cs @@ -96,16 +96,6 @@ namespace OpenRA.FileSystem return entries.ContainsKey(filename); } - public IEnumerable ClassicHashes() - { - return entries.Keys.Select(filename => PackageEntry.HashFilename(filename, PackageHashType.Classic)); - } - - public IEnumerable CrcHashes() - { - return Enumerable.Empty(); - } - public IEnumerable AllFileNames() { return entries.Keys; diff --git a/OpenRA.Game/FileSystem/D2kSoundResources.cs b/OpenRA.Game/FileSystem/D2kSoundResources.cs index b587df77c9..369b9ddeb4 100644 --- a/OpenRA.Game/FileSystem/D2kSoundResources.cs +++ b/OpenRA.Game/FileSystem/D2kSoundResources.cs @@ -10,18 +10,29 @@ using System.Collections.Generic; using System.IO; +using OpenRA.Primitives; namespace OpenRA.FileSystem { public sealed class D2kSoundResources : IReadOnlyPackage { + struct Entry + { + public readonly uint Offset; + public readonly uint Length; + + public Entry(uint offset, uint length) + { + Offset = offset; + Length = length; + } + } + readonly Stream s; readonly string filename; - readonly List filenames; readonly int priority; - - readonly Dictionary index = new Dictionary(); + readonly Dictionary index = new Dictionary(); public D2kSoundResources(FileSystem context, string filename, int priority) { @@ -31,20 +42,13 @@ namespace OpenRA.FileSystem s = context.Open(filename); try { - filenames = new List(); - var headerLength = s.ReadUInt32(); while (s.Position < headerLength + 4) { var name = s.ReadASCIIZ(); var offset = s.ReadUInt32(); var length = s.ReadUInt32(); - - var hash = PackageEntry.HashFilename(name, PackageHashType.Classic); - if (!index.ContainsKey(hash)) - index.Add(hash, new PackageEntry(hash, offset, length)); - - filenames.Add(name); + index.Add(name, new Entry(offset, length)); } } catch @@ -54,45 +58,30 @@ namespace OpenRA.FileSystem } } - public Stream GetContent(uint hash) + public Stream GetContent(string filename) { - PackageEntry e; - if (!index.TryGetValue(hash, out e)) + Entry e; + if (!index.TryGetValue(filename, out e)) return null; s.Seek(e.Offset, SeekOrigin.Begin); return new MemoryStream(s.ReadBytes((int)e.Length)); } - public Stream GetContent(string filename) - { - return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic)); - } - public bool Exists(string filename) { - return index.ContainsKey(PackageEntry.HashFilename(filename, PackageHashType.Classic)); + return index.ContainsKey(filename); } public IEnumerable AllFileNames() { - return filenames; + return index.Keys; } public string Name { get { return filename; } } public int Priority { get { return 1000 + priority; } } - public IEnumerable ClassicHashes() - { - return index.Keys; - } - - public IEnumerable CrcHashes() - { - yield break; - } - public void Dispose() { s.Dispose(); diff --git a/OpenRA.Game/FileSystem/FileSystem.cs b/OpenRA.Game/FileSystem/FileSystem.cs index 3658ab36d2..9945b3ba62 100644 --- a/OpenRA.Game/FileSystem/FileSystem.cs +++ b/OpenRA.Game/FileSystem/FileSystem.cs @@ -19,14 +19,12 @@ namespace OpenRA.FileSystem { public class FileSystem { - public readonly List PackagePaths = new List(); public readonly List MountedPackages = new List(); static readonly Dictionary AssemblyCache = new Dictionary(); int order; - Cache> crcHashIndex = new Cache>(_ => new List()); - Cache> classicHashIndex = new Cache>(_ => new List()); + Cache> fileIndex = new Cache>(_ => new List()); public IReadWritePackage CreatePackage(string filename, int order, Dictionary content) { @@ -93,7 +91,6 @@ namespace OpenRA.FileSystem name = Platform.ResolvePath(name); - PackagePaths.Add(name); Action a = () => MountInner(OpenPackage(name, annotation, order++)); if (optional) @@ -107,27 +104,23 @@ namespace OpenRA.FileSystem { MountedPackages.Add(package); - foreach (var hash in package.ClassicHashes()) + foreach (var filename in package.AllFileNames()) { - var packageList = classicHashIndex[hash]; - if (!packageList.Contains(package)) - packageList.Add(package); - } - - foreach (var hash in package.CrcHashes()) - { - var packageList = crcHashIndex[hash]; + var packageList = fileIndex[filename]; if (!packageList.Contains(package)) packageList.Add(package); } } - public bool Unmount(IReadOnlyPackage mount) + public bool Unmount(IReadOnlyPackage package) { - if (MountedPackages.Contains(mount)) - mount.Dispose(); + foreach (var packagesForFile in fileIndex.Values) + packagesForFile.RemoveAll(p => p == package); - return MountedPackages.RemoveAll(f => f == mount) > 0; + if (MountedPackages.Contains(package)) + package.Dispose(); + + return MountedPackages.RemoveAll(p => p == package) > 0; } public void UnmountAll() @@ -136,9 +129,7 @@ namespace OpenRA.FileSystem package.Dispose(); MountedPackages.Clear(); - PackagePaths.Clear(); - classicHashIndex = new Cache>(_ => new List()); - crcHashIndex = new Cache>(_ => new List()); + fileIndex = new Cache>(_ => new List()); } public void LoadFromManifest(Manifest manifest) @@ -151,10 +142,9 @@ namespace OpenRA.FileSystem Mount(pkg.Key, pkg.Value); } - Stream GetFromCache(PackageHashType type, string filename) + Stream GetFromCache(string filename) { - var index = type == PackageHashType.CRC32 ? crcHashIndex : classicHashIndex; - var package = index[PackageEntry.HashFilename(filename, type)] + var package = fileIndex[filename] .Where(x => x.Exists(filename)) .MinByOrDefault(x => x.Priority); @@ -191,11 +181,7 @@ namespace OpenRA.FileSystem // TODO: This disables caching for explicit package requests if (filename.IndexOfAny(new[] { '/', '\\' }) == -1 && !explicitPackage) { - s = GetFromCache(PackageHashType.Classic, filename); - if (s != null) - return true; - - s = GetFromCache(PackageHashType.CRC32, filename); + s = GetFromCache(filename); if (s != null) return true; } diff --git a/OpenRA.Game/FileSystem/Folder.cs b/OpenRA.Game/FileSystem/Folder.cs index 5fe419b2f9..1fcef789d9 100644 --- a/OpenRA.Game/FileSystem/Folder.cs +++ b/OpenRA.Game/FileSystem/Folder.cs @@ -43,17 +43,6 @@ namespace OpenRA.FileSystem catch { return null; } } - public IEnumerable ClassicHashes() - { - foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly)) - yield return PackageEntry.HashFilename(Path.GetFileName(filename), PackageHashType.Classic); - } - - public IEnumerable CrcHashes() - { - yield break; - } - public IEnumerable AllFileNames() { foreach (var filename in Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly)) diff --git a/OpenRA.Game/FileSystem/IPackage.cs b/OpenRA.Game/FileSystem/IPackage.cs index e336b0602e..cb9c54d1c5 100644 --- a/OpenRA.Game/FileSystem/IPackage.cs +++ b/OpenRA.Game/FileSystem/IPackage.cs @@ -18,8 +18,6 @@ namespace OpenRA.FileSystem { Stream GetContent(string filename); bool Exists(string filename); - IEnumerable ClassicHashes(); - IEnumerable CrcHashes(); IEnumerable AllFileNames(); int Priority { get; } string Name { get; } diff --git a/OpenRA.Game/FileSystem/IdxEntry.cs b/OpenRA.Game/FileSystem/IdxEntry.cs index 8b71792379..c8fb088aba 100644 --- a/OpenRA.Game/FileSystem/IdxEntry.cs +++ b/OpenRA.Game/FileSystem/IdxEntry.cs @@ -15,80 +15,31 @@ namespace OpenRA.FileSystem { public class IdxEntry { - public const string DefaultExtension = "wav"; - - public readonly uint Hash; - public readonly string Name; - public readonly string Extension; + public readonly string Filename; public readonly uint Offset; public readonly uint Length; public readonly uint SampleRate; public readonly uint Flags; public readonly uint ChunkSize; - public IdxEntry(uint hash, uint offset, uint length, uint sampleRate, uint flags, uint chuckSize) - { - Hash = hash; - Offset = offset; - Length = length; - SampleRate = sampleRate; - Flags = flags; - ChunkSize = chuckSize; - } - public IdxEntry(Stream s) { - var asciiname = s.ReadASCII(16); - - var pos = asciiname.IndexOf('\0'); + var name = s.ReadASCII(16); + var pos = name.IndexOf('\0'); if (pos != 0) - asciiname = asciiname.Substring(0, pos); + name = name.Substring(0, pos); - Name = asciiname; - Extension = DefaultExtension; + Filename = string.Concat(name, ".wav"); Offset = s.ReadUInt32(); Length = s.ReadUInt32(); SampleRate = s.ReadUInt32(); Flags = s.ReadUInt32(); ChunkSize = s.ReadUInt32(); - Hash = HashFilename(string.Concat(Name, ".", Extension), PackageHashType.CRC32); - } - - public void Write(BinaryWriter w) - { - w.Write(Name.PadRight(16, '\0')); - w.Write(Offset); - w.Write(Length); - w.Write(SampleRate); - w.Write(Flags); - w.Write(ChunkSize); } public override string ToString() { - string filename; - if (names.TryGetValue(Hash, out filename)) - return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(filename, Offset, Length); - else - return "0x{0:x8} - offset 0x{1:x8} - length 0x{2:x8}".F(Hash, Offset, Length); - } - - public static uint HashFilename(string name, PackageHashType type) - { - return PackageEntry.HashFilename(name, type); - } - - static Dictionary names = new Dictionary(); - - public static void AddStandardName(string s) - { - // RA1 and TD - var hash = HashFilename(s, PackageHashType.Classic); - names.Add(hash, s); - - // TS - var crcHash = HashFilename(s, PackageHashType.CRC32); - names.Add(crcHash, s); + return "{0} - offset 0x{1:x8} - length 0x{2:x8}".F(Filename, Offset, Length); } } } diff --git a/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs b/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs index 618810ada4..17756bd979 100644 --- a/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs +++ b/OpenRA.Game/FileSystem/InstallShieldCABExtractor.cs @@ -451,11 +451,6 @@ namespace OpenRA.FileSystem GetContentById(index, destfile); } - public IEnumerable ClassicHashes() - { - return fileLookup.Keys.Select(k => PackageEntry.HashFilename(k, PackageHashType.Classic)); - } - public Stream GetContentById(uint index) { var fileDes = fileDescriptors[index]; @@ -507,11 +502,6 @@ namespace OpenRA.FileSystem return GetContentById(fileLookup[fileName]); } - public IEnumerable CrcHashes() - { - yield break; - } - public IEnumerable AllFileNames() { return fileLookup.Keys; diff --git a/OpenRA.Game/FileSystem/InstallShieldPackage.cs b/OpenRA.Game/FileSystem/InstallShieldPackage.cs index dd28d1042d..240cb88475 100644 --- a/OpenRA.Game/FileSystem/InstallShieldPackage.cs +++ b/OpenRA.Game/FileSystem/InstallShieldPackage.cs @@ -17,8 +17,19 @@ namespace OpenRA.FileSystem { public sealed class InstallShieldPackage : IReadOnlyPackage { - readonly Dictionary index = new Dictionary(); - readonly List filenames; + struct Entry + { + public readonly uint Offset; + public readonly uint Length; + + public Entry(uint offset, uint length) + { + Offset = offset; + Length = length; + } + } + + readonly Dictionary index = new Dictionary(); readonly Stream s; readonly long dataStart = 255; readonly int priority; @@ -29,40 +40,45 @@ namespace OpenRA.FileSystem this.filename = filename; this.priority = priority; - filenames = new List(); - s = context.Open(filename); try { // Parse package header - var reader = new BinaryReader(s); - var signature = reader.ReadUInt32(); + var signature = s.ReadUInt32(); if (signature != 0x8C655D13) throw new InvalidDataException("Not an Installshield package"); - reader.ReadBytes(8); - /*var FileCount = */reader.ReadUInt16(); - reader.ReadBytes(4); - /*var ArchiveSize = */reader.ReadUInt32(); - reader.ReadBytes(19); - var tocAddress = reader.ReadInt32(); - reader.ReadBytes(4); - var dirCount = reader.ReadUInt16(); + s.Position += 8; + /*var FileCount = */s.ReadUInt16(); + s.Position += 4; + /*var ArchiveSize = */s.ReadUInt32(); + s.Position += 19; + var tocAddress = s.ReadInt32(); + s.Position += 4; + var dirCount = s.ReadUInt16(); // Parse the directory list - s.Seek(tocAddress, SeekOrigin.Begin); - var tocReader = new BinaryReader(s); - - var fileCountInDirs = new List(); + s.Position = tocAddress; // Parse directories + var directories = new Dictionary(); for (var i = 0; i < dirCount; i++) - fileCountInDirs.Add(ParseDirectory(tocReader)); + { + // Parse directory header + var fileCount = s.ReadUInt16(); + var chunkSize = s.ReadUInt16(); + var nameLength = s.ReadUInt16(); + var dirName = s.ReadASCII(nameLength); + + // Skip to the end of the chunk + s.ReadBytes(chunkSize - nameLength - 6); + directories.Add(dirName, fileCount); + } // Parse files - foreach (var fileCount in fileCountInDirs) - for (var i = 0; i < fileCount; i++) - ParseFile(reader); + foreach (var dir in directories) + for (var i = 0; i < dir.Value; i++) + ParseFile(s, dir.Key); } catch { @@ -71,44 +87,29 @@ namespace OpenRA.FileSystem } } - static uint ParseDirectory(BinaryReader reader) - { - // Parse directory header - var fileCount = reader.ReadUInt16(); - var chunkSize = reader.ReadUInt16(); - var nameLength = reader.ReadUInt16(); - reader.ReadChars(nameLength); // var DirName = new String(reader.ReadChars(NameLength)); - - // Skip to the end of the chunk - reader.ReadBytes(chunkSize - nameLength - 6); - return fileCount; - } - uint accumulatedData = 0; - void ParseFile(BinaryReader reader) + void ParseFile(Stream s, string dirName) { - reader.ReadBytes(7); - var compressedSize = reader.ReadUInt32(); - reader.ReadBytes(12); - var chunkSize = reader.ReadUInt16(); - reader.ReadBytes(4); - var nameLength = reader.ReadByte(); - var fileName = new string(reader.ReadChars(nameLength)); + s.Position += 7; + var compressedSize = s.ReadUInt32(); + s.Position += 12; + var chunkSize = s.ReadUInt16(); + s.Position += 4; + var nameLength = s.ReadByte(); + var fileName = dirName + "\\" + s.ReadASCII(nameLength); - var hash = PackageEntry.HashFilename(fileName, PackageHashType.Classic); - if (!index.ContainsKey(hash)) - index.Add(hash, new PackageEntry(hash, accumulatedData, compressedSize)); - filenames.Add(fileName); + // Use index syntax to overwrite any duplicate entries with the last value + index[fileName] = new Entry(accumulatedData, compressedSize); accumulatedData += compressedSize; // Skip to the end of the chunk - reader.ReadBytes(chunkSize - nameLength - 30); + s.Position += chunkSize - nameLength - 30; } - public Stream GetContent(uint hash) + public Stream GetContent(string filename) { - PackageEntry e; - if (!index.TryGetValue(hash, out e)) + Entry e; + if (!index.TryGetValue(filename, out e)) return null; s.Seek(dataStart + e.Offset, SeekOrigin.Begin); @@ -117,39 +118,19 @@ namespace OpenRA.FileSystem return new MemoryStream(Blast.Decompress(data)); } - public Stream GetContent(string filename) - { - return GetContent(PackageEntry.HashFilename(filename, PackageHashType.Classic)); - } - - public IEnumerable ClassicHashes() + public IEnumerable AllFileNames() { return index.Keys; } - public IEnumerable CrcHashes() - { - yield break; - } - - public IEnumerable AllFileNames() - { - return filenames; - } - public bool Exists(string filename) { - return index.ContainsKey(PackageEntry.HashFilename(filename, PackageHashType.Classic)); + return index.ContainsKey(filename); } public int Priority { get { return 2000 + priority; } } public string Name { get { return filename; } } - public void Write(Dictionary contents) - { - throw new NotImplementedException("Cannot save InstallShieldPackages."); - } - public void Dispose() { s.Dispose(); diff --git a/OpenRA.Game/FileSystem/MixFile.cs b/OpenRA.Game/FileSystem/MixFile.cs index 25532a8ff5..66914b2c54 100644 --- a/OpenRA.Game/FileSystem/MixFile.cs +++ b/OpenRA.Game/FileSystem/MixFile.cs @@ -170,23 +170,6 @@ namespace OpenRA.FileSystem return hash.HasValue ? GetContent(hash.Value) : null; } - static readonly uint[] Nothing = { }; - public IEnumerable ClassicHashes() - { - if (type == PackageHashType.Classic) - return index.Keys; - - return Nothing; - } - - public IEnumerable CrcHashes() - { - if (type == PackageHashType.CRC32) - return index.Keys; - - return Nothing; - } - public IEnumerable AllFileNames() { var lookup = new Dictionary(); diff --git a/OpenRA.Game/FileSystem/Pak.cs b/OpenRA.Game/FileSystem/Pak.cs index e7fc40023e..6ac57a7ae4 100644 --- a/OpenRA.Game/FileSystem/Pak.cs +++ b/OpenRA.Game/FileSystem/Pak.cs @@ -70,17 +70,6 @@ namespace OpenRA.FileSystem return new MemoryStream(data); } - public IEnumerable ClassicHashes() - { - foreach (var filename in index.Keys) - yield return PackageEntry.HashFilename(filename, PackageHashType.Classic); - } - - public IEnumerable CrcHashes() - { - yield break; - } - public IEnumerable AllFileNames() { foreach (var filename in index.Keys) diff --git a/OpenRA.Game/FileSystem/ZipFile.cs b/OpenRA.Game/FileSystem/ZipFile.cs index f376e23e68..03e25ce0f5 100644 --- a/OpenRA.Game/FileSystem/ZipFile.cs +++ b/OpenRA.Game/FileSystem/ZipFile.cs @@ -71,17 +71,6 @@ namespace OpenRA.FileSystem } } - public IEnumerable ClassicHashes() - { - foreach (ZipEntry entry in pkg) - yield return PackageEntry.HashFilename(entry.Name, PackageHashType.Classic); - } - - public IEnumerable CrcHashes() - { - yield break; - } - public IEnumerable AllFileNames() { foreach (ZipEntry entry in pkg) diff --git a/OpenRA.Mods.Common/InstallUtils.cs b/OpenRA.Mods.Common/InstallUtils.cs index 92d2c9c2e8..275e72d449 100644 --- a/OpenRA.Mods.Common/InstallUtils.cs +++ b/OpenRA.Mods.Common/InstallUtils.cs @@ -37,9 +37,26 @@ namespace OpenRA.Mods.Common 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(string srcPath, string package, string annotation, Dictionary filesByDirectory, - string destPath, bool overwrite, Action onProgress, Action onError) + string destPath, bool overwrite, ContentInstaller.FilenameCase caseModifier, Action onProgress, Action onError) { Directory.CreateDirectory(destPath); @@ -55,7 +72,7 @@ namespace OpenRA.Mods.Common foreach (var file in directory.Value) { var containingDir = Path.Combine(destPath, targetDir); - var dest = Path.Combine(containingDir, file.ToLowerInvariant()); + var dest = Path.Combine(containingDir, GetFileName(file, caseModifier)); if (File.Exists(dest)) { if (overwrite) @@ -83,7 +100,7 @@ namespace OpenRA.Mods.Common } public static bool CopyFiles(string srcPath, Dictionary files, string destPath, - bool overwrite, Action onProgress, Action onError) + bool overwrite, ContentInstaller.FilenameCase caseModifier, Action onProgress, Action onError) { Directory.CreateDirectory(destPath); @@ -100,9 +117,9 @@ namespace OpenRA.Mods.Common return false; } - var destFile = Path.GetFileName(file); + var destFile = GetFileName(file, caseModifier); var containingDir = Path.Combine(destPath, targetDir); - var dest = Path.Combine(containingDir, destFile.ToLowerInvariant()); + var dest = Path.Combine(containingDir, destFile); if (File.Exists(dest) && !overwrite) { Log.Write("debug", "Skipping {0}".F(dest)); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs index 1d5b2be5cf..95cf3deb31 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Installation/InstallFromCDLogic.cs @@ -132,7 +132,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic var destFile = Platform.ResolvePath("^", "Content", modId, filename.ToLowerInvariant()); cabExtractor.ExtractFile(uint.Parse(archive[0]), destFile); var annotation = archive.Length > 1 ? archive[1] : null; - InstallUtils.ExtractFromPackage(source, destFile, annotation, extractFiles, destDir, overwrite, onProgress, onError); + InstallUtils.ExtractFromPackage(source, destFile, annotation, extractFiles, destDir, overwrite, installData.OutputFilenameCase, onProgress, onError); progressBar.Percentage += installPercent; } } @@ -183,7 +183,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic { try { - if (!InstallUtils.CopyFiles(source, copyFiles, dest, overwrite, onProgress, onError)) + if (!InstallUtils.CopyFiles(source, copyFiles, dest, overwrite, installData.OutputFilenameCase, onProgress, onError)) { onError("Copying files from CD failed."); return; @@ -191,7 +191,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic if (!string.IsNullOrEmpty(extractPackage)) { - if (!InstallUtils.ExtractFromPackage(source, extractPackage, annotation, extractFiles, dest, overwrite, onProgress, onError)) + if (!InstallUtils.ExtractFromPackage(source, extractPackage, annotation, extractFiles, dest, + overwrite, installData.OutputFilenameCase, onProgress, onError)) { onError("Extracting files from CD failed."); return; diff --git a/mods/cnc/mod.yaml b/mods/cnc/mod.yaml index 17177eae48..26c69c7625 100644 --- a/mods/cnc/mod.yaml +++ b/mods/cnc/mod.yaml @@ -146,13 +146,11 @@ LoadScreen: CncLoadScreen 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 - FilesToCopy: CONQUER.MIX, DESERT.MIX, SCORES.MIX, SOUNDS.MIX, TEMPERAT.MIX, WINTER.MIX - FilesToExtract: speech.mix, tempicnh.mix, transit.mix PackageMirrorList: http://www.openra.net/packages/cnc-mirrors.txt DiskTestFiles: conquer.mix, desert.mix, install/setup.z PackageToExtractFromCD: install/setup.z ExtractFilesFromCD: - .: speech.mix, tempicnh.mix, transit.mix + .: 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 diff --git a/mods/d2k/maps/atreides-01a/map.yaml b/mods/d2k/maps/atreides-01a/map.yaml index 373138015a..592dcac56c 100644 --- a/mods/d2k/maps/atreides-01a/map.yaml +++ b/mods/d2k/maps/atreides-01a/map.yaml @@ -19,7 +19,7 @@ Visibility: MissionSelector Type: Campaign Videos: - Briefing: a_br01_e.vqa + Briefing: A_BR01_E.VQA Options: Crates: False diff --git a/mods/d2k/maps/atreides-01b/map.yaml b/mods/d2k/maps/atreides-01b/map.yaml index 4a640bbb1b..de5ad5ce68 100644 --- a/mods/d2k/maps/atreides-01b/map.yaml +++ b/mods/d2k/maps/atreides-01b/map.yaml @@ -19,7 +19,7 @@ Visibility: MissionSelector Type: Campaign Videos: - Briefing: a_br01_e.vqa + Briefing: A_BR01_E.VQA Options: Crates: False diff --git a/mods/d2k/maps/atreides-02a/map.yaml b/mods/d2k/maps/atreides-02a/map.yaml index 9132b6771d..294c0e37c5 100644 --- a/mods/d2k/maps/atreides-02a/map.yaml +++ b/mods/d2k/maps/atreides-02a/map.yaml @@ -19,7 +19,7 @@ Visibility: MissionSelector Type: Campaign Videos: - Briefing: a_br02_e.vqa + Briefing: A_BR02_E.VQA Options: Crates: False diff --git a/mods/d2k/maps/atreides-02b/map.yaml b/mods/d2k/maps/atreides-02b/map.yaml index 1b3f2030a9..fe9eb172f4 100644 --- a/mods/d2k/maps/atreides-02b/map.yaml +++ b/mods/d2k/maps/atreides-02b/map.yaml @@ -19,7 +19,7 @@ Visibility: MissionSelector Type: Campaign Videos: - Briefing: a_br02_e.vqa + Briefing: A_BR02_E.VQA Options: Crates: False diff --git a/mods/d2k/maps/atreides-03a/map.yaml b/mods/d2k/maps/atreides-03a/map.yaml index b9adbabb0e..5ccda9f77c 100644 --- a/mods/d2k/maps/atreides-03a/map.yaml +++ b/mods/d2k/maps/atreides-03a/map.yaml @@ -19,7 +19,7 @@ Visibility: MissionSelector Type: Campaign Videos: - Briefing: a_br03_e.vqa + Briefing: A_BR03_E.VQA Options: Crates: False diff --git a/mods/d2k/mod.yaml b/mods/d2k/mod.yaml index 2bace6adeb..736461a12b 100644 --- a/mods/d2k/mod.yaml +++ b/mods/d2k/mod.yaml @@ -130,6 +130,7 @@ LoadScreen: LogoStripeLoadScreen 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 @@ -137,8 +138,8 @@ ContentInstaller: PackageToExtractFromCD: setup/setup.z OverwriteFiles: False ExtractFilesFromCD: - .: SOUND.RS, DATA.R8, MOUSE.R8, BLOXBASE.R8, BLOXBAT.R8, BLOXBGBS.R8, BLOXICE.R8, BLOXTREE.R8, BLOXWAST.R8, PALETTE.BIN - GAMESFX: A_ECONF1.AUD, A_ECONF2.AUD, A_ECONF3.AUD, A_ESEL1.AUD, A_ESEL2.AUD, A_ESEL3.AUD, A_FCONF1.AUD, A_FCONF2.AUD, A_FCONF3.AUD,A_FCONF4.AUD, A_FSEL1.AUD, A_FSEL2.AUD, A_FSEL3.AUD, A_FSEL4.AUD, AI_1MIN.AUD, AI_2MIN.AUD, AI_3MIN.AUD, AI_4MIN.AUD, AI_5MIN.AUD, AI_ABORT.AUD, AI_ATACK.AUD, AI_BDRDY.AUD, AI_BLOST.AUD, AI_BUILD.AUD, AI_CANCL.AUD, AI_CAPT.AUD, A_ICONF1.AUD, A_ICONF2.AUD, A_ICONF3.AUD, AI_DHRDY.AUD, AI_DPLOY.AUD, AI_ENEMY.AUD, AI_GANEW.AUD, AI_GLOAD.AUD, AI_GSAVE.AUD, AI_GUARD.AUD, AI_HATTK.AUD, AI_HOLD.AUD, AI_LAUNC.AUD, AI_MAP1A.AUD, AI_MAP1B.AUD, AI_MAP1C.AUD, AI_MAP2A.AUD, AI_MAP2B.AUD, AI_MAP2C.AUD, AI_MAP3A.AUD, AI_MAP4A.AUD, AI_MAP5A.AUD, AI_MAP6A.AUD, AI_MAP7A.AUD, AI_MAP8A.AUD, AI_MAP9A.AUD, AI_MEND.AUD, AI_MFAIL.AUD, AI_MONEY.AUD, AI_MWIN.AUD, AI_NEWOP.AUD, AI_NROOM.AUD, AI_ORDER.AUD, AI_PLACE.AUD, AI_POWER.AUD, AI_PREP.AUD, AI_PRMRY.AUD, AI_REINF.AUD, AI_RUN.AUD, A_ISEL1.AUD, A_ISEL2.AUD, A_ISEL3.AUD, AI_SELL.AUD, AI_SILOS.AUD, AI_SPORT.AUD, AI_TRAIN.AUD, AI_ULOST.AUD, AI_UNRDY.AUD, AI_UPGOP.AUD, AI_UPGRD.AUD, AI_WATTK.AUD, AI_WSIGN.AUD, A_VCONF1.AUD, A_VCONF2.AUD, A_VCONF3.AUD, A_VSEL1.AUD, A_VSEL2.AUD, A_VSEL3.AUD, G_SCONF1.AUD, G_SCONF2.AUD, G_SCONF3.AUD, G_SSEL1.AUD, G_SSEL2.AUD, G_SSEL3.AUD, H_ECONF1.AUD, H_ECONF2.AUD, H_ECONF3.AUD, H_ESEL1.AUD, H_ESEL2.AUD, H_ESEL3.AUD, HI_1MIN.AUD, HI_2MIN.AUD, HI_3MIN.AUD, HI_4MIN.AUD, HI_5MIN.AUD, HI_ABORT.AUD, HI_ATACK.AUD, HI_BDRDY.AUD, HI_BLOST.AUD, HI_BUILD.AUD, HI_CANCL.AUD, HI_CAPT.AUD, H_ICONF1.AUD, H_ICONF2.AUD, H_ICONF3.AUD, HI_DHRDY.AUD, HI_DPLOY.AUD, HI_ENEMY.AUD, HI_GANEW.AUD,HI_GLOAD.AUD, HI_GSAVE.AUD, HI_GUARD.AUD, HI_HATTK.AUD, HI_HOLD.AUD, HI_LAUNC.AUD, HI_MAP1A.AUD, HI_MAP1B.AUD, HI_MAP1C.AUD, HI_MAP2A.AUD, HI_MAP2B.AUD, HI_MAP2C.AUD, HI_MAP3A.AUD, HI_MAP3B.AUD, HI_MAP4A.AUD, HI_MAP4B.AUD, HI_MAP5A.AUD, HI_MAP6A.AUD, HI_MAP6B.AUD, HI_MAP7A.AUD, HI_MAP9A.AUD, HI_MAP9.AUD, HI_MEND.AUD, HI_MFAIL.AUD, HI_MONEY.AUD, HI_MWIN.AUD, HI_NEWOP.AUD, HI_NROOM.AUD, HI_ORDER.AUD, HI_PLACE.AUD, HI_POWER.AUD, HI_PREP.AUD, HI_PRMRY.AUD, HI_REINF.AUD, HI_RUN.AUD, H_ISEL1.AUD, H_ISEL2.AUD, H_ISEL3.AUD, HI_SELL.AUD, HI_SILOS.AUD,HI_SPORT.AUD, HI_TRAIN.AUD, HI_ULOST.AUD, HI_UNRDY.AUD, HI_UPGOP.AUD, HI_UPGRD.AUD, HI_WATTK.AUD, HI_WSIGN.AUD, H_VCONF1.AUD, H_VCONF2.AUD, H_VCONF3.AUD, H_VSEL1.AUD, H_VSEL2.AUD, H_VSEL3.AUD, O_ECONF1.AUD, O_ECONF2.AUD, O_ECONF3.AUD, O_ESEL1.AUD, O_ESEL2.AUD, O_ESEL3.AUD, OI_1MIN.AUD, OI_2MIN.AUD, OI_3MIN.AUD, OI_4MIN.AUD, OI_5MIN.AUD, OI_ABORT.AUD, OI_ATACK.AUD, OI_BDRDY.AUD, OI_BLOST.AUD, OI_BUILD.AUD, OI_CANCL.AUD, OI_CAPT.AUD, O_ICONF1.AUD, O_ICONF2.AUD, O_ICONF3.AUD, OI_DHRDY.AUD, OI_DPLOY.AUD, OI_ENEMY.AUD, OI_GANEW.AUD, OI_GLOAD.AUD, OI_GSAVE.AUD, OI_GUARD.AUD, OI_HATTK.AUD, OI_HOLD.AUD, OI_LAUNC.AUD, OI_MAP1A.AUD, OI_MAP1B.AUD, OI_MAP1C.AUD, OI_MAP2A.AUD, OI_MAP2B.AUD, OI_MAP2C.AUD, OI_MAP3A.AUD, OI_MAP4A.AUD, OI_MAP5A.AUD, OI_MAP6A.AUD, OI_MAP7A.AUD, OI_MAP8A.AUD, OI_MAP9A.AUD, OI_MEND.AUD, OI_MFAIL.AUD, OI_MONEY.AUD, OI_MWIN.AUD, OI_NEWOP.AUD, OI_NROOM.AUD, OI_ORDER.AUD, OI_PLACE.AUD, OI_POWER.AUD, OI_PREP.AUD, OI_PRMRY.AUD, OI_REINF.AUD, OI_RUN.AUD, O_ISEL1.AUD, O_ISEL2.AUD, O_ISEL3.AUD, OI_SELL.AUD, OI_SILOS.AUD, OI_SPORT.AUD, OI_TRAIN.AUD, OI_ULOST.AUD, OI_UNRDY.AUD, OI_UPGOP.AUD, OI_UPGRD.AUD, OI_WATTK.AUD, OI_WSIGN.AUD, O_SCONF1.AUD, O_SCONF2.AUD, O_SCONF3.AUD, O_SSEL1.AUD, O_SSEL2.AUD, O_SSEL3.AUD, O_VCONF1.AUD, O_VCONF2.AUD, O_VCONF3.AUD, O_VSEL1.AUD, O_VSEL2.AUD, O_VSEL3.AUD + .: 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