diff --git a/pkNX.Containers/Container.cs b/pkNX.Containers/Container.cs index 559b00f3..33e328a6 100644 --- a/pkNX.Containers/Container.cs +++ b/pkNX.Containers/Container.cs @@ -1,73 +1,72 @@ -using System; +using System; using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +public static class Container { - public static class Container + /// + /// Gets a new for the provided and type. + /// + /// File location + /// File type + public static IFileContainer GetContainer(string path, ContainerType t) { - /// - /// Gets a new for the provided and type. - /// - /// File location - /// File type - public static IFileContainer GetContainer(string path, ContainerType t) + return t switch { - return t switch - { - ContainerType.GARC => new GARC(path), - ContainerType.Mini => MiniUtil.GetMini(path), - ContainerType.SARC => new SARC(path), - ContainerType.Folder => new FolderContainer(path), - ContainerType.SingleFile => new SingleFileContainer(path), - ContainerType.GFPack => new GFPack(path), - _ => throw new ArgumentOutOfRangeException(nameof(t), t, null) - }; - } + ContainerType.GARC => new GARC(path), + ContainerType.Mini => MiniUtil.GetMini(path), + ContainerType.SARC => new SARC(path), + ContainerType.Folder => new FolderContainer(path), + ContainerType.SingleFile => new SingleFileContainer(path), + ContainerType.GFPack => new GFPack(path), + _ => throw new ArgumentOutOfRangeException(nameof(t), t, null) + }; + } - /// - /// Gets a for the stream. - /// - /// Path to the binary data - public static IFileContainer? GetContainer(string path) - { - var fs = new FileStream(path, FileMode.Open); - var container = GetContainer(fs); - if (container is not LargeContainer) // not kept - fs.Dispose(); - if (container == null) - return null; - - container.FilePath = path; - return container; - } - - /// - /// Gets a for the stream. - /// - /// Stream for the binary data - public static IFileContainer? GetContainer(Stream stream) - { - var br = new BinaryReader(stream); - var container = GetContainer(br); - if (container is not LargeContainer) // not kept - br.Dispose(); - return container; - } - - /// - /// Gets a for the stream within the . - /// - /// Reader for the binary data - public static IFileContainer? GetContainer(BinaryReader br) - { - IFileContainer? container; - if ((container = GARC.GetGARC(br)) != null) - return container; - if ((container = MiniUtil.GetMini(br)) != null) - return container; - if ((container = SARC.GetSARC(br)) != null) - return container; + /// + /// Gets a for the stream. + /// + /// Path to the binary data + public static IFileContainer? GetContainer(string path) + { + var fs = new FileStream(path, FileMode.Open); + var container = GetContainer(fs); + if (container is not LargeContainer) // not kept + fs.Dispose(); + if (container == null) return null; - } + + container.FilePath = path; + return container; + } + + /// + /// Gets a for the stream. + /// + /// Stream for the binary data + public static IFileContainer? GetContainer(Stream stream) + { + var br = new BinaryReader(stream); + var container = GetContainer(br); + if (container is not LargeContainer) // not kept + br.Dispose(); + return container; + } + + /// + /// Gets a for the stream within the . + /// + /// Reader for the binary data + public static IFileContainer? GetContainer(BinaryReader br) + { + IFileContainer? container; + if ((container = GARC.GetGARC(br)) != null) + return container; + if ((container = MiniUtil.GetMini(br)) != null) + return container; + if ((container = SARC.GetSARC(br)) != null) + return container; + return null; } } diff --git a/pkNX.Containers/ContainerHandler/ContainerHandler.cs b/pkNX.Containers/ContainerHandler/ContainerHandler.cs index 7a69ff3e..8ee15a04 100644 --- a/pkNX.Containers/ContainerHandler/ContainerHandler.cs +++ b/pkNX.Containers/ContainerHandler/ContainerHandler.cs @@ -2,28 +2,27 @@ // ReSharper disable ClassNeverInstantiated.Global // ReSharper disable EventNeverSubscribedTo.Global -namespace pkNX.Containers +namespace pkNX.Containers; + +public sealed class ContainerHandler { - public sealed class ContainerHandler + public event EventHandler? FileCountDetermined; + public event EventHandler? FileProgressed; + + private int count; + + public void Initialize(int total) { - public event EventHandler? FileCountDetermined; - public event EventHandler? FileProgressed; - - private int count; - - public void Initialize(int total) - { - count = total; - var args = new FileCountDeterminedEventArgs {Total = total}; - FileCountDetermined?.Invoke(null, args); - } - - public void StepFile(int ctr, int total = -1, string? fileName = null) - { - if (total < 0) - total = count; - var args = new FileProgressedEventArgs {Current = ctr, Total = total, CurrentFile = fileName ?? string.Empty}; - FileProgressed?.Invoke(null, args); - } + count = total; + var args = new FileCountDeterminedEventArgs {Total = total}; + FileCountDetermined?.Invoke(null, args); } -} \ No newline at end of file + + public void StepFile(int ctr, int total = -1, string? fileName = null) + { + if (total < 0) + total = count; + var args = new FileProgressedEventArgs {Current = ctr, Total = total, CurrentFile = fileName ?? string.Empty}; + FileProgressed?.Invoke(null, args); + } +} diff --git a/pkNX.Containers/ContainerHandler/FileCountDeterminedEventArgs.cs b/pkNX.Containers/ContainerHandler/FileCountDeterminedEventArgs.cs index 359a4f9b..f056caa0 100644 --- a/pkNX.Containers/ContainerHandler/FileCountDeterminedEventArgs.cs +++ b/pkNX.Containers/ContainerHandler/FileCountDeterminedEventArgs.cs @@ -1,9 +1,8 @@ using System; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class FileCountDeterminedEventArgs : EventArgs { - public class FileCountDeterminedEventArgs : EventArgs - { - public int Total { get; set; } - } -} \ No newline at end of file + public int Total { get; set; } +} diff --git a/pkNX.Containers/ContainerHandler/FileProgressedEventArgs.cs b/pkNX.Containers/ContainerHandler/FileProgressedEventArgs.cs index 2a7a2aba..502b782a 100644 --- a/pkNX.Containers/ContainerHandler/FileProgressedEventArgs.cs +++ b/pkNX.Containers/ContainerHandler/FileProgressedEventArgs.cs @@ -1,11 +1,10 @@ -using System; +using System; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class FileProgressedEventArgs : EventArgs { - public class FileProgressedEventArgs : EventArgs - { - public int Current { get; set; } - public int Total { get; set; } - public string? CurrentFile { get; set; } - } -} \ No newline at end of file + public int Current { get; set; } + public int Total { get; set; } + public string? CurrentFile { get; set; } +} diff --git a/pkNX.Containers/ContainerParent.cs b/pkNX.Containers/ContainerParent.cs index 87b2d6be..1490d5fd 100644 --- a/pkNX.Containers/ContainerParent.cs +++ b/pkNX.Containers/ContainerParent.cs @@ -1,15 +1,14 @@ -namespace pkNX.Containers -{ - public enum ContainerParent - { - /// - /// File is located in the RomFS. - /// - RomFS, +namespace pkNX.Containers; - /// - /// File is located in the ExeFS. - /// - ExeFS, - } -} \ No newline at end of file +public enum ContainerParent +{ + /// + /// File is located in the RomFS. + /// + RomFS, + + /// + /// File is located in the ExeFS. + /// + ExeFS, +} diff --git a/pkNX.Containers/ContainerType.cs b/pkNX.Containers/ContainerType.cs index 9b08d11b..b9aa0123 100644 --- a/pkNX.Containers/ContainerType.cs +++ b/pkNX.Containers/ContainerType.cs @@ -1,12 +1,11 @@ -namespace pkNX.Containers +namespace pkNX.Containers; + +public enum ContainerType { - public enum ContainerType - { - GARC, - Mini, - SARC, - Folder, - SingleFile, - GFPack, - } + GARC, + Mini, + SARC, + Folder, + SingleFile, + GFPack, } diff --git a/pkNX.Containers/FakeContainer.cs b/pkNX.Containers/FakeContainer.cs index 6d20bf20..09fcca01 100644 --- a/pkNX.Containers/FakeContainer.cs +++ b/pkNX.Containers/FakeContainer.cs @@ -1,55 +1,54 @@ -using System.IO; +using System.IO; using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class FakeContainer : IFileContainer { - public class FakeContainer : IFileContainer + public readonly byte[][] Files; + private readonly byte[][] Backup; + + public FakeContainer(byte[][] files) { - public readonly byte[][] Files; - private readonly byte[][] Backup; + Files = files; + Backup = new byte[files.Length][]; + for (int i = 0; i < Backup.Length; i++) + Backup[i] = (byte[])files[i].Clone(); + } - public FakeContainer(byte[][] files) + public string? FilePath { get; set; } = string.Empty; + public bool Modified { get; set; } + public int Count => Files.Length; + + public byte[] this[int index] + { + get => Files[index]; + set => Files[index] = value; + } + + public Task GetFiles() => Task.FromResult(Files); + public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[file]); + public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(this[file] = value); + public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => SaveAll(path, handler, token), token); + + public void SaveAll(string path, ContainerHandler handler, CancellationToken token) + { + handler.Initialize(Files.Length); + for (int i = 0; i < Files.Length; i++) { - Files = files; - Backup = new byte[files.Length][]; - for (int i = 0; i < Backup.Length; i++) - Backup[i] = (byte[])files[i].Clone(); - } - - public string? FilePath { get; set; } = string.Empty; - public bool Modified { get; set; } - public int Count => Files.Length; - - public byte[] this[int index] - { - get => Files[index]; - set => Files[index] = value; - } - - public Task GetFiles() => Task.FromResult(Files); - public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[file]); - public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(this[file] = value); - public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => SaveAll(path, handler, token), token); - - public void SaveAll(string path, ContainerHandler handler, CancellationToken token) - { - handler.Initialize(Files.Length); - for (int i = 0; i < Files.Length; i++) - { - if (token.IsCancellationRequested) - return; - File.WriteAllBytes(Path.Combine(path, $"{i}.bin"), Files[i]); - handler.StepFile(i); - } - } - - public void Dump(string path, ContainerHandler handler) => SaveAs(path, handler, CancellationToken.None); - - public void CancelEdits() - { - for (int i = 0; i < Files.Length; i++) - Files[i] = (byte[])Backup[i].Clone(); + if (token.IsCancellationRequested) + return; + File.WriteAllBytes(Path.Combine(path, $"{i}.bin"), Files[i]); + handler.StepFile(i); } } -} \ No newline at end of file + + public void Dump(string path, ContainerHandler handler) => SaveAs(path, handler, CancellationToken.None); + + public void CancelEdits() + { + for (int i = 0; i < Files.Length; i++) + Files[i] = (byte[])Backup[i].Clone(); + } +} diff --git a/pkNX.Containers/FileMitm.cs b/pkNX.Containers/FileMitm.cs index dd62a41e..b5d99f96 100644 --- a/pkNX.Containers/FileMitm.cs +++ b/pkNX.Containers/FileMitm.cs @@ -1,59 +1,65 @@ -using System.IO; +using System; +using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// Man in the middle redirection of file r/w requests +/// +public static class FileMitm { - /// - /// Man in the middle redirection of file r/w requests - /// - public static class FileMitm + public static bool Enabled { get; private set; } + + public static void EnableIfSetup() => Enabled = PathOriginal != null; + public static void Disable() => Enabled = false; + + private static string? PathOriginal; + private static string? PathRedirect; + + public static byte[] ReadAllBytes(string path) { - public static bool Enabled { get; private set; } - - public static void EnableIfSetup() => Enabled = PathOriginal != null; - public static void Disable() => Enabled = false; - - private static string? PathOriginal; - private static string? PathRedirect; - - public static byte[] ReadAllBytes(string path) - { - path = GetRedirectedReadPath(path); - return File.ReadAllBytes(path); - } - - public static void WriteAllBytes(string path, byte[] data) - { - if (string.IsNullOrWhiteSpace(path)) - throw new FileNotFoundException("Invalid filename."); - path = GetRedirectedWritePath(path); - File.WriteAllBytes(path, data); - } - - public static string GetRedirectedReadPath(string path) - { - if (!Enabled) - return path; - var newDest = path.Replace(PathOriginal, PathRedirect); - if (!File.Exists(newDest)) - return path; - return newDest; - } - - public static string GetRedirectedWritePath(string path) - { - if (!Enabled) - return path; - var newDest = path.Replace(PathOriginal, PathRedirect); - var parent = Path.GetDirectoryName(newDest); - Directory.CreateDirectory(parent); - return newDest; - } - - public static void SetRedirect(string original, string dest) - { - PathOriginal = original; - PathRedirect = dest; - Enabled = true; - } + path = GetRedirectedReadPath(path); + return File.ReadAllBytes(path); } -} \ No newline at end of file + + public static void WriteAllBytes(string path, byte[] data) + { + if (string.IsNullOrWhiteSpace(path)) + throw new FileNotFoundException("Invalid filename."); + path = GetRedirectedWritePath(path); + File.WriteAllBytes(path, data); + } + + public static string GetRedirectedReadPath(string path) + { + if (!Enabled) + return path; + if (PathOriginal is null) + throw new ArgumentException("No original path specified."); + var newDest = path.Replace(PathOriginal, PathRedirect); + if (!File.Exists(newDest)) + return path; + return newDest; + } + + public static string GetRedirectedWritePath(string path) + { + if (!Enabled) + return path; + if (PathOriginal is null) + throw new ArgumentException("No original path specified."); + var newDest = path.Replace(PathOriginal, PathRedirect); + var parent = Path.GetDirectoryName(newDest); + if (parent is null) + throw new ArgumentException("Invalid path specified."); + Directory.CreateDirectory(parent); + return newDest; + } + + public static void SetRedirect(string original, string dest) + { + PathOriginal = original; + PathRedirect = dest; + Enabled = true; + } +} diff --git a/pkNX.Containers/FolderContainer.cs b/pkNX.Containers/FolderContainer.cs index bdba1751..8eac08dc 100644 --- a/pkNX.Containers/FolderContainer.cs +++ b/pkNX.Containers/FolderContainer.cs @@ -1,126 +1,127 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class FolderContainer : IFileContainer { - public class FolderContainer : IFileContainer + private readonly List Paths = new(); + private readonly List Data = new(); + private readonly List TrackModify = new(); + + public string? FilePath { get; set; } + + public FolderContainer() { } + public FolderContainer(IEnumerable files) => AddFiles(files); + + public FolderContainer(string path) => FilePath = path; + public FolderContainer(string path, Func filter) : this(path) => Initialize(filter); + + public IReadOnlyList GetPaths() => Paths; + + public void Initialize(Func? filter = null) { - private readonly List Paths = new(); - private readonly List Data = new(); - private readonly List TrackModify = new(); + if (Paths.Count > 0) + return; // already initialized + if (FilePath is null) + throw new ArgumentException("No path specified to initialize from."); + IEnumerable files = Directory.GetFiles(FilePath, "*", SearchOption.AllDirectories); + if (filter != null) + files = files.Where(filter); + files = files.OrderBy(z => Path.GetFileName(z).Length); // alphabetical sorting doesn't play nice with 100 & 1000 + AddFiles(files); + } - public string? FilePath { get; set; } + public void AddFile(string file, byte[]? data = null) + { + Paths.Add(file); + Data.Add(data); + TrackModify.Add(false); + } - public FolderContainer() { } - public FolderContainer(IEnumerable files) => AddFiles(files); + public void AddFiles(IEnumerable files) + { + foreach (var f in files) + AddFile(f); + } - public FolderContainer(string path) => FilePath = path; - public FolderContainer(string path, Func filter) : this(path) => Initialize(filter); + public byte[]? GetFileData(string file) + { + var index = Paths.FindIndex(z => Path.GetFileName(z) == file); + if (index < 0) + return null; + string path = Paths[index]; + var data = Data[index] ??= FileMitm.ReadAllBytes(path); + return (byte[])data.Clone(); + } - public IReadOnlyList GetPaths() => Paths; + public byte[] GetFileData(int index) + { + var data = Data[index] ??= FileMitm.ReadAllBytes(Paths[index]); + return (byte[])data.Clone(); + } - public void Initialize(Func? filter = null) + public byte[] this[int index] + { + get => GetFileData(index); + set { - if (Paths.Count > 0) - return; // already initialized - IEnumerable files = Directory.GetFiles(FilePath, "*", SearchOption.AllDirectories); - if (filter != null) - files = files.Where(filter); - files = files.OrderBy(z => Path.GetFileName(z).Length); // alphabetical sorting doesn't play nice with 100 & 1000 - AddFiles(files); - } + var current = Data[index] ??= GetFileData(index); + TrackModify[index] = !value.SequenceEqual(current); - public void AddFile(string file, byte[]? data = null) - { - Paths.Add(file); - Data.Add(data); - TrackModify.Add(false); - } - - public void AddFiles(IEnumerable files) - { - foreach (var f in files) - AddFile(f); - } - - public byte[]? GetFileData(string file) - { - var index = Paths.FindIndex(z => Path.GetFileName(z) == file); - if (index < 0) - return null; - string path = Paths[index]; - var data = Data[index] ??= FileMitm.ReadAllBytes(path); - return (byte[])data.Clone(); - } - - public byte[] GetFileData(int index) - { - var data = Data[index] ??= FileMitm.ReadAllBytes(Paths[index]); - return (byte[])data.Clone(); - } - - public byte[] this[int index] - { - get => GetFileData(index); - set - { - var current = Data[index] ??= GetFileData(index); - TrackModify[index] = !value.SequenceEqual(current); - - Data[index] = value; - } - } - - public void ResetIndex(int index) - { - Data[index] = null; - TrackModify[index] = false; - } - - public string GetFileName(int index) => Paths[index]; - - public bool Modified - { - get => TrackModify.Count(z => z) != 0; - set => CancelEdits(); - } - - public int Count => Paths.Count; - - public Task GetFiles() => Task.FromResult(Paths.Select(FileMitm.ReadAllBytes).ToArray()); - public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[file]); - public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(this[file] = value); - public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(SaveAll, token); - - private void SaveAll() - { - for (int i = 0; i < Paths.Count; i++) - { - if (!TrackModify[i]) - continue; - var data = Data[i]; - if (data == null) - continue; - FileMitm.WriteAllBytes(Paths[i], data); - } - } - - public void CancelEdits() - { - for (int i = 0; i < TrackModify.Count; i++) - { - TrackModify[i] = false; - Data[i] = null; - } - } - - public void Dump(string path, ContainerHandler handler) - { - SaveAll(); // there's really nothing to dump, just save any modified + Data[index] = value; } } + + public void ResetIndex(int index) + { + Data[index] = null; + TrackModify[index] = false; + } + + public string GetFileName(int index) => Paths[index]; + + public bool Modified + { + get => TrackModify.Contains(true); + set => CancelEdits(); + } + + public int Count => Paths.Count; + + public Task GetFiles() => Task.FromResult(Paths.Select(FileMitm.ReadAllBytes).ToArray()); + public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[file]); + public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(this[file] = value); + public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(SaveAll, token); + + private void SaveAll() + { + for (int i = 0; i < Paths.Count; i++) + { + if (!TrackModify[i]) + continue; + var data = Data[i]; + if (data == null) + continue; + FileMitm.WriteAllBytes(Paths[i], data); + } + } + + public void CancelEdits() + { + for (int i = 0; i < TrackModify.Count; i++) + { + TrackModify[i] = false; + Data[i] = null; + } + } + + public void Dump(string path, ContainerHandler handler) + { + SaveAll(); // there's really nothing to dump, just save any modified + } } diff --git a/pkNX.Containers/GARC/FATB.cs b/pkNX.Containers/GARC/FATB.cs index 9e624d33..36558284 100644 --- a/pkNX.Containers/GARC/FATB.cs +++ b/pkNX.Containers/GARC/FATB.cs @@ -1,54 +1,53 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +internal class FATB { - internal class FATB + private const uint MAGIC = 0x46415442; + + private readonly uint Magic = MAGIC; + private readonly int HeaderSize = 0xC; + private readonly ushort EntryCount; + private readonly short Padding = -1; + + private FATBEntry[] Entries { get; } + public FATBEntry this[int index] => Entries[index]; + + public FATB(BinaryReader br, int DataOffset) { - private const uint MAGIC = 0x46415442; + Magic = br.ReadUInt32(); + HeaderSize = br.ReadInt32(); + EntryCount = br.ReadUInt16(); + Padding = br.ReadInt16(); - private readonly uint Magic = MAGIC; - private readonly int HeaderSize = 0xC; - private readonly ushort EntryCount; - private readonly short Padding = -1; + Entries = new FATBEntry[EntryCount]; + for (int i = 0; i < EntryCount; i++) + Entries[i] = new FATBEntry(br, DataOffset); + } - private FATBEntry[] Entries { get; } - public FATBEntry this[int index] => Entries[index]; - - public FATB(BinaryReader br, int DataOffset) + public FATB(IReadOnlyList files) + { + EntryCount = (ushort)files.Count; + Entries = new FATBEntry[EntryCount]; + for (int i = 0; i < EntryCount; i++) { - Magic = br.ReadUInt32(); - HeaderSize = br.ReadInt32(); - EntryCount = br.ReadUInt16(); - Padding = br.ReadInt16(); - - Entries = new FATBEntry[EntryCount]; - for (int i = 0; i < EntryCount; i++) - Entries[i] = new FATBEntry(br, DataOffset); - } - - public FATB(IReadOnlyList files) - { - EntryCount = (ushort)files.Count; - Entries = new FATBEntry[EntryCount]; - for (int i = 0; i < EntryCount; i++) - { - if (!Directory.Exists(files[i])) - Entries[i] = new FATBEntry(files[i]); - else - Entries[i] = new FATBEntry(Directory.GetFiles(files[i])); - } - } - - public void Write(BinaryWriter bw) - { - bw.Write(Magic); - bw.Write(HeaderSize); - bw.Write(EntryCount); - bw.Write(Padding); - foreach (var entry in Entries) - entry.Write(bw); - // sub entry writing handled separately + if (!Directory.Exists(files[i])) + Entries[i] = new FATBEntry(files[i]); + else + Entries[i] = new FATBEntry(Directory.GetFiles(files[i])); } } -} \ No newline at end of file + + public void Write(BinaryWriter bw) + { + bw.Write(Magic); + bw.Write(HeaderSize); + bw.Write(EntryCount); + bw.Write(Padding); + foreach (var entry in Entries) + entry.Write(bw); + // sub entry writing handled separately + } +} diff --git a/pkNX.Containers/GARC/FATBEntry.cs b/pkNX.Containers/GARC/FATBEntry.cs index 06068fb9..e9f89096 100644 --- a/pkNX.Containers/GARC/FATBEntry.cs +++ b/pkNX.Containers/GARC/FATBEntry.cs @@ -1,127 +1,126 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; -namespace pkNX.Containers +namespace pkNX.Containers; + +internal class FATBEntry { - internal class FATBEntry + private readonly uint Vector; + public readonly bool IsFolder; + public readonly FATBSubEntry[] SubEntries; + + private FATBEntry() { - private readonly uint Vector; - public readonly bool IsFolder; - public readonly FATBSubEntry[] SubEntries; + var sub = SubEntries = new FATBSubEntry[32]; + for (int i = 0; i < sub.Length; i++) + sub[i] = new FATBSubEntry(); + } - private FATBEntry() + public FATBEntry(string file) : this() + { + IsFolder = false; + Vector = 1; + SubEntries[0].Exists = true; + SubEntries[0].File = file; + } + + public FATBEntry(IEnumerable files) : this() + { + IsFolder = true; + Vector = 0; + foreach (var f in files) { - var sub = SubEntries = new FATBSubEntry[32]; - for (int i = 0; i < sub.Length; i++) - sub[i] = new FATBSubEntry(); - } + var fn = Path.GetFileNameWithoutExtension(f); + if (!int.TryParse(fn, out var val) || val >= SubEntries.Length) + continue; + if (FATBSubEntry.GetFileNumber(val) != fn) + continue; - public FATBEntry(string file) : this() - { - IsFolder = false; - Vector = 1; - SubEntries[0].Exists = true; - SubEntries[0].File = file; - } + Vector |= (uint)(1 << val); - public FATBEntry(IEnumerable files) : this() - { - IsFolder = true; - Vector = 0; - foreach (var f in files) - { - var fn = Path.GetFileNameWithoutExtension(f); - if (!int.TryParse(fn, out var val) || val >= SubEntries.Length) - continue; - if (FATBSubEntry.GetFileNumber(val) != fn) - continue; - - Vector |= (uint)(1 << val); - - SubEntries[val].Exists = true; - SubEntries[val].File = f; - } - } - - public FATBEntry(BinaryReader br, int DataOffset) : this() - { - Vector = br.ReadUInt32(); - - int ctr = 0; - for (int b = 0; b < 32; b++) - { - SubEntries[b].Exists = (Vector & 1 << b) != 0; - if (!SubEntries[b].Exists) - continue; - SubEntries[b].Start = br.ReadInt32(); - SubEntries[b].End = br.ReadInt32(); - SubEntries[b].Length = br.ReadInt32(); - SubEntries[b].ParentDataPosition = DataOffset; - ctr++; - } - IsFolder = ctr > 1; - } - - public void Write(BinaryWriter bw) - { - bw.Write(Vector); - foreach (var s in SubEntries.Where(s => s.Exists)) - { - bw.Write(s.Start); - bw.Write(s.End); - bw.Write(s.Length); - } - } - - public void WriteEntries(BinaryWriter bw, Stream originalStream, int padToNearest, int DataOffset, ref int max, ref int maxPad) - { - var dest = bw.BaseStream; - - bw.Write(Vector); - foreach (var entry in SubEntries.Where(z => z.Exists)) - { - entry.Write(originalStream, dest, DataOffset); - - int padding = GetPadding(entry.Length, padToNearest); - if (max < entry.Length) - { - max = entry.Length; - maxPad = entry.Length + padding; - } - - while (padding-- > 0) - bw.Write((byte)0xFF); - } - } - - private static int GetPadding(int length, int padTo) - { - var remain = length % padTo; - return remain == 0 ? 0 : padTo - remain; - } - - public void Dump(string path, int index, string format, Stream parent, int DataOffset) - { - var fn = index.ToString(format); - if (!IsFolder) - { - var loc = Path.Combine(path, fn + ".bin"); - SubEntries[0].Dump(parent, loc, DataOffset); - return; - } - - path = Path.Combine(path, fn); - Directory.CreateDirectory(path); - for (var i = 0; i < SubEntries.Length; i++) - { - var entry = SubEntries[i]; - if (!entry.Exists) - continue; - fn = i.ToString("D2"); - var loc = Path.Combine(path, fn + ".bin"); - entry.Dump(parent, loc, DataOffset); - } + SubEntries[val].Exists = true; + SubEntries[val].File = f; } } -} \ No newline at end of file + + public FATBEntry(BinaryReader br, int DataOffset) : this() + { + Vector = br.ReadUInt32(); + + int ctr = 0; + for (int b = 0; b < 32; b++) + { + SubEntries[b].Exists = (Vector & 1 << b) != 0; + if (!SubEntries[b].Exists) + continue; + SubEntries[b].Start = br.ReadInt32(); + SubEntries[b].End = br.ReadInt32(); + SubEntries[b].Length = br.ReadInt32(); + SubEntries[b].ParentDataPosition = DataOffset; + ctr++; + } + IsFolder = ctr > 1; + } + + public void Write(BinaryWriter bw) + { + bw.Write(Vector); + foreach (var s in SubEntries.Where(s => s.Exists)) + { + bw.Write(s.Start); + bw.Write(s.End); + bw.Write(s.Length); + } + } + + public void WriteEntries(BinaryWriter bw, Stream originalStream, int padToNearest, int DataOffset, ref int max, ref int maxPad) + { + var dest = bw.BaseStream; + + bw.Write(Vector); + foreach (var entry in SubEntries.Where(z => z.Exists)) + { + entry.Write(originalStream, dest, DataOffset); + + int padding = GetPadding(entry.Length, padToNearest); + if (max < entry.Length) + { + max = entry.Length; + maxPad = entry.Length + padding; + } + + while (padding-- > 0) + bw.Write((byte)0xFF); + } + } + + private static int GetPadding(int length, int padTo) + { + var remain = length % padTo; + return remain == 0 ? 0 : padTo - remain; + } + + public void Dump(string path, int index, string format, Stream parent, int DataOffset) + { + var fn = index.ToString(format); + if (!IsFolder) + { + var loc = Path.Combine(path, fn + ".bin"); + SubEntries[0].Dump(parent, loc, DataOffset); + return; + } + + path = Path.Combine(path, fn); + Directory.CreateDirectory(path); + for (var i = 0; i < SubEntries.Length; i++) + { + var entry = SubEntries[i]; + if (!entry.Exists) + continue; + fn = i.ToString("D2"); + var loc = Path.Combine(path, fn + ".bin"); + entry.Dump(parent, loc, DataOffset); + } + } +} diff --git a/pkNX.Containers/GARC/FATBSubEntry.cs b/pkNX.Containers/GARC/FATBSubEntry.cs index 0c97dc02..b7ca57d4 100644 --- a/pkNX.Containers/GARC/FATBSubEntry.cs +++ b/pkNX.Containers/GARC/FATBSubEntry.cs @@ -1,8 +1,7 @@ -namespace pkNX.Containers +namespace pkNX.Containers; + +public class FATBSubEntry : LargeContainerEntry { - public class FATBSubEntry : LargeContainerEntry - { - public bool Exists; - public static string GetFileNumber(int index) => $"{index:00}"; - } -} \ No newline at end of file + public bool Exists; + public static string GetFileNumber(int index) => $"{index:00}"; +} diff --git a/pkNX.Containers/GARC/FATO.cs b/pkNX.Containers/GARC/FATO.cs index 9b166b84..9fd9e484 100644 --- a/pkNX.Containers/GARC/FATO.cs +++ b/pkNX.Containers/GARC/FATO.cs @@ -1,47 +1,46 @@ -using System.IO; +using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +internal class FATO { - internal class FATO + private const uint MAGIC = 0x4641544F; + + private readonly uint Magic = MAGIC; + private readonly int HeaderSize = 0xC; + public readonly ushort EntryCount; + private readonly short Padding = -1; + + private FATOEntry[] Entries { get; } + public FATOEntry this[int index] => Entries[index]; + + public FATO(BinaryReader br) { - private const uint MAGIC = 0x4641544F; + Magic = br.ReadUInt32(); + HeaderSize = br.ReadInt32(); + EntryCount = br.ReadUInt16(); + Padding = br.ReadInt16(); - private readonly uint Magic = MAGIC; - private readonly int HeaderSize = 0xC; - public readonly ushort EntryCount; - private readonly short Padding = -1; - - private FATOEntry[] Entries { get; } - public FATOEntry this[int index] => Entries[index]; - - public FATO(BinaryReader br) - { - Magic = br.ReadUInt32(); - HeaderSize = br.ReadInt32(); - EntryCount = br.ReadUInt16(); - Padding = br.ReadInt16(); - - Entries = new FATOEntry[EntryCount]; - for (int i = 0; i < EntryCount; i++) - Entries[i] = new FATOEntry(br); - } - - public FATO(int count) - { - EntryCount = (ushort)count; - Entries = new FATOEntry[EntryCount]; - for (int i = 0; i < EntryCount; i++) - Entries[i] = new FATOEntry(); - } - - public void Write(BinaryWriter bw) - { - bw.Write(Magic); - bw.Write(HeaderSize); - bw.Write(EntryCount); - bw.Write(Padding); - foreach (var entry in Entries) - entry.Write(bw); - } + Entries = new FATOEntry[EntryCount]; + for (int i = 0; i < EntryCount; i++) + Entries[i] = new FATOEntry(br); } -} \ No newline at end of file + + public FATO(int count) + { + EntryCount = (ushort)count; + Entries = new FATOEntry[EntryCount]; + for (int i = 0; i < EntryCount; i++) + Entries[i] = new FATOEntry(); + } + + public void Write(BinaryWriter bw) + { + bw.Write(Magic); + bw.Write(HeaderSize); + bw.Write(EntryCount); + bw.Write(Padding); + foreach (var entry in Entries) + entry.Write(bw); + } +} diff --git a/pkNX.Containers/GARC/FATOEntry.cs b/pkNX.Containers/GARC/FATOEntry.cs index baf5894e..7356b101 100644 --- a/pkNX.Containers/GARC/FATOEntry.cs +++ b/pkNX.Containers/GARC/FATOEntry.cs @@ -1,14 +1,13 @@ -using System.IO; +using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +internal class FATOEntry { - internal class FATOEntry - { - public uint Offset { get; set; } + public uint Offset { get; set; } - internal FATOEntry(uint offset = 0) => Offset = offset; - internal FATOEntry(BinaryReader br) => Offset = br.ReadUInt32(); + internal FATOEntry(uint offset = 0) => Offset = offset; + internal FATOEntry(BinaryReader br) => Offset = br.ReadUInt32(); - internal void Write(BinaryWriter bw) => bw.Write(Offset); - } -} \ No newline at end of file + internal void Write(BinaryWriter bw) => bw.Write(Offset); +} diff --git a/pkNX.Containers/GARC/GARC.cs b/pkNX.Containers/GARC/GARC.cs index 8592f6c1..668c98f5 100644 --- a/pkNX.Containers/GARC/GARC.cs +++ b/pkNX.Containers/GARC/GARC.cs @@ -1,135 +1,134 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class GARC : LargeContainer { - public class GARC : LargeContainer - { - private GARCHeader Header; - private FATO FATO; - private FATB FATB; + private GARCHeader Header; + private FATO FATO; + private FATB FATB; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public GARC(BinaryReader br) => OpenRead(br); - public GARC(string file) => OpenBinary(file); + public GARC(BinaryReader br) => OpenRead(br); + public GARC(string file) => OpenBinary(file); #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public GARC(IReadOnlyList files, GARCVersion version = GARCVersion.VER_6) - { - Header = new GARCHeader(version); - FATO = new FATO(files.Count); - FATB = new FATB(files); - Files = new byte[]?[files.Count]; - } + public GARC(IReadOnlyList files, GARCVersion version = GARCVersion.VER_6) + { + Header = new GARCHeader(version); + FATO = new FATO(files.Count); + FATB = new FATB(files); + Files = new byte[]?[files.Count]; + } - protected override void Initialize() - { - Reader!.BaseStream.Position = 0; - Header = new GARCHeader(Reader); - FATO = new FATO(Reader); - FATB = new FATB(Reader, Header.DataOffset); - Files = new byte[]?[FATO.EntryCount]; - } + protected override void Initialize() + { + Reader!.BaseStream.Position = 0; + Header = new GARCHeader(Reader); + FATO = new FATO(Reader); + FATB = new FATB(Reader, Header.DataOffset); + Files = new byte[]?[FATO.EntryCount]; + } - protected override int GetFileOffset(int file, int subFile = 0) - { - var f = FATB[file].SubEntries[subFile]; - return f.Start; - } + protected override int GetFileOffset(int file, int subFile = 0) + { + var f = FATB[file].SubEntries[subFile]; + return f.Start; + } - public override byte[] GetEntry(int index, int subFile) - { - var f = FATB[index].SubEntries[subFile]; - if (f.File is byte[] data) - return data; - - data = f.GetFileData(Reader!.BaseStream); - f.File = data; // cache for future fetches + public override byte[] GetEntry(int index, int subFile) + { + var f = FATB[index].SubEntries[subFile]; + if (f.File is byte[] data) return data; - } - public override void SetEntry(int index, byte[]? value, int subFile) + data = f.GetFileData(Reader!.BaseStream); + f.File = data; // cache for future fetches + return data; + } + + public override void SetEntry(int index, byte[]? value, int subFile) + { + Modified |= value != null && !GetEntry(index, subFile).SequenceEqual(value); + var f = FATB[index].SubEntries[subFile]; + f.File = value; + } + + protected override Task Pack(BinaryWriter bw, ContainerHandler handler, CancellationToken token) + { + return Task.Run(() => PackGARC(bw, handler, token), token); + } + + private void PackGARC(BinaryWriter bw, ContainerHandler handler, CancellationToken token) + { + StartPack(); + handler.Initialize(Count); + + WriteIntro(bw); + int dataOffset = (int)bw.BaseStream.Position; + for (int i = 0; i < Count; i++) { - Modified |= value != null && !GetEntry(index, subFile).SequenceEqual(value); - var f = FATB[index].SubEntries[subFile]; - f.File = value; + if (token.IsCancellationRequested) + return; + WriteEntry(bw, i, dataOffset); } + WriteIntro(bw, true); + bw.Flush(); + } - protected override Task Pack(BinaryWriter bw, ContainerHandler handler, CancellationToken token) + private void StartPack() + { + Header.ContentLargestUnpadded = 0; + Header.ContentLargestPadded = 0; + } + + private void WriteIntro(BinaryWriter bw, bool lastPass = false) + { + Header.Write(bw); + FATO.Write(bw); + FATB.Write(bw); + if (lastPass) + Header.DataOffset = (int)bw.BaseStream.Position; + } + + private void WriteEntry(BinaryWriter bw, int i, int DataOffset) + { + FATO[i].Offset = (uint)bw.BaseStream.Position; + FATB[i].WriteEntries(bw, Reader!.BaseStream, Header.ContentPadToNearest, DataOffset, + ref Header.ContentLargestUnpadded, ref Header.ContentLargestPadded); + } + + public override void Dump(string path, ContainerHandler handler) + { + string format = this.GetFileFormatString(); + + if (!Directory.Exists(path)) + Directory.CreateDirectory(path); + + handler.Initialize(Count); + for (int i = 0; i < Count; i++) { - return Task.Run(() => PackGARC(bw, handler, token), token); - } - - private void PackGARC(BinaryWriter bw, ContainerHandler handler, CancellationToken token) - { - StartPack(); - handler.Initialize(Count); - - WriteIntro(bw); - int dataOffset = (int)bw.BaseStream.Position; - for (int i = 0; i < Count; i++) - { - if (token.IsCancellationRequested) - return; - WriteEntry(bw, i, dataOffset); - } - WriteIntro(bw, true); - bw.Flush(); - } - - private void StartPack() - { - Header.ContentLargestUnpadded = 0; - Header.ContentLargestPadded = 0; - } - - private void WriteIntro(BinaryWriter bw, bool lastPass = false) - { - Header.Write(bw); - FATO.Write(bw); - FATB.Write(bw); - if (lastPass) - Header.DataOffset = (int)bw.BaseStream.Position; - } - - private void WriteEntry(BinaryWriter bw, int i, int DataOffset) - { - FATO[i].Offset = (uint)bw.BaseStream.Position; - FATB[i].WriteEntries(bw, Reader!.BaseStream, Header.ContentPadToNearest, DataOffset, - ref Header.ContentLargestUnpadded, ref Header.ContentLargestPadded); - } - - public override void Dump(string path, ContainerHandler handler) - { - string format = this.GetFileFormatString(); - - if (!Directory.Exists(path)) - Directory.CreateDirectory(path); - - handler.Initialize(Count); - for (int i = 0; i < Count; i++) - { - FATB[i].Dump(path, i, format, Reader!.BaseStream, Header.DataOffset); - handler.StepFile(i+1); - } - } - - public static GARC? GetGARC(BinaryReader br) - { - if (br.BaseStream.Length < 20) - return null; - br.BaseStream.Position = 0; - if (br.ReadUInt32() != GARCHeader.MAGIC) - return null; - br.BaseStream.Position = 10; - var ver = br.ReadUInt16(); - - if (ver is 0x0600 or 0x0400) - return new GARC(br); - return null; + FATB[i].Dump(path, i, format, Reader!.BaseStream, Header.DataOffset); + handler.StepFile(i+1); } } + + public static GARC? GetGARC(BinaryReader br) + { + if (br.BaseStream.Length < 20) + return null; + br.BaseStream.Position = 0; + if (br.ReadUInt32() != GARCHeader.MAGIC) + return null; + br.BaseStream.Position = 10; + var ver = br.ReadUInt16(); + + if (ver is 0x0600 or 0x0400) + return new GARC(br); + return null; + } } diff --git a/pkNX.Containers/GARC/GARCHeader.cs b/pkNX.Containers/GARC/GARCHeader.cs index 376e15b1..8f4004b9 100644 --- a/pkNX.Containers/GARC/GARCHeader.cs +++ b/pkNX.Containers/GARC/GARCHeader.cs @@ -1,98 +1,97 @@ -using System; +using System; using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class GARCHeader { - public class GARCHeader + internal const uint MAGIC = 0x4E415243; // CRAG + private const ushort VER_4 = (ushort)GARCVersion.VER_4; + private const ushort VER_6 = (ushort)GARCVersion.VER_6; + + private readonly uint Magic = MAGIC; + private readonly int HeaderSize; + private readonly ushort Endianess = 0xFEFF; + private readonly ushort Version; + private readonly uint ChunkCount = 4; + + public int DataOffset { get; set; } + public uint FileSize { get; } + + public readonly int ContentPadToNearest = 4; // Format 6 Only (4 bytes is standard in VER_4, and is not stored) + public int ContentLargestUnpadded; + public int ContentLargestPadded; // Format 6 Only + + public bool VER6 => Version == VER_6; + public bool VER4 => Version == VER_4; + + public GARCHeader(GARCVersion version) { - internal const uint MAGIC = 0x4E415243; // CRAG - private const ushort VER_4 = (ushort)GARCVersion.VER_4; - private const ushort VER_6 = (ushort)GARCVersion.VER_6; - - private readonly uint Magic = MAGIC; - private readonly int HeaderSize; - private readonly ushort Endianess = 0xFEFF; - private readonly ushort Version; - private readonly uint ChunkCount = 4; - - public int DataOffset { get; set; } - public uint FileSize { get; } - - public readonly int ContentPadToNearest = 4; // Format 6 Only (4 bytes is standard in VER_4, and is not stored) - public int ContentLargestUnpadded; - public int ContentLargestPadded; // Format 6 Only - - public bool VER6 => Version == VER_6; - public bool VER4 => Version == VER_4; - - public GARCHeader(GARCVersion version) + Version = version switch { - Version = version switch - { - GARCVersion.VER_6 => VER_6, - GARCVersion.VER_4 => VER_4, - _ => (ushort)version, - }; - HeaderSize = VER6 ? 0x24 : 0x1C; - } + GARCVersion.VER_6 => VER_6, + GARCVersion.VER_4 => VER_4, + _ => (ushort)version, + }; + HeaderSize = VER6 ? 0x24 : 0x1C; + } - public GARCHeader(BinaryReader br) + public GARCHeader(BinaryReader br) + { + Magic = br.ReadUInt32(); + HeaderSize = br.ReadInt32(); + Endianess = br.ReadUInt16(); + Version = br.ReadUInt16(); + ChunkCount = br.ReadUInt32(); + + if (ChunkCount != 4) + throw new FormatException($"Invalid GARC Chunk Count: {ChunkCount}"); + + DataOffset = br.ReadInt32(); + FileSize = br.ReadUInt32(); + + switch (Version) { - Magic = br.ReadUInt32(); - HeaderSize = br.ReadInt32(); - Endianess = br.ReadUInt16(); - Version = br.ReadUInt16(); - ChunkCount = br.ReadUInt32(); - - if (ChunkCount != 4) - throw new FormatException($"Invalid GARC Chunk Count: {ChunkCount}"); - - DataOffset = br.ReadInt32(); - FileSize = br.ReadUInt32(); - - switch (Version) - { - case VER_4: - ContentLargestUnpadded = br.ReadInt32(); - ContentPadToNearest = 4; - break; - case VER_6: - ContentLargestPadded = br.ReadInt32(); - ContentLargestUnpadded = br.ReadInt32(); - ContentPadToNearest = br.ReadInt32(); - break; - default: - throw new FormatException($"Invalid GARC Version: 0x{Version:X4}"); - } - } - - public void Write(BinaryWriter bw) - { - bw.Write(Magic); - bw.Write(HeaderSize); - bw.Write(Endianess); - bw.Write(Version); - bw.Write(ChunkCount); - - if (ChunkCount != 4) - throw new FormatException($"Invalid GARC Chunk Count: {ChunkCount}"); - - bw.Write(DataOffset); - bw.Write(FileSize); - - switch (Version) - { - case VER_4: - bw.Write(ContentLargestUnpadded); - break; - case VER_6: - bw.Write(ContentLargestPadded); - bw.Write(ContentLargestUnpadded); - bw.Write(ContentPadToNearest); - break; - default: - throw new FormatException($"Invalid GARC Version: 0x{Version:X4}"); - } + case VER_4: + ContentLargestUnpadded = br.ReadInt32(); + ContentPadToNearest = 4; + break; + case VER_6: + ContentLargestPadded = br.ReadInt32(); + ContentLargestUnpadded = br.ReadInt32(); + ContentPadToNearest = br.ReadInt32(); + break; + default: + throw new FormatException($"Invalid GARC Version: 0x{Version:X4}"); } } -} \ No newline at end of file + + public void Write(BinaryWriter bw) + { + bw.Write(Magic); + bw.Write(HeaderSize); + bw.Write(Endianess); + bw.Write(Version); + bw.Write(ChunkCount); + + if (ChunkCount != 4) + throw new FormatException($"Invalid GARC Chunk Count: {ChunkCount}"); + + bw.Write(DataOffset); + bw.Write(FileSize); + + switch (Version) + { + case VER_4: + bw.Write(ContentLargestUnpadded); + break; + case VER_6: + bw.Write(ContentLargestPadded); + bw.Write(ContentLargestUnpadded); + bw.Write(ContentPadToNearest); + break; + default: + throw new FormatException($"Invalid GARC Version: 0x{Version:X4}"); + } + } +} diff --git a/pkNX.Containers/GARC/GARCVersion.cs b/pkNX.Containers/GARC/GARCVersion.cs index 403f7320..8087748a 100644 --- a/pkNX.Containers/GARC/GARCVersion.cs +++ b/pkNX.Containers/GARC/GARCVersion.cs @@ -1,8 +1,7 @@ -namespace pkNX.Containers +namespace pkNX.Containers; + +public enum GARCVersion : ushort { - public enum GARCVersion : ushort - { - VER_4 = 0x0400, - VER_6 = 0x0600, - } -} \ No newline at end of file + VER_4 = 0x0400, + VER_6 = 0x0600, +} diff --git a/pkNX.Containers/IFileContainer.cs b/pkNX.Containers/IFileContainer.cs index 65ed294c..518c79b5 100644 --- a/pkNX.Containers/IFileContainer.cs +++ b/pkNX.Containers/IFileContainer.cs @@ -1,47 +1,46 @@ -using System; +using System; using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// Array of Files +/// +public interface IFileContainer { /// - /// Array of Files + /// Path the was loaded from. /// - public interface IFileContainer - { - /// - /// Path the was loaded from. - /// - string? FilePath { get; set; } + string? FilePath { get; set; } - /// - /// Indication if the contents of the have been modified. - /// - bool Modified { get; set; } + /// + /// Indication if the contents of the have been modified. + /// + bool Modified { get; set; } - /// - /// Count of files inside the . - /// - int Count { get; } + /// + /// Count of files inside the . + /// + int Count { get; } - /// - /// File access for individually indexed files. - /// - /// File number to fetch - /// Data representing the file at the specified index. - byte[] this[int index] { get; set; } + /// + /// File access for individually indexed files. + /// + /// File number to fetch + /// Data representing the file at the specified index. + byte[] this[int index] { get; set; } - Task GetFiles(); - Task GetFile(int file, int subFile = 0); - Task SetFile(int file, byte[] value, int subFile = 0); - Task SaveAs(string path, ContainerHandler handler, CancellationToken token); + Task GetFiles(); + Task GetFile(int file, int subFile = 0); + Task SetFile(int file, byte[] value, int subFile = 0); + Task SaveAs(string path, ContainerHandler handler, CancellationToken token); - void Dump(string path, ContainerHandler handler); - void CancelEdits(); - } - - public static class FileContainerExtensions - { - public static string GetFileFormatString(this IFileContainer c) => "D" + Math.Ceiling(Math.Log10(c.Count)); - } + void Dump(string path, ContainerHandler handler); + void CancelEdits(); +} + +public static class FileContainerExtensions +{ + public static string GetFileFormatString(this IFileContainer c) => "D" + Math.Ceiling(Math.Log10(c.Count)); } diff --git a/pkNX.Containers/LargeContainer.cs b/pkNX.Containers/LargeContainer.cs index a531d440..0b2048fb 100644 --- a/pkNX.Containers/LargeContainer.cs +++ b/pkNX.Containers/LargeContainer.cs @@ -1,156 +1,155 @@ -using System; +using System; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; using pkNX.Containers; -namespace pkNX +namespace pkNX; + +/// +/// More complex container format for large long lived archives. +/// +public abstract class LargeContainer : IDisposable, IFileContainer { + public virtual int Count => Files.Length; + + public Task GetFiles() => new(() => { CacheAll(); return Files!; }); + public Task GetFile(int file, int subFile = 0) => new(() => GetEntry(file, subFile)); + public Task SetFile(int file, byte[] value, int subFile = 0) => new(() => SetEntry(file, value, subFile)); + + public string? Extension => Path.GetExtension(FilePath); + public string? FileName => Path.GetFileName(FilePath); + public string? FilePath { get; set; } + public bool Modified { get; set; } + + protected byte[]?[] Files = Array.Empty(); + /// - /// More complex container format for large long lived archives. + /// Packs the to the specified writing stream. /// - public abstract class LargeContainer : IDisposable, IFileContainer + /// Stream Writer to write contents to. + /// Manager for monitoring progress. + /// Cancellation object + /// Awaitable Task + protected abstract Task Pack(BinaryWriter bw, ContainerHandler handler, CancellationToken token); + + #region File Reading + + protected BinaryReader? Reader { get; private set; } + private Stream? Stream; + + protected void OpenBinary(string path) { - public virtual int Count => Files.Length; + path = FileMitm.GetRedirectedReadPath(path); + Stream = new FileStream(path, FileMode.Open); + Reader = new BinaryReader(Stream); + Initialize(); + } - public Task GetFiles() => new(() => { CacheAll(); return Files!; }); - public Task GetFile(int file, int subFile = 0) => new(() => GetEntry(file, subFile)); - public Task SetFile(int file, byte[] value, int subFile = 0) => new(() => SetEntry(file, value, subFile)); + protected void OpenRead(BinaryReader br) + { + Reader = br; + Stream = br.BaseStream; + Initialize(); + } - public string? Extension => Path.GetExtension(FilePath); - public string? FileName => Path.GetFileName(FilePath); - public string? FilePath { get; set; } - public bool Modified { get; set; } + protected abstract void Initialize(); - protected byte[]?[] Files = Array.Empty(); + protected abstract int GetFileOffset(int file, int subFile = 0); - /// - /// Packs the to the specified writing stream. - /// - /// Stream Writer to write contents to. - /// Manager for monitoring progress. - /// Cancellation object - /// Awaitable Task - protected abstract Task Pack(BinaryWriter bw, ContainerHandler handler, CancellationToken token); + public BinaryReader Seek(int file, long offset = 0, int subFile = 0) + { + if (Reader == null) + throw new NullReferenceException("Reader is not initialized."); + offset += GetFileOffset(file, subFile); + Reader.BaseStream.Position = offset; + return Reader; + } - #region File Reading + public abstract byte[] GetEntry(int index, int subFile); - protected BinaryReader? Reader { get; private set; } - private Stream? Stream; + public virtual void SetEntry(int index, byte[]? value, int subFile) + { + Files[index] = value; + Modified |= value != null && !this[index].SequenceEqual(value); + } - protected void OpenBinary(string path) + private byte[] GetCachedValue(int i, int subFile) + { + return Files[i] ??= GetEntry(i, subFile); + } + + #endregion + + public byte[] this[int index] + { + get => (byte[]) GetCachedValue(index, 0).Clone(); + set => SetEntry(index, value, 0); + } + + public void CacheAll() + { + for (int i = 0; i < Files.Length; i++) + Files[i] ??= GetCachedValue(i, 0); + + Reader = null; + Stream?.Close(); + Stream = null; + } + + public void CancelEdits() + { + if (Reader == null) + throw new ArgumentNullException(nameof(Reader)); + + for (int i = 0; i < Files.Length; i++) + Files[i] = null; + + Modified = false; + } + + public abstract void Dump(string path, ContainerHandler handler); + + public async Task SaveAs(string path, ContainerHandler handler, CancellationToken token = new()) + { + bool sameLocation = path == FilePath && Reader != null; + var writePath = sameLocation ? Path.GetTempFileName() : path; + + path = FileMitm.GetRedirectedWritePath(path); + var stream = new FileStream(path, FileMode.CreateNew); + using (var bw = new BinaryWriter(stream)) + await Pack(bw, handler, token).ConfigureAwait(false); + + if (token.IsCancellationRequested) { - path = FileMitm.GetRedirectedReadPath(path); - Stream = new FileStream(path, FileMode.Open); - Reader = new BinaryReader(Stream); - Initialize(); + stream.Close(); + File.Delete(path); + return; } - protected void OpenRead(BinaryReader br) + if (sameLocation && path != writePath) { - Reader = br; - Stream = br.BaseStream; - Initialize(); - } - - protected abstract void Initialize(); - - protected abstract int GetFileOffset(int file, int subFile = 0); - - public BinaryReader Seek(int file, long offset = 0, int subFile = 0) - { - if (Reader == null) - throw new NullReferenceException("Reader is not initialized."); - offset += GetFileOffset(file, subFile); - Reader.BaseStream.Position = offset; - return Reader; - } - - public abstract byte[] GetEntry(int index, int subFile); - - public virtual void SetEntry(int index, byte[]? value, int subFile) - { - Files[index] = value; - Modified |= value != null && !this[index].SequenceEqual(value); - } - - private byte[] GetCachedValue(int i, int subFile) - { - return Files[i] ??= GetEntry(i, subFile); - } - - #endregion - - public byte[] this[int index] - { - get => (byte[]) GetCachedValue(index, 0).Clone(); - set => SetEntry(index, value, 0); - } - - public void CacheAll() - { - for (int i = 0; i < Files.Length; i++) - Files[i] ??= GetCachedValue(i, 0); - - Reader = null; - Stream?.Close(); - Stream = null; - } - - public void CancelEdits() - { - if (Reader == null) - throw new ArgumentNullException(nameof(Reader)); - - for (int i = 0; i < Files.Length; i++) - Files[i] = null; - - Modified = false; - } - - public abstract void Dump(string path, ContainerHandler handler); - - public async Task SaveAs(string path, ContainerHandler handler, CancellationToken token = new()) - { - bool sameLocation = path == FilePath && Reader != null; - var writePath = sameLocation ? Path.GetTempFileName() : path; - - path = FileMitm.GetRedirectedWritePath(path); - var stream = new FileStream(path, FileMode.CreateNew); - using (var bw = new BinaryWriter(stream)) - await Pack(bw, handler, token).ConfigureAwait(false); - - if (token.IsCancellationRequested) - { - stream.Close(); + if (File.Exists(path)) File.Delete(path); - return; - } - - if (sameLocation && path != writePath) - { - if (File.Exists(path)) - File.Delete(path); - File.Move(writePath, path); - } - - Stream?.Dispose(); - Reader?.Dispose(); - - Stream = stream; - Reader = new BinaryReader(Stream); + File.Move(writePath, path); } - public void Dispose() - { - Dispose(true); - } + Stream?.Dispose(); + Reader?.Dispose(); - protected virtual void Dispose(bool disposing) - { - Stream?.Dispose(); - Reader?.Dispose(); - } + Stream = stream; + Reader = new BinaryReader(Stream); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + Stream?.Dispose(); + Reader?.Dispose(); } } diff --git a/pkNX.Containers/LargeContainerEntry.cs b/pkNX.Containers/LargeContainerEntry.cs index 55bbbbbe..ab1b3d68 100644 --- a/pkNX.Containers/LargeContainerEntry.cs +++ b/pkNX.Containers/LargeContainerEntry.cs @@ -1,74 +1,73 @@ -using System.IO; +using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class LargeContainerEntry { - public class LargeContainerEntry + public int Start { get; set; } + public int End { get; set; } + public virtual int Length { get; set; } + public object? File { get; set; } + public int ParentDataPosition { get; set; } + + public byte[] GetFileData(Stream parent) { - public int Start { get; set; } - public int End { get; set; } - public virtual int Length { get; set; } - public object? File { get; set; } - public int ParentDataPosition { get; set; } + parent.Seek(Start + ParentDataPosition, SeekOrigin.Begin); + byte[] data = new byte[Length]; + _ = parent.Read(data, 0, Length); + return data; + } - public byte[] GetFileData(Stream parent) + public void Write(Stream parent, Stream dest, int DataOffset) + { + switch (File) { - parent.Seek(Start + ParentDataPosition, SeekOrigin.Begin); - byte[] data = new byte[Length]; - _ = parent.Read(data, 0, Length); - return data; - } - - public void Write(Stream parent, Stream dest, int DataOffset) - { - switch (File) - { - case string f: - WriteFrom(dest, DataOffset, f); - break; - case byte[] data: - WriteFrom(dest, DataOffset, data); - break; - default: - WriteFrom(dest, DataOffset, parent); - break; - } - } - - private void WriteFrom(Stream dest, int DataOffset, string f) - { - Start = (int)dest.Position - DataOffset; - using (var s = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.None)) - s.CopyTo(dest); - End = (int)dest.Position - DataOffset; - Length = End - Start; - } - - private void WriteFrom(Stream dest, int DataOffset, byte[] data) - { - Start = (int)dest.Position - DataOffset; - Length = data.Length; - End = Start + Length; - - File = data; - dest.Write(data, 0, data.Length); - } - - private void WriteFrom(Stream dest, int DataOffset, Stream source) - { - Start = (int)dest.Position - DataOffset; - End = Start + Length; - - source.Seek(Start + ParentDataPosition, SeekOrigin.Begin); - source.CopyTo(dest, Length); - } - - public void Dump(Stream parent, string path, int DataOffset) - { - if (File is string) - return; - - using var file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); - Write(parent, file, DataOffset); + case string f: + WriteFrom(dest, DataOffset, f); + break; + case byte[] data: + WriteFrom(dest, DataOffset, data); + break; + default: + WriteFrom(dest, DataOffset, parent); + break; } } + + private void WriteFrom(Stream dest, int DataOffset, string f) + { + Start = (int)dest.Position - DataOffset; + using (var s = new FileStream(f, FileMode.Open, FileAccess.Read, FileShare.None)) + s.CopyTo(dest); + End = (int)dest.Position - DataOffset; + Length = End - Start; + } + + private void WriteFrom(Stream dest, int DataOffset, byte[] data) + { + Start = (int)dest.Position - DataOffset; + Length = data.Length; + End = Start + Length; + + File = data; + dest.Write(data, 0, data.Length); + } + + private void WriteFrom(Stream dest, int DataOffset, Stream source) + { + Start = (int)dest.Position - DataOffset; + End = Start + Length; + + source.Seek(Start + ParentDataPosition, SeekOrigin.Begin); + source.CopyTo(dest, Length); + } + + public void Dump(Stream parent, string path, int DataOffset) + { + if (File is string) + return; + + using var file = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None); + Write(parent, file, DataOffset); + } } diff --git a/pkNX.Containers/Mini/Mini.cs b/pkNX.Containers/Mini/Mini.cs index 71d561cf..bc7f34e5 100644 --- a/pkNX.Containers/Mini/Mini.cs +++ b/pkNX.Containers/Mini/Mini.cs @@ -1,70 +1,69 @@ -using System.IO; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class Mini : IFileContainer { - public class Mini : IFileContainer + public string Identifier { get; } + public byte[][] Files { get; private set; } + + public Mini(byte[][] data, string ident) { - public string Identifier { get; } - public byte[][] Files { get; private set; } + Identifier = ident; + Files = data; + Backup = new byte[data.Length][]; + for (int i = 0; i < Backup.Length; i++) + Backup[i] = (byte[])data[i].Clone(); + } - public Mini(byte[][] data, string ident) + public byte[] this[int index] + { + get => (byte[])Files[index].Clone(); + set { - Identifier = ident; - Files = data; - Backup = new byte[data.Length][]; - for (int i = 0; i < Backup.Length; i++) - Backup[i] = (byte[])data[i].Clone(); + Modified |= !Files[index].SequenceEqual(value); + Files[index] = value; } + } - public byte[] this[int index] + public string? FilePath { get; set; } + private readonly byte[][] Backup; + + public bool Modified { get; set; } + public int Count => Files.Length; + + public Task GetFile(int file, int subFile = 0) => Task.FromResult(Files[file]); + public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(Files[file] = value); + public Task GetFiles() => Task.FromResult(Files); + + public void CancelEdits() + { + Modified = false; + Files = new byte[Backup.Length][]; + for (int i = 0; i < Files.Length; i++) + Files[i] = (byte[]) Backup[i].Clone(); + } + + public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => + { + byte[] data = MiniUtil.PackMini(Files, Identifier); + FileMitm.WriteAllBytes(path, data); + }, token); + + public void Dump(string path, ContainerHandler handler) + { + string format = this.GetFileFormatString(); + Directory.CreateDirectory(path); + + handler.Initialize(Count); + for (int i = 0; i < Count; i++) { - get => (byte[])Files[index].Clone(); - set - { - Modified |= !Files[index].SequenceEqual(value); - Files[index] = value; - } - } - - public string? FilePath { get; set; } - private readonly byte[][] Backup; - - public bool Modified { get; set; } - public int Count => Files.Length; - - public Task GetFile(int file, int subFile = 0) => Task.FromResult(Files[file]); - public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(Files[file] = value); - public Task GetFiles() => Task.FromResult(Files); - - public void CancelEdits() - { - Modified = false; - Files = new byte[Backup.Length][]; - for (int i = 0; i < Files.Length; i++) - Files[i] = (byte[]) Backup[i].Clone(); - } - - public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => - { - byte[] data = MiniUtil.PackMini(Files, Identifier); - FileMitm.WriteAllBytes(path, data); - }, token); - - public void Dump(string path, ContainerHandler handler) - { - string format = this.GetFileFormatString(); - Directory.CreateDirectory(path); - - handler.Initialize(Count); - for (int i = 0; i < Count; i++) - { - var fn = Path.Combine(path, i.ToString(format) + ".bin"); - FileMitm.WriteAllBytes(fn, Files[i]); - handler.StepFile(i + 1); - } + var fn = Path.Combine(path, i.ToString(format) + ".bin"); + FileMitm.WriteAllBytes(fn, Files[i]); + handler.StepFile(i + 1); } } } diff --git a/pkNX.Containers/Mini/MiniUtil.cs b/pkNX.Containers/Mini/MiniUtil.cs index c22cb3f1..b07db2b9 100644 --- a/pkNX.Containers/Mini/MiniUtil.cs +++ b/pkNX.Containers/Mini/MiniUtil.cs @@ -1,159 +1,158 @@ -using System; +using System; using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// // Mini Packing Util +/// +public static class MiniUtil { - /// - /// // Mini Packing Util - /// - public static class MiniUtil + public static byte[] PackMini(string folder, string identifier) => PackMini(Directory.GetFiles(folder), identifier); + + public static byte[] PackMini(string[] files, string identifier) { - public static byte[] PackMini(string folder, string identifier) => PackMini(Directory.GetFiles(folder), identifier); + byte[][] fileData = new byte[files.Length][]; + for (int i = 0; i < fileData.Length; i++) + fileData[i] = FileMitm.ReadAllBytes(files[i]); + return PackMini(fileData, identifier); + } - public static byte[] PackMini(string[] files, string identifier) + public static byte[] PackMini(byte[][] fileData, string identifier) + { + // Create new Binary with the relevant header bytes + byte[] data = new byte[4]; + data[0] = (byte)identifier[0]; + data[1] = (byte)identifier[1]; + Array.Copy(BitConverter.GetBytes((ushort)fileData.Length), 0, data, 2, 2); + + int count = fileData.Length; + int dataOffset = 4 + 4 + (count * 4); + + // Start the data filling. + using MemoryStream dataout = new(); + using MemoryStream offsetMap = new(); + using BinaryWriter bd = new(dataout); + using BinaryWriter bo = new(offsetMap); + // For each file... + for (int i = 0; i < count; i++) { - byte[][] fileData = new byte[files.Length][]; - for (int i = 0; i < fileData.Length; i++) - fileData[i] = FileMitm.ReadAllBytes(files[i]); - return PackMini(fileData, identifier); + // Write File Offset + uint fileOffset = (uint)(dataout.Position + dataOffset); + bo.Write(fileOffset); + + // Write File to Stream + bd.Write(fileData[i]); + + // Pad the Data MemoryStream with Zeroes until len%4=0; + while (dataout.Length % 4 != 0) + bd.Write((byte)0); + // File Offset will be updated as the offset is based off of the Data length. + } + // Cap the File + bo.Write((uint)(dataout.Position + dataOffset)); + + using var newPack = new MemoryStream(); + using var header = new MemoryStream(data); + header.WriteTo(newPack); + offsetMap.WriteTo(newPack); + dataout.WriteTo(newPack); + return newPack.ToArray(); + } + + public static byte[][] UnpackMini(string file, string identifier) + { + byte[] fileData = FileMitm.ReadAllBytes(file); + return UnpackMini(fileData, identifier); + } + + public static byte[][] UnpackMini(byte[] fileData, string identifier) + { + if (fileData.Length < 4) + throw new ArgumentOutOfRangeException(nameof(fileData)); + + if (identifier.Length == 2) + { + if (identifier[0] != fileData[0] || identifier[1] != fileData[1]) + throw new FormatException("Prefix does not match."); } - public static byte[] PackMini(byte[][] fileData, string identifier) + int count = BitConverter.ToUInt16(fileData, 2); int ctr = 4; + int start = BitConverter.ToInt32(fileData, ctr); ctr += 4; + byte[][] returnData = new byte[count][]; + for (int i = 0; i < count; i++) { - // Create new Binary with the relevant header bytes - byte[] data = new byte[4]; - data[0] = (byte)identifier[0]; - data[1] = (byte)identifier[1]; - Array.Copy(BitConverter.GetBytes((ushort)fileData.Length), 0, data, 2, 2); - - int count = fileData.Length; - int dataOffset = 4 + 4 + (count * 4); - - // Start the data filling. - using MemoryStream dataout = new(); - using MemoryStream offsetMap = new(); - using BinaryWriter bd = new(dataout); - using BinaryWriter bo = new(offsetMap); - // For each file... - for (int i = 0; i < count; i++) - { - // Write File Offset - uint fileOffset = (uint)(dataout.Position + dataOffset); - bo.Write(fileOffset); - - // Write File to Stream - bd.Write(fileData[i]); - - // Pad the Data MemoryStream with Zeroes until len%4=0; - while (dataout.Length % 4 != 0) - bd.Write((byte)0); - // File Offset will be updated as the offset is based off of the Data length. - } - // Cap the File - bo.Write((uint)(dataout.Position + dataOffset)); - - using var newPack = new MemoryStream(); - using var header = new MemoryStream(data); - header.WriteTo(newPack); - offsetMap.WriteTo(newPack); - dataout.WriteTo(newPack); - return newPack.ToArray(); + int end = BitConverter.ToInt32(fileData, ctr); ctr += 4; + int len = end - start; + byte[] data = new byte[len]; + Buffer.BlockCopy(fileData, start, data, 0, len); + returnData[i] = data; + start = end; } + return returnData; + } - public static byte[][] UnpackMini(string file, string identifier) + public static Mini GetMini(string path) + { + path = FileMitm.GetRedirectedReadPath(path); + using var fs = new FileStream(path, FileMode.Open, FileAccess.Read); + using var br = new BinaryReader(fs); + var result = GetMini(br); + if (result is null) + throw new FormatException($"The file at {path} is not a {nameof(Mini)} file."); + return result; + } + + public static Mini? GetMini(BinaryReader br) + { + var ident = GetIsMini(br); + if (string.IsNullOrEmpty(ident)) + return null; + + br.BaseStream.Position = 0; + var data = br.ReadBytes((int)br.BaseStream.Length); + var unpack = UnpackMini(data, ident); + return new Mini(unpack, ident); + } + + public static string GetIsMini(BinaryReader br) + { + if (br.BaseStream.Length < 12) + return string.Empty; + br.BaseStream.Position = 0; + var ident = br.ReadBytes(2); + var count = br.ReadUInt16(); + + int finalLengthOfs = 4 + (count * 4); + if (br.BaseStream.Length < finalLengthOfs + 4) + return string.Empty; + br.BaseStream.Position = 4 + (count * 4); + var len = br.ReadUInt32(); + if (len != br.BaseStream.Length) + return string.Empty; + return $"{(char)ident[0]}{(char)ident[1]}"; + } + + public static string GetIsMini(string path) + { + try { - byte[] fileData = FileMitm.ReadAllBytes(file); - return UnpackMini(fileData, identifier); - } - - public static byte[][] UnpackMini(byte[] fileData, string identifier) - { - if (fileData.Length < 4) - throw new ArgumentOutOfRangeException(nameof(fileData)); - - if (identifier.Length == 2) - { - if (identifier[0] != fileData[0] || identifier[1] != fileData[1]) - throw new FormatException("Prefix does not match."); - } - - int count = BitConverter.ToUInt16(fileData, 2); int ctr = 4; - int start = BitConverter.ToInt32(fileData, ctr); ctr += 4; - byte[][] returnData = new byte[count][]; - for (int i = 0; i < count; i++) - { - int end = BitConverter.ToInt32(fileData, ctr); ctr += 4; - int len = end - start; - byte[] data = new byte[len]; - Buffer.BlockCopy(fileData, start, data, 0, len); - returnData[i] = data; - start = end; - } - return returnData; - } - - public static Mini GetMini(string path) - { - path = FileMitm.GetRedirectedReadPath(path); - using var fs = new FileStream(path, FileMode.Open, FileAccess.Read); + path = FileMitm.GetRedirectedWritePath(path); + using var fs = new FileStream(path, FileMode.Open); using var br = new BinaryReader(fs); - var result = GetMini(br); - if (result is null) - throw new FormatException($"The file at {path} is not a {nameof(Mini)} file."); - return result; + return GetIsMini(br); } + catch { return string.Empty; } + } - public static Mini? GetMini(BinaryReader br) + public static string GetIsMini(byte[] data) + { + try { - var ident = GetIsMini(br); - if (string.IsNullOrEmpty(ident)) - return null; - - br.BaseStream.Position = 0; - var data = br.ReadBytes((int)br.BaseStream.Length); - var unpack = UnpackMini(data, ident); - return new Mini(unpack, ident); - } - - public static string GetIsMini(BinaryReader br) - { - if (br.BaseStream.Length < 12) - return string.Empty; - br.BaseStream.Position = 0; - var ident = br.ReadBytes(2); - var count = br.ReadUInt16(); - - int finalLengthOfs = 4 + (count * 4); - if (br.BaseStream.Length < finalLengthOfs + 4) - return string.Empty; - br.BaseStream.Position = 4 + (count * 4); - var len = br.ReadUInt32(); - if (len != br.BaseStream.Length) - return string.Empty; - return $"{(char)ident[0]}{(char)ident[1]}"; - } - - public static string GetIsMini(string path) - { - try - { - path = FileMitm.GetRedirectedWritePath(path); - using var fs = new FileStream(path, FileMode.Open); - using var br = new BinaryReader(fs); - return GetIsMini(br); - } - catch { return string.Empty; } - } - - public static string GetIsMini(byte[] data) - { - try - { - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - return GetIsMini(br); - } - catch { return string.Empty; } + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + return GetIsMini(br); } + catch { return string.Empty; } } } diff --git a/pkNX.Containers/Misc/AHTB.cs b/pkNX.Containers/Misc/AHTB.cs index 2ff342a9..ed472175 100644 --- a/pkNX.Containers/Misc/AHTB.cs +++ b/pkNX.Containers/Misc/AHTB.cs @@ -1,64 +1,63 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Runtime.Serialization; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// Asynchronous Hash TaBle containing file names and their corresponding hashes. +/// +/// gfl::container::HashTable +[Serializable] +public class AHTB : Dictionary { - /// - /// Asynchronous Hash TaBle containing file names and their corresponding hashes. - /// - /// gfl::container::HashTable - [Serializable] - public class AHTB : Dictionary + public readonly AHTBEntry[] Entries; + public const uint Magic = 0x42544841; // AHTB + public static bool IsAHTB(byte[] data) => BitConverter.ToUInt32(data, 0) == Magic; + + public AHTB(byte[] table) { - public readonly AHTBEntry[] Entries; - public const uint Magic = 0x42544841; // AHTB - public static bool IsAHTB(byte[] data) => BitConverter.ToUInt32(data, 0) == Magic; + using var ms = new MemoryStream(table); + using var br = new BinaryReader(ms); + var magic = br.ReadUInt32(); + Debug.Assert(magic == Magic); + var count = br.ReadUInt32(); - public AHTB(byte[] table) + Entries = new AHTBEntry[count]; + for (int i = 0; i < count; i++) { - using var ms = new MemoryStream(table); - using var br = new BinaryReader(ms); - var magic = br.ReadUInt32(); - Debug.Assert(magic == Magic); - var count = br.ReadUInt32(); - - Entries = new AHTBEntry[count]; - for (int i = 0; i < count; i++) - { - var e = new AHTBEntry(br); - Entries[i] = e; - if (!ContainsKey(e.Hash)) - Add(e.Hash, e.Name); - } - } - - public int GetIndex(ulong hash) - { - if (!TryGetValue(hash, out _)) - return -1; - return Array.FindIndex(Entries, z => z.Hash == hash); - } - - protected AHTB(SerializationInfo info, StreamingContext context) - { - Entries = this.Select(z => new AHTBEntry(z.Key, (ushort) z.Value.Length, z.Value)).ToArray(); - } - - public int GetIndex(string value) => GetIndex(FnvHash.HashFnv1a_64(value)); - - public IEnumerable Summary => Entries.Select((z, i) => $"{i:0000}\t{z.Summary}"); - public IEnumerable ShortSummary => Entries.Select(z => z.Summary); - - public Dictionary ToDictionary() - { - var map = new Dictionary(); - foreach (var entry in Entries) - map[entry.Hash] = entry.Name; - return map; + var e = new AHTBEntry(br); + Entries[i] = e; + if (!ContainsKey(e.Hash)) + Add(e.Hash, e.Name); } } + + public int GetIndex(ulong hash) + { + if (!TryGetValue(hash, out _)) + return -1; + return Array.FindIndex(Entries, z => z.Hash == hash); + } + + protected AHTB(SerializationInfo info, StreamingContext context) + { + Entries = this.Select(z => new AHTBEntry(z.Key, (ushort) z.Value.Length, z.Value)).ToArray(); + } + + public int GetIndex(string value) => GetIndex(FnvHash.HashFnv1a_64(value)); + + public IEnumerable Summary => Entries.Select((z, i) => $"{i:0000}\t{z.Summary}"); + public IEnumerable ShortSummary => Entries.Select(z => z.Summary); + + public Dictionary ToDictionary() + { + var map = new Dictionary(); + foreach (var entry in Entries) + map[entry.Hash] = entry.Name; + return map; + } } diff --git a/pkNX.Containers/Misc/AHTBEntry.cs b/pkNX.Containers/Misc/AHTBEntry.cs index 985ed370..8745671b 100644 --- a/pkNX.Containers/Misc/AHTBEntry.cs +++ b/pkNX.Containers/Misc/AHTBEntry.cs @@ -1,37 +1,36 @@ -using System.IO; +using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class AHTBEntry { - public class AHTBEntry + public ulong Hash; + public ushort NameLength; + public string Name; + + public AHTBEntry(ulong hash, ushort namelen, string name) { - public ulong Hash; - public ushort NameLength; - public string Name; - - public AHTBEntry(ulong hash, ushort namelen, string name) - { - Hash = hash; - NameLength = namelen; - Name = name; - } - - public AHTBEntry(BinaryReader br) - { - Hash = br.ReadUInt64(); - NameLength = br.ReadUInt16(); - Name = br.ReadStringBytesUntil(0); // could use Length field, but they're always \0 terminated - //Debug.Assert(FnvHash.HashFnv1a_64(Name) == Hash); - //Debug.Assert(Name.Length + 1 == NameLength); // Always null terminated - } - - public void Write(BinaryWriter bw) - { - bw.Write(Hash); - bw.Write(Name.Length + 1); - bw.Write(Name); - bw.Write((byte)0); // \0 terminator - } - - public string Summary => $"{Hash:X16}\t{Name}"; + Hash = hash; + NameLength = namelen; + Name = name; } -} \ No newline at end of file + + public AHTBEntry(BinaryReader br) + { + Hash = br.ReadUInt64(); + NameLength = br.ReadUInt16(); + Name = br.ReadStringBytesUntil(0); // could use Length field, but they're always \0 terminated + //Debug.Assert(FnvHash.HashFnv1a_64(Name) == Hash); + //Debug.Assert(Name.Length + 1 == NameLength); // Always null terminated + } + + public void Write(BinaryWriter bw) + { + bw.Write(Hash); + bw.Write(Name.Length + 1); + bw.Write(Name); + bw.Write((byte)0); // \0 terminator + } + + public string Summary => $"{Hash:X16}\t{Name}"; +} diff --git a/pkNX.Containers/Misc/BinaryRWExtensions.cs b/pkNX.Containers/Misc/BinaryRWExtensions.cs index 3f69d733..5d8dd215 100644 --- a/pkNX.Containers/Misc/BinaryRWExtensions.cs +++ b/pkNX.Containers/Misc/BinaryRWExtensions.cs @@ -1,45 +1,44 @@ -using System.Diagnostics; +using System.Diagnostics; using System.IO; using System.Runtime.InteropServices; using System.Text; -namespace pkNX.Containers +namespace pkNX.Containers; + +public static class BinaryRWExtensions { - public static class BinaryRWExtensions + public static T ReadStruct(this BinaryReader br) where T : struct { - public static T ReadStruct(this BinaryReader br) where T : struct - { - var bytes = br.ReadBytes(Marshal.SizeOf()); - return bytes.ToStructure(); - } - - public static T[] ReadStructArray(this BinaryReader br, uint count) where T : struct - { - Debug.Assert(count < 1000); // pls no - var arr = new T[count]; - for (int i = 0; i < arr.Length; i++) - arr[i] = br.ReadStruct(); - return arr; - } - - public static string ReadNXString(this BinaryReader br) - { - var length = br.ReadUInt16(); - var bytes = br.ReadBytes(length); - var str = Encoding.ASCII.GetString(bytes); - br.ReadByte(); // \0 - if (br.BaseStream.Position % 2 != 0) - br.ReadByte(); // fix align - return str; - } - - public static string ReadStringBytesUntil(this BinaryReader br, byte end = 0) - { - StringBuilder str = new(); - byte b; - while ((b = br.ReadByte()) != end) - str.Append((char)b); - return str.ToString(); - } + var bytes = br.ReadBytes(Marshal.SizeOf()); + return bytes.ToStructure(); } -} \ No newline at end of file + + public static T[] ReadStructArray(this BinaryReader br, uint count) where T : struct + { + Debug.Assert(count < 1000); // pls no + var arr = new T[count]; + for (int i = 0; i < arr.Length; i++) + arr[i] = br.ReadStruct(); + return arr; + } + + public static string ReadNXString(this BinaryReader br) + { + var length = br.ReadUInt16(); + var bytes = br.ReadBytes(length); + var str = Encoding.ASCII.GetString(bytes); + br.ReadByte(); // \0 + if (br.BaseStream.Position % 2 != 0) + br.ReadByte(); // fix align + return str; + } + + public static string ReadStringBytesUntil(this BinaryReader br, byte end = 0) + { + StringBuilder str = new(); + byte b; + while ((b = br.ReadByte()) != end) + str.Append((char)b); + return str.ToString(); + } +} diff --git a/pkNX.Containers/Misc/DatEntry.cs b/pkNX.Containers/Misc/DatEntry.cs index 0330a83a..3705b506 100644 --- a/pkNX.Containers/Misc/DatEntry.cs +++ b/pkNX.Containers/Misc/DatEntry.cs @@ -1,38 +1,37 @@ -using System.IO; +using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +public readonly struct DatEntry { - public readonly struct DatEntry + public readonly ulong Hash; + public readonly int Value; + + public DatEntry(ulong hash, int value) { - public readonly ulong Hash; - public readonly int Value; - - public DatEntry(ulong hash, int value) - { - Hash = hash; - Value = value; - } - - public DatEntry(BinaryReader br) - { - Hash = br.ReadUInt64(); - Value = br.ReadInt32(); - br.ReadInt32(); - } - - public void Write(BinaryWriter bw) - { - bw.Write(Hash); - bw.Write(Value); - bw.Write(0); - } - - public string Summary => $"{Hash:X16}\t{Value}"; - - public override bool Equals(object obj) => obj is DatEntry d && Equals(d); - public bool Equals(DatEntry d) => d.Hash == Hash; - public override int GetHashCode() => Hash.GetHashCode(); - public static bool operator ==(DatEntry left, DatEntry right) => left.Equals(right); - public static bool operator !=(DatEntry left, DatEntry right) => !(left == right); + Hash = hash; + Value = value; } -} \ No newline at end of file + + public DatEntry(BinaryReader br) + { + Hash = br.ReadUInt64(); + Value = br.ReadInt32(); + br.ReadInt32(); + } + + public void Write(BinaryWriter bw) + { + bw.Write(Hash); + bw.Write(Value); + bw.Write(0); + } + + public string Summary => $"{Hash:X16}\t{Value}"; + + public override bool Equals(object? obj) => obj is DatEntry d && Equals(d); + public bool Equals(DatEntry d) => d.Hash == Hash; + public override int GetHashCode() => Hash.GetHashCode(); + public static bool operator ==(DatEntry left, DatEntry right) => left.Equals(right); + public static bool operator !=(DatEntry left, DatEntry right) => !(left == right); +} diff --git a/pkNX.Containers/Misc/DatTable.cs b/pkNX.Containers/Misc/DatTable.cs index 0897caeb..2ce07441 100644 --- a/pkNX.Containers/Misc/DatTable.cs +++ b/pkNX.Containers/Misc/DatTable.cs @@ -1,66 +1,65 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// Data Table for Hash->Value lookup +/// +/// for similar structure. +[Serializable] +public class DatTable : Dictionary { - /// - /// Data Table for Hash->Value lookup - /// - /// for similar structure. - [Serializable] - public class DatTable : Dictionary + // u32 count + // hash-val tuple[count] + + // hash-val tuple: size=0x10 + // - 8byte hash + // - u32(?) index + // - u32(?) unk + + public static bool IsDatTable(byte[] bytes) { - // u32 count - // hash-val tuple[count] - - // hash-val tuple: size=0x10 - // - 8byte hash - // - u32(?) index - // - u32(?) unk - - public static bool IsDatTable(byte[] bytes) - { - // pretty weak, don't call this if you aren't sure! - var count = BitConverter.ToUInt32(bytes, 0); - return 4 + (count * 0x10) == bytes.Length; - } - - private readonly DatEntry[] Entries; - - public DatTable(byte[] data) - { - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - var count = br.ReadInt32(); - - Entries = new DatEntry[count]; - for (int i = 0; i < Entries.Length; i++) - { - var e = new DatEntry(br); - Entries[i] = e; - if (!ContainsKey(e.Hash)) - Add(e.Hash, e.Value); - } - } - - public int GetIndex(ulong hash) - { - if (!TryGetValue(hash, out _)) - return -1; - return Array.FindIndex(Entries, z => z.Hash == hash); - } - - protected DatTable(SerializationInfo info, StreamingContext context) - { - Entries = this.Select(z => new DatEntry(z.Key, z.Value)).ToArray(); - } - - public int GetIndex(string value) => GetIndex(FnvHash.HashFnv1a_64(value)); - - public IEnumerable Summary => Entries.Select((z, i) => $"{i:0000}\t{z.Summary}"); - public IEnumerable ShortSummary => Entries.Select(z => z.Summary); + // pretty weak, don't call this if you aren't sure! + var count = BitConverter.ToUInt32(bytes, 0); + return 4 + (count * 0x10) == bytes.Length; } -} \ No newline at end of file + + private readonly DatEntry[] Entries; + + public DatTable(byte[] data) + { + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + var count = br.ReadInt32(); + + Entries = new DatEntry[count]; + for (int i = 0; i < Entries.Length; i++) + { + var e = new DatEntry(br); + Entries[i] = e; + if (!ContainsKey(e.Hash)) + Add(e.Hash, e.Value); + } + } + + public int GetIndex(ulong hash) + { + if (!TryGetValue(hash, out _)) + return -1; + return Array.FindIndex(Entries, z => z.Hash == hash); + } + + protected DatTable(SerializationInfo info, StreamingContext context) + { + Entries = this.Select(z => new DatEntry(z.Key, z.Value)).ToArray(); + } + + public int GetIndex(string value) => GetIndex(FnvHash.HashFnv1a_64(value)); + + public IEnumerable Summary => Entries.Select((z, i) => $"{i:0000}\t{z.Summary}"); + public IEnumerable ShortSummary => Entries.Select(z => z.Summary); +} diff --git a/pkNX.Containers/Misc/FnvHash.cs b/pkNX.Containers/Misc/FnvHash.cs index 12cf267d..06a2ed0b 100644 --- a/pkNX.Containers/Misc/FnvHash.cs +++ b/pkNX.Containers/Misc/FnvHash.cs @@ -1,114 +1,113 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// Fowler–Noll–Vo non-cryptographic hash +/// +public static class FnvHash { + // 64 bit implementation + private const ulong kFnvPrime_64 = 0x00000100000001b3; + private const ulong kOffsetBasis_64 = 0xCBF29CE484222645; + /// - /// Fowler–Noll–Vo non-cryptographic hash + /// Gets the hash code of the input sequence via the default Fnv1 method. /// - public static class FnvHash + /// Input sequence + /// Initial hash value + /// Computed hash code + public static ulong HashFnv1_64(IEnumerable input, ulong hash = kOffsetBasis_64) { - // 64 bit implementation - private const ulong kFnvPrime_64 = 0x00000100000001b3; - private const ulong kOffsetBasis_64 = 0xCBF29CE484222645; - - /// - /// Gets the hash code of the input sequence via the default Fnv1 method. - /// - /// Input sequence - /// Initial hash value - /// Computed hash code - public static ulong HashFnv1_64(IEnumerable input, ulong hash = kOffsetBasis_64) + foreach (var c in input) { - foreach (var c in input) - { - hash *= kFnvPrime_64; - hash ^= c; - } - return hash; + hash *= kFnvPrime_64; + hash ^= c; } + return hash; + } - /// - /// Gets the hash code of the input sequence via the default Fnv1 method. - /// - /// Input sequence - /// Initial hash value - /// Computed hash code - public static ulong HashFnv1_64(IEnumerable input, ulong hash = kOffsetBasis_64) + /// + /// Gets the hash code of the input sequence via the default Fnv1 method. + /// + /// Input sequence + /// Initial hash value + /// Computed hash code + public static ulong HashFnv1_64(IEnumerable input, ulong hash = kOffsetBasis_64) + { + foreach (var c in input) { - foreach (var c in input) - { - hash *= kFnvPrime_64; - hash ^= c; - } - return hash; + hash *= kFnvPrime_64; + hash ^= c; } + return hash; + } - /// - /// Gets the hash code of the input sequence via the alternative Fnv1 method. - /// - /// Input sequence - /// Initial hash value - /// Computed hash code - public static ulong HashFnv1a_64(IEnumerable input, ulong hash = kOffsetBasis_64) + /// + /// Gets the hash code of the input sequence via the alternative Fnv1 method. + /// + /// Input sequence + /// Initial hash value + /// Computed hash code + public static ulong HashFnv1a_64(IEnumerable input, ulong hash = kOffsetBasis_64) + { + foreach (var c in input) { - foreach (var c in input) - { - hash ^= c; - hash *= kFnvPrime_64; - } - return hash; + hash ^= c; + hash *= kFnvPrime_64; } + return hash; + } - /// - /// Gets the hash code of the input sequence via the alternative Fnv1 method. - /// - /// Input sequence - /// Initial hash value - /// Computed hash code - public static ulong HashFnv1a_64(IEnumerable input, ulong hash = kOffsetBasis_64) + /// + /// Gets the hash code of the input sequence via the alternative Fnv1 method. + /// + /// Input sequence + /// Initial hash value + /// Computed hash code + public static ulong HashFnv1a_64(IEnumerable input, ulong hash = kOffsetBasis_64) + { + foreach (var c in input) { - foreach (var c in input) - { - hash ^= c; - hash *= kFnvPrime_64; - } - return hash; + hash ^= c; + hash *= kFnvPrime_64; } + return hash; + } - // 32 bit implementation - private const uint kFnvPrime_32 = 0x01000193; - private const uint kOffsetBasis_32 = 0x811C9DC5; + // 32 bit implementation + private const uint kFnvPrime_32 = 0x01000193; + private const uint kOffsetBasis_32 = 0x811C9DC5; - /// - /// Gets the hash code of the input sequence via the default Fnv1 method. - /// - /// Input sequence - /// Initial hash value - /// Computed hash code - public static uint HashFnv1_32(IEnumerable input, uint hash = kOffsetBasis_32) + /// + /// Gets the hash code of the input sequence via the default Fnv1 method. + /// + /// Input sequence + /// Initial hash value + /// Computed hash code + public static uint HashFnv1_32(IEnumerable input, uint hash = kOffsetBasis_32) + { + foreach (var c in input) { - foreach (var c in input) - { - hash *= kFnvPrime_32; - hash ^= c; - } - return hash; + hash *= kFnvPrime_32; + hash ^= c; } + return hash; + } - /// - /// Gets the hash code of the input sequence via the alternative Fnv1 method. - /// - /// Input sequence - /// Initial hash value - /// Computed hash code - public static uint HashFnv1a_32(IEnumerable input, uint hash = kOffsetBasis_32) + /// + /// Gets the hash code of the input sequence via the alternative Fnv1 method. + /// + /// Input sequence + /// Initial hash value + /// Computed hash code + public static uint HashFnv1a_32(IEnumerable input, uint hash = kOffsetBasis_32) + { + foreach (var c in input) { - foreach (var c in input) - { - hash ^= c; - hash *= kFnvPrime_32; - } - return hash; + hash ^= c; + hash *= kFnvPrime_32; } + return hash; } } diff --git a/pkNX.Containers/Misc/GFPack.cs b/pkNX.Containers/Misc/GFPack.cs index c4612db5..e52f2dc2 100644 --- a/pkNX.Containers/Misc/GFPack.cs +++ b/pkNX.Containers/Misc/GFPack.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -8,442 +8,443 @@ using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class GFPack : IEnumerable, IFileContainer { - public class GFPack : IEnumerable, IFileContainer - { - public const ulong Magic = 0x4B434150_584C4647; // GFLXPACK + public const ulong Magic = 0x4B434150_584C4647; // GFLXPACK - // Overall structure: Header, metadata, and the raw compressed files - public GFPackHeader Header { get; set; } - public GFPackPointers Pointers { get; set; } - public FileHashAbsolute[] HashAbsolute { get; set; } - public FileHashFolder[] HashInFolder { get; set; } - public FileData[] FileTable { get; set; } + // Overall structure: Header, metadata, and the raw compressed files + public GFPackHeader Header { get; set; } + public GFPackPointers Pointers { get; set; } + public FileHashAbsolute[] HashAbsolute { get; set; } + public FileHashFolder[] HashInFolder { get; set; } + public FileData[] FileTable { get; set; } - public byte[][] CompressedFiles { get; set; } - public byte[][] DecompressedFiles { get; set; } + public byte[][] CompressedFiles { get; set; } + public byte[][] DecompressedFiles { get; set; } #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public GFPack(string path) : this(FileMitm.ReadAllBytes(path)) => FilePath = path; - public GFPack(string[] directories, string parent = @"\bin") => LoadFiles(directories, parent); - - /// - /// Initializes a packed object, and unpacks the data to accessible properties. - /// - /// Packed file - public GFPack(byte[] data) - { - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - ReadPack(br); - } - - public GFPack(BinaryReader br) => ReadPack(br); -#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - - private void ReadPack(BinaryReader br) - { - Header = br.ReadBytes(GFPackHeader.SIZE).ToClass(); - Debug.Assert(Header.MAGIC == Magic); - Pointers = new GFPackPointers(br, Header.CountFolders); - - Debug.Assert(Pointers.PtrHashPaths == br.BaseStream.Position); - HashAbsolute = new FileHashAbsolute[Header.CountFiles]; - for (int i = 0; i < HashAbsolute.Length; i++) - HashAbsolute[i] = br.ReadBytes(FileHashAbsolute.SIZE).ToClass(); - - HashInFolder = new FileHashFolder[Header.CountFolders]; - for (int f = 0; f < HashInFolder.Length; f++) - { - Debug.Assert(Pointers.PtrHashFolders[f] == br.BaseStream.Position); - var table = HashInFolder[f] = new FileHashFolder - { - Folder = br.ReadBytes(FileHashIndex.SIZE).ToClass() - }; - table.Files = new FileHashIndex[table.Folder.FileCount]; - for (int i = 0; i < table.Files.Length; i++) - table.Files[i] = br.ReadBytes(FileHashIndex.SIZE).ToClass(); - } - - Debug.Assert(Pointers.PtrFileTable == br.BaseStream.Position); - FileTable = new FileData[Header.CountFiles]; - for (int i = 0; i < FileTable.Length; i++) - FileTable[i] = br.ReadBytes(FileData.SIZE).ToClass(); - - CompressedFiles = new byte[Header.CountFiles][]; - for (int i = 0; i < CompressedFiles.Length; i++) - { - br.BaseStream.Position = FileTable[i].OffsetPacked; - CompressedFiles[i] = br.ReadBytes(FileTable[i].SizeCompressed); - } - - DecompressedFiles = new byte[Header.CountFiles][]; - for (int i = 0; i < DecompressedFiles.Length; i++) - DecompressedFiles[i] = Decompress(CompressedFiles[i], FileTable[i].SizeDecompressed, FileTable[i].Type); - } - - public IEnumerator GetEnumerator() => (IEnumerator)DecompressedFiles.GetEnumerator(); - IEnumerator IEnumerable.GetEnumerator() => DecompressedFiles.GetEnumerator(); - public int Count => Header.CountFiles; - - public byte[] this[int index] - { - get => (byte[])DecompressedFiles[index].Clone(); - set - { - Modified |= !DecompressedFiles[index].SequenceEqual(value); - DecompressedFiles[index] = value; - } - } - - public int GetIndexFull(ulong hash) => Array.FindIndex(HashAbsolute, z => z.HashFnv1aPathFull == hash); - public int GetIndexFull(string path) => GetIndexFull(FnvHash.HashFnv1a_64(path)); - - public int GetIndexFileName(ulong hash) - { - foreach (var f in HashInFolder) - { - int index = f.GetIndexFileName(hash); - if (index >= 0) - return f.Files[index].Index; - } - return -1; - } - - public int GetIndexFileName(string name) - { - foreach (var f in HashInFolder) - { - int index = f.GetIndexFileName(name); - if (index >= 0) - return f.Files[index].Index; - } - return -1; - } - - public byte[] GetDataFileName(string name) - { - int index = GetIndexFileName(name); - return DecompressedFiles[index]; - } - - public byte[] GetDataFull(ulong hash) => DecompressedFiles[GetIndexFull(hash)]; - - public byte[] GetDataFullPath(string path) => GetDataFull(FnvHash.HashFnv1a_64(path)); - - public void SetDataFileName(string name, byte[] data) - { - int index = GetIndexFileName(name); - DecompressedFiles[index] = data; - } - - public void SetDataFullPath(string path, byte[] data) - { - var hash = FnvHash.HashFnv1a_64(path); - int index = GetIndexFull(hash); - DecompressedFiles[index] = data; - } - - public void LoadFiles(string[] directories, string parent, CompressionType type = CompressionType.Lz4) - { - var groups = directories.Select(Directory.GetFiles).ToArray(); - var files = groups.SelectMany(z => z).ToArray(); - Header = new GFPackHeader { CountFolders = directories.Length, CountFiles = files.Length }; - - HashAbsolute = new FileHashAbsolute[files.Length]; - HashInFolder = new FileHashFolder[groups.Length]; - FileTable = new FileData[files.Length]; - DecompressedFiles = new byte[files.Length][]; - CompressedFiles = new byte[files.Length][]; - - for (int f = 0; f < groups.Length; f++) - { - var folderFiles = groups[f]; - var folderName = Path.GetDirectoryName(directories[f]); - var table = HashInFolder[f] = new FileHashFolder(); - table.Folder = new FileHashFolderInfo - { - FileCount = folderFiles.Length, - HashFnv1aPathFolderName = FnvHash.HashFnv1a_64(folderName), - }; - table.Files = new FileHashIndex[folderFiles.Length]; - for (int i = 0; i < folderFiles.Length; i++) - { - var file = folderFiles[i]; - int index = Array.IndexOf(files, folderFiles[i]); - var nameshort = Path.GetFileName(file); - ulong hashShort = FnvHash.HashFnv1a_64(nameshort); - table.Files[i] = new FileHashIndex { HashFnv1aPathFileName = hashShort, Index = index }; - } - } - - for (var i = 0; i < files.Length; i++) - { - var file = files[i]; - var namelong = file[file.IndexOf(parent, StringComparison.Ordinal)..]; - ulong hashFull = FnvHash.HashFnv1a_64(namelong); - - HashAbsolute[i] = new FileHashAbsolute { HashFnv1aPathFull = hashFull }; - FileTable[i] = new FileData { Type = type }; - DecompressedFiles[i] = FileMitm.ReadAllBytes(file); - } - Modified = true; - } - - public byte[] Write() - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - WriteHeaderTableList(bw); - for (var i = 0; i < DecompressedFiles.Length; i++) - { - var entry = FileTable[i]; - var f = DecompressedFiles[i]; - var c = Compress(f, entry.Type); - CompressedFiles[i] = c; - - // update entry details - entry.SizeDecompressed = f.Length; - entry.SizeCompressed = c.Length; - entry.OffsetPacked = (int)bw.BaseStream.Position; - - bw.Write(c); - while (bw.BaseStream.Position % 0x10 != 0) // pad to nearest 0x10 alignment - bw.Write((byte)0); - } - bw.BaseStream.Position = 0; - WriteHeaderTableList(bw); - return ms.ToArray(); - } - - private static byte[] Decompress(byte[] encryptedData, int decryptedLength, CompressionType type) - { - return type switch - { - CompressionType.None => encryptedData, - CompressionType.Zlib => throw new NotSupportedException(nameof(CompressionType.Zlib)), // not implemented - CompressionType.Lz4 => LZ4.Decode(encryptedData, decryptedLength), - CompressionType.OodleKraken => Oodle.Decompress(encryptedData, decryptedLength)!, - CompressionType.OodleLeviathan => Oodle.Decompress(encryptedData, decryptedLength)!, - CompressionType.OodleMermaid => Oodle.Decompress(encryptedData, decryptedLength)!, - CompressionType.OodleSelkie => Oodle.Decompress(encryptedData, decryptedLength)!, - CompressionType.OodleHydra => Oodle.Decompress(encryptedData, decryptedLength)!, - _ => throw new ArgumentOutOfRangeException(nameof(type)), - }; - } - - private static byte[] Compress(byte[] decryptedData, CompressionType type) - { - return type switch - { - CompressionType.None => decryptedData, - CompressionType.Zlib => throw new NotSupportedException(nameof(CompressionType.Zlib)), // not implemented - CompressionType.Lz4 => LZ4.Encode(decryptedData), - CompressionType.OodleKraken => Oodle.Compress(decryptedData, out _, OodleFormat.Kraken).ToArray(), - CompressionType.OodleLeviathan => Oodle.Compress(decryptedData, out _, OodleFormat.Leviathan).ToArray(), - CompressionType.OodleMermaid => Oodle.Compress(decryptedData, out _, OodleFormat.Mermaid).ToArray(), - CompressionType.OodleSelkie => Oodle.Compress(decryptedData, out _, OodleFormat.Selkie).ToArray(), - CompressionType.OodleHydra => Oodle.Compress(decryptedData, out _, OodleFormat.Hydra).ToArray(), - _ => throw new ArgumentOutOfRangeException(nameof(type)), - }; - } - - public void CancelEdits() - { - for (int i = 0; i < DecompressedFiles.Length; i++) - DecompressedFiles[i] = Decompress(CompressedFiles[i], FileTable[i].SizeDecompressed, FileTable[i].Type); - Modified = false; - } - - private void WriteHeaderTableList(BinaryWriter bw) - { - bw.Write(Header.ToBytesClass()); - Pointers.Write(bw); - Pointers.PtrHashPaths = bw.BaseStream.Position; - foreach (var hp in HashAbsolute) - bw.Write(hp.ToBytesClass()); - - for (var f = 0; f < Pointers.PtrHashFolders.Length; f++) - { - Pointers.PtrHashFolders[f] = bw.BaseStream.Position; - - var folder = HashInFolder[f]; - folder.Folder.FileCount = folder.Files.Length; - bw.Write(folder.Folder.ToBytesClass()); - foreach (var hi in folder.Files) - bw.Write(hi.ToBytesClass()); - } - - Pointers.PtrFileTable = bw.BaseStream.Position; - foreach (var ft in FileTable) - bw.Write(ft.ToBytesClass()); - } - - public string? FilePath { get; set; } - public bool Modified { get; set; } - public Task GetFiles() => Task.FromResult(DecompressedFiles); - public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[file]); - public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(this[file] = value); - public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => FileMitm.WriteAllBytes(path, Write()), token); - - public void Dump(string path, ContainerHandler handler) - { - handler.Initialize(FileTable.Length); - string format = this.GetFileFormatString(); - - foreach (var grp in HashInFolder) - { - var dirName = grp.Folder.HashFnv1aPathFolderName; - foreach (var f in grp.Files) - { - var index = f.Index; - var name = f.HashFnv1aPathFileName; - - var fn = $"{index.ToString(format)} {name:X16}.bin"; - var data = DecompressedFiles[f.Index]; - - var subfolder = HashInFolder.Length == 1 ? fn : Path.Combine(dirName.ToString("X16"), fn); - var loc = Path.Combine(path, subfolder); - FileMitm.WriteAllBytes(loc, data); - } - } - } - } + public GFPack(string path) : this(FileMitm.ReadAllBytes(path)) => FilePath = path; + public GFPack(string[] directories, string parent = @"\bin") => LoadFiles(directories, parent); /// - /// Intro bytes to the packed binary. + /// Initializes a packed object, and unpacks the data to accessible properties. /// - [StructLayout(LayoutKind.Sequential)] - public class GFPackHeader + /// Packed file + public GFPack(byte[] data) { - public const int SIZE = 0x18; - public ulong MAGIC = GFPack.Magic; - public uint Version = 0x1000; - public uint IsRelocated; // bit0 - - /// - /// Count of Files packed into the binary. - /// - public int CountFiles; - - /// - /// Count of Folders packed into the binary. - /// - public int CountFolders; + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + ReadPack(br); } - public class GFPackPointers + public GFPack(BinaryReader br) => ReadPack(br); +#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. + + private void ReadPack(BinaryReader br) { - /// - /// Data offset for the table. - /// - public long PtrFileTable; // array stored at end + Header = br.ReadBytes(GFPackHeader.SIZE).ToClass(); + Debug.Assert(Header.MAGIC == Magic); + Pointers = new GFPackPointers(br, Header.CountFolders); - /// - /// Data offset for the table. - /// - public long PtrHashPaths; // array stored first + Debug.Assert(Pointers.PtrHashPaths == br.BaseStream.Position); + HashAbsolute = new FileHashAbsolute[Header.CountFiles]; + for (int i = 0; i < HashAbsolute.Length; i++) + HashAbsolute[i] = br.ReadBytes(FileHashAbsolute.SIZE).ToClass(); - /// - /// Data offset for the table, which has a leading . - /// - public long[] PtrHashFolders; // array stored in middle - - // immediately after the pointers are the arrays - - public GFPackPointers(BinaryReader br, int folderCount) + HashInFolder = new FileHashFolder[Header.CountFolders]; + for (int f = 0; f < HashInFolder.Length; f++) { - PtrFileTable = br.ReadInt64(); - PtrHashPaths = br.ReadInt64(); - PtrHashFolders = new long[folderCount]; - for (int i = 0; i < PtrHashFolders.Length; i++) - PtrHashFolders[i] = br.ReadInt64(); + Debug.Assert(Pointers.PtrHashFolders[f] == br.BaseStream.Position); + var table = HashInFolder[f] = new FileHashFolder + { + Folder = br.ReadBytes(FileHashIndex.SIZE).ToClass() + }; + table.Files = new FileHashIndex[table.Folder.FileCount]; + for (int i = 0; i < table.Files.Length; i++) + table.Files[i] = br.ReadBytes(FileHashIndex.SIZE).ToClass(); } - public void Write(BinaryWriter bw) + Debug.Assert(Pointers.PtrFileTable == br.BaseStream.Position); + FileTable = new FileData[Header.CountFiles]; + for (int i = 0; i < FileTable.Length; i++) + FileTable[i] = br.ReadBytes(FileData.SIZE).ToClass(); + + CompressedFiles = new byte[Header.CountFiles][]; + for (int i = 0; i < CompressedFiles.Length; i++) { - bw.Write(PtrFileTable); - bw.Write(PtrHashPaths); - foreach (var table in PtrHashFolders) - bw.Write(table); + br.BaseStream.Position = FileTable[i].OffsetPacked; + CompressedFiles[i] = br.ReadBytes(FileTable[i].SizeCompressed); + } + + DecompressedFiles = new byte[Header.CountFiles][]; + for (int i = 0; i < DecompressedFiles.Length; i++) + DecompressedFiles[i] = Decompress(CompressedFiles[i], FileTable[i].SizeDecompressed, FileTable[i].Type); + } + + public IEnumerator GetEnumerator() => (IEnumerator)DecompressedFiles.GetEnumerator(); + IEnumerator IEnumerable.GetEnumerator() => DecompressedFiles.GetEnumerator(); + public int Count => Header.CountFiles; + + public byte[] this[int index] + { + get => (byte[])DecompressedFiles[index].Clone(); + set + { + Modified |= !DecompressedFiles[index].SequenceEqual(value); + DecompressedFiles[index] = value; } } - [StructLayout(LayoutKind.Sequential)] - public class FileHashAbsolute + public int GetIndexFull(ulong hash) => Array.FindIndex(HashAbsolute, z => z.HashFnv1aPathFull == hash); + public int GetIndexFull(string path) => GetIndexFull(FnvHash.HashFnv1a_64(path)); + + public int GetIndexFileName(ulong hash) { - public const int SIZE = 0x08; - - /// - /// Filename (with directory details) hash. - /// - public ulong HashFnv1aPathFull; - - public bool IsMatch(string fileName) => FnvHash.HashFnv1a_64(fileName) == HashFnv1aPathFull; + foreach (var f in HashInFolder) + { + int index = f.GetIndexFileName(hash); + if (index >= 0) + return f.Files[index].Index; + } + return -1; } - public class FileHashFolder + public int GetIndexFileName(string name) { - public FileHashFolderInfo Folder = new(); - public FileHashIndex[] Files = Array.Empty(); - public int GetIndexFileName(ulong hash) => Array.FindIndex(Files, z => z.HashFnv1aPathFileName == hash); - public int GetIndexFileName(string name) => Array.FindIndex(Files, z => z.IsMatch(name)); + foreach (var f in HashInFolder) + { + int index = f.GetIndexFileName(name); + if (index >= 0) + return f.Files[index].Index; + } + return -1; } - [StructLayout(LayoutKind.Sequential)] - public class FileHashFolderInfo + public byte[] GetDataFileName(string name) { - public const int SIZE = 0x10; - - /// - /// Filename (without directory details) hash. - /// - public ulong HashFnv1aPathFolderName; - public int FileCount; - public uint Padding = 0xCC; - - public bool IsMatch(string fileName) => FnvHash.HashFnv1a_64(fileName) == HashFnv1aPathFolderName; + int index = GetIndexFileName(name); + return DecompressedFiles[index]; } - [StructLayout(LayoutKind.Sequential)] - public class FileHashIndex + public byte[] GetDataFull(ulong hash) => DecompressedFiles[GetIndexFull(hash)]; + + public byte[] GetDataFullPath(string path) => GetDataFull(FnvHash.HashFnv1a_64(path)); + + public void SetDataFileName(string name, byte[] data) { - public const int SIZE = 0x10; - - /// - /// Filename (without directory details) hash. - /// - public ulong HashFnv1aPathFileName; - public int Index; - public uint Padding = 0xCC; - - public bool IsMatch(string fileName) => FnvHash.HashFnv1a_64(fileName) == HashFnv1aPathFileName; + int index = GetIndexFileName(name); + DecompressedFiles[index] = data; } - [StructLayout(LayoutKind.Sequential)] - public class FileData + public void SetDataFullPath(string path, byte[] data) { - public const int SIZE = 0x18; - - public ushort Level = 9; // quality? - public CompressionType Type; - public int SizeDecompressed; - public int SizeCompressed; - public int Padding = 0xCC; - public int OffsetPacked; - public uint unused; + var hash = FnvHash.HashFnv1a_64(path); + int index = GetIndexFull(hash); + DecompressedFiles[index] = data; } - public enum CompressionType : ushort + public void LoadFiles(string[] directories, string parent, CompressionType type = CompressionType.Lz4) { - None = 0, - Zlib = 1, - Lz4 = 2, - OodleKraken = 3, - OodleLeviathan = 4, - OodleMermaid = 5, - OodleSelkie = 6, - OodleHydra = 7, + var groups = directories.Select(Directory.GetFiles).ToArray(); + var files = groups.SelectMany(z => z).ToArray(); + Header = new GFPackHeader { CountFolders = directories.Length, CountFiles = files.Length }; + + HashAbsolute = new FileHashAbsolute[files.Length]; + HashInFolder = new FileHashFolder[groups.Length]; + FileTable = new FileData[files.Length]; + DecompressedFiles = new byte[files.Length][]; + CompressedFiles = new byte[files.Length][]; + + for (int f = 0; f < groups.Length; f++) + { + var folderFiles = groups[f]; + var folderName = Path.GetDirectoryName(directories[f]); + if (folderName is null) + throw new Exception("Invalid folder name"); + var table = HashInFolder[f] = new FileHashFolder(); + table.Folder = new FileHashFolderInfo + { + FileCount = folderFiles.Length, + HashFnv1aPathFolderName = FnvHash.HashFnv1a_64(folderName), + }; + table.Files = new FileHashIndex[folderFiles.Length]; + for (int i = 0; i < folderFiles.Length; i++) + { + var file = folderFiles[i]; + int index = Array.IndexOf(files, folderFiles[i]); + var nameshort = Path.GetFileName(file); + ulong hashShort = FnvHash.HashFnv1a_64(nameshort); + table.Files[i] = new FileHashIndex { HashFnv1aPathFileName = hashShort, Index = index }; + } + } + + for (var i = 0; i < files.Length; i++) + { + var file = files[i]; + var namelong = file[file.IndexOf(parent, StringComparison.Ordinal)..]; + ulong hashFull = FnvHash.HashFnv1a_64(namelong); + + HashAbsolute[i] = new FileHashAbsolute { HashFnv1aPathFull = hashFull }; + FileTable[i] = new FileData { Type = type }; + DecompressedFiles[i] = FileMitm.ReadAllBytes(file); + } + Modified = true; + } + + public byte[] Write() + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + WriteHeaderTableList(bw); + for (var i = 0; i < DecompressedFiles.Length; i++) + { + var entry = FileTable[i]; + var f = DecompressedFiles[i]; + var c = Compress(f, entry.Type); + CompressedFiles[i] = c; + + // update entry details + entry.SizeDecompressed = f.Length; + entry.SizeCompressed = c.Length; + entry.OffsetPacked = (int)bw.BaseStream.Position; + + bw.Write(c); + while (bw.BaseStream.Position % 0x10 != 0) // pad to nearest 0x10 alignment + bw.Write((byte)0); + } + bw.BaseStream.Position = 0; + WriteHeaderTableList(bw); + return ms.ToArray(); + } + + private static byte[] Decompress(byte[] encryptedData, int decryptedLength, CompressionType type) + { + return type switch + { + CompressionType.None => encryptedData, + CompressionType.Zlib => throw new NotSupportedException(nameof(CompressionType.Zlib)), // not implemented + CompressionType.Lz4 => LZ4.Decode(encryptedData, decryptedLength), + CompressionType.OodleKraken => Oodle.Decompress(encryptedData, decryptedLength)!, + CompressionType.OodleLeviathan => Oodle.Decompress(encryptedData, decryptedLength)!, + CompressionType.OodleMermaid => Oodle.Decompress(encryptedData, decryptedLength)!, + CompressionType.OodleSelkie => Oodle.Decompress(encryptedData, decryptedLength)!, + CompressionType.OodleHydra => Oodle.Decompress(encryptedData, decryptedLength)!, + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + } + + private static byte[] Compress(byte[] decryptedData, CompressionType type) + { + return type switch + { + CompressionType.None => decryptedData, + CompressionType.Zlib => throw new NotSupportedException(nameof(CompressionType.Zlib)), // not implemented + CompressionType.Lz4 => LZ4.Encode(decryptedData), + CompressionType.OodleKraken => Oodle.Compress(decryptedData, out _, OodleFormat.Kraken).ToArray(), + CompressionType.OodleLeviathan => Oodle.Compress(decryptedData, out _, OodleFormat.Leviathan).ToArray(), + CompressionType.OodleMermaid => Oodle.Compress(decryptedData, out _, OodleFormat.Mermaid).ToArray(), + CompressionType.OodleSelkie => Oodle.Compress(decryptedData, out _, OodleFormat.Selkie).ToArray(), + CompressionType.OodleHydra => Oodle.Compress(decryptedData, out _, OodleFormat.Hydra).ToArray(), + _ => throw new ArgumentOutOfRangeException(nameof(type)), + }; + } + + public void CancelEdits() + { + for (int i = 0; i < DecompressedFiles.Length; i++) + DecompressedFiles[i] = Decompress(CompressedFiles[i], FileTable[i].SizeDecompressed, FileTable[i].Type); + Modified = false; + } + + private void WriteHeaderTableList(BinaryWriter bw) + { + bw.Write(Header.ToBytesClass()); + Pointers.Write(bw); + Pointers.PtrHashPaths = bw.BaseStream.Position; + foreach (var hp in HashAbsolute) + bw.Write(hp.ToBytesClass()); + + for (var f = 0; f < Pointers.PtrHashFolders.Length; f++) + { + Pointers.PtrHashFolders[f] = bw.BaseStream.Position; + + var folder = HashInFolder[f]; + folder.Folder.FileCount = folder.Files.Length; + bw.Write(folder.Folder.ToBytesClass()); + foreach (var hi in folder.Files) + bw.Write(hi.ToBytesClass()); + } + + Pointers.PtrFileTable = bw.BaseStream.Position; + foreach (var ft in FileTable) + bw.Write(ft.ToBytesClass()); + } + + public string? FilePath { get; set; } + public bool Modified { get; set; } + public Task GetFiles() => Task.FromResult(DecompressedFiles); + public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[file]); + public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(this[file] = value); + public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => FileMitm.WriteAllBytes(path, Write()), token); + + public void Dump(string path, ContainerHandler handler) + { + handler.Initialize(FileTable.Length); + string format = this.GetFileFormatString(); + + foreach (var grp in HashInFolder) + { + var dirName = grp.Folder.HashFnv1aPathFolderName; + foreach (var f in grp.Files) + { + var index = f.Index; + var name = f.HashFnv1aPathFileName; + + var fn = $"{index.ToString(format)} {name:X16}.bin"; + var data = DecompressedFiles[f.Index]; + + var subfolder = HashInFolder.Length == 1 ? fn : Path.Combine(dirName.ToString("X16"), fn); + var loc = Path.Combine(path, subfolder); + FileMitm.WriteAllBytes(loc, data); + } + } } } + +/// +/// Intro bytes to the packed binary. +/// +[StructLayout(LayoutKind.Sequential)] +public class GFPackHeader +{ + public const int SIZE = 0x18; + public ulong MAGIC = GFPack.Magic; + public uint Version = 0x1000; + public uint IsRelocated; // bit0 + + /// + /// Count of Files packed into the binary. + /// + public int CountFiles; + + /// + /// Count of Folders packed into the binary. + /// + public int CountFolders; +} + +public class GFPackPointers +{ + /// + /// Data offset for the table. + /// + public long PtrFileTable; // array stored at end + + /// + /// Data offset for the table. + /// + public long PtrHashPaths; // array stored first + + /// + /// Data offset for the table, which has a leading . + /// + public long[] PtrHashFolders; // array stored in middle + + // immediately after the pointers are the arrays + + public GFPackPointers(BinaryReader br, int folderCount) + { + PtrFileTable = br.ReadInt64(); + PtrHashPaths = br.ReadInt64(); + PtrHashFolders = new long[folderCount]; + for (int i = 0; i < PtrHashFolders.Length; i++) + PtrHashFolders[i] = br.ReadInt64(); + } + + public void Write(BinaryWriter bw) + { + bw.Write(PtrFileTable); + bw.Write(PtrHashPaths); + foreach (var table in PtrHashFolders) + bw.Write(table); + } +} + +[StructLayout(LayoutKind.Sequential)] +public class FileHashAbsolute +{ + public const int SIZE = 0x08; + + /// + /// Filename (with directory details) hash. + /// + public ulong HashFnv1aPathFull; + + public bool IsMatch(string fileName) => FnvHash.HashFnv1a_64(fileName) == HashFnv1aPathFull; +} + +public class FileHashFolder +{ + public FileHashFolderInfo Folder = new(); + public FileHashIndex[] Files = Array.Empty(); + public int GetIndexFileName(ulong hash) => Array.FindIndex(Files, z => z.HashFnv1aPathFileName == hash); + public int GetIndexFileName(string name) => Array.FindIndex(Files, z => z.IsMatch(name)); +} + +[StructLayout(LayoutKind.Sequential)] +public class FileHashFolderInfo +{ + public const int SIZE = 0x10; + + /// + /// Filename (without directory details) hash. + /// + public ulong HashFnv1aPathFolderName; + public int FileCount; + public uint Padding = 0xCC; + + public bool IsMatch(string fileName) => FnvHash.HashFnv1a_64(fileName) == HashFnv1aPathFolderName; +} + +[StructLayout(LayoutKind.Sequential)] +public class FileHashIndex +{ + public const int SIZE = 0x10; + + /// + /// Filename (without directory details) hash. + /// + public ulong HashFnv1aPathFileName; + public int Index; + public uint Padding = 0xCC; + + public bool IsMatch(string fileName) => FnvHash.HashFnv1a_64(fileName) == HashFnv1aPathFileName; +} + +[StructLayout(LayoutKind.Sequential)] +public class FileData +{ + public const int SIZE = 0x18; + + public ushort Level = 9; // quality? + public CompressionType Type; + public int SizeDecompressed; + public int SizeCompressed; + public int Padding = 0xCC; + public int OffsetPacked; + public uint unused; +} + +public enum CompressionType : ushort +{ + None = 0, + Zlib = 1, + Lz4 = 2, + OodleKraken = 3, + OodleLeviathan = 4, + OodleMermaid = 5, + OodleSelkie = 6, + OodleHydra = 7, +} diff --git a/pkNX.Containers/Misc/LZ4.cs b/pkNX.Containers/Misc/LZ4.cs index 28f1970f..c0aa05eb 100644 --- a/pkNX.Containers/Misc/LZ4.cs +++ b/pkNX.Containers/Misc/LZ4.cs @@ -1,10 +1,9 @@ -using LZ4; +using LZ4; -namespace pkNX.Containers +namespace pkNX.Containers; + +public static class LZ4 { - public static class LZ4 - { - public static byte[] Decode(byte[] data, int decLength) => LZ4Codec.Decode(data, 0, data.Length, decLength); - public static byte[] Encode(byte[] data) => LZ4Codec.Encode(data, 0, data.Length); - } + public static byte[] Decode(byte[] data, int decLength) => LZ4Codec.Decode(data, 0, data.Length, decLength); + public static byte[] Encode(byte[] data) => LZ4Codec.Encode(data, 0, data.Length); } diff --git a/pkNX.Containers/Misc/Oodle.cs b/pkNX.Containers/Misc/Oodle.cs index 7e81b44c..f8a29ab9 100644 --- a/pkNX.Containers/Misc/Oodle.cs +++ b/pkNX.Containers/Misc/Oodle.cs @@ -1,156 +1,155 @@ -using System; +using System; using System.Runtime.InteropServices; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// Oodle Compression and Decompression wrapper around the external dll. +/// +/// +/// These methods are safely tuned for Span in order to minimize allocation. +/// +public static class Oodle { /// - /// Oodle Compression and Decompression wrapper around the external dll. + /// Oodle Library Path /// - /// - /// These methods are safely tuned for Span in order to minimize allocation. - /// - public static class Oodle + public const string OodleLibraryPath = "oo2core_8_win64"; + + /// + /// Oodle64 Decompression Method + /// + [DllImport(OodleLibraryPath, CallingConvention = CallingConvention.Cdecl)] + private static extern long OodleLZ_Decompress(ref byte buffer, long bufferSize, ref byte result, long outputBufferSize, + OodleFuzzSafe fuzz = OodleFuzzSafe.Yes, + OodleCheckCrc crc = OodleCheckCrc.No, + OodleVerbosity verbosity = OodleVerbosity.None, + long context = 0, long e = 0, long callback = 0, long callback_ctx = 0, long scratch = 0, long scratch_size = 0, + OodleThreadPhase threadPhase = OodleThreadPhase.Unthreaded); + + /// + /// Oodle64 Compression Method + /// + [DllImport(OodleLibraryPath)] + private static extern long OodleLZ_Compress(OodleFormat format, ref byte buffer, long bufferSize, ref byte result, OodleCompressionLevel level, + long opts = 0, long context = 0, long unused = 0, long scratch = 0, long scratch_size = 0); + + /// + /// Decompresses a span of Oodle Compressed bytes (Requires Oodle DLL) + /// + /// Input Compressed Data + /// Decompressed Size + /// Resulting Array if success, otherwise null. + public static byte[]? Decompress(ReadOnlySpan input, long decompressedLength) { - /// - /// Oodle Library Path - /// - public const string OodleLibraryPath = "oo2core_8_win64"; - - /// - /// Oodle64 Decompression Method - /// - [DllImport(OodleLibraryPath, CallingConvention = CallingConvention.Cdecl)] - private static extern long OodleLZ_Decompress(ref byte buffer, long bufferSize, ref byte result, long outputBufferSize, - OodleFuzzSafe fuzz = OodleFuzzSafe.Yes, - OodleCheckCrc crc = OodleCheckCrc.No, - OodleVerbosity verbosity = OodleVerbosity.None, - long context = 0, long e = 0, long callback = 0, long callback_ctx = 0, long scratch = 0, long scratch_size = 0, - OodleThreadPhase threadPhase = OodleThreadPhase.Unthreaded); - - /// - /// Oodle64 Compression Method - /// - [DllImport(OodleLibraryPath)] - private static extern long OodleLZ_Compress(OodleFormat format, ref byte buffer, long bufferSize, ref byte result, OodleCompressionLevel level, - long opts = 0, long context = 0, long unused = 0, long scratch = 0, long scratch_size = 0); - - /// - /// Decompresses a span of Oodle Compressed bytes (Requires Oodle DLL) - /// - /// Input Compressed Data - /// Decompressed Size - /// Resulting Array if success, otherwise null. - public static byte[]? Decompress(ReadOnlySpan input, long decompressedLength) - { - var result = new byte[decompressedLength]; - return Decompress(input, result); - } - - private static byte[]? Decompress(ReadOnlySpan input, byte[] result) - { - var dest = result.AsSpan(); - long decodedSize = OodleLZ_Decompress(ref MemoryMarshal.GetReference(input), input.Length, ref MemoryMarshal.GetReference(dest), result.Length); - if (decodedSize == 0) - return null; // failed - return result; - } - - /// - /// Compresses a span of bytes to Oodle Compressed bytes (Requires Oodle DLL) - /// - /// Input Decompressed Data - /// Actual Compressed Data size - /// Compression format to use - /// Compression setting to use - /// Span of compressed data with remainder aligned working bytes. - public static Span Compress(ReadOnlySpan input, out int compressedSize, - OodleFormat format = OodleFormat.Kraken, OodleCompressionLevel level = OodleCompressionLevel.Optimal2) - { - var maxSize = GetCompressedBufferSizeNeeded(input.Length); - var result = new byte[maxSize].AsSpan(); - return Compress(input, result, out compressedSize, format, level); - } - - private static Span Compress(ReadOnlySpan input, Span result, out int compressedSize, OodleFormat format, OodleCompressionLevel level) - { - var encodedSize = OodleLZ_Compress(format, ref MemoryMarshal.GetReference(input), input.Length, ref MemoryMarshal.GetReference(result), level); - - // Oodle's compressed result leaves data after the "compressed length" return index. - // Return an aligned span (ensuring length is a multiple of 4). - // Retaining these unused bytes matches the behavior observed in New Pokémon Snap DRPF files. - compressedSize = (int)encodedSize; - var align = (compressedSize + 3) & ~3; - return result[..align]; - } - - /// - /// Gets the dimension required to compress the data. - /// - /// - /// - private static long GetCompressedBufferSizeNeeded(long inputSize) - { - return inputSize + (274 * ((inputSize + 0x3FFFF) / 0x40000)); - } + var result = new byte[decompressedLength]; + return Decompress(input, result); } - public enum OodleFormat : uint + private static byte[]? Decompress(ReadOnlySpan input, byte[] result) { - LZH = 0, - LZHLW = 1, - LZNIB = 2, - None = 3, - LZB16 = 4, - LZBLW = 5, - LZA = 6, - LZNA = 7, - Kraken = 8, - Mermaid = 9, - BitKnit = 10, - Selkie = 11, - Hydra = 12, - Leviathan = 13, + var dest = result.AsSpan(); + long decodedSize = OodleLZ_Decompress(ref MemoryMarshal.GetReference(input), input.Length, ref MemoryMarshal.GetReference(dest), result.Length); + if (decodedSize == 0) + return null; // failed + return result; } - public enum OodleCompressionLevel : ulong + /// + /// Compresses a span of bytes to Oodle Compressed bytes (Requires Oodle DLL) + /// + /// Input Decompressed Data + /// Actual Compressed Data size + /// Compression format to use + /// Compression setting to use + /// Span of compressed data with remainder aligned working bytes. + public static Span Compress(ReadOnlySpan input, out int compressedSize, + OodleFormat format = OodleFormat.Kraken, OodleCompressionLevel level = OodleCompressionLevel.Optimal2) { - None = 0, - SuperFast = 1, - VeryFast = 2, - Fast = 3, - Normal = 4, - Optimal1 = 5, - Optimal2 = 6, - Optimal3 = 7, - Optimal4 = 8, - Optimal5 = 9, + var maxSize = GetCompressedBufferSizeNeeded(input.Length); + var result = new byte[maxSize].AsSpan(); + return Compress(input, result, out compressedSize, format, level); } - public enum OodleFuzzSafe + private static Span Compress(ReadOnlySpan input, Span result, out int compressedSize, OodleFormat format, OodleCompressionLevel level) { - No = 0, - Yes = 1, + var encodedSize = OodleLZ_Compress(format, ref MemoryMarshal.GetReference(input), input.Length, ref MemoryMarshal.GetReference(result), level); + + // Oodle's compressed result leaves data after the "compressed length" return index. + // Return an aligned span (ensuring length is a multiple of 4). + // Retaining these unused bytes matches the behavior observed in New Pokémon Snap DRPF files. + compressedSize = (int)encodedSize; + var align = (compressedSize + 3) & ~3; + return result[..align]; } - public enum OodleCheckCrc + /// + /// Gets the dimension required to compress the data. + /// + /// + /// + private static long GetCompressedBufferSizeNeeded(long inputSize) { - No = 0, - Yes = 1, - } - - public enum OodleVerbosity - { - None = 0, - Max = 3, - } - - [Flags] - public enum OodleThreadPhase - { - Invalid = 0, - ThreadPhase1 = 1, - ThreadPhase2 = 2, - - Unthreaded = ThreadPhase1 | ThreadPhase2, // 3 + return inputSize + (274 * ((inputSize + 0x3FFFF) / 0x40000)); } } + +public enum OodleFormat : uint +{ + LZH = 0, + LZHLW = 1, + LZNIB = 2, + None = 3, + LZB16 = 4, + LZBLW = 5, + LZA = 6, + LZNA = 7, + Kraken = 8, + Mermaid = 9, + BitKnit = 10, + Selkie = 11, + Hydra = 12, + Leviathan = 13, +} + +public enum OodleCompressionLevel : ulong +{ + None = 0, + SuperFast = 1, + VeryFast = 2, + Fast = 3, + Normal = 4, + Optimal1 = 5, + Optimal2 = 6, + Optimal3 = 7, + Optimal4 = 8, + Optimal5 = 9, +} + +public enum OodleFuzzSafe +{ + No = 0, + Yes = 1, +} + +public enum OodleCheckCrc +{ + No = 0, + Yes = 1, +} + +public enum OodleVerbosity +{ + None = 0, + Max = 3, +} + +[Flags] +public enum OodleThreadPhase +{ + Invalid = 0, + ThreadPhase1 = 1, + ThreadPhase2 = 2, + + Unthreaded = ThreadPhase1 | ThreadPhase2, // 3 +} diff --git a/pkNX.Containers/Misc/StructConverter.cs b/pkNX.Containers/Misc/StructConverter.cs index ad98436d..e5059ea5 100644 --- a/pkNX.Containers/Misc/StructConverter.cs +++ b/pkNX.Containers/Misc/StructConverter.cs @@ -1,46 +1,45 @@ -using System; +using System; using System.Runtime.InteropServices; -namespace pkNX.Containers +namespace pkNX.Containers; + +internal static class StructConverter { - internal static class StructConverter + public static T ToStructure(this byte[] bytes) where T : struct { - public static T ToStructure(this byte[] bytes) where T : struct - { - var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } - finally { handle.Free(); } - } + var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T))!; } + finally { handle.Free(); } + } - public static T ToClass(this byte[] bytes) where T : class - { - var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } - finally { handle.Free(); } - } + public static T ToClass(this byte[] bytes) where T : class + { + var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T))!; } + finally { handle.Free(); } + } - public static byte[] ToBytesClass(this T obj) where T : class - { - int size = Marshal.SizeOf(obj); - byte[] arr = new byte[size]; + public static byte[] ToBytesClass(this T obj) where T : class + { + int size = Marshal.SizeOf(obj); + byte[] arr = new byte[size]; - IntPtr ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(obj, ptr, true); - Marshal.Copy(ptr, arr, 0, size); - Marshal.FreeHGlobal(ptr); - return arr; - } + IntPtr ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + Marshal.Copy(ptr, arr, 0, size); + Marshal.FreeHGlobal(ptr); + return arr; + } - public static byte[] ToBytes(this T obj) where T : struct - { - int size = Marshal.SizeOf(obj); - byte[] arr = new byte[size]; + public static byte[] ToBytes(this T obj) where T : struct + { + int size = Marshal.SizeOf(obj); + byte[] arr = new byte[size]; - IntPtr ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(obj, ptr, true); - Marshal.Copy(ptr, arr, 0, size); - Marshal.FreeHGlobal(ptr); - return arr; - } + IntPtr ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + Marshal.Copy(ptr, arr, 0, size); + Marshal.FreeHGlobal(ptr); + return arr; } } diff --git a/pkNX.Containers/NX/NSO.cs b/pkNX.Containers/NX/NSO.cs index 0ecf9845..a93c7d4b 100644 --- a/pkNX.Containers/NX/NSO.cs +++ b/pkNX.Containers/NX/NSO.cs @@ -1,134 +1,133 @@ -using System.IO; +using System.IO; using System.Linq; using System.Security.Cryptography; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class NSO { - public class NSO - { - public NSOHeader Header { get; private set; } + public NSOHeader Header { get; private set; } - public byte[] CompressedText { get; set; } - public byte[] CompressedRO { get; set; } - public byte[] CompressedData { get; set; } + public byte[] CompressedText { get; set; } + public byte[] CompressedRO { get; set; } + public byte[] CompressedData { get; set; } - public byte[] DecompressedText { get; set; } - public byte[] DecompressedRO { get; set; } - public byte[] DecompressedData { get; set; } + public byte[] DecompressedText { get; set; } + public byte[] DecompressedRO { get; set; } + public byte[] DecompressedData { get; set; } - public bool ValidText => Hash(DecompressedText).SequenceEqual(Header.HashText); - public bool ValidRO => Hash(DecompressedText).SequenceEqual(Header.HashText); - public bool ValidData => Hash(DecompressedText).SequenceEqual(Header.HashText); + public bool ValidText => Hash(DecompressedText).SequenceEqual(Header.HashText); + public bool ValidRO => Hash(DecompressedText).SequenceEqual(Header.HashText); + public bool ValidData => Hash(DecompressedText).SequenceEqual(Header.HashText); - public decimal CompressionRatioText => (decimal)DecompressedText.Length / CompressedText.Length; - public decimal CompressionRatioRO => (decimal)DecompressedRO.Length / CompressedRO.Length; - public decimal CompressionRatioData => (decimal)DecompressedData.Length / CompressedData.Length; + public decimal CompressionRatioText => (decimal)DecompressedText.Length / CompressedText.Length; + public decimal CompressionRatioRO => (decimal)DecompressedRO.Length / CompressedRO.Length; + public decimal CompressionRatioData => (decimal)DecompressedData.Length / CompressedData.Length; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public NSO(BinaryReader br) => ReadHeader(br); + public NSO(BinaryReader br) => ReadHeader(br); - public NSO(byte[] data) - { - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - ReadHeader(br); - } + public NSO(byte[] data) + { + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + ReadHeader(br); + } #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - private void ReadHeader(BinaryReader br) - { - if (br.BaseStream.Length < NSOHeader.SIZE) - return; - Header = br.ReadBytes(NSOHeader.SIZE).ToClass(); + private void ReadHeader(BinaryReader br) + { + if (br.BaseStream.Length < NSOHeader.SIZE) + return; + Header = br.ReadBytes(NSOHeader.SIZE).ToClass(); - // seek around to decode - CompressedText = GetCompressedSegment(br, Header.HeaderText, Header.SizeCompressedText); - CompressedRO = GetCompressedSegment(br, Header.HeaderRO, Header.SizeCompressedRO); - CompressedData = GetCompressedSegment(br, Header.HeaderData, Header.SizeCompressedData); + // seek around to decode + CompressedText = GetCompressedSegment(br, Header.HeaderText, Header.SizeCompressedText); + CompressedRO = GetCompressedSegment(br, Header.HeaderRO, Header.SizeCompressedRO); + CompressedData = GetCompressedSegment(br, Header.HeaderData, Header.SizeCompressedData); - Decompress(); - } + Decompress(); + } - public static byte[] GetCompressedSegment(BinaryReader br, SegmentHeader h, int sizeCompressed) - { - br.BaseStream.Position = h.FileOffset; - return br.ReadBytes(sizeCompressed); - } + public static byte[] GetCompressedSegment(BinaryReader br, SegmentHeader h, int sizeCompressed) + { + br.BaseStream.Position = h.FileOffset; + return br.ReadBytes(sizeCompressed); + } - public static byte[] GetDecompressedSegment(BinaryReader br, SegmentHeader h, int sizeCompressed) - { - byte[] data = GetCompressedSegment(br, h, sizeCompressed); - return LZ4.Decode(data, h.DecompressedSize); - } + public static byte[] GetDecompressedSegment(BinaryReader br, SegmentHeader h, int sizeCompressed) + { + byte[] data = GetCompressedSegment(br, h, sizeCompressed); + return LZ4.Decode(data, h.DecompressedSize); + } - public static byte[] Hash(byte[] data) - { - using var method = SHA256.Create(); - return method.ComputeHash(data); - } + public static byte[] Hash(byte[] data) + { + using var method = SHA256.Create(); + return method.ComputeHash(data); + } - private void Decompress() - { - DecompressedText = Header.Flags.HasFlagFast(NSOFlag.CompressedText) - ? LZ4.Decode(CompressedText, Header.HeaderText.DecompressedSize) - : CompressedText; - DecompressedRO = Header.Flags.HasFlagFast(NSOFlag.CompressedRO) - ? LZ4.Decode(CompressedRO, Header.HeaderRO.DecompressedSize) - : CompressedRO; - DecompressedData = Header.Flags.HasFlagFast(NSOFlag.CompressedData) - ? LZ4.Decode(CompressedData, Header.HeaderData.DecompressedSize) - : CompressedData; - } + private void Decompress() + { + DecompressedText = Header.Flags.HasFlagFast(NSOFlag.CompressedText) + ? LZ4.Decode(CompressedText, Header.HeaderText.DecompressedSize) + : CompressedText; + DecompressedRO = Header.Flags.HasFlagFast(NSOFlag.CompressedRO) + ? LZ4.Decode(CompressedRO, Header.HeaderRO.DecompressedSize) + : CompressedRO; + DecompressedData = Header.Flags.HasFlagFast(NSOFlag.CompressedData) + ? LZ4.Decode(CompressedData, Header.HeaderData.DecompressedSize) + : CompressedData; + } - private void Compress() - { - CompressedText = Header.Flags.HasFlagFast(NSOFlag.CompressedText) - ? LZ4.Encode(DecompressedText) - : DecompressedText; - Header.SizeCompressedText = CompressedText.Length; - Header.HeaderText.DecompressedSize = DecompressedText.Length; - Header.HashText = Hash(DecompressedText); + private void Compress() + { + CompressedText = Header.Flags.HasFlagFast(NSOFlag.CompressedText) + ? LZ4.Encode(DecompressedText) + : DecompressedText; + Header.SizeCompressedText = CompressedText.Length; + Header.HeaderText.DecompressedSize = DecompressedText.Length; + Header.HashText = Hash(DecompressedText); - CompressedRO = Header.Flags.HasFlagFast(NSOFlag.CompressedRO) - ? LZ4.Encode(DecompressedRO) - : DecompressedRO; - Header.SizeCompressedRO = CompressedRO.Length; - Header.HeaderRO.DecompressedSize = DecompressedRO.Length; - Header.HashRO = Hash(DecompressedRO); + CompressedRO = Header.Flags.HasFlagFast(NSOFlag.CompressedRO) + ? LZ4.Encode(DecompressedRO) + : DecompressedRO; + Header.SizeCompressedRO = CompressedRO.Length; + Header.HeaderRO.DecompressedSize = DecompressedRO.Length; + Header.HashRO = Hash(DecompressedRO); - CompressedData = Header.Flags.HasFlagFast(NSOFlag.CompressedData) - ? LZ4.Encode(DecompressedData) - : DecompressedData; - Header.SizeCompressedData = CompressedData.Length; - Header.HeaderData.DecompressedSize = DecompressedData.Length; - Header.HashData = Hash(DecompressedData); - } + CompressedData = Header.Flags.HasFlagFast(NSOFlag.CompressedData) + ? LZ4.Encode(DecompressedData) + : DecompressedData; + Header.SizeCompressedData = CompressedData.Length; + Header.HeaderData.DecompressedSize = DecompressedData.Length; + Header.HashData = Hash(DecompressedData); + } - public byte[] Write() - { - Compress(); - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - bw.Write(Header.ToBytesClass()); - while (bw.BaseStream.Position != Header.HeaderText.FileOffset) - bw.Write((byte)0); // match layout for previous example + public byte[] Write() + { + Compress(); + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + bw.Write(Header.ToBytesClass()); + while (bw.BaseStream.Position != Header.HeaderText.FileOffset) + bw.Write((byte)0); // match layout for previous example - // text - Header.HeaderText.FileOffset = (int)bw.BaseStream.Position; - bw.Write(CompressedText); + // text + Header.HeaderText.FileOffset = (int)bw.BaseStream.Position; + bw.Write(CompressedText); - // ro - Header.HeaderRO.FileOffset = (int)bw.BaseStream.Position; - bw.Write(CompressedRO); + // ro + Header.HeaderRO.FileOffset = (int)bw.BaseStream.Position; + bw.Write(CompressedRO); - // data - Header.HeaderData.FileOffset = (int)bw.BaseStream.Position; - bw.Write(CompressedData); + // data + Header.HeaderData.FileOffset = (int)bw.BaseStream.Position; + bw.Write(CompressedData); - bw.BaseStream.Position = 0; - bw.Write(Header.ToBytesClass()); + bw.BaseStream.Position = 0; + bw.Write(Header.ToBytesClass()); - return ms.ToArray(); - } + return ms.ToArray(); } } diff --git a/pkNX.Containers/NX/NSOFlag.cs b/pkNX.Containers/NX/NSOFlag.cs index d10f1219..9f9154da 100644 --- a/pkNX.Containers/NX/NSOFlag.cs +++ b/pkNX.Containers/NX/NSOFlag.cs @@ -1,23 +1,22 @@ using System; -namespace pkNX.Containers -{ - [Flags] - public enum NSOFlag : uint - { - None = 0, - CompressedText = 1 << 0, - CompressedRO = 1 << 1, - CompressedData = 1 << 2, - CheckHashText = 1 << 3, - CheckHashRO = 1 << 4, - CheckHashData = 1 << 5, - Unused6 = 1 << 6, - Unused7 = 1 << 7, - } +namespace pkNX.Containers; - public static class NsoFlagExtensions - { - public static bool HasFlagFast(this NSOFlag value, NSOFlag flag) => (value & flag) != 0; - } -} \ No newline at end of file +[Flags] +public enum NSOFlag : uint +{ + None = 0, + CompressedText = 1 << 0, + CompressedRO = 1 << 1, + CompressedData = 1 << 2, + CheckHashText = 1 << 3, + CheckHashRO = 1 << 4, + CheckHashData = 1 << 5, + Unused6 = 1 << 6, + Unused7 = 1 << 7, +} + +public static class NsoFlagExtensions +{ + public static bool HasFlagFast(this NSOFlag value, NSOFlag flag) => (value & flag) != 0; +} diff --git a/pkNX.Containers/NX/NSOHeader.cs b/pkNX.Containers/NX/NSOHeader.cs index d8d5fa28..ac3cf9c5 100644 --- a/pkNX.Containers/NX/NSOHeader.cs +++ b/pkNX.Containers/NX/NSOHeader.cs @@ -1,51 +1,50 @@ using System.Runtime.InteropServices; -namespace pkNX.Containers +namespace pkNX.Containers; + +[StructLayout(LayoutKind.Sequential)] +public class NSOHeader { - [StructLayout(LayoutKind.Sequential)] - public class NSOHeader - { - public const int SIZE = 0x100; - public const uint ExpectedMagic = 0x304F534E; // NSO0 - public bool Valid => Magic == ExpectedMagic; + public const int SIZE = 0x100; + public const uint ExpectedMagic = 0x304F534E; // NSO0 + public bool Valid => Magic == ExpectedMagic; - // Structure below + // Structure below - public uint Magic; - public uint Version; - public uint Reserved; - public NSOFlag Flags; + public uint Magic; + public uint Version; + public uint Reserved; + public NSOFlag Flags; #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - public SegmentHeader HeaderText; - public int ModuleOffset; - public SegmentHeader HeaderRO; - public int ModuleFileSize; - public SegmentHeader HeaderData; - public int BssSize; + public SegmentHeader HeaderText; + public int ModuleOffset; + public SegmentHeader HeaderRO; + public int ModuleFileSize; + public SegmentHeader HeaderData; + public int BssSize; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] - public byte[] DigestBuildID; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[] DigestBuildID; - public int SizeCompressedText; - public int SizeCompressedRO; - public int SizeCompressedData; + public int SizeCompressedText; + public int SizeCompressedRO; + public int SizeCompressedData; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C)] - public byte[] Padding; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1C)] + public byte[] Padding; - public RelativeExtent APIInfo; - public RelativeExtent DynStr; - public RelativeExtent DynSym; + public RelativeExtent APIInfo; + public RelativeExtent DynStr; + public RelativeExtent DynSym; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] - public byte[] HashText; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[] HashText; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] - public byte[] HashRO; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[] HashRO; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] - public byte[] HashData; - } + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x20)] + public byte[] HashData; +} #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. -} \ No newline at end of file diff --git a/pkNX.Containers/NX/RelativeExtent.cs b/pkNX.Containers/NX/RelativeExtent.cs index 42fae8b3..c3548a7c 100644 --- a/pkNX.Containers/NX/RelativeExtent.cs +++ b/pkNX.Containers/NX/RelativeExtent.cs @@ -1,11 +1,10 @@ using System.Runtime.InteropServices; -namespace pkNX.Containers +namespace pkNX.Containers; + +[StructLayout(LayoutKind.Sequential)] +public class RelativeExtent { - [StructLayout(LayoutKind.Sequential)] - public class RelativeExtent - { - public int RegionRODataOffset; - public int RegionSize; - } -} \ No newline at end of file + public int RegionRODataOffset; + public int RegionSize; +} diff --git a/pkNX.Containers/NX/SegmentHeader.cs b/pkNX.Containers/NX/SegmentHeader.cs index 250aaacc..298bc4f5 100644 --- a/pkNX.Containers/NX/SegmentHeader.cs +++ b/pkNX.Containers/NX/SegmentHeader.cs @@ -1,12 +1,11 @@ using System.Runtime.InteropServices; -namespace pkNX.Containers +namespace pkNX.Containers; + +[StructLayout(LayoutKind.Sequential)] +public class SegmentHeader { - [StructLayout(LayoutKind.Sequential)] - public class SegmentHeader - { - public int FileOffset; - public int MemoryOffset; - public int DecompressedSize; - } -} \ No newline at end of file + public int FileOffset; + public int MemoryOffset; + public int DecompressedSize; +} diff --git a/pkNX.Containers/SARC/SARC.cs b/pkNX.Containers/SARC/SARC.cs index 19b2f3a0..fcdf8f9e 100644 --- a/pkNX.Containers/SARC/SARC.cs +++ b/pkNX.Containers/SARC/SARC.cs @@ -1,173 +1,172 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// Simple (?) ARChive +/// +public sealed class SARC : LargeContainer { + private const string Identifier = nameof(SARC); + + public SARCHeader Header { get; set; } + public SFAT SFAT; + public SFNT SFNT; + + public override int Count => SFAT.Entries.Count; + /// - /// Simple (?) ARChive + /// The required matches the first 4 bytes of the file data. /// - public sealed class SARC : LargeContainer + public bool SigMatches => Header.Magic == Identifier; + + /// + /// Initializes an empty . + /// + /// Files inside the . + /// Root location of the archive + public SARC(IReadOnlyList files, string baseFolder) { - private const string Identifier = nameof(SARC); - - public SARCHeader Header { get; set; } - public SFAT SFAT; - public SFNT SFNT; - - public override int Count => SFAT.Entries.Count; - - /// - /// The required matches the first 4 bytes of the file data. - /// - public bool SigMatches => Header.Magic == Identifier; - - /// - /// Initializes an empty . - /// - /// Files inside the . - /// Root location of the archive - public SARC(IReadOnlyList files, string baseFolder) - { - Header = new SARCHeader(); - SFAT = new SFAT(baseFolder, files); - SFNT = new SFNT(); - Files = new byte[]?[SFAT.Entries.Count]; - } + Header = new SARCHeader(); + SFAT = new SFAT(baseFolder, files); + SFNT = new SFNT(); + Files = new byte[]?[SFAT.Entries.Count]; + } #pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - /// - /// Initializes a from a file location. - /// - /// - public SARC(string path) => OpenBinary(path); + /// + /// Initializes a from a file location. + /// + /// + public SARC(string path) => OpenBinary(path); - /// - /// Initializes a from a provided stream. - /// - /// - public SARC(Stream fs) => OpenRead(new BinaryReader(fs)); + /// + /// Initializes a from a provided stream. + /// + /// + public SARC(Stream fs) => OpenRead(new BinaryReader(fs)); - /// - /// Initializes a from a provided reader. - /// - /// - public SARC(BinaryReader br) => OpenRead(br); + /// + /// Initializes a from a provided reader. + /// + /// + public SARC(BinaryReader br) => OpenRead(br); #pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable. - /// - /// Reads the contents of the header and file info tables. - /// - protected override void Initialize() + /// + /// Reads the contents of the header and file info tables. + /// + protected override void Initialize() + { + if (Reader is null) + throw new NullReferenceException(nameof(Reader)); + Header = new SARCHeader(Reader); + if (!SigMatches) + return; + SFAT = new SFAT(Reader, Header.DataOffset); + SFNT = new SFNT(Reader); + } + + protected override Task Pack(BinaryWriter bw, ContainerHandler handler, CancellationToken token) + { + return Task.Run(() => PackSARC(bw, handler, token), token); + } + + private void PackSARC(BinaryWriter bw, ContainerHandler handler, CancellationToken token) + { + StartPack(); + var count = SFAT.Entries.Count; + handler.Initialize(count); + var currentStringOffset = SFNT.StringOffset; + + WriteIntro(bw); + for (int i = 0; i < count; i++) { - if (Reader is null) - throw new NullReferenceException(nameof(Reader)); - Header = new SARCHeader(Reader); - if (!SigMatches) + var entr = SFAT.Entries[i]; + if (entr.FileName == null) + entr.GetFileName(Reader!.BaseStream, (int)currentStringOffset); + entr.WriteFileName(Reader!.BaseStream, (int)SFNT.StringOffset); + while (Reader.BaseStream.Position % 4 != 0) + bw.Write((byte)0); + } + for (int i = 0; i < count; i++) + { + if (token.IsCancellationRequested) return; - SFAT = new SFAT(Reader, Header.DataOffset); - SFNT = new SFNT(Reader); + WriteEntry(bw, i); } + WriteIntro(bw, true); + bw.Flush(); + } - protected override Task Pack(BinaryWriter bw, ContainerHandler handler, CancellationToken token) - { - return Task.Run(() => PackSARC(bw, handler, token), token); - } + private void StartPack() { } - private void PackSARC(BinaryWriter bw, ContainerHandler handler, CancellationToken token) - { - StartPack(); - var count = SFAT.Entries.Count; - handler.Initialize(count); - var currentStringOffset = SFNT.StringOffset; + private void WriteIntro(BinaryWriter bw, bool finalPass = false) + { + Header.Write(bw); + SFAT.Write(bw); + SFNT.Write(bw); + if (finalPass) + Header.DataOffset = (int)bw.BaseStream.Position; + } - WriteIntro(bw); - for (int i = 0; i < count; i++) - { - var entr = SFAT.Entries[i]; - if (entr.FileName == null) - entr.GetFileName(Reader!.BaseStream, (int)currentStringOffset); - entr.WriteFileName(Reader!.BaseStream, (int)SFNT.StringOffset); - while (Reader.BaseStream.Position % 4 != 0) - bw.Write((byte)0); - } - for (int i = 0; i < count; i++) - { - if (token.IsCancellationRequested) - return; - WriteEntry(bw, i); - } - WriteIntro(bw, true); - bw.Flush(); - } + private void WriteEntry(BinaryWriter bw, int i) + { + throw new NotImplementedException(); + } - private void StartPack() { } + protected override int GetFileOffset(int file, int subFile = 0) + { + var f = SFAT[file]; + return Header.DataOffset + f.Start; + } - private void WriteIntro(BinaryWriter bw, bool finalPass = false) - { - Header.Write(bw); - SFAT.Write(bw); - SFNT.Write(bw); - if (finalPass) - Header.DataOffset = (int)bw.BaseStream.Position; - } - - private void WriteEntry(BinaryWriter bw, int i) - { - throw new NotImplementedException(); - } - - protected override int GetFileOffset(int file, int subFile = 0) - { - var f = SFAT[file]; - return Header.DataOffset + f.Start; - } - - public override byte[] GetEntry(int index, int subFile) - { - var f = SFAT[index]; - if (f.File is byte[] data) - return data; - - data = f.GetFileData(Reader!.BaseStream); - f.File = data; // cache for future fetches + public override byte[] GetEntry(int index, int subFile) + { + var f = SFAT[index]; + if (f.File is byte[] data) return data; - } - public override void Dump(string? path, ContainerHandler handler) + data = f.GetFileData(Reader!.BaseStream); + f.File = data; // cache for future fetches + return data; + } + + public override void Dump(string? path, ContainerHandler handler) + { + path ??= FilePath; + if (path == null) + throw new ArgumentNullException(nameof(path)); + if (File.Exists(path)) + path = Path.GetDirectoryName(path); + if (path == null) + throw new ArgumentNullException(nameof(path)); + + var folder = FileName ?? "sarc"; + string dir = Path.Combine(path, folder); + + Directory.CreateDirectory(dir); + var count = SFAT.Entries.Count; + handler.Initialize(count); + for (int i = 0; i < count; i++) { - path ??= FilePath; - if (path == null) - throw new ArgumentNullException(nameof(path)); - if (File.Exists(path)) - path = Path.GetDirectoryName(path); - if (path == null) - throw new ArgumentNullException(nameof(path)); - - var folder = FileName ?? "sarc"; - string dir = Path.Combine(path, folder); - - Directory.CreateDirectory(dir); - var count = SFAT.Entries.Count; - handler.Initialize(count); - for (int i = 0; i < count; i++) - { - SFAT.Entries[i].Dump(Reader!.BaseStream, path, Header.DataOffset); - handler.StepFile(i + 1); - } - } - - public static SARC? GetSARC(BinaryReader br) - { - if (br.BaseStream.Length < 20) - return null; - br.BaseStream.Position = 0; - var ident = new string(br.ReadChars(4)); - if (ident != SARCHeader.Identifier) - return null; - return new SARC(br); + SFAT.Entries[i].Dump(Reader!.BaseStream, path, Header.DataOffset); + handler.StepFile(i + 1); } } -} \ No newline at end of file + + public static SARC? GetSARC(BinaryReader br) + { + if (br.BaseStream.Length < 20) + return null; + br.BaseStream.Position = 0; + var ident = new string(br.ReadChars(4)); + if (ident != SARCHeader.Identifier) + return null; + return new SARC(br); + } +} diff --git a/pkNX.Containers/SARC/SARCHeader.cs b/pkNX.Containers/SARC/SARCHeader.cs index a2d346d1..c4893c7f 100644 --- a/pkNX.Containers/SARC/SARCHeader.cs +++ b/pkNX.Containers/SARC/SARCHeader.cs @@ -1,47 +1,46 @@ -using System.IO; +using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class SARCHeader { - public class SARCHeader + public const string Identifier = nameof(SARC); + + /// + /// The required matches the first 4 bytes of the file data. + /// + public bool SigMatches => Magic == Identifier; + + public string Magic = Identifier; + public ushort HeaderSize = 0x14; + public ushort Endianness = 0xFFFE; + public uint FileSize; + public int DataOffset; + public ushort Version = 0x0100; + public ushort Reserved; + + public SARCHeader() { } + + public SARCHeader(BinaryReader Reader) { - public const string Identifier = nameof(SARC); + Magic = new string(Reader.ReadChars(4)); + HeaderSize = Reader.ReadUInt16(); + Endianness = Reader.ReadUInt16(); + FileSize = Reader.ReadUInt32(); + DataOffset = Reader.ReadInt32(); + Version = Reader.ReadUInt16(); + Reserved = Reader.ReadUInt16(); + } - /// - /// The required matches the first 4 bytes of the file data. - /// - public bool SigMatches => Magic == Identifier; - - public string Magic = Identifier; - public ushort HeaderSize = 0x14; - public ushort Endianness = 0xFFFE; - public uint FileSize; - public int DataOffset; - public ushort Version = 0x0100; - public ushort Reserved; - - public SARCHeader() { } - - public SARCHeader(BinaryReader Reader) - { - Magic = new string(Reader.ReadChars(4)); - HeaderSize = Reader.ReadUInt16(); - Endianness = Reader.ReadUInt16(); - FileSize = Reader.ReadUInt32(); - DataOffset = Reader.ReadInt32(); - Version = Reader.ReadUInt16(); - Reserved = Reader.ReadUInt16(); - } - - public void Write(BinaryWriter bw) - { - foreach (var c in Magic) - bw.Write((byte)c); - bw.Write(HeaderSize); - bw.Write(FileSize); - bw.Write(FileSize); - bw.Write(DataOffset); - bw.Write(Version); - bw.Write(Reserved); - } + public void Write(BinaryWriter bw) + { + foreach (var c in Magic) + bw.Write((byte)c); + bw.Write(HeaderSize); + bw.Write(FileSize); + bw.Write(FileSize); + bw.Write(DataOffset); + bw.Write(Version); + bw.Write(Reserved); } } diff --git a/pkNX.Containers/SARC/SFAT.cs b/pkNX.Containers/SARC/SFAT.cs index f538ea59..313533db 100644 --- a/pkNX.Containers/SARC/SFAT.cs +++ b/pkNX.Containers/SARC/SFAT.cs @@ -1,78 +1,77 @@ -using System; +using System; using System.Collections.Generic; using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// File Access Table +/// +public class SFAT { + public const string Identifier = nameof(SFAT); + /// - /// File Access Table + /// The required matches the first 4 bytes of the file data. /// - public class SFAT + public bool SigMatches => Magic == Identifier; + + private readonly string Magic = Identifier; + private readonly ushort HeaderSize = 0xC; + private readonly ushort EntryCount; + private readonly uint HashMult = 0x65; + public readonly List Entries; + + public SFATEntry this[int index] { - public const string Identifier = nameof(SFAT); + get => Entries[index]; + set => Entries[index] = value; + } - /// - /// The required matches the first 4 bytes of the file data. - /// - public bool SigMatches => Magic == Identifier; - - private readonly string Magic = Identifier; - private readonly ushort HeaderSize = 0xC; - private readonly ushort EntryCount; - private readonly uint HashMult = 0x65; - public readonly List Entries; - - public SFATEntry this[int index] + public SFAT(string baseFolder, IReadOnlyList files) + { + EntryCount = (ushort)files.Count; + Entries = new List(EntryCount); + for (int i = 0; i < EntryCount; i++) { - get => Entries[index]; - set => Entries[index] = value; - } + Entries[i] = new SFATEntry {File = files[i]}; - public SFAT(string baseFolder, IReadOnlyList files) - { - EntryCount = (ushort)files.Count; - Entries = new List(EntryCount); - for (int i = 0; i < EntryCount; i++) - { - Entries[i] = new SFATEntry {File = files[i]}; - - var fn = files[i].Remove(baseFolder.Length); - Entries[i].SetFileName(fn, HashMult); - } - } - - public SFAT(BinaryReader br, int DataOffset) - { - Magic = new string(br.ReadChars(4)); - if (!SigMatches) - throw new FormatException(nameof(SFAT)); - - HeaderSize = br.ReadUInt16(); - EntryCount = br.ReadUInt16(); - HashMult = br.ReadUInt32(); - Entries = new List(EntryCount); - - for (int i = 0; i < EntryCount; i++) - Entries.Add(new SFATEntry(br, DataOffset)); - } - - public string GetFileName(int index, Stream parent, int StringOffset) => this[index].GetFileName(parent, StringOffset); - public void SetFileName(int index, string value) => this[index].SetFileName(value, HashMult); - - public void Write(BinaryWriter bw) - { - foreach (var c in Magic) - bw.Write((byte)c); - bw.Write(HeaderSize); - bw.Write(EntryCount); - bw.Write(HashMult); - WriteEntries(bw); - } - - public void WriteEntries(BinaryWriter bw) - { - foreach (var entry in Entries) - entry.Write(bw); + var fn = files[i].Remove(baseFolder.Length); + Entries[i].SetFileName(fn, HashMult); } } -} \ No newline at end of file + + public SFAT(BinaryReader br, int DataOffset) + { + Magic = new string(br.ReadChars(4)); + if (!SigMatches) + throw new FormatException(nameof(SFAT)); + + HeaderSize = br.ReadUInt16(); + EntryCount = br.ReadUInt16(); + HashMult = br.ReadUInt32(); + Entries = new List(EntryCount); + + for (int i = 0; i < EntryCount; i++) + Entries.Add(new SFATEntry(br, DataOffset)); + } + + public string GetFileName(int index, Stream parent, int StringOffset) => this[index].GetFileName(parent, StringOffset); + public void SetFileName(int index, string value) => this[index].SetFileName(value, HashMult); + + public void Write(BinaryWriter bw) + { + foreach (var c in Magic) + bw.Write((byte)c); + bw.Write(HeaderSize); + bw.Write(EntryCount); + bw.Write(HashMult); + WriteEntries(bw); + } + + public void WriteEntries(BinaryWriter bw) + { + foreach (var entry in Entries) + entry.Write(bw); + } +} diff --git a/pkNX.Containers/SARC/SFATEntry.cs b/pkNX.Containers/SARC/SFATEntry.cs index 1f46f32d..40a6a6ef 100644 --- a/pkNX.Containers/SARC/SFATEntry.cs +++ b/pkNX.Containers/SARC/SFATEntry.cs @@ -1,81 +1,80 @@ -using System.IO; +using System.IO; using System.Text; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// File Access Table () Entry +/// +public class SFATEntry : LargeContainerEntry { - /// - /// File Access Table () Entry - /// - public class SFATEntry : LargeContainerEntry + public uint FileNameHash; + public int FileNameOffset; + + public string? FileName { get; private set; } + + private static uint GetHash(string name, int length, uint multiplier) { - public uint FileNameHash; - public int FileNameOffset; - - public string? FileName { get; private set; } - - private static uint GetHash(string name, int length, uint multiplier) - { - uint result = 0; - for (int i = 0; i < length; i++) - result = name[i] + (result * multiplier); - return result; - } - - public override int Length - { - get => End - Start; - set { } - } - - public SFATEntry() { } - - public SFATEntry(BinaryReader br, int DataOffset) - { - FileNameHash = br.ReadUInt32(); - FileNameOffset = br.ReadInt32(); - Start = br.ReadInt32(); - End = br.ReadInt32(); - ParentDataPosition = DataOffset; - } - - public void Write(BinaryWriter bw) - { - bw.Write(FileNameHash); - bw.Write(FileNameOffset); - bw.Write(Start); - bw.Write(End); - } - - public string GetFileName(Stream parent, int StringOffset) - { - if (FileName != null) - return FileName; - - var ofs = ((FileNameOffset & 0x00FFFFFF) * 4) + StringOffset; - parent.Seek(ofs, SeekOrigin.Begin); - var sb = new StringBuilder(); - - for (char c = (char)parent.ReadByte(); c != 0; c = (char)parent.ReadByte()) - sb.Append(c); - - FileName = sb.Replace('/', Path.DirectorySeparatorChar).ToString(); - return FileName; - } - - public void WriteFileName(Stream parent, int StringOffset) - { - FileNameOffset = (int)(parent.Position - StringOffset) / 4; - - var str = FileName?.Replace(Path.DirectorySeparatorChar, '/') ?? string.Empty; - foreach (var b in str) - parent.WriteByte((byte)b); - parent.WriteByte(0); // \0 - } - - public void SetFileName(string value, uint hashMult) - { - FileName = value; - FileNameHash = GetHash(value, value.Length, hashMult); - } + uint result = 0; + for (int i = 0; i < length; i++) + result = name[i] + (result * multiplier); + return result; } -} \ No newline at end of file + + public override int Length + { + get => End - Start; + set { } + } + + public SFATEntry() { } + + public SFATEntry(BinaryReader br, int DataOffset) + { + FileNameHash = br.ReadUInt32(); + FileNameOffset = br.ReadInt32(); + Start = br.ReadInt32(); + End = br.ReadInt32(); + ParentDataPosition = DataOffset; + } + + public void Write(BinaryWriter bw) + { + bw.Write(FileNameHash); + bw.Write(FileNameOffset); + bw.Write(Start); + bw.Write(End); + } + + public string GetFileName(Stream parent, int StringOffset) + { + if (FileName != null) + return FileName; + + var ofs = ((FileNameOffset & 0x00FFFFFF) * 4) + StringOffset; + parent.Seek(ofs, SeekOrigin.Begin); + var sb = new StringBuilder(); + + for (char c = (char)parent.ReadByte(); c != 0; c = (char)parent.ReadByte()) + sb.Append(c); + + FileName = sb.Replace('/', Path.DirectorySeparatorChar).ToString(); + return FileName; + } + + public void WriteFileName(Stream parent, int StringOffset) + { + FileNameOffset = (int)(parent.Position - StringOffset) / 4; + + var str = FileName?.Replace(Path.DirectorySeparatorChar, '/') ?? string.Empty; + foreach (var b in str) + parent.WriteByte((byte)b); + parent.WriteByte(0); // \0 + } + + public void SetFileName(string value, uint hashMult) + { + FileName = value; + FileNameHash = GetHash(value, value.Length, hashMult); + } +} diff --git a/pkNX.Containers/SARC/SFNT.cs b/pkNX.Containers/SARC/SFNT.cs index a956b49d..b0b7234b 100644 --- a/pkNX.Containers/SARC/SFNT.cs +++ b/pkNX.Containers/SARC/SFNT.cs @@ -1,45 +1,44 @@ using System; using System.IO; -namespace pkNX.Containers +namespace pkNX.Containers; + +/// +/// File Name Table +/// +public class SFNT { + public const string Identifier = nameof(SFNT); + /// - /// File Name Table + /// The required matches the first 4 bytes of the file data. /// - public class SFNT + public bool SigMatches => Magic == Identifier; + + public string Magic = Identifier; + public ushort HeaderSize; + public ushort Reserved; + public uint StringOffset; + + public SFNT() { } + + public SFNT(BinaryReader br) { - public const string Identifier = nameof(SFNT); + Magic = new string(br.ReadChars(4)); + if (!SigMatches) + throw new FormatException(nameof(SFNT)); - /// - /// The required matches the first 4 bytes of the file data. - /// - public bool SigMatches => Magic == Identifier; - - public string Magic = Identifier; - public ushort HeaderSize; - public ushort Reserved; - public uint StringOffset; - - public SFNT() { } - - public SFNT(BinaryReader br) - { - Magic = new string(br.ReadChars(4)); - if (!SigMatches) - throw new FormatException(nameof(SFNT)); - - HeaderSize = br.ReadUInt16(); - Reserved = br.ReadUInt16(); - StringOffset = (uint)br.BaseStream.Position; - } - - public void Write(BinaryWriter bw) - { - foreach (var c in Magic) - bw.Write((byte)c); - bw.Write(HeaderSize); - bw.Write(Reserved); - StringOffset = (uint)bw.BaseStream.Position; - } + HeaderSize = br.ReadUInt16(); + Reserved = br.ReadUInt16(); + StringOffset = (uint)br.BaseStream.Position; } -} \ No newline at end of file + + public void Write(BinaryWriter bw) + { + foreach (var c in Magic) + bw.Write((byte)c); + bw.Write(HeaderSize); + bw.Write(Reserved); + StringOffset = (uint)bw.BaseStream.Position; + } +} diff --git a/pkNX.Containers/SingleFileContainer.cs b/pkNX.Containers/SingleFileContainer.cs index d137b560..af35a17a 100644 --- a/pkNX.Containers/SingleFileContainer.cs +++ b/pkNX.Containers/SingleFileContainer.cs @@ -1,45 +1,44 @@ -using System; +using System; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; -namespace pkNX.Containers +namespace pkNX.Containers; + +public class SingleFileContainer : IFileContainer { - public class SingleFileContainer : IFileContainer + public string? FilePath { get; set; } + public bool Modified { get; set; } + public int Count => 1; + + public byte[] Data = Array.Empty(); + private byte[] Backup = Array.Empty(); + public SingleFileContainer(byte[] data) => LoadData(data); + public SingleFileContainer(BinaryReader br) => LoadData(br.ReadBytes((int) br.BaseStream.Length)); + public SingleFileContainer(string path) => LoadData(FileMitm.ReadAllBytes(FilePath = path)); + + private void LoadData(byte[] data) => Backup = (byte[]) (Data = data).Clone(); + + public void CancelEdits() { - public string? FilePath { get; set; } - public bool Modified { get; set; } - public int Count => 1; - - public byte[] Data = Array.Empty(); - private byte[] Backup = Array.Empty(); - public SingleFileContainer(byte[] data) => LoadData(data); - public SingleFileContainer(BinaryReader br) => LoadData(br.ReadBytes((int) br.BaseStream.Length)); - public SingleFileContainer(string path) => LoadData(FileMitm.ReadAllBytes(FilePath = path)); - - private void LoadData(byte[] data) => Backup = (byte[]) (Data = data).Clone(); - - public void CancelEdits() - { - Modified = false; - Data = (byte[]) Backup.Clone(); - } - - public byte[] this[int index] - { - get => (byte[])Data.Clone(); - set - { - Modified |= !Data.SequenceEqual(value); - Data = value; - } - } - - public Task GetFiles() => Task.FromResult(new[] {this[0]}); - public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[0]); - public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(Data = value); - public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => Dump(path, handler), token); - public void Dump(string? path, ContainerHandler handler) => FileMitm.WriteAllBytes(path ?? FilePath!, Data); + Modified = false; + Data = (byte[]) Backup.Clone(); } + + public byte[] this[int index] + { + get => (byte[])Data.Clone(); + set + { + Modified |= !Data.SequenceEqual(value); + Data = value; + } + } + + public Task GetFiles() => Task.FromResult(new[] {this[0]}); + public Task GetFile(int file, int subFile = 0) => Task.FromResult(this[0]); + public Task SetFile(int file, byte[] value, int subFile = 0) => Task.FromResult(Data = value); + public Task SaveAs(string path, ContainerHandler handler, CancellationToken token) => new(() => Dump(path, handler), token); + public void Dump(string? path, ContainerHandler handler) => FileMitm.WriteAllBytes(path ?? FilePath!, Data); } diff --git a/pkNX.Containers/pkNX.Containers.csproj b/pkNX.Containers/pkNX.Containers.csproj index ff322c46..025142bd 100644 --- a/pkNX.Containers/pkNX.Containers.csproj +++ b/pkNX.Containers/pkNX.Containers.csproj @@ -1,16 +1,14 @@ - netstandard2.0;net461 + net6.0 Packing & Unpacking 10 enable - - diff --git a/pkNX.Game/Editors/DataCache.cs b/pkNX.Game/Editors/DataCache.cs index ad58dab9..161b8152 100644 --- a/pkNX.Game/Editors/DataCache.cs +++ b/pkNX.Game/Editors/DataCache.cs @@ -2,114 +2,113 @@ using pkNX.Containers; using pkNX.Structures.FlatBuffers; -namespace pkNX.Game +namespace pkNX.Game; + +public class DataCache : IDataEditor where T : class { - public class DataCache : IDataEditor where T : class + public IFileContainer Data { protected get; set; } + public Func Create { private get; set; } + public Func Write { protected get; set; } + + public DataCache(T[] cache) => Cache = cache; + public DataCache(IFileContainer f) : this(new T[f.Count]) => Data = f; + + protected readonly T[] Cache; + private bool Cached; + + public int Length => Cache.Length; + + public T this[int index] { - public IFileContainer Data { protected get; set; } - public Func Create { private get; set; } - public Func Write { protected get; set; } + get => Cache[index] ??= Create(Data[index]); + set => Cache[index] = value; + } - public DataCache(T[] cache) => Cache = cache; - public DataCache(IFileContainer f) : this(new T[f.Count]) => Data = f; + public void CancelEdits() + { + for (int i = 0; i < Cache.Length; i++) + Cache[i] = default; + } - protected readonly T[] Cache; - private bool Cached; + public void Initialize() { } - public int Length => Cache.Length; - - public T this[int index] - { - get => Cache[index] ??= Create(Data[index]); - set => Cache[index] = value; - } - - public void CancelEdits() - { - for (int i = 0; i < Cache.Length; i++) - Cache[i] = default; - } - - public void Initialize() { } - - public T[] LoadAll() - { - if (Cached) - return Cache; - for (int i = 0; i < Length; i++) - { - // ReSharper disable once AssignmentIsFullyDiscarded - _ = this[i]; // force load cache - } - - Cached = true; + public T[] LoadAll() + { + if (Cached) return Cache; + for (int i = 0; i < Length; i++) + { + // ReSharper disable once AssignmentIsFullyDiscarded + _ = this[i]; // force load cache } - public void ClearAll() - { - Cached = false; - for (int i = 0; i < Cache.Length; i++) - Cache[i] = null; - } + Cached = true; + return Cache; + } - /// - /// Pushes changes back to the . - /// - public virtual void Save() - { - for (int i = 0; i < Cache.Length; i++) - { - var val = Cache[i]; - if (val == null) - continue; - Data[i] = Write(val); - } - } + public void ClearAll() + { + Cached = false; + for (int i = 0; i < Cache.Length; i++) + Cache[i] = null; } /// - /// Data with already known contents. + /// Pushes changes back to the . /// - /// - public class DirectCache : DataCache where T : class + public virtual void Save() { - public DirectCache(T[] cache) : base(cache) { } - public override void Save() { } + for (int i = 0; i < Cache.Length; i++) + { + var val = Cache[i]; + if (val == null) + continue; + Data[i] = Write(val); + } + } +} + +/// +/// Data with already known contents. +/// +/// +public class DirectCache : DataCache where T : class +{ + public DirectCache(T[] cache) : base(cache) { } + public override void Save() { } +} + +/// +/// Data 'from a flatbuffer table +/// +/// The type of table +/// The type of data inside the table +public class TableCache + where TTable : class, IFlatBufferArchive + where TData : class +{ + public IFileContainer File { get; private set; } + public TTable Root { get; private set; } + public TData[] Table => Root.Table; + public DataCache Cache { get; private set; } + + public TableCache(IFileContainer f) + { + File = f; + Root = FlatBufferConverter.DeserializeFrom(f[0]); + Cache = new DirectCache(Root.Table); } - /// - /// Data 'from a flatbuffer table - /// - /// The type of table - /// The type of data inside the table - public class TableCache - where TTable : class, IFlatBufferArchive - where TData : class + public void Save() { - public IFileContainer File { get; private set; } - public TTable Root { get; private set; } - public TData[] Table => Root.Table; - public DataCache Cache { get; private set; } - - public TableCache(IFileContainer f) - { - File = f; - Root = FlatBufferConverter.DeserializeFrom(f[0]); - Cache = new DirectCache(Root.Table); - } - - public void Save() - { - File[0] = FlatBufferConverter.SerializeFrom(Root); - } - - public TData this[int index] - { - get => Cache[index]; - set => Cache[index] = value; - } - - public int Length => Cache.Length; + File[0] = FlatBufferConverter.SerializeFrom(Root); } + + public TData this[int index] + { + get => Cache[index]; + set => Cache[index] = value; + } + + public int Length => Cache.Length; } \ No newline at end of file diff --git a/pkNX.Game/Editors/EditorFactory.cs b/pkNX.Game/Editors/EditorFactory.cs index 20bdf852..a8ff978c 100644 --- a/pkNX.Game/Editors/EditorFactory.cs +++ b/pkNX.Game/Editors/EditorFactory.cs @@ -1,6 +1,5 @@ -namespace pkNX.Game +namespace pkNX.Game; + +public class EditorFactory { - public class EditorFactory - { - } -} +} \ No newline at end of file diff --git a/pkNX.Game/Editors/EditorUtil.cs b/pkNX.Game/Editors/EditorUtil.cs index 297ca089..2dc6c334 100644 --- a/pkNX.Game/Editors/EditorUtil.cs +++ b/pkNX.Game/Editors/EditorUtil.cs @@ -1,16 +1,15 @@ -namespace pkNX.Game +namespace pkNX.Game; + +public static class EditorUtil { - public static class EditorUtil + public static string[] SanitizeMoveList(string[] list) { - public static string[] SanitizeMoveList(string[] list) - { - var movelist = (string[])list.Clone(); - if (movelist.Length < 658) - return movelist; - string[] ps = { "P", "S" }; // Distinguish Physical/Special Z Moves - for (int i = 622; i < 658; i++) - movelist[i] += $" ({ps[i % 2]})"; + var movelist = (string[])list.Clone(); + if (movelist.Length < 658) return movelist; - } + string[] ps = { "P", "S" }; // Distinguish Physical/Special Z Moves + for (int i = 622; i < 658; i++) + movelist[i] += $" ({ps[i % 2]})"; + return movelist; } -} +} \ No newline at end of file diff --git a/pkNX.Game/Editors/IDataEditor.cs b/pkNX.Game/Editors/IDataEditor.cs index b23e23ea..6dbcb3e5 100644 --- a/pkNX.Game/Editors/IDataEditor.cs +++ b/pkNX.Game/Editors/IDataEditor.cs @@ -1,9 +1,8 @@ -namespace pkNX.Game +namespace pkNX.Game; + +public interface IDataEditor { - public interface IDataEditor - { - void CancelEdits(); - void Initialize(); - void Save(); - } + void CancelEdits(); + void Initialize(); + void Save(); } \ No newline at end of file diff --git a/pkNX.Game/Editors/Poke/PokeEditor.cs b/pkNX.Game/Editors/Poke/PokeEditor.cs index be3873e5..280955e3 100644 --- a/pkNX.Game/Editors/Poke/PokeEditor.cs +++ b/pkNX.Game/Editors/Poke/PokeEditor.cs @@ -1,30 +1,29 @@ using System.Collections.Generic; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public class PokeEditor : IDataEditor { - public class PokeEditor : IDataEditor + public IPersonalTable Personal { get; set; } + public DataCache Learn { get; set; } + public DataCache Evolve { get; set; } + public DataCache Mega { get; set; } + public IReadOnlyList TMHM { get; set; } + + public void CancelEdits() { - public IPersonalTable Personal { get; set; } - public DataCache Learn { get; set; } - public DataCache Evolve { get; set; } - public DataCache Mega { get; set; } - public IReadOnlyList TMHM { get; set; } - - public void CancelEdits() - { - Learn.CancelEdits(); - Evolve.CancelEdits(); - Mega?.CancelEdits(); - } - - public void Initialize() { } - - public void Save() - { - Learn.Save(); - Evolve.Save(); - Mega?.Save(); - } + Learn.CancelEdits(); + Evolve.CancelEdits(); + Mega?.CancelEdits(); } -} + + public void Initialize() { } + + public void Save() + { + Learn.Save(); + Evolve.Save(); + Mega?.Save(); + } +} \ No newline at end of file diff --git a/pkNX.Game/Editors/Poke/PokeEditor8a.cs b/pkNX.Game/Editors/Poke/PokeEditor8a.cs index b8d17f53..e0da64f8 100644 --- a/pkNX.Game/Editors/Poke/PokeEditor8a.cs +++ b/pkNX.Game/Editors/Poke/PokeEditor8a.cs @@ -1,32 +1,30 @@ -using System.Collections.Generic; using pkNX.Structures; using pkNX.Structures.FlatBuffers; -namespace pkNX.Game +namespace pkNX.Game; + +public class PokeEditor8a : IDataEditor { - public class PokeEditor8a : IDataEditor + public IPersonalTable Personal { get; set; } + public TableCache PokeMisc { get; set; } + public TableCache Evolve { get; set; } + public TableCache Learn { get; set; } + public TableCache FieldDropTables { get; set; } + public TableCache BattleDropTabels { get; set; } + public TableCache DexResearch { get; set; } + + public void CancelEdits() { } + + public void Initialize() { } + + public void Save() { - public IPersonalTable Personal { get; set; } - public TableCache PokeMisc { get; set; } - public TableCache Evolve { get; set; } - public TableCache Learn { get; set; } - public TableCache FieldDropTables { get; set; } - public TableCache BattleDropTabels { get; set; } - public TableCache DexResearch { get; set; } - - public void CancelEdits() { } - - public void Initialize() { } - - public void Save() - { - Personal.Save(); - PokeMisc.Save(); - Learn.Save(); - Evolve.Save(); - FieldDropTables.Save(); - BattleDropTabels.Save(); - DexResearch.Save(); - } + Personal.Save(); + PokeMisc.Save(); + Learn.Save(); + Evolve.Save(); + FieldDropTables.Save(); + BattleDropTabels.Save(); + DexResearch.Save(); } } diff --git a/pkNX.Game/Editors/ShinyRate/ShinyRateGG.cs b/pkNX.Game/Editors/ShinyRate/ShinyRateGG.cs index da33ea98..4ec6b1ec 100644 --- a/pkNX.Game/Editors/ShinyRate/ShinyRateGG.cs +++ b/pkNX.Game/Editors/ShinyRate/ShinyRateGG.cs @@ -1,88 +1,87 @@ using System; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public sealed class ShinyRateGG : ShinyRateInfo { - public sealed class ShinyRateGG : ShinyRateInfo + /* + Shiny Rate Patch -- fix the loop counter regardless of input param value. + ARM64 disassembly @ sub_71007399D8 + LDRB W8, [X19, #0x25] // load loop max + ADD W20, W20, #1 // increment counter + CMP W20, W8 // compare counter to max + BL -44 // branch if less (loop) + B [....] // branch (no loop), PID is done! + + Patch creation: accept input for reroll count=1-4091 + Get u32: ((count & 0xFFF) << 10) | 0b111000100_000000000000_1010011111 + Convert to bytes, this is our new "CMP W20, XXX" instruction + + Replace these bytes: + 68 96 40 39 94 06 00 11 9F 02 08 6B + With these bytes: + 68 96 40 39 94 06 00 11 [u32 bytes] + + *** + Always Shiny Patch -- nop the bl + write 1F 20 03 D5 after the above 12 byte sequence + + *** + Revert above patch -- restore the bl + write AB FE FF 54 after the above 12 byte sequence + */ + + private readonly int CodeOffset; + private static readonly byte[] Pattern = { 0x68, 0x96, 0x40, 0x39, 0x94, 0x06, 0x00, 0x11 }; + private static readonly byte[] Default = { 0x9F, 0x02, 0x08, 0x6B }; // cmp W20, W8 + private static readonly byte[] Always12 = { 0x1F, 0x20, 0x03, 0xD5 }; // nop + private static readonly byte[] Revert12 = { 0xAB, 0xFE, 0xFF, 0x54 }; // bl + + public ShinyRateGG(byte[] data) : base(data) => CodeOffset = CodePattern.IndexOfBytes(data, Pattern, 0x500_000); + + public override bool IsEditable => CodeOffset > 0; + + public override bool IsDefault => !IsAlways && IsPresent(Data, Default, CodeOffset + 8); + public override bool IsFixed => !IsAlways && !IsDefault; + public override bool IsAlways => IsPresent(Data, Always12, CodeOffset + 12); + + public override bool AllowAlways => false; + + public override int GetFixedRate() // "CMP W20, {val}" instruction { - /* - Shiny Rate Patch -- fix the loop counter regardless of input param value. - ARM64 disassembly @ sub_71007399D8 - LDRB W8, [X19, #0x25] // load loop max - ADD W20, W20, #1 // increment counter - CMP W20, W8 // compare counter to max - BL -44 // branch if less (loop) - B [....] // branch (no loop), PID is done! + if (!IsFixed) + return -1; + var instr = BitConverter.ToUInt32(Data, CodeOffset + 8); + return (int)((instr >> 10) & 0xFFF); + } - Patch creation: accept input for reroll count=1-4091 - Get u32: ((count & 0xFFF) << 10) | 0b111000100_000000000000_1010011111 - Convert to bytes, this is our new "CMP W20, XXX" instruction + public override void SetDefault() + { + Default.CopyTo(Data, CodeOffset + 8); + Revert12.CopyTo(Data, CodeOffset + 12); + } - Replace these bytes: - 68 96 40 39 94 06 00 11 9F 02 08 6B - With these bytes: - 68 96 40 39 94 06 00 11 [u32 bytes] + public override void SetFixedRate(int rerollCount) + { + var instr = GetFixedInstruction(rerollCount); + instr.CopyTo(Data, CodeOffset + 8); + Revert12.CopyTo(Data, CodeOffset + 12); + } - *** - Always Shiny Patch -- nop the bl - write 1F 20 03 D5 after the above 12 byte sequence + public override void SetAlwaysShiny() + { + Default.CopyTo(Data, CodeOffset + 8); + Always12.CopyTo(Data, CodeOffset + 12); + } - *** - Revert above patch -- restore the bl - write AB FE FF 54 after the above 12 byte sequence - */ - - private readonly int CodeOffset; - private static readonly byte[] Pattern = { 0x68, 0x96, 0x40, 0x39, 0x94, 0x06, 0x00, 0x11 }; - private static readonly byte[] Default = { 0x9F, 0x02, 0x08, 0x6B }; // cmp W20, W8 - private static readonly byte[] Always12 = { 0x1F, 0x20, 0x03, 0xD5 }; // nop - private static readonly byte[] Revert12 = { 0xAB, 0xFE, 0xFF, 0x54 }; // bl - - public ShinyRateGG(byte[] data) : base(data) => CodeOffset = CodePattern.IndexOfBytes(data, Pattern, 0x500_000); - - public override bool IsEditable => CodeOffset > 0; - - public override bool IsDefault => !IsAlways && IsPresent(Data, Default, CodeOffset + 8); - public override bool IsFixed => !IsAlways && !IsDefault; - public override bool IsAlways => IsPresent(Data, Always12, CodeOffset + 12); - - public override bool AllowAlways => false; - - public override int GetFixedRate() // "CMP W20, {val}" instruction - { - if (!IsFixed) - return -1; - var instr = BitConverter.ToUInt32(Data, CodeOffset + 8); - return (int)((instr >> 10) & 0xFFF); - } - - public override void SetDefault() - { - Default.CopyTo(Data, CodeOffset + 8); - Revert12.CopyTo(Data, CodeOffset + 12); - } - - public override void SetFixedRate(int rerollCount) - { - var instr = GetFixedInstruction(rerollCount); - instr.CopyTo(Data, CodeOffset + 8); - Revert12.CopyTo(Data, CodeOffset + 12); - } - - public override void SetAlwaysShiny() - { - Default.CopyTo(Data, CodeOffset + 8); - Always12.CopyTo(Data, CodeOffset + 12); - } - - public static byte[] GetFixedInstruction(int count) - { - if (count <= 0) - count = 1; - else if (count >= 4092) - count = 4091; - var val = ((count & 0xFFF) << 10) | 0b111000100_000000000000_1010011111; - return BitConverter.GetBytes((uint)val); - } + public static byte[] GetFixedInstruction(int count) + { + if (count <= 0) + count = 1; + else if (count >= 4092) + count = 4091; + var val = ((count & 0xFFF) << 10) | 0b111000100_000000000000_1010011111; + return BitConverter.GetBytes((uint)val); } } \ No newline at end of file diff --git a/pkNX.Game/Editors/ShinyRate/ShinyRateInfo.cs b/pkNX.Game/Editors/ShinyRate/ShinyRateInfo.cs index 89f3c192..ea29dfe9 100644 --- a/pkNX.Game/Editors/ShinyRate/ShinyRateInfo.cs +++ b/pkNX.Game/Editors/ShinyRate/ShinyRateInfo.cs @@ -1,30 +1,29 @@ -namespace pkNX.Game +namespace pkNX.Game; + +public abstract class ShinyRateInfo { - public abstract class ShinyRateInfo + public byte[] Data { get; } + protected ShinyRateInfo(byte[] data) => Data = data; + + public abstract bool IsEditable { get; } + + public abstract bool IsDefault { get; } + public abstract bool IsFixed { get; } + public abstract bool IsAlways { get; } + public abstract bool AllowAlways { get; } + + public abstract int GetFixedRate(); + public abstract void SetDefault(); + public abstract void SetFixedRate(int rerollCount); + public abstract void SetAlwaysShiny(); + + protected static bool IsPresent(byte[] source, byte[] pattern, int offset) { - public byte[] Data { get; } - protected ShinyRateInfo(byte[] data) => Data = data; - - public abstract bool IsEditable { get; } - - public abstract bool IsDefault { get; } - public abstract bool IsFixed { get; } - public abstract bool IsAlways { get; } - public abstract bool AllowAlways { get; } - - public abstract int GetFixedRate(); - public abstract void SetDefault(); - public abstract void SetFixedRate(int rerollCount); - public abstract void SetAlwaysShiny(); - - protected static bool IsPresent(byte[] source, byte[] pattern, int offset) + for (int i = 0; i < pattern.Length; i++) { - for (int i = 0; i < pattern.Length; i++) - { - if (source[i + offset] != pattern[i]) - return false; - } - return true; + if (source[i + offset] != pattern[i]) + return false; } + return true; } -} +} \ No newline at end of file diff --git a/pkNX.Game/Editors/ShinyRate/ShinyRateSWSH.cs b/pkNX.Game/Editors/ShinyRate/ShinyRateSWSH.cs index fb078d5c..06eef824 100644 --- a/pkNX.Game/Editors/ShinyRate/ShinyRateSWSH.cs +++ b/pkNX.Game/Editors/ShinyRate/ShinyRateSWSH.cs @@ -1,96 +1,94 @@ using System; -using System.Diagnostics; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public sealed class ShinyRateSWSH : ShinyRateInfo { - public sealed class ShinyRateSWSH : ShinyRateInfo + /* + Shiny Rate Patch -- fix the overworld loop counter regardless of shiny rate factors. + ARM64 disassembly @ FUN_7100d311f0 (Shield), FUN_7100d311c0 (Sword) + + orr w24,w24,w0 // set flag for shiny if found + cmp w25,w23 // check loop counter + b.cs LAB_7100d314c8 // break if maximum loop reached + + + Patch creation: accept input for reroll count=0-4095 + Get u32: ((count & 0xFFF) << 10) | 0b0111000100_000000000000_11001_11111 + Convert to bytes, this is our new "CMP W25, XXX" instruction + + Replace these bytes: + 18 03 00 2a 3f 03 17 6b 62 00 00 54 + With these bytes: + 18 03 00 2a [u32 bytes] 62 00 00 54 + + *** + Always Shiny Patch -- nop the b.cs + write 1f 20 03 d5 to the last 4 bytes of the above sequence + + *** + Revert above patch -- restore the b.cs + write 62 00 00 54 after the above 12 byte sequence. + */ + + private readonly int FunctionOffset; // loop counter and break + private static readonly byte[] FunctionPrelude = { 0xff, 0x03, 0x06, 0xd1, 0xfc, 0x6f, 0x12, 0xa9, 0xfa, 0x67, 0x13, 0xa9, 0xf8, 0x5f, 0x14, 0xa9, 0xf6, 0x57, 0x15, 0xa9, 0xf4, 0x4f, 0x16, 0xa9, 0xfd, 0x7b, 0x17, 0xa9, 0xfd, 0xc3, 0x05, 0x91, 0xfa, 0xc6, 0x00, 0xf0 }; + + private static readonly int RerollCountCheckOffset = 0x2C8; + private static readonly byte[] RerollCountCheckDefault = { 0x3f, 0x03, 0x17, 0x6b}; + + private static readonly int RerollCountBreakOffset = 0x2CC; + private static readonly byte[] RerollCountBreakDefault = { 0x62, 0x00, 0x00, 0x54 }; // b.cs $pc + 12 + private static readonly byte[] RerollCountBreakNop = { 0x1F, 0x20, 0x03, 0xD5 }; // nop + + public ShinyRateSWSH(byte[] data, int offset = 0x700_000) : base(data) { - /* - Shiny Rate Patch -- fix the overworld loop counter regardless of shiny rate factors. - ARM64 disassembly @ FUN_7100d311f0 (Shield), FUN_7100d311c0 (Sword) + FunctionOffset = CodePattern.IndexOfBytes(data, FunctionPrelude, offset); + } - orr w24,w24,w0 // set flag for shiny if found - cmp w25,w23 // check loop counter - b.cs LAB_7100d314c8 // break if maximum loop reached + public override bool IsEditable => FunctionOffset > 0; + public override bool IsDefault => !IsAlways && !IsAlways; + public override bool IsFixed => !IsPresent(Data, RerollCountCheckDefault, FunctionOffset + RerollCountCheckOffset); + public override bool IsAlways => IsPresent(Data, RerollCountBreakNop, FunctionOffset + RerollCountBreakOffset); - Patch creation: accept input for reroll count=0-4095 - Get u32: ((count & 0xFFF) << 10) | 0b0111000100_000000000000_11001_11111 - Convert to bytes, this is our new "CMP W25, XXX" instruction + public override bool AllowAlways => true; - Replace these bytes: - 18 03 00 2a 3f 03 17 6b 62 00 00 54 - With these bytes: - 18 03 00 2a [u32 bytes] 62 00 00 54 + public override int GetFixedRate() // "CMP W25, {val}" instruction + { + if (!IsFixed) + return -1; + var instr = BitConverter.ToUInt32(Data, FunctionOffset + RerollCountCheckOffset); + return (int)((instr >> 10) & 0xFFF); + } - *** - Always Shiny Patch -- nop the b.cs - write 1f 20 03 d5 to the last 4 bytes of the above sequence + public override void SetDefault() + { + RerollCountCheckDefault.CopyTo(Data, FunctionOffset + RerollCountCheckOffset); + RerollCountBreakDefault.CopyTo(Data, FunctionOffset + RerollCountBreakOffset); + } - *** - Revert above patch -- restore the b.cs - write 62 00 00 54 after the above 12 byte sequence. - */ + public override void SetFixedRate(int rerollCount) + { + SetDefault(); + var instr = GetFixedInstruction(rerollCount); + instr.CopyTo(Data, FunctionOffset + RerollCountCheckOffset); + } - private readonly int FunctionOffset; // loop counter and break - private static readonly byte[] FunctionPrelude = { 0xff, 0x03, 0x06, 0xd1, 0xfc, 0x6f, 0x12, 0xa9, 0xfa, 0x67, 0x13, 0xa9, 0xf8, 0x5f, 0x14, 0xa9, 0xf6, 0x57, 0x15, 0xa9, 0xf4, 0x4f, 0x16, 0xa9, 0xfd, 0x7b, 0x17, 0xa9, 0xfd, 0xc3, 0x05, 0x91, 0xfa, 0xc6, 0x00, 0xf0 }; + public override void SetAlwaysShiny() + { + SetDefault(); + RerollCountBreakNop.CopyTo(Data, FunctionOffset + RerollCountBreakOffset); + } - private static readonly int RerollCountCheckOffset = 0x2C8; - private static readonly byte[] RerollCountCheckDefault = { 0x3f, 0x03, 0x17, 0x6b}; - - private static readonly int RerollCountBreakOffset = 0x2CC; - private static readonly byte[] RerollCountBreakDefault = { 0x62, 0x00, 0x00, 0x54 }; // b.cs $pc + 12 - private static readonly byte[] RerollCountBreakNop = { 0x1F, 0x20, 0x03, 0xD5 }; // nop - - public ShinyRateSWSH(byte[] data, int offset = 0x700_000) : base(data) - { - FunctionOffset = CodePattern.IndexOfBytes(data, FunctionPrelude, offset); - } - - public override bool IsEditable => FunctionOffset > 0; - - public override bool IsDefault => !IsAlways && !IsAlways; - public override bool IsFixed => !IsPresent(Data, RerollCountCheckDefault, FunctionOffset + RerollCountCheckOffset); - public override bool IsAlways => IsPresent(Data, RerollCountBreakNop, FunctionOffset + RerollCountBreakOffset); - - public override bool AllowAlways => true; - - public override int GetFixedRate() // "CMP W25, {val}" instruction - { - if (!IsFixed) - return -1; - var instr = BitConverter.ToUInt32(Data, FunctionOffset + RerollCountCheckOffset); - return (int)((instr >> 10) & 0xFFF); - } - - public override void SetDefault() - { - RerollCountCheckDefault.CopyTo(Data, FunctionOffset + RerollCountCheckOffset); - RerollCountBreakDefault.CopyTo(Data, FunctionOffset + RerollCountBreakOffset); - } - - public override void SetFixedRate(int rerollCount) - { - SetDefault(); - var instr = GetFixedInstruction(rerollCount); - instr.CopyTo(Data, FunctionOffset + RerollCountCheckOffset); - } - - public override void SetAlwaysShiny() - { - SetDefault(); - RerollCountBreakNop.CopyTo(Data, FunctionOffset + RerollCountBreakOffset); - } - - public static byte[] GetFixedInstruction(int count) - { - if (count <= 0) - count = 1; - else if (count >= 4092) - count = 4091; - var val = ((count & 0xFFF) << 10) | 0b0111000100_000000000000_11001_11111; - return BitConverter.GetBytes((uint)val); - } + public static byte[] GetFixedInstruction(int count) + { + if (count <= 0) + count = 1; + else if (count >= 4092) + count = 4091; + var val = ((count & 0xFFF) << 10) | 0b0111000100_000000000000_11001_11111; + return BitConverter.GetBytes((uint)val); } } diff --git a/pkNX.Game/Editors/TMEditorGG.cs b/pkNX.Game/Editors/TMEditorGG.cs index 395791f4..ca903da2 100644 --- a/pkNX.Game/Editors/TMEditorGG.cs +++ b/pkNX.Game/Editors/TMEditorGG.cs @@ -3,43 +3,42 @@ using pkNX.Containers; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public class TMEditorGG { - public class TMEditorGG + private readonly int Offset; + private readonly NSO NSO; + private readonly byte[] Data; + + private const int count = 60; + + public TMEditorGG(byte[] data) { - private readonly int Offset; - private readonly NSO NSO; - private readonly byte[] Data; + NSO = new NSO(data); + Data = NSO.DecompressedRO; - private const int count = 60; - - public TMEditorGG(byte[] data) - { - NSO = new NSO(data); - Data = NSO.DecompressedRO; - - // tm list is stored immediately after TM item index list - var pattern = CodePattern.TMHM_GG; - Offset = CodePattern.IndexOfBytes(Data, pattern, 0x200_000); - if (Valid) - Offset += pattern.Length; - } - - public ushort[] GetMoves() - { - var moves = new ushort[count]; - for (int i = 0; i < moves.Length; i++) - moves[i] = BitConverter.ToUInt16(Data, Offset + (2 * i)); - return moves; - } - - public void SetMoves(ushort[] finalMoves) - { - var result = finalMoves.SelectMany(BitConverter.GetBytes).ToArray(); - result.CopyTo(Data, Offset); - } - - public bool Valid => Offset > 0; - public byte[] Write() => NSO.Write(); + // tm list is stored immediately after TM item index list + var pattern = CodePattern.TMHM_GG; + Offset = CodePattern.IndexOfBytes(Data, pattern, 0x200_000); + if (Valid) + Offset += pattern.Length; } -} + + public ushort[] GetMoves() + { + var moves = new ushort[count]; + for (int i = 0; i < moves.Length; i++) + moves[i] = BitConverter.ToUInt16(Data, Offset + (2 * i)); + return moves; + } + + public void SetMoves(ushort[] finalMoves) + { + var result = finalMoves.SelectMany(BitConverter.GetBytes).ToArray(); + result.CopyTo(Data, Offset); + } + + public bool Valid => Offset > 0; + public byte[] Write() => NSO.Write(); +} \ No newline at end of file diff --git a/pkNX.Game/Editors/TrainerEditor.cs b/pkNX.Game/Editors/TrainerEditor.cs index 643f19fe..960b1c65 100644 --- a/pkNX.Game/Editors/TrainerEditor.cs +++ b/pkNX.Game/Editors/TrainerEditor.cs @@ -3,81 +3,80 @@ using pkNX.Containers; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public class TrainerEditor : IDataEditor { - public class TrainerEditor : IDataEditor + public IFileContainer TrainerData; + public IFileContainer TrainerPoke; + public IFileContainer TrainerClass; + public IFileContainer TrainerMsg; + + public Func ReadTrainer; + public Func ReadPoke; + public Func ReadTeam; + public Func WriteTeam; + public Func ReadClass; + + private VsTrainer[] Cache; + private TrainerClass[] CacheClass; + + public int Length => Cache.Length; + + public void Initialize() { - public IFileContainer TrainerData; - public IFileContainer TrainerPoke; - public IFileContainer TrainerClass; - public IFileContainer TrainerMsg; + Cache = new VsTrainer[TrainerData.Count]; + CacheClass = new TrainerClass[TrainerData.Count]; + } - public Func ReadTrainer; - public Func ReadPoke; - public Func ReadTeam; - public Func WriteTeam; - public Func ReadClass; + public VsTrainer this[int index] + { + get => Cache[index] ??= LoadTrainer(index); + set => Cache[index] = value; + } - private VsTrainer[] Cache; - private TrainerClass[] CacheClass; + public TrainerClass GetClass(int index) => CacheClass[index] ??= ReadClass(TrainerClass[index]); - public int Length => Cache.Length; - - public void Initialize() + private VsTrainer LoadTrainer(int index) + { + var tr = ReadTrainer(TrainerData[index]); + var poke = ReadTeam(TrainerPoke[index], tr); + var data = new VsTrainer { - Cache = new VsTrainer[TrainerData.Count]; - CacheClass = new TrainerClass[TrainerData.Count]; - } + ID = index, + Self = tr, + }; + data.Team.AddRange(poke); + return data; + } - public VsTrainer this[int index] + public void Save() + { + for (int i = 0; i < Length; i++) { - get => Cache[index] ??= LoadTrainer(index); - set => Cache[index] = value; - } - - public TrainerClass GetClass(int index) => CacheClass[index] ??= ReadClass(TrainerClass[index]); - - private VsTrainer LoadTrainer(int index) - { - var tr = ReadTrainer(TrainerData[index]); - var poke = ReadTeam(TrainerPoke[index], tr); - var data = new VsTrainer - { - ID = index, - Self = tr, - }; - data.Team.AddRange(poke); - return data; - } - - public void Save() - { - for (int i = 0; i < Length; i++) - { - var data = Cache[i]; - if (data == null) - continue; - data.Self.NumPokemon = data.Team.Count; - TrainerData[i] = data.Self.Write(); - TrainerPoke[i] = data.Team.SelectMany(z => z.Write()).ToArray(); - } - } - - public VsTrainer[] LoadAll() - { - for (int i = 0; i < Length; i++) - { - // ReSharper disable once AssignmentIsFullyDiscarded - _ = this[i]; // force load cache - } - - return Cache; - } - - public void CancelEdits() - { - TrainerData.CancelEdits(); - TrainerPoke.CancelEdits(); + var data = Cache[i]; + if (data == null) + continue; + data.Self.NumPokemon = data.Team.Count; + TrainerData[i] = data.Self.Write(); + TrainerPoke[i] = data.Team.SelectMany(z => z.Write()).ToArray(); } } + + public VsTrainer[] LoadAll() + { + for (int i = 0; i < Length; i++) + { + // ReSharper disable once AssignmentIsFullyDiscarded + _ = this[i]; // force load cache + } + + return Cache; + } + + public void CancelEdits() + { + TrainerData.CancelEdits(); + TrainerPoke.CancelEdits(); + } } \ No newline at end of file diff --git a/pkNX.Game/Editors/TypeChartEditor.cs b/pkNX.Game/Editors/TypeChartEditor.cs index 19b7b7d9..21ec2839 100644 --- a/pkNX.Game/Editors/TypeChartEditor.cs +++ b/pkNX.Game/Editors/TypeChartEditor.cs @@ -2,80 +2,79 @@ using pkNX.Structures; using Util = pkNX.Randomization.Util; -namespace pkNX.Game +namespace pkNX.Game; + +public class TypeChartEditor { - public class TypeChartEditor + public byte[] Data; + public int Width => (int)Math.Sqrt(Data.Length); + public int Height => (int)Math.Sqrt(Data.Length); + + public TypeChartEditor(byte[] data) => Data = data; + + public void Randomize() { - public byte[] Data; - public int Width => (int)Math.Sqrt(Data.Length); - public int Height => (int)Math.Sqrt(Data.Length); - - public TypeChartEditor(byte[] data) => Data = data; - - public void Randomize() + var rnd = Util.Random; + for (int i = 0; i < Data.Length; i++) { - var rnd = Util.Random; - for (int i = 0; i < Data.Length; i++) - { - var rv = rnd.Next(100); - Data[i] = GetEffectiveness(rv); - } - } - - private static byte GetEffectiveness(int rv) - { - return rv switch - { - < 2 => (byte)TypeEffectiveness.Immune, // 2% - < 19 => (byte)TypeEffectiveness.NotVery, // 17% - < 36 => (byte)TypeEffectiveness.Super, // 17% - _ => (byte)TypeEffectiveness.Normal, - }; - } - - private static readonly uint[] Colors = - { - 0xFF000000, - 0, // unused - 0xFFFF0000, - 0, // unused - 0xFFFFFFFF, - 0, 0, 0, // unused - 0xFF008000, - }; - - public static byte[] GetTypeChartImageData(int itemsize, int itemsPerRow, byte[] vals, out int width, out int height) - { - width = itemsize * itemsPerRow; - height = itemsize * vals.Length / itemsPerRow; - var bmpData = new byte[4 * width * height]; - - // loop over area - for (int i = 0; i < vals.Length; i++) - { - int X = i % itemsPerRow; - int Y = i / itemsPerRow; - - // Plop into image - byte[] itemColor = BitConverter.GetBytes(Colors[vals[i]]); - for (int x = 0; x < itemsize * itemsize; x++) - { - var ofs = (((Y * itemsize) + (x % itemsize)) * width * 4) + (((X * itemsize) + (x / itemsize)) * 4); - Buffer.BlockCopy(itemColor, 0, bmpData, ofs, 4); - } - } - // slap on a grid - byte[] gridColor = BitConverter.GetBytes(0x17000000); - for (int i = 0; i < width * height; i++) - { - if (i % itemsize == 0 || i / (itemsize * itemsPerRow) % itemsize == 0) - { - var ofs = (i / (itemsize * itemsPerRow) * width * 4) + (i % (itemsize * itemsPerRow) * 4); - Buffer.BlockCopy(gridColor, 0, bmpData, ofs, 4); - } - } - - return bmpData; + var rv = rnd.Next(100); + Data[i] = GetEffectiveness(rv); } } -} + + private static byte GetEffectiveness(int rv) + { + return rv switch + { + < 2 => (byte)TypeEffectiveness.Immune, // 2% + < 19 => (byte)TypeEffectiveness.NotVery, // 17% + < 36 => (byte)TypeEffectiveness.Super, // 17% + _ => (byte)TypeEffectiveness.Normal, + }; + } + + private static readonly uint[] Colors = + { + 0xFF000000, + 0, // unused + 0xFFFF0000, + 0, // unused + 0xFFFFFFFF, + 0, 0, 0, // unused + 0xFF008000, + }; + + public static byte[] GetTypeChartImageData(int itemsize, int itemsPerRow, byte[] vals, out int width, out int height) + { + width = itemsize * itemsPerRow; + height = itemsize * vals.Length / itemsPerRow; + var bmpData = new byte[4 * width * height]; + + // loop over area + for (int i = 0; i < vals.Length; i++) + { + int X = i % itemsPerRow; + int Y = i / itemsPerRow; + + // Plop into image + byte[] itemColor = BitConverter.GetBytes(Colors[vals[i]]); + for (int x = 0; x < itemsize * itemsize; x++) + { + var ofs = (((Y * itemsize) + (x % itemsize)) * width * 4) + (((X * itemsize) + (x / itemsize)) * 4); + Buffer.BlockCopy(itemColor, 0, bmpData, ofs, 4); + } + } + // slap on a grid + byte[] gridColor = BitConverter.GetBytes(0x17000000); + for (int i = 0; i < width * height; i++) + { + if (i % itemsize == 0 || i / (itemsize * itemsPerRow) % itemsize == 0) + { + var ofs = (i / (itemsize * itemsPerRow) * width * 4) + (i % (itemsize * itemsPerRow) * 4); + Buffer.BlockCopy(gridColor, 0, bmpData, ofs, 4); + } + } + + return bmpData; + } +} \ No newline at end of file diff --git a/pkNX.Game/File/GameFile.cs b/pkNX.Game/File/GameFile.cs index 6a1cbfaa..2138e805 100644 --- a/pkNX.Game/File/GameFile.cs +++ b/pkNX.Game/File/GameFile.cs @@ -1,229 +1,228 @@ -namespace pkNX.Game +namespace pkNX.Game; + +/// +/// Simple descriptor related to what purpose the game data serves. +/// +public enum GameFile { - /// - /// Simple descriptor related to what purpose the game data serves. - /// - public enum GameFile - { - /// Contains the game text that is commonly re-used, not related to the storyline or general overworld content. - GameText, + /// Contains the game text that is commonly re-used, not related to the storyline or general overworld content. + GameText, - /// Localized Game Text for . - GameText0, + /// Localized Game Text for . + GameText0, - /// Localized Game Text for . - GameText1, + /// Localized Game Text for . + GameText1, - /// Localized Game Text for . - GameText2, + /// Localized Game Text for . + GameText2, - /// Localized Game Text for . - GameText3, + /// Localized Game Text for . + GameText3, - /// Localized Game Text for . - GameText4, + /// Localized Game Text for . + GameText4, - /// Localized Game Text for . - GameText5, + /// Localized Game Text for . + GameText5, - /// Localized Game Text for . - GameText6, + /// Localized Game Text for . + GameText6, - /// Localized Game Text for . - GameText7, + /// Localized Game Text for . + GameText7, - /// Localized Game Text for . - GameText8, + /// Localized Game Text for . + GameText8, - /// Localized Game Text for . - GameText9, + /// Localized Game Text for . + GameText9, - /// Contains the story text that is used to tell the story via overworld events and interactions. - StoryText, + /// Contains the story text that is used to tell the story via overworld events and interactions. + StoryText, - /// Localized Story Text for . - StoryText0, + /// Localized Story Text for . + StoryText0, - /// Localized Story Text for . - StoryText1, + /// Localized Story Text for . + StoryText1, - /// Localized Story Text for . - StoryText2, + /// Localized Story Text for . + StoryText2, - /// Localized Story Text for . - StoryText3, + /// Localized Story Text for . + StoryText3, - /// Localized Story Text for . - StoryText4, + /// Localized Story Text for . + StoryText4, - /// Localized Story Text for . - StoryText5, + /// Localized Story Text for . + StoryText5, - /// Localized Story Text for . - StoryText6, + /// Localized Story Text for . + StoryText6, - /// Localized Story Text for . - StoryText7, + /// Localized Story Text for . + StoryText7, - /// Localized Story Text for . - StoryText8, + /// Localized Story Text for . + StoryText8, - /// Localized Story Text for . - StoryText9, + /// Localized Story Text for . + StoryText9, - /// Overworld grass/etc encounterable species data. - Encounters, + /// Overworld grass/etc encounterable species data. + Encounters, - /// Trainer Data related to Trainers of a shared type. - TrainerClass, + /// Trainer Data related to Trainers of a shared type. + TrainerClass, - /// Trainer Data for individual Trainers that can be battled. - TrainerData, + /// Trainer Data for individual Trainers that can be battled. + TrainerData, - /// Trainer PKM template data for regular battles. - TrainerPoke, + /// Trainer PKM template data for regular battles. + TrainerPoke, - /// Move data that defines the properties of in-game moves. - MoveStats, + /// Move data that defines the properties of in-game moves. + MoveStats, - /// Egg Moves a species can learn when bred. - EggMoves, + /// Egg Moves a species can learn when bred. + EggMoves, - /// Moves a species can learn via level up. - Learnsets, + /// Moves a species can learn via level up. + Learnsets, - /// Evolutions a species can have under specified conditions. - Evolutions, + /// Evolutions a species can have under specified conditions. + Evolutions, - /// Mega Evolutions a species can have under specified conditions. - MegaEvolutions, + /// Mega Evolutions a species can have under specified conditions. + MegaEvolutions, - /// In-game stats a species can have. - PersonalStats, + /// In-game stats a species can have. + PersonalStats, - /// Properties of in-game posessible items. - ItemStats, + /// Properties of in-game posessible items. + ItemStats, - /// Static (fixed position/condition) encounter table. - EncounterStatic, + /// Static (fixed position/condition) encounter table. + EncounterStatic, - /// Post-game roulette trainer data with normal difficulty. - FacilityTrainerNormal, + /// Post-game roulette trainer data with normal difficulty. + FacilityTrainerNormal, - /// Post-game roulette trainer data with heightened difficulty. - FacilityTrainerSuper, + /// Post-game roulette trainer data with heightened difficulty. + FacilityTrainerSuper, - /// Post-game roulette PKM template data for normal difficulty trainers. - FacilityPokeNormal, + /// Post-game roulette PKM template data for normal difficulty trainers. + FacilityPokeNormal, - /// Post-game roulette PKM template data for heightened difficulty trainers. - FacilityPokeSuper, + /// Post-game roulette PKM template data for heightened difficulty trainers. + FacilityPokeSuper, - /// Title Screen staging data. - TitleScreen, + /// Title Screen staging data. + TitleScreen, - /// Box Interface wallpapers. - Wallpaper, + /// Box Interface wallpapers. + Wallpaper, - /// Walk/Collision data for individual Maps. - MapMatrix, + /// Walk/Collision data for individual Maps. + MapMatrix, - /// Zone assembling information to build large maps from individual small zones. - MapGameRegion, + /// Zone assembling information to build large maps from individual small zones. + MapGameRegion, - /// Area settings and permissives related to in-game areas the player travels to. - ZoneData, + /// Area settings and permissives related to in-game areas the player travels to. + ZoneData, - /// Post-battle items that can be picked up. - BattleDrops, + /// Post-battle items that can be picked up. + BattleDrops, - /// Items that can be dropped by pokemon in the field. - FieldDrops, + /// Items that can be dropped by pokemon in the field. + FieldDrops, - /// Map data for individual zones. - WorldData, + /// Map data for individual zones. + WorldData, - /// UI Sprites for pretty in-game move descriptors. - MoveSprites, + /// UI Sprites for pretty in-game move descriptors. + MoveSprites, - /// Traded Pokémon swap data. - EncounterTrade, + /// Traded Pokémon swap data. + EncounterTrade, - /// Gift Pokémon data. - EncounterGift, + /// Gift Pokémon data. + EncounterGift, - /// Nest Data - NestData, + /// Nest Data + NestData, - /// Wild Data - WildData, + /// Wild Data + WildData, - /// Wild Data - WildData1, + /// Wild Data + WildData1, - /// Wild Data - WildData2, + /// Wild Data + WildData2, - /// Dynamax Adventure Dens - DynamaxDens, + /// Dynamax Adventure Dens + DynamaxDens, - /// Area Placement Archive - Placement, + /// Area Placement Archive + Placement, - /// Shop Inventory Lists - Shops, + /// Shop Inventory Lists + Shops, - /// Rental Team Pokémon - Rentals, + /// Rental Team Pokémon + Rentals, - /// Symbol Behavior Definition - SymbolBehave, + /// Symbol Behavior Definition + SymbolBehave, - /// Area Resident Archive - Resident, + /// Area Resident Archive + Resident, - /// "PokeEncount" Rate Multipler Archive - EncounterRateTable, + /// "PokeEncount" Rate Multipler Archive + EncounterRateTable, - /// huge_outbreak.bin - Outbreak, + /// huge_outbreak.bin + Outbreak, - /// wazashop_table.bin - MoveShop, + /// wazashop_table.bin + MoveShop, - /// "PokeMisc" Details about a given Species-Form not stored in - PokeMisc, + /// "PokeMisc" Details about a given Species-Form not stored in + PokeMisc, - /// All pokedex research tasks - DexResearch, + /// All pokedex research tasks + DexResearch, - ThrowableParam, - ThrowParam, - ThrowableResourceSet, - ThrowableResource, - ThrowPermissionSet, + ThrowableParam, + ThrowParam, + ThrowableResourceSet, + ThrowableResource, + ThrowPermissionSet, - /// Gives bonus rolls based on met thresholds. - ShinyRolls, - WormholeConfig, - CaptureConfig, - BattleLogicConfig, - PlayerConfig, - EventFarmConfig, - FieldLandmarkConfig, - BattleViewConfig, - AICommonConfig, - FieldSpawnerConfig, - OutbreakConfig, - EvolutionConfig, - BallThrowConfig, - SizeScaleConfig, + /// Gives bonus rolls based on met thresholds. + ShinyRolls, + WormholeConfig, + CaptureConfig, + BattleLogicConfig, + PlayerConfig, + EventFarmConfig, + FieldLandmarkConfig, + BattleViewConfig, + AICommonConfig, + FieldSpawnerConfig, + OutbreakConfig, + EvolutionConfig, + BallThrowConfig, + SizeScaleConfig, - AppConfigList, - HaShop, - NewHugeGroup, - NewHugeGroupLottery, - NewHugeLottery, - NewHugeTimeLimit, - } -} + AppConfigList, + HaShop, + NewHugeGroup, + NewHugeGroupLottery, + NewHugeLottery, + NewHugeTimeLimit, +} \ No newline at end of file diff --git a/pkNX.Game/File/GameFileMapping.cs b/pkNX.Game/File/GameFileMapping.cs index cf71a5db..8d63b99c 100644 --- a/pkNX.Game/File/GameFileMapping.cs +++ b/pkNX.Game/File/GameFileMapping.cs @@ -5,267 +5,266 @@ using pkNX.Containers; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +/// +/// Handles file retrieval and lifetime management for a 's data. +/// +public class GameFileMapping { - /// - /// Handles file retrieval and lifetime management for a 's data. - /// - public class GameFileMapping + private readonly Dictionary Cache = new(); + private readonly IReadOnlyCollection FileMap; + + public readonly ContainerHandler ProgressTracker = new(); + public readonly CancellationTokenSource TokenSource = new(); + + private readonly GameLocation ROM; + public GameFileMapping(GameLocation rom) => FileMap = GetMapping((ROM = rom).Game); + + internal IFileContainer GetFile(GameFile file, int language) { - private readonly Dictionary Cache = new(); - private readonly IReadOnlyCollection FileMap; + if (file is GameFile.GameText or GameFile.StoryText) + file += language + 1; // shift to localized language - public readonly ContainerHandler ProgressTracker = new(); - public readonly CancellationTokenSource TokenSource = new(); - - private readonly GameLocation ROM; - public GameFileMapping(GameLocation rom) => FileMap = GetMapping((ROM = rom).Game); - - internal IFileContainer GetFile(GameFile file, int language) - { - if (file is GameFile.GameText or GameFile.StoryText) - file += language + 1; // shift to localized language - - if (Cache.TryGetValue(file, out var container)) - return container; - - var info = FileMap.FirstOrDefault(f => f.File == file); - if (info == null) - throw new ArgumentException($"Unknown {nameof(GameFile)} provided.", file.ToString()); - - var basePath = info.Parent == ContainerParent.ExeFS ? ROM.ExeFS : ROM.RomFS; - container = info.Get(basePath); - Cache.Add(file, container); + if (Cache.TryGetValue(file, out var container)) return container; - } - internal void SaveAll() - { - foreach (var container in Cache) - { - var c = container.Value; - if (c.Modified) - c.SaveAs(c.FilePath, ProgressTracker, TokenSource.Token).RunSynchronously(); - } - var modified = Cache.Where(z => z.Value.Modified).ToArray(); - foreach (var m in modified) - Cache.Remove(m.Key); - } + var info = FileMap.FirstOrDefault(f => f.File == file); + if (info == null) + throw new ArgumentException($"Unknown {nameof(GameFile)} provided.", file.ToString()); - public static IReadOnlyCollection GetMapping(GameVersion game) => game switch - { - GameVersion.GP => GG, - GameVersion.GE => GG, - GameVersion.GG => GG, - GameVersion.SW => SWSH, - GameVersion.SH => SWSH, - GameVersion.SWSH => SWSH, - GameVersion.PLA => PLA, - _ => null, - }; - - #region Gen7 - - /// - /// Let's Go Pikachu & Let's Go Eevee - /// - private static readonly GameFileReference[] GG = - { - new(GameFile.TrainerData, "bin", "trainer", "trainer_data"), - new(GameFile.TrainerPoke, "bin", "trainer", "trainer_poke"), - new(GameFile.TrainerClass, "bin", "trainer", "trainer_type"), - - new(GameFile.GameText0, 0, "bin", "message", "JPN", "common"), - new(GameFile.GameText1, 1, "bin", "message", "JPN_KANJI", "common"), - new(GameFile.GameText2, 2, "bin", "message", "English", "common"), - new(GameFile.GameText3, 3, "bin", "message", "French", "common"), - new(GameFile.GameText4, 4, "bin", "message", "Italian", "common"), - new(GameFile.GameText5, 5, "bin", "message", "German", "common"), - // 6 unused lang - new(GameFile.GameText6, 7, "bin", "message", "Spanish", "common"), - new(GameFile.GameText7, 8, "bin", "message", "Korean", "common"), - new(GameFile.GameText8, 9, "bin", "message", "Simp_Chinese", "common"), - new(GameFile.GameText9, 10, "bin", "message", "Trad_Chinese", "common"), - - new(GameFile.StoryText0, 0, "bin", "message", "JPN", "script"), - new(GameFile.StoryText1, 1, "bin", "message", "JPN_KANJI", "script"), - new(GameFile.StoryText2, 2, "bin", "message", "English", "script"), - new(GameFile.StoryText3, 3, "bin", "message", "French", "script"), - new(GameFile.StoryText4, 4, "bin", "message", "Italian", "script"), - new(GameFile.StoryText5, 5, "bin", "message", "German", "script"), - // 6 unused lang - new(GameFile.StoryText6, 7, "bin", "message", "Spanish", "script"), - new(GameFile.StoryText7, 8, "bin", "message", "Korean", "script"), - new(GameFile.StoryText8, 9, "bin", "message", "Simp_Chinese", "script"), - new(GameFile.StoryText9, 10, "bin", "message", "Trad_Chinese", "script"), - - new(GameFile.ItemStats, "bin", "pokelib", "item"), - new(GameFile.Evolutions, "bin", "pokelib", "evolution"), - new(GameFile.PersonalStats, "bin", "pokelib", "personal"), - new(GameFile.MegaEvolutions, "bin", "pokelib", "mega_evolution"), - new(GameFile.MoveStats, ContainerType.Mini, "bin", "pokelib", "waza", "waza_data.bin"), - new(GameFile.EncounterStatic, ContainerType.SingleFile, "bin", "script_event_data", "event_encount.bin"), - new(GameFile.EncounterTrade, ContainerType.SingleFile, "bin", "script_event_data", "field_trade_data.bin"), - new(GameFile.EncounterGift, ContainerType.SingleFile, "bin", "script_event_data", "add_poke.bin"), - new(GameFile.Learnsets, ContainerType.GFPack, "bin", "archive", "waza_oboe.gfpak"), - - new(GameFile.WildData1, ContainerType.SingleFile, "bin", "field", "param", "encount", "encount_data_p.bin"), - new(GameFile.WildData2, ContainerType.SingleFile, "bin", "field", "param", "encount", "encount_data_e.bin"), - new(GameFile.Shops, ContainerType.SingleFile, "bin", "app", "shop", "shop_data.bin"), - - // Cutscenes bin\demo - // Models bin\archive\pokemon - // pretty much everything is obviously named :) - #endregion - }; - - #region Gen 8 - /// - /// Sword - /// - private static readonly GameFileReference[] SWSH = - { - new(GameFile.TrainerData, "bin", "trainer", "trainer_data"), - new(GameFile.TrainerPoke, "bin", "trainer", "trainer_poke"), - new(GameFile.TrainerClass, "bin", "trainer", "trainer_type"), - - new(GameFile.GameText0, 0, "bin", "message", "JPN", "common"), - new(GameFile.GameText1, 1, "bin", "message", "JPN_KANJI", "common"), - new(GameFile.GameText2, 2, "bin", "message", "English", "common"), - new(GameFile.GameText3, 3, "bin", "message", "French", "common"), - new(GameFile.GameText4, 4, "bin", "message", "Italian", "common"), - new(GameFile.GameText5, 5, "bin", "message", "German", "common"), - // 6 unused lang - new(GameFile.GameText6, 7, "bin", "message", "Spanish", "common"), - new(GameFile.GameText7, 8, "bin", "message", "Korean", "common"), - new(GameFile.GameText8, 9, "bin", "message", "Simp_Chinese", "common"), - new(GameFile.GameText9, 10, "bin", "message", "Trad_Chinese", "common"), - - new(GameFile.StoryText0, 0, "bin", "message", "JPN", "script"), - new(GameFile.StoryText1, 1, "bin", "message", "JPN_KANJI", "script"), - new(GameFile.StoryText2, 2, "bin", "message", "English", "script"), - new(GameFile.StoryText3, 3, "bin", "message", "French", "script"), - new(GameFile.StoryText4, 4, "bin", "message", "Italian", "script"), - new(GameFile.StoryText5, 5, "bin", "message", "German", "script"), - // 6 unused lang - new(GameFile.StoryText6, 7, "bin", "message", "Spanish", "script"), - new(GameFile.StoryText7, 8, "bin", "message", "Korean", "script"), - new(GameFile.StoryText8, 9, "bin", "message", "Simp_Chinese", "script"), - new(GameFile.StoryText9, 10, "bin", "message", "Trad_Chinese", "script"), - - new(GameFile.ItemStats, ContainerType.SingleFile, "bin", "pml", "item", "item.dat"), - new(GameFile.Evolutions, "bin", "pml", "evolution"), - new(GameFile.EggMoves, "bin", "pml", "tamagowaza"), - new(GameFile.PersonalStats, "bin", "pml", "personal"), - new(GameFile.MoveStats, "bin", "pml", "waza"), - new(GameFile.EncounterStatic, ContainerType.SingleFile, "bin", "script_event_data", "event_encount_data.bin"), - new(GameFile.EncounterTrade, ContainerType.SingleFile, "bin", "script_event_data", "field_trade.bin"), - new(GameFile.EncounterGift, ContainerType.SingleFile, "bin", "script_event_data", "add_poke.bin"), - new(GameFile.Learnsets, ContainerType.SingleFile, "bin", "pml", "waza_oboe", "wazaoboe_total.bin"), - - new(GameFile.FacilityPokeNormal, ContainerType.SingleFile, "bin", "field", "param", "battle_tower", "battle_tower_poke_table.bin"), - new(GameFile.FacilityTrainerNormal, ContainerType.SingleFile, "bin", "field", "param", "battle_tower", "battle_tower_trainer_table.bin"), - - new(GameFile.WildData, ContainerType.SingleFile, "bin", "archive", "field", "resident", "data_table.gfpak"), - new(GameFile.NestData, ContainerType.SingleFile, "bin", "archive", "field", "resident", "data_table.gfpak"), - - new(GameFile.DynamaxDens, ContainerType.SingleFile, "bin", "appli", "chika", "data_table", "underground_exploration_poke.bin"), - - new(GameFile.Placement, ContainerType.SingleFile, "bin", "archive", "field", "resident", "placement.gfpak"), - new(GameFile.Shops, ContainerType.SingleFile, "bin", "appli", "shop", "bin", "shop_data.bin"), - new(GameFile.Rentals, ContainerType.SingleFile, "bin", "script_event_data", "rental.bin"), - new(GameFile.SymbolBehave, ContainerType.SingleFile, "bin", "field", "param", "symbol_encount_mons_param", "symbol_encount_mons_param.bin") - - // Cutscenes bin\demo - // Models bin\archive\pokemon - // pretty much everything is obviously named :) - }; - - /// - /// Sword - /// - private static readonly GameFileReference[] PLA = - { - new(GameFile.TrainerData, "bin", "trainer"), - - new(GameFile.GameText0, 0, "bin", "message", "JPN", "common"), - new(GameFile.GameText1, 1, "bin", "message", "JPN_KANJI", "common"), - new(GameFile.GameText2, 2, "bin", "message", "English", "common"), - new(GameFile.GameText3, 3, "bin", "message", "French", "common"), - new(GameFile.GameText4, 4, "bin", "message", "Italian", "common"), - new(GameFile.GameText5, 5, "bin", "message", "German", "common"), - // 6 unused lang - new(GameFile.GameText6, 7, "bin", "message", "Spanish", "common"), - new(GameFile.GameText7, 8, "bin", "message", "Korean", "common"), - new(GameFile.GameText8, 9, "bin", "message", "Simp_Chinese", "common"), - new(GameFile.GameText9, 10, "bin", "message", "Trad_Chinese", "common"), - - new(GameFile.StoryText0, 0, "bin", "message", "JPN", "script"), - new(GameFile.StoryText1, 1, "bin", "message", "JPN_KANJI", "script"), - new(GameFile.StoryText2, 2, "bin", "message", "English", "script"), - new(GameFile.StoryText3, 3, "bin", "message", "French", "script"), - new(GameFile.StoryText4, 4, "bin", "message", "Italian", "script"), - new(GameFile.StoryText5, 5, "bin", "message", "German", "script"), - // 6 unused lang - new(GameFile.StoryText6, 7, "bin", "message", "Spanish", "script"), - new(GameFile.StoryText7, 8, "bin", "message", "Korean", "script"), - new(GameFile.StoryText8, 9, "bin", "message", "Simp_Chinese", "script"), - new(GameFile.StoryText9, 10, "bin", "message", "Trad_Chinese", "script"), - - new(GameFile.ItemStats, ContainerType.SingleFile, "bin", "pml", "item", "item.dat"), - new(GameFile.Evolutions, ContainerType.SingleFile, "bin", "pml", "evolution", "evolution_data_total.evobin"), - new(GameFile.PersonalStats, ContainerType.SingleFile, "bin", "pml", "personal", "personal_data_total.perbin"), - new(GameFile.MoveStats, "bin", "pml", "waza"), - new(GameFile.EncounterStatic, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_event_encount.bin"), - new(GameFile.EncounterTrade, ContainerType.SingleFile, "bin", "script_event_data", "field_trade.bin"), - new(GameFile.EncounterGift, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_add.bin"), - new(GameFile.Learnsets, ContainerType.SingleFile, "bin", "pml", "waza_oboe", "waza_oboe_total.wazaoboe"), - - new(GameFile.Resident, ContainerType.GFPack, "bin", "archive", "field", "resident_release.gfpak"), - - new(GameFile.FieldDrops, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_drop_item.bin"), - new(GameFile.BattleDrops, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_drop_item_battle.bin"), - - new(GameFile.DexResearch, ContainerType.SingleFile, "bin", "appli", "pokedex", "res_table", "pokedex_research_task_table.bin"), - - new(GameFile.EncounterRateTable, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_encount.bin"), - new(GameFile.PokeMisc, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_misc.bin"), - new(GameFile.Outbreak, ContainerType.SingleFile, "bin", "field", "encount", "huge_outbreak.bin"), - new(GameFile.MoveShop, ContainerType.SingleFile, "bin", "appli", "wazaremember", "bin", "wazashop_table.bin"), - - new(GameFile.ThrowableParam, ContainerType.SingleFile, "bin", "capture", "throwable_param_table.bin"), - new(GameFile.ThrowParam, ContainerType.SingleFile, "bin", "capture", "throw_param_table.bin"), - new(GameFile.ThrowableResourceSet, ContainerType.SingleFile, "bin", "capture", "throwable_resourceset_dictionary.bin"), - new(GameFile.ThrowableResource, ContainerType.SingleFile, "bin", "capture", "throwable_resource_dictionary.bin"), - new(GameFile.ThrowPermissionSet, ContainerType.SingleFile, "bin", "capture", "throw_permissionset_dictionary.bin"), - new(GameFile.HaShop, ContainerType.SingleFile, "bin", "appli", "shop", "bin", "ha_shop_data.bin"), - - new(GameFile.ShinyRolls, ContainerType.SingleFile, "bin", "misc", "app_config", "pokemon_rare.bin"), - new(GameFile.WormholeConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_wormhole_config.bin"), - new(GameFile.CaptureConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "common_capture_config.bin"), - new(GameFile.BattleLogicConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "battle_logic_config.bin"), - new(GameFile.PlayerConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "player_config.bin"), - new(GameFile.EventFarmConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "event_farm_config.bin"), - new(GameFile.AppConfigList, ContainerType.SingleFile, "bin", "misc", "app_config", "app_config_list.bin"), - new(GameFile.FieldLandmarkConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_landmark_config.bin"), - new(GameFile.BattleViewConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "battle_view_config.bin"), - new(GameFile.AICommonConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "ai_common_config.bin"), - new(GameFile.FieldSpawnerConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_spawner_config.bin"), - new(GameFile.OutbreakConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_huge_outbreak.bin"), - new(GameFile.EvolutionConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "pokemon_evolution_config.bin"), - new(GameFile.BallThrowConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_my_poke_ball_config.bin"), - new(GameFile.SizeScaleConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "pokemon_size_category_adjust_scale_config.bin"), - new(GameFile.SymbolBehave, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_ai.bin"), - - new(GameFile.NewHugeGroup, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_group.bin"), - new(GameFile.NewHugeGroupLottery, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_group_lottery.bin"), - new(GameFile.NewHugeLottery, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_lottery.bin"), - new(GameFile.NewHugeTimeLimit, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_time_limit.bin"), - - // Cutscenes bin\demo - // Models bin\archive\pokemon - // pretty much everything is obviously named :) - }; - #endregion + var basePath = info.Parent == ContainerParent.ExeFS ? ROM.ExeFS : ROM.RomFS; + container = info.Get(basePath); + Cache.Add(file, container); + return container; } -} + + internal void SaveAll() + { + foreach (var container in Cache) + { + var c = container.Value; + if (c.Modified) + c.SaveAs(c.FilePath, ProgressTracker, TokenSource.Token).RunSynchronously(); + } + var modified = Cache.Where(z => z.Value.Modified).ToArray(); + foreach (var m in modified) + Cache.Remove(m.Key); + } + + public static IReadOnlyCollection GetMapping(GameVersion game) => game switch + { + GameVersion.GP => GG, + GameVersion.GE => GG, + GameVersion.GG => GG, + GameVersion.SW => SWSH, + GameVersion.SH => SWSH, + GameVersion.SWSH => SWSH, + GameVersion.PLA => PLA, + _ => null, + }; + + #region Gen7 + + /// + /// Let's Go Pikachu & Let's Go Eevee + /// + private static readonly GameFileReference[] GG = + { + new(GameFile.TrainerData, "bin", "trainer", "trainer_data"), + new(GameFile.TrainerPoke, "bin", "trainer", "trainer_poke"), + new(GameFile.TrainerClass, "bin", "trainer", "trainer_type"), + + new(GameFile.GameText0, 0, "bin", "message", "JPN", "common"), + new(GameFile.GameText1, 1, "bin", "message", "JPN_KANJI", "common"), + new(GameFile.GameText2, 2, "bin", "message", "English", "common"), + new(GameFile.GameText3, 3, "bin", "message", "French", "common"), + new(GameFile.GameText4, 4, "bin", "message", "Italian", "common"), + new(GameFile.GameText5, 5, "bin", "message", "German", "common"), + // 6 unused lang + new(GameFile.GameText6, 7, "bin", "message", "Spanish", "common"), + new(GameFile.GameText7, 8, "bin", "message", "Korean", "common"), + new(GameFile.GameText8, 9, "bin", "message", "Simp_Chinese", "common"), + new(GameFile.GameText9, 10, "bin", "message", "Trad_Chinese", "common"), + + new(GameFile.StoryText0, 0, "bin", "message", "JPN", "script"), + new(GameFile.StoryText1, 1, "bin", "message", "JPN_KANJI", "script"), + new(GameFile.StoryText2, 2, "bin", "message", "English", "script"), + new(GameFile.StoryText3, 3, "bin", "message", "French", "script"), + new(GameFile.StoryText4, 4, "bin", "message", "Italian", "script"), + new(GameFile.StoryText5, 5, "bin", "message", "German", "script"), + // 6 unused lang + new(GameFile.StoryText6, 7, "bin", "message", "Spanish", "script"), + new(GameFile.StoryText7, 8, "bin", "message", "Korean", "script"), + new(GameFile.StoryText8, 9, "bin", "message", "Simp_Chinese", "script"), + new(GameFile.StoryText9, 10, "bin", "message", "Trad_Chinese", "script"), + + new(GameFile.ItemStats, "bin", "pokelib", "item"), + new(GameFile.Evolutions, "bin", "pokelib", "evolution"), + new(GameFile.PersonalStats, "bin", "pokelib", "personal"), + new(GameFile.MegaEvolutions, "bin", "pokelib", "mega_evolution"), + new(GameFile.MoveStats, ContainerType.Mini, "bin", "pokelib", "waza", "waza_data.bin"), + new(GameFile.EncounterStatic, ContainerType.SingleFile, "bin", "script_event_data", "event_encount.bin"), + new(GameFile.EncounterTrade, ContainerType.SingleFile, "bin", "script_event_data", "field_trade_data.bin"), + new(GameFile.EncounterGift, ContainerType.SingleFile, "bin", "script_event_data", "add_poke.bin"), + new(GameFile.Learnsets, ContainerType.GFPack, "bin", "archive", "waza_oboe.gfpak"), + + new(GameFile.WildData1, ContainerType.SingleFile, "bin", "field", "param", "encount", "encount_data_p.bin"), + new(GameFile.WildData2, ContainerType.SingleFile, "bin", "field", "param", "encount", "encount_data_e.bin"), + new(GameFile.Shops, ContainerType.SingleFile, "bin", "app", "shop", "shop_data.bin"), + + // Cutscenes bin\demo + // Models bin\archive\pokemon + // pretty much everything is obviously named :) + #endregion + }; + + #region Gen 8 + /// + /// Sword + /// + private static readonly GameFileReference[] SWSH = + { + new(GameFile.TrainerData, "bin", "trainer", "trainer_data"), + new(GameFile.TrainerPoke, "bin", "trainer", "trainer_poke"), + new(GameFile.TrainerClass, "bin", "trainer", "trainer_type"), + + new(GameFile.GameText0, 0, "bin", "message", "JPN", "common"), + new(GameFile.GameText1, 1, "bin", "message", "JPN_KANJI", "common"), + new(GameFile.GameText2, 2, "bin", "message", "English", "common"), + new(GameFile.GameText3, 3, "bin", "message", "French", "common"), + new(GameFile.GameText4, 4, "bin", "message", "Italian", "common"), + new(GameFile.GameText5, 5, "bin", "message", "German", "common"), + // 6 unused lang + new(GameFile.GameText6, 7, "bin", "message", "Spanish", "common"), + new(GameFile.GameText7, 8, "bin", "message", "Korean", "common"), + new(GameFile.GameText8, 9, "bin", "message", "Simp_Chinese", "common"), + new(GameFile.GameText9, 10, "bin", "message", "Trad_Chinese", "common"), + + new(GameFile.StoryText0, 0, "bin", "message", "JPN", "script"), + new(GameFile.StoryText1, 1, "bin", "message", "JPN_KANJI", "script"), + new(GameFile.StoryText2, 2, "bin", "message", "English", "script"), + new(GameFile.StoryText3, 3, "bin", "message", "French", "script"), + new(GameFile.StoryText4, 4, "bin", "message", "Italian", "script"), + new(GameFile.StoryText5, 5, "bin", "message", "German", "script"), + // 6 unused lang + new(GameFile.StoryText6, 7, "bin", "message", "Spanish", "script"), + new(GameFile.StoryText7, 8, "bin", "message", "Korean", "script"), + new(GameFile.StoryText8, 9, "bin", "message", "Simp_Chinese", "script"), + new(GameFile.StoryText9, 10, "bin", "message", "Trad_Chinese", "script"), + + new(GameFile.ItemStats, ContainerType.SingleFile, "bin", "pml", "item", "item.dat"), + new(GameFile.Evolutions, "bin", "pml", "evolution"), + new(GameFile.EggMoves, "bin", "pml", "tamagowaza"), + new(GameFile.PersonalStats, "bin", "pml", "personal"), + new(GameFile.MoveStats, "bin", "pml", "waza"), + new(GameFile.EncounterStatic, ContainerType.SingleFile, "bin", "script_event_data", "event_encount_data.bin"), + new(GameFile.EncounterTrade, ContainerType.SingleFile, "bin", "script_event_data", "field_trade.bin"), + new(GameFile.EncounterGift, ContainerType.SingleFile, "bin", "script_event_data", "add_poke.bin"), + new(GameFile.Learnsets, ContainerType.SingleFile, "bin", "pml", "waza_oboe", "wazaoboe_total.bin"), + + new(GameFile.FacilityPokeNormal, ContainerType.SingleFile, "bin", "field", "param", "battle_tower", "battle_tower_poke_table.bin"), + new(GameFile.FacilityTrainerNormal, ContainerType.SingleFile, "bin", "field", "param", "battle_tower", "battle_tower_trainer_table.bin"), + + new(GameFile.WildData, ContainerType.SingleFile, "bin", "archive", "field", "resident", "data_table.gfpak"), + new(GameFile.NestData, ContainerType.SingleFile, "bin", "archive", "field", "resident", "data_table.gfpak"), + + new(GameFile.DynamaxDens, ContainerType.SingleFile, "bin", "appli", "chika", "data_table", "underground_exploration_poke.bin"), + + new(GameFile.Placement, ContainerType.SingleFile, "bin", "archive", "field", "resident", "placement.gfpak"), + new(GameFile.Shops, ContainerType.SingleFile, "bin", "appli", "shop", "bin", "shop_data.bin"), + new(GameFile.Rentals, ContainerType.SingleFile, "bin", "script_event_data", "rental.bin"), + new(GameFile.SymbolBehave, ContainerType.SingleFile, "bin", "field", "param", "symbol_encount_mons_param", "symbol_encount_mons_param.bin") + + // Cutscenes bin\demo + // Models bin\archive\pokemon + // pretty much everything is obviously named :) + }; + + /// + /// Sword + /// + private static readonly GameFileReference[] PLA = + { + new(GameFile.TrainerData, "bin", "trainer"), + + new(GameFile.GameText0, 0, "bin", "message", "JPN", "common"), + new(GameFile.GameText1, 1, "bin", "message", "JPN_KANJI", "common"), + new(GameFile.GameText2, 2, "bin", "message", "English", "common"), + new(GameFile.GameText3, 3, "bin", "message", "French", "common"), + new(GameFile.GameText4, 4, "bin", "message", "Italian", "common"), + new(GameFile.GameText5, 5, "bin", "message", "German", "common"), + // 6 unused lang + new(GameFile.GameText6, 7, "bin", "message", "Spanish", "common"), + new(GameFile.GameText7, 8, "bin", "message", "Korean", "common"), + new(GameFile.GameText8, 9, "bin", "message", "Simp_Chinese", "common"), + new(GameFile.GameText9, 10, "bin", "message", "Trad_Chinese", "common"), + + new(GameFile.StoryText0, 0, "bin", "message", "JPN", "script"), + new(GameFile.StoryText1, 1, "bin", "message", "JPN_KANJI", "script"), + new(GameFile.StoryText2, 2, "bin", "message", "English", "script"), + new(GameFile.StoryText3, 3, "bin", "message", "French", "script"), + new(GameFile.StoryText4, 4, "bin", "message", "Italian", "script"), + new(GameFile.StoryText5, 5, "bin", "message", "German", "script"), + // 6 unused lang + new(GameFile.StoryText6, 7, "bin", "message", "Spanish", "script"), + new(GameFile.StoryText7, 8, "bin", "message", "Korean", "script"), + new(GameFile.StoryText8, 9, "bin", "message", "Simp_Chinese", "script"), + new(GameFile.StoryText9, 10, "bin", "message", "Trad_Chinese", "script"), + + new(GameFile.ItemStats, ContainerType.SingleFile, "bin", "pml", "item", "item.dat"), + new(GameFile.Evolutions, ContainerType.SingleFile, "bin", "pml", "evolution", "evolution_data_total.evobin"), + new(GameFile.PersonalStats, ContainerType.SingleFile, "bin", "pml", "personal", "personal_data_total.perbin"), + new(GameFile.MoveStats, "bin", "pml", "waza"), + new(GameFile.EncounterStatic, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_event_encount.bin"), + new(GameFile.EncounterTrade, ContainerType.SingleFile, "bin", "script_event_data", "field_trade.bin"), + new(GameFile.EncounterGift, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_add.bin"), + new(GameFile.Learnsets, ContainerType.SingleFile, "bin", "pml", "waza_oboe", "waza_oboe_total.wazaoboe"), + + new(GameFile.Resident, ContainerType.GFPack, "bin", "archive", "field", "resident_release.gfpak"), + + new(GameFile.FieldDrops, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_drop_item.bin"), + new(GameFile.BattleDrops, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_drop_item_battle.bin"), + + new(GameFile.DexResearch, ContainerType.SingleFile, "bin", "appli", "pokedex", "res_table", "pokedex_research_task_table.bin"), + + new(GameFile.EncounterRateTable, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_encount.bin"), + new(GameFile.PokeMisc, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_misc.bin"), + new(GameFile.Outbreak, ContainerType.SingleFile, "bin", "field", "encount", "huge_outbreak.bin"), + new(GameFile.MoveShop, ContainerType.SingleFile, "bin", "appli", "wazaremember", "bin", "wazashop_table.bin"), + + new(GameFile.ThrowableParam, ContainerType.SingleFile, "bin", "capture", "throwable_param_table.bin"), + new(GameFile.ThrowParam, ContainerType.SingleFile, "bin", "capture", "throw_param_table.bin"), + new(GameFile.ThrowableResourceSet, ContainerType.SingleFile, "bin", "capture", "throwable_resourceset_dictionary.bin"), + new(GameFile.ThrowableResource, ContainerType.SingleFile, "bin", "capture", "throwable_resource_dictionary.bin"), + new(GameFile.ThrowPermissionSet, ContainerType.SingleFile, "bin", "capture", "throw_permissionset_dictionary.bin"), + new(GameFile.HaShop, ContainerType.SingleFile, "bin", "appli", "shop", "bin", "ha_shop_data.bin"), + + new(GameFile.ShinyRolls, ContainerType.SingleFile, "bin", "misc", "app_config", "pokemon_rare.bin"), + new(GameFile.WormholeConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_wormhole_config.bin"), + new(GameFile.CaptureConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "common_capture_config.bin"), + new(GameFile.BattleLogicConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "battle_logic_config.bin"), + new(GameFile.PlayerConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "player_config.bin"), + new(GameFile.EventFarmConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "event_farm_config.bin"), + new(GameFile.AppConfigList, ContainerType.SingleFile, "bin", "misc", "app_config", "app_config_list.bin"), + new(GameFile.FieldLandmarkConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_landmark_config.bin"), + new(GameFile.BattleViewConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "battle_view_config.bin"), + new(GameFile.AICommonConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "ai_common_config.bin"), + new(GameFile.FieldSpawnerConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_spawner_config.bin"), + new(GameFile.OutbreakConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_huge_outbreak.bin"), + new(GameFile.EvolutionConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "pokemon_evolution_config.bin"), + new(GameFile.BallThrowConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "field_my_poke_ball_config.bin"), + new(GameFile.SizeScaleConfig, ContainerType.SingleFile, "bin", "misc", "app_config", "pokemon_size_category_adjust_scale_config.bin"), + new(GameFile.SymbolBehave, ContainerType.SingleFile, "bin", "pokemon", "data", "poke_ai.bin"), + + new(GameFile.NewHugeGroup, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_group.bin"), + new(GameFile.NewHugeGroupLottery, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_group_lottery.bin"), + new(GameFile.NewHugeLottery, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_lottery.bin"), + new(GameFile.NewHugeTimeLimit, ContainerType.SingleFile, "bin", "field", "encount", "new_huge_outbreak_time_limit.bin"), + + // Cutscenes bin\demo + // Models bin\archive\pokemon + // pretty much everything is obviously named :) + }; + #endregion +} \ No newline at end of file diff --git a/pkNX.Game/File/GameFileReference.cs b/pkNX.Game/File/GameFileReference.cs index ac0f6a50..5cc998cd 100644 --- a/pkNX.Game/File/GameFileReference.cs +++ b/pkNX.Game/File/GameFileReference.cs @@ -1,92 +1,91 @@ using System.IO; using pkNX.Containers; -namespace pkNX.Game +namespace pkNX.Game; + +/// +/// File reference pointing to the location of the data. +/// +public class GameFileReference { /// - /// File reference pointing to the location of the data. + /// Type of data the file contains. /// - public class GameFileReference + public GameFile File { get; } + + /// + /// Location of the file in the user's environment. + /// + public string RelativePath { get; } + + /// + /// Type of container the data is within. + /// + public ContainerType Type { get; } + + /// + /// Toggle to indicate that the data is localized and should be shifted. + /// + public bool LanguageVariant { get; } + + public int Language { get; } + + /// + /// Indicates the parent of the data. + /// + public ContainerParent Parent { get; set; } + + internal GameFileReference(int FileNumber, GameFile ident, ContainerType t = ContainerType.GARC) { - /// - /// Type of data the file contains. - /// - public GameFile File { get; } + File = ident; + Type = t; - /// - /// Location of the file in the user's environment. - /// - public string RelativePath { get; } + int A = FileNumber / 100 % 10; + int B = FileNumber / 10 % 10; + int C = FileNumber / 1 % 10; + RelativePath = Path.Combine("a", A.ToString(), B.ToString(), C.ToString()); + } - /// - /// Type of container the data is within. - /// - public ContainerType Type { get; } + internal GameFileReference(string relPath, ContainerType t, GameFile ident, bool variant = false) + { + File = ident; + Type = t; + LanguageVariant = variant; - /// - /// Toggle to indicate that the data is localized and should be shifted. - /// - public bool LanguageVariant { get; } + RelativePath = relPath; + } - public int Language { get; } + internal GameFileReference(GameFile ident, int lang, params string[] relPath) + { + File = ident; + Type = ContainerType.Folder; + LanguageVariant = true; + Language = lang; - /// - /// Indicates the parent of the data. - /// - public ContainerParent Parent { get; set; } + RelativePath = Path.Combine(relPath); + } - internal GameFileReference(int FileNumber, GameFile ident, ContainerType t = ContainerType.GARC) - { - File = ident; - Type = t; + internal GameFileReference(GameFile ident, params string[] relPath) + { + File = ident; + Type = ContainerType.Folder; - int A = FileNumber / 100 % 10; - int B = FileNumber / 10 % 10; - int C = FileNumber / 1 % 10; - RelativePath = Path.Combine("a", A.ToString(), B.ToString(), C.ToString()); - } + RelativePath = Path.Combine(relPath); + } - internal GameFileReference(string relPath, ContainerType t, GameFile ident, bool variant = false) - { - File = ident; - Type = t; - LanguageVariant = variant; + internal GameFileReference(GameFile ident, ContainerType t, params string[] relPath) + { + File = ident; + Type = t; - RelativePath = relPath; - } + RelativePath = Path.Combine(relPath); + } - internal GameFileReference(GameFile ident, int lang, params string[] relPath) - { - File = ident; - Type = ContainerType.Folder; - LanguageVariant = true; - Language = lang; - - RelativePath = Path.Combine(relPath); - } - - internal GameFileReference(GameFile ident, params string[] relPath) - { - File = ident; - Type = ContainerType.Folder; - - RelativePath = Path.Combine(relPath); - } - - internal GameFileReference(GameFile ident, ContainerType t, params string[] relPath) - { - File = ident; - Type = t; - - RelativePath = Path.Combine(relPath); - } - - public IFileContainer Get(string basePath) - { - var path = Path.Combine(basePath, RelativePath); - var container = Container.GetContainer(path, Type); - container.FilePath = path; - return container; - } + public IFileContainer Get(string basePath) + { + var path = Path.Combine(basePath, RelativePath); + var container = Container.GetContainer(path, Type); + container.FilePath = path; + return container; } } \ No newline at end of file diff --git a/pkNX.Game/GameLanguage.cs b/pkNX.Game/GameLanguage.cs index 5cd955be..cc0eea9b 100644 --- a/pkNX.Game/GameLanguage.cs +++ b/pkNX.Game/GameLanguage.cs @@ -1,58 +1,57 @@ -namespace pkNX.Game +namespace pkNX.Game; + +/// +/// Game Language IDs to index consecutive localized files +/// +public enum GameLanguage { /// - /// Game Language IDs to index consecutive localized files + /// Japanese (katakana) /// - public enum GameLanguage - { - /// - /// Japanese (katakana) - /// - カタカナ = 0, + カタカナ = 0, - /// - /// Japanese (hiragana) - /// - 漢字 = 1, + /// + /// Japanese (hiragana) + /// + 漢字 = 1, - /// - /// English - /// - English = 2, + /// + /// English + /// + English = 2, - /// - /// French - /// - Français = 3, + /// + /// French + /// + Français = 3, - /// - /// Italian - /// - Italiano = 4, + /// + /// Italian + /// + Italiano = 4, - /// - /// German - /// - Deutsch = 5, + /// + /// German + /// + Deutsch = 5, - /// - /// Spanish - /// - Español = 6, + /// + /// Spanish + /// + Español = 6, - /// - /// Korean - /// - 한국 = 7, + /// + /// Korean + /// + 한국 = 7, - /// - /// Chinese (Simplified) - /// - 汉字简化方案 = 8, + /// + /// Chinese (Simplified) + /// + 汉字简化方案 = 8, - /// - /// Chinese (Traditional) - /// - 漢字簡化方案 = 9, - } -} + /// + /// Chinese (Traditional) + /// + 漢字簡化方案 = 9, +} \ No newline at end of file diff --git a/pkNX.Game/GameLocation.cs b/pkNX.Game/GameLocation.cs index 0d16c1d3..598558de 100644 --- a/pkNX.Game/GameLocation.cs +++ b/pkNX.Game/GameLocation.cs @@ -2,136 +2,135 @@ using System.IO; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +/// +/// Environment Data where the Game's Data is located on the user's machine. +/// +public sealed class GameLocation { /// - /// Environment Data where the Game's Data is located on the user's machine. + /// Location of the RomFS /// - public sealed class GameLocation + public string RomFS { get; } + + /// + /// Location of the ExeFS. + /// + public string ExeFS { get; } + + /// + /// Game version the files belong to. + /// + public GameVersion Game { get; } + + private GameLocation(string romfs, string exefs, GameVersion game) { - /// - /// Location of the RomFS - /// - public string RomFS { get; } + Game = game; + RomFS = romfs; + ExeFS = exefs; + } - /// - /// Location of the ExeFS. - /// - public string ExeFS { get; } + /// + /// Determines the of the input directory and detects the location of files for editing. + /// + /// Directory the game data is in + /// Detected version + /// New object with references to file paths. + public static GameLocation GetGame(string dir, GameVersion gameOverride = GameVersion.Any) + { + if (dir == null || !Directory.Exists(dir)) + return null; - /// - /// Game version the files belong to. - /// - public GameVersion Game { get; } + var dirs = Directory.GetDirectories(dir); + var romfs = Array.Find(dirs, z => Path.GetFileName(z).StartsWith("rom", StringComparison.CurrentCultureIgnoreCase)); + var exefs = Array.Find(dirs, z => Path.GetFileName(z).StartsWith("exe", StringComparison.CurrentCultureIgnoreCase)); - private GameLocation(string romfs, string exefs, GameVersion game) + if (romfs == null && exefs == null) + return null; + + var game = gameOverride != GameVersion.Any ? gameOverride : GetGameFromPath(romfs, exefs); + if (game == GameVersion.Invalid) + return null; + return new GameLocation(romfs, exefs, game); + } + + private static GameVersion GetGameFromPath(string romfs, string exefs) + { + var files = Directory.GetFiles(romfs, "*", SearchOption.AllDirectories); + return GetGameFromCount(files.Length, romfs, exefs); + } + + private const int FILECOUNT_XY = 271; + private const int FILECOUNT_ORASDEMO = 301; + private const int FILECOUNT_ORAS = 299; + private const int FILECOUNT_SMDEMO = 239; + private const int FILECOUNT_SM = 311; + private const int FILECOUNT_USUM = 333; + private const int FILECOUNT_GG = 27818; + private const int FILECOUNT_SWSH = 41702; + private const int FILECOUNT_SWSH_110 = 41951; // Ver. 1.1.0 (Galarian Slowpoke) + private const int FILECOUNT_SWSH_120 = 46867; // Ver. 1.2.0 (Isle of Armor) + private const int FILECOUNT_SWSH_130 = 50494; // Ver. 1.3.0 (Crown Tundra) + private const int FILECOUNT_LA = 18_370; + private const int FILECOUNT_LA_101 = 18_371; // Ver. 1.0.1 (Day 1 Patch) + private const int FILECOUNT_LA_110 = 19_095; // Ver. 1.1.0 (Daybreak) + + private static GameVersion GetGameFromCount(int fileCount, string romfs, string exefs) + { + string GetTitleID() => BitConverter.ToUInt64(File.ReadAllBytes(Path.Combine(exefs, "main.npdm")), 0x290).ToString("X16"); + + switch (fileCount) { - Game = game; - RomFS = romfs; - ExeFS = exefs; - } - - /// - /// Determines the of the input directory and detects the location of files for editing. - /// - /// Directory the game data is in - /// Detected version - /// New object with references to file paths. - public static GameLocation GetGame(string dir, GameVersion gameOverride = GameVersion.Any) - { - if (dir == null || !Directory.Exists(dir)) - return null; - - var dirs = Directory.GetDirectories(dir); - var romfs = Array.Find(dirs, z => Path.GetFileName(z).StartsWith("rom", StringComparison.CurrentCultureIgnoreCase)); - var exefs = Array.Find(dirs, z => Path.GetFileName(z).StartsWith("exe", StringComparison.CurrentCultureIgnoreCase)); - - if (romfs == null && exefs == null) - return null; - - var game = gameOverride != GameVersion.Any ? gameOverride : GetGameFromPath(romfs, exefs); - if (game == GameVersion.Invalid) - return null; - return new GameLocation(romfs, exefs, game); - } - - private static GameVersion GetGameFromPath(string romfs, string exefs) - { - var files = Directory.GetFiles(romfs, "*", SearchOption.AllDirectories); - return GetGameFromCount(files.Length, romfs, exefs); - } - - private const int FILECOUNT_XY = 271; - private const int FILECOUNT_ORASDEMO = 301; - private const int FILECOUNT_ORAS = 299; - private const int FILECOUNT_SMDEMO = 239; - private const int FILECOUNT_SM = 311; - private const int FILECOUNT_USUM = 333; - private const int FILECOUNT_GG = 27818; - private const int FILECOUNT_SWSH = 41702; - private const int FILECOUNT_SWSH_110 = 41951; // Ver. 1.1.0 (Galarian Slowpoke) - private const int FILECOUNT_SWSH_120 = 46867; // Ver. 1.2.0 (Isle of Armor) - private const int FILECOUNT_SWSH_130 = 50494; // Ver. 1.3.0 (Crown Tundra) - private const int FILECOUNT_LA = 18_370; - private const int FILECOUNT_LA_101 = 18_371; // Ver. 1.0.1 (Day 1 Patch) - private const int FILECOUNT_LA_110 = 19_095; // Ver. 1.1.0 (Daybreak) - - private static GameVersion GetGameFromCount(int fileCount, string romfs, string exefs) - { - string GetTitleID() => BitConverter.ToUInt64(File.ReadAllBytes(Path.Combine(exefs, "main.npdm")), 0x290).ToString("X16"); - - switch (fileCount) + case FILECOUNT_XY: return GameVersion.XY; + case FILECOUNT_ORASDEMO: return GameVersion.ORASDEMO; + case FILECOUNT_ORAS: return GameVersion.ORAS; + case FILECOUNT_SMDEMO: return GameVersion.SMDEMO; + case FILECOUNT_SM: { - case FILECOUNT_XY: return GameVersion.XY; - case FILECOUNT_ORASDEMO: return GameVersion.ORASDEMO; - case FILECOUNT_ORAS: return GameVersion.ORAS; - case FILECOUNT_SMDEMO: return GameVersion.SMDEMO; - case FILECOUNT_SM: - { - var encdata = Path.Combine(romfs, "a", "0", "8", "2"); - if (File.Exists(encdata) && new FileInfo(encdata).Length != 0) - return GameVersion.SN; - return GameVersion.MN; - } - - case FILECOUNT_USUM: - { - var encdata = Path.Combine(romfs, "a", "0", "8", "2"); - if (File.Exists(encdata) && new FileInfo(encdata).Length != 0) - return GameVersion.US; - return GameVersion.UM; - } - - case FILECOUNT_GG: - { - bool eevee = Directory.Exists(Path.Combine(romfs, "bin", "movies", "EEVEE_GO")); - if (eevee) - return GameVersion.GE; - return GameVersion.GP; - } - - case FILECOUNT_SWSH: - case FILECOUNT_SWSH_110: - case FILECOUNT_SWSH_120: - case FILECOUNT_SWSH_130: - { - if (exefs == null) - return GameVersion.SWSH; - - return GetTitleID() switch - { - "0100ABF008968000" => GameVersion.SW, - "01008DB008C2C000" => GameVersion.SH, - _ => GameVersion.SWSH, // can't figure out Title ID, default to SWSH so that wild editor prompts for version selection - }; - } - - case FILECOUNT_LA or FILECOUNT_LA_101 or FILECOUNT_LA_110: - return GameVersion.PLA; - - default: - return GameVersion.Invalid; + var encdata = Path.Combine(romfs, "a", "0", "8", "2"); + if (File.Exists(encdata) && new FileInfo(encdata).Length != 0) + return GameVersion.SN; + return GameVersion.MN; } + + case FILECOUNT_USUM: + { + var encdata = Path.Combine(romfs, "a", "0", "8", "2"); + if (File.Exists(encdata) && new FileInfo(encdata).Length != 0) + return GameVersion.US; + return GameVersion.UM; + } + + case FILECOUNT_GG: + { + bool eevee = Directory.Exists(Path.Combine(romfs, "bin", "movies", "EEVEE_GO")); + if (eevee) + return GameVersion.GE; + return GameVersion.GP; + } + + case FILECOUNT_SWSH: + case FILECOUNT_SWSH_110: + case FILECOUNT_SWSH_120: + case FILECOUNT_SWSH_130: + { + if (exefs == null) + return GameVersion.SWSH; + + return GetTitleID() switch + { + "0100ABF008968000" => GameVersion.SW, + "01008DB008C2C000" => GameVersion.SH, + _ => GameVersion.SWSH, // can't figure out Title ID, default to SWSH so that wild editor prompts for version selection + }; + } + + case FILECOUNT_LA or FILECOUNT_LA_101 or FILECOUNT_LA_110: + return GameVersion.PLA; + + default: + return GameVersion.Invalid; } } -} +} \ No newline at end of file diff --git a/pkNX.Game/GameManager.cs b/pkNX.Game/GameManager.cs index 84f9044d..ebf4e5ca 100644 --- a/pkNX.Game/GameManager.cs +++ b/pkNX.Game/GameManager.cs @@ -2,119 +2,118 @@ using pkNX.Containers; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +/// +/// Manages fetching of game data. +/// +public abstract class GameManager { + protected readonly GameLocation ROM; + protected readonly TextManager Text; // GameText + protected readonly GameFileMapping FileMap; + public readonly GameInfo Info; + private int _language; + + public string PathExeFS => ROM.ExeFS; + public string PathRomFS => ROM.RomFS; + /// - /// Manages fetching of game data. + /// Language to use when fetching string & graphic assets. /// - public abstract class GameManager + public int Language { - protected readonly GameLocation ROM; - protected readonly TextManager Text; // GameText - protected readonly GameFileMapping FileMap; - public readonly GameInfo Info; - private int _language; - - public string PathExeFS => ROM.ExeFS; - public string PathRomFS => ROM.RomFS; - - /// - /// Language to use when fetching string & graphic assets. - /// - public int Language + get => _language; + set { - get => _language; - set - { - if (value == _language) - return; - _language = value; - Text?.ClearCache(); - } - } - - /// - /// Current the data represents. - /// - public GameVersion Game => ROM.Game; - - /// - /// Initializes a new for the input with initial . - /// - /// - /// - protected GameManager(GameLocation rom, int language) - { - ROM = rom; - Language = language; - FileMap = new GameFileMapping(rom); - Text = new TextManager(Game); - Info = new GameInfo(Game); - } - - /// - /// Fetches a from the Game data. - /// - /// File type to fetch - /// Container that contains the game data requested. - /// Sugar for the other method. - public IFileContainer this[GameFile file] => GetFile(file); - - /// - /// Fetches a from the Game data. - /// - /// File type to fetch - /// Container that contains the game data requested. - public IFileContainer GetFile(GameFile file) => FileMap.GetFile(file, Language); - - /// - /// Fetches strings for the input . - /// - /// Text file to fetch - /// Array of strings from the requested text file. - public string[] GetStrings(TextName text) - { - var arc = this[GameFile.GameText]; - var lines = Text.GetStrings(text, arc); - return lines; - } - - /// - /// Saves all open files and finalizes the ROM data. - /// - /// Skip re-initialization of game data. - public void SaveAll(bool closing) - { - Terminate(); - FileMap.SaveAll(); - if (!closing) - Initialize(); - } - - public virtual void Initialize() - { - SetMitm(); - } - - protected abstract void Terminate(); - protected abstract void SetMitm(); - - public FolderContainer GetFilteredFolder(GameFile type, Func filter = null) - { - var c = (FolderContainer)this[type]; - c.Initialize(filter); - return c; - } - - public static GameManager GetManager(GameLocation loc, int language) - { - return loc.Game switch - { - GameVersion.GP or GameVersion.GE or GameVersion.GG => new GameManagerGG(loc, language), - GameVersion.SW or GameVersion.SH or GameVersion.SWSH => new GameManagerSWSH(loc, language), - GameVersion.PLA => new GameManagerPLA(loc, language), - _ => throw new ArgumentException(nameof(loc.Game)) - }; + if (value == _language) + return; + _language = value; + Text?.ClearCache(); } } -} + + /// + /// Current the data represents. + /// + public GameVersion Game => ROM.Game; + + /// + /// Initializes a new for the input with initial . + /// + /// + /// + protected GameManager(GameLocation rom, int language) + { + ROM = rom; + Language = language; + FileMap = new GameFileMapping(rom); + Text = new TextManager(Game); + Info = new GameInfo(Game); + } + + /// + /// Fetches a from the Game data. + /// + /// File type to fetch + /// Container that contains the game data requested. + /// Sugar for the other method. + public IFileContainer this[GameFile file] => GetFile(file); + + /// + /// Fetches a from the Game data. + /// + /// File type to fetch + /// Container that contains the game data requested. + public IFileContainer GetFile(GameFile file) => FileMap.GetFile(file, Language); + + /// + /// Fetches strings for the input . + /// + /// Text file to fetch + /// Array of strings from the requested text file. + public string[] GetStrings(TextName text) + { + var arc = this[GameFile.GameText]; + var lines = Text.GetStrings(text, arc); + return lines; + } + + /// + /// Saves all open files and finalizes the ROM data. + /// + /// Skip re-initialization of game data. + public void SaveAll(bool closing) + { + Terminate(); + FileMap.SaveAll(); + if (!closing) + Initialize(); + } + + public virtual void Initialize() + { + SetMitm(); + } + + protected abstract void Terminate(); + protected abstract void SetMitm(); + + public FolderContainer GetFilteredFolder(GameFile type, Func filter = null) + { + var c = (FolderContainer)this[type]; + c.Initialize(filter); + return c; + } + + public static GameManager GetManager(GameLocation loc, int language) + { + return loc.Game switch + { + GameVersion.GP or GameVersion.GE or GameVersion.GG => new GameManagerGG(loc, language), + GameVersion.SW or GameVersion.SH or GameVersion.SWSH => new GameManagerSWSH(loc, language), + GameVersion.PLA => new GameManagerPLA(loc, language), + _ => throw new ArgumentException(nameof(loc.Game)) + }; + } +} \ No newline at end of file diff --git a/pkNX.Game/GameManagerGG.cs b/pkNX.Game/GameManagerGG.cs index e9a27afa..fbc80178 100644 --- a/pkNX.Game/GameManagerGG.cs +++ b/pkNX.Game/GameManagerGG.cs @@ -3,73 +3,72 @@ using pkNX.Containers; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public class GameManagerGG : GameManager { - public class GameManagerGG : GameManager + public GameManagerGG(GameLocation rom, int language) : base(rom, language) { } + private GameVersion ActualGame; + private string TitleID => ActualGame == GameVersion.GP ? Pikachu : Eevee; + private const string Pikachu = "010003F003A34000"; + private const string Eevee = "0100187003A36000"; + + /// + /// Generally useful game data that can be used by multiple editors. + /// + public GameData Data { get; protected set; } + + protected override void SetMitm() { - public GameManagerGG(GameLocation rom, int language) : base(rom, language) { } - private GameVersion ActualGame; - private string TitleID => ActualGame == GameVersion.GP ? Pikachu : Eevee; - private const string Pikachu = "010003F003A34000"; - private const string Eevee = "0100187003A36000"; + var basePath = Path.GetDirectoryName(ROM.RomFS); + // unlike SWSH, LGPE has a unique opening movie in romfs to differentiate between versions + bool eevee = Directory.Exists(Path.Combine(PathRomFS, "bin", "movies", "EEVEE_GO")); + ActualGame = eevee ? GameVersion.GE : GameVersion.GP; + var redirect = Path.Combine(basePath, TitleID); + FileMitm.SetRedirect(basePath, redirect); + } - /// - /// Generally useful game data that can be used by multiple editors. - /// - public GameData Data { get; protected set; } + public override void Initialize() + { + base.Initialize(); - protected override void SetMitm() + // initialize gametext + GetFilteredFolder(GameFile.GameText, z => Path.GetExtension(z) == ".dat"); + + // initialize common structures + var personal = GetFilteredFolder(GameFile.PersonalStats, z => Path.GetFileNameWithoutExtension(z) == "personal_total"); + Data = new GameData { - var basePath = Path.GetDirectoryName(ROM.RomFS); - // unlike SWSH, LGPE has a unique opening movie in romfs to differentiate between versions - bool eevee = Directory.Exists(Path.Combine(PathRomFS, "bin", "movies", "EEVEE_GO")); - ActualGame = eevee ? GameVersion.GE : GameVersion.GP; - var redirect = Path.Combine(basePath, TitleID); - FileMitm.SetRedirect(basePath, redirect); - } - - public override void Initialize() - { - base.Initialize(); - - // initialize gametext - GetFilteredFolder(GameFile.GameText, z => Path.GetExtension(z) == ".dat"); - - // initialize common structures - var personal = GetFilteredFolder(GameFile.PersonalStats, z => Path.GetFileNameWithoutExtension(z) == "personal_total"); - Data = new GameData + MoveData = new DataCache(this[GameFile.MoveStats]) // mini { - MoveData = new DataCache(this[GameFile.MoveStats]) // mini - { - Create = z => new Move7(z), - Write = z => z.Write(), - }, - LevelUpData = new DataCache(this[GameFile.Learnsets]) // gfpak - { - Create = z => new Learnset6(z), - Write = z => z.Write(), - }, + Create = z => new Move7(z), + Write = z => z.Write(), + }, + LevelUpData = new DataCache(this[GameFile.Learnsets]) // gfpak + { + Create = z => new Learnset6(z), + Write = z => z.Write(), + }, - // folders; - PersonalData = new PersonalTable7GG(personal[0]), - MegaEvolutionData = new DataCache(GetFilteredFolder(GameFile.MegaEvolutions)) - { - Create = MegaEvolutionSet.ReadArray, - Write = MegaEvolutionSet.WriteArray, - }, - EvolutionData = new DataCache(GetFilteredFolder(GameFile.Evolutions)) - { - Create = data => new EvolutionSet7(data), - Write = evo => evo.Write(), - }, - }; - } + // folders; + PersonalData = new PersonalTable7GG(personal[0]), + MegaEvolutionData = new DataCache(GetFilteredFolder(GameFile.MegaEvolutions)) + { + Create = MegaEvolutionSet.ReadArray, + Write = MegaEvolutionSet.WriteArray, + }, + EvolutionData = new DataCache(GetFilteredFolder(GameFile.Evolutions)) + { + Create = data => new EvolutionSet7(data), + Write = evo => evo.Write(), + }, + }; + } - protected override void Terminate() - { - // Store Personal Data back in the file. Let the container detect if it is modified. - var personal = this[GameFile.PersonalStats]; - personal[0] = Data.PersonalData.Table.SelectMany(z => ((IPersonalInfoBin)z).Write()).ToArray(); - } + protected override void Terminate() + { + // Store Personal Data back in the file. Let the container detect if it is modified. + var personal = this[GameFile.PersonalStats]; + personal[0] = Data.PersonalData.Table.SelectMany(z => ((IPersonalInfoBin)z).Write()).ToArray(); } } \ No newline at end of file diff --git a/pkNX.Game/GameManagerPLA.cs b/pkNX.Game/GameManagerPLA.cs index 59f2ad07..ef279c9d 100644 --- a/pkNX.Game/GameManagerPLA.cs +++ b/pkNX.Game/GameManagerPLA.cs @@ -5,81 +5,80 @@ using pkNX.Structures; using pkNX.Structures.FlatBuffers; -namespace pkNX.Game +namespace pkNX.Game; + +public class GameManagerPLA : GameManager { - public class GameManagerPLA : GameManager + public GameManagerPLA(GameLocation rom, int language) : base(rom, language) { } + private string PathNPDM => Path.Combine(PathExeFS, "main.npdm"); + private string TitleID => BitConverter.ToUInt64(File.ReadAllBytes(PathNPDM), 0x470).ToString("X16"); + + /// + /// Generally useful game data that can be used by multiple editors. + /// + public GameData8a Data { get; protected set; } + + protected override void SetMitm() { - public GameManagerPLA(GameLocation rom, int language) : base(rom, language) { } - private string PathNPDM => Path.Combine(PathExeFS, "main.npdm"); - private string TitleID => BitConverter.ToUInt64(File.ReadAllBytes(PathNPDM), 0x470).ToString("X16"); - - /// - /// Generally useful game data that can be used by multiple editors. - /// - public GameData8a Data { get; protected set; } - - protected override void SetMitm() - { - var basePath = Path.GetDirectoryName(ROM.RomFS); - var tid = ROM.ExeFS != null ? TitleID : "arceus"; - var redirect = Path.Combine(basePath, tid); - FileMitm.SetRedirect(basePath, redirect); - } - - public override void Initialize() - { - base.Initialize(); - - // initialize gametext - ResetText(); - - // initialize common structures - ResetData(); - - ItemConverter.ItemNames = GetStrings(TextName.ItemNames); - } - - private void ResetData() - { - Data = new GameData8a - { - // Folders - MoveData = GetMoves(), - - // Single Files - PersonalData = new PersonalTable8LA(GetFile(GameFile.PersonalStats)), - PokeMiscData = new(GetFile(GameFile.PokeMisc)), - LevelUpData = new(GetFile(GameFile.Learnsets)), - EvolutionData = new(GetFile(GameFile.Evolutions)), - - FieldDrops = new(GetFile(GameFile.FieldDrops)), - BattleDrops = new(GetFile(GameFile.BattleDrops)), - DexResearch = new(GetFile(GameFile.DexResearch)), - }; - - DropTableConverter.DropTableHashes = Data.FieldDrops.Table.Select(x => x.Hash).ToArray(); - } - - private DataCache GetMoves() - { - var move = this[GameFile.MoveStats]; - ((FolderContainer)move).Initialize(); - return new DataCache(move) - { - Create = FlatBufferConverter.DeserializeFrom, - Write = FlatBufferConverter.SerializeFrom, - }; - } - - public void ResetMoves() => Data.MoveData.ClearAll(); - - public void ResetText() - { - GetFilteredFolder(GameFile.GameText, z => Path.GetExtension(z) == ".dat"); - } - - protected override void Terminate() - { - } + var basePath = Path.GetDirectoryName(ROM.RomFS); + var tid = ROM.ExeFS != null ? TitleID : "arceus"; + var redirect = Path.Combine(basePath, tid); + FileMitm.SetRedirect(basePath, redirect); } -} + + public override void Initialize() + { + base.Initialize(); + + // initialize gametext + ResetText(); + + // initialize common structures + ResetData(); + + ItemConverter.ItemNames = GetStrings(TextName.ItemNames); + } + + private void ResetData() + { + Data = new GameData8a + { + // Folders + MoveData = GetMoves(), + + // Single Files + PersonalData = new PersonalTable8LA(GetFile(GameFile.PersonalStats)), + PokeMiscData = new(GetFile(GameFile.PokeMisc)), + LevelUpData = new(GetFile(GameFile.Learnsets)), + EvolutionData = new(GetFile(GameFile.Evolutions)), + + FieldDrops = new(GetFile(GameFile.FieldDrops)), + BattleDrops = new(GetFile(GameFile.BattleDrops)), + DexResearch = new(GetFile(GameFile.DexResearch)), + }; + + DropTableConverter.DropTableHashes = Data.FieldDrops.Table.Select(x => x.Hash).ToArray(); + } + + private DataCache GetMoves() + { + var move = this[GameFile.MoveStats]; + ((FolderContainer)move).Initialize(); + return new DataCache(move) + { + Create = FlatBufferConverter.DeserializeFrom, + Write = FlatBufferConverter.SerializeFrom, + }; + } + + public void ResetMoves() => Data.MoveData.ClearAll(); + + public void ResetText() + { + GetFilteredFolder(GameFile.GameText, z => Path.GetExtension(z) == ".dat"); + } + + protected override void Terminate() + { + } +} \ No newline at end of file diff --git a/pkNX.Game/GameManagerSWSH.cs b/pkNX.Game/GameManagerSWSH.cs index d6fcf1b7..2ea6764d 100644 --- a/pkNX.Game/GameManagerSWSH.cs +++ b/pkNX.Game/GameManagerSWSH.cs @@ -5,81 +5,80 @@ using pkNX.Structures; using pkNX.Structures.FlatBuffers; -namespace pkNX.Game +namespace pkNX.Game; + +public class GameManagerSWSH : GameManager { - public class GameManagerSWSH : GameManager + public GameManagerSWSH(GameLocation rom, int language) : base(rom, language) { } + private string npdmPath => Path.Combine(PathExeFS, "main.npdm"); + private string TitleID => BitConverter.ToUInt64(File.ReadAllBytes(npdmPath), 0x290).ToString("X16"); + + /// + /// Generally useful game data that can be used by multiple editors. + /// + public GameData Data { get; protected set; } + + protected override void SetMitm() { - public GameManagerSWSH(GameLocation rom, int language) : base(rom, language) { } - private string npdmPath => Path.Combine(PathExeFS, "main.npdm"); - private string TitleID => BitConverter.ToUInt64(File.ReadAllBytes(npdmPath), 0x290).ToString("X16"); + var basePath = Path.GetDirectoryName(ROM.RomFS); + var tid = ROM.ExeFS != null ? TitleID : "0100ABF008968000"; // no way to differentiate without exefs, so default to Sword + var redirect = Path.Combine(basePath, tid); + FileMitm.SetRedirect(basePath, redirect); + } - /// - /// Generally useful game data that can be used by multiple editors. - /// - public GameData Data { get; protected set; } + private FakeContainer Learn; - protected override void SetMitm() + public override void Initialize() + { + base.Initialize(); + + // initialize gametext + ResetText(); + + // initialize common structures + var personal = GetFilteredFolder(GameFile.PersonalStats, z => Path.GetFileNameWithoutExtension(z) == "personal_total"); + var learn = this[GameFile.Learnsets][0]; + var splitLearn = learn.Split(0x104); + Learn = new FakeContainer(splitLearn); + + var move = this[GameFile.MoveStats]; + ((FolderContainer)move).Initialize(); + Data = new GameData { - var basePath = Path.GetDirectoryName(ROM.RomFS); - var tid = ROM.ExeFS != null ? TitleID : "0100ABF008968000"; // no way to differentiate without exefs, so default to Sword - var redirect = Path.Combine(basePath, tid); - FileMitm.SetRedirect(basePath, redirect); - } - - private FakeContainer Learn; - - public override void Initialize() - { - base.Initialize(); - - // initialize gametext - ResetText(); - - // initialize common structures - var personal = GetFilteredFolder(GameFile.PersonalStats, z => Path.GetFileNameWithoutExtension(z) == "personal_total"); - var learn = this[GameFile.Learnsets][0]; - var splitLearn = learn.Split(0x104); - Learn = new FakeContainer(splitLearn); - - var move = this[GameFile.MoveStats]; - ((FolderContainer)move).Initialize(); - Data = new GameData + MoveData = new DataCache(move) { - MoveData = new DataCache(move) - { - Create = FlatBufferConverter.DeserializeFrom, - Write = z => FlatBufferConverter.SerializeFrom((Waza8)z), - }, - LevelUpData = new DataCache(Learn) - { - Create = z => new Learnset8(z), - Write = z => z.Write(), - }, + Create = FlatBufferConverter.DeserializeFrom, + Write = z => FlatBufferConverter.SerializeFrom((Waza8)z), + }, + LevelUpData = new DataCache(Learn) + { + Create = z => new Learnset8(z), + Write = z => z.Write(), + }, - // folders - PersonalData = new PersonalTable8SWSH(personal[0]), - EvolutionData = new DataCache(GetFilteredFolder(GameFile.Evolutions)) - { - Create = data => new EvolutionSet8(data), - Write = evo => evo.Write(), - }, - }; - } + // folders + PersonalData = new PersonalTable8SWSH(personal[0]), + EvolutionData = new DataCache(GetFilteredFolder(GameFile.Evolutions)) + { + Create = data => new EvolutionSet8(data), + Write = evo => evo.Write(), + }, + }; + } - public void ResetMoves() => GetFilteredFolder(GameFile.MoveStats); + public void ResetMoves() => GetFilteredFolder(GameFile.MoveStats); - public void ResetText() - { - GetFilteredFolder(GameFile.GameText, z => Path.GetExtension(z) == ".dat"); - } + public void ResetText() + { + GetFilteredFolder(GameFile.GameText, z => Path.GetExtension(z) == ".dat"); + } - protected override void Terminate() - { - // Store Personal Data back in the file. Let the container detect if it is modified. - var personal = this[GameFile.PersonalStats]; - personal[0] = Data.PersonalData.Table.SelectMany(z => ((IPersonalInfoBin)z).Write()).ToArray(); - var learn = this[GameFile.Learnsets]; - learn[0] = Learn.Files.SelectMany(z => z).ToArray(); - } + protected override void Terminate() + { + // Store Personal Data back in the file. Let the container detect if it is modified. + var personal = this[GameFile.PersonalStats]; + personal[0] = Data.PersonalData.Table.SelectMany(z => ((IPersonalInfoBin)z).Write()).ToArray(); + var learn = this[GameFile.Learnsets]; + learn[0] = Learn.Files.SelectMany(z => z).ToArray(); } } \ No newline at end of file diff --git a/pkNX.Game/Misc/SWSHInfo.cs b/pkNX.Game/Misc/SWSHInfo.cs index 1897e9d3..182cd02a 100644 --- a/pkNX.Game/Misc/SWSHInfo.cs +++ b/pkNX.Game/Misc/SWSHInfo.cs @@ -1,631 +1,630 @@ using System.Collections.Generic; using static pkNX.Game.SWSHSlotType; -namespace pkNX.Game +namespace pkNX.Game; + +public static class SWSHInfo { - public static class SWSHInfo + public static readonly IReadOnlyDictionary ZoneLocations = new Dictionary { - public static readonly IReadOnlyDictionary ZoneLocations = new Dictionary - { - {0x078BC1FF1A657844, 012}, // on Route 1 - {0x10355EFF1F4DB0B5, 018}, // on Route 2 - {0x776776717EA4483E, 122}, // in the Rolling Fields (in a Wild Area) - {0x776777717EA449F1, 124}, // in the Dappled Grove (in a Wild Area) - {0x776778717EA44BA4, 126}, // at Watchtower Ruins (in a Wild Area) - {0x776779717EA44D57, 128}, // at East Lake Axewell (in a Wild Area) - {0x77677A717EA44F0A, 130}, // at West Lake Axewell (in a Wild Area) - {0x77677B717EA450BD, 132}, // on Axew's Eye (in a Wild Area) - {0x77676C717EA43740, 134}, // at South Lake Miloch (in a Wild Area) - {0x77676D717EA438F3, 136}, // near the Giant's Seat (in a Wild Area) - {0x776AFA717EA75E61, 138}, // at North Lake Miloch (in a Wild Area) - {0x194B97FF2492111A, 028}, // on Route 3 - {0x776E81717EAA799D, 140}, // at the Motostoke Riverbank (in a Wild Area) - {0x776E7E717EAA7484, 142}, // in Bridge Field (in a Wild Area) - {0xDBCF5CFF0180B073, 032}, // on Route 4 - {0x8F67CD45F405D66E, 008}, // in the Slumbering Weald - {0xE0D6E5E78C91F4A7, 020}, // in the city of Motostoke - {0xE4E595FF06C510D8, 040}, // on Route 5 - {0x1C7150C0594994E5, 044}, // in the town of Hulbury - {0x7D3B7A45E97D4A51, 054}, // in Galar Mine No. 2 - {0x75D83E45E5AA7953, 030}, // in Galar Mine - {0x7D3B7745E97D4538, 052}, // in the Motostoke Outskirts - {0xA88AC04602050B95, 076}, // in Glimwood Tangle - {0xEDFC32FF0C0A1B29, 068}, // on Route 6 - {0xF55F6BFF0FDCE70E, 084}, // on Route 7 - {0x449AE0FF3D19D777, 086}, // on Route 8 - {0x4BFDF9FF40EC6CFC, 088}, // on Route 8 (on Steamdrift Way) - {0x4BFDFCFF40EC7215, 090}, // on Route 9 - {0x4BFDF6FF40EC67E3, 092}, // on Route 9 (in Circhester Bay) - {0x4BFDFBFF40EC7062, 094}, // on Route 9 (in Outer Spikemuth) - {0xB332930807F9D48A, 106}, // on Route 10 // Near Station - {0x7771E5717EAD5960, 144}, // in the Stony Wilderness (in a Wild Area) - {0x7771E8717EAD5E79, 146}, // in Dusty Bowl (in a Wild Area) - {0x7771E7717EAD5CC6, 148}, // around the Giant's Mirror (in a Wild Area) - {0x7771EA717EAD61DF, 150}, // on the Hammerlocke Hills (in a Wild Area) - {0x7771E9717EAD602C, 152}, // near the Giant's Cap (in a Wild Area) - {0x7771EC717EAD6545, 154}, // at the Lake of Outrage (in a Wild Area) - {0x10355BFF1F4DAB9C, 018}, // on Route 2 - {0xB332920807F9D2D7, 106}, // on Route 10 - {0x8F67CB45F405D308, 008}, // in the Slumbering Weald + {0x078BC1FF1A657844, 012}, // on Route 1 + {0x10355EFF1F4DB0B5, 018}, // on Route 2 + {0x776776717EA4483E, 122}, // in the Rolling Fields (in a Wild Area) + {0x776777717EA449F1, 124}, // in the Dappled Grove (in a Wild Area) + {0x776778717EA44BA4, 126}, // at Watchtower Ruins (in a Wild Area) + {0x776779717EA44D57, 128}, // at East Lake Axewell (in a Wild Area) + {0x77677A717EA44F0A, 130}, // at West Lake Axewell (in a Wild Area) + {0x77677B717EA450BD, 132}, // on Axew's Eye (in a Wild Area) + {0x77676C717EA43740, 134}, // at South Lake Miloch (in a Wild Area) + {0x77676D717EA438F3, 136}, // near the Giant's Seat (in a Wild Area) + {0x776AFA717EA75E61, 138}, // at North Lake Miloch (in a Wild Area) + {0x194B97FF2492111A, 028}, // on Route 3 + {0x776E81717EAA799D, 140}, // at the Motostoke Riverbank (in a Wild Area) + {0x776E7E717EAA7484, 142}, // in Bridge Field (in a Wild Area) + {0xDBCF5CFF0180B073, 032}, // on Route 4 + {0x8F67CD45F405D66E, 008}, // in the Slumbering Weald + {0xE0D6E5E78C91F4A7, 020}, // in the city of Motostoke + {0xE4E595FF06C510D8, 040}, // on Route 5 + {0x1C7150C0594994E5, 044}, // in the town of Hulbury + {0x7D3B7A45E97D4A51, 054}, // in Galar Mine No. 2 + {0x75D83E45E5AA7953, 030}, // in Galar Mine + {0x7D3B7745E97D4538, 052}, // in the Motostoke Outskirts + {0xA88AC04602050B95, 076}, // in Glimwood Tangle + {0xEDFC32FF0C0A1B29, 068}, // on Route 6 + {0xF55F6BFF0FDCE70E, 084}, // on Route 7 + {0x449AE0FF3D19D777, 086}, // on Route 8 + {0x4BFDF9FF40EC6CFC, 088}, // on Route 8 (on Steamdrift Way) + {0x4BFDFCFF40EC7215, 090}, // on Route 9 + {0x4BFDF6FF40EC67E3, 092}, // on Route 9 (in Circhester Bay) + {0x4BFDFBFF40EC7062, 094}, // on Route 9 (in Outer Spikemuth) + {0xB332930807F9D48A, 106}, // on Route 10 // Near Station + {0x7771E5717EAD5960, 144}, // in the Stony Wilderness (in a Wild Area) + {0x7771E8717EAD5E79, 146}, // in Dusty Bowl (in a Wild Area) + {0x7771E7717EAD5CC6, 148}, // around the Giant's Mirror (in a Wild Area) + {0x7771EA717EAD61DF, 150}, // on the Hammerlocke Hills (in a Wild Area) + {0x7771E9717EAD602C, 152}, // near the Giant's Cap (in a Wild Area) + {0x7771EC717EAD6545, 154}, // at the Lake of Outrage (in a Wild Area) + {0x10355BFF1F4DAB9C, 018}, // on Route 2 + {0xB332920807F9D2D7, 106}, // on Route 10 + {0x8F67CB45F405D308, 008}, // in the Slumbering Weald - {0xCD6E4FBCE1466F32, 012}, // on Route 1 - {0xDF686EC613544BD1, 018}, // on Route 2 - {0xD602B2A66C268F7C, 122}, // in the Rolling Fields (in a Wild Area) - {0x458C9CA2C0087385, 124}, // in the Dappled Grove (in a Wild Area) - {0xE20E6AE30AAA57D2, 126}, // at Watchtower Ruins (in a Wild Area) - {0xEEEEAC06BAC8D0B3, 128}, // at East Lake Axewell (in a Wild Area) - {0xF8D1E527F7B21FA0, 130}, // at West Lake Axewell (in a Wild Area) - {0xB6CFE90E0378FD79, 132}, // on Axew's Eye (in a Wild Area) - {0x520D8DD522E9A4C6, 134}, // at South Lake Miloch (in a Wild Area) - {0xBC7237A0392D8837, 136}, // near the Giant's Seat (in a Wild Area) - {0xB67C706F5BAE9E35, 138}, // at North Lake Miloch (in a Wild Area) - {0xDA910F69A1B92FED, 130}, // at West Lake Axewell (in a Wild Area) // Surfing - {0x7C17DB1B430F9543, 134}, // at South Lake Miloch (in a Wild Area) // Surfing - {0xCC0F8A437312B8AC, 128}, // at East Lake Axewell (in a Wild Area) // Surfing - {0x8BE2F6160986FB8E, 138}, // at North Lake Miloch (in a Wild Area) // Surfing - {0x0E8392C0A57D5830, 028}, // on Route 3 - {0x82A7A328A26B9057, 030}, // in Galar Mine - {0x5B2BC38E044EC2B7, 032}, // on Route 4 - {0x8D68276C03A332BE, 040}, // on Route 5 - {0x16D2FC4840A658A5, 054}, // in Galar Mine No. 2 - {0x3D6D58A96894575E, 052}, // in the Motostoke Outskirts - {0x6AA652641154B119, 140}, // at the Motostoke Riverbank (in a Wild Area) - {0x36A5DC94335E1E72, 142}, // in Bridge Field (in a Wild Area) - {0xE503416A1C05765D, 068}, // on Route 6 - {0x201EF8E9D2A32D71, 076}, // in Glimwood Tangle - {0x42312695C904658C, 084}, // on Route 7 - {0x1B95A78295F6F213, 086}, // on Route 8 - {0xAADAC3CB6A1DFE8A, 088}, // on Route 8 (on Steamdrift Way) - {0x9116B224702CDCF1, 090}, // on Route 9 - {0xCDD3B5660D2E5E67, 092}, // on Route 9 (in Circhester Bay) - {0x5A3B8F8147272058, 094}, // on Route 9 (in Outer Spikemuth) - {0xA93101EA38598995, 090}, // on Route 9 // Surfing - {0x0181225223DE5420, 106}, // on Route 10 // Near Station - {0x1F0F1AE1818C4326, 144}, // in the Stony Wilderness (in a Wild Area) - {0xAD11B3F3B2AC662D, 146}, // in Dusty Bowl (in a Wild Area) - {0xCD9719B2E64F2AA4, 148}, // around the Giant's Mirror (in a Wild Area) - {0xCD48625EDC10CBFB, 150}, // on the Hammerlocke Hills (in a Wild Area) - {0x712F3056573E23FA, 152}, // near the Giant's Cap (in a Wild Area) - {0x593196758BA16B61, 154}, // at the Lake of Outrage (in a Wild Area) - {0xF79DE930E6F50533, 106}, // on Route 10 - {0xA26A4595F72EDAEA, 018}, // on Route 2 // high level - {0x56580C94EDFCE664, 028}, // on Route 3 // just rolycoly and trubbish, probably trash - {0xCB38FEA3F71C3958, 122}, // in the Rolling Fields (in a Wild Area) // Flying Spawns butterfree/pidove - {0x1F174D36062B8C38, 122}, // in the Rolling Fields (in a Wild Area) // Underground Spawns digglet/roggenrola - {0x23017513039A78E7, 122}, // in the Rolling Fields (in a Wild Area) // ? Second full table, has pancham instead of bunnelby - {0xF1BA4AAD9AAB2C1A, 126}, // at Watchtower Ruins (in a Wild Area) // Flying Spawns woobat/noibat - {0x3D2E746F9D3F5CB5, 128}, // at East Lake Axewell (in a Wild Area) // Flying Spawns bufferfree/pidove - {0x6E121A9CE4F58F1E, 128}, // at East Lake Axewell (in a Wild Area) // More Flying Spawns bufferfree/pidove, different rates than above - {0x3171A0C61793816E, 134}, // at South Lake Miloch (in a Wild Area) // Flying Spawns wingull/drifloon - {0x198E4023A1B2DDEF, 134}, // at South Lake Miloch (in a Wild Area) // ? Second table, has mostly machop/stunky/tyrogue - {0xFAB1C08E70C0F1CA, 140}, // at the Motostoke Riverbank (in a Wild Area) // Surfing - {0xB9F76CEE459CEC07, 142}, // in Bridge Field (in a Wild Area) // Surfing - {0x5F4E0AB29FD3F13A, 142}, // in Bridge Field (in a Wild Area) // Flying Spawns noibat/woobat/tranquill - {0xF603DEA4177200EA, 144}, // in the Stony Wilderness (in a Wild Area) // ? Second full table - {0x76EE4E28DD28374E, 144}, // in the Stony Wilderness (in a Wild Area) // Flying Spawns tranquill/sigilyph - {0x3F264B6FCB5647B4, 148}, // around the Giant's Mirror (in a Wild Area) // Flying Spawns tranquill/corvisquire - {0x2D887A1CA9B1B99A, 146}, // in Dusty Bowl (in a Wild Area) // Flying Spawns braviary - {0x2BE7E6A8901ECC20, 148}, // around the Giant's Mirror (in a Wild Area) // Underground Spawns dugtrio/excadrill/boldore - {0x39F0170769BF4524, 146}, // in Dusty Bowl (in a Wild Area) // Surfing. Also used for 148,around the Giant's Mirror (in a Wild Area) surfing. - {0xB2067FBCF8D5C7BA, 152}, // near the Giant's Cap (in a Wild Area) // Underground Spawns rolycoly/rhyhorn/boldore - {0x48B9525945EE48B5, 144}, // in the Stony Wilderness (in a Wild Area) // ? third full table - {0xB5756B87989661E1, 152}, // near the Giant's Cap (in a Wild Area) // ? second full table - {0x7AB83D18C831DDEB, 152}, // near the Giant's Cap (in a Wild Area) // ? third full table - {0xDBEF8A8593377AAA, 152}, // near the Giant's Cap (in a Wild Area) // Underground Spawns Solrock - {0x066F97F8765BC22D, 150}, // on the Hammerlocke Hills (in a Wild Area) // Flying Spawns Unfezant/Corvisquire - {0x87A97AFF94BC6CF2, 154}, // at the Lake of Outrage (in a Wild Area) // Surfing - {0x94289204B628522C, 008}, // in the Slumbering Weald // early - {0x5D02F15C043B872E, 008}, // in the Slumbering Weald // late - {0xA4945486A2B97DFF, 018}, // on Route 2 // Surfing - {0xAC1187E9EC166853, 092}, // on Route 9 (in Circhester Bay) // Surfing + {0xCD6E4FBCE1466F32, 012}, // on Route 1 + {0xDF686EC613544BD1, 018}, // on Route 2 + {0xD602B2A66C268F7C, 122}, // in the Rolling Fields (in a Wild Area) + {0x458C9CA2C0087385, 124}, // in the Dappled Grove (in a Wild Area) + {0xE20E6AE30AAA57D2, 126}, // at Watchtower Ruins (in a Wild Area) + {0xEEEEAC06BAC8D0B3, 128}, // at East Lake Axewell (in a Wild Area) + {0xF8D1E527F7B21FA0, 130}, // at West Lake Axewell (in a Wild Area) + {0xB6CFE90E0378FD79, 132}, // on Axew's Eye (in a Wild Area) + {0x520D8DD522E9A4C6, 134}, // at South Lake Miloch (in a Wild Area) + {0xBC7237A0392D8837, 136}, // near the Giant's Seat (in a Wild Area) + {0xB67C706F5BAE9E35, 138}, // at North Lake Miloch (in a Wild Area) + {0xDA910F69A1B92FED, 130}, // at West Lake Axewell (in a Wild Area) // Surfing + {0x7C17DB1B430F9543, 134}, // at South Lake Miloch (in a Wild Area) // Surfing + {0xCC0F8A437312B8AC, 128}, // at East Lake Axewell (in a Wild Area) // Surfing + {0x8BE2F6160986FB8E, 138}, // at North Lake Miloch (in a Wild Area) // Surfing + {0x0E8392C0A57D5830, 028}, // on Route 3 + {0x82A7A328A26B9057, 030}, // in Galar Mine + {0x5B2BC38E044EC2B7, 032}, // on Route 4 + {0x8D68276C03A332BE, 040}, // on Route 5 + {0x16D2FC4840A658A5, 054}, // in Galar Mine No. 2 + {0x3D6D58A96894575E, 052}, // in the Motostoke Outskirts + {0x6AA652641154B119, 140}, // at the Motostoke Riverbank (in a Wild Area) + {0x36A5DC94335E1E72, 142}, // in Bridge Field (in a Wild Area) + {0xE503416A1C05765D, 068}, // on Route 6 + {0x201EF8E9D2A32D71, 076}, // in Glimwood Tangle + {0x42312695C904658C, 084}, // on Route 7 + {0x1B95A78295F6F213, 086}, // on Route 8 + {0xAADAC3CB6A1DFE8A, 088}, // on Route 8 (on Steamdrift Way) + {0x9116B224702CDCF1, 090}, // on Route 9 + {0xCDD3B5660D2E5E67, 092}, // on Route 9 (in Circhester Bay) + {0x5A3B8F8147272058, 094}, // on Route 9 (in Outer Spikemuth) + {0xA93101EA38598995, 090}, // on Route 9 // Surfing + {0x0181225223DE5420, 106}, // on Route 10 // Near Station + {0x1F0F1AE1818C4326, 144}, // in the Stony Wilderness (in a Wild Area) + {0xAD11B3F3B2AC662D, 146}, // in Dusty Bowl (in a Wild Area) + {0xCD9719B2E64F2AA4, 148}, // around the Giant's Mirror (in a Wild Area) + {0xCD48625EDC10CBFB, 150}, // on the Hammerlocke Hills (in a Wild Area) + {0x712F3056573E23FA, 152}, // near the Giant's Cap (in a Wild Area) + {0x593196758BA16B61, 154}, // at the Lake of Outrage (in a Wild Area) + {0xF79DE930E6F50533, 106}, // on Route 10 + {0xA26A4595F72EDAEA, 018}, // on Route 2 // high level + {0x56580C94EDFCE664, 028}, // on Route 3 // just rolycoly and trubbish, probably trash + {0xCB38FEA3F71C3958, 122}, // in the Rolling Fields (in a Wild Area) // Flying Spawns butterfree/pidove + {0x1F174D36062B8C38, 122}, // in the Rolling Fields (in a Wild Area) // Underground Spawns digglet/roggenrola + {0x23017513039A78E7, 122}, // in the Rolling Fields (in a Wild Area) // ? Second full table, has pancham instead of bunnelby + {0xF1BA4AAD9AAB2C1A, 126}, // at Watchtower Ruins (in a Wild Area) // Flying Spawns woobat/noibat + {0x3D2E746F9D3F5CB5, 128}, // at East Lake Axewell (in a Wild Area) // Flying Spawns bufferfree/pidove + {0x6E121A9CE4F58F1E, 128}, // at East Lake Axewell (in a Wild Area) // More Flying Spawns bufferfree/pidove, different rates than above + {0x3171A0C61793816E, 134}, // at South Lake Miloch (in a Wild Area) // Flying Spawns wingull/drifloon + {0x198E4023A1B2DDEF, 134}, // at South Lake Miloch (in a Wild Area) // ? Second table, has mostly machop/stunky/tyrogue + {0xFAB1C08E70C0F1CA, 140}, // at the Motostoke Riverbank (in a Wild Area) // Surfing + {0xB9F76CEE459CEC07, 142}, // in Bridge Field (in a Wild Area) // Surfing + {0x5F4E0AB29FD3F13A, 142}, // in Bridge Field (in a Wild Area) // Flying Spawns noibat/woobat/tranquill + {0xF603DEA4177200EA, 144}, // in the Stony Wilderness (in a Wild Area) // ? Second full table + {0x76EE4E28DD28374E, 144}, // in the Stony Wilderness (in a Wild Area) // Flying Spawns tranquill/sigilyph + {0x3F264B6FCB5647B4, 148}, // around the Giant's Mirror (in a Wild Area) // Flying Spawns tranquill/corvisquire + {0x2D887A1CA9B1B99A, 146}, // in Dusty Bowl (in a Wild Area) // Flying Spawns braviary + {0x2BE7E6A8901ECC20, 148}, // around the Giant's Mirror (in a Wild Area) // Underground Spawns dugtrio/excadrill/boldore + {0x39F0170769BF4524, 146}, // in Dusty Bowl (in a Wild Area) // Surfing. Also used for 148,around the Giant's Mirror (in a Wild Area) surfing. + {0xB2067FBCF8D5C7BA, 152}, // near the Giant's Cap (in a Wild Area) // Underground Spawns rolycoly/rhyhorn/boldore + {0x48B9525945EE48B5, 144}, // in the Stony Wilderness (in a Wild Area) // ? third full table + {0xB5756B87989661E1, 152}, // near the Giant's Cap (in a Wild Area) // ? second full table + {0x7AB83D18C831DDEB, 152}, // near the Giant's Cap (in a Wild Area) // ? third full table + {0xDBEF8A8593377AAA, 152}, // near the Giant's Cap (in a Wild Area) // Underground Spawns Solrock + {0x066F97F8765BC22D, 150}, // on the Hammerlocke Hills (in a Wild Area) // Flying Spawns Unfezant/Corvisquire + {0x87A97AFF94BC6CF2, 154}, // at the Lake of Outrage (in a Wild Area) // Surfing + {0x94289204B628522C, 008}, // in the Slumbering Weald // early + {0x5D02F15C043B872E, 008}, // in the Slumbering Weald // late + {0xA4945486A2B97DFF, 018}, // on Route 2 // Surfing + {0xAC1187E9EC166853, 092}, // on Route 9 (in Circhester Bay) // Surfing - // DLC 1 - Isle of Armor - {0x908A64718CA374E6, 164}, // in the Fields of Honor - {0x908A63718CA37333, 166}, // in the Soothing Wetlands - {0x908A62718CA37180, 168}, // in the Forest of Focus - {0x908A69718CA37D65, 170}, // on Challenge Beach - {0x908A68718CA37BB2, 172}, // in Brawlers' Cave - {0x908A67718CA379FF, 174}, // on Challenge Road - {0x908A66718CA3784C, 176}, // in Courageous Cavern - {0x908A6D718CA38431, 178}, // in Loop Lagoon - {0x908A6C718CA3827E, 180}, // in the Training Lowlands - {0x90875F718CA13690, 182}, // in Warm-Up Tunnel - {0x908760718CA13843, 184}, // in the Potbottom Desert - {0x909170718CA9A7F8, 186}, // in the Workout Sea - {0x909173718CA9AD11, 188}, // in the Stepping-Stone Sea - {0x909172718CA9AB5E, 190}, // in the Insular Sea - {0x909175718CA9B077, 192}, // in the Honeycalm Sea - {0x908DEC718CA691D5, 194}, // on Honeycalm Island + // DLC 1 - Isle of Armor + {0x908A64718CA374E6, 164}, // in the Fields of Honor + {0x908A63718CA37333, 166}, // in the Soothing Wetlands + {0x908A62718CA37180, 168}, // in the Forest of Focus + {0x908A69718CA37D65, 170}, // on Challenge Beach + {0x908A68718CA37BB2, 172}, // in Brawlers' Cave + {0x908A67718CA379FF, 174}, // on Challenge Road + {0x908A66718CA3784C, 176}, // in Courageous Cavern + {0x908A6D718CA38431, 178}, // in Loop Lagoon + {0x908A6C718CA3827E, 180}, // in the Training Lowlands + {0x90875F718CA13690, 182}, // in Warm-Up Tunnel + {0x908760718CA13843, 184}, // in the Potbottom Desert + {0x909170718CA9A7F8, 186}, // in the Workout Sea + {0x909173718CA9AD11, 188}, // in the Stepping-Stone Sea + {0x909172718CA9AB5E, 190}, // in the Insular Sea + {0x909175718CA9B077, 192}, // in the Honeycalm Sea + {0x908DEC718CA691D5, 194}, // on Honeycalm Island - {0x525D03DF0309D804, 164}, // in the Fields of Honor // Ground Spawns - {0xB0621052994A5089, 164}, // in the Fields of Honor // Surfing - {0x91B1D1436BAF5871, 164}, // in the Fields of Honor // Beach - {0xC449DFAB894F632C, 178}, // in Loop Lagoon // Beach - {0x273693DD91D7BD10, 170}, // on Challenge Beach // Beach - {0xD61582D408C39E60, 170}, // on Challenge Beach // Surfing (River) - {0xBECC9623CD3E8C77, 166}, // in the Soothing Wetlands // Ground Spawns - {0x1C051CB6F97C2068, 166}, // in the Soothing Wetlands // Puddles - {0xBC028EF260AD9406, 168}, // in the Forest of Focus // Ground Spawns - {0x32AB88FC9797DC83, 168}, // in the Forest of Focus // Surfing - {0x39D078468AA0DCC1, 170}, // on Challenge Beach // Ground Spawns - {0x3BFB22D0FB5B42D2, 170}, // on Challenge Beach // Surfing (Ocean) - {0x2B1DF6E85F9BAE28, 172}, // in Brawlers' Cave // Ground Spawns - {0x36FE81B956D0DCB5, 172}, // in Brawlers' Cave // Surfing - {0xBBAA199D0705405B, 174}, // on Challenge Road // Ground Spawns - {0xFB9A7FD6D979C6DA, 176}, // in Courageous Cavern // Ground Spawns - {0xBC0E1701C0276FCF, 176}, // in Courageous Cavern // Surfing - {0xAC2ED08E980FCFC5, 178}, // in Loop Lagoon // Ground Spawns - {0x7D2E205E8E300EE1, 178}, // in Loop Lagoon // Water Spawns - {0x67E3FF10EB64FB79, 180}, // in the Training Lowlands // Beach - {0x85E286D82C666BBC, 180}, // in the Training Lowlands // Ground Spawns - {0x95E125D2EE3ED656, 182}, // in Warm-up Tunnel - {0xA7F495799F209587, 184}, // in the Potbottom Desert - {0x30AAD92559FCE81E, 186}, // in the Workout Sea // Ground Spawns - {0x6F748A46C8E3802C, 186}, // in the Workout Sea // Surfing - {0x97A3E0687E3C5B01, 188}, // in the Stepping-Stone Sea // Surfing - {0xDDDFF88957FD5B5C, 190}, // in the Insular Sea // Ground Spawns - {0xF3036CD294CE9365, 188}, // in the Stepping-Stone Sea // Ground Spawns - {0xFB9BB438425D58DA, 190}, // in the Insular Sea // Surfing - {0xC16C1E2A1B5FFE87, 192}, // in the Honeycalm Sea // Surfing - {0x081D7EF6A1C192B1, 194}, // on Honeycalm Island // Ground Spawns - {0x86EFBF49516B5555, 194}, // on Honeycalm Island // Surfing - {0x39AB700A9F1AB71F, 180}, // in the Training Lowlands // Surfing - {0x96C6A2A36131F383, 188}, // in the Stepping-Stone Sea // Sharpedo - {0xC92D06352150C78A, 190}, // in the Insular Sea // Sharpedo - {0xED1F9772AA35C3CD, 186}, // in the Workout Sea // Sharpedo - {0x9C0049D3E6129924, 192}, // in the Honeycalm Sea // Sharpedo + {0x525D03DF0309D804, 164}, // in the Fields of Honor // Ground Spawns + {0xB0621052994A5089, 164}, // in the Fields of Honor // Surfing + {0x91B1D1436BAF5871, 164}, // in the Fields of Honor // Beach + {0xC449DFAB894F632C, 178}, // in Loop Lagoon // Beach + {0x273693DD91D7BD10, 170}, // on Challenge Beach // Beach + {0xD61582D408C39E60, 170}, // on Challenge Beach // Surfing (River) + {0xBECC9623CD3E8C77, 166}, // in the Soothing Wetlands // Ground Spawns + {0x1C051CB6F97C2068, 166}, // in the Soothing Wetlands // Puddles + {0xBC028EF260AD9406, 168}, // in the Forest of Focus // Ground Spawns + {0x32AB88FC9797DC83, 168}, // in the Forest of Focus // Surfing + {0x39D078468AA0DCC1, 170}, // on Challenge Beach // Ground Spawns + {0x3BFB22D0FB5B42D2, 170}, // on Challenge Beach // Surfing (Ocean) + {0x2B1DF6E85F9BAE28, 172}, // in Brawlers' Cave // Ground Spawns + {0x36FE81B956D0DCB5, 172}, // in Brawlers' Cave // Surfing + {0xBBAA199D0705405B, 174}, // on Challenge Road // Ground Spawns + {0xFB9A7FD6D979C6DA, 176}, // in Courageous Cavern // Ground Spawns + {0xBC0E1701C0276FCF, 176}, // in Courageous Cavern // Surfing + {0xAC2ED08E980FCFC5, 178}, // in Loop Lagoon // Ground Spawns + {0x7D2E205E8E300EE1, 178}, // in Loop Lagoon // Water Spawns + {0x67E3FF10EB64FB79, 180}, // in the Training Lowlands // Beach + {0x85E286D82C666BBC, 180}, // in the Training Lowlands // Ground Spawns + {0x95E125D2EE3ED656, 182}, // in Warm-up Tunnel + {0xA7F495799F209587, 184}, // in the Potbottom Desert + {0x30AAD92559FCE81E, 186}, // in the Workout Sea // Ground Spawns + {0x6F748A46C8E3802C, 186}, // in the Workout Sea // Surfing + {0x97A3E0687E3C5B01, 188}, // in the Stepping-Stone Sea // Surfing + {0xDDDFF88957FD5B5C, 190}, // in the Insular Sea // Ground Spawns + {0xF3036CD294CE9365, 188}, // in the Stepping-Stone Sea // Ground Spawns + {0xFB9BB438425D58DA, 190}, // in the Insular Sea // Surfing + {0xC16C1E2A1B5FFE87, 192}, // in the Honeycalm Sea // Surfing + {0x081D7EF6A1C192B1, 194}, // on Honeycalm Island // Ground Spawns + {0x86EFBF49516B5555, 194}, // on Honeycalm Island // Surfing + {0x39AB700A9F1AB71F, 180}, // in the Training Lowlands // Surfing + {0x96C6A2A36131F383, 188}, // in the Stepping-Stone Sea // Sharpedo + {0xC92D06352150C78A, 190}, // in the Insular Sea // Sharpedo + {0xED1F9772AA35C3CD, 186}, // in the Workout Sea // Sharpedo + {0x9C0049D3E6129924, 192}, // in the Honeycalm Sea // Sharpedo - // DLC 2 - Crown Tundra - {0x87E14B7187BC1CC1, 204}, // on Slippery Slope - {0x87E1487187BC17A8, 206}, // in Freezington - {0x87E1497187BC195B, 208}, // in Frostpoint Field - {0x87E14E7187BC21DA, 210}, // in the Giant's Bed - {0x87E14F7187BC238D, 212}, // in the Old Cemetery - {0x87E14C7187BC1E74, 214}, // on Snowslide Slope - {0x87E14D7187BC2027, 216}, // in the Tunnel to the Top - {0x87E1427187BC0D76, 218}, // on the Path to the Peak - {0x87E1437187BC0F29, 220}, // at the Crown Shrine - {0x87E4507187BE5B17, 222}, // at the Giant's Foot - {0x87E44F7187BE5964, 224}, // in Roaring-Sea Caves - {0x87E4527187BE5E7D, 226}, // at the Frigid Sea - {0x87E4517187BE5CCA, 228}, // in Three-Point Pass - {0x87DA3F7187B5E9AF, 230}, // at Ballimere Lake - {0x87DA407187B5EB62, 232}, // in Lakeside Cave - {0x87DA417187B5ED15, 234}, // at Dyna Tree Hill + // DLC 2 - Crown Tundra + {0x87E14B7187BC1CC1, 204}, // on Slippery Slope + {0x87E1487187BC17A8, 206}, // in Freezington + {0x87E1497187BC195B, 208}, // in Frostpoint Field + {0x87E14E7187BC21DA, 210}, // in the Giant's Bed + {0x87E14F7187BC238D, 212}, // in the Old Cemetery + {0x87E14C7187BC1E74, 214}, // on Snowslide Slope + {0x87E14D7187BC2027, 216}, // in the Tunnel to the Top + {0x87E1427187BC0D76, 218}, // on the Path to the Peak + {0x87E1437187BC0F29, 220}, // at the Crown Shrine + {0x87E4507187BE5B17, 222}, // at the Giant's Foot + {0x87E44F7187BE5964, 224}, // in Roaring-Sea Caves + {0x87E4527187BE5E7D, 226}, // at the Frigid Sea + {0x87E4517187BE5CCA, 228}, // in Three-Point Pass + {0x87DA3F7187B5E9AF, 230}, // at Ballimere Lake + {0x87DA407187B5EB62, 232}, // in Lakeside Cave + {0x87DA417187B5ED15, 234}, // at Dyna Tree Hill - {0xD6EA3DE40B009E55, 204}, // on Slippery Slope - {0xADF616908BD308DF, 208}, // in Frostpoint Field - {0x308C5EB6A846D1F0, 210}, // in the Giant's Bed - {0x50E781F91B97C049, 212}, // in the Old Cemetery - {0xC303110BF1EC3322, 214}, // on Snowslide Slope - {0xB768660B0BF4C0C3, 216}, // in the Tunnel to the Top - {0xFCB78AFCCECAF094, 218}, // on the Path to the Peak - {0xA345459C03EA6673, 222}, // at the Giant's Foot - {0xE4A982819ACF7292, 224}, // in Roaring-Sea Caves - {0x18AAF85178C7B839, 226}, // at the Frigid Sea - {0x3EC6FCDC0C77D460, 228}, // in Three-Point Pass - {0xE5225F9325CCA74B, 230}, // at Ballimere Lake - {0x2F1B41507D695958, 232}, // in Lakeside Cave + {0xD6EA3DE40B009E55, 204}, // on Slippery Slope + {0xADF616908BD308DF, 208}, // in Frostpoint Field + {0x308C5EB6A846D1F0, 210}, // in the Giant's Bed + {0x50E781F91B97C049, 212}, // in the Old Cemetery + {0xC303110BF1EC3322, 214}, // on Snowslide Slope + {0xB768660B0BF4C0C3, 216}, // in the Tunnel to the Top + {0xFCB78AFCCECAF094, 218}, // on the Path to the Peak + {0xA345459C03EA6673, 222}, // at the Giant's Foot + {0xE4A982819ACF7292, 224}, // in Roaring-Sea Caves + {0x18AAF85178C7B839, 226}, // at the Frigid Sea + {0x3EC6FCDC0C77D460, 228}, // in Three-Point Pass + {0xE5225F9325CCA74B, 230}, // at Ballimere Lake + {0x2F1B41507D695958, 232}, // in Lakeside Cave - {0xF8A59FCA719D1EAE, 210}, // in the Giant's Bed (Surfing), also used for 222 (in the Giant's Foot Surfing) - {0x55D8F226A42368B7, 224}, // in Roaring-Sea Caves (Surfing) - {0x78536116469DC44D, 226}, // at the Frigid Sea (Surfing) - {0x9BDD6D11FFBEDA3F, 230}, // at Ballimere Lake (Surfing) - }; + {0xF8A59FCA719D1EAE, 210}, // in the Giant's Bed (Surfing), also used for 222 (in the Giant's Foot Surfing) + {0x55D8F226A42368B7, 224}, // in Roaring-Sea Caves (Surfing) + {0x78536116469DC44D, 226}, // at the Frigid Sea (Surfing) + {0x9BDD6D11FFBEDA3F, 230}, // at Ballimere Lake (Surfing) + }; - public static readonly IReadOnlyDictionary Zones = new Dictionary - { - { 0x078BC1FF1A657844, "Route 1" }, - { 0x10355EFF1F4DB0B5, "Route 2" }, - { 0x776776717EA4483E, "Rolling Fields" }, - { 0x776777717EA449F1, "Dappled Grove" }, - { 0x776778717EA44BA4, "Watchtower Ruins" }, - { 0x776779717EA44D57, "East Lake Axewell" }, - { 0x77677A717EA44F0A, "West Lake Axewell" }, - { 0x77677B717EA450BD, "Axew's Eye" }, - { 0x77676C717EA43740, "South Lake Miloch" }, - { 0x77676D717EA438F3, "Giant's Seat" }, - { 0x776AFA717EA75E61, "North Lake Miloch" }, - { 0x194B97FF2492111A, "Route 3" }, - { 0x776E81717EAA799D, "Motostoke Riverbank" }, - { 0x776E7E717EAA7484, "Bridge Field" }, - { 0xDBCF5CFF0180B073, "Route 4" }, - { 0x8F67CD45F405D66E, "Slumbering Weald (Low Level)" }, - { 0xE0D6E5E78C91F4A7, "City of Motostoke" }, - { 0xE4E595FF06C510D8, "Route 5" }, - { 0x1C7150C0594994E5, "Town of Hulbury" }, - { 0x7D3B7A45E97D4A51, "Galar Mine No. 2" }, - { 0x75D83E45E5AA7953, "Galar Mine" }, - { 0x7D3B7745E97D4538, "Motostoke Outskirts" }, - { 0xA88AC04602050B95, "Glimwood Tangle" }, - { 0xEDFC32FF0C0A1B29, "Route 6" }, - { 0xF55F6BFF0FDCE70E, "Route 7" }, - { 0x449AE0FF3D19D777, "Route 8" }, - { 0x4BFDF9FF40EC6CFC, "Route 8 (on Steamdrift Way)" }, - { 0x4BFDFCFF40EC7215, "Route 9" }, - { 0x4BFDF6FF40EC67E3, "Route 9 (in Circhester Bay)" }, - { 0x4BFDFBFF40EC7062, "Route 9 (in Outer Spikemuth)" }, - { 0xB332930807F9D48A, "Route 10 (Near Station)" }, - { 0x7771E5717EAD5960, "Stony Wilderness" }, - { 0x7771E8717EAD5E79, "Dusty Bowl" }, - { 0x7771E7717EAD5CC6, "Giant's Mirror" }, - { 0x7771EA717EAD61DF, "Hammerlocke Hills" }, - { 0x7771E9717EAD602C, "Giant's Cap" }, - { 0x7771EC717EAD6545, "Lake of Outrage" }, - { 0x10355BFF1F4DAB9C, "Route 2 (High Level)" }, - { 0xB332920807F9D2D7, "Route 10" }, - { 0x8F67CB45F405D308, "Slumbering Weald (High Level)" }, - { 0xCD6E4FBCE1466F32, "Route 1" }, - { 0xDF686EC613544BD1, "Route 2" }, - { 0xD602B2A66C268F7C, "Rolling Fields" }, - { 0x458C9CA2C0087385, "Dappled Grove" }, - { 0xE20E6AE30AAA57D2, "Watchtower Ruins" }, - { 0xEEEEAC06BAC8D0B3, "East Lake Axewell" }, - { 0xF8D1E527F7B21FA0, "West Lake Axewell" }, - { 0xB6CFE90E0378FD79, "Axew's Eye" }, - { 0x520D8DD522E9A4C6, "South Lake Miloch" }, - { 0xBC7237A0392D8837, "Giant's Seat" }, - { 0xB67C706F5BAE9E35, "North Lake Miloch" }, - { 0xDA910F69A1B92FED, "West Lake Axewell (Surfing)" }, - { 0x7C17DB1B430F9543, "South Lake Miloch (Surfing)" }, - { 0xCC0F8A437312B8AC, "East Lake Axewell (Surfing)" }, - { 0x8BE2F6160986FB8E, "North Lake Miloch (Surfing)" }, - { 0x0E8392C0A57D5830, "Route 3" }, - { 0x82A7A328A26B9057, "Galar Mine" }, - { 0x5B2BC38E044EC2B7, "Route 4" }, - { 0x8D68276C03A332BE, "Route 5" }, - { 0x16D2FC4840A658A5, "Galar Mine No. 2" }, - { 0x3D6D58A96894575E, "Motostoke Outskirts" }, - { 0x6AA652641154B119, "Motostoke Riverbank" }, - { 0x36A5DC94335E1E72, "Bridge Field" }, - { 0xE503416A1C05765D, "Route 6" }, - { 0x201EF8E9D2A32D71, "Glimwood Tangle" }, - { 0x42312695C904658C, "Route 7" }, - { 0x1B95A78295F6F213, "Route 8" }, - { 0xAADAC3CB6A1DFE8A, "Route 8 (on Steamdrift Way)" }, - { 0x9116B224702CDCF1, "Route 9" }, - { 0xCDD3B5660D2E5E67, "Route 9 (in Circhester Bay)" }, - { 0x5A3B8F8147272058, "Route 9 (in Outer Spikemuth)" }, - { 0xA93101EA38598995, "Route 9 (Surfing)" }, - { 0x0181225223DE5420, "Route 10 (Near Station)" }, - { 0x1F0F1AE1818C4326, "Stony Wilderness" }, - { 0xAD11B3F3B2AC662D, "Dusty Bowl" }, - { 0xCD9719B2E64F2AA4, "Giant's Mirror" }, - { 0xCD48625EDC10CBFB, "Hammerlocke Hills" }, - { 0x712F3056573E23FA, "Giant's Cap" }, - { 0x593196758BA16B61, "Lake of Outrage" }, - { 0xF79DE930E6F50533, "Route 10" }, - { 0xA26A4595F72EDAEA, "Route 2 (High Level)" }, - { 0x56580C94EDFCE664, "Route 3 (Garbage)" }, - { 0xCB38FEA3F71C3958, "Rolling Fields (Flying)" }, - { 0x1F174D36062B8C38, "Rolling Fields (Ground)" }, - { 0x23017513039A78E7, "Rolling Fields (2)" }, - { 0xF1BA4AAD9AAB2C1A, "Watchtower Ruins (Flying)" }, - { 0x3D2E746F9D3F5CB5, "East Lake Axewell (Flying)" }, - { 0x6E121A9CE4F58F1E, "East Lake Axewell (Flying)" }, - { 0x3171A0C61793816E, "South Lake Miloch (Flying)" }, - { 0x198E4023A1B2DDEF, "South Lake Miloch (2)" }, - { 0xFAB1C08E70C0F1CA, "Motostoke Riverbank (Surfing)" }, - { 0xB9F76CEE459CEC07, "Bridge Field (Surfing)" }, - { 0x5F4E0AB29FD3F13A, "Bridge Field (Flying)" }, - { 0xF603DEA4177200EA, "Stony Wilderness (2)" }, - { 0x76EE4E28DD28374E, "Stony Wilderness (Flying)" }, - { 0x3F264B6FCB5647B4, "Giant's Mirror (Flying)" }, - { 0x2D887A1CA9B1B99A, "Dusty Bowl (Flying)" }, - { 0x2BE7E6A8901ECC20, "Giant's Mirror (Ground)" }, - { 0x39F0170769BF4524, "Dusty Bowl and Giant's Mirror (Surfing)" }, - { 0xB2067FBCF8D5C7BA, "Giant's Cap (Ground)" }, - { 0x48B9525945EE48B5, "Stony Wilderness (3)" }, - { 0xB5756B87989661E1, "Giant's Cap (2)" }, - { 0x7AB83D18C831DDEB, "Giant's Cap (3)" }, - { 0xDBEF8A8593377AAA, "Giant's Cap (Lunatone/Solrock)" }, - { 0x066F97F8765BC22D, "Hammerlocke Hills (Flying)" }, - { 0x87A97AFF94BC6CF2, "Lake of Outrage (Surfing)" }, - { 0x94289204B628522C, "Slumbering Weald (Low Level)" }, - { 0x5D02F15C043B872E, "Slumbering Weald (High Level)" }, - { 0xA4945486A2B97DFF, "Route 2 (Surfing)" }, - { 0xAC1187E9EC166853, "Route 9 (in Circhester Bay) (Surfing)" }, + public static readonly IReadOnlyDictionary Zones = new Dictionary + { + { 0x078BC1FF1A657844, "Route 1" }, + { 0x10355EFF1F4DB0B5, "Route 2" }, + { 0x776776717EA4483E, "Rolling Fields" }, + { 0x776777717EA449F1, "Dappled Grove" }, + { 0x776778717EA44BA4, "Watchtower Ruins" }, + { 0x776779717EA44D57, "East Lake Axewell" }, + { 0x77677A717EA44F0A, "West Lake Axewell" }, + { 0x77677B717EA450BD, "Axew's Eye" }, + { 0x77676C717EA43740, "South Lake Miloch" }, + { 0x77676D717EA438F3, "Giant's Seat" }, + { 0x776AFA717EA75E61, "North Lake Miloch" }, + { 0x194B97FF2492111A, "Route 3" }, + { 0x776E81717EAA799D, "Motostoke Riverbank" }, + { 0x776E7E717EAA7484, "Bridge Field" }, + { 0xDBCF5CFF0180B073, "Route 4" }, + { 0x8F67CD45F405D66E, "Slumbering Weald (Low Level)" }, + { 0xE0D6E5E78C91F4A7, "City of Motostoke" }, + { 0xE4E595FF06C510D8, "Route 5" }, + { 0x1C7150C0594994E5, "Town of Hulbury" }, + { 0x7D3B7A45E97D4A51, "Galar Mine No. 2" }, + { 0x75D83E45E5AA7953, "Galar Mine" }, + { 0x7D3B7745E97D4538, "Motostoke Outskirts" }, + { 0xA88AC04602050B95, "Glimwood Tangle" }, + { 0xEDFC32FF0C0A1B29, "Route 6" }, + { 0xF55F6BFF0FDCE70E, "Route 7" }, + { 0x449AE0FF3D19D777, "Route 8" }, + { 0x4BFDF9FF40EC6CFC, "Route 8 (on Steamdrift Way)" }, + { 0x4BFDFCFF40EC7215, "Route 9" }, + { 0x4BFDF6FF40EC67E3, "Route 9 (in Circhester Bay)" }, + { 0x4BFDFBFF40EC7062, "Route 9 (in Outer Spikemuth)" }, + { 0xB332930807F9D48A, "Route 10 (Near Station)" }, + { 0x7771E5717EAD5960, "Stony Wilderness" }, + { 0x7771E8717EAD5E79, "Dusty Bowl" }, + { 0x7771E7717EAD5CC6, "Giant's Mirror" }, + { 0x7771EA717EAD61DF, "Hammerlocke Hills" }, + { 0x7771E9717EAD602C, "Giant's Cap" }, + { 0x7771EC717EAD6545, "Lake of Outrage" }, + { 0x10355BFF1F4DAB9C, "Route 2 (High Level)" }, + { 0xB332920807F9D2D7, "Route 10" }, + { 0x8F67CB45F405D308, "Slumbering Weald (High Level)" }, + { 0xCD6E4FBCE1466F32, "Route 1" }, + { 0xDF686EC613544BD1, "Route 2" }, + { 0xD602B2A66C268F7C, "Rolling Fields" }, + { 0x458C9CA2C0087385, "Dappled Grove" }, + { 0xE20E6AE30AAA57D2, "Watchtower Ruins" }, + { 0xEEEEAC06BAC8D0B3, "East Lake Axewell" }, + { 0xF8D1E527F7B21FA0, "West Lake Axewell" }, + { 0xB6CFE90E0378FD79, "Axew's Eye" }, + { 0x520D8DD522E9A4C6, "South Lake Miloch" }, + { 0xBC7237A0392D8837, "Giant's Seat" }, + { 0xB67C706F5BAE9E35, "North Lake Miloch" }, + { 0xDA910F69A1B92FED, "West Lake Axewell (Surfing)" }, + { 0x7C17DB1B430F9543, "South Lake Miloch (Surfing)" }, + { 0xCC0F8A437312B8AC, "East Lake Axewell (Surfing)" }, + { 0x8BE2F6160986FB8E, "North Lake Miloch (Surfing)" }, + { 0x0E8392C0A57D5830, "Route 3" }, + { 0x82A7A328A26B9057, "Galar Mine" }, + { 0x5B2BC38E044EC2B7, "Route 4" }, + { 0x8D68276C03A332BE, "Route 5" }, + { 0x16D2FC4840A658A5, "Galar Mine No. 2" }, + { 0x3D6D58A96894575E, "Motostoke Outskirts" }, + { 0x6AA652641154B119, "Motostoke Riverbank" }, + { 0x36A5DC94335E1E72, "Bridge Field" }, + { 0xE503416A1C05765D, "Route 6" }, + { 0x201EF8E9D2A32D71, "Glimwood Tangle" }, + { 0x42312695C904658C, "Route 7" }, + { 0x1B95A78295F6F213, "Route 8" }, + { 0xAADAC3CB6A1DFE8A, "Route 8 (on Steamdrift Way)" }, + { 0x9116B224702CDCF1, "Route 9" }, + { 0xCDD3B5660D2E5E67, "Route 9 (in Circhester Bay)" }, + { 0x5A3B8F8147272058, "Route 9 (in Outer Spikemuth)" }, + { 0xA93101EA38598995, "Route 9 (Surfing)" }, + { 0x0181225223DE5420, "Route 10 (Near Station)" }, + { 0x1F0F1AE1818C4326, "Stony Wilderness" }, + { 0xAD11B3F3B2AC662D, "Dusty Bowl" }, + { 0xCD9719B2E64F2AA4, "Giant's Mirror" }, + { 0xCD48625EDC10CBFB, "Hammerlocke Hills" }, + { 0x712F3056573E23FA, "Giant's Cap" }, + { 0x593196758BA16B61, "Lake of Outrage" }, + { 0xF79DE930E6F50533, "Route 10" }, + { 0xA26A4595F72EDAEA, "Route 2 (High Level)" }, + { 0x56580C94EDFCE664, "Route 3 (Garbage)" }, + { 0xCB38FEA3F71C3958, "Rolling Fields (Flying)" }, + { 0x1F174D36062B8C38, "Rolling Fields (Ground)" }, + { 0x23017513039A78E7, "Rolling Fields (2)" }, + { 0xF1BA4AAD9AAB2C1A, "Watchtower Ruins (Flying)" }, + { 0x3D2E746F9D3F5CB5, "East Lake Axewell (Flying)" }, + { 0x6E121A9CE4F58F1E, "East Lake Axewell (Flying)" }, + { 0x3171A0C61793816E, "South Lake Miloch (Flying)" }, + { 0x198E4023A1B2DDEF, "South Lake Miloch (2)" }, + { 0xFAB1C08E70C0F1CA, "Motostoke Riverbank (Surfing)" }, + { 0xB9F76CEE459CEC07, "Bridge Field (Surfing)" }, + { 0x5F4E0AB29FD3F13A, "Bridge Field (Flying)" }, + { 0xF603DEA4177200EA, "Stony Wilderness (2)" }, + { 0x76EE4E28DD28374E, "Stony Wilderness (Flying)" }, + { 0x3F264B6FCB5647B4, "Giant's Mirror (Flying)" }, + { 0x2D887A1CA9B1B99A, "Dusty Bowl (Flying)" }, + { 0x2BE7E6A8901ECC20, "Giant's Mirror (Ground)" }, + { 0x39F0170769BF4524, "Dusty Bowl and Giant's Mirror (Surfing)" }, + { 0xB2067FBCF8D5C7BA, "Giant's Cap (Ground)" }, + { 0x48B9525945EE48B5, "Stony Wilderness (3)" }, + { 0xB5756B87989661E1, "Giant's Cap (2)" }, + { 0x7AB83D18C831DDEB, "Giant's Cap (3)" }, + { 0xDBEF8A8593377AAA, "Giant's Cap (Lunatone/Solrock)" }, + { 0x066F97F8765BC22D, "Hammerlocke Hills (Flying)" }, + { 0x87A97AFF94BC6CF2, "Lake of Outrage (Surfing)" }, + { 0x94289204B628522C, "Slumbering Weald (Low Level)" }, + { 0x5D02F15C043B872E, "Slumbering Weald (High Level)" }, + { 0xA4945486A2B97DFF, "Route 2 (Surfing)" }, + { 0xAC1187E9EC166853, "Route 9 (in Circhester Bay) (Surfing)" }, - // DLC 1 - Isle of Armor - { 0x908A64718CA374E6, "Fields of Honor" }, - { 0x908A63718CA37333, "Soothing Wetlands" }, - { 0x908A62718CA37180, "Forest of Focus" }, - { 0x908A69718CA37D65, "Challenge Beach" }, - { 0x908A68718CA37BB2, "Brawlers' Cave" }, - { 0x908A67718CA379FF, "Challenge Road" }, - { 0x908A66718CA3784C, "Courageous Cavern" }, - { 0x908A6D718CA38431, "Loop Lagoon" }, - { 0x908A6C718CA3827E, "Training Lowlands" }, - { 0x90875F718CA13690, "Warm-Up Tunnel" }, - { 0x908760718CA13843, "Potbottom Desert" }, - { 0x909170718CA9A7F8, "Workout Sea" }, - { 0x909173718CA9AD11, "Stepping-Stone Sea" }, - { 0x909172718CA9AB5E, "Insular Sea" }, - { 0x909175718CA9B077, "Honeycalm Sea" }, - { 0x908DEC718CA691D5, "Honeycalm Island" }, + // DLC 1 - Isle of Armor + { 0x908A64718CA374E6, "Fields of Honor" }, + { 0x908A63718CA37333, "Soothing Wetlands" }, + { 0x908A62718CA37180, "Forest of Focus" }, + { 0x908A69718CA37D65, "Challenge Beach" }, + { 0x908A68718CA37BB2, "Brawlers' Cave" }, + { 0x908A67718CA379FF, "Challenge Road" }, + { 0x908A66718CA3784C, "Courageous Cavern" }, + { 0x908A6D718CA38431, "Loop Lagoon" }, + { 0x908A6C718CA3827E, "Training Lowlands" }, + { 0x90875F718CA13690, "Warm-Up Tunnel" }, + { 0x908760718CA13843, "Potbottom Desert" }, + { 0x909170718CA9A7F8, "Workout Sea" }, + { 0x909173718CA9AD11, "Stepping-Stone Sea" }, + { 0x909172718CA9AB5E, "Insular Sea" }, + { 0x909175718CA9B077, "Honeycalm Sea" }, + { 0x908DEC718CA691D5, "Honeycalm Island" }, - { 0x525D03DF0309D804, "Fields of Honor" }, - { 0xB0621052994A5089, "Fields of Honor (Surfing)" }, - { 0x91B1D1436BAF5871, "Fields of Honor (Beach)" }, - { 0xC449DFAB894F632C, "Loop Lagoon (Beach)" }, - { 0x273693DD91D7BD10, "Challenge Beach (Beach)" }, - { 0xD61582D408C39E60, "Challenge Beach (Surfing - River)" }, - { 0xBECC9623CD3E8C77, "Soothing Wetlands" }, - { 0x1C051CB6F97C2068, "Soothing Wetlands (Puddles)" }, - { 0xBC028EF260AD9406, "Forest of Focus" }, - { 0x32AB88FC9797DC83, "Forest of Focus (Surfing)" }, - { 0x39D078468AA0DCC1, "Challenge Beach" }, - { 0x3BFB22D0FB5B42D2, "Challenge Beach (Surfing - Ocean)" }, - { 0x2B1DF6E85F9BAE28, "Brawlers' Cave" }, - { 0x36FE81B956D0DCB5, "Brawlers' Cave (Surfing)" }, - { 0xBBAA199D0705405B, "Challenge Road" }, - { 0xFB9A7FD6D979C6DA, "Courageous Cavern" }, - { 0xBC0E1701C0276FCF, "Courageous Cavern (Surfing)" }, - { 0xAC2ED08E980FCFC5, "Loop Lagoon" }, - { 0x7D2E205E8E300EE1, "Loop Lagoon (Surfing)" }, - { 0x67E3FF10EB64FB79, "Training Lowlands (Beach)" }, - { 0x85E286D82C666BBC, "Training Lowlands" }, - { 0x95E125D2EE3ED656, "Warm-up Tunnel" }, - { 0xA7F495799F209587, "Potbottom Desert" }, - { 0x30AAD92559FCE81E, "Workout Sea" }, - { 0x6F748A46C8E3802C, "Workout Sea (Surfing)" }, - { 0x97A3E0687E3C5B01, "Stepping-Stone Sea (Surfing)" }, - { 0xDDDFF88957FD5B5C, "Insular Sea" }, - { 0xF3036CD294CE9365, "Stepping-Stone Sea" }, - { 0xFB9BB438425D58DA, "Insular Sea (Surfing)" }, - { 0xC16C1E2A1B5FFE87, "Honeycalm Sea (Surfing)" }, - { 0x081D7EF6A1C192B1, "Honeycalm Island" }, - { 0x86EFBF49516B5555, "Honeycalm Island (Surfing)" }, - { 0x39AB700A9F1AB71F, "Training Lowlands (Surfing)" }, - { 0x96C6A2A36131F383, "Stepping-Stone Sea (Sharpedo)" }, - { 0xC92D06352150C78A, "Insular Sea (Sharpedo)" }, - { 0xED1F9772AA35C3CD, "Workout Sea (Sharpedo)" }, - { 0x9C0049D3E6129924, "Honeycalm Sea (Sharpedo)" }, + { 0x525D03DF0309D804, "Fields of Honor" }, + { 0xB0621052994A5089, "Fields of Honor (Surfing)" }, + { 0x91B1D1436BAF5871, "Fields of Honor (Beach)" }, + { 0xC449DFAB894F632C, "Loop Lagoon (Beach)" }, + { 0x273693DD91D7BD10, "Challenge Beach (Beach)" }, + { 0xD61582D408C39E60, "Challenge Beach (Surfing - River)" }, + { 0xBECC9623CD3E8C77, "Soothing Wetlands" }, + { 0x1C051CB6F97C2068, "Soothing Wetlands (Puddles)" }, + { 0xBC028EF260AD9406, "Forest of Focus" }, + { 0x32AB88FC9797DC83, "Forest of Focus (Surfing)" }, + { 0x39D078468AA0DCC1, "Challenge Beach" }, + { 0x3BFB22D0FB5B42D2, "Challenge Beach (Surfing - Ocean)" }, + { 0x2B1DF6E85F9BAE28, "Brawlers' Cave" }, + { 0x36FE81B956D0DCB5, "Brawlers' Cave (Surfing)" }, + { 0xBBAA199D0705405B, "Challenge Road" }, + { 0xFB9A7FD6D979C6DA, "Courageous Cavern" }, + { 0xBC0E1701C0276FCF, "Courageous Cavern (Surfing)" }, + { 0xAC2ED08E980FCFC5, "Loop Lagoon" }, + { 0x7D2E205E8E300EE1, "Loop Lagoon (Surfing)" }, + { 0x67E3FF10EB64FB79, "Training Lowlands (Beach)" }, + { 0x85E286D82C666BBC, "Training Lowlands" }, + { 0x95E125D2EE3ED656, "Warm-up Tunnel" }, + { 0xA7F495799F209587, "Potbottom Desert" }, + { 0x30AAD92559FCE81E, "Workout Sea" }, + { 0x6F748A46C8E3802C, "Workout Sea (Surfing)" }, + { 0x97A3E0687E3C5B01, "Stepping-Stone Sea (Surfing)" }, + { 0xDDDFF88957FD5B5C, "Insular Sea" }, + { 0xF3036CD294CE9365, "Stepping-Stone Sea" }, + { 0xFB9BB438425D58DA, "Insular Sea (Surfing)" }, + { 0xC16C1E2A1B5FFE87, "Honeycalm Sea (Surfing)" }, + { 0x081D7EF6A1C192B1, "Honeycalm Island" }, + { 0x86EFBF49516B5555, "Honeycalm Island (Surfing)" }, + { 0x39AB700A9F1AB71F, "Training Lowlands (Surfing)" }, + { 0x96C6A2A36131F383, "Stepping-Stone Sea (Sharpedo)" }, + { 0xC92D06352150C78A, "Insular Sea (Sharpedo)" }, + { 0xED1F9772AA35C3CD, "Workout Sea (Sharpedo)" }, + { 0x9C0049D3E6129924, "Honeycalm Sea (Sharpedo)" }, - // DLC 2 - Crown Tundra - { 0x87E14B7187BC1CC1, "Slippery Slope" }, - { 0x87E1487187BC17A8, "Freezington" }, - { 0x87E1497187BC195B, "Frostpoint Field" }, - { 0x87E14E7187BC21DA, "Giant's Bed" }, - { 0x87E14F7187BC238D, "Old Cemetery" }, - { 0x87E14C7187BC1E74, "Snowslide Slope" }, - { 0x87E14D7187BC2027, "Tunnel to the Top" }, - { 0x87E1427187BC0D76, "Path to the Peak" }, - { 0x87E1437187BC0F29, "Crown Shrine" }, - { 0x87E4507187BE5B17, "Giant's Foot" }, - { 0x87E44F7187BE5964, "Roaring-Sea Caves" }, - { 0x87E4527187BE5E7D, "Frigid Sea" }, - { 0x87E4517187BE5CCA, "Three-Point Pass" }, - { 0x87DA3F7187B5E9AF, "Ballimere Lake" }, - { 0x87DA407187B5EB62, "Lakeside Cave" }, - { 0x87DA417187B5ED15, "Dyna Tree Hill" }, + // DLC 2 - Crown Tundra + { 0x87E14B7187BC1CC1, "Slippery Slope" }, + { 0x87E1487187BC17A8, "Freezington" }, + { 0x87E1497187BC195B, "Frostpoint Field" }, + { 0x87E14E7187BC21DA, "Giant's Bed" }, + { 0x87E14F7187BC238D, "Old Cemetery" }, + { 0x87E14C7187BC1E74, "Snowslide Slope" }, + { 0x87E14D7187BC2027, "Tunnel to the Top" }, + { 0x87E1427187BC0D76, "Path to the Peak" }, + { 0x87E1437187BC0F29, "Crown Shrine" }, + { 0x87E4507187BE5B17, "Giant's Foot" }, + { 0x87E44F7187BE5964, "Roaring-Sea Caves" }, + { 0x87E4527187BE5E7D, "Frigid Sea" }, + { 0x87E4517187BE5CCA, "Three-Point Pass" }, + { 0x87DA3F7187B5E9AF, "Ballimere Lake" }, + { 0x87DA407187B5EB62, "Lakeside Cave" }, + { 0x87DA417187B5ED15, "Dyna Tree Hill" }, - { 0xD6EA3DE40B009E55, "Slippery Slope" }, - { 0xADF616908BD308DF, "Frostpoint Field" }, - { 0x308C5EB6A846D1F0, "Giant's Bed" }, - { 0x50E781F91B97C049, "Old Cemetery" }, - { 0xC303110BF1EC3322, "Snowslide Slope" }, - { 0xB768660B0BF4C0C3, "Tunnel to the Top" }, - { 0xFCB78AFCCECAF094, "Path to the Peak" }, - { 0xA345459C03EA6673, "Giant's Foot" }, - { 0xE4A982819ACF7292, "Roaring-Sea Caves" }, - { 0x18AAF85178C7B839, "Frigid Sea" }, - { 0x3EC6FCDC0C77D460, "Three-Point Pass" }, - { 0xE5225F9325CCA74B, "Ballimere Lake" }, - { 0x2F1B41507D695958, "Lakeside Cave" }, + { 0xD6EA3DE40B009E55, "Slippery Slope" }, + { 0xADF616908BD308DF, "Frostpoint Field" }, + { 0x308C5EB6A846D1F0, "Giant's Bed" }, + { 0x50E781F91B97C049, "Old Cemetery" }, + { 0xC303110BF1EC3322, "Snowslide Slope" }, + { 0xB768660B0BF4C0C3, "Tunnel to the Top" }, + { 0xFCB78AFCCECAF094, "Path to the Peak" }, + { 0xA345459C03EA6673, "Giant's Foot" }, + { 0xE4A982819ACF7292, "Roaring-Sea Caves" }, + { 0x18AAF85178C7B839, "Frigid Sea" }, + { 0x3EC6FCDC0C77D460, "Three-Point Pass" }, + { 0xE5225F9325CCA74B, "Ballimere Lake" }, + { 0x2F1B41507D695958, "Lakeside Cave" }, - { 0xF8A59FCA719D1EAE, "Giant's Bed / Giant's Foot (Surfing)" }, - { 0x55D8F226A42368B7, "Roaring-Sea Caves (Surfing)" }, - { 0x78536116469DC44D, "Frigid Sea (Surfing)" }, - { 0x9BDD6D11FFBEDA3F, "Ballimere Lake (Surfing)" }, - }; + { 0xF8A59FCA719D1EAE, "Giant's Bed / Giant's Foot (Surfing)" }, + { 0x55D8F226A42368B7, "Roaring-Sea Caves (Surfing)" }, + { 0x78536116469DC44D, "Frigid Sea (Surfing)" }, + { 0x9BDD6D11FFBEDA3F, "Ballimere Lake (Surfing)" }, + }; - public static readonly IReadOnlyDictionary ZoneType = new Dictionary - { - {0x078BC1FF1A657844, (byte)HiddenMain}, // on Route 1 - {0x10355EFF1F4DB0B5, (byte)HiddenMain}, // on Route 2 - {0x776776717EA4483E, (byte)HiddenMain}, // in the Rolling Fields (in a Wild Area) - {0x776777717EA449F1, (byte)HiddenMain}, // in the Dappled Grove (in a Wild Area) - {0x776778717EA44BA4, (byte)HiddenMain}, // at Watchtower Ruins (in a Wild Area) - {0x776779717EA44D57, (byte)HiddenMain}, // at East Lake Axewell (in a Wild Area) - {0x77677A717EA44F0A, (byte)HiddenMain}, // at West Lake Axewell (in a Wild Area) - {0x77677B717EA450BD, (byte)HiddenMain}, // on Axew's Eye (in a Wild Area) - {0x77676C717EA43740, (byte)HiddenMain}, // at South Lake Miloch (in a Wild Area) - {0x77676D717EA438F3, (byte)HiddenMain}, // near the Giant's Seat (in a Wild Area) - {0x776AFA717EA75E61, (byte)HiddenMain}, // at North Lake Miloch (in a Wild Area) - {0x194B97FF2492111A, (byte)HiddenMain}, // on Route 3 - {0x776E81717EAA799D, (byte)HiddenMain}, // at the Motostoke Riverbank (in a Wild Area) - {0x776E7E717EAA7484, (byte)HiddenMain}, // in Bridge Field (in a Wild Area) - {0xDBCF5CFF0180B073, (byte)HiddenMain}, // on Route 4 - {0x8F67CD45F405D66E, (byte)HiddenMain}, // in the Slumbering Weald - {0xE0D6E5E78C91F4A7, (byte)OnlyFishing}, // in the city of Motostoke - {0xE4E595FF06C510D8, (byte)HiddenMain}, // on Route 5 - {0x1C7150C0594994E5, (byte)OnlyFishing}, // in the town of Hulbury - {0x7D3B7A45E97D4A51, (byte)HiddenMain}, // in Galar Mine No. 2 - {0x75D83E45E5AA7953, (byte)HiddenMain}, // in Galar Mine - {0x7D3B7745E97D4538, (byte)HiddenMain}, // in the Motostoke Outskirts - {0xA88AC04602050B95, (byte)HiddenMain}, // in Glimwood Tangle - {0xEDFC32FF0C0A1B29, (byte)HiddenMain}, // on Route 6 - {0xF55F6BFF0FDCE70E, (byte)HiddenMain}, // on Route 7 - {0x449AE0FF3D19D777, (byte)HiddenMain}, // on Route 8 - {0x4BFDF9FF40EC6CFC, (byte)HiddenMain}, // on Route 8 (on Steamdrift Way) - {0x4BFDFCFF40EC7215, (byte)HiddenMain}, // on Route 9 - {0x4BFDF6FF40EC67E3, (byte)HiddenMain}, // on Route 9 (in Circhester Bay) - {0x4BFDFBFF40EC7062, (byte)HiddenMain}, // on Route 9 (in Outer Spikemuth) - {0xB332930807F9D48A, (byte)HiddenMain}, // on Route 10 // Near Station - {0x7771E5717EAD5960, (byte)HiddenMain}, // in the Stony Wilderness (in a Wild Area) - {0x7771E8717EAD5E79, (byte)HiddenMain}, // in Dusty Bowl (in a Wild Area) - {0x7771E7717EAD5CC6, (byte)HiddenMain}, // around the Giant's Mirror (in a Wild Area) - {0x7771EA717EAD61DF, (byte)HiddenMain}, // on the Hammerlocke Hills (in a Wild Area) - {0x7771E9717EAD602C, (byte)HiddenMain}, // near the Giant's Cap (in a Wild Area) - {0x7771EC717EAD6545, (byte)HiddenMain}, // at the Lake of Outrage (in a Wild Area) - {0x10355BFF1F4DAB9C, (byte)HiddenMain2}, // on Route 2 - {0xB332920807F9D2D7, (byte)HiddenMain}, // on Route 10 - {0x8F67CB45F405D308, (byte)HiddenMain2}, // in the Slumbering Weald + public static readonly IReadOnlyDictionary ZoneType = new Dictionary + { + {0x078BC1FF1A657844, (byte)HiddenMain}, // on Route 1 + {0x10355EFF1F4DB0B5, (byte)HiddenMain}, // on Route 2 + {0x776776717EA4483E, (byte)HiddenMain}, // in the Rolling Fields (in a Wild Area) + {0x776777717EA449F1, (byte)HiddenMain}, // in the Dappled Grove (in a Wild Area) + {0x776778717EA44BA4, (byte)HiddenMain}, // at Watchtower Ruins (in a Wild Area) + {0x776779717EA44D57, (byte)HiddenMain}, // at East Lake Axewell (in a Wild Area) + {0x77677A717EA44F0A, (byte)HiddenMain}, // at West Lake Axewell (in a Wild Area) + {0x77677B717EA450BD, (byte)HiddenMain}, // on Axew's Eye (in a Wild Area) + {0x77676C717EA43740, (byte)HiddenMain}, // at South Lake Miloch (in a Wild Area) + {0x77676D717EA438F3, (byte)HiddenMain}, // near the Giant's Seat (in a Wild Area) + {0x776AFA717EA75E61, (byte)HiddenMain}, // at North Lake Miloch (in a Wild Area) + {0x194B97FF2492111A, (byte)HiddenMain}, // on Route 3 + {0x776E81717EAA799D, (byte)HiddenMain}, // at the Motostoke Riverbank (in a Wild Area) + {0x776E7E717EAA7484, (byte)HiddenMain}, // in Bridge Field (in a Wild Area) + {0xDBCF5CFF0180B073, (byte)HiddenMain}, // on Route 4 + {0x8F67CD45F405D66E, (byte)HiddenMain}, // in the Slumbering Weald + {0xE0D6E5E78C91F4A7, (byte)OnlyFishing}, // in the city of Motostoke + {0xE4E595FF06C510D8, (byte)HiddenMain}, // on Route 5 + {0x1C7150C0594994E5, (byte)OnlyFishing}, // in the town of Hulbury + {0x7D3B7A45E97D4A51, (byte)HiddenMain}, // in Galar Mine No. 2 + {0x75D83E45E5AA7953, (byte)HiddenMain}, // in Galar Mine + {0x7D3B7745E97D4538, (byte)HiddenMain}, // in the Motostoke Outskirts + {0xA88AC04602050B95, (byte)HiddenMain}, // in Glimwood Tangle + {0xEDFC32FF0C0A1B29, (byte)HiddenMain}, // on Route 6 + {0xF55F6BFF0FDCE70E, (byte)HiddenMain}, // on Route 7 + {0x449AE0FF3D19D777, (byte)HiddenMain}, // on Route 8 + {0x4BFDF9FF40EC6CFC, (byte)HiddenMain}, // on Route 8 (on Steamdrift Way) + {0x4BFDFCFF40EC7215, (byte)HiddenMain}, // on Route 9 + {0x4BFDF6FF40EC67E3, (byte)HiddenMain}, // on Route 9 (in Circhester Bay) + {0x4BFDFBFF40EC7062, (byte)HiddenMain}, // on Route 9 (in Outer Spikemuth) + {0xB332930807F9D48A, (byte)HiddenMain}, // on Route 10 // Near Station + {0x7771E5717EAD5960, (byte)HiddenMain}, // in the Stony Wilderness (in a Wild Area) + {0x7771E8717EAD5E79, (byte)HiddenMain}, // in Dusty Bowl (in a Wild Area) + {0x7771E7717EAD5CC6, (byte)HiddenMain}, // around the Giant's Mirror (in a Wild Area) + {0x7771EA717EAD61DF, (byte)HiddenMain}, // on the Hammerlocke Hills (in a Wild Area) + {0x7771E9717EAD602C, (byte)HiddenMain}, // near the Giant's Cap (in a Wild Area) + {0x7771EC717EAD6545, (byte)HiddenMain}, // at the Lake of Outrage (in a Wild Area) + {0x10355BFF1F4DAB9C, (byte)HiddenMain2}, // on Route 2 + {0xB332920807F9D2D7, (byte)HiddenMain}, // on Route 10 + {0x8F67CB45F405D308, (byte)HiddenMain2}, // in the Slumbering Weald - {0xCD6E4FBCE1466F32, (byte)SymbolMain}, // on Route 1 - {0xDF686EC613544BD1, (byte)SymbolMain}, // on Route 2 - {0xD602B2A66C268F7C, (byte)SymbolMain}, // in the Rolling Fields (in a Wild Area) - {0x458C9CA2C0087385, (byte)SymbolMain}, // in the Dappled Grove (in a Wild Area) - {0xE20E6AE30AAA57D2, (byte)SymbolMain}, // at Watchtower Ruins (in a Wild Area) - {0xEEEEAC06BAC8D0B3, (byte)SymbolMain}, // at East Lake Axewell (in a Wild Area) - {0xF8D1E527F7B21FA0, (byte)SymbolMain}, // at West Lake Axewell (in a Wild Area) - {0xB6CFE90E0378FD79, (byte)SymbolMain}, // on Axew's Eye (in a Wild Area) - {0x520D8DD522E9A4C6, (byte)SymbolMain}, // at South Lake Miloch (in a Wild Area) - {0xBC7237A0392D8837, (byte)SymbolMain}, // near the Giant's Seat (in a Wild Area) - {0xB67C706F5BAE9E35, (byte)SymbolMain}, // at North Lake Miloch (in a Wild Area) - {0xDA910F69A1B92FED, (byte)Surfing}, // at West Lake Axewell (in a Wild Area) // Surfing - {0x7C17DB1B430F9543, (byte)Surfing}, // at South Lake Miloch (in a Wild Area) // Surfing - {0xCC0F8A437312B8AC, (byte)Surfing}, // at East Lake Axewell (in a Wild Area) // Surfing - {0x8BE2F6160986FB8E, (byte)Surfing}, // at North Lake Miloch (in a Wild Area) // Surfing - {0x0E8392C0A57D5830, (byte)SymbolMain}, // on Route 3 - {0x82A7A328A26B9057, (byte)SymbolMain}, // in Galar Mine - {0x5B2BC38E044EC2B7, (byte)SymbolMain}, // on Route 4 - {0x8D68276C03A332BE, (byte)SymbolMain}, // on Route 5 - {0x16D2FC4840A658A5, (byte)SymbolMain}, // in Galar Mine No. 2 - {0x3D6D58A96894575E, (byte)SymbolMain}, // in the Motostoke Outskirts - {0x6AA652641154B119, (byte)SymbolMain}, // at the Motostoke Riverbank (in a Wild Area) - {0x36A5DC94335E1E72, (byte)SymbolMain}, // in Bridge Field (in a Wild Area) - {0xE503416A1C05765D, (byte)SymbolMain}, // on Route 6 - {0x201EF8E9D2A32D71, (byte)Inaccessible}, // in Glimwood Tangle - {0x42312695C904658C, (byte)SymbolMain}, // on Route 7 - {0x1B95A78295F6F213, (byte)SymbolMain}, // on Route 8 - {0xAADAC3CB6A1DFE8A, (byte)SymbolMain}, // on Route 8 (on Steamdrift Way) - {0x9116B224702CDCF1, (byte)SymbolMain}, // on Route 9 - {0xCDD3B5660D2E5E67, (byte)SymbolMain}, // on Route 9 (in Circhester Bay) - {0x5A3B8F8147272058, (byte)SymbolMain}, // on Route 9 (in Outer Spikemuth) - {0xA93101EA38598995, (byte)Surfing}, // on Route 9 // Surfing - {0x0181225223DE5420, (byte)SymbolMain}, // on Route 10 // Near Station - {0x1F0F1AE1818C4326, (byte)SymbolMain}, // in the Stony Wilderness (in a Wild Area) - {0xAD11B3F3B2AC662D, (byte)SymbolMain}, // in Dusty Bowl (in a Wild Area) - {0xCD9719B2E64F2AA4, (byte)SymbolMain}, // around the Giant's Mirror (in a Wild Area) - {0xCD48625EDC10CBFB, (byte)SymbolMain}, // on the Hammerlocke Hills (in a Wild Area) - {0x712F3056573E23FA, (byte)SymbolMain}, // near the Giant's Cap (in a Wild Area) - {0x593196758BA16B61, (byte)SymbolMain}, // at the Lake of Outrage (in a Wild Area) - {0xF79DE930E6F50533, (byte)SymbolMain}, // on Route 10 - {0xA26A4595F72EDAEA, (byte)SymbolMain2}, // on Route 2 // high level - {0x56580C94EDFCE664, (byte)Ground}, // on Route 3 // just rolycoly and trubbish, probably trash - {0xCB38FEA3F71C3958, (byte)Sky}, // in the Rolling Fields (in a Wild Area) // Flying Spawns butterfree/pidove - {0x1F174D36062B8C38, (byte)Ground}, // in the Rolling Fields (in a Wild Area) // Underground Spawns digglet/roggenrola - {0x23017513039A78E7, (byte)SymbolMain2}, // in the Rolling Fields (in a Wild Area) // ? Second full table, has pancham instead of bunnelby - {0xF1BA4AAD9AAB2C1A, (byte)Sky}, // at Watchtower Ruins (in a Wild Area) // Flying Spawns woobat/noibat - {0x3D2E746F9D3F5CB5, (byte)Sky}, // at East Lake Axewell (in a Wild Area) // Flying Spawns bufferfree/pidove - {0x6E121A9CE4F58F1E, (byte)Sky2}, // at East Lake Axewell (in a Wild Area) // More Flying Spawns bufferfree/pidove, different rates than above - {0x3171A0C61793816E, (byte)Sky}, // at South Lake Miloch (in a Wild Area) // Flying Spawns wingull/drifloon - {0x198E4023A1B2DDEF, (byte)SymbolMain2}, // at South Lake Miloch (in a Wild Area) // ? Second table, has mostly machop/stunky/tyrogue - {0xFAB1C08E70C0F1CA, (byte)Surfing}, // at the Motostoke Riverbank (in a Wild Area) // Surfing - {0xB9F76CEE459CEC07, (byte)Surfing}, // in Bridge Field (in a Wild Area) // Surfing - {0x5F4E0AB29FD3F13A, (byte)Sky}, // in Bridge Field (in a Wild Area) // Flying Spawns noibat/woobat/tranquill - {0xF603DEA4177200EA, (byte)SymbolMain2}, // in the Stony Wilderness (in a Wild Area) // ? Second full table - {0x76EE4E28DD28374E, (byte)Sky}, // in the Stony Wilderness (in a Wild Area) // Flying Spawns tranquill/sigilyph - {0x3F264B6FCB5647B4, (byte)Sky}, // around the Giant's Mirror (in a Wild Area) // Flying Spawns tranquill/corvisquire - {0x2D887A1CA9B1B99A, (byte)Sky}, // in Dusty Bowl (in a Wild Area) // Flying Spawns braviary - {0x2BE7E6A8901ECC20, (byte)Ground}, // around the Giant's Mirror (in a Wild Area) // Underground Spawns dugtrio/excadrill/boldore - {0x39F0170769BF4524, (byte)Surfing}, // in Dusty Bowl (in a Wild Area) // Surfing. Also used for 148,around the Giant's Mirror (in a Wild Area) surfing. - {0xB2067FBCF8D5C7BA, (byte)Ground}, // near the Giant's Cap (in a Wild Area) // Underground Spawns rolycoly/rhyhorn/boldore - {0x48B9525945EE48B5, (byte)SymbolMain3}, // in the Stony Wilderness (in a Wild Area) // ? third full table - {0xB5756B87989661E1, (byte)SymbolMain2}, // near the Giant's Cap (in a Wild Area) // ? second full table - {0x7AB83D18C831DDEB, (byte)SymbolMain3}, // near the Giant's Cap (in a Wild Area) // ? third full table - {0xDBEF8A8593377AAA, (byte)Ground2}, // near the Giant's Cap (in a Wild Area) // Underground Spawns Solrock - {0x066F97F8765BC22D, (byte)Sky}, // on the Hammerlocke Hills (in a Wild Area) // Flying Spawns Unfezant/Corvisquire - {0x87A97AFF94BC6CF2, (byte)Surfing}, // at the Lake of Outrage (in a Wild Area) // Surfing - {0x94289204B628522C, (byte)SymbolMain}, // in the Slumbering Weald // early - {0x5D02F15C043B872E, (byte)SymbolMain2}, // in the Slumbering Weald // late - {0xA4945486A2B97DFF, (byte)Surfing}, // on Route 2 // Surfing - {0xAC1187E9EC166853, (byte)Surfing}, // on Route 9 (in Circhester Bay) // Surfing + {0xCD6E4FBCE1466F32, (byte)SymbolMain}, // on Route 1 + {0xDF686EC613544BD1, (byte)SymbolMain}, // on Route 2 + {0xD602B2A66C268F7C, (byte)SymbolMain}, // in the Rolling Fields (in a Wild Area) + {0x458C9CA2C0087385, (byte)SymbolMain}, // in the Dappled Grove (in a Wild Area) + {0xE20E6AE30AAA57D2, (byte)SymbolMain}, // at Watchtower Ruins (in a Wild Area) + {0xEEEEAC06BAC8D0B3, (byte)SymbolMain}, // at East Lake Axewell (in a Wild Area) + {0xF8D1E527F7B21FA0, (byte)SymbolMain}, // at West Lake Axewell (in a Wild Area) + {0xB6CFE90E0378FD79, (byte)SymbolMain}, // on Axew's Eye (in a Wild Area) + {0x520D8DD522E9A4C6, (byte)SymbolMain}, // at South Lake Miloch (in a Wild Area) + {0xBC7237A0392D8837, (byte)SymbolMain}, // near the Giant's Seat (in a Wild Area) + {0xB67C706F5BAE9E35, (byte)SymbolMain}, // at North Lake Miloch (in a Wild Area) + {0xDA910F69A1B92FED, (byte)Surfing}, // at West Lake Axewell (in a Wild Area) // Surfing + {0x7C17DB1B430F9543, (byte)Surfing}, // at South Lake Miloch (in a Wild Area) // Surfing + {0xCC0F8A437312B8AC, (byte)Surfing}, // at East Lake Axewell (in a Wild Area) // Surfing + {0x8BE2F6160986FB8E, (byte)Surfing}, // at North Lake Miloch (in a Wild Area) // Surfing + {0x0E8392C0A57D5830, (byte)SymbolMain}, // on Route 3 + {0x82A7A328A26B9057, (byte)SymbolMain}, // in Galar Mine + {0x5B2BC38E044EC2B7, (byte)SymbolMain}, // on Route 4 + {0x8D68276C03A332BE, (byte)SymbolMain}, // on Route 5 + {0x16D2FC4840A658A5, (byte)SymbolMain}, // in Galar Mine No. 2 + {0x3D6D58A96894575E, (byte)SymbolMain}, // in the Motostoke Outskirts + {0x6AA652641154B119, (byte)SymbolMain}, // at the Motostoke Riverbank (in a Wild Area) + {0x36A5DC94335E1E72, (byte)SymbolMain}, // in Bridge Field (in a Wild Area) + {0xE503416A1C05765D, (byte)SymbolMain}, // on Route 6 + {0x201EF8E9D2A32D71, (byte)Inaccessible}, // in Glimwood Tangle + {0x42312695C904658C, (byte)SymbolMain}, // on Route 7 + {0x1B95A78295F6F213, (byte)SymbolMain}, // on Route 8 + {0xAADAC3CB6A1DFE8A, (byte)SymbolMain}, // on Route 8 (on Steamdrift Way) + {0x9116B224702CDCF1, (byte)SymbolMain}, // on Route 9 + {0xCDD3B5660D2E5E67, (byte)SymbolMain}, // on Route 9 (in Circhester Bay) + {0x5A3B8F8147272058, (byte)SymbolMain}, // on Route 9 (in Outer Spikemuth) + {0xA93101EA38598995, (byte)Surfing}, // on Route 9 // Surfing + {0x0181225223DE5420, (byte)SymbolMain}, // on Route 10 // Near Station + {0x1F0F1AE1818C4326, (byte)SymbolMain}, // in the Stony Wilderness (in a Wild Area) + {0xAD11B3F3B2AC662D, (byte)SymbolMain}, // in Dusty Bowl (in a Wild Area) + {0xCD9719B2E64F2AA4, (byte)SymbolMain}, // around the Giant's Mirror (in a Wild Area) + {0xCD48625EDC10CBFB, (byte)SymbolMain}, // on the Hammerlocke Hills (in a Wild Area) + {0x712F3056573E23FA, (byte)SymbolMain}, // near the Giant's Cap (in a Wild Area) + {0x593196758BA16B61, (byte)SymbolMain}, // at the Lake of Outrage (in a Wild Area) + {0xF79DE930E6F50533, (byte)SymbolMain}, // on Route 10 + {0xA26A4595F72EDAEA, (byte)SymbolMain2}, // on Route 2 // high level + {0x56580C94EDFCE664, (byte)Ground}, // on Route 3 // just rolycoly and trubbish, probably trash + {0xCB38FEA3F71C3958, (byte)Sky}, // in the Rolling Fields (in a Wild Area) // Flying Spawns butterfree/pidove + {0x1F174D36062B8C38, (byte)Ground}, // in the Rolling Fields (in a Wild Area) // Underground Spawns digglet/roggenrola + {0x23017513039A78E7, (byte)SymbolMain2}, // in the Rolling Fields (in a Wild Area) // ? Second full table, has pancham instead of bunnelby + {0xF1BA4AAD9AAB2C1A, (byte)Sky}, // at Watchtower Ruins (in a Wild Area) // Flying Spawns woobat/noibat + {0x3D2E746F9D3F5CB5, (byte)Sky}, // at East Lake Axewell (in a Wild Area) // Flying Spawns bufferfree/pidove + {0x6E121A9CE4F58F1E, (byte)Sky2}, // at East Lake Axewell (in a Wild Area) // More Flying Spawns bufferfree/pidove, different rates than above + {0x3171A0C61793816E, (byte)Sky}, // at South Lake Miloch (in a Wild Area) // Flying Spawns wingull/drifloon + {0x198E4023A1B2DDEF, (byte)SymbolMain2}, // at South Lake Miloch (in a Wild Area) // ? Second table, has mostly machop/stunky/tyrogue + {0xFAB1C08E70C0F1CA, (byte)Surfing}, // at the Motostoke Riverbank (in a Wild Area) // Surfing + {0xB9F76CEE459CEC07, (byte)Surfing}, // in Bridge Field (in a Wild Area) // Surfing + {0x5F4E0AB29FD3F13A, (byte)Sky}, // in Bridge Field (in a Wild Area) // Flying Spawns noibat/woobat/tranquill + {0xF603DEA4177200EA, (byte)SymbolMain2}, // in the Stony Wilderness (in a Wild Area) // ? Second full table + {0x76EE4E28DD28374E, (byte)Sky}, // in the Stony Wilderness (in a Wild Area) // Flying Spawns tranquill/sigilyph + {0x3F264B6FCB5647B4, (byte)Sky}, // around the Giant's Mirror (in a Wild Area) // Flying Spawns tranquill/corvisquire + {0x2D887A1CA9B1B99A, (byte)Sky}, // in Dusty Bowl (in a Wild Area) // Flying Spawns braviary + {0x2BE7E6A8901ECC20, (byte)Ground}, // around the Giant's Mirror (in a Wild Area) // Underground Spawns dugtrio/excadrill/boldore + {0x39F0170769BF4524, (byte)Surfing}, // in Dusty Bowl (in a Wild Area) // Surfing. Also used for 148,around the Giant's Mirror (in a Wild Area) surfing. + {0xB2067FBCF8D5C7BA, (byte)Ground}, // near the Giant's Cap (in a Wild Area) // Underground Spawns rolycoly/rhyhorn/boldore + {0x48B9525945EE48B5, (byte)SymbolMain3}, // in the Stony Wilderness (in a Wild Area) // ? third full table + {0xB5756B87989661E1, (byte)SymbolMain2}, // near the Giant's Cap (in a Wild Area) // ? second full table + {0x7AB83D18C831DDEB, (byte)SymbolMain3}, // near the Giant's Cap (in a Wild Area) // ? third full table + {0xDBEF8A8593377AAA, (byte)Ground2}, // near the Giant's Cap (in a Wild Area) // Underground Spawns Solrock + {0x066F97F8765BC22D, (byte)Sky}, // on the Hammerlocke Hills (in a Wild Area) // Flying Spawns Unfezant/Corvisquire + {0x87A97AFF94BC6CF2, (byte)Surfing}, // at the Lake of Outrage (in a Wild Area) // Surfing + {0x94289204B628522C, (byte)SymbolMain}, // in the Slumbering Weald // early + {0x5D02F15C043B872E, (byte)SymbolMain2}, // in the Slumbering Weald // late + {0xA4945486A2B97DFF, (byte)Surfing}, // on Route 2 // Surfing + {0xAC1187E9EC166853, (byte)Surfing}, // on Route 9 (in Circhester Bay) // Surfing - // DLC 1 - Isle of Armor - {0x908A64718CA374E6, (byte)HiddenMain}, // in the Fields of Honor - {0x908A63718CA37333, (byte)HiddenMain}, // in the Soothing Wetlands - {0x908A62718CA37180, (byte)HiddenMain}, // in the Forest of Focus - {0x908A69718CA37D65, (byte)HiddenMain}, // on Challenge Beach - {0x908A68718CA37BB2, (byte)Inaccessible}, // in Brawlers' Cave - {0x908A67718CA379FF, (byte)HiddenMain}, // on Challenge Road - {0x908A66718CA3784C, (byte)OnlyFishing}, // in Courageous Cavern // Only fishing? - {0x908A6D718CA38431, (byte)HiddenMain}, // in Loop Lagoon - {0x908A6C718CA3827E, (byte)HiddenMain}, // in the Training Lowlands - {0x90875F718CA13690, (byte)Inaccessible}, // in Warm-Up Tunnel - {0x908760718CA13843, (byte)Inaccessible}, // in the Potbottom Desert - {0x909170718CA9A7F8, (byte)HiddenMain}, // in the Workout Sea - {0x909173718CA9AD11, (byte)HiddenMain}, // in the Stepping-Stone Sea - {0x909172718CA9AB5E, (byte)HiddenMain}, // in the Insular Sea - {0x909175718CA9B077, (byte)OnlyFishing}, // in the Honeycalm Sea // Only fishing? - {0x908DEC718CA691D5, (byte)HiddenMain}, // on Honeycalm Island + // DLC 1 - Isle of Armor + {0x908A64718CA374E6, (byte)HiddenMain}, // in the Fields of Honor + {0x908A63718CA37333, (byte)HiddenMain}, // in the Soothing Wetlands + {0x908A62718CA37180, (byte)HiddenMain}, // in the Forest of Focus + {0x908A69718CA37D65, (byte)HiddenMain}, // on Challenge Beach + {0x908A68718CA37BB2, (byte)Inaccessible}, // in Brawlers' Cave + {0x908A67718CA379FF, (byte)HiddenMain}, // on Challenge Road + {0x908A66718CA3784C, (byte)OnlyFishing}, // in Courageous Cavern // Only fishing? + {0x908A6D718CA38431, (byte)HiddenMain}, // in Loop Lagoon + {0x908A6C718CA3827E, (byte)HiddenMain}, // in the Training Lowlands + {0x90875F718CA13690, (byte)Inaccessible}, // in Warm-Up Tunnel + {0x908760718CA13843, (byte)Inaccessible}, // in the Potbottom Desert + {0x909170718CA9A7F8, (byte)HiddenMain}, // in the Workout Sea + {0x909173718CA9AD11, (byte)HiddenMain}, // in the Stepping-Stone Sea + {0x909172718CA9AB5E, (byte)HiddenMain}, // in the Insular Sea + {0x909175718CA9B077, (byte)OnlyFishing}, // in the Honeycalm Sea // Only fishing? + {0x908DEC718CA691D5, (byte)HiddenMain}, // on Honeycalm Island - {0x525D03DF0309D804, (byte)SymbolMain}, // in the Fields of Honor // Ground Spawns - {0xB0621052994A5089, (byte)Surfing}, // in the Fields of Honor // Surfing - {0x91B1D1436BAF5871, (byte)Ground}, // in the Fields of Honor // Beach Slowpoke - {0xC449DFAB894F632C, (byte)Ground}, // in Loop Lagoon // Beach - {0x273693DD91D7BD10, (byte)Ground}, // on Challenge Beach // Beach - {0xD61582D408C39E60, (byte)Surfing}, // on Challenge Beach // Surfing (River) - {0xBECC9623CD3E8C77, (byte)SymbolMain}, // in the Soothing Wetlands // Ground Spawns - {0x1C051CB6F97C2068, (byte)Ground}, // in the Soothing Wetlands // Puddles - {0xBC028EF260AD9406, (byte)SymbolMain}, // in the Forest of Focus // Ground Spawns - {0x32AB88FC9797DC83, (byte)Surfing}, // in the Forest of Focus // Surfing - {0x39D078468AA0DCC1, (byte)SymbolMain}, // on Challenge Beach // Ground Spawns - {0x3BFB22D0FB5B42D2, (byte)Surfing2}, // on Challenge Beach // Surfing (Ocean) - {0x2B1DF6E85F9BAE28, (byte)SymbolMain}, // in Brawlers' Cave // Ground Spawns - {0x36FE81B956D0DCB5, (byte)Surfing}, // in Brawlers' Cave // Surfing - {0xBBAA199D0705405B, (byte)SymbolMain}, // on Challenge Road // Ground Spawns - {0xFB9A7FD6D979C6DA, (byte)SymbolMain}, // in Courageous Cavern // Ground Spawns - {0xBC0E1701C0276FCF, (byte)Surfing}, // in Courageous Cavern // Surfing - {0xAC2ED08E980FCFC5, (byte)SymbolMain}, // in Loop Lagoon // Ground Spawns - {0x7D2E205E8E300EE1, (byte)Surfing}, // in Loop Lagoon // Water Spawns - {0x67E3FF10EB64FB79, (byte)Ground}, // in the Training Lowlands // Beach - {0x85E286D82C666BBC, (byte)SymbolMain}, // in the Training Lowlands // Ground Spawns - {0x95E125D2EE3ED656, (byte)SymbolMain}, // in Warm-up Tunnel - {0xA7F495799F209587, (byte)SymbolMain}, // in the Potbottom Desert - {0x30AAD92559FCE81E, (byte)SymbolMain}, // in the Workout Sea // Ground Spawns - {0x6F748A46C8E3802C, (byte)Surfing}, // in the Workout Sea // Surfing - {0x97A3E0687E3C5B01, (byte)Surfing}, // in the Stepping-Stone Sea // Surfing - {0xDDDFF88957FD5B5C, (byte)SymbolMain}, // in the Insular Sea // Ground Spawns - {0xF3036CD294CE9365, (byte)SymbolMain}, // in the Stepping-Stone Sea // Ground Spawns - {0xFB9BB438425D58DA, (byte)Surfing}, // in the Insular Sea // Surfing - {0xC16C1E2A1B5FFE87, (byte)Surfing}, // in the Honeycalm Sea // Surfing - {0x081D7EF6A1C192B1, (byte)SymbolMain}, // on Honeycalm Island // Ground Spawns - {0x86EFBF49516B5555, (byte)Surfing}, // on Honeycalm Island // Surfing - {0x39AB700A9F1AB71F, (byte)Surfing}, // in the Training Lowlands // Surfing - {0x96C6A2A36131F383, (byte)Sharpedo}, // in the Stepping-Stone Sea // Sharpedo - {0xC92D06352150C78A, (byte)Sharpedo}, // in the Insular Sea // Sharpedo - {0xED1F9772AA35C3CD, (byte)Sharpedo}, // in the Workout Sea // Sharpedo - {0x9C0049D3E6129924, (byte)Sharpedo}, // in the Honeycalm Sea // Sharpedo + {0x525D03DF0309D804, (byte)SymbolMain}, // in the Fields of Honor // Ground Spawns + {0xB0621052994A5089, (byte)Surfing}, // in the Fields of Honor // Surfing + {0x91B1D1436BAF5871, (byte)Ground}, // in the Fields of Honor // Beach Slowpoke + {0xC449DFAB894F632C, (byte)Ground}, // in Loop Lagoon // Beach + {0x273693DD91D7BD10, (byte)Ground}, // on Challenge Beach // Beach + {0xD61582D408C39E60, (byte)Surfing}, // on Challenge Beach // Surfing (River) + {0xBECC9623CD3E8C77, (byte)SymbolMain}, // in the Soothing Wetlands // Ground Spawns + {0x1C051CB6F97C2068, (byte)Ground}, // in the Soothing Wetlands // Puddles + {0xBC028EF260AD9406, (byte)SymbolMain}, // in the Forest of Focus // Ground Spawns + {0x32AB88FC9797DC83, (byte)Surfing}, // in the Forest of Focus // Surfing + {0x39D078468AA0DCC1, (byte)SymbolMain}, // on Challenge Beach // Ground Spawns + {0x3BFB22D0FB5B42D2, (byte)Surfing2}, // on Challenge Beach // Surfing (Ocean) + {0x2B1DF6E85F9BAE28, (byte)SymbolMain}, // in Brawlers' Cave // Ground Spawns + {0x36FE81B956D0DCB5, (byte)Surfing}, // in Brawlers' Cave // Surfing + {0xBBAA199D0705405B, (byte)SymbolMain}, // on Challenge Road // Ground Spawns + {0xFB9A7FD6D979C6DA, (byte)SymbolMain}, // in Courageous Cavern // Ground Spawns + {0xBC0E1701C0276FCF, (byte)Surfing}, // in Courageous Cavern // Surfing + {0xAC2ED08E980FCFC5, (byte)SymbolMain}, // in Loop Lagoon // Ground Spawns + {0x7D2E205E8E300EE1, (byte)Surfing}, // in Loop Lagoon // Water Spawns + {0x67E3FF10EB64FB79, (byte)Ground}, // in the Training Lowlands // Beach + {0x85E286D82C666BBC, (byte)SymbolMain}, // in the Training Lowlands // Ground Spawns + {0x95E125D2EE3ED656, (byte)SymbolMain}, // in Warm-up Tunnel + {0xA7F495799F209587, (byte)SymbolMain}, // in the Potbottom Desert + {0x30AAD92559FCE81E, (byte)SymbolMain}, // in the Workout Sea // Ground Spawns + {0x6F748A46C8E3802C, (byte)Surfing}, // in the Workout Sea // Surfing + {0x97A3E0687E3C5B01, (byte)Surfing}, // in the Stepping-Stone Sea // Surfing + {0xDDDFF88957FD5B5C, (byte)SymbolMain}, // in the Insular Sea // Ground Spawns + {0xF3036CD294CE9365, (byte)SymbolMain}, // in the Stepping-Stone Sea // Ground Spawns + {0xFB9BB438425D58DA, (byte)Surfing}, // in the Insular Sea // Surfing + {0xC16C1E2A1B5FFE87, (byte)Surfing}, // in the Honeycalm Sea // Surfing + {0x081D7EF6A1C192B1, (byte)SymbolMain}, // on Honeycalm Island // Ground Spawns + {0x86EFBF49516B5555, (byte)Surfing}, // on Honeycalm Island // Surfing + {0x39AB700A9F1AB71F, (byte)Surfing}, // in the Training Lowlands // Surfing + {0x96C6A2A36131F383, (byte)Sharpedo}, // in the Stepping-Stone Sea // Sharpedo + {0xC92D06352150C78A, (byte)Sharpedo}, // in the Insular Sea // Sharpedo + {0xED1F9772AA35C3CD, (byte)Sharpedo}, // in the Workout Sea // Sharpedo + {0x9C0049D3E6129924, (byte)Sharpedo}, // in the Honeycalm Sea // Sharpedo - // DLC 2 - Crown Tundra - {0x87E14B7187BC1CC1, (byte)HiddenMain}, // on Slippery Slope - {0x87E1487187BC17A8, (byte)Inaccessible}, // in Freezington - {0x87E1497187BC195B, (byte)HiddenMain}, // in Frostpoint Field - {0x87E14E7187BC21DA, (byte)HiddenMain}, // in the Giant's Bed - {0x87E14F7187BC238D, (byte)HiddenMain}, // in the Old Cemetery - {0x87E14C7187BC1E74, (byte)HiddenMain}, // on Snowslide Slope - {0x87E14D7187BC2027, (byte)Inaccessible}, // in the Tunnel to the Top - {0x87E1427187BC0D76, (byte)Inaccessible}, // on the Path to the Peak - {0x87E1437187BC0F29, (byte)Inaccessible}, // at the Crown Shrine - {0x87E4507187BE5B17, (byte)HiddenMain}, // at the Giant's Foot - {0x87E44F7187BE5964, (byte)Inaccessible}, // in Roaring-Sea Caves - {0x87E4527187BE5E7D, (byte)HiddenMain}, // at the Frigid Sea - {0x87E4517187BE5CCA, (byte)HiddenMain}, // in Three-Point Pass - {0x87DA3F7187B5E9AF, (byte)HiddenMain}, // at Ballimere Lake - {0x87DA407187B5EB62, (byte)Inaccessible}, // in Lakeside Cave - {0x87DA417187B5ED15, (byte)Inaccessible}, // at Dyna Tree Hill + // DLC 2 - Crown Tundra + {0x87E14B7187BC1CC1, (byte)HiddenMain}, // on Slippery Slope + {0x87E1487187BC17A8, (byte)Inaccessible}, // in Freezington + {0x87E1497187BC195B, (byte)HiddenMain}, // in Frostpoint Field + {0x87E14E7187BC21DA, (byte)HiddenMain}, // in the Giant's Bed + {0x87E14F7187BC238D, (byte)HiddenMain}, // in the Old Cemetery + {0x87E14C7187BC1E74, (byte)HiddenMain}, // on Snowslide Slope + {0x87E14D7187BC2027, (byte)Inaccessible}, // in the Tunnel to the Top + {0x87E1427187BC0D76, (byte)Inaccessible}, // on the Path to the Peak + {0x87E1437187BC0F29, (byte)Inaccessible}, // at the Crown Shrine + {0x87E4507187BE5B17, (byte)HiddenMain}, // at the Giant's Foot + {0x87E44F7187BE5964, (byte)Inaccessible}, // in Roaring-Sea Caves + {0x87E4527187BE5E7D, (byte)HiddenMain}, // at the Frigid Sea + {0x87E4517187BE5CCA, (byte)HiddenMain}, // in Three-Point Pass + {0x87DA3F7187B5E9AF, (byte)HiddenMain}, // at Ballimere Lake + {0x87DA407187B5EB62, (byte)Inaccessible}, // in Lakeside Cave + {0x87DA417187B5ED15, (byte)Inaccessible}, // at Dyna Tree Hill - {0xD6EA3DE40B009E55, (byte)SymbolMain}, // on Slippery Slope - {0xADF616908BD308DF, (byte)SymbolMain}, // in Frostpoint Field - {0x308C5EB6A846D1F0, (byte)SymbolMain}, // in the Giant's Bed - {0x50E781F91B97C049, (byte)SymbolMain}, // in the Old Cemetery - {0xC303110BF1EC3322, (byte)SymbolMain}, // on Snowslide Slope - {0xB768660B0BF4C0C3, (byte)SymbolMain}, // in the Tunnel to the Top - {0xFCB78AFCCECAF094, (byte)SymbolMain}, // on the Path to the Peak - {0xA345459C03EA6673, (byte)SymbolMain}, // at the Giant's Foot - {0xE4A982819ACF7292, (byte)SymbolMain}, // in Roaring-Sea Caves - {0x18AAF85178C7B839, (byte)SymbolMain}, // at the Frigid Sea - {0x3EC6FCDC0C77D460, (byte)SymbolMain}, // in Three-Point Pass - {0xE5225F9325CCA74B, (byte)SymbolMain}, // at Ballimere Lake - {0x2F1B41507D695958, (byte)SymbolMain}, // in Lakeside Cave + {0xD6EA3DE40B009E55, (byte)SymbolMain}, // on Slippery Slope + {0xADF616908BD308DF, (byte)SymbolMain}, // in Frostpoint Field + {0x308C5EB6A846D1F0, (byte)SymbolMain}, // in the Giant's Bed + {0x50E781F91B97C049, (byte)SymbolMain}, // in the Old Cemetery + {0xC303110BF1EC3322, (byte)SymbolMain}, // on Snowslide Slope + {0xB768660B0BF4C0C3, (byte)SymbolMain}, // in the Tunnel to the Top + {0xFCB78AFCCECAF094, (byte)SymbolMain}, // on the Path to the Peak + {0xA345459C03EA6673, (byte)SymbolMain}, // at the Giant's Foot + {0xE4A982819ACF7292, (byte)SymbolMain}, // in Roaring-Sea Caves + {0x18AAF85178C7B839, (byte)SymbolMain}, // at the Frigid Sea + {0x3EC6FCDC0C77D460, (byte)SymbolMain}, // in Three-Point Pass + {0xE5225F9325CCA74B, (byte)SymbolMain}, // at Ballimere Lake + {0x2F1B41507D695958, (byte)SymbolMain}, // in Lakeside Cave - {0xF8A59FCA719D1EAE, (byte)Surfing}, // in the Giant's Bed (Surfing), also used for 222 (in the Giant's Foot Surfing) - {0x55D8F226A42368B7, (byte)Surfing}, // in Roaring-Sea Caves (Surfing) - {0x78536116469DC44D, (byte)Surfing}, // at the Frigid Sea (Surfing) - {0x9BDD6D11FFBEDA3F, (byte)Surfing}, // at Ballimere Lake (Surfing) - }; - } -} + {0xF8A59FCA719D1EAE, (byte)Surfing}, // in the Giant's Bed (Surfing), also used for 222 (in the Giant's Foot Surfing) + {0x55D8F226A42368B7, (byte)Surfing}, // in Roaring-Sea Caves (Surfing) + {0x78536116469DC44D, (byte)Surfing}, // at the Frigid Sea (Surfing) + {0x9BDD6D11FFBEDA3F, (byte)Surfing}, // at Ballimere Lake (Surfing) + }; +} \ No newline at end of file diff --git a/pkNX.Game/Text/TextManager.cs b/pkNX.Game/Text/TextManager.cs index 07f79d4c..c0a450e6 100644 --- a/pkNX.Game/Text/TextManager.cs +++ b/pkNX.Game/Text/TextManager.cs @@ -4,48 +4,47 @@ using pkNX.Containers; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public class TextManager { - public class TextManager + private readonly TextConfig Config; + private readonly IReadOnlyCollection References; + + private readonly Dictionary Cache = new(); + + public void ClearCache() => Cache.Clear(); + + public TextManager(GameVersion game, TextConfig config = null) { - private readonly TextConfig Config; - private readonly IReadOnlyCollection References; - - private readonly Dictionary Cache = new(); - - public void ClearCache() => Cache.Clear(); - - public TextManager(GameVersion game, TextConfig config = null) - { - References = TextMapping.GetMapping(game); - Config = config ?? new TextConfig(game); - } - - internal string[] GetStrings(byte[] data, bool remap = false) - { - var txt = new TextFile(data, Config, remap); - return txt.Lines; - } - - internal string[] GetStrings(TextName file, IFileContainer textFile, bool remap = false) - { - if (Cache.TryGetValue(file, out var container)) - return container; - - var info = References.FirstOrDefault(f => f.Name == file); - if (info == null) - throw new ArgumentException($"Unknown {nameof(TextName)} provided.", file.ToString()); - - byte[] data; - string path = info.FileName; - if (!string.IsNullOrWhiteSpace(path) && textFile is FolderContainer c) - data = c.GetFileData(info.FileName); - else - data = textFile[info.Index]; - - var lines = GetStrings(data, remap); - Cache.Add(file, lines); - return lines; - } + References = TextMapping.GetMapping(game); + Config = config ?? new TextConfig(game); } -} + + internal string[] GetStrings(byte[] data, bool remap = false) + { + var txt = new TextFile(data, Config, remap); + return txt.Lines; + } + + internal string[] GetStrings(TextName file, IFileContainer textFile, bool remap = false) + { + if (Cache.TryGetValue(file, out var container)) + return container; + + var info = References.FirstOrDefault(f => f.Name == file); + if (info == null) + throw new ArgumentException($"Unknown {nameof(TextName)} provided.", file.ToString()); + + byte[] data; + string path = info.FileName; + if (!string.IsNullOrWhiteSpace(path) && textFile is FolderContainer c) + data = c.GetFileData(info.FileName); + else + data = textFile[info.Index]; + + var lines = GetStrings(data, remap); + Cache.Add(file, lines); + return lines; + } +} \ No newline at end of file diff --git a/pkNX.Game/Text/TextMapping.cs b/pkNX.Game/Text/TextMapping.cs index 8bf2ecc8..3056d9aa 100644 --- a/pkNX.Game/Text/TextMapping.cs +++ b/pkNX.Game/Text/TextMapping.cs @@ -1,205 +1,204 @@ using System.Collections.Generic; using pkNX.Structures; -namespace pkNX.Game +namespace pkNX.Game; + +public static class TextMapping { - public static class TextMapping + public static IReadOnlyCollection GetMapping(GameVersion game) { - public static IReadOnlyCollection GetMapping(GameVersion game) + return game switch { - return game switch - { - GameVersion.XY => XY, - GameVersion.ORASDEMO => AO, - GameVersion.ORAS => AO, - GameVersion.SMDEMO => SMDEMO, - GameVersion.SN => SM, - GameVersion.MN => SM, - GameVersion.US => USUM, - GameVersion.UM => USUM, - GameVersion.GP => GG, - GameVersion.GE => GG, - GameVersion.GG => GG, - GameVersion.SW => SWSH, - GameVersion.SH => SWSH, - GameVersion.SWSH => SWSH, - GameVersion.PLA => PLA, - _ => null - }; - } - - private static readonly TextReference[] XY = - { - new(005, TextName.Forms), - new(013, TextName.MoveNames), - new(015, TextName.MoveFlavor), - new(017, TextName.Types), - new(020, TextName.TrainerClasses), - new(021, TextName.TrainerNames), - new(022, TextName.TrainerText), - new(034, TextName.AbilityNames), - new(047, TextName.Natures), - new(072, TextName.metlist_00000), - new(080, TextName.SpeciesNames), - new(096, TextName.ItemNames), - new(099, TextName.ItemFlavor), - new(130, TextName.MaisonTrainerNames), - new(131, TextName.SuperTrainerNames), - new(141, TextName.OPowerFlavor), - }; - - private static readonly TextReference[] AO = - { - new(005, TextName.Forms), - new(014, TextName.MoveNames), - new(016, TextName.MoveFlavor), - new(018, TextName.Types), - new(021, TextName.TrainerClasses), - new(022, TextName.TrainerNames), - new(023, TextName.TrainerText), - new(037, TextName.AbilityNames), - new(051, TextName.Natures), - new(090, TextName.metlist_00000), - new(098, TextName.SpeciesNames), - new(114, TextName.ItemNames), - new(117, TextName.ItemFlavor), - new(153, TextName.MaisonTrainerNames), - new(154, TextName.SuperTrainerNames), - new(165, TextName.OPowerFlavor), - }; - - private static readonly TextReference[] SMDEMO = - { - new(020, TextName.ItemFlavor), - new(021, TextName.ItemNames), - new(026, TextName.SpeciesNames), - new(030, TextName.metlist_00000), - new(044, TextName.Forms), - new(044, TextName.Natures), - new(046, TextName.AbilityNames), - new(049, TextName.TrainerText), - new(050, TextName.TrainerNames), - new(051, TextName.TrainerClasses), - new(052, TextName.Types), - new(054, TextName.MoveFlavor), - new(055, TextName.MoveNames), - }; - - private static readonly TextReference[] SM = - { - new(035, TextName.ItemFlavor), - new(036, TextName.ItemNames), - new(055, TextName.SpeciesNames), - new(067, TextName.metlist_00000), - new(086, TextName.BattleRoyalNames), - new(087, TextName.Natures), - new(096, TextName.AbilityNames), - new(099, TextName.BattleTreeNames), - new(104, TextName.TrainerText), - new(105, TextName.TrainerNames), - new(106, TextName.TrainerClasses), - new(107, TextName.Types), - new(112, TextName.MoveFlavor), - new(113, TextName.MoveNames), - new(114, TextName.Forms), - new(116, TextName.SpeciesClassifications), - new(119, TextName.PokedexEntry1), - new(120, TextName.PokedexEntry2) - }; - - private static readonly TextReference[] USUM = - { - new(039, TextName.ItemFlavor), - new(040, TextName.ItemNames), - new(060, TextName.SpeciesNames), - new(072, TextName.metlist_00000), - new(091, TextName.BattleRoyalNames), - new(092, TextName.Natures), - new(101, TextName.AbilityNames), - new(104, TextName.BattleTreeNames), - new(109, TextName.TrainerText), - new(110, TextName.TrainerNames), - new(111, TextName.TrainerClasses), - new(112, TextName.Types), - new(117, TextName.MoveFlavor), - new(118, TextName.MoveNames), - new(119, TextName.Forms), - new(121, TextName.SpeciesClassifications), - new(124, TextName.PokedexEntry1), - new(125, TextName.PokedexEntry2) - }; - - private static readonly TextReference[] GG = - { - new("iteminfo.dat", TextName.ItemFlavor), - new("itemname.dat", TextName.ItemNames), - new("monsname.dat", TextName.SpeciesNames), - new("place_name.dat", TextName.metlist_00000), - new("seikaku.dat", TextName.Natures), - new("tokusei.dat", TextName.AbilityNames), - new("tokuseiinfo.dat", TextName.AbilityFlavor), - new("trname.dat", TextName.TrainerNames), - new("trtype.dat", TextName.TrainerClasses), - new("trmsg.dat", TextName.TrainerText), - new("typename.dat", TextName.Types), - new("wazainfo.dat", TextName.MoveFlavor), - new("wazaname.dat", TextName.MoveNames), - new("zkn_form.dat", TextName.Forms), - new("zkn_type.dat", TextName.SpeciesClassifications), - new("zukan_comment_A.dat", TextName.PokedexEntry1), - }; - - private static readonly TextReference[] SWSH = - { - new("iteminfo.dat", TextName.ItemFlavor), - new("itemname.dat", TextName.ItemNames), - new("monsname.dat", TextName.SpeciesNames), - new("place_name_indirect.dat", TextName.metlist_00000), - new("place_name_spe.dat", TextName.metlist_30000), - new("place_name_out.dat", TextName.metlist_40000), - new("place_name_per.dat", TextName.metlist_60000), - new("seikaku.dat", TextName.Natures), - new("tokusei.dat", TextName.AbilityNames), - new("tokuseiinfo.dat", TextName.AbilityFlavor), - new("trname.dat", TextName.TrainerNames), - new("trtype.dat", TextName.TrainerClasses), - new("trmsg.dat", TextName.TrainerText), - new("typename.dat", TextName.Types), - new("wazainfo.dat", TextName.MoveFlavor), - new("wazaname.dat", TextName.MoveNames), - new("zkn_form.dat", TextName.Forms), - new("zkn_type.dat", TextName.SpeciesClassifications), - new("zukan_comment_A.dat", TextName.PokedexEntry1), - new("zukan_comment_B.dat", TextName.PokedexEntry2), - new("ribbon.dat", TextName.RibbonMark), - new("poke_memory_feeling.dat", TextName.MemoryFeelings), - }; - - - private static readonly TextReference[] PLA = - { - new("iteminfo.dat", TextName.ItemFlavor), - new("itemname.dat", TextName.ItemNames), - new("monsname.dat", TextName.SpeciesNames), - new("place_name_indirect.dat", TextName.metlist_00000), - new("place_name_spe.dat", TextName.metlist_30000), - new("place_name_out.dat", TextName.metlist_40000), - new("place_name_per.dat", TextName.metlist_60000), - new("seikaku.dat", TextName.Natures), - new("tokusei.dat", TextName.AbilityNames), - new("tokuseiinfo.dat", TextName.AbilityFlavor), - new("trname.dat", TextName.TrainerNames), - new("trtype.dat", TextName.TrainerClasses), - new("trmsg.dat", TextName.TrainerText), - new("typename.dat", TextName.Types), - new("wazainfo.dat", TextName.MoveFlavor), - new("wazaname.dat", TextName.MoveNames), - new("zkn_form.dat", TextName.Forms), - new("zkn_type.dat", TextName.SpeciesClassifications), - new("zukan_comment_A.dat", TextName.PokedexEntry1), - new("zukan_comment_B.dat", TextName.PokedexEntry2), - new("ribbon.dat", TextName.RibbonMark), - new("poke_memory_feeling.dat", TextName.MemoryFeelings), + GameVersion.XY => XY, + GameVersion.ORASDEMO => AO, + GameVersion.ORAS => AO, + GameVersion.SMDEMO => SMDEMO, + GameVersion.SN => SM, + GameVersion.MN => SM, + GameVersion.US => USUM, + GameVersion.UM => USUM, + GameVersion.GP => GG, + GameVersion.GE => GG, + GameVersion.GG => GG, + GameVersion.SW => SWSH, + GameVersion.SH => SWSH, + GameVersion.SWSH => SWSH, + GameVersion.PLA => PLA, + _ => null }; } + + private static readonly TextReference[] XY = + { + new(005, TextName.Forms), + new(013, TextName.MoveNames), + new(015, TextName.MoveFlavor), + new(017, TextName.Types), + new(020, TextName.TrainerClasses), + new(021, TextName.TrainerNames), + new(022, TextName.TrainerText), + new(034, TextName.AbilityNames), + new(047, TextName.Natures), + new(072, TextName.metlist_00000), + new(080, TextName.SpeciesNames), + new(096, TextName.ItemNames), + new(099, TextName.ItemFlavor), + new(130, TextName.MaisonTrainerNames), + new(131, TextName.SuperTrainerNames), + new(141, TextName.OPowerFlavor), + }; + + private static readonly TextReference[] AO = + { + new(005, TextName.Forms), + new(014, TextName.MoveNames), + new(016, TextName.MoveFlavor), + new(018, TextName.Types), + new(021, TextName.TrainerClasses), + new(022, TextName.TrainerNames), + new(023, TextName.TrainerText), + new(037, TextName.AbilityNames), + new(051, TextName.Natures), + new(090, TextName.metlist_00000), + new(098, TextName.SpeciesNames), + new(114, TextName.ItemNames), + new(117, TextName.ItemFlavor), + new(153, TextName.MaisonTrainerNames), + new(154, TextName.SuperTrainerNames), + new(165, TextName.OPowerFlavor), + }; + + private static readonly TextReference[] SMDEMO = + { + new(020, TextName.ItemFlavor), + new(021, TextName.ItemNames), + new(026, TextName.SpeciesNames), + new(030, TextName.metlist_00000), + new(044, TextName.Forms), + new(044, TextName.Natures), + new(046, TextName.AbilityNames), + new(049, TextName.TrainerText), + new(050, TextName.TrainerNames), + new(051, TextName.TrainerClasses), + new(052, TextName.Types), + new(054, TextName.MoveFlavor), + new(055, TextName.MoveNames), + }; + + private static readonly TextReference[] SM = + { + new(035, TextName.ItemFlavor), + new(036, TextName.ItemNames), + new(055, TextName.SpeciesNames), + new(067, TextName.metlist_00000), + new(086, TextName.BattleRoyalNames), + new(087, TextName.Natures), + new(096, TextName.AbilityNames), + new(099, TextName.BattleTreeNames), + new(104, TextName.TrainerText), + new(105, TextName.TrainerNames), + new(106, TextName.TrainerClasses), + new(107, TextName.Types), + new(112, TextName.MoveFlavor), + new(113, TextName.MoveNames), + new(114, TextName.Forms), + new(116, TextName.SpeciesClassifications), + new(119, TextName.PokedexEntry1), + new(120, TextName.PokedexEntry2) + }; + + private static readonly TextReference[] USUM = + { + new(039, TextName.ItemFlavor), + new(040, TextName.ItemNames), + new(060, TextName.SpeciesNames), + new(072, TextName.metlist_00000), + new(091, TextName.BattleRoyalNames), + new(092, TextName.Natures), + new(101, TextName.AbilityNames), + new(104, TextName.BattleTreeNames), + new(109, TextName.TrainerText), + new(110, TextName.TrainerNames), + new(111, TextName.TrainerClasses), + new(112, TextName.Types), + new(117, TextName.MoveFlavor), + new(118, TextName.MoveNames), + new(119, TextName.Forms), + new(121, TextName.SpeciesClassifications), + new(124, TextName.PokedexEntry1), + new(125, TextName.PokedexEntry2) + }; + + private static readonly TextReference[] GG = + { + new("iteminfo.dat", TextName.ItemFlavor), + new("itemname.dat", TextName.ItemNames), + new("monsname.dat", TextName.SpeciesNames), + new("place_name.dat", TextName.metlist_00000), + new("seikaku.dat", TextName.Natures), + new("tokusei.dat", TextName.AbilityNames), + new("tokuseiinfo.dat", TextName.AbilityFlavor), + new("trname.dat", TextName.TrainerNames), + new("trtype.dat", TextName.TrainerClasses), + new("trmsg.dat", TextName.TrainerText), + new("typename.dat", TextName.Types), + new("wazainfo.dat", TextName.MoveFlavor), + new("wazaname.dat", TextName.MoveNames), + new("zkn_form.dat", TextName.Forms), + new("zkn_type.dat", TextName.SpeciesClassifications), + new("zukan_comment_A.dat", TextName.PokedexEntry1), + }; + + private static readonly TextReference[] SWSH = + { + new("iteminfo.dat", TextName.ItemFlavor), + new("itemname.dat", TextName.ItemNames), + new("monsname.dat", TextName.SpeciesNames), + new("place_name_indirect.dat", TextName.metlist_00000), + new("place_name_spe.dat", TextName.metlist_30000), + new("place_name_out.dat", TextName.metlist_40000), + new("place_name_per.dat", TextName.metlist_60000), + new("seikaku.dat", TextName.Natures), + new("tokusei.dat", TextName.AbilityNames), + new("tokuseiinfo.dat", TextName.AbilityFlavor), + new("trname.dat", TextName.TrainerNames), + new("trtype.dat", TextName.TrainerClasses), + new("trmsg.dat", TextName.TrainerText), + new("typename.dat", TextName.Types), + new("wazainfo.dat", TextName.MoveFlavor), + new("wazaname.dat", TextName.MoveNames), + new("zkn_form.dat", TextName.Forms), + new("zkn_type.dat", TextName.SpeciesClassifications), + new("zukan_comment_A.dat", TextName.PokedexEntry1), + new("zukan_comment_B.dat", TextName.PokedexEntry2), + new("ribbon.dat", TextName.RibbonMark), + new("poke_memory_feeling.dat", TextName.MemoryFeelings), + }; + + + private static readonly TextReference[] PLA = + { + new("iteminfo.dat", TextName.ItemFlavor), + new("itemname.dat", TextName.ItemNames), + new("monsname.dat", TextName.SpeciesNames), + new("place_name_indirect.dat", TextName.metlist_00000), + new("place_name_spe.dat", TextName.metlist_30000), + new("place_name_out.dat", TextName.metlist_40000), + new("place_name_per.dat", TextName.metlist_60000), + new("seikaku.dat", TextName.Natures), + new("tokusei.dat", TextName.AbilityNames), + new("tokuseiinfo.dat", TextName.AbilityFlavor), + new("trname.dat", TextName.TrainerNames), + new("trtype.dat", TextName.TrainerClasses), + new("trmsg.dat", TextName.TrainerText), + new("typename.dat", TextName.Types), + new("wazainfo.dat", TextName.MoveFlavor), + new("wazaname.dat", TextName.MoveNames), + new("zkn_form.dat", TextName.Forms), + new("zkn_type.dat", TextName.SpeciesClassifications), + new("zukan_comment_A.dat", TextName.PokedexEntry1), + new("zukan_comment_B.dat", TextName.PokedexEntry2), + new("ribbon.dat", TextName.RibbonMark), + new("poke_memory_feeling.dat", TextName.MemoryFeelings), + }; } \ No newline at end of file diff --git a/pkNX.Game/Text/TextName.cs b/pkNX.Game/Text/TextName.cs index ba2d17a8..7b6c786d 100644 --- a/pkNX.Game/Text/TextName.cs +++ b/pkNX.Game/Text/TextName.cs @@ -1,39 +1,38 @@ -namespace pkNX.Game +namespace pkNX.Game; + +public enum TextName { - public enum TextName - { - AbilityNames, - AbilityFlavor, + AbilityNames, + AbilityFlavor, - MoveNames, - MoveFlavor, + MoveNames, + MoveFlavor, - ItemNames, - ItemFlavor, + ItemNames, + ItemFlavor, - SpeciesNames, - Types, - Natures, - Forms, + SpeciesNames, + Types, + Natures, + Forms, - TrainerNames, - TrainerClasses, - TrainerText, - metlist_00000, - metlist_30000, - metlist_40000, - metlist_60000, - OPowerFlavor, - MaisonTrainerNames, - SuperTrainerNames, - BattleRoyalNames, - BattleTreeNames, + TrainerNames, + TrainerClasses, + TrainerText, + metlist_00000, + metlist_30000, + metlist_40000, + metlist_60000, + OPowerFlavor, + MaisonTrainerNames, + SuperTrainerNames, + BattleRoyalNames, + BattleTreeNames, - SpeciesClassifications, - PokedexEntry1, - PokedexEntry2, + SpeciesClassifications, + PokedexEntry1, + PokedexEntry2, - RibbonMark, - MemoryFeelings - } + RibbonMark, + MemoryFeelings } \ No newline at end of file diff --git a/pkNX.Game/Text/TextReference.cs b/pkNX.Game/Text/TextReference.cs index ee89309c..e9ba14c0 100644 --- a/pkNX.Game/Text/TextReference.cs +++ b/pkNX.Game/Text/TextReference.cs @@ -1,22 +1,21 @@  -namespace pkNX.Game +namespace pkNX.Game; + +public class TextReference { - public class TextReference + public readonly int Index; + public readonly TextName Name; + public readonly string FileName; + + internal TextReference(int index, TextName name) { - public readonly int Index; - public readonly TextName Name; - public readonly string FileName; - - internal TextReference(int index, TextName name) - { - Index = index; - Name = name; - } - - internal TextReference(string fileName, TextName name) - { - FileName = fileName; - Name = name; - } + Index = index; + Name = name; } -} + + internal TextReference(string fileName, TextName name) + { + FileName = fileName; + Name = name; + } +} \ No newline at end of file diff --git a/pkNX.Game/pkNX.Game.csproj b/pkNX.Game/pkNX.Game.csproj index cfd0c190..b27952ee 100644 --- a/pkNX.Game/pkNX.Game.csproj +++ b/pkNX.Game/pkNX.Game.csproj @@ -1,16 +1,11 @@ - netstandard2.0;net461 + net6.0 Game Data Manager 10 - - - - - diff --git a/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs b/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs index 9bdeb1b9..650e1b33 100644 --- a/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs +++ b/pkNX.Randomization/Randomizers/EvolutionRandomizer.cs @@ -1,135 +1,134 @@ -using pkNX.Structures; +using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +/// +/// randomizer. +/// +public class EvolutionRandomizer : Randomizer { - /// - /// randomizer. - /// - public class EvolutionRandomizer : Randomizer + private readonly EvolutionSet[] Evolutions; + private readonly GameInfo Game; + private readonly IPersonalTable Personal; + public readonly SpeciesRandomizer RandSpec; + public readonly FormRandomizer RandForm; + + public EvolutionRandomizer(GameInfo game, EvolutionSet[] evolutions, IPersonalTable t) { - private readonly EvolutionSet[] Evolutions; - private readonly GameInfo Game; - private readonly IPersonalTable Personal; - public readonly SpeciesRandomizer RandSpec; - public readonly FormRandomizer RandForm; + Game = game; + Personal = t; + Evolutions = evolutions; + RandSpec = new SpeciesRandomizer(Game, t); + RandForm = new FormRandomizer(t); + } - public EvolutionRandomizer(GameInfo game, EvolutionSet[] evolutions, IPersonalTable t) + public override void Execute() + { + for (var i = 0; i < Evolutions.Length; i++) { - Game = game; - Personal = t; - Evolutions = evolutions; - RandSpec = new SpeciesRandomizer(Game, t); - RandForm = new FormRandomizer(t); + var evo = Evolutions[i]; + if (Personal[i].HP == 0) + continue; + Randomize(evo, i); } + } - public override void Execute() + public void ExecuteTrade() + { + for (var i = 0; i < Evolutions.Length; i++) { - for (var i = 0; i < Evolutions.Length; i++) - { - var evo = Evolutions[i]; - if (Personal[i].HP == 0) - continue; - Randomize(evo, i); - } + var evo = Evolutions[i]; + ReplaceTradeMethods(evo, i); } + } - public void ExecuteTrade() + public void ExecuteEvolveEveryLevel() + { + for (var i = 0; i < Evolutions.Length; i++) { - for (var i = 0; i < Evolutions.Length; i++) - { - var evo = Evolutions[i]; - ReplaceTradeMethods(evo, i); - } + var evo = Evolutions[i]; + if (Personal[i].HP == 0) + continue; + Personal[i].EXPGrowth = (int)EXPGroup.Slow; // keep everything the same to preserve levels after evolving + MakeEvolveEveryLevel(evo, i); } + } - public void ExecuteEvolveEveryLevel() + private void Randomize(EvolutionSet evos, int species) + { + foreach (var evo in evos.PossibleEvolutions) { - for (var i = 0; i < Evolutions.Length; i++) + if (evo.Method != 0) { - var evo = Evolutions[i]; - if (Personal[i].HP == 0) - continue; - Personal[i].EXPGrowth = (int)EXPGroup.Slow; // keep everything the same to preserve levels after evolving - MakeEvolveEveryLevel(evo, i); - } - } - - private void Randomize(EvolutionSet evos, int species) - { - foreach (var evo in evos.PossibleEvolutions) - { - if (evo.Method != 0) - { - evo.Species = (ushort)RandSpec.GetRandomSpecies(evo.Species, species); - evo.Form = (byte)RandForm.GetRandomForme(evo.Species, false, false, true, Game.SWSH, Personal.Table); - } - } - } - - private void ReplaceTradeMethods(EvolutionSet evos, int species) - { - for (var i = 0; i < evos.PossibleEvolutions.Length; i++) - { - var evo = evos.PossibleEvolutions[i]; - ReplaceTradeMethod(evo, species, i); - } - } - - private void ReplaceTradeMethod(EvolutionMethod evo, int species, int evoIndex) - { - switch (evo.Method) - { - case EvolutionType.Trade when Game.Generation == 6: - evo.Method = EvolutionType.LevelUp; // trade -> level up - evo.Argument = 30; - return; - case EvolutionType.Trade when Game.Generation >= 7: - evo.Method = EvolutionType.LevelUp; // trade -> level up - evo.Level = 30; - return; - case EvolutionType.TradeHeldItem: - evo.Method = EvolutionType.LevelUpHeldItemDay; - return; - case EvolutionType.TradeShelmetKarrablast: - evo.Method = EvolutionType.LevelUpWithTeammate; - if (species == (int)Species.Karrablast) - evo.Argument = (int)Species.Shelmet; // Karrablast with Shelmet - if (species == (int)Species.Shelmet) - evo.Argument = (int)Species.Karrablast; // Shelmet with Karrablast - return; - - case EvolutionType.LevelUpVersion: - evo.Method = evoIndex == 0 ? EvolutionType.LevelUpECl5 : EvolutionType.LevelUpECgeq5; - evo.Argument = 0; // clear ver - return; - case EvolutionType.LevelUpVersionDay: - evo.Method = EvolutionType.LevelUpFriendshipMorning; - evo.Argument = 0; // clear ver - return; - case EvolutionType.LevelUpVersionNight: - evo.Method = EvolutionType.LevelUpFriendshipNight; - evo.Argument = 0; // clear ver - return; - } - } - - private static void MakeEvolveEveryLevel(EvolutionSet evos, int species) - { - var evoSet = evos.PossibleEvolutions; - evoSet[0] = new EvolutionMethod - { - Argument = 0, // clear - Form = 0, // randomized later - Level = 1, - Method = EvolutionType.LevelUp, - Species = (ushort)species, // randomized later - }; - - if (evoSet[1].HasData) // has other branched evolutions; remove them - { - for (int i = 1; i < evoSet.Length; i++) - evoSet[i] = new EvolutionMethod(); + evo.Species = (ushort)RandSpec.GetRandomSpecies(evo.Species, species); + evo.Form = (byte)RandForm.GetRandomForme(evo.Species, false, false, true, Game.SWSH, Personal.Table); } } } -} \ No newline at end of file + + private void ReplaceTradeMethods(EvolutionSet evos, int species) + { + for (var i = 0; i < evos.PossibleEvolutions.Length; i++) + { + var evo = evos.PossibleEvolutions[i]; + ReplaceTradeMethod(evo, species, i); + } + } + + private void ReplaceTradeMethod(EvolutionMethod evo, int species, int evoIndex) + { + switch (evo.Method) + { + case EvolutionType.Trade when Game.Generation == 6: + evo.Method = EvolutionType.LevelUp; // trade -> level up + evo.Argument = 30; + return; + case EvolutionType.Trade when Game.Generation >= 7: + evo.Method = EvolutionType.LevelUp; // trade -> level up + evo.Level = 30; + return; + case EvolutionType.TradeHeldItem: + evo.Method = EvolutionType.LevelUpHeldItemDay; + return; + case EvolutionType.TradeShelmetKarrablast: + evo.Method = EvolutionType.LevelUpWithTeammate; + if (species == (int)Species.Karrablast) + evo.Argument = (int)Species.Shelmet; // Karrablast with Shelmet + if (species == (int)Species.Shelmet) + evo.Argument = (int)Species.Karrablast; // Shelmet with Karrablast + return; + + case EvolutionType.LevelUpVersion: + evo.Method = evoIndex == 0 ? EvolutionType.LevelUpECl5 : EvolutionType.LevelUpECgeq5; + evo.Argument = 0; // clear ver + return; + case EvolutionType.LevelUpVersionDay: + evo.Method = EvolutionType.LevelUpFriendshipMorning; + evo.Argument = 0; // clear ver + return; + case EvolutionType.LevelUpVersionNight: + evo.Method = EvolutionType.LevelUpFriendshipNight; + evo.Argument = 0; // clear ver + return; + } + } + + private static void MakeEvolveEveryLevel(EvolutionSet evos, int species) + { + var evoSet = evos.PossibleEvolutions; + evoSet[0] = new EvolutionMethod + { + Argument = 0, // clear + Form = 0, // randomized later + Level = 1, + Method = EvolutionType.LevelUp, + Species = (ushort)species, // randomized later + }; + + if (evoSet[1].HasData) // has other branched evolutions; remove them + { + for (int i = 1; i < evoSet.Length; i++) + evoSet[i] = new EvolutionMethod(); + } + } +} diff --git a/pkNX.Randomization/Randomizers/FormRandomizer.cs b/pkNX.Randomization/Randomizers/FormRandomizer.cs index dd5127df..482f12f4 100644 --- a/pkNX.Randomization/Randomizers/FormRandomizer.cs +++ b/pkNX.Randomization/Randomizers/FormRandomizer.cs @@ -1,84 +1,82 @@ -using pkNX.Structures; +using pkNX.Structures; using System; -using System.Linq; using static pkNX.Structures.Species; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public class FormRandomizer { - public class FormRandomizer + private readonly IPersonalTable Personal; + + public FormRandomizer(IPersonalTable t) { - private readonly IPersonalTable Personal; + Personal = t; + } - public FormRandomizer(IPersonalTable t) - { - Personal = t; - } + public int GetRandomForme(int species, bool mega, bool fused, bool alola, bool galar, IPersonalInfo[]? stats = null) + { + stats ??= Personal.Table; + if (stats[species].FormCount <= 1) + return 0; + bool IsGen6 = Personal.MaxSpeciesID == 721; - public int GetRandomForme(int species, bool mega, bool fused, bool alola, bool galar, IPersonalInfo[]? stats = null) + switch ((Species)species) { - stats ??= Personal.Table; - if (stats[species].FormCount <= 1) + // Rayquaza's Forme Count was unchanged in SWSH despite Megas being removed, so just in case the user allows random Megas, disallow this invalid Forme. + case Rayquaza when Personal.Table.Length == 1192: return 0; - bool IsGen6 = Personal.MaxSpeciesID == 721; + case Unown: + case Deerling: + case Sawsbuck: + return 31; // Random + case Greninja when !mega: + return 0; + case Scatterbug: + case Spewpa: + case Vivillon: + return 30; // save file specific + case Zygarde when !IsGen6: + return Util.Random.Next(4); // Complete Forme is battle only + case Minior: + return Util.Random.Next(7); // keep the core color a surprise - switch ((Species)species) + case Meowth when galar: + return Util.Random.Next(3); // Kanto, Alola, Galar + + // only allow Standard, not Zen Mode + case Darmanitan when galar: { - // Rayquaza's Forme Count was unchanged in SWSH despite Megas being removed, so just in case the user allows random Megas, disallow this invalid Forme. - case Rayquaza when Personal.Table.Length == 1192: - return 0; - case Unown: - case Deerling: - case Sawsbuck: - return 31; // Random - case Greninja when !mega: - return 0; - case Scatterbug: - case Spewpa: - case Vivillon: - return 30; // save file specific - case Zygarde when !IsGen6: - return Util.Random.Next(4); // Complete Forme is battle only - case Minior: - return Util.Random.Next(7); // keep the core color a surprise - - case Meowth when galar: - return Util.Random.Next(3); // Kanto, Alola, Galar - - // only allow Standard, not Zen Mode - case Darmanitan when galar: - { - int form = Util.Random.Next(stats[species].FormCount); - return form & 2; - } - - // some species have 1 invalid form among several other valid forms, handle them here - case Pikachu when Personal.Table.Length == 1192: - case Slowbro when galar: - { - int form = Util.Random.Next(stats[species].FormCount - 1); - int banned = GetInvalidForm(species, galar, Personal); - if (form == banned) - form++; - return form; - } + int form = Util.Random.Next(stats[species].FormCount); + return form & 2; } - if (Personal.Table.Length == 980 && species is (int)Pikachu or (int)Eevee) // gg tableB -- no starters, they crash trainer battles. - return 0; - if (alola && Legal.EvolveToAlolanForms.Contains((ushort)species)) - return Util.Random.Next(2); - if (galar && Legal.EvolveToGalarForms.Contains((ushort)species)) - return Util.Random.Next(2); - if (!Legal.BattleExclusiveForms.Contains(species) || mega || (fused && Legal.BattleFusions.Contains(species))) - return Util.Random.Next(stats[species].FormCount); // Slot-Random - return 0; + // some species have 1 invalid form among several other valid forms, handle them here + case Pikachu when Personal.Table.Length == 1192: + case Slowbro when galar: + { + int form = Util.Random.Next(stats[species].FormCount - 1); + int banned = GetInvalidForm(species, galar, Personal); + if (form == banned) + form++; + return form; + } } - public static int GetInvalidForm(int species, bool galar, IPersonalTable stats) => species switch - { - (int)Pikachu when stats.Table.Length == 1192 => 8, // LGPE Partner Pikachu - (int)Slowbro when galar => 1, // Mega Slowbro - _ => throw new ArgumentOutOfRangeException(nameof(species)) - }; + if (Personal.Table.Length == 980 && species is (int)Pikachu or (int)Eevee) // gg tableB -- no starters, they crash trainer battles. + return 0; + if (alola && Legal.EvolveToAlolanForms.Contains((ushort)species)) + return Util.Random.Next(2); + if (galar && Legal.EvolveToGalarForms.Contains((ushort)species)) + return Util.Random.Next(2); + if (!Legal.BattleExclusiveForms.Contains(species) || mega || (fused && Legal.BattleFusions.Contains(species))) + return Util.Random.Next(stats[species].FormCount); // Slot-Random + return 0; } + + public static int GetInvalidForm(int species, bool galar, IPersonalTable stats) => species switch + { + (int)Pikachu when stats.Table.Length == 1192 => 8, // LGPE Partner Pikachu + (int)Slowbro when galar => 1, // Mega Slowbro + _ => throw new ArgumentOutOfRangeException(nameof(species)) + }; } diff --git a/pkNX.Randomization/Randomizers/GenericRandomizer.cs b/pkNX.Randomization/Randomizers/GenericRandomizer.cs index 90ee4573..493d85b6 100644 --- a/pkNX.Randomization/Randomizers/GenericRandomizer.cs +++ b/pkNX.Randomization/Randomizers/GenericRandomizer.cs @@ -1,43 +1,42 @@ -namespace pkNX.Randomization +namespace pkNX.Randomization; + +/// Cyclical Shuffled Randomizer +/// +/// The shuffled list is iterated over, and reshuffled when exhausted. +/// The list does not repeat values until the list is exhausted. +/// +public class GenericRandomizer { - /// Cyclical Shuffled Randomizer - /// - /// The shuffled list is iterated over, and reshuffled when exhausted. - /// The list does not repeat values until the list is exhausted. - /// - public class GenericRandomizer + public GenericRandomizer(T[] randomValues) { - public GenericRandomizer(T[] randomValues) - { - RandomValues = randomValues; - } + RandomValues = randomValues; + } - private readonly T[] RandomValues; - private int ctr; - public int Count => RandomValues.Length; + private readonly T[] RandomValues; + private int ctr; + public int Count => RandomValues.Length; - public void Reset() - { - ctr = 0; + public void Reset() + { + ctr = 0; + Util.Shuffle(RandomValues); + } + + public T Next() + { + if (ctr == 0) Util.Shuffle(RandomValues); - } - public T Next() - { - if (ctr == 0) - Util.Shuffle(RandomValues); + T value = RandomValues[ctr++]; + ctr %= RandomValues.Length; + return value; + } - T value = RandomValues[ctr++]; - ctr %= RandomValues.Length; - return value; - } - - public T[] GetMany(int count) - { - var arr = new T[count]; - for (int i = 0; i < arr.Length; i++) - arr[i] = Next(); - return arr; - } + public T[] GetMany(int count) + { + var arr = new T[count]; + for (int i = 0; i < arr.Length; i++) + arr[i] = Next(); + return arr; } } diff --git a/pkNX.Randomization/Randomizers/LearnsetRandomizer.cs b/pkNX.Randomization/Randomizers/LearnsetRandomizer.cs index d86aceeb..dc123f79 100644 --- a/pkNX.Randomization/Randomizers/LearnsetRandomizer.cs +++ b/pkNX.Randomization/Randomizers/LearnsetRandomizer.cs @@ -1,158 +1,157 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +/// +/// randomizer. +/// +public class LearnsetRandomizer : Randomizer { - /// - /// randomizer. - /// - public class LearnsetRandomizer : Randomizer + private readonly Learnset[] Learnsets; + private readonly GameInfo Game; + private readonly IPersonalTable Personal; + private MoveRandomizer moverand; + public IReadOnlyList Moves { private get; set; } = Array.Empty(); + + public LearnSettings Settings { get; private set; } = new(); + public IList BannedMoves { set => moverand.Settings.BannedMoves = value; } + + public LearnsetRandomizer(GameInfo game, Learnset[] learnsets, IPersonalTable t) { - private readonly Learnset[] Learnsets; - private readonly GameInfo Game; - private readonly IPersonalTable Personal; - private MoveRandomizer moverand; - public IReadOnlyList Moves { private get; set; } = Array.Empty(); + Game = game; + Learnsets = learnsets; + Personal = t; - public LearnSettings Settings { get; private set; } = new(); - public IList BannedMoves { set => moverand.Settings.BannedMoves = value; } + // temp, overwrite later if using it + moverand = new MoveRandomizer(game, Moves, Personal); + } - public LearnsetRandomizer(GameInfo game, Learnset[] learnsets, IPersonalTable t) + private static readonly int[] MetronomeMove = { 118 }; + private static readonly int[] MetronomeLevel = { 1 }; + + public void ExecuteMetronome() + { + foreach (var learn in Learnsets) + learn.Update(MetronomeMove, MetronomeLevel); + } + + public void ExecuteExpandOnly() + { + foreach (var learn in Learnsets) { - Game = game; - Learnsets = learnsets; - Personal = t; - - // temp, overwrite later if using it - moverand = new MoveRandomizer(game, Moves, Personal); - } - - private static readonly int[] MetronomeMove = { 118 }; - private static readonly int[] MetronomeLevel = { 1 }; - - public void ExecuteMetronome() - { - foreach (var learn in Learnsets) - learn.Update(MetronomeMove, MetronomeLevel); - } - - public void ExecuteExpandOnly() - { - foreach (var learn in Learnsets) - { - var count = learn.Count; - if (count == 0) - continue; - if (count >= Settings.ExpandTo) - continue; - - int diff = Settings.ExpandTo - count; - var moves = learn.Moves; - Array.Resize(ref moves, Settings.ExpandTo); - var levels = learn.Moves; - Array.Resize(ref levels, Settings.ExpandTo); - for (int i = count; i < Settings.ExpandTo; i++) - { - moves[i] = 1; - levels[i] = Math.Min(100, levels[count - 1] + diff); - } - learn.Update(moves, levels); - } - } - - public void Initialize(IMove[] moves, LearnSettings settings, MovesetRandSettings moverandset, int[]? bannedMoves = null) - { - Moves = moves; - Settings = settings; - - moverand = new MoveRandomizer(Game, Moves, Personal); - moverand.Initialize(moverandset, bannedMoves ?? Array.Empty()); - } - - public override void Execute() - { - for (var i = 0; i < Learnsets.Length; i++) - { - if (Personal[i].HP == 0) - continue; - Randomize(Learnsets[i], i); - } - } - - private void Randomize(Learnset set, int index) - { - int[] moves = GetRandomMoves(set.Count, index); - int[] levels = GetRandomLevels(set, moves.Length); - - if (Settings.Learn4Level1) - { - for (int i = 0; i < Math.Min(4, levels.Length); ++i) - levels[i] = 1; - } - - set.Update(moves, levels); - } - - private int[] GetRandomLevels(Learnset set, int count) - { - int[] levels = new int[count]; + var count = learn.Count; if (count == 0) - return levels; - if (Settings.Spread) + continue; + if (count >= Settings.ExpandTo) + continue; + + int diff = Settings.ExpandTo - count; + var moves = learn.Moves; + Array.Resize(ref moves, Settings.ExpandTo); + var levels = learn.Moves; + Array.Resize(ref levels, Settings.ExpandTo); + for (int i = count; i < Settings.ExpandTo; i++) { - levels[0] = 1; - decimal increment = Settings.SpreadTo / (decimal)count; - for (int i = 1; i < count; i++) - levels[i] = (int)(i * increment); - return levels; + moves[i] = 1; + levels[i] = Math.Min(100, levels[count - 1] + diff); } - if (levels.Length == count && levels.Length == set.Levels.Length) - return set.Levels; // don't modify - - var exist = set.Levels; - int lastlevel = Math.Min(1, exist.LastOrDefault()); - exist.CopyTo(levels, 0); - for (int i = exist.Length; i < levels.Length; i++) - levels[i] = Math.Max(100, lastlevel + (exist.Length - i + 1)); - - return levels; - } - - private int[] GetRandomMoves(int count, int index) - { - count = Settings.Expand ? Settings.ExpandTo : count; - - int[] moves = new int[count]; - if (count == 0) - return moves; - moves[0] = Settings.STABFirst ? moverand.GetRandomFirstMove(index) : MoveRandomizer.GetRandomFirstMoveAny(); - var rand = moverand.GetRandomLearnset(index, count - 1); - - // STAB Moves (if requested) come first; randomize the order of moves - Util.Shuffle(rand); - if (Settings.OrderByPower) - moverand.ReorderMovesPower(rand); - rand.CopyTo(moves, 1); - return moves; - } - - internal int[] GetHighPoweredMoves(ushort species, byte form, int count = 4) => GetHighPoweredMoves(Moves, species, form, count); - - public int[] GetCurrentMoves(ushort species, byte form, int level, int count = 4) - { - int i = Personal.GetFormIndex(species, form); - var moves = Learnsets[i].GetEncounterMoves(level); - Array.Resize(ref moves, count); - return moves; - } - - public int[] GetHighPoweredMoves(IReadOnlyList movedata, ushort species, byte form, int count = 4) - { - int index = Personal.GetFormIndex(species, form); - var learn = Learnsets[index]; - return learn.GetHighPoweredMoves(count, movedata); + learn.Update(moves, levels); } } -} \ No newline at end of file + + public void Initialize(IMove[] moves, LearnSettings settings, MovesetRandSettings moverandset, int[]? bannedMoves = null) + { + Moves = moves; + Settings = settings; + + moverand = new MoveRandomizer(Game, Moves, Personal); + moverand.Initialize(moverandset, bannedMoves ?? Array.Empty()); + } + + public override void Execute() + { + for (var i = 0; i < Learnsets.Length; i++) + { + if (Personal[i].HP == 0) + continue; + Randomize(Learnsets[i], i); + } + } + + private void Randomize(Learnset set, int index) + { + int[] moves = GetRandomMoves(set.Count, index); + int[] levels = GetRandomLevels(set, moves.Length); + + if (Settings.Learn4Level1) + { + for (int i = 0; i < Math.Min(4, levels.Length); ++i) + levels[i] = 1; + } + + set.Update(moves, levels); + } + + private int[] GetRandomLevels(Learnset set, int count) + { + int[] levels = new int[count]; + if (count == 0) + return levels; + if (Settings.Spread) + { + levels[0] = 1; + decimal increment = Settings.SpreadTo / (decimal)count; + for (int i = 1; i < count; i++) + levels[i] = (int)(i * increment); + return levels; + } + if (levels.Length == count && levels.Length == set.Levels.Length) + return set.Levels; // don't modify + + var exist = set.Levels; + int lastlevel = Math.Min(1, exist.LastOrDefault()); + exist.CopyTo(levels, 0); + for (int i = exist.Length; i < levels.Length; i++) + levels[i] = Math.Max(100, lastlevel + (exist.Length - i + 1)); + + return levels; + } + + private int[] GetRandomMoves(int count, int index) + { + count = Settings.Expand ? Settings.ExpandTo : count; + + int[] moves = new int[count]; + if (count == 0) + return moves; + moves[0] = Settings.STABFirst ? moverand.GetRandomFirstMove(index) : MoveRandomizer.GetRandomFirstMoveAny(); + var rand = moverand.GetRandomLearnset(index, count - 1); + + // STAB Moves (if requested) come first; randomize the order of moves + Util.Shuffle(rand); + if (Settings.OrderByPower) + moverand.ReorderMovesPower(rand); + rand.CopyTo(moves, 1); + return moves; + } + + internal int[] GetHighPoweredMoves(ushort species, byte form, int count = 4) => GetHighPoweredMoves(Moves, species, form, count); + + public int[] GetCurrentMoves(ushort species, byte form, int level, int count = 4) + { + int i = Personal.GetFormIndex(species, form); + var moves = Learnsets[i].GetEncounterMoves(level); + Array.Resize(ref moves, count); + return moves; + } + + public int[] GetHighPoweredMoves(IReadOnlyList movedata, ushort species, byte form, int count = 4) + { + int index = Personal.GetFormIndex(species, form); + var learn = Learnsets[index]; + return learn.GetHighPoweredMoves(count, movedata); + } +} diff --git a/pkNX.Randomization/Randomizers/MoveRandType.cs b/pkNX.Randomization/Randomizers/MoveRandType.cs index 00be587c..1f29503a 100644 --- a/pkNX.Randomization/Randomizers/MoveRandType.cs +++ b/pkNX.Randomization/Randomizers/MoveRandType.cs @@ -1,11 +1,10 @@ -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public enum MoveRandType { - public enum MoveRandType - { - None, - RandomMoves, - LevelUpMoves, - HighPowered, - MetronomeOnly, - } -} \ No newline at end of file + None, + RandomMoves, + LevelUpMoves, + HighPowered, + MetronomeOnly, +} diff --git a/pkNX.Randomization/Randomizers/MoveRandomizer.cs b/pkNX.Randomization/Randomizers/MoveRandomizer.cs index 4dbbf06f..d3e2502c 100644 --- a/pkNX.Randomization/Randomizers/MoveRandomizer.cs +++ b/pkNX.Randomization/Randomizers/MoveRandomizer.cs @@ -3,179 +3,178 @@ using System.Linq; using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public class MoveRandomizer : Randomizer { - public class MoveRandomizer : Randomizer + private readonly IReadOnlyList MoveData; + private readonly IPersonalTable SpeciesStat; + private readonly GameInfo Config; + + private GenericRandomizer RandMove; + internal MovesetRandSettings Settings = new(); + + public MoveRandomizer(GameInfo config, IReadOnlyList moves, IPersonalTable t) { - private readonly IReadOnlyList MoveData; - private readonly IPersonalTable SpeciesStat; - private readonly GameInfo Config; - - private GenericRandomizer RandMove; - internal MovesetRandSettings Settings = new(); - - public MoveRandomizer(GameInfo config, IReadOnlyList moves, IPersonalTable t) - { - Config = config; - var maxMoveId = config.MaxMoveID; - MoveData = moves; - SpeciesStat = t; - RandMove = new GenericRandomizer(Enumerable.Range(1, maxMoveId - 1).ToArray()); - } - - public override void Execute() => throw new Exception("Shouldn't be called."); - - public static readonly int[] FixedDamageMoves = { 49, 82 }; - - public void Initialize(MovesetRandSettings settings, int[] bannedMoves) - { - Settings = settings; - - var banned = new List(); - banned.AddRange(Legal.Taboo_Moves.Concat(Legal.Z_Moves).Concat(Legal.Max_Moves)); - if (Settings.BanFixedDamageMoves) - banned.AddRange(FixedDamageMoves); - banned.AddRange(bannedMoves); - - Settings.BannedMoves = banned.ToArray(); - - var all = Enumerable.Range(1, Config.MaxMoveID - 1); - var moves = all.Except(banned); - if (MoveData[0] is Move8Fake) - moves = moves.Where(z => ((Move8Fake)MoveData[z]).CanUseMove); - RandMove = new GenericRandomizer(moves.ToArray()); - } - - public int[] GetRandomLearnset(int index, int movecount) => GetRandomLearnset(SpeciesStat[index], movecount); - - public int[] GetRandomLearnset(IPersonalType Types, int movecount) - { - var oldSTABCount = Settings.STABCount; - Settings.STABCount = (int)(Settings.STABPercent * movecount / 100); - int[] moves = GetRandomMoveset(Types, movecount); - Settings.STABCount = oldSTABCount; - return moves; - } - - public int[] GetRandomMoveset(int index, int movecount = 4) => GetRandomMoveset(SpeciesStat[index], movecount); - - public int[] GetRandomMoveset(IPersonalType Types, int movecount = 4) - { - int loopctr = 0; - const int maxLoop = 666; - - int[] moves; - do { moves = GetRandomMoves(Types, movecount); } - while (!IsMovesetMeetingRequirements(moves, Types, movecount) && loopctr++ <= maxLoop); - - return moves; - } - - private int[] GetRandomMoves(IPersonalType Types, int movecount = 4) - { - int[] moves = new int[movecount]; - int i = 0; - if (Settings.STAB) - { - for (; i < Settings.STABCount; i++) - moves[i] = GetRandomSTABMove(Types); - } - - for (; i < moves.Length; i++) // remainder of moves - moves[i] = RandMove.Next(); - return moves; - } - - private int GetRandomSTABMove(IPersonalType types) - { - int move; - int ctr = 0; - do { move = RandMove.Next(); } - while (!types.IsType((Types)MoveData[move].Type) && ctr++ < RandMove.Count); - return move; - } - - private bool IsMovesetMeetingRequirements(int[] moves, IPersonalType types, int count) - { - if (Settings.DMG && Settings.DMGCount > moves.Count(move => MoveData[move].Category != 0)) - return false; - - if (Settings.STAB) - { - var stabCt = moves.Count(move => types.IsType((Types)MoveData[move].Type)); - if (stabCt < Settings.STABCount) - return false; - } - - if (moves.Any(Settings.BannedMoves.Contains)) - return false; - - return moves.Distinct().Count() == count; - } - - public void ReorderMovesPower(IList moves) => ReorderMovesPower(moves, MoveData); - - private static void ReorderMovesPower(IList moves, IReadOnlyList movedata) - { - var data = moves.Select((Move, Index) => new { Index, Move, Data = movedata[Move] }); - var powered = data.Where(z => z.Data.Power > 1).ToList(); - var indexes = powered.ConvertAll(z => z.Index); - var order = powered.OrderBy(z => z.Data.Power * Math.Max(1, (z.Data.HitMin + z.Data.HitMax) / 2m)).ToList(); - - for (var i = 0; i < order.Count; i++) - moves[indexes[i]] = order[i].Move; - } - - private static readonly int[] firstMoves = - { - 1, // Pound - 40, // Poison Sting - 52, // Ember - 55, // Water Gun - 64, // Peck - 71, // Absorb - 84, // Thunder Shock - 98, // Quick Attack - 122, // Lick - 141, // Leech Life - }; - - private static readonly GenericRandomizer first = new(firstMoves); - - public static int GetRandomFirstMoveAny() - { - first.Reset(); - return first.Next(); - } - - public int GetRandomFirstMove(int index) => GetRandomFirstMove(SpeciesStat[index]); - - public int GetRandomFirstMove(IPersonalType types) - { - first.Reset(); - int ctr = 0; - int move; - do - { - move = first.Next(); - if (++ctr == firstMoves.Length) - return move; - } while (!types.IsType((Types)MoveData[move].Type)); - return move; - } - - public bool SanitizeMovesetForBannedMoves(int[] moves, int index) - { - bool updated = false; - for (int m = 0; m < moves.Length; m++) - { - if (!Settings.BannedMoves.Contains(moves[m])) - continue; - updated = true; - moves[m] = GetRandomFirstMove(index); - } - - return updated; - } + Config = config; + var maxMoveId = config.MaxMoveID; + MoveData = moves; + SpeciesStat = t; + RandMove = new GenericRandomizer(Enumerable.Range(1, maxMoveId - 1).ToArray()); } -} \ No newline at end of file + + public override void Execute() => throw new Exception("Shouldn't be called."); + + public static readonly int[] FixedDamageMoves = { 49, 82 }; + + public void Initialize(MovesetRandSettings settings, int[] bannedMoves) + { + Settings = settings; + + var banned = new List(); + banned.AddRange(Legal.Taboo_Moves.Concat(Legal.Z_Moves).Concat(Legal.Max_Moves)); + if (Settings.BanFixedDamageMoves) + banned.AddRange(FixedDamageMoves); + banned.AddRange(bannedMoves); + + Settings.BannedMoves = banned.ToArray(); + + var all = Enumerable.Range(1, Config.MaxMoveID - 1); + var moves = all.Except(banned); + if (MoveData[0] is Move8Fake) + moves = moves.Where(z => ((Move8Fake)MoveData[z]).CanUseMove); + RandMove = new GenericRandomizer(moves.ToArray()); + } + + public int[] GetRandomLearnset(int index, int movecount) => GetRandomLearnset(SpeciesStat[index], movecount); + + public int[] GetRandomLearnset(IPersonalType Types, int movecount) + { + var oldSTABCount = Settings.STABCount; + Settings.STABCount = (int)(Settings.STABPercent * movecount / 100); + int[] moves = GetRandomMoveset(Types, movecount); + Settings.STABCount = oldSTABCount; + return moves; + } + + public int[] GetRandomMoveset(int index, int movecount = 4) => GetRandomMoveset(SpeciesStat[index], movecount); + + public int[] GetRandomMoveset(IPersonalType Types, int movecount = 4) + { + int loopctr = 0; + const int maxLoop = 666; + + int[] moves; + do { moves = GetRandomMoves(Types, movecount); } + while (!IsMovesetMeetingRequirements(moves, Types, movecount) && loopctr++ <= maxLoop); + + return moves; + } + + private int[] GetRandomMoves(IPersonalType Types, int movecount = 4) + { + int[] moves = new int[movecount]; + int i = 0; + if (Settings.STAB) + { + for (; i < Settings.STABCount; i++) + moves[i] = GetRandomSTABMove(Types); + } + + for (; i < moves.Length; i++) // remainder of moves + moves[i] = RandMove.Next(); + return moves; + } + + private int GetRandomSTABMove(IPersonalType types) + { + int move; + int ctr = 0; + do { move = RandMove.Next(); } + while (!types.IsType((Types)MoveData[move].Type) && ctr++ < RandMove.Count); + return move; + } + + private bool IsMovesetMeetingRequirements(int[] moves, IPersonalType types, int count) + { + if (Settings.DMG && Settings.DMGCount > moves.Count(move => MoveData[move].Category != 0)) + return false; + + if (Settings.STAB) + { + var stabCt = moves.Count(move => types.IsType((Types)MoveData[move].Type)); + if (stabCt < Settings.STABCount) + return false; + } + + if (moves.Any(Settings.BannedMoves.Contains)) + return false; + + return moves.Distinct().Count() == count; + } + + public void ReorderMovesPower(IList moves) => ReorderMovesPower(moves, MoveData); + + private static void ReorderMovesPower(IList moves, IReadOnlyList movedata) + { + var data = moves.Select((Move, Index) => new { Index, Move, Data = movedata[Move] }); + var powered = data.Where(z => z.Data.Power > 1).ToList(); + var indexes = powered.ConvertAll(z => z.Index); + var order = powered.OrderBy(z => z.Data.Power * Math.Max(1, (z.Data.HitMin + z.Data.HitMax) / 2m)).ToList(); + + for (var i = 0; i < order.Count; i++) + moves[indexes[i]] = order[i].Move; + } + + private static readonly int[] firstMoves = + { + 1, // Pound + 40, // Poison Sting + 52, // Ember + 55, // Water Gun + 64, // Peck + 71, // Absorb + 84, // Thunder Shock + 98, // Quick Attack + 122, // Lick + 141, // Leech Life + }; + + private static readonly GenericRandomizer first = new(firstMoves); + + public static int GetRandomFirstMoveAny() + { + first.Reset(); + return first.Next(); + } + + public int GetRandomFirstMove(int index) => GetRandomFirstMove(SpeciesStat[index]); + + public int GetRandomFirstMove(IPersonalType types) + { + first.Reset(); + int ctr = 0; + int move; + do + { + move = first.Next(); + if (++ctr == firstMoves.Length) + return move; + } while (!types.IsType((Types)MoveData[move].Type)); + return move; + } + + public bool SanitizeMovesetForBannedMoves(int[] moves, int index) + { + bool updated = false; + for (int m = 0; m < moves.Length; m++) + { + if (!Settings.BannedMoves.Contains(moves[m])) + continue; + updated = true; + moves[m] = GetRandomFirstMove(index); + } + + return updated; + } +} diff --git a/pkNX.Randomization/Randomizers/Personal/Consistency.cs b/pkNX.Randomization/Randomizers/Personal/Consistency.cs index 99b286ad..059f897e 100644 --- a/pkNX.Randomization/Randomizers/Personal/Consistency.cs +++ b/pkNX.Randomization/Randomizers/Personal/Consistency.cs @@ -1,29 +1,28 @@ -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public enum RandSetting { - public enum RandSetting - { - Unchanged, - Randomized, - } - - public enum Permissive - { - Yes, - No, - } - - public enum ModifyState - { - Shared, - One, - Two, - All, - } - - public enum CatchRate - { - Unchanged, - BSTScaled, - Random, - } + Unchanged, + Randomized, +} + +public enum Permissive +{ + Yes, + No, +} + +public enum ModifyState +{ + Shared, + One, + Two, + All, +} + +public enum CatchRate +{ + Unchanged, + BSTScaled, + Random, } diff --git a/pkNX.Randomization/Randomizers/Personal/PersonalRandSettings.cs b/pkNX.Randomization/Randomizers/Personal/PersonalRandSettings.cs index 1f4d1846..972539ce 100644 --- a/pkNX.Randomization/Randomizers/Personal/PersonalRandSettings.cs +++ b/pkNX.Randomization/Randomizers/Personal/PersonalRandSettings.cs @@ -1,210 +1,208 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; -using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +/// +/// Randomization settings when randomizing a personal info instance. +/// +[Serializable] +[TypeConverter(typeof(ExpandableObjectConverter))] +public class PersonalRandSettings : RandSettings { + private const string Moves = nameof(Moves); + private const string Types = nameof(Types); + private const string Stats = nameof(Stats); + private const string Abilities = nameof(Abilities); + private const string Misc = nameof(Misc); + private const string Evolutions = nameof(Evolutions); + + /// Toggle to use Evolution data for inherited personal info instance properties. + [Category("A1"), Description("Evolution Chain Species Randomization instead of Pure Random. Refer to the Evolutions settings when using this mode.")] + public bool ModifyByEvolutions { get; set; } = true; + + #region Moves + /// Permits randomizing the TM learn permission flags. + [Category(Moves), Description("Enables randomizing the TM (Technical Machine) compatibility flags.")] + public bool ModifyLearnsetTM { get; set; } = true; + + /// Permits randomizing the HM learn permission flags. + [Category(Moves), Description("Enables randomizing the HM (Hidden Machine) compatibility flags.")] + public bool ModifyLearnsetHM { get; set; } = true; + + /// Permits randomizing the move tutor permission flags. + [Category(Moves), Description("Enables randomizing the move tutor compatibility flags.")] + public bool ModifyLearnsetMoveTutors { get; set; } = true; + + /// Permits randomizing the type tutor permission flags. + [Category(Moves), Description("Enables randomizing the type tutor compatibility flags.")] + public bool ModifyLearnsetTypeTutors { get; set; } + + /// Percent chance to learn a TMHM move (0-100). + /// Average Learnable TMs is 35.260. + [Category(Moves), Description("Percentage chance to learn a given TM move.")] + public float LearnTMPercent { get; set; } = 35; + + /// Percent chance to learn a type tutor move (0-100). + /// 136 special tutor moves learnable by species in Untouched ORAS. + [Category(Moves), Description("Percentage chance to learn a given special Type Tutor move.")] + public float LearnTypeTutorPercent { get; set; } = 2; + + /// Percent chance to learn a tutor move (0-100). + /// 10001 tutor moves learnable by 826 species in Untouched ORAS. + [Category(Moves), Description("Percentage chance to learn a given Move Tutor move.")] + public float LearnMoveTutorPercent { get; set; } = 30; + #endregion + + #region Types + /// Permits modification of elemental types. + [Category(Types), Description("Enables a PKM's Type to be modified.")] + public bool ModifyTypes { get; set; } = true; + + /// Option to modify the elemental types. + [Category(Types), Description("Option to modify the Types depending on the specified setting.")] + public ModifyState Type { get; set; } = ModifyState.All; + + /// Chance that both types are the same. + [Category(Types), Description("Chance that both types are the same.")] + public float SameTypeChance { get; set; } = 50; + #endregion + + #region Ability + /// Toggle to permit modification of abilities. + [Category(Abilities), Description("Enables a PKM's Abilities to be modified.")] + public bool ModifyAbility { get; set; } = true; + + /// Permits Wonder Guard as a random ability. + [Category(Abilities), Description("Permits Wonder Guard as a random ability.")] + public Permissive WonderGuard { get; set; } = Permissive.No; + + /// Option to modify the abilities. + [Category(Abilities), Description("Option to modify the Abilities depending on the specified setting.")] + public ModifyState Ability { get; set; } = ModifyState.All; + + /// Chance that both abilities are the same. + [Category(Abilities), Description("Chance that both abilities are the same.")] + public float SameAbilityChance { get; set; } = 100; + #endregion + + #region Stats + /// Permits modification of Base Stats. + [Category(Stats), Description("Enables a PKM's base stats to be modified.")] + public bool ModifyStats { get; set; } = true; + + /// Amount a Base Stat is amplified as a low bound. + [Category(Stats), Description("Minimum Percentage bound a Base Stat is after randomizing. 100 corresponds to an unchanged minimum.")] + public int StatDeviationMin { get; set; } = 75; + + /// Amount a Base Stat is amplified as a high bound. + [Category(Stats), Description("Maximum Percentage bound a Base Stat is after randomizing. 100 corresponds to an unchanged maximum.")] + public int StatDeviationMax { get; set; } = 125; + + /// Toggle to permit shuffling of Base Stats. + [Category(Stats), Description("Shuffles the PKM's base stats after any modifications have been made.")] + public bool ShuffleStats { get; set; } = true; + + /// Permits randomizing the HP stat. + [Category(Stats), Description("Permits randomizing the HP base stat.")] + public bool HP { get; set; } = true; + + /// Permits randomizing the Attack stat. + [Category(Stats), Description("Permits randomizing the Attack base stat.")] + public bool ATK { get; set; } = true; + + /// Permits randomizing the Defense stat. + [Category(Stats), Description("Permits randomizing the Defense base stat.")] + public bool DEF { get; set; } = true; + + /// Permits randomizing the Special Attack stat. + [Category(Stats), Description("Permits randomizing the Special Attack base stat.")] + public bool SPA { get; set; } = true; + + /// Permits randomizing the Special Defense stat. + [Category(Stats), Description("Permits randomizing the Special Defense base stat.")] + public bool SPD { get; set; } = true; + + /// Permits randomizing the Speed stat. + [Category(Stats), Description("Permits randomizing the Speed base stat.")] + public bool SPE { get; set; } = true; + /// - /// Randomization settings when randomizing a . + /// Flags to edit the stats when randomizing. /// - [Serializable] - [TypeConverter(typeof(ExpandableObjectConverter))] - public class PersonalRandSettings : RandSettings - { - private const string Moves = nameof(Moves); - private const string Types = nameof(Types); - private const string Stats = nameof(Stats); - private const string Abilities = nameof(Abilities); - private const string Misc = nameof(Misc); - private const string Evolutions = nameof(Evolutions); + public IReadOnlyList StatsToRandomize => new[] {HP, ATK, DEF, SPE, SPA, SPD}; + #endregion - /// Toggle to use Evolution data for inherited properties. - [Category("A1"), Description("Evolution Chain Species Randomization instead of Pure Random. Refer to the Evolutions settings when using this mode.")] - public bool ModifyByEvolutions { get; set; } = true; + #region Misc + /// Option permitting modification of Catch Rate. + [Category(Misc), Description("Enables a PKM's catch rate to be modified. Can inversely scale off BST.")] + public CatchRate CatchRate { get; set; } = CatchRate.Unchanged; - #region Moves - /// Permits randomizing the values. - [Category(Moves), Description("Enables randomizing the TM (Technical Machine) compatibility flags.")] - public bool ModifyLearnsetTM { get; set; } = true; + /// Permits modification of Held Items. + [Category(Misc), Description("Enables a PKM's held items to be modified.")] + public bool ModifyHeldItems { get; set; } = true; - /// Permits randomizing the values. - [Category(Moves), Description("Enables randomizing the HM (Hidden Machine) compatibility flags.")] - public bool ModifyLearnsetHM { get; set; } = true; + /// Chance all held items are the same. + [Category(Misc), Description("Percentage chance that all Held Items are the same, resulting in a 100% chance of having the held item.")] + public float AlwaysHeldItemChance { get; set; } = 20; - /// Permits randomizing the values. - [Category(Moves), Description("Enables randomizing the move tutor compatibility flags.")] - public bool ModifyLearnsetMoveTutors { get; set; } = true; + /// Permits modification of Egg Groups. + [Category(Misc), Description("Enables a PKM's egg groups to be modified.")] + public bool ModifyEgg { get; set; } - /// Permits randomizing the values. - [Category(Moves), Description("Enables randomizing the type tutor compatibility flags.")] - public bool ModifyLearnsetTypeTutors { get; set; } = false; + /// Chance both egg groups are the same. + [Category(Misc), Description("Percentage chance that both egg groups will be the same.")] + public float SameEggGroupChance { get; set; } = 50; + #endregion - /// Percent chance to learn a TMHM move (0-100). - /// Average Learnable TMs is 35.260. - [Category(Moves), Description("Percentage chance to learn a given TM move.")] - public float LearnTMPercent { get; set; } = 35; + #region Evolutions + /// Toggles inheriting types from the pre-evolution that evolves into this species/form. + [Category(Evolutions), Description("Toggles inheriting types from the pre-evolution that evolves into this species/form.")] + public bool InheritType { get; set; } = true; - /// Percent chance to learn a type tutor move (0-100). - /// 136 special tutor moves learnable by species in Untouched ORAS. - [Category(Moves), Description("Percentage chance to learn a given special Type Tutor move.")] - public float LearnTypeTutorPercent { get; set; } = 2; + /// Maximum amount of Types that can be different from the pre-evolution. + [Category(Evolutions), Description("Maximum amount of Types that can be different from the pre-evolution.")] + public ModifyState InheritTypeSetting { get; set; } = ModifyState.One; - /// Percent chance to learn a tutor move (0-100). - /// 10001 tutor moves learnable by 826 species in Untouched ORAS. - [Category(Moves), Description("Percentage chance to learn a given Move Tutor move.")] - public float LearnMoveTutorPercent { get; set; } = 30; - #endregion + /// Percentage chance that only one type will be inherited, and a new random one will replace the other. + [Category(Evolutions), Description("Percentage chance that only one type will be inherited, and a new random one will replace the other.")] + public float InheritTypeOnlyOneChance { get; set; } = 65; - #region Types - /// Permits modification of . - [Category(Types), Description("Enables a PKM's Type to be modified.")] - public bool ModifyTypes { get; set; } = true; + /// Percentage chance that neither one type will be inherited, and new random ones will replace the others. + [Category(Evolutions), Description("Percentage chance that neither type will be inherited, and new random ones will replace the others.")] + public float InheritTypeNeitherChance { get; set; } = 30; - /// Option to modify the . - [Category(Types), Description("Option to modify the Types depending on the specified setting.")] - public ModifyState Type { get; set; } = ModifyState.All; + /// Toggles chance that neither one type will be inherited, and new random ones will replace the others. + [Category(Evolutions), Description("Amount of abilities that will be inherited, and new random ones will replace the others.")] + public ModifyState InheritAbilitySetting { get; set; } = ModifyState.One; - /// Chance that both types are the same. - [Category(Types), Description("Chance that both types are the same.")] - public float SameTypeChance { get; set; } = 50; - #endregion + /// Toggles inheriting abilities from the pre-evolution that evolves into this species/form. + [Category(Evolutions), Description("Toggles inheriting abilities from the pre-evolution that evolves into this species/form.")] + public bool InheritAbility { get; set; } = true; - #region Ability - /// Toggle to permit modification of . - [Category(Abilities), Description("Enables a PKM's Abilities to be modified.")] - public bool ModifyAbility { get; set; } = true; + /// Percentage chance that only one ability will be inherited, and a new random one will replace the other. + [Category(Evolutions), Description("Percentage chance that only one ability will be inherited, and a new random one will replace the other.")] + public float InheritAbilityOnlyOneChance { get; set; } = 45; - /// Permits Wonder Guard as a random ability. - [Category(Abilities), Description("Permits Wonder Guard as a random ability.")] - public Permissive WonderGuard { get; set; } = Permissive.No; + /// Percentage chance that neither one ability will be inherited, and new random ones will replace the others. + [Category(Evolutions), Description("Percentage chance that neither ability will be inherited, and new random ones will replace the others.")] + public float InheritAbilityNeitherChance { get; set; } = 20; - /// Option to modify the . - [Category(Abilities), Description("Option to modify the Abilities depending on the specified setting.")] - public ModifyState Ability { get; set; } = ModifyState.All; + /// Inherit the held item values from the pre-evolution. + [Category(Evolutions), Description("Inherit the held item values from the pre-evolution.")] + public bool InheritHeldItem { get; set; } = true; - /// Chance that both abilities are the same. - [Category(Abilities), Description("Chance that both abilities are the same.")] - public float SameAbilityChance { get; set; } = 100; - #endregion + /// Inherit the TM/HM compatibility from the pre-evolution. + [Category(Evolutions), Description("Inherit the TM/HM compatibility values from the pre-evolution.")] + public bool InheritChildTM { get; set; } = true; - #region Stats - /// Permits modification of . - [Category(Stats), Description("Enables a PKM's base stats to be modified.")] - public bool ModifyStats { get; set; } = true; + /// Inherit the Tutor compatibility from the pre-evolution. + [Category(Evolutions), Description("Inherit the Tutor compatibility values from the pre-evolution.")] + public bool InheritChildTutor { get; set; } = true; - /// Amount a Base Stat is amplified as a low bound. - [Category(Stats), Description("Minimum Percentage bound a Base Stat is after randomizing. 100 corresponds to an unchanged minimum.")] - public int StatDeviationMin { get; set; } = 75; - - /// Amount a Base Stat is amplified as a high bound. - [Category(Stats), Description("Maximum Percentage bound a Base Stat is after randomizing. 100 corresponds to an unchanged maximum.")] - public int StatDeviationMax { get; set; } = 125; - - /// Toggle to permit shuffling of . - [Category(Stats), Description("Shuffles the PKM's base stats after any modifications have been made.")] - public bool ShuffleStats { get; set; } = true; - - /// Permits randomizing the stat. - [Category(Stats), Description("Permits randomizing the HP base stat.")] - public bool HP { get; set; } = true; - - /// Permits randomizing the stat. - [Category(Stats), Description("Permits randomizing the Attack base stat.")] - public bool ATK { get; set; } = true; - - /// Permits randomizing the stat. - [Category(Stats), Description("Permits randomizing the Defense base stat.")] - public bool DEF { get; set; } = true; - - /// Permits randomizing the stat. - [Category(Stats), Description("Permits randomizing the Special Attack base stat.")] - public bool SPA { get; set; } = true; - - /// Permits randomizing the stat. - [Category(Stats), Description("Permits randomizing the Special Defense base stat.")] - public bool SPD { get; set; } = true; - - /// Permits randomizing the stat. - [Category(Stats), Description("Permits randomizing the Speed base stat.")] - public bool SPE { get; set; } = true; - - /// - /// Flags to edit the stats when randomizing. - /// - public IReadOnlyList StatsToRandomize => new[] {HP, ATK, DEF, SPE, SPA, SPD}; - #endregion - - #region Misc - /// Option permitting modification of . - [Category(Misc), Description("Enables a PKM's catch rate to be modified. Can inversely scale off BST.")] - public CatchRate CatchRate { get; set; } = CatchRate.Unchanged; - - /// Permits modification of Held Items. - [Category(Misc), Description("Enables a PKM's held items to be modified.")] - public bool ModifyHeldItems { get; set; } = true; - - /// Chance all held items are the same. - [Category(Misc), Description("Percentage chance that all Held Items are the same, resulting in a 100% chance of having the held item.")] - public float AlwaysHeldItemChance { get; set; } = 20; - - /// Permits modification of . - [Category(Misc), Description("Enables a PKM's egg groups to be modified.")] - public bool ModifyEgg { get; set; } = false; - - /// Chance both egg groups are the same. - [Category(Misc), Description("Percentage chance that both egg groups will be the same.")] - public float SameEggGroupChance { get; set; } = 50; - #endregion - - #region Evolutions - /// Toggles inheriting types from the pre-evolution that evolves into this species/form. - [Category(Evolutions), Description("Toggles inheriting types from the pre-evolution that evolves into this species/form.")] - public bool InheritType { get; set; } = true; - - /// Maximum amount of Types that can be different from the pre-evolution. - [Category(Evolutions), Description("Maximum amount of Types that can be different from the pre-evolution.")] - public ModifyState InheritTypeSetting { get; set; } = ModifyState.One; - - /// Percentage chance that only one type will be inherited, and a new random one will replace the other. - [Category(Evolutions), Description("Percentage chance that only one type will be inherited, and a new random one will replace the other.")] - public float InheritTypeOnlyOneChance { get; set; } = 65; - - /// Percentage chance that neither one type will be inherited, and new random ones will replace the others. - [Category(Evolutions), Description("Percentage chance that neither type will be inherited, and new random ones will replace the others.")] - public float InheritTypeNeitherChance { get; set; } = 30; - - /// Toggles chance that neither one type will be inherited, and new random ones will replace the others. - [Category(Evolutions), Description("Amount of abilities that will be inherited, and new random ones will replace the others.")] - public ModifyState InheritAbilitySetting { get; set; } = ModifyState.One; - - /// Toggles inheriting abilities from the pre-evolution that evolves into this species/form. - [Category(Evolutions), Description("Toggles inheriting abilities from the pre-evolution that evolves into this species/form.")] - public bool InheritAbility { get; set; } = true; - - /// Percentage chance that only one ability will be inherited, and a new random one will replace the other. - [Category(Evolutions), Description("Percentage chance that only one ability will be inherited, and a new random one will replace the other.")] - public float InheritAbilityOnlyOneChance { get; set; } = 45; - - /// Percentage chance that neither one ability will be inherited, and new random ones will replace the others. - [Category(Evolutions), Description("Percentage chance that neither ability will be inherited, and new random ones will replace the others.")] - public float InheritAbilityNeitherChance { get; set; } = 20; - - /// Inherit the held item values from the pre-evolution. - [Category(Evolutions), Description("Inherit the held item values from the pre-evolution.")] - public bool InheritHeldItem { get; set; } = true; - - /// Inherit the TM/HM compatibility from the pre-evolution. - [Category(Evolutions), Description("Inherit the TM/HM compatibility values from the pre-evolution.")] - public bool InheritChildTM { get; set; } = true; - - /// Inherit the Tutor compatibility from the pre-evolution. - [Category(Evolutions), Description("Inherit the Tutor compatibility values from the pre-evolution.")] - public bool InheritChildTutor { get; set; } = true; - - /// Inherit the Type Tutor values from the pre-evolution. - [Category(Evolutions), Description("Inherit the Type Tutor compatibility values from the pre-evolution.")] - public bool InheritChildSpecial { get; set; } = true; - #endregion - } -} \ No newline at end of file + /// Inherit the Type Tutor values from the pre-evolution. + [Category(Evolutions), Description("Inherit the Type Tutor compatibility values from the pre-evolution.")] + public bool InheritChildSpecial { get; set; } = true; + #endregion +} diff --git a/pkNX.Randomization/Randomizers/Personal/PersonalRandomizer.cs b/pkNX.Randomization/Randomizers/Personal/PersonalRandomizer.cs index 4a59d111..ec80bc43 100644 --- a/pkNX.Randomization/Randomizers/Personal/PersonalRandomizer.cs +++ b/pkNX.Randomization/Randomizers/Personal/PersonalRandomizer.cs @@ -1,456 +1,454 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public class PersonalRandomizer : Randomizer { - public class PersonalRandomizer : Randomizer + private const int tmcount = 100; + private const int eggGroupCount = 16; + private const int TypeCount = 18; + + private readonly GameInfo Game; + private readonly IPersonalTable Table; + private readonly EvolutionSet[] Evolutions; + + public PersonalRandSettings Settings { get; set; } = new(); + + public PersonalRandomizer(IPersonalTable table, GameInfo game, EvolutionSet[] evolutions) { - private const int tmcount = 100; - private const int eggGroupCount = 16; - private const int TypeCount = 18; - - private readonly GameInfo Game; - private readonly IPersonalTable Table; - private readonly EvolutionSet[] Evolutions; - - public PersonalRandSettings Settings { get; set; } = new(); - - public PersonalRandomizer(IPersonalTable table, GameInfo game, EvolutionSet[] evolutions) + Game = game; + Table = table; + Evolutions = evolutions; + if (File.Exists("bannedabilites.txt")) { - Game = game; - Table = table; - Evolutions = evolutions; - if (File.Exists("bannedabilites.txt")) - { - var data = File.ReadAllLines("bannedabilities.txt"); - var list = new List(BannedAbilities); - list.AddRange(data.Select(z => Convert.ToInt32(z))); - BannedAbilities = list; - } + var data = File.ReadAllLines("bannedabilities.txt"); + var list = new List(BannedAbilities); + list.AddRange(data.Select(z => Convert.ToInt32(z))); + BannedAbilities = list; } + } - public override void Execute() + public override void Execute() + { + if (Settings.ModifyByEvolutions) + RandomizeChains(); + else + RandomizeAllSpecies(); + } + + private void RandomizeAllSpecies() + { + for (ushort species = 0; species <= Game.MaxSpeciesID; species++) + RandomizeSpecies(species); + } + + private bool[] processed = Array.Empty(); + + private void RandomizeChains() + { + processed = new bool[Table.Table.Length]; + for (ushort species = 0; species <= Game.MaxSpeciesID; species++) { - if (Settings.ModifyByEvolutions) - RandomizeChains(); - else - RandomizeAllSpecies(); + for (byte f = 0; f <= Table[species].FormCount; f++) + RandomizeChain(species, f); } + } - private void RandomizeAllSpecies() - { - for (ushort species = 0; species <= Game.MaxSpeciesID; species++) - RandomizeSpecies(species); - } - - private bool[] processed = Array.Empty(); - - private void RandomizeChains() - { - processed = new bool[Table.Table.Length]; - for (ushort species = 0; species <= Game.MaxSpeciesID; species++) - { - for (byte f = 0; f <= Table[species].FormCount; f++) - RandomizeChain(species, f); - } - } - - private bool AlreadyProcessed(int index) - { - var p = processed; - if (p.Length <= index) - return false; - if (p[index]) - return true; - p[index] = true; + private bool AlreadyProcessed(int index) + { + var p = processed; + if (p.Length <= index) return false; - } + if (p[index]) + return true; + p[index] = true; + return false; + } - private void RandomizeChain(ushort species, byte form) + private void RandomizeChain(ushort species, byte form) + { + var index = Table.GetFormIndex(species, form); + if (AlreadyProcessed(index)) + return; + processed[index] = true; + + var entry = Table[index]; + Randomize(entry, species); + ProcessEvolutions(species, form, index); + } + + private void ProcessEvolutions(int species, int form, int devolvedIndex) + { + var evoindex = GetEvolutionEntry((ushort)species, (byte)form); + var evos = Evolutions[evoindex]; + + if (evos.PossibleEvolutions.Length == 1) { - var index = Table.GetFormIndex(species, form); - if (AlreadyProcessed(index)) + var evo = evos.PossibleEvolutions[0]; + var ei = Table.GetFormIndex(evo.Species, evo.Form); + + if (AlreadyProcessed(ei)) return; - processed[index] = true; - - var entry = Table[index]; - Randomize(entry, species); - ProcessEvolutions(species, form, index); + RandomizeSingleChain(evo, devolvedIndex); + ProcessEvolutions(evo.Species, evo.Form, ei); } - - private void ProcessEvolutions(int species, int form, int devolvedIndex) + else { - var evoindex = GetEvolutionEntry((ushort)species, (byte)form); - var evos = Evolutions[evoindex]; - - if (evos.PossibleEvolutions.Length == 1) + foreach (var evo in evos.PossibleEvolutions) { - var evo = evos.PossibleEvolutions[0]; - var ei = Table.GetFormIndex((ushort)evo.Species, (byte)evo.Form); - + var ei = Table.GetFormIndex(evo.Species, evo.Form); if (AlreadyProcessed(ei)) return; - RandomizeSingleChain(evo, devolvedIndex); + RandomizeSplitChain(evo, devolvedIndex); ProcessEvolutions(evo.Species, evo.Form, ei); } - else - { - foreach (var evo in evos.PossibleEvolutions) - { - var ei = Table.GetFormIndex((ushort)evo.Species, (byte)evo.Form); - if (AlreadyProcessed(ei)) - return; - RandomizeSplitChain(evo, devolvedIndex); - ProcessEvolutions(evo.Species, evo.Form, ei); - } - } - } - - private void RandomizeSingleChain(EvolutionMethod evo, int devolvedIndex) - { - var child = Table[devolvedIndex]; - var z = Table.GetFormEntry((ushort)evo.Species, (byte)evo.Form); - RandomizeFrom(z, child, evo.Species); - } - - private void RandomizeSplitChain(EvolutionMethod evo, int devolvedIndex) - { - var child = Table[devolvedIndex]; - var z = Table.GetFormEntry((ushort)evo.Species, (byte)evo.Form); - RandomizeFrom(z, child, evo.Species); - } - - private int GetEvolutionEntry(ushort species, byte form) - { - if (Game.Generation < 7) - return species; - return Table.GetFormIndex(species, form); - } - - private void RandomizeSpecies(ushort species) - { - var entry = Table[species]; - Randomize(entry, species); - var formCount = entry.FormCount; - for (byte form = 1; form <= formCount; form++) - { - entry = Table.GetFormEntry(species, form); - Randomize(entry, species); - } - } - - public void RandomizeFrom(IPersonalInfo z, IPersonalInfo child, int species) - { - if (Settings.ModifyStats) - RandomizeStats(z); - if (Settings.ShuffleStats) - RandomShuffledStats(z); - - if (Settings.ModifyTypes) - { - if (Settings.InheritType && Settings.InheritTypeSetting != ModifyState.All) - { - switch (Settings.InheritTypeSetting) - { - case ModifyState.Shared: - default: - z.Type1 = child.Type1; - z.Type2 = child.Type2; - break; - case ModifyState.Two when Rand.Next(100) < Settings.InheritTypeOnlyOneChance: - case ModifyState.One when Rand.Next(100) < Settings.InheritTypeOnlyOneChance: - switch (Rand.Next(2)) - { - case 0: - z.Type1 = (Types)GetRandomType(); - z.Type2 = child.Type2; - break; - case 1: - z.Type1 = child.Type1; - z.Type2 = (Types)GetRandomType(); - break; - } - break; - case ModifyState.Two when Rand.Next(100) < Settings.InheritTypeNeitherChance: - RandomizeTypes(z); - break; - - } - } - else - { - RandomizeTypes(z); - } - } - - if (Settings.ModifyAbility) - { - if (Settings.InheritAbility) - { - Span abils = stackalloc int[3]; - child.GetAbilities(abils); - GetRandomAbilities(abils, Settings.InheritAbilitySetting); - z.SetAbilities(abils); - } - else - { - RandomizeAbilities(z); - } - } - - if (z is IMovesInfo_1 mi) - { - if (Settings.ModifyLearnsetTM || Settings.ModifyLearnsetHM) - { - if (Settings.InheritChildTM) - mi.TMHM = ((IMovesInfo_1)child).TMHM; - else - RandomizeTMHM(mi); - } - - if (Settings.ModifyLearnsetTypeTutors) - { - if (Settings.InheritChildSpecial) - mi.TypeTutors = ((IMovesInfo_1)child).TypeTutors; - else - RandomizeTypeTutors(mi, species); - } - } - - if (Settings.ModifyLearnsetMoveTutors && z is IMovesInfo_2 mi2) - { - if (Settings.InheritChildTutor) - mi2.SpecialTutors = ((IMovesInfo_2)child).SpecialTutors; - else - RandomizeSpecialTutors(mi2); - } - - if (Settings.ModifyEgg) - { - z.EggGroup1 = child.EggGroup1; - z.EggGroup2 = child.EggGroup2; - } - - if (Settings.ModifyHeldItems) - { - if (Settings.InheritHeldItem) - { - z.Item1 = child.Item1; - z.Item2 = child.Item2; - z.Item3 = child.Item3; - } - else - { - RandomizeHeldItems(z); - } - } - - ExecuteCatchRate(z); - } - - private void GetRandomAbilities(Span abils, ModifyState setting) - { - switch (setting) - { - case ModifyState.Shared: - return; - case ModifyState.Two when Rand.Next(100) < Settings.InheritAbilityNeitherChance: - GetRandomAbilities(abils, 1); - break; - case ModifyState.Two when Rand.Next(100) < Settings.InheritAbilityOnlyOneChance: - case ModifyState.One when Rand.Next(100) < Settings.InheritAbilityOnlyOneChance: - GetRandomAbilities(abils, 2); - break; - case ModifyState.All: - GetRandomAbilities(abils); - if (Rand.Next(100) < Settings.SameAbilityChance) - { - int index = Rand.Next(2); - abils[index ^ 1] = abils[index]; - } - break; - } - } - - public void Randomize(IPersonalInfo z, int species) - { - if (Settings.ModifyStats) - RandomizeStats(z); - if (Settings.ShuffleStats) - RandomShuffledStats(z); - - if (Settings.ModifyTypes) - RandomizeTypes(z); - - if (Settings.ModifyAbility) - RandomizeAbilities(z); - - if (z is IMovesInfo_1 mi) - { - if (Settings.ModifyLearnsetTM || Settings.ModifyLearnsetHM) - RandomizeTMHM(mi); - - if (Settings.ModifyLearnsetTypeTutors) - RandomizeTypeTutors(mi, species); - } - - if (Settings.ModifyLearnsetMoveTutors && z is IMovesInfo_2 mi2) - RandomizeSpecialTutors(mi2); - - if (Settings.ModifyEgg) - RandomizeEggGroups(z); - - if (Settings.ModifyHeldItems) - RandomizeHeldItems(z); - - ExecuteCatchRate(z); - } - - private void ExecuteCatchRate(IPersonalInfo z) - { - if (Settings.CatchRate == CatchRate.Random) - z.CatchRate = Rand.Next(3, 251); // Random Catch Rate between 3 and 250. - else if (Settings.CatchRate == CatchRate.BSTScaled) - z.CatchRate = GetBSTCatchRate(z.GetBaseStatTotal()); - } - - private static int GetBSTCatchRate(int BST) - { - var c = 11 * (Math.Sqrt(Math.Max(0, 600 - BST))); - - const int min = 3; - return (int)Math.Min(255, min + c); - } - - private void RandomizeTMHM(IMovesInfo_1 z) - { - var tms = z.TMHM; - - if (Settings.ModifyLearnsetTM) - { - for (int j = 0; j < tmcount; j++) - tms[j] = Rand.Next(100) < Settings.LearnTMPercent; - } - - if (Settings.ModifyLearnsetHM) - { - for (int j = tmcount; j < tms.Length; j++) - tms[j] = Rand.Next(100) < Settings.LearnTMPercent; - } - - z.TMHM = tms; - } - - private void RandomizeTypeTutors(IMovesInfo_1 z, int species) - { - var t = z.TypeTutors; - for (int i = 0; i < t.Length; i++) - t[i] = Rand.Next(100) < Settings.LearnTypeTutorPercent; - - // Make sure Rayquaza can learn Dragon Ascent. - if (!Game.XY && species == (int)Species.Rayquaza) - t[7] = true; - - z.TypeTutors = t; - } - - private void RandomizeSpecialTutors(IMovesInfo_2 z) - { - var tutors = z.SpecialTutors; - foreach (bool[] tutor in tutors) - { - for (int i = 0; i < tutor.Length; i++) - tutor[i] = Rand.Next(100) < Settings.LearnMoveTutorPercent; - } - - z.SpecialTutors = tutors; - } - - private void RandomizeAbilities(IPersonalAbility z) - { - Span abils = stackalloc int[3]; - z.GetAbilities(abils); - GetRandomAbilities(abils, Settings.Ability); - z.SetAbilities(abils); - } - - private void GetRandomAbilities(Span abils, int skip = 0) - { - for (int i = 0; i < abils.Length - skip; i++) - abils[i] = GetRandomAbility(); - } - - private void RandomizeEggGroups(IPersonalEgg z) - { - z.EggGroup1 = GetRandomEggGroup(); - z.EggGroup2 = Rand.Next(100) < Settings.SameEggGroupChance ? z.EggGroup1 : GetRandomEggGroup(); - } - - private void RandomizeHeldItems(IPersonalItems z) - { - for (int j = 0; j < z.GetNumItems(); j++) - z.SetItemAtIndex(j, GetRandomHeldItem()); - } - - private void RandomizeTypes(IPersonalType z) - { - z.Type1 = (Types)GetRandomType(); - z.Type2 = Rand.Next(0, 100) < Settings.SameTypeChance ? z.Type1 : (Types)GetRandomType(); - } - - private void RandomizeStats(IBaseStat z) - { - // Fiddle with Base Stats, don't muck with Shedinja. - if (z.GetBaseStatValue(0) == 1) - return; - - int RandDeviation() => Rand.Next(Settings.StatDeviationMin, Settings.StatDeviationMax); - for (int i = 0; i < z.GetNumBaseStats(); i++) - { - if (!Settings.StatsToRandomize[i]) - continue; - - var val = z.GetBaseStatValue(i) * RandDeviation() / 100; - z.SetBaseStatValue(i, Math.Max(1, Math.Min(255, val))); - } - } - - private static void RandomShuffledStats(IBaseStat z) - { - // Fiddle with Base Stats, don't muck with Shedinja. - if (z.GetBaseStatValue(0) == 1) - return; - - var stats = new int[z.GetNumBaseStats()]; - for (int i = 0; i < z.GetNumBaseStats(); i++) - stats[i] = z.GetBaseStatValue(i); - - Util.Shuffle(stats); - - for (int i = 0; i < z.GetNumBaseStats(); i++) - z.SetBaseStatValue(i, stats[i]); - } - - private int GetRandomType() => Rand.Next(0, TypeCount); - private int GetRandomEggGroup() => Rand.Next(1, eggGroupCount); - private int GetRandomHeldItem() => Game.HeldItems.Length > 1 ? Game.HeldItems[Rand.Next(1, Game.HeldItems.Length)] : 0; - private readonly IList BannedAbilities = Array.Empty(); - - private int GetRandomAbility() - { - const int WonderGuard = 25; - while (true) - { - int newabil = Rand.Next(1, Game.MaxAbilityID + 1); - if (newabil == WonderGuard && Settings.WonderGuard == Permissive.No) - continue; - if (BannedAbilities.Contains(newabil)) - continue; - return newabil; - } + } + } + + private void RandomizeSingleChain(EvolutionMethod evo, int devolvedIndex) + { + var child = Table[devolvedIndex]; + var z = Table.GetFormEntry(evo.Species, evo.Form); + RandomizeFrom(z, child, evo.Species); + } + + private void RandomizeSplitChain(EvolutionMethod evo, int devolvedIndex) + { + var child = Table[devolvedIndex]; + var z = Table.GetFormEntry(evo.Species, evo.Form); + RandomizeFrom(z, child, evo.Species); + } + + private int GetEvolutionEntry(ushort species, byte form) + { + if (Game.Generation < 7) + return species; + return Table.GetFormIndex(species, form); + } + + private void RandomizeSpecies(ushort species) + { + var entry = Table[species]; + Randomize(entry, species); + var formCount = entry.FormCount; + for (byte form = 1; form <= formCount; form++) + { + entry = Table.GetFormEntry(species, form); + Randomize(entry, species); + } + } + + public void RandomizeFrom(IPersonalInfo z, IPersonalInfo child, int species) + { + if (Settings.ModifyStats) + RandomizeStats(z); + if (Settings.ShuffleStats) + RandomShuffledStats(z); + + if (Settings.ModifyTypes) + { + if (Settings.InheritType && Settings.InheritTypeSetting != ModifyState.All) + { + switch (Settings.InheritTypeSetting) + { + case ModifyState.Shared: + default: + z.Type1 = child.Type1; + z.Type2 = child.Type2; + break; + case ModifyState.Two when Rand.Next(100) < Settings.InheritTypeOnlyOneChance: + case ModifyState.One when Rand.Next(100) < Settings.InheritTypeOnlyOneChance: + switch (Rand.Next(2)) + { + case 0: + z.Type1 = (Types)GetRandomType(); + z.Type2 = child.Type2; + break; + case 1: + z.Type1 = child.Type1; + z.Type2 = (Types)GetRandomType(); + break; + } + break; + case ModifyState.Two when Rand.Next(100) < Settings.InheritTypeNeitherChance: + RandomizeTypes(z); + break; + } + } + else + { + RandomizeTypes(z); + } + } + + if (Settings.ModifyAbility) + { + if (Settings.InheritAbility) + { + Span abils = stackalloc int[3]; + child.GetAbilities(abils); + GetRandomAbilities(abils, Settings.InheritAbilitySetting); + z.SetAbilities(abils); + } + else + { + RandomizeAbilities(z); + } + } + + if (z is IMovesInfo_1 mi) + { + if (Settings.ModifyLearnsetTM || Settings.ModifyLearnsetHM) + { + if (Settings.InheritChildTM) + mi.TMHM = ((IMovesInfo_1)child).TMHM; + else + RandomizeTMHM(mi); + } + + if (Settings.ModifyLearnsetTypeTutors) + { + if (Settings.InheritChildSpecial) + mi.TypeTutors = ((IMovesInfo_1)child).TypeTutors; + else + RandomizeTypeTutors(mi, species); + } + } + + if (Settings.ModifyLearnsetMoveTutors && z is IMovesInfo_2 mi2) + { + if (Settings.InheritChildTutor) + mi2.SpecialTutors = ((IMovesInfo_2)child).SpecialTutors; + else + RandomizeSpecialTutors(mi2); + } + + if (Settings.ModifyEgg) + { + z.EggGroup1 = child.EggGroup1; + z.EggGroup2 = child.EggGroup2; + } + + if (Settings.ModifyHeldItems) + { + if (Settings.InheritHeldItem) + { + z.Item1 = child.Item1; + z.Item2 = child.Item2; + z.Item3 = child.Item3; + } + else + { + RandomizeHeldItems(z); + } + } + + ExecuteCatchRate(z); + } + + private void GetRandomAbilities(Span abils, ModifyState setting) + { + switch (setting) + { + case ModifyState.Shared: + return; + case ModifyState.Two when Rand.Next(100) < Settings.InheritAbilityNeitherChance: + GetRandomAbilities(abils, 1); + break; + case ModifyState.Two when Rand.Next(100) < Settings.InheritAbilityOnlyOneChance: + case ModifyState.One when Rand.Next(100) < Settings.InheritAbilityOnlyOneChance: + GetRandomAbilities(abils, 2); + break; + case ModifyState.All: + GetRandomAbilities(abils); + if (Rand.Next(100) < Settings.SameAbilityChance) + { + int index = Rand.Next(2); + abils[index ^ 1] = abils[index]; + } + break; + } + } + + public void Randomize(IPersonalInfo z, int species) + { + if (Settings.ModifyStats) + RandomizeStats(z); + if (Settings.ShuffleStats) + RandomShuffledStats(z); + + if (Settings.ModifyTypes) + RandomizeTypes(z); + + if (Settings.ModifyAbility) + RandomizeAbilities(z); + + if (z is IMovesInfo_1 mi) + { + if (Settings.ModifyLearnsetTM || Settings.ModifyLearnsetHM) + RandomizeTMHM(mi); + + if (Settings.ModifyLearnsetTypeTutors) + RandomizeTypeTutors(mi, species); + } + + if (Settings.ModifyLearnsetMoveTutors && z is IMovesInfo_2 mi2) + RandomizeSpecialTutors(mi2); + + if (Settings.ModifyEgg) + RandomizeEggGroups(z); + + if (Settings.ModifyHeldItems) + RandomizeHeldItems(z); + + ExecuteCatchRate(z); + } + + private void ExecuteCatchRate(IPersonalInfo z) + { + if (Settings.CatchRate == CatchRate.Random) + z.CatchRate = Rand.Next(3, 251); // Random Catch Rate between 3 and 250. + else if (Settings.CatchRate == CatchRate.BSTScaled) + z.CatchRate = GetBSTCatchRate(z.GetBaseStatTotal()); + } + + private static int GetBSTCatchRate(int BST) + { + var c = 11 * (Math.Sqrt(Math.Max(0, 600 - BST))); + + const int min = 3; + return (int)Math.Min(255, min + c); + } + + private void RandomizeTMHM(IMovesInfo_1 z) + { + var tms = z.TMHM; + + if (Settings.ModifyLearnsetTM) + { + for (int j = 0; j < tmcount; j++) + tms[j] = Rand.Next(100) < Settings.LearnTMPercent; + } + + if (Settings.ModifyLearnsetHM) + { + for (int j = tmcount; j < tms.Length; j++) + tms[j] = Rand.Next(100) < Settings.LearnTMPercent; + } + + z.TMHM = tms; + } + + private void RandomizeTypeTutors(IMovesInfo_1 z, int species) + { + var t = z.TypeTutors; + for (int i = 0; i < t.Length; i++) + t[i] = Rand.Next(100) < Settings.LearnTypeTutorPercent; + + // Make sure Rayquaza can learn Dragon Ascent. + if (!Game.XY && species == (int)Species.Rayquaza) + t[7] = true; + + z.TypeTutors = t; + } + + private void RandomizeSpecialTutors(IMovesInfo_2 z) + { + var tutors = z.SpecialTutors; + foreach (bool[] tutor in tutors) + { + for (int i = 0; i < tutor.Length; i++) + tutor[i] = Rand.Next(100) < Settings.LearnMoveTutorPercent; + } + + z.SpecialTutors = tutors; + } + + private void RandomizeAbilities(IPersonalAbility z) + { + Span abils = stackalloc int[3]; + z.GetAbilities(abils); + GetRandomAbilities(abils, Settings.Ability); + z.SetAbilities(abils); + } + + private void GetRandomAbilities(Span abils, int skip = 0) + { + for (int i = 0; i < abils.Length - skip; i++) + abils[i] = GetRandomAbility(); + } + + private void RandomizeEggGroups(IPersonalEgg z) + { + z.EggGroup1 = GetRandomEggGroup(); + z.EggGroup2 = Rand.Next(100) < Settings.SameEggGroupChance ? z.EggGroup1 : GetRandomEggGroup(); + } + + private void RandomizeHeldItems(IPersonalItems z) + { + for (int j = 0; j < z.GetNumItems(); j++) + z.SetItemAtIndex(j, GetRandomHeldItem()); + } + + private void RandomizeTypes(IPersonalType z) + { + z.Type1 = (Types)GetRandomType(); + z.Type2 = Rand.Next(0, 100) < Settings.SameTypeChance ? z.Type1 : (Types)GetRandomType(); + } + + private void RandomizeStats(IBaseStat z) + { + // Fiddle with Base Stats, don't muck with Shedinja. + if (z.GetBaseStatValue(0) == 1) + return; + + int RandDeviation() => Rand.Next(Settings.StatDeviationMin, Settings.StatDeviationMax); + for (int i = 0; i < z.GetNumBaseStats(); i++) + { + if (!Settings.StatsToRandomize[i]) + continue; + + var val = z.GetBaseStatValue(i) * RandDeviation() / 100; + z.SetBaseStatValue(i, Math.Max(1, Math.Min(255, val))); + } + } + + private static void RandomShuffledStats(IBaseStat z) + { + // Fiddle with Base Stats, don't muck with Shedinja. + if (z.GetBaseStatValue(0) == 1) + return; + + var stats = new int[z.GetNumBaseStats()]; + for (int i = 0; i < z.GetNumBaseStats(); i++) + stats[i] = z.GetBaseStatValue(i); + + Util.Shuffle(stats); + + for (int i = 0; i < z.GetNumBaseStats(); i++) + z.SetBaseStatValue(i, stats[i]); + } + + private int GetRandomType() => Rand.Next(0, TypeCount); + private int GetRandomEggGroup() => Rand.Next(1, eggGroupCount); + private int GetRandomHeldItem() => Game.HeldItems.Length > 1 ? Game.HeldItems[Rand.Next(1, Game.HeldItems.Length)] : 0; + private readonly IList BannedAbilities = Array.Empty(); + + private int GetRandomAbility() + { + const int WonderGuard = 25; + while (true) + { + int newabil = Rand.Next(1, Game.MaxAbilityID + 1); + if (newabil == WonderGuard && Settings.WonderGuard == Permissive.No) + continue; + if (BannedAbilities.Contains(newabil)) + continue; + return newabil; } } } diff --git a/pkNX.Randomization/Randomizers/Randomizer.cs b/pkNX.Randomization/Randomizers/Randomizer.cs index 52fbbce9..f1c459e4 100644 --- a/pkNX.Randomization/Randomizers/Randomizer.cs +++ b/pkNX.Randomization/Randomizers/Randomizer.cs @@ -1,11 +1,10 @@ -using System; +using System; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public abstract class Randomizer { - public abstract class Randomizer - { - public abstract void Execute(); + public abstract void Execute(); - protected readonly Random Rand = Util.Random; - } + protected readonly Random Rand = Util.Random; } diff --git a/pkNX.Randomization/Randomizers/Settings/LearnSettings.cs b/pkNX.Randomization/Randomizers/Settings/LearnSettings.cs index d49eaa16..d2258d19 100644 --- a/pkNX.Randomization/Randomizers/Settings/LearnSettings.cs +++ b/pkNX.Randomization/Randomizers/Settings/LearnSettings.cs @@ -1,34 +1,33 @@ using System; using System.ComponentModel; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +[Serializable] +[TypeConverter(typeof(ExpandableObjectConverter))] +public class LearnSettings { - [Serializable] - [TypeConverter(typeof(ExpandableObjectConverter))] - public class LearnSettings - { - private const string General = nameof(General); - private const string Misc = nameof(Misc); + private const string General = nameof(General); + private const string Misc = nameof(Misc); - [Category(General), Description("Expands the learnset to the specified count.")] - public bool Expand { get; set; } = true; + [Category(General), Description("Expands the learnset to the specified count.")] + public bool Expand { get; set; } = true; - [Category(General), Description("Count to expand the learnset to.")] - public int ExpandTo { get; set; } = 25; + [Category(General), Description("Count to expand the learnset to.")] + public int ExpandTo { get; set; } = 25; - [Category(General), Description("Evenly spreads learned moves out from level 1 to the specified end level.")] - public bool Spread { get; set; } = true; + [Category(General), Description("Evenly spreads learned moves out from level 1 to the specified end level.")] + public bool Spread { get; set; } = true; - [Category(General), Description("Level to end learning level up moves.")] - public int SpreadTo { get; set; } = 75; + [Category(General), Description("Level to end learning level up moves.")] + public int SpreadTo { get; set; } = 75; - [Category(Misc), Description("Reorders moves so that moves are learned with increasing power.")] - public bool OrderByPower { get; set; } = true; + [Category(Misc), Description("Reorders moves so that moves are learned with increasing power.")] + public bool OrderByPower { get; set; } = true; - [Category(Misc), Description("Requires the first move learned to be STAB.")] - public bool STABFirst { get; set; } = true; + [Category(Misc), Description("Requires the first move learned to be STAB.")] + public bool STABFirst { get; set; } = true; - [Category(Misc), Description("Requires 4 moves to be available at level 1.")] - public bool Learn4Level1 { get; set; } = false; - } -} \ No newline at end of file + [Category(Misc), Description("Requires 4 moves to be available at level 1.")] + public bool Learn4Level1 { get; set; } +} diff --git a/pkNX.Randomization/Randomizers/Settings/MovesetRandSettings.cs b/pkNX.Randomization/Randomizers/Settings/MovesetRandSettings.cs index cbb1e227..90393718 100644 --- a/pkNX.Randomization/Randomizers/Settings/MovesetRandSettings.cs +++ b/pkNX.Randomization/Randomizers/Settings/MovesetRandSettings.cs @@ -2,35 +2,34 @@ using System.Collections.Generic; using System.ComponentModel; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +[Serializable] +[TypeConverter(typeof(ExpandableObjectConverter))] +public class MovesetRandSettings { - [Serializable] - [TypeConverter(typeof(ExpandableObjectConverter))] - public class MovesetRandSettings - { - private const string Damage = nameof(Damage); - private const string SameType = nameof(SameType); - private const string Misc = nameof(Misc); + private const string Damage = nameof(Damage); + private const string SameType = nameof(SameType); + private const string Misc = nameof(Misc); - [Category(Damage), Description("Forces the moveset to have a minimum amount of damaging moves.")] - public bool DMG { get; set; } = true; + [Category(Damage), Description("Forces the moveset to have a minimum amount of damaging moves.")] + public bool DMG { get; set; } = true; - [Category(Damage), Description("Minimum amount of damaging moves in generated movesets.")] - public int DMGCount { get; set; } = 2; + [Category(Damage), Description("Minimum amount of damaging moves in generated movesets.")] + public int DMGCount { get; set; } = 2; - [Category(SameType), Description("Forces the moveset to have a minimum amount of STAB moves.")] - public bool STAB { get; set; } = true; + [Category(SameType), Description("Forces the moveset to have a minimum amount of STAB moves.")] + public bool STAB { get; set; } = true; - [Category(SameType), Description("Minimum amount of STAB moves in generated 4-move movesets.")] - public int STABCount { get; set; } = 2; + [Category(SameType), Description("Minimum amount of STAB moves in generated 4-move movesets.")] + public int STABCount { get; set; } = 2; - [Category(SameType), Description("Minimum percent of STAB moves in generated learnsets.")] - public float STABPercent { get; set; } = 25; + [Category(SameType), Description("Minimum percent of STAB moves in generated learnsets.")] + public float STABPercent { get; set; } = 25; - [Category(Misc), Description("Banned move IDs.")] - internal IList BannedMoves { get; set; } = Array.Empty(); + [Category(Misc), Description("Banned move IDs.")] + internal IList BannedMoves { get; set; } = Array.Empty(); - [Category(Misc), Description("Prevents Pokmon movesets from containing fixed damage moves.")] - public bool BanFixedDamageMoves { get; set; } = true; - } -} \ No newline at end of file + [Category(Misc), Description("Prevents Pokémon movesets from containing fixed damage moves.")] + public bool BanFixedDamageMoves { get; set; } = true; +} diff --git a/pkNX.Randomization/Randomizers/Settings/RandSettings.cs b/pkNX.Randomization/Randomizers/Settings/RandSettings.cs index d9e6a891..3821f8b3 100644 --- a/pkNX.Randomization/Randomizers/Settings/RandSettings.cs +++ b/pkNX.Randomization/Randomizers/Settings/RandSettings.cs @@ -1,6 +1,5 @@ -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public class RandSettings { - public class RandSettings - { - } -} \ No newline at end of file +} diff --git a/pkNX.Randomization/Randomizers/Settings/SpeciesSettings.cs b/pkNX.Randomization/Randomizers/Settings/SpeciesSettings.cs index 3e3493c9..072fba23 100644 --- a/pkNX.Randomization/Randomizers/Settings/SpeciesSettings.cs +++ b/pkNX.Randomization/Randomizers/Settings/SpeciesSettings.cs @@ -1,229 +1,228 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +/// +/// Settings for what Species are permitted during randomization. +/// +[Serializable] +[TypeConverter(typeof(ExpandableObjectConverter))] +public class SpeciesSettings : RandSettings { + private const string General = nameof(General); + private const string Misc = nameof(Misc); + + /// Allows Generation 1 species when randomizing. + [Category(General), Description("Allows Generation 1 species when randomizing.")] + public bool Gen1 { get; set; } = true; + + /// Allows Generation 2 species when randomizing. + [Category(General), Description("Allows Generation 2 species when randomizing.")] + public bool Gen2 { get; set; } = true; + + /// Allows Generation 3 species when randomizing. + [Category(General), Description("Allows Generation 3 species when randomizing.")] + public bool Gen3 { get; set; } = true; + + /// Allows Generation 4 species when randomizing. + [Category(General), Description("Allows Generation 4 species when randomizing.")] + public bool Gen4 { get; set; } = true; + + /// Allows Generation 5 species when randomizing. + [Category(General), Description("Allows Generation 5 species when randomizing.")] + public bool Gen5 { get; set; } = true; + + /// Allows Generation 6 species when randomizing. + [Category(General), Description("Allows Generation 6 species when randomizing.")] + public bool Gen6 { get; set; } = true; + + /// Allows Generation 7 species when randomizing. + [Category(General), Description("Allows Generation 7 species when randomizing.")] + public bool Gen7 { get; set; } = true; + + /// Allows Generation 8 species when randomizing. + [Category(General), Description("Allows Generation 8 species when randomizing.")] + public bool Gen8 { get; set; } = true; + + /// Allows Legendary species when randomizing. + [Category(Misc), Description("Allows Legendary species when randomizing.")] + public bool Legends { get; set; } + + /// Allows Event-only (Mythical) species when randomizing. + [Category(Misc), Description("Allows Event-only (Mythical) species when randomizing.")] + public bool Events { get; set; } + + /// Allows Shedinja as a random species when randomizing. + [Category(Misc), Description("Allows Shedinja as a random species when randomizing.")] + public bool Shedinja { get; set; } + + /// Requires the randomized species to be in the same EXP Group as the original species. + [Category(Misc), Description("Requires the randomized species to be in the same EXP Group as the original species. Note: might not be used by all randomizers.")] + public bool EXPGroup { get; set; } + + /// Requires the randomized species to have a similar Base Stat Total as the original species. + [Category(Misc), Description("Requires the randomized species to have a similar Base Stat Total as the original species. Note: might not be used by all randomizers.")] + public bool BST { get; set; } = true; + + /// Requires the randomized species to have a similar typing as the original species. + [Category(Misc), Description("Requires the randomized species to have a similar typing as the original species. Note: might not be used by all randomizers.")] + public bool Type { get; set; } + + /// Makes the appearance of Legendary Pokémon to appear on boosted rates (percent). Ignored if 0 or Legends setting on Species is False. + [Category(Misc), Description("Makes the appearance of Legendary Pokémon to appear on boosted rates (percent). Ignored if 0 or Legends setting on Species is False.")] + public float LegendsChance { get; set; } = 2.5f; + + /// Makes the appearance of Event (Mythical) Pokémon to appear on boosted rates (percent). Ignored if 0 or Legends setting on Species is False. + [Category(Misc), Description("Makes the appearance of Event (Mythical) Pokémon to appear on boosted rates (percent).")] + public float EventsChance { get; set; } = 2.5f; + /// - /// Settings for what Species are permitted during randomization. + /// Gets an array of Species according to the specified settings. /// - [Serializable] - [TypeConverter(typeof(ExpandableObjectConverter))] - public class SpeciesSettings : RandSettings + /// Max Species ID + /// + /// + public int[] GetSpecies(int maxSpecies, int generation) { - private const string General = nameof(General); - private const string Misc = nameof(Misc); + var list = new List(); + if (Gen1) AddGen1Species(list, maxSpecies); + if (Gen2) AddGen2Species(list, maxSpecies); + if (Gen3) AddGen3Species(list, maxSpecies); + if (Gen4) AddGen4Species(list, maxSpecies); + if (Gen5) AddGen5Species(list, maxSpecies); + if (Gen6) AddGen6Species(list, maxSpecies); + if (Gen7) AddGen7Species(list, maxSpecies); + if (Gen8) AddGen8Species(list, maxSpecies); - /// Allows Generation 1 species when randomizing. - [Category(General), Description("Allows Generation 1 species when randomizing.")] - public bool Gen1 { get; set; } = true; + if (generation == 7 && Gen1 && Events && maxSpecies <= Legal.MaxSpeciesID_7_GG) + AddGGEvents(list); - /// Allows Generation 2 species when randomizing. - [Category(General), Description("Allows Generation 2 species when randomizing.")] - public bool Gen2 { get; set; } = true; + return list.Count == 0 ? GetSpeciesAll(maxSpecies) : list.ToArray(); + } - /// Allows Generation 3 species when randomizing. - [Category(General), Description("Allows Generation 3 species when randomizing.")] - public bool Gen3 { get; set; } = true; + private static int[] GetSpeciesAll(int maxSpecies) => Enumerable.Range(1, maxSpecies).ToArray(); - /// Allows Generation 4 species when randomizing. - [Category(General), Description("Allows Generation 4 species when randomizing.")] - public bool Gen4 { get; set; } = true; + private void AddGen1Species(List list, int maxSpecies) + { + if (maxSpecies <= 0) + return; + list.AddRange(Enumerable.Range(1, 143)); // Bulbasaur - Snorlax + list.AddRange(Enumerable.Range(147, 3)); // Dratini, Dragonair, Dragonite - /// Allows Generation 5 species when randomizing. - [Category(General), Description("Allows Generation 5 species when randomizing.")] - public bool Gen5 { get; set; } = true; - - /// Allows Generation 6 species when randomizing. - [Category(General), Description("Allows Generation 6 species when randomizing.")] - public bool Gen6 { get; set; } = true; - - /// Allows Generation 7 species when randomizing. - [Category(General), Description("Allows Generation 7 species when randomizing.")] - public bool Gen7 { get; set; } = true; - - /// Allows Generation 8 species when randomizing. - [Category(General), Description("Allows Generation 8 species when randomizing.")] - public bool Gen8 { get; set; } = true; - - /// Allows Legendary species when randomizing. - [Category(Misc), Description("Allows Legendary species when randomizing.")] - public bool Legends { get; set; } = false; - - /// Allows Event-only (Mythical) species when randomizing. - [Category(Misc), Description("Allows Event-only (Mythical) species when randomizing.")] - public bool Events { get; set; } = false; - - /// Allows Shedinja as a random species when randomizing. - [Category(Misc), Description("Allows Shedinja as a random species when randomizing.")] - public bool Shedinja { get; set; } = false; - - /// Requires the randomized species to be in the same EXP Group as the original species. - [Category(Misc), Description("Requires the randomized species to be in the same EXP Group as the original species. Note: might not be used by all randomizers.")] - public bool EXPGroup { get; set; } = false; - - /// Requires the randomized species to have a similar Base Stat Total as the original species. - [Category(Misc), Description("Requires the randomized species to have a similar Base Stat Total as the original species. Note: might not be used by all randomizers.")] - public bool BST { get; set; } = true; - - /// Requires the randomized species to have a similar typing as the original species. - [Category(Misc), Description("Requires the randomized species to have a similar typing as the original species. Note: might not be used by all randomizers.")] - public bool Type { get; set; } = false; - - /// Makes the appearance of Legendary Pokémon to appear on boosted rates (percent). Ignored if 0 or Legends setting on Species is False. - [Category(Misc), Description("Makes the appearance of Legendary Pokémon to appear on boosted rates (percent). Ignored if 0 or Legends setting on Species is False.")] - public float LegendsChance { get; set; } = 2.5f; - - /// Makes the appearance of Event (Mythical) Pokémon to appear on boosted rates (percent). Ignored if 0 or Legends setting on Species is False. - [Category(Misc), Description("Makes the appearance of Event (Mythical) Pokémon to appear on boosted rates (percent).")] - public float EventsChance { get; set; } = 2.5f; - - /// - /// Gets an array of Species according to the specified settings. - /// - /// Max Species ID - /// - /// - public int[] GetSpecies(int maxSpecies, int generation) + if (Legends) { - var list = new List(); - if (Gen1) AddGen1Species(list, maxSpecies); - if (Gen2) AddGen2Species(list, maxSpecies); - if (Gen3) AddGen3Species(list, maxSpecies); - if (Gen4) AddGen4Species(list, maxSpecies); - if (Gen5) AddGen5Species(list, maxSpecies); - if (Gen6) AddGen6Species(list, maxSpecies); - if (Gen7) AddGen7Species(list, maxSpecies); - if (Gen8) AddGen8Species(list, maxSpecies); + list.AddRange(Enumerable.Range(144, 3)); // Articuno, Zapdos, Moltres + list.Add(150); // Mewtwo + } + if (Events) list.Add(151); // Mew + } - if (generation == 7 && Gen1 && Events && maxSpecies <= Legal.MaxSpeciesID_7_GG) + private void AddGen2Species(List list, int maxSpecies) + { + if (maxSpecies <= 151) + return; + list.AddRange(Enumerable.Range(152, 91)); // Chikorita - Blissey + list.AddRange(Enumerable.Range(246, 3)); // Larvitar - Tyranitar + + if (Legends) + { + list.AddRange(Enumerable.Range(243, 3)); // Raikou, Entei, Suicune + list.AddRange(Enumerable.Range(249, 2)); // Lugia, Ho-Oh + } + if (Events) list.Add(251); // Celebi + } + + private void AddGen3Species(List list, int maxSpecies) + { + if (maxSpecies <= 251) + return; + list.AddRange(Enumerable.Range(252, 40)); // Treecko - Ninjask + list.AddRange(Enumerable.Range(293, 84)); // Whismur - Metagross + if (Shedinja) list.Add(292); // Shedinja + if (Legends) list.AddRange(Enumerable.Range(377, 8)); // Hoenn Legendaries + if (Events) list.AddRange(Enumerable.Range(385, 2)); // Jirachi, Deoxys + } + + private void AddGen4Species(List list, int maxSpecies) + { + if (maxSpecies <= 386) + return; + list.AddRange(Enumerable.Range(387, 93)); // Turtwig - Rotom + if (Legends) list.AddRange(Enumerable.Range(480, 9)); // Sinnoh Legendaries + if (Events) list.AddRange(Enumerable.Range(489, 5)); // Phione, Manaphy, Darkrai, Shaymin, Arceus + } + + private void AddGen5Species(List list, int maxSpecies) + { + if (maxSpecies <= 493) + return; + list.AddRange(Enumerable.Range(495, 143)); // Snivy - Volcarona + if (Legends) list.AddRange(Enumerable.Range(638, 9)); // Unova Legendaries + if (Events) list.Add(494); list.AddRange(Enumerable.Range(647, 3)); // Victini, Keldeo, Meloetta, Genesect + } + + private void AddGen6Species(List list, int maxSpecies) + { + if (maxSpecies <= 649) + return; + list.AddRange(Enumerable.Range(650, 66)); // Chespin - Noivern + if (Legends) list.AddRange(Enumerable.Range(716, 3)); // Kalos Legendaries + if (Events) list.AddRange(Enumerable.Range(719, 3)); // Diancie, Hoopa, Volcanion + } + + private void AddGen7Species(List list, int maxSpecies) + { + if (maxSpecies <= Legal.MaxSpeciesID_6) + return; + list.AddRange(Enumerable.Range(722, 50)); // Rowlet - Pyukumuku + list.AddRange(Enumerable.Range(774, 11)); // Minior - Kommo-o + + if (Legends) + { + list.AddRange(Enumerable.Range(772, 2)); // Type: Null, Silvally + list.AddRange(Enumerable.Range(785, 16)); // Alola Legendaries, Ultra Beasts + } + if (Events) list.AddRange(Enumerable.Range(801, 2)); // Magearna, Marshadow + + if (maxSpecies >= Legal.MaxSpeciesID_7_USUM) // USUM + { + if (Legends) list.AddRange(Enumerable.Range(803, 4)); // Poipole, Naganadel, Stakataka, Blacephalon + if (Events) list.Add(807); // Zeraora + } + if (maxSpecies >= Legal.MaxSpeciesID_7_GG) // LGPE + { + if (Events) AddGGEvents(list); - - return list.Count == 0 ? GetSpeciesAll(maxSpecies) : list.ToArray(); - } - - private static int[] GetSpeciesAll(int maxSpecies) => Enumerable.Range(1, maxSpecies).ToArray(); - - private void AddGen1Species(List list, int maxSpecies) - { - if (maxSpecies <= 0) - return; - list.AddRange(Enumerable.Range(1, 143)); // Bulbasaur - Snorlax - list.AddRange(Enumerable.Range(147, 3)); // Dratini, Dragonair, Dragonite - - if (Legends) - { - list.AddRange(Enumerable.Range(144, 3)); // Articuno, Zapdos, Moltres - list.Add(150); // Mewtwo - } - if (Events) list.Add(151); // Mew - } - - private void AddGen2Species(List list, int maxSpecies) - { - if (maxSpecies <= 151) - return; - list.AddRange(Enumerable.Range(152, 91)); // Chikorita - Blissey - list.AddRange(Enumerable.Range(246, 3)); // Larvitar - Tyranitar - - if (Legends) - { - list.AddRange(Enumerable.Range(243, 3)); // Raikou, Entei, Suicune - list.AddRange(Enumerable.Range(249, 2)); // Lugia, Ho-Oh - } - if (Events) list.Add(251); // Celebi - } - - private void AddGen3Species(List list, int maxSpecies) - { - if (maxSpecies <= 251) - return; - list.AddRange(Enumerable.Range(252, 40)); // Treecko - Ninjask - list.AddRange(Enumerable.Range(293, 84)); // Whismur - Metagross - if (Shedinja) list.Add(292); // Shedinja - if (Legends) list.AddRange(Enumerable.Range(377, 8)); // Hoenn Legendaries - if (Events) list.AddRange(Enumerable.Range(385, 2)); // Jirachi, Deoxys - } - - private void AddGen4Species(List list, int maxSpecies) - { - if (maxSpecies <= 386) - return; - list.AddRange(Enumerable.Range(387, 93)); // Turtwig - Rotom - if (Legends) list.AddRange(Enumerable.Range(480, 9)); // Sinnoh Legendaries - if (Events) list.AddRange(Enumerable.Range(489, 5)); // Phione, Manaphy, Darkrai, Shaymin, Arceus - } - - private void AddGen5Species(List list, int maxSpecies) - { - if (maxSpecies <= 493) - return; - list.AddRange(Enumerable.Range(495, 143)); // Snivy - Volcarona - if (Legends) list.AddRange(Enumerable.Range(638, 9)); // Unova Legendaries - if (Events) list.Add(494); list.AddRange(Enumerable.Range(647, 3)); // Victini, Keldeo, Meloetta, Genesect - } - - private void AddGen6Species(List list, int maxSpecies) - { - if (maxSpecies <= 649) - return; - list.AddRange(Enumerable.Range(650, 66)); // Chespin - Noivern - if (Legends) list.AddRange(Enumerable.Range(716, 3)); // Kalos Legendaries - if (Events) list.AddRange(Enumerable.Range(719, 3)); // Diancie, Hoopa, Volcanion - } - - private void AddGen7Species(List list, int maxSpecies) - { - if (maxSpecies <= Legal.MaxSpeciesID_6) - return; - list.AddRange(Enumerable.Range(722, 50)); // Rowlet - Pyukumuku - list.AddRange(Enumerable.Range(774, 11)); // Minior - Kommo-o - - if (Legends) - { - list.AddRange(Enumerable.Range(772, 2)); // Type: Null, Silvally - list.AddRange(Enumerable.Range(785, 16)); // Alola Legendaries, Ultra Beasts - } - if (Events) list.AddRange(Enumerable.Range(801, 2)); // Magearna, Marshadow - - if (maxSpecies >= Legal.MaxSpeciesID_7_USUM) // USUM - { - if (Legends) list.AddRange(Enumerable.Range(803, 4)); // Poipole, Naganadel, Stakataka, Blacephalon - if (Events) list.Add(807); // Zeraora - } - if (maxSpecies >= Legal.MaxSpeciesID_7_GG) // LGPE - { - if (Events) - AddGGEvents(list); - } - } - - private void AddGen8Species(List list, int maxSpecies) - { - if (maxSpecies <= Legal.MaxSpeciesID_7_GG) - return; - list.AddRange(Enumerable.Range(810, 78)); // Grookey - Dragapult - - if (Legends) - { - list.AddRange(Enumerable.Range(888, 3)); // Zacian, Zamazenta, Eternatus - list.AddRange(Enumerable.Range(891, 2)); // Kubfu, Urshifu - list.AddRange(Enumerable.Range(894, 5)); // Regieleki, Regidrago, Glastrier, Spectrier, Calyrex - } - if (Events) list.Add(893); // Zarude - - if (maxSpecies >= Legal.MaxSpeciesID_8a) - { - list.AddRange(Enumerable.Range(899, 6)); // Wyrdeer - Overqwil - if (Legends) list.Add(905); // Enamorus - } - } - - private static void AddGGEvents(List list) - { - list.AddRange(Enumerable.Range(808, Legal.MaxSpeciesID_7_GG - Legal.MaxSpeciesID_7_USUM)); // Meltan, Melmetal } } + + private void AddGen8Species(List list, int maxSpecies) + { + if (maxSpecies <= Legal.MaxSpeciesID_7_GG) + return; + list.AddRange(Enumerable.Range(810, 78)); // Grookey - Dragapult + + if (Legends) + { + list.AddRange(Enumerable.Range(888, 3)); // Zacian, Zamazenta, Eternatus + list.AddRange(Enumerable.Range(891, 2)); // Kubfu, Urshifu + list.AddRange(Enumerable.Range(894, 5)); // Regieleki, Regidrago, Glastrier, Spectrier, Calyrex + } + if (Events) list.Add(893); // Zarude + + if (maxSpecies >= Legal.MaxSpeciesID_8a) + { + list.AddRange(Enumerable.Range(899, 6)); // Wyrdeer - Overqwil + if (Legends) list.Add(905); // Enamorus + } + } + + private static void AddGGEvents(List list) + { + list.AddRange(Enumerable.Range(808, Legal.MaxSpeciesID_7_GG - Legal.MaxSpeciesID_7_USUM)); // Meltan, Melmetal + } } diff --git a/pkNX.Randomization/Randomizers/Settings/TrainerRandSettings.cs b/pkNX.Randomization/Randomizers/Settings/TrainerRandSettings.cs index 718fa123..00af18cd 100644 --- a/pkNX.Randomization/Randomizers/Settings/TrainerRandSettings.cs +++ b/pkNX.Randomization/Randomizers/Settings/TrainerRandSettings.cs @@ -1,98 +1,97 @@ using System; using System.ComponentModel; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +[Serializable] +[TypeConverter(typeof(ExpandableObjectConverter))] +public class TrainerRandSettings { - [Serializable] - [TypeConverter(typeof(ExpandableObjectConverter))] - public class TrainerRandSettings - { - private const string General = nameof(General); - private const string Classes = nameof(Classes); - private const string PKM = nameof(PKM); - private const string Stats = nameof(Stats); - private const string Moves = nameof(Moves); + private const string General = nameof(General); + private const string Classes = nameof(Classes); + private const string PKM = nameof(PKM); + private const string Stats = nameof(Stats); + private const string Moves = nameof(Moves); - #region General - [Category(General), Description("Modifies the team count per specifications, and forces fixed counts for some trainers.")] - public bool ModifyTeamCount { get; set; } = true; + #region General + [Category(General), Description("Modifies the team count per specifications, and forces fixed counts for some trainers.")] + public bool ModifyTeamCount { get; set; } = true; - [Category(General), Description("Minimum count of PKM the Trainer has. New PKM will be added to the team if less are currently present.")] - public int TeamCountMin { get; set; } = 1; + [Category(General), Description("Minimum count of PKM the Trainer has. New PKM will be added to the team if less are currently present.")] + public int TeamCountMin { get; set; } = 1; - [Category(General), Description("Maximum count of PKM the Trainer has. PKM will be removed from the team if more are currently present.")] - public int TeamCountMax { get; set; } = 6; + [Category(General), Description("Maximum count of PKM the Trainer has. PKM will be removed from the team if more are currently present.")] + public int TeamCountMax { get; set; } = 6; - [Category(General), Description("Chooses a random type for the Trainer, and requires each PKM to have that type.")] - public bool TeamTypeThemed { get; set; } = false; + [Category(General), Description("Chooses a random type for the Trainer, and requires each PKM to have that type.")] + public bool TeamTypeThemed { get; set; } - [Category(General), Description("Maxes out the Trainer AI value to use its team and moves most effectively.")] - public bool TrainerMaxAI { get; set; } = true; + [Category(General), Description("Maxes out the Trainer AI value to use its team and moves most effectively.")] + public bool TrainerMaxAI { get; set; } = true; - [Category(General), Description("Force special strong battles to have a full team of 6 PKM.")] - public bool ForceSpecialTeamCount6 { get; set; } = true; + [Category(General), Description("Force special strong battles to have a full team of 6 PKM.")] + public bool ForceSpecialTeamCount6 { get; set; } = true; - [Category(General), Description("Force all battles to be a Double Battle with an even (not odd) amount of PKM.")] - public bool ForceDoubles { get; set; } - #endregion + [Category(General), Description("Force all battles to be a Double Battle with an even (not odd) amount of PKM.")] + public bool ForceDoubles { get; set; } + #endregion - #region Classes - [Category(Classes), Description("Change Trainer Class to another random Trainer Class.")] - public bool RandomTrainerClass { get; set; } = false; + #region Classes + [Category(Classes), Description("Change Trainer Class to another random Trainer Class.")] + public bool RandomTrainerClass { get; set; } - [Category(Classes), Description("Skip changing Trainer Classes that are considered special (avoiding crashes).")] - public bool SkipSpecialClasses { get; set; } = true; - #endregion + [Category(Classes), Description("Skip changing Trainer Classes that are considered special (avoiding crashes).")] + public bool SkipSpecialClasses { get; set; } = true; + #endregion - #region PKM - [Category(PKM), Description("Randomizes the Species and basic stat details of all Team members.")] - public bool RandomizeTeam { get; set; } = true; + #region PKM + [Category(PKM), Description("Randomizes the Species and basic stat details of all Team members.")] + public bool RandomizeTeam { get; set; } = true; - [Category(PKM), Description("Allows random Mega Forms when randomizing species.")] - public bool AllowRandomMegaForms { get; set; } = false; + [Category(PKM), Description("Allows random Mega Forms when randomizing species.")] + public bool AllowRandomMegaForms { get; set; } - [Category(PKM), Description("Allows random Fused PKM when randomizing species.")] - public bool AllowRandomFusions { get; set; } = false; + [Category(PKM), Description("Allows random Fused PKM when randomizing species.")] + public bool AllowRandomFusions { get; set; } - [Category(PKM), Description("Allows random Held Items when randomizing species.")] - public bool AllowRandomHeldItems { get; set; } = false; + [Category(PKM), Description("Allows random Held Items when randomizing species.")] + public bool AllowRandomHeldItems { get; set; } - [Category(PKM), Description("Forces all PKM above the specified level setting to be fully evolved.")] - public bool ForceFullyEvolved { get; set; } = true; + [Category(PKM), Description("Forces all PKM above the specified level setting to be fully evolved.")] + public bool ForceFullyEvolved { get; set; } = true; - [Category(PKM), Description("Forces all PKM above this level to be fully evolved if the " + nameof(ForceFullyEvolved) + " setting is set.")] - public int ForceFullyEvolvedAtLevel { get; set; } = 36; + [Category(PKM), Description("Forces all PKM above this level to be fully evolved if the " + nameof(ForceFullyEvolved) + " setting is set.")] + public int ForceFullyEvolvedAtLevel { get; set; } = 36; - [Category(PKM), Description("Swaps Gigantamaxed species with other Gigantamaxed species.")] - public bool GigantamaxSwap { get; set; } = false; + [Category(PKM), Description("Swaps Gigantamaxed species with other Gigantamaxed species.")] + public bool GigantamaxSwap { get; set; } - [Category(PKM), Description("Causes all PKM levels to be boosted by the specified ratio multiplier.")] - public bool BoostLevel { get; set; } = true; + [Category(PKM), Description("Causes all PKM levels to be boosted by the specified ratio multiplier.")] + public bool BoostLevel { get; set; } = true; - [Category(PKM), Description("Boosts levels of all PKM by this ratio if the " + nameof(BoostLevel) + " setting is set.")] - public float LevelBoostRatio { get; set; } = 1.1f; - #endregion + [Category(PKM), Description("Boosts levels of all PKM by this ratio if the " + nameof(BoostLevel) + " setting is set.")] + public float LevelBoostRatio { get; set; } = 1.1f; + #endregion - #region Stats - [Category(Stats), Description("Makes random Trainer PKM shiny.")] - public bool RandomShinies { get; set; } = true; + #region Stats + [Category(Stats), Description("Makes random Trainer PKM shiny.")] + public bool RandomShinies { get; set; } = true; - [Category(Stats), Description("Makes random Trainer PKM shiny at this rate (percent).")] - public float ShinyChance { get; set; } = 2.5f; + [Category(Stats), Description("Makes random Trainer PKM shiny at this rate (percent).")] + public float ShinyChance { get; set; } = 2.5f; - [Category(Stats), Description("Maximizes all IVs.")] - public bool MaxIVs { get; set; } = true; + [Category(Stats), Description("Maximizes all IVs.")] + public bool MaxIVs { get; set; } = true; - [Category(Stats), Description("Picks a random valid ability for each PKM.")] - public bool RandomAbilities { get; set; } = true; + [Category(Stats), Description("Picks a random valid ability for each PKM.")] + public bool RandomAbilities { get; set; } = true; - [Category(Stats), Description("Makes all Dynamaxed PKM have a Dynamax Level of 10.")] - public bool MaxDynamaxLevel { get; set; } = true; - #endregion + [Category(Stats), Description("Makes all Dynamaxed PKM have a Dynamax Level of 10.")] + public bool MaxDynamaxLevel { get; set; } = true; + #endregion - #region Moves - [Category(Moves), Description("How movesets are randomized/chosen for each PKM.")] - public MoveRandType MoveRandType { get; set; } = MoveRandType.RandomMoves; - #endregion - } -} \ No newline at end of file + #region Moves + [Category(Moves), Description("How movesets are randomized/chosen for each PKM.")] + public MoveRandType MoveRandType { get; set; } = MoveRandType.RandomMoves; + #endregion +} diff --git a/pkNX.Randomization/Randomizers/SpeciesRandomizer.cs b/pkNX.Randomization/Randomizers/SpeciesRandomizer.cs index c35f41dc..4134568f 100644 --- a/pkNX.Randomization/Randomizers/SpeciesRandomizer.cs +++ b/pkNX.Randomization/Randomizers/SpeciesRandomizer.cs @@ -1,172 +1,171 @@ -using System; +using System; using System.Linq; using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public class SpeciesRandomizer { - public class SpeciesRandomizer + private readonly IPersonalTable SpeciesStat; + private readonly int MaxSpeciesID; + private readonly GameInfo Game; + + private SpeciesSettings s = new(); + + public SpeciesRandomizer(GameInfo game, IPersonalTable t) { - private readonly IPersonalTable SpeciesStat; - private readonly int MaxSpeciesID; - private readonly GameInfo Game; + Game = game; + MaxSpeciesID = Game.MaxSpeciesID; + SpeciesStat = t; + } - private SpeciesSettings s = new(); + /// + /// Initializes the according to the provided settings. + /// + /// General settings + /// Optional extra: banned species + public void Initialize(SpeciesSettings settings, params int[] banlist) + { + s = settings; + var list = s.GetSpecies(Game.MaxSpeciesID, Game.Generation).Except(banlist); - public SpeciesRandomizer(GameInfo game, IPersonalTable t) + legends = Game.Generation == 8 ? Legal.Legendary_8 : Legal.Legendary_1; + events = Game.Generation == 8 ? Legal.Mythical_8 : Legal.Mythical_GG; + + RandSpec = new GenericRandomizer(list.ToArray()); + RandLegend = new GenericRandomizer(legends.Except(banlist).ToArray()); + RandEvent = new GenericRandomizer(events.Except(banlist).ToArray()); + } + + #region Random Species Filtering Parameters + private GenericRandomizer RandSpec = new(Array.Empty()); + private GenericRandomizer RandLegend = new(Array.Empty()); + private GenericRandomizer RandEvent = new(Array.Empty()); + private int[] legends = Array.Empty(); + private int[] events = Array.Empty(); + private int loopctr; + private const int l = 10; // tweakable scalars + private const int h = 11; + #endregion + + internal int GetRandomSpecies(int oldSpecies, params int[] bannedSpecies) + { + // Get a new random species + var oldpkm = SpeciesStat[oldSpecies]; + + loopctr = 0; // altering calculations to prevent infinite loops + int newSpecies; + while (!GetNewSpecies(oldSpecies, oldpkm, out newSpecies) || bannedSpecies.Contains(newSpecies)) + loopctr++; + return newSpecies; + } + + public int GetRandomSpeciesType(int oldSpecies, int type) + { + // Get a new random species + IPersonalInfo oldpkm = SpeciesStat[oldSpecies]; + + loopctr = 0; // altering calculations to prevent infinite loops + int newSpecies; + while (!GetNewSpecies(oldSpecies, oldpkm, out newSpecies) || !GetIsTypeMatch(newSpecies, type)) + loopctr++; + return newSpecies; + } + + private bool GetIsTypeMatch(int newSpecies, int type) => type == -1 || SpeciesStat[newSpecies].IsType((Types)type) || loopctr > 9000; + + public int GetRandomSpecies() => RandSpec.Next(); + + public int GetRandomSpecies(int oldSpecies) + { + // Get a new random species + var oldpkm = SpeciesStat[oldSpecies]; + + loopctr = 0; // altering calculations to prevent infinite loops + int newSpecies; + while (!GetNewSpecies(oldSpecies, oldpkm, out newSpecies)) { - Game = game; - MaxSpeciesID = Game.MaxSpeciesID; - SpeciesStat = t; - } - - /// - /// Initializes the according to the provided settings. - /// - /// General settings - /// Optional extra: banned species - public void Initialize(SpeciesSettings settings, params int[] banlist) - { - s = settings; - var list = s.GetSpecies(Game.MaxSpeciesID, Game.Generation).Except(banlist); - - legends = Game.Generation == 8 ? Legal.Legendary_8 : Legal.Legendary_1; - events = Game.Generation == 8 ? Legal.Mythical_8 : Legal.Mythical_GG; - - RandSpec = new GenericRandomizer(list.ToArray()); - RandLegend = new GenericRandomizer(legends.Except(banlist).ToArray()); - RandEvent = new GenericRandomizer(events.Except(banlist).ToArray()); - } - - #region Random Species Filtering Parameters - private GenericRandomizer RandSpec = new(Array.Empty()); - private GenericRandomizer RandLegend = new(Array.Empty()); - private GenericRandomizer RandEvent = new(Array.Empty()); - private int[] legends = Array.Empty(); - private int[] events = Array.Empty(); - private int loopctr; - private const int l = 10; // tweakable scalars - private const int h = 11; - #endregion - - internal int GetRandomSpecies(int oldSpecies, params int[] bannedSpecies) - { - // Get a new random species - var oldpkm = SpeciesStat[oldSpecies]; - - loopctr = 0; // altering calculations to prevent infinite loops - int newSpecies; - while (!GetNewSpecies(oldSpecies, oldpkm, out newSpecies) || bannedSpecies.Contains(newSpecies)) - loopctr++; - return newSpecies; - } - - public int GetRandomSpeciesType(int oldSpecies, int type) - { - // Get a new random species - IPersonalInfo oldpkm = SpeciesStat[oldSpecies]; - - loopctr = 0; // altering calculations to prevent infinite loops - int newSpecies; - while (!GetNewSpecies(oldSpecies, oldpkm, out newSpecies) || !GetIsTypeMatch(newSpecies, type)) - loopctr++; - return newSpecies; - } - - private bool GetIsTypeMatch(int newSpecies, int type) => type == -1 || SpeciesStat[newSpecies].IsType((Types)type) || loopctr > 9000; - - public int GetRandomSpecies() => RandSpec.Next(); - - public int GetRandomSpecies(int oldSpecies) - { - // Get a new random species - var oldpkm = SpeciesStat[oldSpecies]; - - loopctr = 0; // altering calculations to prevent infinite loops - int newSpecies; - while (!GetNewSpecies(oldSpecies, oldpkm, out newSpecies)) + if (loopctr > 0x0001_0000) { - if (loopctr > 0x0001_0000) - { - var pkm = SpeciesStat[newSpecies]; - if (IsSpeciesBSTBad(oldpkm, pkm) && loopctr > 0x0001_1000) // keep trying for at minimum BST - continue; - return newSpecies; // failed to find any match based on criteria, return random species that may or may not match criteria - } - loopctr++; + var pkm = SpeciesStat[newSpecies]; + if (IsSpeciesBSTBad(oldpkm, pkm) && loopctr > 0x0001_1000) // keep trying for at minimum BST + continue; + return newSpecies; // failed to find any match based on criteria, return random species that may or may not match criteria } - return newSpecies; + loopctr++; } + return newSpecies; + } - public int[] RandomSpeciesList => Enumerable.Range(1, MaxSpeciesID).ToArray(); + public int[] RandomSpeciesList => Enumerable.Range(1, MaxSpeciesID).ToArray(); - private bool GetNewSpecies(int currentSpecies, IPersonalInfo oldpkm, out int newSpecies) + private bool GetNewSpecies(int currentSpecies, IPersonalInfo oldpkm, out int newSpecies) + { + bool isLegend = false; + + newSpecies = RandSpec.Next(); + + // If we randomly got a legendary or mythical, not really a need to reroll + if (legends.Contains(newSpecies) || events.Contains(newSpecies)) isLegend = true; + + if ((Util.Random.Next(0, 100 + 1) < s.LegendsChance) && s.Legends) { - bool isLegend = false; - - newSpecies = RandSpec.Next(); - - // If we randomly got a legendary or mythical, not really a need to reroll - if (legends.Contains(newSpecies) || events.Contains(newSpecies)) isLegend = true; - - if ((Util.Random.Next(0, 100 + 1) < s.LegendsChance) && s.Legends) - { - if (!isLegend) newSpecies = RandLegend.Next(); - isLegend = true; - } - - if ((Util.Random.Next(0, 100 + 1) < s.EventsChance) && s.Events) - { - if (!isLegend) newSpecies = RandEvent.Next(); - } - - var pkm = SpeciesStat[newSpecies]; - - if (IsSpeciesReplacementBad(newSpecies, currentSpecies)) // no A->A randomization - return false; - return IsCriteriaMatch(oldpkm, pkm); + if (!isLegend) newSpecies = RandLegend.Next(); + isLegend = true; } - private bool IsSpeciesReplacementBad(int newSpecies, int currentSpecies) + if ((Util.Random.Next(0, 100 + 1) < s.EventsChance) && s.Events) { - if (newSpecies != currentSpecies) - return false; - return loopctr < MaxSpeciesID * 10; + if (!isLegend) newSpecies = RandEvent.Next(); } - private bool IsCriteriaMatch(IPersonalInfo oldpkm, IPersonalInfo pkm) - { - if (IsSpeciesEXPRateBad(oldpkm, pkm)) - return false; - if (IsSpeciesTypeBad(oldpkm, pkm)) - return false; - if (IsSpeciesBSTBad(oldpkm, pkm)) - return false; - return true; - } + var pkm = SpeciesStat[newSpecies]; - private bool IsSpeciesEXPRateBad(IPersonalTraits oldpkm, IPersonalTraits pkm) - { - return s.EXPGroup && oldpkm.EXPGrowth == pkm.EXPGrowth; - } + if (IsSpeciesReplacementBad(newSpecies, currentSpecies)) // no A->A randomization + return false; + return IsCriteriaMatch(oldpkm, pkm); + } - private bool IsSpeciesTypeBad(IPersonalType oldpkm, IPersonalType pkm) - { - return s.Type && (oldpkm.IsType(pkm.Type1) || oldpkm.IsType(pkm.Type2)); - } + private bool IsSpeciesReplacementBad(int newSpecies, int currentSpecies) + { + if (newSpecies != currentSpecies) + return false; + return loopctr < MaxSpeciesID * 10; + } - private bool IsSpeciesBSTBad(IPersonalInfo oldpkm, IPersonalInfo pkm) - { - if (!s.BST) - return false; + private bool IsCriteriaMatch(IPersonalInfo oldpkm, IPersonalInfo pkm) + { + if (IsSpeciesEXPRateBad(oldpkm, pkm)) + return false; + if (IsSpeciesTypeBad(oldpkm, pkm)) + return false; + if (IsSpeciesBSTBad(oldpkm, pkm)) + return false; + return true; + } - // Base stat total has to be close to original BST - int oldBST = oldpkm.GetBaseStatTotal(); - int pkmBST = pkm.GetBaseStatTotal(); + private bool IsSpeciesEXPRateBad(IPersonalTraits oldpkm, IPersonalTraits pkm) + { + return s.EXPGroup && oldpkm.EXPGrowth == pkm.EXPGrowth; + } - int expand = loopctr / MaxSpeciesID; - int lo = oldBST * l / (h + expand); - int hi = oldBST * (h + expand) / l; - return lo > pkmBST || pkmBST > hi; - } + private bool IsSpeciesTypeBad(IPersonalType oldpkm, IPersonalType pkm) + { + return s.Type && (oldpkm.IsType(pkm.Type1) || oldpkm.IsType(pkm.Type2)); + } + + private bool IsSpeciesBSTBad(IPersonalInfo oldpkm, IPersonalInfo pkm) + { + if (!s.BST) + return false; + + // Base stat total has to be close to original BST + int oldBST = oldpkm.GetBaseStatTotal(); + int pkmBST = pkm.GetBaseStatTotal(); + + int expand = loopctr / MaxSpeciesID; + int lo = oldBST * l / (h + expand); + int hi = oldBST * (h + expand) / l; + return lo > pkmBST || pkmBST > hi; } } diff --git a/pkNX.Randomization/Randomizers/TrainerRandomizer.cs b/pkNX.Randomization/Randomizers/TrainerRandomizer.cs index 141c23ea..79ff33fb 100644 --- a/pkNX.Randomization/Randomizers/TrainerRandomizer.cs +++ b/pkNX.Randomization/Randomizers/TrainerRandomizer.cs @@ -3,400 +3,399 @@ using System.Linq; using pkNX.Structures; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public class TrainerRandomizer : Randomizer { - public class TrainerRandomizer : Randomizer + private readonly GameInfo Info; + private readonly IPersonalTable Personal; + private readonly VsTrainer[] Trainers; + private readonly int[] PossibleHeldItems; + private readonly int[] GigantamaxForms; + private readonly Dictionary MegaDictionary; + private readonly Dictionary IndexFixedCount; + private readonly IList SpecialClasses; + private readonly IList CrashClasses; + + public int ClassCount { get; set; } + public EvolutionSet[] Evos { get; } + + // Set these before starting up + public GenericRandomizer Class { get; set; } = null!; + public LearnsetRandomizer Learn { get; set; } = null!; + public SpeciesRandomizer RandSpec { get; set; } = null!; + public FormRandomizer RandForm { get; set; } = null!; + public MoveRandomizer RandMove { get; set; } = null!; + public Func GetBlank { get; set; } = null!; + + private TrainerRandSettings Settings = null!; + private SpeciesSettings SpecSettings = null!; + + public TrainerRandomizer(GameInfo info, IPersonalTable t, VsTrainer[] trainers, EvolutionSet[] evos) { - private readonly GameInfo Info; - private readonly IPersonalTable Personal; - private readonly VsTrainer[] Trainers; - private readonly int[] PossibleHeldItems; - private readonly int[] GigantamaxForms; - private readonly Dictionary MegaDictionary; - private readonly Dictionary IndexFixedCount; - private readonly IList SpecialClasses; - private readonly IList CrashClasses; + Trainers = trainers; + Info = info; + Personal = t; + Evos = evos; - public int ClassCount { get; set; } - public EvolutionSet[] Evos { get; } + PossibleHeldItems = Legal.GetRandomItemList(Info.Game); + GigantamaxForms = Legal.GigantamaxForms.ToArray(); + MegaDictionary = Legal.GetMegaDictionary(Info.Game); + IndexFixedCount = GetFixedCountIndexes(Info.Game); + SpecialClasses = GetSpecialClasses(Info.Game); + CrashClasses = GetCrashClasses(Info.Game); + } - // Set these before starting up - public GenericRandomizer Class { get; set; } = null!; - public LearnsetRandomizer Learn { get; set; } = null!; - public SpeciesRandomizer RandSpec { get; set; } = null!; - public FormRandomizer RandForm { get; set; } = null!; - public MoveRandomizer RandMove { get; set; } = null!; - public Func GetBlank { get; set; } = null!; + public void Initialize(TrainerRandSettings settings, SpeciesSettings spec) + { + Settings = settings; + SpecSettings = spec; - private TrainerRandSettings Settings = null!; - private SpeciesSettings SpecSettings = null!; + IEnumerable classes = Enumerable.Range(0, ClassCount).Except(CrashClasses); + if (Settings.SkipSpecialClasses) + classes = classes.Except(SpecialClasses); + Class = new GenericRandomizer(classes.ToArray()); + } - public TrainerRandomizer(GameInfo info, IPersonalTable t, VsTrainer[] trainers, EvolutionSet[] evos) + public override void Execute() + { + foreach (var tr in Trainers) { - Trainers = trainers; - Info = info; - Personal = t; - Evos = evos; + if (tr.Team.Count == 0) + continue; - PossibleHeldItems = Legal.GetRandomItemList(Info.Game); - GigantamaxForms = Legal.GigantamaxForms.ToArray(); - MegaDictionary = Legal.GetMegaDictionary(Info.Game); - IndexFixedCount = GetFixedCountIndexes(Info.Game); - SpecialClasses = GetSpecialClasses(Info.Game); - CrashClasses = GetCrashClasses(Info.Game); - } + // Trainer + if (Settings.RandomTrainerClass) + SetRandomClass(tr); + if (Settings.ModifyTeamCount) + SetupTeamCount(tr); + if (Settings.TrainerMaxAI) + MaximizeAIFlags(tr); - public void Initialize(TrainerRandSettings settings, SpeciesSettings spec) - { - Settings = settings; - SpecSettings = spec; - - IEnumerable classes = Enumerable.Range(0, ClassCount).Except(CrashClasses); - if (Settings.SkipSpecialClasses) - classes = classes.Except(SpecialClasses); - Class = new GenericRandomizer(classes.ToArray()); - } - - public override void Execute() - { - foreach (var tr in Trainers) + // Team + foreach (var pk in tr.Team) { - if (tr.Team.Count == 0) + if (pk.Species == 0) continue; - - // Trainer - if (Settings.RandomTrainerClass) - SetRandomClass(tr); - if (Settings.ModifyTeamCount) - SetupTeamCount(tr); - if (Settings.TrainerMaxAI) - MaximizeAIFlags(tr); - - // Team - foreach (var pk in tr.Team) - { - if (pk.Species == 0) - continue; - DetermineSpecies(pk); - UpdatePKMFromSettings(pk); - } + DetermineSpecies(pk); + UpdatePKMFromSettings(pk); } } - - public static void MaximizeAIFlags(VsTrainer tr) - { - const TrainerAI max = (TrainerAI.Basic | TrainerAI.Strong | TrainerAI.Expert | TrainerAI.PokeChange); - tr.Self.AI |= (int)max; - } - - private void SetupTeamCount(VsTrainer tr) - { - bool special = IndexFixedCount.TryGetValue(tr.ID, out var count); - special &= (count != 6 || Settings.ForceSpecialTeamCount6); - int min = special ? count : Settings.TeamCountMin; - int max = special ? count : Settings.TeamCountMax; - - var avgBST = (int)tr.Team.Average(pk => Personal[pk.Species].GetBaseStatTotal()); - int avgLevel = (int)tr.Team.Average(pk => pk.Level); - var pinfo = Personal.Table.OrderBy(pk => Math.Abs(avgBST - pk.GetBaseStatTotal())).First(); - int avgSpec = Array.IndexOf(Personal.Table, pinfo); - - if (Settings.ForceDoubles && !(special && count % 2 == 1)) - { - if (tr.Team.Count % 2 != 0) - tr.Team.Add(GetBlankPKM(avgLevel, avgSpec)); - tr.Self.AI |= (int)TrainerAI.Doubles; - tr.Self.Mode = BattleMode.Doubles; - } - - if (tr.Team.Count < min) - { - for (int p = tr.Team.Count; p < min; p++) - tr.Team.Add(GetBlankPKM(avgLevel, avgSpec)); - } - else if (tr.Team.Count > max) - { - tr.Team.RemoveRange(max, tr.Team.Count - max); - } - } - - private void SetRandomClass(VsTrainer tr) - { - // ignore special classes - if (Settings.SkipSpecialClasses && SpecialClasses.Contains(tr.Self.Class)) - return; - - if (CrashClasses.Contains(tr.Self.Class)) - return; // keep as is - - tr.Self.Class = Class.Next(); - } - - private void DetermineSpecies(IPokeData pk) - { - if (Settings.RandomizeTeam) - { - int Type = Settings.TeamTypeThemed ? Util.Random.Next(17) : -1; - RandomizeSpecFormItem(pk, Type); - - pk.Gender = 0; // random - pk.Nature = Util.Random.Next(25); // random - } - } - - private void RandomizeSpecFormItem(IPokeData pk, int Type) - { - if (pk is TrainerPoke7b p7b) - { - RandomizeSpecForm(p7b, Type); - return; - } - - // replaces Megas with another Mega (Dexio and Lysandre in USUM) - if (MegaDictionary.Any(z => z.Value.Contains(pk.HeldItem))) - { - int[] mega = GetRandomMega(MegaDictionary, out int species); - pk.Species = species; - int index = Util.Random.Next(mega.Length); - pk.HeldItem = mega[index]; - pk.Form = 0; // allow it to Mega Evolve naturally - } - else // every other pkm - { - pk.Species = RandSpec.GetRandomSpeciesType(pk.Species, Type); - pk.Form = RandForm.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, Settings.AllowRandomFusions, true, true, Personal.Table); - } - } - - private void RandomizeSpecForm(TrainerPoke7b pk, int type) - { - bool isMega = pk.MegaFormChoice != 0; - if (isMega) - { - int[] mega = GetRandomMega(MegaDictionary, out int species); - pk.Species = species; - pk.CanMegaEvolve = true; - pk.MegaFormChoice = Util.Random.Next(mega.Length) + 1; - pk.Form = 0; // allow it to Mega Evolve naturally - return; - } - - pk.Species = RandSpec.GetRandomSpeciesType(pk.Species, type); - pk.Form = RandForm.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, Settings.AllowRandomFusions, true, false, Personal.Table); - } - - private void TryForceEvolve(IPokeData pk) - { - if (!Settings.ForceFullyEvolved || pk.Level < Settings.ForceFullyEvolvedAtLevel) - return; - - var evos = Evos; - int species = pk.Species; - int form = pk.Form; - - int timesEvolved = TryForceEvolve(evos, ref species, ref form); - if (timesEvolved == 0) - return; - pk.Species = species; - pk.Form = form; - } - - private int TryForceEvolve(IReadOnlyList evos, ref int species, ref int form) - { - int timesEvolved = 0; - do - { - var index = Personal.GetFormIndex((ushort)species, (byte)form); - var eSet = evos[index].PossibleEvolutions; - int evoCount = eSet.Count(z => z.HasData); - if (evoCount == 0 && species != (int)Species.Meltan) - break; - ++timesEvolved; - var next = Util.Random.Next(evoCount); - var nextEvo = eSet[next]; - - // Meltan only evolves in GO, so force evolve if no custom evo method has been added - if (evoCount == 0 && species == (int)Species.Meltan) - species = (int)Species.Melmetal; - else - species = nextEvo.Species; - - form = nextEvo.Form >= 0 ? nextEvo.Form : form; - } - while (timesEvolved < 3); // prevent randomized evos from looping excessively - return timesEvolved; - } - - private void UpdatePKMFromSettings(TrainerPoke pk) - { - if (Settings.AllowRandomHeldItems && pk is not TrainerPoke7b) - pk.HeldItem = PossibleHeldItems[Util.Random.Next(PossibleHeldItems.Length)]; - if (Settings.BoostLevel) - BoostLevel(pk, Settings.LevelBoostRatio); - if (Settings.RandomShinies) - pk.Shiny = Util.Random.Next(0, 100 + 1) < Settings.ShinyChance; - if (Settings.RandomAbilities) - pk.Ability = Util.Random.Next(1, 4); // 1, 2, or H - if (Settings.MaxIVs) - pk.IVs = new[] { 31, 31, 31, 31, 31, 31 }; - - TryForceEvolve(pk); - - // Gen 8 settings - if (pk is TrainerPoke8 c) - { - if (Settings.GigantamaxSwap && c.CanGigantamax) - { - // only allow Gigantamax Forms per the user's species settings - var species = SpecSettings.GetSpecies(Info.MaxSpeciesID, Info.Generation); - var AllowedGigantamaxes = species.Intersect(GigantamaxForms).ToArray(); - - if (AllowedGigantamaxes.Length == 0) // return if the user's settings make it to where no gmax fits the criteria - return; - - c.Species = AllowedGigantamaxes[Util.Random.Next(AllowedGigantamaxes.Length)]; - c.Form = c.Species is (int)Species.Pikachu or (int)Species.Meowth ? 0 : RandForm.GetRandomForme(c.Species, false, false, false, false, Personal.Table); // Pikachu & Meowth altforms can't gmax - } - if (Settings.MaxDynamaxLevel && c.CanDynamax) - c.DynamaxLevel = 10; - } - - RandomizeEntryMoves(pk); - } - - public static void BoostLevel(IPokeData pk, double ratio) - { - pk.Level = Legal.GetModifiedLevel(pk.Level, ratio); - } - - public void ModifyAllPokemon(Action act) - { - if (act == null) - throw new ArgumentException(nameof(act)); - - foreach (var tr in Trainers.Where(z => z.Team.Count != 0)) - { - foreach (var pk in tr.Team) - { - if (pk.Species != 0) - act(pk); - } - } - } - - public void ModifyAllTrainers(Action act) - { - if (act == null) - throw new ArgumentException(nameof(act)); - - foreach (var tr in Trainers.Where(z => z.Team.Count != 0)) - { - act(tr); - } - } - - private void RandomizeEntryMoves(TrainerPoke pk) - { - switch (Settings.MoveRandType) - { - case MoveRandType.RandomMoves: // Random - pk.Moves = RandMove.GetRandomMoveset(pk.Species); - break; - case MoveRandType.LevelUpMoves: - pk.Moves = Learn.GetCurrentMoves((ushort)pk.Species, (byte)pk.Form, pk.Level); - break; - case MoveRandType.HighPowered: - pk.Moves = Learn.GetHighPoweredMoves((ushort)pk.Species, (byte)pk.Form); - break; - case MoveRandType.MetronomeOnly: // Metronome - pk.Moves = new[] { 118, 0, 0, 0 }; - break; - default: - return; - } - - // sanitize moves - var moves = pk.Moves; - if (RandMove.SanitizeMovesetForBannedMoves(moves, pk.Species)) - pk.Moves = moves; - } - - private TrainerPoke GetBlankPKM(int avgLevel, int avgSpec) - { - var pk = GetBlank(); - pk.Species = RandSpec.GetRandomSpecies(avgSpec); - pk.Level = avgLevel; - return pk; - } - - private static int[] GetRandomMega(Dictionary megas, out int species) - { - int rnd = Util.Random.Next(megas.Count); - species = megas.Keys.ElementAt(rnd); - return megas.Values.ElementAt(rnd); - } - - // 1 poke max - private static readonly int[] royal = { 081, 082, 083, 084, 185 }; - - // 3 poke max - private static readonly int[] MultiBattle_GG = - { - 007, 008, 020, 021, 024, 025, 032, 033, 050, 051, // Jessie & James - 028, 029, 030, 031, // Rival vs Archer & Grunt - }; - - // 3 poke max - private static readonly int[] MultiBattle_SWSH = - { - 156, 157, 158, 197, 198, 199, 225, 226, 227, 312, 313, 314, // Hop - 223, 224, // Sordward and Shielbert - }; - - private static Dictionary GetFixedCountIndexes(GameVersion game) - { - if (GameVersion.XY.Contains(game)) - return Legal.ImportantTrainers_XY.ToDictionary(z => z, _ => 6); - if (GameVersion.ORAS.Contains(game)) - return Legal.ImportantTrainers_ORAS.ToDictionary(z => z, _ => 6); - if (GameVersion.SM.Contains(game)) - return Legal.ImportantTrainers_SM.ToDictionary(z => z, index => royal.Contains(index) ? 1 : 6); - if (GameVersion.USUM.Contains(game)) - return Legal.ImportantTrainers_USUM.ToDictionary(z => z, index => royal.Contains(index) ? 1 : 6); - if (GameVersion.GG.Contains(game)) - return Legal.ImportantTrainers_GG.ToDictionary(z => z, index => MultiBattle_GG.Contains(index) ? 3 : 6); - if (GameVersion.SWSH.Contains(game)) - return Legal.ImportantTrainers_SWSH.ToDictionary(z => z, index => MultiBattle_SWSH.Contains(index) ? 3 : 6); - return new Dictionary(); - } - - private static readonly int[] CrashClasses_GG = Legal.BlacklistedClasses_GG; - private static readonly int[] CrashClasses_SWSH = Legal.BlacklistedClasses_SWSH; - - private static int[] GetSpecialClasses(GameVersion game) - { - if (GameVersion.SWSH.Contains(game)) - return Legal.SpecialClasses_SWSH; - if (GameVersion.GG.Contains(game)) - return Legal.SpecialClasses_GG; - if (GameVersion.USUM.Contains(game)) - return Legal.SpecialClasses_USUM; - if (GameVersion.SM.Contains(game)) - return Legal.SpecialClasses_SM; - if (GameVersion.ORAS.Contains(game)) - return Legal.SpecialClasses_ORAS; - if (GameVersion.XY.Contains(game)) - return Legal.SpecialClasses_XY; - return Array.Empty(); - } - - private static int[] GetCrashClasses(GameVersion game) - { - if (GameVersion.SWSH.Contains(game)) - return CrashClasses_SWSH; - if (GameVersion.GG.Contains(game)) - return CrashClasses_GG; - return Array.Empty(); - } } -} \ No newline at end of file + + public static void MaximizeAIFlags(VsTrainer tr) + { + const TrainerAI max = (TrainerAI.Basic | TrainerAI.Strong | TrainerAI.Expert | TrainerAI.PokeChange); + tr.Self.AI |= (int)max; + } + + private void SetupTeamCount(VsTrainer tr) + { + bool special = IndexFixedCount.TryGetValue(tr.ID, out var count); + special &= (count != 6 || Settings.ForceSpecialTeamCount6); + int min = special ? count : Settings.TeamCountMin; + int max = special ? count : Settings.TeamCountMax; + + var avgBST = (int)tr.Team.Average(pk => Personal[pk.Species].GetBaseStatTotal()); + int avgLevel = (int)tr.Team.Average(pk => pk.Level); + var pinfo = Personal.Table.OrderBy(pk => Math.Abs(avgBST - pk.GetBaseStatTotal())).First(); + int avgSpec = Array.IndexOf(Personal.Table, pinfo); + + if (Settings.ForceDoubles && !(special && count % 2 == 1)) + { + if (tr.Team.Count % 2 != 0) + tr.Team.Add(GetBlankPKM(avgLevel, avgSpec)); + tr.Self.AI |= (int)TrainerAI.Doubles; + tr.Self.Mode = BattleMode.Doubles; + } + + if (tr.Team.Count < min) + { + for (int p = tr.Team.Count; p < min; p++) + tr.Team.Add(GetBlankPKM(avgLevel, avgSpec)); + } + else if (tr.Team.Count > max) + { + tr.Team.RemoveRange(max, tr.Team.Count - max); + } + } + + private void SetRandomClass(VsTrainer tr) + { + // ignore special classes + if (Settings.SkipSpecialClasses && SpecialClasses.Contains(tr.Self.Class)) + return; + + if (CrashClasses.Contains(tr.Self.Class)) + return; // keep as is + + tr.Self.Class = Class.Next(); + } + + private void DetermineSpecies(IPokeData pk) + { + if (Settings.RandomizeTeam) + { + int Type = Settings.TeamTypeThemed ? Util.Random.Next(17) : -1; + RandomizeSpecFormItem(pk, Type); + + pk.Gender = 0; // random + pk.Nature = Util.Random.Next(25); // random + } + } + + private void RandomizeSpecFormItem(IPokeData pk, int Type) + { + if (pk is TrainerPoke7b p7b) + { + RandomizeSpecForm(p7b, Type); + return; + } + + // replaces Megas with another Mega (Dexio and Lysandre in USUM) + if (MegaDictionary.Any(z => z.Value.Contains(pk.HeldItem))) + { + int[] mega = GetRandomMega(MegaDictionary, out int species); + pk.Species = species; + int index = Util.Random.Next(mega.Length); + pk.HeldItem = mega[index]; + pk.Form = 0; // allow it to Mega Evolve naturally + } + else // every other pkm + { + pk.Species = RandSpec.GetRandomSpeciesType(pk.Species, Type); + pk.Form = RandForm.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, Settings.AllowRandomFusions, true, true, Personal.Table); + } + } + + private void RandomizeSpecForm(TrainerPoke7b pk, int type) + { + bool isMega = pk.MegaFormChoice != 0; + if (isMega) + { + int[] mega = GetRandomMega(MegaDictionary, out int species); + pk.Species = species; + pk.CanMegaEvolve = true; + pk.MegaFormChoice = Util.Random.Next(mega.Length) + 1; + pk.Form = 0; // allow it to Mega Evolve naturally + return; + } + + pk.Species = RandSpec.GetRandomSpeciesType(pk.Species, type); + pk.Form = RandForm.GetRandomForme(pk.Species, Settings.AllowRandomMegaForms, Settings.AllowRandomFusions, true, false, Personal.Table); + } + + private void TryForceEvolve(IPokeData pk) + { + if (!Settings.ForceFullyEvolved || pk.Level < Settings.ForceFullyEvolvedAtLevel) + return; + + var evos = Evos; + int species = pk.Species; + int form = pk.Form; + + int timesEvolved = TryForceEvolve(evos, ref species, ref form); + if (timesEvolved == 0) + return; + pk.Species = species; + pk.Form = form; + } + + private int TryForceEvolve(IReadOnlyList evos, ref int species, ref int form) + { + int timesEvolved = 0; + do + { + var index = Personal.GetFormIndex((ushort)species, (byte)form); + var eSet = evos[index].PossibleEvolutions; + int evoCount = eSet.Count(z => z.HasData); + if (evoCount == 0 && species != (int)Species.Meltan) + break; + ++timesEvolved; + var next = Util.Random.Next(evoCount); + var nextEvo = eSet[next]; + + // Meltan only evolves in GO, so force evolve if no custom evo method has been added + if (evoCount == 0 && species == (int)Species.Meltan) + species = (int)Species.Melmetal; + else + species = nextEvo.Species; + + form = nextEvo.Form; + } + while (timesEvolved < 3); // prevent randomized evos from looping excessively + return timesEvolved; + } + + private void UpdatePKMFromSettings(TrainerPoke pk) + { + if (Settings.AllowRandomHeldItems && pk is not TrainerPoke7b) + pk.HeldItem = PossibleHeldItems[Util.Random.Next(PossibleHeldItems.Length)]; + if (Settings.BoostLevel) + BoostLevel(pk, Settings.LevelBoostRatio); + if (Settings.RandomShinies) + pk.Shiny = Util.Random.Next(0, 100 + 1) < Settings.ShinyChance; + if (Settings.RandomAbilities) + pk.Ability = Util.Random.Next(1, 4); // 1, 2, or H + if (Settings.MaxIVs) + pk.IVs = new[] { 31, 31, 31, 31, 31, 31 }; + + TryForceEvolve(pk); + + // Gen 8 settings + if (pk is TrainerPoke8 c) + { + if (Settings.GigantamaxSwap && c.CanGigantamax) + { + // only allow Gigantamax Forms per the user's species settings + var species = SpecSettings.GetSpecies(Info.MaxSpeciesID, Info.Generation); + var AllowedGigantamaxes = species.Intersect(GigantamaxForms).ToArray(); + + if (AllowedGigantamaxes.Length == 0) // return if the user's settings make it to where no gmax fits the criteria + return; + + c.Species = AllowedGigantamaxes[Util.Random.Next(AllowedGigantamaxes.Length)]; + c.Form = c.Species is (int)Species.Pikachu or (int)Species.Meowth ? 0 : RandForm.GetRandomForme(c.Species, false, false, false, false, Personal.Table); // Pikachu & Meowth altforms can't gmax + } + if (Settings.MaxDynamaxLevel && c.CanDynamax) + c.DynamaxLevel = 10; + } + + RandomizeEntryMoves(pk); + } + + public static void BoostLevel(IPokeData pk, double ratio) + { + pk.Level = Legal.GetModifiedLevel(pk.Level, ratio); + } + + public void ModifyAllPokemon(Action act) + { + if (act == null) + throw new ArgumentException(nameof(act)); + + foreach (var tr in Trainers.Where(z => z.Team.Count != 0)) + { + foreach (var pk in tr.Team) + { + if (pk.Species != 0) + act(pk); + } + } + } + + public void ModifyAllTrainers(Action act) + { + if (act == null) + throw new ArgumentException(null, nameof(act)); + + foreach (var tr in Trainers.Where(z => z.Team.Count != 0)) + { + act(tr); + } + } + + private void RandomizeEntryMoves(TrainerPoke pk) + { + switch (Settings.MoveRandType) + { + case MoveRandType.RandomMoves: // Random + pk.Moves = RandMove.GetRandomMoveset(pk.Species); + break; + case MoveRandType.LevelUpMoves: + pk.Moves = Learn.GetCurrentMoves((ushort)pk.Species, (byte)pk.Form, pk.Level); + break; + case MoveRandType.HighPowered: + pk.Moves = Learn.GetHighPoweredMoves((ushort)pk.Species, (byte)pk.Form); + break; + case MoveRandType.MetronomeOnly: // Metronome + pk.Moves = new[] { 118, 0, 0, 0 }; + break; + default: + return; + } + + // sanitize moves + var moves = pk.Moves; + if (RandMove.SanitizeMovesetForBannedMoves(moves, pk.Species)) + pk.Moves = moves; + } + + private TrainerPoke GetBlankPKM(int avgLevel, int avgSpec) + { + var pk = GetBlank(); + pk.Species = RandSpec.GetRandomSpecies(avgSpec); + pk.Level = avgLevel; + return pk; + } + + private static int[] GetRandomMega(Dictionary megas, out int species) + { + int rnd = Util.Random.Next(megas.Count); + species = megas.Keys.ElementAt(rnd); + return megas.Values.ElementAt(rnd); + } + + // 1 poke max + private static readonly int[] royal = { 081, 082, 083, 084, 185 }; + + // 3 poke max + private static readonly int[] MultiBattle_GG = + { + 007, 008, 020, 021, 024, 025, 032, 033, 050, 051, // Jessie & James + 028, 029, 030, 031, // Rival vs Archer & Grunt + }; + + // 3 poke max + private static readonly int[] MultiBattle_SWSH = + { + 156, 157, 158, 197, 198, 199, 225, 226, 227, 312, 313, 314, // Hop + 223, 224, // Sordward and Shielbert + }; + + private static Dictionary GetFixedCountIndexes(GameVersion game) + { + if (GameVersion.XY.Contains(game)) + return Legal.ImportantTrainers_XY.ToDictionary(z => z, _ => 6); + if (GameVersion.ORAS.Contains(game)) + return Legal.ImportantTrainers_ORAS.ToDictionary(z => z, _ => 6); + if (GameVersion.SM.Contains(game)) + return Legal.ImportantTrainers_SM.ToDictionary(z => z, index => royal.Contains(index) ? 1 : 6); + if (GameVersion.USUM.Contains(game)) + return Legal.ImportantTrainers_USUM.ToDictionary(z => z, index => royal.Contains(index) ? 1 : 6); + if (GameVersion.GG.Contains(game)) + return Legal.ImportantTrainers_GG.ToDictionary(z => z, index => MultiBattle_GG.Contains(index) ? 3 : 6); + if (GameVersion.SWSH.Contains(game)) + return Legal.ImportantTrainers_SWSH.ToDictionary(z => z, index => MultiBattle_SWSH.Contains(index) ? 3 : 6); + return new Dictionary(); + } + + private static readonly int[] CrashClasses_GG = Legal.BlacklistedClasses_GG; + private static readonly int[] CrashClasses_SWSH = Legal.BlacklistedClasses_SWSH; + + private static int[] GetSpecialClasses(GameVersion game) + { + if (GameVersion.SWSH.Contains(game)) + return Legal.SpecialClasses_SWSH; + if (GameVersion.GG.Contains(game)) + return Legal.SpecialClasses_GG; + if (GameVersion.USUM.Contains(game)) + return Legal.SpecialClasses_USUM; + if (GameVersion.SM.Contains(game)) + return Legal.SpecialClasses_SM; + if (GameVersion.ORAS.Contains(game)) + return Legal.SpecialClasses_ORAS; + if (GameVersion.XY.Contains(game)) + return Legal.SpecialClasses_XY; + return Array.Empty(); + } + + private static int[] GetCrashClasses(GameVersion game) + { + if (GameVersion.SWSH.Contains(game)) + return CrashClasses_SWSH; + if (GameVersion.GG.Contains(game)) + return CrashClasses_GG; + return Array.Empty(); + } +} diff --git a/pkNX.Randomization/Util.cs b/pkNX.Randomization/Util.cs index a15f1ca2..ba5d45f8 100644 --- a/pkNX.Randomization/Util.cs +++ b/pkNX.Randomization/Util.cs @@ -1,66 +1,65 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace pkNX.Randomization +namespace pkNX.Randomization; + +public static class Util { - public static class Util + public static Random Random { get; private set; } = new(); + + public static void ReseedRand(int seed) { - public static Random Random { get; private set; } = new(); - - public static void ReseedRand(int seed) - { - Random = new Random(seed); - Structures.Util.Rand = Random; - } - - public static uint Rand32() => (uint)Random.Next(1 << 30) << 2 | (uint)Random.Next(1 << 2); - - public static void Shuffle(IList array) - { - int n = array.Count; - for (int i = 0; i < n; i++) - { - int r = i + (int)(Random.NextDouble() * (n - i)); - (array[r], array[i]) = (array[i], array[r]); - } - } - - public static int ToInt32(string? value) - { - if (value is null) - return 0; - string val = value.Replace(" ", "").Replace("_", "").Trim(); - return string.IsNullOrWhiteSpace(val) ? 0 : int.Parse(val); - } - - public static uint ToUInt32(string? value) - { - if (value is null) - return 0; - string val = value.Replace(" ", "").Replace("_", "").Trim(); - return string.IsNullOrWhiteSpace(val) ? 0 : uint.Parse(val); - } - - public static uint GetHexValue(string s) - { - string str = GetOnlyHex(s); - return string.IsNullOrWhiteSpace(str) ? 0 : Convert.ToUInt32(str, 16); - } - - private static bool IsHex(char c) => c is >= '0' and <= '9' or >= 'A' and <= 'F' or >= 'a' and <= 'f'; - private static string TitleCase(string word) => char.ToUpper(word[0]) + word[1..].ToLower(); - - /// - /// Filters the string down to only valid hex characters, returning a new string. - /// - /// Input string to filter - public static string GetOnlyHex(string str) => string.IsNullOrWhiteSpace(str) ? string.Empty : string.Concat(str.Where(IsHex)); - - /// - /// Returns a new string with each word converted to its appropriate title case. - /// - /// Input string to modify - public static string ToTitleCase(string str) => string.IsNullOrWhiteSpace(str) ? string.Empty : string.Join(" ", str.Split(' ').Select(TitleCase)); + Random = new Random(seed); + Structures.Util.Rand = Random; } + + public static uint Rand32() => (uint)Random.Next(1 << 30) << 2 | (uint)Random.Next(1 << 2); + + public static void Shuffle(IList array) + { + int n = array.Count; + for (int i = 0; i < n; i++) + { + int r = i + (int)(Random.NextDouble() * (n - i)); + (array[r], array[i]) = (array[i], array[r]); + } + } + + public static int ToInt32(string? value) + { + if (value is null) + return 0; + string val = value.Replace(" ", "").Replace("_", "").Trim(); + return string.IsNullOrWhiteSpace(val) ? 0 : int.Parse(val); + } + + public static uint ToUInt32(string? value) + { + if (value is null) + return 0; + string val = value.Replace(" ", "").Replace("_", "").Trim(); + return string.IsNullOrWhiteSpace(val) ? 0 : uint.Parse(val); + } + + public static uint GetHexValue(string s) + { + string str = GetOnlyHex(s); + return string.IsNullOrWhiteSpace(str) ? 0 : Convert.ToUInt32(str, 16); + } + + private static bool IsHex(char c) => c is >= '0' and <= '9' or >= 'A' and <= 'F' or >= 'a' and <= 'f'; + private static string TitleCase(string word) => char.ToUpper(word[0]) + word[1..].ToLower(); + + /// + /// Filters the string down to only valid hex characters, returning a new string. + /// + /// Input string to filter + public static string GetOnlyHex(string str) => string.IsNullOrWhiteSpace(str) ? string.Empty : string.Concat(str.Where(IsHex)); + + /// + /// Returns a new string with each word converted to its appropriate title case. + /// + /// Input string to modify + public static string ToTitleCase(string str) => string.IsNullOrWhiteSpace(str) ? string.Empty : string.Join(" ", str.Split(' ').Select(TitleCase)); } diff --git a/pkNX.Randomization/pkNX.Randomization.csproj b/pkNX.Randomization/pkNX.Randomization.csproj index 45972359..b7bf9988 100644 --- a/pkNX.Randomization/pkNX.Randomization.csproj +++ b/pkNX.Randomization/pkNX.Randomization.csproj @@ -1,17 +1,12 @@ - + - netstandard2.0;net461 + net6.0 Randomizer Utility 10 enable - - - - - diff --git a/pkNX.Sprites/FormConverter.cs b/pkNX.Sprites/FormConverter.cs index 4292f7b3..f6b7c369 100644 --- a/pkNX.Sprites/FormConverter.cs +++ b/pkNX.Sprites/FormConverter.cs @@ -1,64 +1,63 @@ -using System.Collections.Generic; +using System.Collections.Generic; using pkNX.Structures; using static pkNX.Structures.Species; -namespace pkNX.Sprites +namespace pkNX.Sprites; + +public static class FormConverter { - public static class FormConverter + public static bool IsTotemForm(int species, int form, int generation = 7) { - public static bool IsTotemForm(int species, int form, int generation = 7) - { - if (generation != 7) - return false; - if (form == 0) - return false; - if (!Legal.Totem_USUM.Contains((ushort)species)) - return false; - if (species == (int)Mimikyu) - return form is 2 or 3; - if (Legal.Totem_Alolan.Contains((ushort)species)) - return form == 2; - return form == 1; - } + if (generation != 7) + return false; + if (form == 0) + return false; + if (!Legal.Totem_USUM.Contains((ushort)species)) + return false; + if (species == (int)Mimikyu) + return form is 2 or 3; + if (Legal.Totem_Alolan.Contains((ushort)species)) + return form == 2; + return form == 1; + } - public static int GetTotemBaseForm(int species, int form) - { - if (species == (int)Mimikyu) - return form - 2; - return form - 1; - } + public static int GetTotemBaseForm(int species, int form) + { + if (species == (int)Mimikyu) + return form - 2; + return form - 1; + } - public static bool IsValidOutOfBoundsForme(int species, int form, int generation) + public static bool IsValidOutOfBoundsForme(int species, int form, int generation) + { + return (Species)species switch { - return (Species)species switch - { - Unown => form < (generation == 2 ? 26 : 28), // A-Z : A-Z?! - Mothim => form < 3, // Wormadam base form is kept - Scatterbug or Spewpa => form < 18, - _ => false - }; - } - - /// - /// Checks if the species should have a drop-down selection visible for the form value. - /// - /// Game specific personal info - /// ID - public static bool HasFormSelection(IPersonalFormInfo pi, int species) - { - if (HasFormeValuesNotIndicatedByPersonal.Contains(species)) - return true; - - int count = pi.FormCount; - return count > 1; - } - - private static readonly HashSet HasFormeValuesNotIndicatedByPersonal = new() - { - (int)Unown, - (int)Mothim, // Burmy forme carried over, not cleared - (int)Scatterbug, - (int)Spewpa, // Vivillon pre-evos + Unown => form < (generation == 2 ? 26 : 28), // A-Z : A-Z?! + Mothim => form < 3, // Wormadam base form is kept + Scatterbug or Spewpa => form < 18, + _ => false }; } + + /// + /// Checks if the species should have a drop-down selection visible for the form value. + /// + /// Game specific personal info + /// ID + public static bool HasFormSelection(IPersonalFormInfo pi, int species) + { + if (HasFormeValuesNotIndicatedByPersonal.Contains(species)) + return true; + + int count = pi.FormCount; + return count > 1; + } + + private static readonly HashSet HasFormeValuesNotIndicatedByPersonal = new() + { + (int)Unown, + (int)Mothim, // Burmy forme carried over, not cleared + (int)Scatterbug, + (int)Spewpa, // Vivillon pre-evos + }; } diff --git a/pkNX.Sprites/ImageUtil.cs b/pkNX.Sprites/ImageUtil.cs index fc9633ab..2a01f8c7 100644 --- a/pkNX.Sprites/ImageUtil.cs +++ b/pkNX.Sprites/ImageUtil.cs @@ -1,261 +1,260 @@ -using System; +using System; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using System.Runtime.InteropServices; -namespace pkNX.Sprites +namespace pkNX.Sprites; + +/// +/// Image Layering/Blending Utility +/// +public static class ImageUtil { - /// - /// Image Layering/Blending Utility - /// - public static class ImageUtil + public static Bitmap LayerImage(Image baseLayer, Image overLayer, int x, int y, double transparency) { - public static Bitmap LayerImage(Image baseLayer, Image overLayer, int x, int y, double transparency) + overLayer = ChangeOpacity(overLayer, transparency); + return LayerImage(baseLayer, overLayer, x, y); + } + + public static Bitmap LayerImage(Image baseLayer, Image overLayer, int x, int y) + { + Bitmap img = new(baseLayer); + using Graphics gr = Graphics.FromImage(img); + gr.DrawImage(overLayer, x, y, overLayer.Width, overLayer.Height); + return img; + } + + public static Bitmap ChangeOpacity(Image img, double trans) + { + if (img.PixelFormat.HasFlag(PixelFormat.Indexed)) + return (Bitmap)img; + + var bmp = (Bitmap)img.Clone(); + GetBitmapData(bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data); + + Marshal.Copy(ptr, data, 0, data.Length); + SetAllTransparencyTo(data, trans); + Marshal.Copy(data, 0, ptr, data.Length); + bmp.UnlockBits(bmpData); + + return bmp; + } + + public static Bitmap ChangeAllColorTo(Image img, Color c) + { + if (img.PixelFormat.HasFlag(PixelFormat.Indexed)) + return (Bitmap)img; + + var bmp = (Bitmap)img.Clone(); + GetBitmapData(bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data); + + Marshal.Copy(ptr, data, 0, data.Length); + ChangeAllColorTo(data, c); + Marshal.Copy(data, 0, ptr, data.Length); + bmp.UnlockBits(bmpData); + + return bmp; + } + + public static Bitmap ToGrayscale(Image img) + { + if (img.PixelFormat.HasFlag(PixelFormat.Indexed)) + return (Bitmap)img; + + var bmp = (Bitmap)img.Clone(); + GetBitmapData(bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data); + + Marshal.Copy(ptr, data, 0, data.Length); + SetAllColorToGrayScale(data); + Marshal.Copy(data, 0, ptr, data.Length); + bmp.UnlockBits(bmpData); + + return bmp; + } + + private static void GetBitmapData(Bitmap bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data) + { + bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); + ptr = bmpData.Scan0; + data = new byte[bmp.Width * bmp.Height * 4]; + } + + public static Bitmap GetBitmap(byte[] data, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb) + { + var bmp = new Bitmap(width, height, format); + var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, format); + var ptr = bmpData.Scan0; + Marshal.Copy(data, 0, ptr, data.Length); + bmp.UnlockBits(bmpData); + return bmp; + } + + public static byte[] GetPixelData(Bitmap bitmap) + { + var argbData = new byte[bitmap.Width * bitmap.Height * 4]; + var bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); + Marshal.Copy(bd.Scan0, argbData, 0, bitmap.Width * bitmap.Height * 4); + bitmap.UnlockBits(bd); + return argbData; + } + + public static void SetAllUsedPixelsOpaque(byte[] data) + { + for (int i = 0; i < data.Length; i += 4) { - overLayer = ChangeOpacity(overLayer, transparency); - return LayerImage(baseLayer, overLayer, x, y); + if (data[i + 3] != 0) + data[i + 3] = 0xFF; + } + } + + public static void RemovePixels(byte[] pixels, byte[] original) + { + for (int i = 0; i < original.Length; i += 4) + { + if (original[i + 3] == 0) + continue; + pixels[i + 0] = 0; + pixels[i + 1] = 0; + pixels[i + 2] = 0; + pixels[i + 3] = 0; + } + } + + private static void SetAllTransparencyTo(byte[] data, double trans) + { + for (int i = 0; i < data.Length; i += 4) + data[i + 3] = (byte)(data[i + 3] * trans); + } + + public static void ChangeAllColorTo(byte[] data, Color c) + { + byte R = c.R; + byte G = c.G; + byte B = c.B; + for (int i = 0; i < data.Length; i += 4) + { + if (data[i + 3] == 0) + continue; + data[i + 0] = B; + data[i + 1] = G; + data[i + 2] = R; + } + } + + private static void SetAllColorToGrayScale(byte[] data) + { + for (int i = 0; i < data.Length; i += 4) + { + if (data[i + 3] == 0) + continue; + byte greyS = (byte)(((0.3 * data[i + 2]) + (0.59 * data[i + 1]) + (0.11 * data[i + 0])) / 3); + data[i + 0] = greyS; + data[i + 1] = greyS; + data[i + 2] = greyS; + } + } + + public static void GlowEdges(byte[] data, byte blue, byte green, byte red, int width, int reach = 3, double amount = 0.0777) + { + PollutePixels(data, width, reach, amount); + CleanPollutedPixels(data, blue, green, red); + } + + private static void PollutePixels(byte[] data, int width, int reach, double amount) + { + int stride = width * 4; + int height = data.Length / stride; + for (int i = 0; i < data.Length; i += 4) + { + // only pollute outwards if the current pixel isn't transparent + if (data[i + 3] == 0) + continue; + + int x = (i % stride) / 4; + int y = (i / stride); + Pollute(x, y); } - public static Bitmap LayerImage(Image baseLayer, Image overLayer, int x, int y) + void Pollute(int x, int y) { - Bitmap img = new(baseLayer); - using Graphics gr = Graphics.FromImage(img); - gr.DrawImage(overLayer, x, y, overLayer.Width, overLayer.Height); - return img; - } - - public static Bitmap ChangeOpacity(Image img, double trans) - { - if (img.PixelFormat.HasFlag(PixelFormat.Indexed)) - return (Bitmap)img; - - var bmp = (Bitmap)img.Clone(); - GetBitmapData(bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data); - - Marshal.Copy(ptr, data, 0, data.Length); - SetAllTransparencyTo(data, trans); - Marshal.Copy(data, 0, ptr, data.Length); - bmp.UnlockBits(bmpData); - - return bmp; - } - - public static Bitmap ChangeAllColorTo(Image img, Color c) - { - if (img.PixelFormat.HasFlag(PixelFormat.Indexed)) - return (Bitmap)img; - - var bmp = (Bitmap)img.Clone(); - GetBitmapData(bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data); - - Marshal.Copy(ptr, data, 0, data.Length); - ChangeAllColorTo(data, c); - Marshal.Copy(data, 0, ptr, data.Length); - bmp.UnlockBits(bmpData); - - return bmp; - } - - public static Bitmap ToGrayscale(Image img) - { - if (img.PixelFormat.HasFlag(PixelFormat.Indexed)) - return (Bitmap)img; - - var bmp = (Bitmap)img.Clone(); - GetBitmapData(bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data); - - Marshal.Copy(ptr, data, 0, data.Length); - SetAllColorToGrayScale(data); - Marshal.Copy(data, 0, ptr, data.Length); - bmp.UnlockBits(bmpData); - - return bmp; - } - - private static void GetBitmapData(Bitmap bmp, out BitmapData bmpData, out IntPtr ptr, out byte[] data) - { - bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); - ptr = bmpData.Scan0; - data = new byte[bmp.Width * bmp.Height * 4]; - } - - public static Bitmap GetBitmap(byte[] data, int width, int height, PixelFormat format = PixelFormat.Format32bppArgb) - { - var bmp = new Bitmap(width, height, format); - var bmpData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, format); - var ptr = bmpData.Scan0; - Marshal.Copy(data, 0, ptr, data.Length); - bmp.UnlockBits(bmpData); - return bmp; - } - - public static byte[] GetPixelData(Bitmap bitmap) - { - var argbData = new byte[bitmap.Width * bitmap.Height * 4]; - var bd = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); - Marshal.Copy(bd.Scan0, argbData, 0, bitmap.Width * bitmap.Height * 4); - bitmap.UnlockBits(bd); - return argbData; - } - - public static void SetAllUsedPixelsOpaque(byte[] data) - { - for (int i = 0; i < data.Length; i += 4) + int left = Math.Max(0, x - reach); + int right = Math.Min(width - 1, x + reach); + int top = Math.Max(0, y - reach); + int bottom = Math.Min(height - 1, y + reach); + for (int i = left; i <= right; i++) { - if (data[i + 3] != 0) - data[i + 3] = 0xFF; - } - } - - public static void RemovePixels(byte[] pixels, byte[] original) - { - for (int i = 0; i < original.Length; i += 4) - { - if (original[i + 3] == 0) - continue; - pixels[i + 0] = 0; - pixels[i + 1] = 0; - pixels[i + 2] = 0; - pixels[i + 3] = 0; - } - } - - private static void SetAllTransparencyTo(byte[] data, double trans) - { - for (int i = 0; i < data.Length; i += 4) - data[i + 3] = (byte)(data[i + 3] * trans); - } - - public static void ChangeAllColorTo(byte[] data, Color c) - { - byte R = c.R; - byte G = c.G; - byte B = c.B; - for (int i = 0; i < data.Length; i += 4) - { - if (data[i + 3] == 0) - continue; - data[i + 0] = B; - data[i + 1] = G; - data[i + 2] = R; - } - } - - private static void SetAllColorToGrayScale(byte[] data) - { - for (int i = 0; i < data.Length; i += 4) - { - if (data[i + 3] == 0) - continue; - byte greyS = (byte)(((0.3 * data[i + 2]) + (0.59 * data[i + 1]) + (0.11 * data[i + 0])) / 3); - data[i + 0] = greyS; - data[i + 1] = greyS; - data[i + 2] = greyS; - } - } - - public static void GlowEdges(byte[] data, byte blue, byte green, byte red, int width, int reach = 3, double amount = 0.0777) - { - PollutePixels(data, width, reach, amount); - CleanPollutedPixels(data, blue, green, red); - } - - private static void PollutePixels(byte[] data, int width, int reach, double amount) - { - int stride = width * 4; - int height = data.Length / stride; - for (int i = 0; i < data.Length; i += 4) - { - // only pollute outwards if the current pixel isn't transparent - if (data[i + 3] == 0) - continue; - - int x = (i % stride) / 4; - int y = (i / stride); - Pollute(x, y); - } - - void Pollute(int x, int y) - { - int left = Math.Max(0, x - reach); - int right = Math.Min(width - 1, x + reach); - int top = Math.Max(0, y - reach); - int bottom = Math.Min(height - 1, y + reach); - for (int i = left; i <= right; i++) + for (int j = top; j <= bottom; j++) { - for (int j = top; j <= bottom; j++) - { - // update one of the color bits - // it is expected that a transparent pixel RGBA value is 0. - var c = 4 * (i + (j * width)); - data[c + 0] += (byte)(amount * (0xFF - data[c + 0])); - } + // update one of the color bits + // it is expected that a transparent pixel RGBA value is 0. + var c = 4 * (i + (j * width)); + data[c + 0] += (byte)(amount * (0xFF - data[c + 0])); } } } + } - private static void CleanPollutedPixels(byte[] data, byte blue, byte green, byte red) + private static void CleanPollutedPixels(byte[] data, byte blue, byte green, byte red) + { + for (int i = 0; i < data.Length; i += 4) { - for (int i = 0; i < data.Length; i += 4) - { - // only clean if the current pixel isn't transparent - if (data[i + 3] != 0) - continue; + // only clean if the current pixel isn't transparent + if (data[i + 3] != 0) + continue; - // grab the transparency from the donor byte - var transparency = data[i + 0]; - if (transparency == 0) - continue; + // grab the transparency from the donor byte + var transparency = data[i + 0]; + if (transparency == 0) + continue; - data[i + 0] = blue; - data[i + 1] = green; - data[i + 2] = red; - data[i + 3] = transparency; - } - } - - public static Color ColorBaseStat(int v) - { - const float maxval = 180; // shift the green cap down - float x = 100f * v / maxval; - if (x > 100) - x = 100; - double red = 255f * (x > 50 ? 1 - (2 * (x - 50) / 100.0) : 1.0); - double green = 255f * (x > 50 ? 1.0 : 2 * x / 100.0); - - return Blend(Color.FromArgb((int)red, (int)green, 0), Color.White, 0.4); - } - - public static Color Blend(Color color, Color backColor, double amount) - { - byte r = (byte)((color.R * amount) + (backColor.R * (1 - amount))); - byte g = (byte)((color.G * amount) + (backColor.G * (1 - amount))); - byte b = (byte)((color.B * amount) + (backColor.B * (1 - amount))); - return Color.FromArgb(r, g, b); - } - - // https://stackoverflow.com/a/24199315 - public static Bitmap ResizeImage(Image image, int width, int height) - { - var destRect = new Rectangle(0, 0, width, height); - var destImage = new Bitmap(width, height); - - destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); - - using var wrapMode = new ImageAttributes(); - wrapMode.SetWrapMode(WrapMode.TileFlipXY); - - using var graphics = Graphics.FromImage(destImage); - graphics.CompositingMode = CompositingMode.SourceCopy; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.SmoothingMode = SmoothingMode.HighQuality; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - - graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); - - return destImage; + data[i + 0] = blue; + data[i + 1] = green; + data[i + 2] = red; + data[i + 3] = transparency; } } + + public static Color ColorBaseStat(int v) + { + const float maxval = 180; // shift the green cap down + float x = 100f * v / maxval; + if (x > 100) + x = 100; + double red = 255f * (x > 50 ? 1 - (2 * (x - 50) / 100.0) : 1.0); + double green = 255f * (x > 50 ? 1.0 : 2 * x / 100.0); + + return Blend(Color.FromArgb((int)red, (int)green, 0), Color.White, 0.4); + } + + public static Color Blend(Color color, Color backColor, double amount) + { + byte r = (byte)((color.R * amount) + (backColor.R * (1 - amount))); + byte g = (byte)((color.G * amount) + (backColor.G * (1 - amount))); + byte b = (byte)((color.B * amount) + (backColor.B * (1 - amount))); + return Color.FromArgb(r, g, b); + } + + // https://stackoverflow.com/a/24199315 + public static Bitmap ResizeImage(Image image, int width, int height) + { + var destRect = new Rectangle(0, 0, width, height); + var destImage = new Bitmap(width, height); + + destImage.SetResolution(image.HorizontalResolution, image.VerticalResolution); + + using var wrapMode = new ImageAttributes(); + wrapMode.SetWrapMode(WrapMode.TileFlipXY); + + using var graphics = Graphics.FromImage(destImage); + graphics.CompositingMode = CompositingMode.SourceCopy; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.SmoothingMode = SmoothingMode.HighQuality; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + + graphics.DrawImage(image, destRect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel, wrapMode); + + return destImage; + } } diff --git a/pkNX.Sprites/SpriteBuilder.cs b/pkNX.Sprites/SpriteBuilder.cs index b0bfe017..66a42794 100644 --- a/pkNX.Sprites/SpriteBuilder.cs +++ b/pkNX.Sprites/SpriteBuilder.cs @@ -1,178 +1,177 @@ -using System.Drawing; +using System.Drawing; using pkNX.Structures; using pkNX.Sprites.Properties; -namespace pkNX.Sprites +namespace pkNX.Sprites; + +public abstract class SpriteBuilder { - public abstract class SpriteBuilder + public static bool ShowEggSpriteAsItem { get; set; } = true; + + public abstract int Width { get; } + public abstract int Height { get; } + + protected abstract int ItemShiftX { get; } + protected abstract int ItemShiftY { get; } + protected abstract int ItemMaxSize { get; } + protected abstract int EggItemShiftX { get; } + protected abstract int EggItemShiftY { get; } + + public abstract Bitmap Hover { get; } + public abstract Bitmap View { get; } + public abstract Bitmap Set { get; } + public abstract Bitmap Delete { get; } + public abstract Bitmap Transparent { get; } + public abstract Bitmap Drag { get; } + public abstract Bitmap UnknownItem { get; } + public abstract Bitmap None { get; } + public abstract Bitmap ItemTM { get; } + public abstract Bitmap ItemTR { get; } + + private const double UnknownFormTransparency = 0.5; + private const double ShinyTransparency = 0.7; + private const double EggUnderLayerTransparency = 0.33; + + protected abstract string GetSpriteStringSpeciesOnly(int species); + + protected abstract string GetSpriteAll(int species, int form, int gender, bool shiny, bool gmax, int generation); + protected abstract string GetItemResourceName(int item); + protected abstract Bitmap Unknown { get; } + protected abstract Bitmap GetEggSprite(int species); + + public Image GetSprite(int species, int form, int gender, int heldItem, bool isEgg, bool isShiny, bool isGigantamax, int generation = -1) { - public static bool ShowEggSpriteAsItem { get; set; } = true; + if (species == 0) + return None; - public abstract int Width { get; } - public abstract int Height { get; } - - protected abstract int ItemShiftX { get; } - protected abstract int ItemShiftY { get; } - protected abstract int ItemMaxSize { get; } - protected abstract int EggItemShiftX { get; } - protected abstract int EggItemShiftY { get; } - - public abstract Bitmap Hover { get; } - public abstract Bitmap View { get; } - public abstract Bitmap Set { get; } - public abstract Bitmap Delete { get; } - public abstract Bitmap Transparent { get; } - public abstract Bitmap Drag { get; } - public abstract Bitmap UnknownItem { get; } - public abstract Bitmap None { get; } - public abstract Bitmap ItemTM { get; } - public abstract Bitmap ItemTR { get; } - - private const double UnknownFormTransparency = 0.5; - private const double ShinyTransparency = 0.7; - private const double EggUnderLayerTransparency = 0.33; - - protected abstract string GetSpriteStringSpeciesOnly(int species); - - protected abstract string GetSpriteAll(int species, int form, int gender, bool shiny, bool gmax, int generation); - protected abstract string GetItemResourceName(int item); - protected abstract Bitmap Unknown { get; } - protected abstract Bitmap GetEggSprite(int species); - - public Image GetSprite(int species, int form, int gender, int heldItem, bool isEgg, bool isShiny, bool isGigantamax, int generation = -1) - { - if (species == 0) - return None; - - var baseImage = GetBaseImage(species, form, gender, isShiny, isGigantamax, generation); - return GetSprite(baseImage, species, heldItem, isEgg, isShiny, isGigantamax, generation); - } - - public Image GetSprite(Image baseSprite, int species, int heldItem, bool isEgg, bool isShiny, bool isGigantamax, int generation = -1, bool isBoxBGRed = false) - { - if (isEgg) - baseSprite = LayerOverImageEgg(baseSprite, species, heldItem != 0); - if (heldItem > 0) - baseSprite = LayerOverImageItem(baseSprite, heldItem, generation); - if (isShiny) - baseSprite = LayerOverImageShiny(baseSprite); - return baseSprite; - } - - private Image GetBaseImage(int species, int form, int gender, bool shiny, bool gmax, int generation) - { - var img = FormConverter.IsTotemForm(species, form) - ? GetBaseImageTotem(species, form, gender, shiny, gmax, generation) - : GetBaseImageDefault(species, form, gender, shiny, gmax, generation); - return img ?? GetBaseImageFallback(species, form, gender, shiny, gmax, generation); - } - - private Image? GetBaseImageTotem(int species, int form, int gender, bool shiny, bool gmax, int generation) - { - var baseform = FormConverter.GetTotemBaseForm(species, form); - var baseImage = GetBaseImageDefault(species, baseform, gender, shiny, gmax, generation); - if (baseImage == null) - return null; - return ImageUtil.ToGrayscale(baseImage); - } - - private Image? GetBaseImageDefault(int species, int form, int gender, bool shiny, bool gmax, int generation) - { - var file = GetSpriteAll(species, form, gender, shiny, gmax, generation); - return (Image?)Resources.ResourceManager.GetObject(file); - } - - private Image GetBaseImageFallback(int species, int form, int gender, bool shiny, bool gmax, int generation) - { - if (shiny) // try again without shiny - { - var img = GetBaseImageDefault(species, form, gender, false, gmax, generation); - if (img != null) - return img; - } - - // try again without form - var baseImage = (Image?)Resources.ResourceManager.GetObject(GetSpriteStringSpeciesOnly(species)); - if (baseImage == null) // failed again - return Unknown; - return ImageUtil.LayerImage(baseImage, Unknown, 0, 0, UnknownFormTransparency); - } - - private Image LayerOverImageItem(Image baseImage, int item, int generation) - { - Image itemimg = (Image?)Resources.ResourceManager.GetObject(GetItemResourceName(item)) ?? Resources.bitem_unk; - if (item is >= 328 and <= 419) // gen2/3/4 TM - itemimg = ItemTM; - else if (item is >= 1130 and <= 1229) // Gen8 TR - itemimg = ItemTR; - - // Redraw item in bottom right corner; since images are cropped, try to not have them at the edge - int x = ItemShiftX + ((ItemMaxSize - itemimg.Width) / 2); - if (x + itemimg.Width > baseImage.Width) - x = baseImage.Width - itemimg.Width; - int y = ItemShiftY + (ItemMaxSize - itemimg.Height); - return ImageUtil.LayerImage(baseImage, itemimg, x, y); - } - - private static Image LayerOverImageShiny(Image baseImage) - { - // Add shiny star to top left of image. - var rare = Resources.rare_icon; - return ImageUtil.LayerImage(baseImage, rare, 0, 0, ShinyTransparency); - } - - private Image LayerOverImageEgg(Image baseImage, int species, bool hasItem) - { - if (ShowEggSpriteAsItem && !hasItem) - return LayerOverImageEggAsItem(baseImage, species); - return LayerOverImageEggTransparentSpecies(baseImage, species); - } - - private Image LayerOverImageEggTransparentSpecies(Image baseImage, int species) - { - // Partially transparent species. - baseImage = ImageUtil.ChangeOpacity(baseImage, EggUnderLayerTransparency); - // Add the egg layer over-top with full opacity. - var egg = GetEggSprite(species); - return ImageUtil.LayerImage(baseImage, egg, 0, 0); - } - - private Image LayerOverImageEggAsItem(Image baseImage, int species) - { - var egg = GetEggSprite(species); - return ImageUtil.LayerImage(baseImage, egg, EggItemShiftX, EggItemShiftY); // similar to held item, since they can't have any - } + var baseImage = GetBaseImage(species, form, gender, isShiny, isGigantamax, generation); + return GetSprite(baseImage, species, heldItem, isEgg, isShiny, isGigantamax, generation); } - /// - /// 56 high, 68 wide sprite builder - /// - public class SpriteBuilder5668 : SpriteBuilder + public Image GetSprite(Image baseSprite, int species, int heldItem, bool isEgg, bool isShiny, bool isGigantamax, int generation = -1, bool isBoxBGRed = false) { - public override int Height => 56; - public override int Width => 68; + if (isEgg) + baseSprite = LayerOverImageEgg(baseSprite, species, heldItem != 0); + if (heldItem > 0) + baseSprite = LayerOverImageItem(baseSprite, heldItem, generation); + if (isShiny) + baseSprite = LayerOverImageShiny(baseSprite); + return baseSprite; + } - protected override int ItemShiftX => 52; - protected override int ItemShiftY => 24; - protected override int ItemMaxSize => 32; - protected override int EggItemShiftX => 9; - protected override int EggItemShiftY => 2; + private Image GetBaseImage(int species, int form, int gender, bool shiny, bool gmax, int generation) + { + var img = FormConverter.IsTotemForm(species, form) + ? GetBaseImageTotem(species, form, gender, shiny, gmax, generation) + : GetBaseImageDefault(species, form, gender, shiny, gmax, generation); + return img ?? GetBaseImageFallback(species, form, gender, shiny, gmax, generation); + } - protected override string GetSpriteStringSpeciesOnly(int species) => 'b' + $"_{species}"; - protected override string GetSpriteAll(int species, int form, int gender, bool shiny, bool gmax, int generation) => 'b' + SpriteName.GetResourceStringSprite(species, form, gender, generation, shiny, gmax); - protected override string GetItemResourceName(int item) => 'b' + $"item_{item}"; - protected override Bitmap Unknown => Resources.b_unknown; - protected override Bitmap GetEggSprite(int species) => species == (int)Species.Manaphy ? Resources.b_490_e : Resources.b_egg; + private Image? GetBaseImageTotem(int species, int form, int gender, bool shiny, bool gmax, int generation) + { + var baseform = FormConverter.GetTotemBaseForm(species, form); + var baseImage = GetBaseImageDefault(species, baseform, gender, shiny, gmax, generation); + if (baseImage == null) + return null; + return ImageUtil.ToGrayscale(baseImage); + } - public override Bitmap Hover => Resources.slotHover68; - public override Bitmap View => Resources.slotView68; - public override Bitmap Set => Resources.slotSet68; - public override Bitmap Delete => Resources.slotDel68; - public override Bitmap Transparent => Resources.slotTrans68; - public override Bitmap Drag => Resources.slotDrag68; - public override Bitmap UnknownItem => Resources.bitem_unk; - public override Bitmap None => Resources.b_0; - public override Bitmap ItemTM => Resources.bitem_tm; - public override Bitmap ItemTR => Resources.bitem_tr; + private Image? GetBaseImageDefault(int species, int form, int gender, bool shiny, bool gmax, int generation) + { + var file = GetSpriteAll(species, form, gender, shiny, gmax, generation); + return (Image?)Resources.ResourceManager.GetObject(file); + } + + private Image GetBaseImageFallback(int species, int form, int gender, bool shiny, bool gmax, int generation) + { + if (shiny) // try again without shiny + { + var img = GetBaseImageDefault(species, form, gender, false, gmax, generation); + if (img != null) + return img; + } + + // try again without form + var baseImage = (Image?)Resources.ResourceManager.GetObject(GetSpriteStringSpeciesOnly(species)); + if (baseImage == null) // failed again + return Unknown; + return ImageUtil.LayerImage(baseImage, Unknown, 0, 0, UnknownFormTransparency); + } + + private Image LayerOverImageItem(Image baseImage, int item, int generation) + { + Image itemimg = (Image?)Resources.ResourceManager.GetObject(GetItemResourceName(item)) ?? Resources.bitem_unk; + if (item is >= 328 and <= 419) // gen2/3/4 TM + itemimg = ItemTM; + else if (item is >= 1130 and <= 1229) // Gen8 TR + itemimg = ItemTR; + + // Redraw item in bottom right corner; since images are cropped, try to not have them at the edge + int x = ItemShiftX + ((ItemMaxSize - itemimg.Width) / 2); + if (x + itemimg.Width > baseImage.Width) + x = baseImage.Width - itemimg.Width; + int y = ItemShiftY + (ItemMaxSize - itemimg.Height); + return ImageUtil.LayerImage(baseImage, itemimg, x, y); + } + + private static Image LayerOverImageShiny(Image baseImage) + { + // Add shiny star to top left of image. + var rare = Resources.rare_icon; + return ImageUtil.LayerImage(baseImage, rare, 0, 0, ShinyTransparency); + } + + private Image LayerOverImageEgg(Image baseImage, int species, bool hasItem) + { + if (ShowEggSpriteAsItem && !hasItem) + return LayerOverImageEggAsItem(baseImage, species); + return LayerOverImageEggTransparentSpecies(baseImage, species); + } + + private Image LayerOverImageEggTransparentSpecies(Image baseImage, int species) + { + // Partially transparent species. + baseImage = ImageUtil.ChangeOpacity(baseImage, EggUnderLayerTransparency); + // Add the egg layer over-top with full opacity. + var egg = GetEggSprite(species); + return ImageUtil.LayerImage(baseImage, egg, 0, 0); + } + + private Image LayerOverImageEggAsItem(Image baseImage, int species) + { + var egg = GetEggSprite(species); + return ImageUtil.LayerImage(baseImage, egg, EggItemShiftX, EggItemShiftY); // similar to held item, since they can't have any } } + +/// +/// 56 high, 68 wide sprite builder +/// +public class SpriteBuilder5668 : SpriteBuilder +{ + public override int Height => 56; + public override int Width => 68; + + protected override int ItemShiftX => 52; + protected override int ItemShiftY => 24; + protected override int ItemMaxSize => 32; + protected override int EggItemShiftX => 9; + protected override int EggItemShiftY => 2; + + protected override string GetSpriteStringSpeciesOnly(int species) => 'b' + $"_{species}"; + protected override string GetSpriteAll(int species, int form, int gender, bool shiny, bool gmax, int generation) => 'b' + SpriteName.GetResourceStringSprite(species, form, gender, generation, shiny, gmax); + protected override string GetItemResourceName(int item) => 'b' + $"item_{item}"; + protected override Bitmap Unknown => Resources.b_unknown; + protected override Bitmap GetEggSprite(int species) => species == (int)Species.Manaphy ? Resources.b_490_e : Resources.b_egg; + + public override Bitmap Hover => Resources.slotHover68; + public override Bitmap View => Resources.slotView68; + public override Bitmap Set => Resources.slotSet68; + public override Bitmap Delete => Resources.slotDel68; + public override Bitmap Transparent => Resources.slotTrans68; + public override Bitmap Drag => Resources.slotDrag68; + public override Bitmap UnknownItem => Resources.bitem_unk; + public override Bitmap None => Resources.b_0; + public override Bitmap ItemTM => Resources.bitem_tm; + public override Bitmap ItemTR => Resources.bitem_tr; +} diff --git a/pkNX.Sprites/SpriteName.cs b/pkNX.Sprites/SpriteName.cs index d3f85d75..cab8d6fa 100644 --- a/pkNX.Sprites/SpriteName.cs +++ b/pkNX.Sprites/SpriteName.cs @@ -1,111 +1,110 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Text; using pkNX.Structures; -namespace pkNX.Sprites +namespace pkNX.Sprites; + +public static class SpriteName { - public static class SpriteName + public static bool AllowShinySprite { get; set; } = true; + public static bool AllowGigantamaxSprite { get; set; } = true; + + private const char Separator = '_'; + private const char Cosplay = 'c'; + private const char Shiny = 's'; + private const string Gigantamax = "gmax"; + private const char GGStarter = 'p'; + + public static string GetResourceStringBall(int ball) => $"_ball{ball}"; + + /// + /// Gets the resource name of the Pokémon sprite. + /// + public static string GetResourceStringSprite(int species, int form, int gender, int generation = 8, bool shiny = false, bool gmax = false) { - public static bool AllowShinySprite { get; set; } = true; - public static bool AllowGigantamaxSprite { get; set; } = true; + if (SpeciesDefaultFormSprite.Contains(species) && !gmax) // Species who show their default sprite regardless of Form + form = 0; - private const char Separator = '_'; - private const char Cosplay = 'c'; - private const char Shiny = 's'; - private const string Gigantamax = "gmax"; - private const char GGStarter = 'p'; + if (gmax && species is (int)Species.Toxtricity or (int)Species.Alcremie) // same sprites for all altform gmaxes + form = 0; - public static string GetResourceStringBall(int ball) => $"_ball{ball}"; - - /// - /// Gets the resource name of the Pokémon sprite. - /// - public static string GetResourceStringSprite(int species, int form, int gender, int generation = 8, bool shiny = false, bool gmax = false) + switch (form) { - if (SpeciesDefaultFormSprite.Contains(species) && !gmax) // Species who show their default sprite regardless of Form + case 30 when species is >= (int)Species.Scatterbug and <= (int)Species.Vivillon: // save file specific form = 0; - - if (gmax && species is (int)Species.Toxtricity or (int)Species.Alcremie) // same sprites for all altform gmaxes + break; + case 31 when species is (int)Species.Unown or (int)Species.Deerling or (int)Species.Sawsbuck: // Random form = 0; - - switch (form) - { - case 30 when species is >= (int)Species.Scatterbug and <= (int)Species.Vivillon: // save file specific - form = 0; - break; - case 31 when species is (int)Species.Unown or (int)Species.Deerling or (int)Species.Sawsbuck: // Random - form = 0; - break; - } - - var sb = new StringBuilder(); - sb.Append(Separator).Append(species); - - if (form != 0) - { - sb.Append(Separator) - .Append(form); - - if (species == (int)Species.Pikachu) - { - if (generation == 6) - { - sb.Append(Cosplay); - gender = 2; // Cosplay Pikachu gift can only be Female, but personal entries are set to be either Gender - } - else if (form == 8) - { - sb.Append(GGStarter); - } - } - else if (species == (int)Species.Eevee) - { - if (form == 1) - sb.Append(GGStarter); - } - } - if (gender == 2 && SpeciesGenderedSprite.Contains(species) && !gmax) - { - sb.Append('f'); - } - - if (gmax && AllowGigantamaxSprite) - { - sb.Append(Separator); - sb.Append(Gigantamax); - } - if (shiny && AllowShinySprite) - sb.Append(Shiny); - return sb.ToString(); + break; } - /// - /// Species that show their default Species sprite regardless of current form - /// - public static readonly HashSet SpeciesDefaultFormSprite = new() - { - (int)Species.Mothim, - (int)Species.Scatterbug, - (int)Species.Spewpa, - (int)Species.Rockruff, - (int)Species.Mimikyu, - (int)Species.Sinistea, - (int)Species.Polteageist, - (int)Species.Urshifu, - }; + var sb = new StringBuilder(); + sb.Append(Separator).Append(species); - /// - /// Species that show a Gender specific Sprite - /// - public static readonly HashSet SpeciesGenderedSprite = new() + if (form != 0) { - (int)Species.Pikachu, - (int)Species.Hippopotas, - (int)Species.Hippowdon, - (int)Species.Unfezant, - (int)Species.Frillish, - (int)Species.Jellicent, - (int)Species.Pyroar, - }; + sb.Append(Separator) + .Append(form); + + if (species == (int)Species.Pikachu) + { + if (generation == 6) + { + sb.Append(Cosplay); + gender = 2; // Cosplay Pikachu gift can only be Female, but personal entries are set to be either Gender + } + else if (form == 8) + { + sb.Append(GGStarter); + } + } + else if (species == (int)Species.Eevee) + { + if (form == 1) + sb.Append(GGStarter); + } + } + if (gender == 2 && SpeciesGenderedSprite.Contains(species) && !gmax) + { + sb.Append('f'); + } + + if (gmax && AllowGigantamaxSprite) + { + sb.Append(Separator); + sb.Append(Gigantamax); + } + if (shiny && AllowShinySprite) + sb.Append(Shiny); + return sb.ToString(); } + + /// + /// Species that show their default Species sprite regardless of current form + /// + public static readonly HashSet SpeciesDefaultFormSprite = new() + { + (int)Species.Mothim, + (int)Species.Scatterbug, + (int)Species.Spewpa, + (int)Species.Rockruff, + (int)Species.Mimikyu, + (int)Species.Sinistea, + (int)Species.Polteageist, + (int)Species.Urshifu, + }; + + /// + /// Species that show a Gender specific Sprite + /// + public static readonly HashSet SpeciesGenderedSprite = new() + { + (int)Species.Pikachu, + (int)Species.Hippopotas, + (int)Species.Hippowdon, + (int)Species.Unfezant, + (int)Species.Frillish, + (int)Species.Jellicent, + (int)Species.Pyroar, + }; } diff --git a/pkNX.Sprites/SpriteUtil.cs b/pkNX.Sprites/SpriteUtil.cs index 2ccf04a0..ebf75250 100644 --- a/pkNX.Sprites/SpriteUtil.cs +++ b/pkNX.Sprites/SpriteUtil.cs @@ -1,24 +1,23 @@ -using System.Drawing; +using System.Drawing; using pkNX.Sprites.Properties; -namespace pkNX.Sprites +namespace pkNX.Sprites; + +public static class SpriteUtil { - public static class SpriteUtil + public static readonly SpriteBuilder5668 SB8 = new(); + public static SpriteBuilder Spriter { get; set; } = SB8; + + public static Image GetBallSprite(int ball) { - public static readonly SpriteBuilder5668 SB8 = new(); - public static SpriteBuilder Spriter { get; set; } = SB8; - - public static Image GetBallSprite(int ball) - { - string resource = SpriteName.GetResourceStringBall(ball); - return (Bitmap?)Resources.ResourceManager.GetObject(resource) ?? Resources._ball4; // Poké Ball (default) - } - - public static Image GetSprite(int species, int form, int gender, int item, bool isegg, bool shiny, bool gmax, int generation = -1) - { - return Spriter.GetSprite(species, form, gender, item, isegg, shiny, gmax, generation); - } - - public static void Initialize() => Spriter = SB8; + string resource = SpriteName.GetResourceStringBall(ball); + return (Bitmap?)Resources.ResourceManager.GetObject(resource) ?? Resources._ball4; // Poké Ball (default) } + + public static Image GetSprite(int species, int form, int gender, int item, bool isegg, bool shiny, bool gmax, int generation = -1) + { + return Spriter.GetSprite(species, form, gender, item, isegg, shiny, gmax, generation); + } + + public static void Initialize() => Spriter = SB8; } diff --git a/pkNX.Sprites/pkNX.Sprites.csproj b/pkNX.Sprites/pkNX.Sprites.csproj index ac3f9fec..b16e07bd 100644 --- a/pkNX.Sprites/pkNX.Sprites.csproj +++ b/pkNX.Sprites/pkNX.Sprites.csproj @@ -1,7 +1,8 @@ - net6.0;net461 + net6.0 + en 10 enable true @@ -12,8 +13,10 @@ - - + + + + True @@ -29,8 +32,4 @@ - - - - diff --git a/pkNX.Structures.FlatBuffers/Arceus/ArchiveContents8a.cs b/pkNX.Structures.FlatBuffers/Arceus/ArchiveContents8a.cs index 50719e2f..30c11be0 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/ArchiveContents8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/ArchiveContents8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8a.cs index 09d1a9d3..b69b3b18 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; // ReSharper disable UnusedMember.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8aUtil.cs b/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8aUtil.cs index bdc9d1fa..c6511712 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8aUtil.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Condition/Condition8aUtil.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Condition/ConditionType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Condition/ConditionType8a.cs index eda19016..42c57fe1 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Condition/ConditionType8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Condition/ConditionType8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; // ReSharper disable UnusedMember.Global #pragma warning disable RCS1154 // Sort enum members. diff --git a/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigEntry8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigEntry8a.cs index 8a385b48..21d4694a 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigEntry8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigEntry8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigList8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigList8a.cs index 8318bcd2..603f9363 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigList8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Config/AppConfigList8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Config/Configure8aEntry.cs b/pkNX.Structures.FlatBuffers/Arceus/Config/Configure8aEntry.cs index e6bbfe91..316c97a6 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Config/Configure8aEntry.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Config/Configure8aEntry.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs index a80f8e39..4e07579a 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Event/Trigger8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerCommandType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerCommandType8a.cs index 9cae608d..66bc849e 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerCommandType8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerCommandType8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; // ReSharper disable UnusedMember.Global #pragma warning disable RCS1154 // Sort enum members. diff --git a/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerType8a.cs index 912f1e9b..e14057a5 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerType8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Event/TriggerType8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; // ReSharper disable UnusedMember.Global #pragma warning disable RCS1154 // Sort enum members. diff --git a/pkNX.Structures.FlatBuffers/Arceus/EvolutionTable8.cs b/pkNX.Structures.FlatBuffers/Arceus/EvolutionTable8.cs index 4a63a6fa..02596687 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/EvolutionTable8.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/EvolutionTable8.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.IO; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/ISlotTableConsumer.cs b/pkNX.Structures.FlatBuffers/Arceus/ISlotTableConsumer.cs index a337086d..fd74765f 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/ISlotTableConsumer.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/ISlotTableConsumer.cs @@ -1,4 +1,4 @@ -namespace pkNX.Structures.FlatBuffers; +namespace pkNX.Structures.FlatBuffers; public interface ISlotTableConsumer { diff --git a/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalInfoLA.cs b/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalInfoLA.cs index 8e678b0c..871a7ca2 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalInfoLA.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalInfoLA.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections; namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalTable8LA.cs b/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalTable8LA.cs index d207327e..5c76234b 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalTable8LA.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Integration/PersonalTable8LA.cs @@ -1,5 +1,4 @@ using pkNX.Containers; -using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; diff --git a/pkNX.Structures.FlatBuffers/Arceus/KeyAssignmentTable.cs b/pkNX.Structures.FlatBuffers/Arceus/KeyAssignmentTable.cs index b1966d1e..c4a56f1e 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/KeyAssignmentTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/KeyAssignmentTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemSpawnTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemSpawnTable8a.cs index 44f5005d..1327ce61 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemSpawnTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemSpawnTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemTable8a.cs index f7636910..6c197bfd 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/LandmarkItemTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; diff --git a/pkNX.Structures.FlatBuffers/Arceus/LbPointsTable.cs b/pkNX.Structures.FlatBuffers/Arceus/LbPointsTable.cs index c4a5499c..bb8179ec 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/LbPointsTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/LbPointsTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Learnset8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Learnset8a.cs index 02efac59..a4987a64 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Learnset8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Learnset8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.IO; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/MassOutbreakTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/MassOutbreakTable8a.cs index af1bdf1f..f701f1c2 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/MassOutbreakTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/MassOutbreakTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/MoveShopTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/MoveShopTable8a.cs index 4c21ed75..f22ed2b8 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/MoveShopTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/MoveShopTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroup8a.cs b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroup8a.cs index c0325c39..eef3f9bf 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroup8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroup8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroupLottery8a.cs b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroupLottery8a.cs index 3cee11f6..ca9da920 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroupLottery8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakGroupLottery8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakLottery8a.cs b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakLottery8a.cs index 5807d19a..f0244057 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakLottery8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakLottery8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakTimeLimit8a.cs b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakTimeLimit8a.cs index 885b32ba..caacbc56 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakTimeLimit8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/NewHuge/NewHugeOutbreakTimeLimit8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/PersonalInfoLAfb.cs b/pkNX.Structures.FlatBuffers/Arceus/PersonalInfoLAfb.cs index 9f93b2c3..46cbb68a 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/PersonalInfoLAfb.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/PersonalInfoLAfb.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; +using System; using System.ComponentModel; using FlatSharp.Attributes; -using System.Linq; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/OybnSettingTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/OybnSettingTable8a.cs index 0e2e29b4..9faa66de 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/OybnSettingTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/OybnSettingTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementItemArchive8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementItemArchive8a.cs index 86ff2996..f3dcf862 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementItemArchive8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementItemArchive8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocation8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocation8a.cs index 56ed556b..31ce68c2 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocation8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocation8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Numerics; @@ -198,7 +198,7 @@ public string LocationTypeIdSummary { if (!Enum.IsDefined(typeof(LocationType8a), LocationTypeID)) throw new ArgumentOutOfRangeException(nameof(LocationTypeID), LocationTypeID, $"Unknown 0x{LocationTypeID:X16}."); - return Enum.GetName(typeof(LocationType8a), LocationTypeID); + return ((LocationType8a)LocationTypeID).ToString(); } } @@ -206,19 +206,15 @@ public string LocationTypeIdSummary private static IReadOnlyDictionary? _locationArgMap; private static IReadOnlyDictionary GetLocationArgMap() => _locationArgMap ??= GenerateLocationArgMap(); - private static IReadOnlyDictionary GenerateLocationArgMap() + private static IReadOnlyDictionary GenerateLocationArgMap() => new Dictionary { - var result = new Dictionary(); - result[0xCBF29CE484222645] = ""; - + [0xCBF29CE484222645] = "", // PlaceName - result[FnvHash.HashFnv1a_64("NoneReport")] = "NoneReport"; - + [FnvHash.HashFnv1a_64("NoneReport")] = "NoneReport", // Bgm - result[FnvHash.HashFnv1a_64("LOW")] = "LOW"; - result[FnvHash.HashFnv1a_64("HIGH")] = "HIGH"; - return result; - } + [FnvHash.HashFnv1a_64("LOW")] = "LOW", + [FnvHash.HashFnv1a_64("HIGH")] = "HIGH", + }; public string LocationArg2Summary => GetLocationArgMap().TryGetValue(LocationTypeArg2, out var arg) ? $"\"{arg}\"" : $"0x{LocationTypeArg2:X16}"; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocationArchive8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocationArchive8a.cs index 0444858b..ae5d3d25 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocationArchive8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementLocationArchive8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementMkrgTable.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementMkrgTable.cs index d0451a97..2d2214e8 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementMkrgTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementMkrgTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementParameters8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementParameters8a.cs index dee0330c..1099e2a7 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementParameters8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementParameters8a.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSearchItemTable.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSearchItemTable.cs index 86a1f9cf..543dcec1 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSearchItemTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSearchItemTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawner8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawner8a.cs index 7804add3..81eb20f0 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawner8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawner8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerData8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerData8a.cs index 0e6f526a..1b6a4ec0 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerData8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerData8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF208a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF208a.cs index e7f5e18d..2ea1ca15 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF208a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF208a.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF218a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF218a.cs index 0580d132..ff799dd7 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF218a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementSpawnerF218a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementUnnnTable.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementUnnnTable.cs index 3043421a..19360f5f 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementUnnnTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementUnnnTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementV3f8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementV3f8a.cs index c77d8cc6..d6c142ed 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementV3f8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Placement/PlacementV3f8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; @@ -14,9 +14,9 @@ namespace pkNX.Structures.FlatBuffers; [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class PlacementV3f8a : IEquatable { - [FlatBufferItem(0)] public float X { get; set; } = 0; - [FlatBufferItem(1)] public float Y { get; set; } = 0; - [FlatBufferItem(2)] public float Z { get; set; } = 0; + [FlatBufferItem(0)] public float X { get; set; } + [FlatBufferItem(1)] public float Y { get; set; } + [FlatBufferItem(2)] public float Z { get; set; } public PlacementV3f8a() { @@ -39,11 +39,11 @@ public PlacementV3f8a(float x = 0, float y = 0, float z = 0) public float MagnitudeSqr => Dot(this); public PlacementV3f8a Normalized => this * (1 / Magnitude); - public float Dot(PlacementV3f8a other) => X * other.X + Y * other.Y + Z * other.Z; - public PlacementV3f8a Cross(PlacementV3f8a other) => new(Y * other.Z - Z * other.Y, Z * other.X - X * other.Z, X * other.Y - Y * other.X); + public float Dot(PlacementV3f8a other) => (X * other.X) + (Y * other.Y) + (Z * other.Z); + public PlacementV3f8a Cross(PlacementV3f8a other) => new((Y * other.Z) - (Z * other.Y), (Z * other.X) - (X * other.Z), (X * other.Y) - (Y * other.X)); public float DistanceTo(PlacementV3f8a other) => (this - other).Magnitude; public float DistanceToSqr(PlacementV3f8a other) => (this - other).MagnitudeSqr; - public PlacementV3f8a Lerp(PlacementV3f8a other, float t) => this + (other - this) * t; + public PlacementV3f8a Lerp(PlacementV3f8a other, float t) => this + ((other - this) * t); public PlacementV3f8a Clone() => new() { @@ -70,16 +70,7 @@ public override bool Equals(object? obj) return Equals((PlacementV3f8a)obj); } - public override int GetHashCode() - { - unchecked - { - var hashCode = X.GetHashCode(); - hashCode = (hashCode * 397) ^ Y.GetHashCode(); - hashCode = (hashCode * 397) ^ Z.GetHashCode(); - return hashCode; - } - } + public override int GetHashCode() => HashCode.Combine(X, Y, Z); public static PlacementV3f8a operator -(PlacementV3f8a v) => new(-v.X, -v.Y, -v.Z); @@ -95,4 +86,4 @@ public override int GetHashCode() public static bool operator ==(PlacementV3f8a? left, PlacementV3f8a? right) => Equals(left, right); public static bool operator !=(PlacementV3f8a? left, PlacementV3f8a? right) => !Equals(left, right); -} \ No newline at end of file +} diff --git a/pkNX.Structures.FlatBuffers/Arceus/PlayReportTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/PlayReportTable8a.cs index 3a3e7bb5..132394e9 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/PlayReportTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/PlayReportTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAIArchive8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAIArchive8a.cs index 28f7ed2c..26d31183 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAIArchive8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAIArchive8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAdd8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAdd8a.cs index 6df0ea1f..d97bf45c 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAdd8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeAdd8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemArchive8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemArchive8a.cs index 83fc7f28..c2e25ef9 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemArchive8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemArchive8a.cs @@ -1,8 +1,5 @@ -using System; -using System.Collections.Generic; +using System; using System.ComponentModel; -using System.Globalization; -using System.Linq; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -32,4 +29,4 @@ public class PokeDropItem8a [FlatBufferItem(04)] public int RareItemProbability { get; set; } public string Dump(string[] itemNames) => $"{Hash:X16}\t{itemNames[RegularItem]}\t{RegularItemProbability}\t{itemNames[RareItem]}\t{RareItemProbability}"; -} \ No newline at end of file +} diff --git a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemBattleArchive8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemBattleArchive8a.cs index 46afb1b0..ed9b9477 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemBattleArchive8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeDropItemBattleArchive8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeMiscTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeMiscTable8a.cs index eb2fa306..38e5adc3 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeMiscTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Poke/PokeMiscTable8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; using System; using System.ComponentModel; @@ -37,9 +37,9 @@ public class PokeMisc8a [FlatBufferItem(06)] public int OybnLevelIndex { get; set; } [FlatBufferItem(07)][TypeConverter(typeof(DropTableConverter))] public ulong DropTableRef { get; set; } - public PokeDropItem8a? DropTable { get; set; } = null; + public PokeDropItem8a? DropTable { get; set; } [FlatBufferItem(08)][TypeConverter(typeof(DropTableConverter))] public ulong AlphaDropTableRef { get; set; } - public PokeDropItem8a? AlphaDropTable { get; set; } = null; + public PokeDropItem8a? AlphaDropTable { get; set; } [FlatBufferItem(09)] public string Value { get; set; } = string.Empty; [FlatBufferItem(10)] public int[] Field_10 { get; set; } = Array.Empty(); diff --git a/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeInfoList.cs b/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeInfoList.cs index df3dae7c..b819f61c 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeInfoList.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeInfoList.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; diff --git a/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeResourceTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeResourceTable8a.cs index 5c7c6875..e4ed328e 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeResourceTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/PokeResource/PokeResourceTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/PokedexDistributionTable.cs b/pkNX.Structures.FlatBuffers/Arceus/PokedexDistributionTable.cs index 9e6b51a5..7eaf2ccf 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/PokedexDistributionTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/PokedexDistributionTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/PokedexRankTable.cs b/pkNX.Structures.FlatBuffers/Arceus/PokedexRankTable.cs index a724f465..2c6d77df 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/PokedexRankTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/PokedexRankTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/PokedexResearchTable.cs b/pkNX.Structures.FlatBuffers/Arceus/PokedexResearchTable.cs index 95d295d8..833d1794 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/PokedexResearchTable.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/PokedexResearchTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using FlatSharp.Attributes; @@ -78,4 +78,4 @@ public enum ResearchTaskType Unknown_8, Unknown_9, Unknown_10, -} \ No newline at end of file +} diff --git a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaBGMTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaBGMTable8a.cs index fa6bddac..b79338cf 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaBGMTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaBGMTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaInstance8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaInstance8a.cs index b67aecef..aa8d14ee 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaInstance8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaInstance8a.cs @@ -1,4 +1,4 @@ -using pkNX.Containers; +using pkNX.Containers; using System.Collections.Generic; namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaSettingsTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaSettingsTable8a.cs index 7e123736..d4e5e3d4 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaSettingsTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaSettingsTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaWeatherTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaWeatherTable8a.cs index 5989b8ca..f749e8f9 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaWeatherTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Resident/AreaWeatherTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentArea8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentArea8a.cs index 4c2943f1..84289243 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentArea8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentArea8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using pkNX.Containers; namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentInfo.cs b/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentInfo.cs index b7c07a77..37828afd 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentInfo.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Resident/Editing/ResidentInfo.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/ScriptIDRecordRelease.cs b/pkNX.Structures.FlatBuffers/Arceus/ScriptIDRecordRelease.cs index 012e894d..612d8e16 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/ScriptIDRecordRelease.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/ScriptIDRecordRelease.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Shop/HaShopTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Shop/HaShopTable8a.cs index 3a4b2e79..affaa854 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Shop/HaShopTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Shop/HaShopTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterData8Archive.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterData8Archive.cs index 9b96e9d5..e0ad5adc 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterData8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterData8Archive.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterEligiblityTraits8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterEligiblityTraits8a.cs index bb0e46c6..29180aae 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterEligiblityTraits8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterEligiblityTraits8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplerArchive8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplerArchive8a.cs index 055acc7e..b7697eb1 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplerArchive8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplerArchive8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplier8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplier8a.cs index 713e2b21..698f2205 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplier8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterMultiplier8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterOybnTraits8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterOybnTraits8a.cs index 8e0b9ed7..e46b8e15 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterOybnTraits8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterOybnTraits8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterSlot8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterSlot8a.cs index 6a0845fa..aacf27ae 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterSlot8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterSlot8a.cs @@ -1,7 +1,6 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; -using System.Net; using FlatSharp.Attributes; using pkNX.Containers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterTable8a.cs index eb1c2fbd..f1c6ce67 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/EncounterTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierTime.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierTime.cs index 5b8d25a8..c20d7384 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierTime.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierTime.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierWeather.cs b/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierWeather.cs index a7a96c24..d8ac6b8b 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierWeather.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Slots/ISlotModifierWeather.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace pkNX.Structures.FlatBuffers; @@ -31,4 +31,4 @@ public static class SlotModifierWeatherExtensions }; public static bool HasWeatherModifier(this ISlotModifierWeather w, int index) => index != 0 && w.GetWeatherMultiplier(index) != -1.0f; -} \ No newline at end of file +} diff --git a/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8a.cs index 0517b304..4ac9aaa7 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8aArchive.cs b/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8aArchive.cs index 2454cb87..7e9b05f4 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8aArchive.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncount8aArchive.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncountPoke8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncountPoke8a.cs index f56c5c19..f68b31a7 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncountPoke8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Static/EventEncountPoke8a.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Throw/CommonCaptureConfigTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Throw/CommonCaptureConfigTable8a.cs index 2dfb9b47..47ce69fd 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Throw/CommonCaptureConfigTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Throw/CommonCaptureConfigTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowParamTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowParamTable8a.cs index 09ab2839..f9bc6a6f 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowParamTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowParamTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowPermissionSetDictionary8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowPermissionSetDictionary8a.cs index 9d13c39d..47b82910 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowPermissionSetDictionary8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowPermissionSetDictionary8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableParamTable8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableParamTable8a.cs index 1174899c..4f4fc55e 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableParamTable8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableParamTable8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceDictionary8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceDictionary8a.cs index f4f8dd13..92b77dff 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceDictionary8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceDictionary8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceSetDictionary8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceSetDictionary8a.cs index e1530b7f..4fbf3b88 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceSetDictionary8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Throw/ThrowableResourceSetDictionary8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/TrData8a.cs b/pkNX.Structures.FlatBuffers/Arceus/TrData8a.cs index f4bf2a74..68831536 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/TrData8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/TrData8a.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using System.Linq; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/AbilityType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/AbilityType8a.cs index d651f921..993363f2 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/AbilityType8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/AbilityType8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; // ReSharper disable UnusedMember.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterDetail8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterDetail8a.cs index 580a1d6d..62e96d8d 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterDetail8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterDetail8a.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; namespace pkNX.Structures.FlatBuffers; @@ -75,4 +75,4 @@ private static bool IsSameEffectiveTable(IReadOnlyList lhs, I } } -public record struct TableSymmetryResult(bool Weather, bool Time, bool[] Complexed); \ No newline at end of file +public record struct TableSymmetryResult(bool Weather, bool Time, bool[] Complexed); diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterTable8aUtil.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterTable8aUtil.cs index 1cc19445..d6ae336d 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterTable8aUtil.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/EncounterTable8aUtil.cs @@ -1,479 +1,478 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +public static class EncounterTable8aUtil { - public static class EncounterTable8aUtil + private const float SpawnerBias = 73; // lured unown and jet + run + private const float WormholeBias = 15; + private const float LandmarkBias = 15; + + public static IEnumerable GetEncounterDump(AreaInstance8a area, + IReadOnlyDictionary map, PokeMiscTable8a misc, + NewHugeOutbreakGroupArchive8a nhoGroup, + NewHugeOutbreakGroupLotteryArchive8a nhoLottery) { - private const float SpawnerBias = 73; // lured unown and jet + run - private const float WormholeBias = 15; - private const float LandmarkBias = 15; + if (area.Locations.Length == 0) + yield break; - public static IEnumerable GetEncounterDump(AreaInstance8a area, - IReadOnlyDictionary map, PokeMiscTable8a misc, - NewHugeOutbreakGroupArchive8a nhoGroup, - NewHugeOutbreakGroupLotteryArchive8a nhoLottery) + foreach (var table in area.Encounters) { - if (area.Locations.Length == 0) - yield break; + var slots = table.Table.Where(z => z.ShinyLock is ShinyType8a.Random).ToList(); + if (slots.Count == 0) + continue; - foreach (var table in area.Encounters) + foreach (var p in GetAreas(area, slots, table, map, misc, nhoGroup, nhoLottery)) + yield return p; + foreach (var x in area.SubAreas) { - var slots = table.Table.Where(z => z.ShinyLock is ShinyType8a.Random).ToList(); - if (slots.Count == 0) - continue; - - foreach (var p in GetAreas(area, slots, table, map, misc, nhoGroup, nhoLottery)) + foreach (var p in GetAreas(x, slots, table, map, misc, nhoGroup, nhoLottery)) yield return p; - foreach (var x in area.SubAreas) - { - foreach (var p in GetAreas(x, slots, table, map, misc, nhoGroup, nhoLottery)) - yield return p; - } } } + } - private static IEnumerable GetAreas(AreaInstance8a area, IReadOnlyCollection slots, EncounterTable8a table, - IReadOnlyDictionary map, PokeMiscTable8a misc, - NewHugeOutbreakGroupArchive8a nhoGroup, - NewHugeOutbreakGroupLotteryArchive8a nhoLottery) + private static IEnumerable GetAreas(AreaInstance8a area, IReadOnlyCollection slots, EncounterTable8a table, + IReadOnlyDictionary map, PokeMiscTable8a misc, + NewHugeOutbreakGroupArchive8a nhoGroup, + NewHugeOutbreakGroupLotteryArchive8a nhoLottery) + { + if (area.Locations.Length == 0) + yield break; + + int baseArea = map[area.Locations.First(z => z.IsNamedPlace).PlaceName].Index; + // Spawners { - if (area.Locations.Length == 0) - yield break; - - int baseArea = map[area.Locations.First(z => z.IsNamedPlace).PlaceName].Index; - // Spawners + var s = area.Spawners; + var spawners = s.Where(z => z.UsesTable(table.TableID)); + var groups = spawners.GroupBy(GetSpawnerType); + foreach (var g in groups) { - var s = area.Spawners; - var spawners = s.Where(z => z.UsesTable(table.TableID)); - var groups = spawners.GroupBy(GetSpawnerType); - foreach (var g in groups) - { - if (g.Key is not (SpawnerType.Spawner or SpawnerType.SpawnerMass)) - throw new Exception(); - var sl = g.SelectMany(z => z.GetIntersectingLocations(area.Locations, SpawnerBias)); - foreach (var a in GetAll(sl, g.Key)) - yield return a; - } - } - { - var s = area.Spawners; - var spawners = s.Where(z => nhoLottery.IsAreaGroup(z, nhoGroup, table.TableID)); - var groups = spawners.GroupBy(GetSpawnerType); - foreach (var g in groups) - { - if (g.Key is not SpawnerType.SpawnerMMO) - throw new Exception(); - var sl = g.SelectMany(z => z.GetIntersectingLocations(area.Locations, SpawnerBias)); - foreach (var a in GetAll(sl, g.Key)) - yield return a; - } - } - - // Wormholes - { - var s = area.Wormholes; - var spawners = s.Where(z => z.UsesTable(table.TableID)); - - // Since Wormholes can have different bonus level ranges, we defer uniqueness testing to the outer method. Just yield all spawners. - foreach (var w in spawners) - { - var bmin = w.Field_20_Value.BonusLevelMin; - var bmax = w.Field_20_Value.BonusLevelMax; - - var sl = w.GetIntersectingLocations(area.Locations, WormholeBias); - foreach (var a in GetAll(sl, SpawnerType.Wormhole, bmin, bmax)) - yield return a; - } - } - - // Landmarks - { - var items = area.LandItems; - var lis = items.Where(z => z.UsesTable(table.TableID)).ToList(); - - var marks = area.LandMarks; - var li = marks.Where(z => lis.Any(sz => z.UsesTable(sz.LandmarkItemSpawnTableID))); - var sl = li.SelectMany(z => z.GetIntersectingLocations(area.Locations, LandmarkBias)); - foreach (var a in GetAll(sl, SpawnerType.Landmark)) + if (g.Key is not (SpawnerType.Spawner or SpawnerType.SpawnerMass)) + throw new Exception(); + var sl = g.SelectMany(z => z.GetIntersectingLocations(area.Locations, SpawnerBias)); + foreach (var a in GetAll(sl, g.Key)) yield return a; } - - IEnumerable GetAll(IEnumerable places, SpawnerType type, int bmin = 0, int bmax = 0) + } + { + var s = area.Spawners; + var spawners = s.Where(z => nhoLottery.IsAreaGroup(z, nhoGroup, table.TableID)); + var groups = spawners.GroupBy(GetSpawnerType); + foreach (var g in groups) { - var temp = places.Select(z => z.PlaceName); - var areas = temp.Select(z => map[z].Index).Distinct().ToList(); - if (areas.Count == 0) - yield break; - if (areas.Remove(baseArea) && areas.Count == 0) - areas.Add(baseArea); - else if (!areas.All(IsDungeonZone) && !areas.Contains(baseArea)) - areas.Add(baseArea); - - areas.Sort(); - yield return GetArea(areas, slots, table.MinLevel, table.MaxLevel, type, misc, bmin, bmax); + if (g.Key is not SpawnerType.SpawnerMMO) + throw new Exception(); + var sl = g.SelectMany(z => z.GetIntersectingLocations(area.Locations, SpawnerBias)); + foreach (var a in GetAll(sl, g.Key)) + yield return a; } } - private static SpawnerType GetSpawnerType(PlacementSpawner8a spawner) + // Wormholes { - var criteria = spawner.Parameters; - if (criteria.ConditionID == Condition8a.Equal) + var s = area.Wormholes; + var spawners = s.Where(z => z.UsesTable(table.TableID)); + + // Since Wormholes can have different bonus level ranges, we defer uniqueness testing to the outer method. Just yield all spawners. + foreach (var w in spawners) { - var arg = criteria.ConditionArg1; - if (arg.StartsWith("FSYS_NEW_OUTBREAK")) - return SpawnerType.SpawnerMMO; - if (arg.StartsWith("WSYS_MASS_GANERATION")) - return SpawnerType.SpawnerMass; + var bmin = w.Field_20_Value.BonusLevelMin; + var bmax = w.Field_20_Value.BonusLevelMax; + + var sl = w.GetIntersectingLocations(area.Locations, WormholeBias); + foreach (var a in GetAll(sl, SpawnerType.Wormhole, bmin, bmax)) + yield return a; } - return SpawnerType.Spawner; } - // 064 Seaside Hollow - // 086 Wayward Cave - // 095 Snowpoint Temple - private static bool IsDungeonZone(int a) => a is 64 or 86 or 95; - - private static readonly int[] OybnSettings = { 15, 15, 15, 20, 20 }; - - private static byte[] GetArea(IReadOnlyList locations, IReadOnlyCollection slots, - int tableMinLevel, int tableMaxLevel, SpawnerType type, - PokeMiscTable8a misc, - int bonusMin = 0, - int bonusMax = 0) + // Landmarks { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - bw.Write((byte)locations.Count); - foreach (var loc in locations) - bw.Write((byte)loc); - if (bw.BaseStream.Position % 2 != 0) - bw.Write((byte)0); + var items = area.LandItems; + var lis = items.Where(z => z.UsesTable(table.TableID)).ToList(); - bw.Write((byte)type); - bw.Write((byte)slots.Count); - foreach (var s in slots) - { - var (_, min, max) = s.GetLevels(tableMinLevel, tableMaxLevel); - min += bonusMin; - max += bonusMax; - int alpha = 0; - var oybn = s.Oybn; - if (oybn.Oybn1 || oybn.Oybn2) - { - var miscEntry = misc.GetEntry(s.Species, s.Form); - var boostIndex = miscEntry.OybnLevelIndex; - var boost = OybnSettings[boostIndex - 1]; - max += boost; - min += boost; - if (s.Oybn.Oybn2) - alpha = 2; // Oybn2 -- Master All Moves Possible? - else if (s.Oybn.Oybn1) - alpha = 1; // Oybn1 -- Master only Alpha move? - } - - var gender = s.Gender == -1 ? 2 : s.Gender; - bw.Write((ushort)s.Species); - bw.Write((byte)s.Form); - bw.Write((byte)alpha); - bw.Write((byte)min); - bw.Write((byte)max); - bw.Write((byte)gender); - bw.Write((byte)s.NumPerfectIvs); - } - return ms.ToArray(); + var marks = area.LandMarks; + var li = marks.Where(z => lis.Any(sz => z.UsesTable(sz.LandmarkItemSpawnTableID))); + var sl = li.SelectMany(z => z.GetIntersectingLocations(area.Locations, LandmarkBias)); + foreach (var a in GetAll(sl, SpawnerType.Landmark)) + yield return a; } - public static IEnumerable GetUnownLines(AreaInstance8a area, IReadOnlyDictionary map) + IEnumerable GetAll(IEnumerable places, SpawnerType type, int bmin = 0, int bmax = 0) { - yield return $"Area: {area.AreaName}"; - foreach (var u in area.Unown.Concat(area.SubAreas.SelectMany(x => x.Unown))) + var temp = places.Select(z => z.PlaceName); + var areas = temp.Select(z => map[z].Index).Distinct().ToList(); + if (areas.Count == 0) + yield break; + if (areas.Remove(baseArea) && areas.Count == 0) + areas.Add(baseArea); + else if (!areas.All(IsDungeonZone) && !areas.Contains(baseArea)) + areas.Add(baseArea); + + areas.Sort(); + yield return GetArea(areas, slots, table.MinLevel, table.MaxLevel, type, misc, bmin, bmax); + } + } + + private static SpawnerType GetSpawnerType(PlacementSpawner8a spawner) + { + var criteria = spawner.Parameters; + if (criteria.ConditionID == Condition8a.Equal) + { + var arg = criteria.ConditionArg1; + if (arg.StartsWith("FSYS_NEW_OUTBREAK")) + return SpawnerType.SpawnerMMO; + if (arg.StartsWith("WSYS_MASS_GANERATION")) + return SpawnerType.SpawnerMass; + } + return SpawnerType.Spawner; + } + + // 064 Seaside Hollow + // 086 Wayward Cave + // 095 Snowpoint Temple + private static bool IsDungeonZone(int a) => a is 64 or 86 or 95; + + private static readonly int[] OybnSettings = { 15, 15, 15, 20, 20 }; + + private static byte[] GetArea(IReadOnlyList locations, IReadOnlyCollection slots, + int tableMinLevel, int tableMaxLevel, SpawnerType type, + PokeMiscTable8a misc, + int bonusMin = 0, + int bonusMax = 0) + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + bw.Write((byte)locations.Count); + foreach (var loc in locations) + bw.Write((byte)loc); + if (bw.BaseStream.Position % 2 != 0) + bw.Write((byte)0); + + bw.Write((byte)type); + bw.Write((byte)slots.Count); + foreach (var s in slots) + { + var (_, min, max) = s.GetLevels(tableMinLevel, tableMaxLevel); + min += bonusMin; + max += bonusMax; + int alpha = 0; + var oybn = s.Oybn; + if (oybn.Oybn1 || oybn.Oybn2) { - var contained = u.GetContainingLocations(area.Locations).First().PlaceName; - var name = map[contained].Name; + var miscEntry = misc.GetEntry(s.Species, s.Form); + var boostIndex = miscEntry.OybnLevelIndex; + var boost = OybnSettings[boostIndex - 1]; + max += boost; + min += boost; + if (s.Oybn.Oybn2) + alpha = 2; // Oybn2 -- Master All Moves Possible? + else if (s.Oybn.Oybn1) + alpha = 1; // Oybn1 -- Master only Alpha move? + } + + var gender = s.Gender == -1 ? 2 : s.Gender; + bw.Write((ushort)s.Species); + bw.Write((byte)s.Form); + bw.Write((byte)alpha); + bw.Write((byte)min); + bw.Write((byte)max); + bw.Write((byte)gender); + bw.Write((byte)s.NumPerfectIvs); + } + return ms.ToArray(); + } + + public static IEnumerable GetUnownLines(AreaInstance8a area, IReadOnlyDictionary map) + { + yield return $"Area: {area.AreaName}"; + foreach (var u in area.Unown.Concat(area.SubAreas.SelectMany(x => x.Unown))) + { + var contained = u.GetContainingLocations(area.Locations).First().PlaceName; + var name = map[contained].Name; + var p = u.Parameters; + yield return $"Unown {u.Identifier} @ {u.Hash_01:X16}_{u.Hash_03:X16} {u.Flag} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()}, {area.AreaName} = {name}"; + } + } + + public static IEnumerable GetUnownLinesBias(AreaInstance8a area, IReadOnlyDictionary map, float bias) + { + yield return $"Area: {area.AreaName}"; + foreach (var u in area.Unown.Concat(area.SubAreas.SelectMany(x => x.Unown))) + { + var contained = u.GetIntersectingLocations(area.Locations, bias); + foreach (var c in contained) + { + var name = map[c.PlaceName].Name; var p = u.Parameters; yield return $"Unown {u.Identifier} @ {u.Hash_01:X16}_{u.Hash_03:X16} {u.Flag} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()}, {area.AreaName} = {name}"; } } + } - public static IEnumerable GetUnownLinesBias(AreaInstance8a area, IReadOnlyDictionary map, float bias) + public static IEnumerable GetLines(EncounterMultiplerArchive8a multiplier_archive, + PokeMiscTable8a misc, string[] speciesNames, + AreaInstance8a area, + NewHugeOutbreakGroupArchive8a nhoGroup, + NewHugeOutbreakGroupLotteryArchive8a nhoLottery, + IReadOnlyDictionary map) + { + yield return $"Area: {area.AreaName}"; + + foreach (var enctable in area.Encounters) { + foreach (var line in GetTableSummary(enctable, multiplier_archive, speciesNames, misc, area, nhoGroup, nhoLottery, map)) + yield return $"\t{line}"; + + yield return string.Empty; + } + } + + private static IEnumerable GetUsedSpawnerSummary(EncounterTable8a t, AreaInstance8a area, + IReadOnlyDictionary valueTuples, + NewHugeOutbreakGroupArchive8a nhoGroup, + NewHugeOutbreakGroupLotteryArchive8a nhoLottery) + { + var usedBySpawners = Array.FindAll(area.Spawners, z => z.UsesTable(t.TableID)); + var usedByWormholes = Array.FindAll(area.Wormholes, z => z.UsesTable(t.TableID)); + var usedByLandmarkSpawns = Array.FindAll(area.LandItems, z => z.UsesTable(t.TableID)); + var usedByLandmarks = Array.FindAll(area.LandMarks, z => usedByLandmarkSpawns.Any(sz => z.UsesTable(sz.LandmarkItemSpawnTableID))); + var usedByNHO = Array.FindAll(area.Spawners, z => nhoLottery.IsAreaGroup(z, nhoGroup, t.TableID)); + + foreach (var s in usedBySpawners) { - yield return $"Area: {area.AreaName}"; - foreach (var u in area.Unown.Concat(area.SubAreas.SelectMany(x => x.Unown))) - { - var contained = u.GetIntersectingLocations(area.Locations, bias); - foreach (var c in contained) - { - var name = map[c.PlaceName].Name; - var p = u.Parameters; - yield return $"Unown {u.Identifier} @ {u.Hash_01:X16}_{u.Hash_03:X16} {u.Flag} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()}, {area.AreaName} = {name}"; - } - } + var contained = s.GetContainingLocations(area.Locations).First().PlaceName; + var name = valueTuples[contained].Name; + var p = s.Parameters; + yield return $"Spawner @ {s.NameSummary}_{s.Field_01:X16} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()} ({s.MinSpawnCount}-{s.MaxSpawnCount}), {area.AreaName} = {name}"; + } + foreach (var s in usedByNHO) + { + var contained = s.GetContainingLocations(area.Locations).First().PlaceName; + var name = valueTuples[contained].Name; + var p = s.Parameters; + yield return $"SpawnerNHO @ {s.NameSummary}_{s.Field_01:X16} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()} ({s.MinSpawnCount}-{s.MaxSpawnCount}), {area.AreaName} = {name}"; + } + foreach (var s in usedByWormholes) + { + var contained = s.GetContainingLocations(area.Locations).First().PlaceName; + var name = valueTuples[contained].Name; + var p = s.Parameters; + var c = s.Field_20_Value; + yield return $"Wormhole: {s.NameSummary}_{s.Field_01:X16} ({p.GetConditionSummary()}) [{c.BonusLevelMin}-{c.BonusLevelMax}] @ {p.Coordinates.ToTriple()} ({s.MinSpawnCount}-{s.MaxSpawnCount}), {area.AreaName} = {name}"; + } + foreach (var s in usedByLandmarks) + { + var contained = s.GetContainingLocations(area.Locations).First().PlaceName; + var name = valueTuples[contained].Name; + var spawn = usedByLandmarkSpawns.First(sz => s.UsesTable(sz.LandmarkItemSpawnTableID)); + var p = s.Parameters; + yield return $"Landmark: {s.NameSummary}_{s.Field_01:X16}_{spawn.NameSummary} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()}, {area.AreaName} = {name}"; + } + } + + private static IEnumerable GetTableSummary(EncounterTable8a t, + EncounterMultiplerArchive8a multiplier_archive, string[] speciesNames, + PokeMiscTable8a misc, + AreaInstance8a area, + NewHugeOutbreakGroupArchive8a nhoGroup, + NewHugeOutbreakGroupLotteryArchive8a nhoLottery, + IReadOnlyDictionary valueTuples) + { + yield return $"{t}:"; + + var totalUses = 0; + foreach (var line in GetUsedSpawnerSummary(t, area, valueTuples, nhoGroup, nhoLottery)) + { + totalUses++; + yield return $"\t{line}"; } - public static IEnumerable GetLines(EncounterMultiplerArchive8a multiplier_archive, - PokeMiscTable8a misc, string[] speciesNames, - AreaInstance8a area, - NewHugeOutbreakGroupArchive8a nhoGroup, - NewHugeOutbreakGroupLotteryArchive8a nhoLottery, - IReadOnlyDictionary map) + foreach (var subArea in area.SubAreas) { - yield return $"Area: {area.AreaName}"; - - foreach (var enctable in area.Encounters) { - foreach (var line in GetTableSummary(enctable, multiplier_archive, speciesNames, misc, area, nhoGroup, nhoLottery, map)) - yield return $"\t{line}"; - - yield return string.Empty; - } - } - - private static IEnumerable GetUsedSpawnerSummary(EncounterTable8a t, AreaInstance8a area, - IReadOnlyDictionary valueTuples, - NewHugeOutbreakGroupArchive8a nhoGroup, - NewHugeOutbreakGroupLotteryArchive8a nhoLottery) - { - var usedBySpawners = Array.FindAll(area.Spawners, z => z.UsesTable(t.TableID)); - var usedByWormholes = Array.FindAll(area.Wormholes, z => z.UsesTable(t.TableID)); - var usedByLandmarkSpawns = Array.FindAll(area.LandItems, z => z.UsesTable(t.TableID)); - var usedByLandmarks = Array.FindAll(area.LandMarks, z => usedByLandmarkSpawns.Any(sz => z.UsesTable(sz.LandmarkItemSpawnTableID))); - var usedByNHO = Array.FindAll(area.Spawners, z => nhoLottery.IsAreaGroup(z, nhoGroup, t.TableID)); - - foreach (var s in usedBySpawners) - { - var contained = s.GetContainingLocations(area.Locations).First().PlaceName; - var name = valueTuples[contained].Name; - var p = s.Parameters; - yield return $"Spawner @ {s.NameSummary}_{s.Field_01:X16} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()} ({s.MinSpawnCount}-{s.MaxSpawnCount}), {area.AreaName} = {name}"; - } - foreach (var s in usedByNHO) - { - var contained = s.GetContainingLocations(area.Locations).First().PlaceName; - var name = valueTuples[contained].Name; - var p = s.Parameters; - yield return $"SpawnerNHO @ {s.NameSummary}_{s.Field_01:X16} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()} ({s.MinSpawnCount}-{s.MaxSpawnCount}), {area.AreaName} = {name}"; - } - foreach (var s in usedByWormholes) - { - var contained = s.GetContainingLocations(area.Locations).First().PlaceName; - var name = valueTuples[contained].Name; - var p = s.Parameters; - var c = s.Field_20_Value; - yield return $"Wormhole: {s.NameSummary}_{s.Field_01:X16} ({p.GetConditionSummary()}) [{c.BonusLevelMin}-{c.BonusLevelMax}] @ {p.Coordinates.ToTriple()} ({s.MinSpawnCount}-{s.MaxSpawnCount}), {area.AreaName} = {name}"; - } - foreach (var s in usedByLandmarks) - { - var contained = s.GetContainingLocations(area.Locations).First().PlaceName; - var name = valueTuples[contained].Name; - var spawn = usedByLandmarkSpawns.First(sz => s.UsesTable(sz.LandmarkItemSpawnTableID)); - var p = s.Parameters; - yield return $"Landmark: {s.NameSummary}_{s.Field_01:X16}_{spawn.NameSummary} ({p.GetConditionSummary()}) @ {p.Coordinates.ToTriple()}, {area.AreaName} = {name}"; - } - } - - private static IEnumerable GetTableSummary(EncounterTable8a t, - EncounterMultiplerArchive8a multiplier_archive, string[] speciesNames, - PokeMiscTable8a misc, - AreaInstance8a area, - NewHugeOutbreakGroupArchive8a nhoGroup, - NewHugeOutbreakGroupLotteryArchive8a nhoLottery, - IReadOnlyDictionary valueTuples) - { - yield return $"{t}:"; - - var totalUses = 0; - foreach (var line in GetUsedSpawnerSummary(t, area, valueTuples, nhoGroup, nhoLottery)) + foreach (var line in GetUsedSpawnerSummary(t, subArea, valueTuples, nhoGroup, nhoLottery)) { totalUses++; yield return $"\t{line}"; } - - foreach (var subArea in area.SubAreas) - { - foreach (var line in GetUsedSpawnerSummary(t, subArea, valueTuples, nhoGroup, nhoLottery)) - { - totalUses++; - yield return $"\t{line}"; - } - } - - if (totalUses == 0) - { - yield return "\tNo spawners? Check that this is used somewhere."; - } - - foreach (var line in GetLines(t.Table, multiplier_archive, speciesNames, t.MinLevel, t.MaxLevel, misc)) - yield return $"\t{line}"; } - private static IEnumerable GetLines(IReadOnlyList arr, - EncounterMultiplerArchive8a multiplier_archive, IReadOnlyList speciesNames, int lvMin, int lvMax, - PokeMiscTable8a misc) + if (totalUses == 0) { - var dividedTables = EncounterDetail8a.GetEmpty(); - FillSlots(arr, multiplier_archive, dividedTables); - EncounterDetail8a.Divide(dividedTables); + yield return "\tNo spawners? Check that this is used somewhere."; + } - var sym = EncounterDetail8a.AnalyzeSymmetry(dividedTables); - if (sym.Time && sym.Weather) + foreach (var line in GetLines(t.Table, multiplier_archive, speciesNames, t.MinLevel, t.MaxLevel, misc)) + yield return $"\t{line}"; + } + + private static IEnumerable GetLines(IReadOnlyList arr, + EncounterMultiplerArchive8a multiplier_archive, IReadOnlyList speciesNames, int lvMin, int lvMax, + PokeMiscTable8a misc) + { + var dividedTables = EncounterDetail8a.GetEmpty(); + FillSlots(arr, multiplier_archive, dividedTables); + EncounterDetail8a.Divide(dividedTables); + + var sym = EncounterDetail8a.AnalyzeSymmetry(dividedTables); + if (sym.Time && sym.Weather) + { + yield return "Any Time/All Weather:"; + foreach (var line in GetEffectiveTableSummary(dividedTables[0, 0], speciesNames, lvMin, lvMax, misc)) + yield return $"\t{line}"; + } + else if (sym.Weather) + { + for (var time = 0; time < dividedTables.GetLength(0); time++) { - yield return "Any Time/All Weather:"; - foreach (var line in GetEffectiveTableSummary(dividedTables[0, 0], speciesNames, lvMin, lvMax, misc)) + yield return $"{(Time8a)time}/All Weather:"; + foreach (var line in GetEffectiveTableSummary(dividedTables[time, 0], speciesNames, lvMin, lvMax, misc)) yield return $"\t{line}"; } - else if (sym.Weather) + } + else if (sym.Time) + { + for (var weather = 0; weather < dividedTables.GetLength(1); weather++) { - for (var time = 0; time < dividedTables.GetLength(0); time++) + yield return $"Any Time/{(Weather8a)weather}:"; + foreach (var line in GetEffectiveTableSummary(dividedTables[0, weather], speciesNames, lvMin, lvMax, misc)) + yield return $"\t{line}"; + } + } + else + { + for (var time = 0; time < dividedTables.GetLength(0); time++) + { + if (sym.Complexed[time]) { yield return $"{(Time8a)time}/All Weather:"; foreach (var line in GetEffectiveTableSummary(dividedTables[time, 0], speciesNames, lvMin, lvMax, misc)) yield return $"\t{line}"; } - } - else if (sym.Time) - { - for (var weather = 0; weather < dividedTables.GetLength(1); weather++) + else { - yield return $"Any Time/{(Weather8a)weather}:"; - foreach (var line in GetEffectiveTableSummary(dividedTables[0, weather], speciesNames, lvMin, lvMax, misc)) - yield return $"\t{line}"; - } - } - else - { - for (var time = 0; time < dividedTables.GetLength(0); time++) - { - if (sym.Complexed[time]) - { - yield return $"{(Time8a)time}/All Weather:"; - foreach (var line in GetEffectiveTableSummary(dividedTables[time, 0], speciesNames, lvMin, lvMax, misc)) - yield return $"\t{line}"; - } - else - { - for (var weather = 0; weather < dividedTables.GetLength(1); weather++) - { - yield return $"{(Time8a)time}/{(Weather8a)weather}:"; - foreach (var line in GetEffectiveTableSummary(dividedTables[time, weather], speciesNames, lvMin, lvMax, misc)) - yield return $"\t{line}"; - } - } - } - } - } - - private static void FillSlots(IEnumerable arr, EncounterMultiplerArchive8a multArchive, List[,] dividedTables) - { - var ctr = 0; - foreach (var slot in arr.OrderByDescending(sl => sl.BaseProbability)) - { - var defaults = multArchive.GetEncounterMultiplier(slot); - for (var time = 0; time < dividedTables.GetLength(0); time++) - { - var MultT = slot.GetTimeModifier(time, defaults); for (var weather = 0; weather < dividedTables.GetLength(1); weather++) { - var MultW = slot.GetWeatherModifier(weather, defaults); - var rate = slot.BaseProbability * MultT * MultW; - if (rate == 0) - continue; - - var detail = new EncounterDetail8a(slot.BaseProbability * MultT * MultW, MultT, MultW, ctr, slot); - dividedTables[time, weather].Add(detail); + yield return $"{(Time8a)time}/{(Weather8a)weather}:"; + foreach (var line in GetEffectiveTableSummary(dividedTables[time, weather], speciesNames, lvMin, lvMax, misc)) + yield return $"\t{line}"; } } - - ctr++; - } - } - - private static IEnumerable GetEffectiveTableSummary(IReadOnlyList table, IReadOnlyList speciesNames, int lvMin, int lvMax, PokeMiscTable8a misc) - { - if (table.Count == 0) - { - yield return " - None"; - yield break; - } - - foreach (var tup in table) - { - var rate = tup.Rate; - var slot = tup.Slot; - - string form = slot.Form == 0 ? string.Empty : $"-{slot.Form}"; - var spec_form = $"{speciesNames[slot.Species]}{form}"; - - var summary = $"- {rate:00.00}%\t{spec_form,-12}"; - - var (force, min, max) = slot.GetLevels(lvMin, lvMax); - if (slot.Oybn.Oybn1 || slot.Oybn.Oybn2) - { - var miscEntry = misc.GetEntry(slot.Species, slot.Form); - var boostIndex = miscEntry.OybnLevelIndex; - var boost = OybnSettings[boostIndex - 1]; - max += boost; - min += boost; - summary += $"\tAlphaLevel={min}-{max}"; - } - else if (force) - { - summary += $"\tOverrideLevel={min}-{max}"; - } - - if (slot.Gender != -1) - summary += $"\tGender={slot.Gender}"; - - if (slot.ShinyLock is not ShinyType8a.Random) - summary += $"\tShinyLock={slot.ShinyLock}"; - - if (slot.AbilityRandType is not AbilityType8a.Any12) - summary += $"\tAbility={slot.AbilityRandType}"; - - if (slot.Nature is not NatureType8a.Random) - summary += $"\tNature={slot.Nature}"; - - var gvs = new[] { slot.GV_HP, slot.GV_ATK, slot.GV_DEF, slot.GV_SPA, slot.GV_SPD, slot.GV_SPE }; - if (gvs.Any(x => x != -1)) - summary += $"\tGVS={string.Join("/", gvs.Select(v => v != -1 ? v.ToString() : "*").ToArray())}"; - - if (slot.NumPerfectIvs != 0) - summary += $"\tPerfectIvs={slot.NumPerfectIvs}"; - - var ivs = new[] { slot.IV_HP, slot.IV_ATK, slot.IV_DEF, slot.IV_SPA, slot.IV_SPD, slot.IV_SPE }; - if (ivs.Any(x => x != -1)) - summary += $"\tIVS={string.Join("/", ivs.Select(v => v != -1 ? v.ToString() : "*").ToArray())}"; - - var oybn = slot.Oybn; - if (oybn.IsOybnAny) - { - if (oybn.Oybn1 && !oybn.Oybn2 && oybn.Field_02 && oybn.Field_03) - summary += "\tOybn=Type1"; - else if (oybn.Oybn1 && oybn.Oybn2 && oybn.Field_02 && oybn.Field_03) - summary += "\tOybn=Type2"; - else - summary += $"\tOybn={{{(oybn.Oybn1 ? 1 : 0)},{(oybn.Oybn2 ? 1 : 0)},{(oybn.Field_02 ? 1 : 0)},{(oybn.Field_03 ? 1 : 0)}}}"; - } - - var elg = slot.Eligibility; - if (slot.Eligibility.ConditionTypeID != ConditionType8a.None) - { - summary += $"\tConditionType={elg.GetConditionTypeSummary()}"; - summary += $"\tCondition={elg.GetConditionSummary()}"; - } - - if (!string.IsNullOrEmpty(slot.Behavior1)) - summary += $"\t{nameof(slot.Behavior1)}=\"{slot.Behavior1}\""; - - if (!string.IsNullOrEmpty(slot.Behavior2)) - summary += $"\t{nameof(slot.Behavior2)}=\"{slot.Behavior2}\""; - - if (slot.SlotID != 0xCBF29CE484222645) - summary += $"\tSlotID={slot.SlotName}"; - - yield return summary; } } } + + private static void FillSlots(IEnumerable arr, EncounterMultiplerArchive8a multArchive, List[,] dividedTables) + { + var ctr = 0; + foreach (var slot in arr.OrderByDescending(sl => sl.BaseProbability)) + { + var defaults = multArchive.GetEncounterMultiplier(slot); + for (var time = 0; time < dividedTables.GetLength(0); time++) + { + var MultT = slot.GetTimeModifier(time, defaults); + for (var weather = 0; weather < dividedTables.GetLength(1); weather++) + { + var MultW = slot.GetWeatherModifier(weather, defaults); + var rate = slot.BaseProbability * MultT * MultW; + if (rate == 0) + continue; + + var detail = new EncounterDetail8a(slot.BaseProbability * MultT * MultW, MultT, MultW, ctr, slot); + dividedTables[time, weather].Add(detail); + } + } + + ctr++; + } + } + + private static IEnumerable GetEffectiveTableSummary(IReadOnlyList table, IReadOnlyList speciesNames, int lvMin, int lvMax, PokeMiscTable8a misc) + { + if (table.Count == 0) + { + yield return " - None"; + yield break; + } + + foreach (var tup in table) + { + var rate = tup.Rate; + var slot = tup.Slot; + + string form = slot.Form == 0 ? string.Empty : $"-{slot.Form}"; + var spec_form = $"{speciesNames[slot.Species]}{form}"; + + var summary = $"- {rate:00.00}%\t{spec_form,-12}"; + + var (force, min, max) = slot.GetLevels(lvMin, lvMax); + if (slot.Oybn.Oybn1 || slot.Oybn.Oybn2) + { + var miscEntry = misc.GetEntry(slot.Species, slot.Form); + var boostIndex = miscEntry.OybnLevelIndex; + var boost = OybnSettings[boostIndex - 1]; + max += boost; + min += boost; + summary += $"\tAlphaLevel={min}-{max}"; + } + else if (force) + { + summary += $"\tOverrideLevel={min}-{max}"; + } + + if (slot.Gender != -1) + summary += $"\tGender={slot.Gender}"; + + if (slot.ShinyLock is not ShinyType8a.Random) + summary += $"\tShinyLock={slot.ShinyLock}"; + + if (slot.AbilityRandType is not AbilityType8a.Any12) + summary += $"\tAbility={slot.AbilityRandType}"; + + if (slot.Nature is not NatureType8a.Random) + summary += $"\tNature={slot.Nature}"; + + var gvs = new[] { slot.GV_HP, slot.GV_ATK, slot.GV_DEF, slot.GV_SPA, slot.GV_SPD, slot.GV_SPE }; + if (gvs.Any(x => x != -1)) + summary += $"\tGVS={string.Join("/", gvs.Select(v => v != -1 ? v.ToString() : "*").ToArray())}"; + + if (slot.NumPerfectIvs != 0) + summary += $"\tPerfectIvs={slot.NumPerfectIvs}"; + + var ivs = new[] { slot.IV_HP, slot.IV_ATK, slot.IV_DEF, slot.IV_SPA, slot.IV_SPD, slot.IV_SPE }; + if (ivs.Any(x => x != -1)) + summary += $"\tIVS={string.Join("/", ivs.Select(v => v != -1 ? v.ToString() : "*").ToArray())}"; + + var oybn = slot.Oybn; + if (oybn.IsOybnAny) + { + if (oybn.Oybn1 && !oybn.Oybn2 && oybn.Field_02 && oybn.Field_03) + summary += "\tOybn=Type1"; + else if (oybn.Oybn1 && oybn.Oybn2 && oybn.Field_02 && oybn.Field_03) + summary += "\tOybn=Type2"; + else + summary += $"\tOybn={{{(oybn.Oybn1 ? 1 : 0)},{(oybn.Oybn2 ? 1 : 0)},{(oybn.Field_02 ? 1 : 0)},{(oybn.Field_03 ? 1 : 0)}}}"; + } + + var elg = slot.Eligibility; + if (slot.Eligibility.ConditionTypeID != ConditionType8a.None) + { + summary += $"\tConditionType={elg.GetConditionTypeSummary()}"; + summary += $"\tCondition={elg.GetConditionSummary()}"; + } + + if (!string.IsNullOrEmpty(slot.Behavior1)) + summary += $"\t{nameof(slot.Behavior1)}=\"{slot.Behavior1}\""; + + if (!string.IsNullOrEmpty(slot.Behavior2)) + summary += $"\t{nameof(slot.Behavior2)}=\"{slot.Behavior2}\""; + + if (slot.SlotID != 0xCBF29CE484222645) + summary += $"\tSlotID={slot.SlotName}"; + + yield return summary; + } + } } diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/IHasCondition8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/IHasCondition8a.cs index 6b6a80c9..bf9666e8 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/IHasCondition8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/IHasCondition8a.cs @@ -1,4 +1,4 @@ -// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedMember.Global namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/NatureType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/NatureType8a.cs index faa08fdf..01f0dcbb 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/NatureType8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/NatureType8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; // ReSharper disable UnusedMember.Global @@ -38,4 +38,4 @@ public enum NatureType8a Careful, Quirky, -} \ No newline at end of file +} diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/ShinyType8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/ShinyType8a.cs index e824026d..56a0c080 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/ShinyType8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/ShinyType8a.cs @@ -1,4 +1,4 @@ -using FlatSharp.Attributes; +using FlatSharp.Attributes; // ReSharper disable UnusedMember.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/SpawnerType.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/SpawnerType.cs index cd829d4d..6f934087 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/SpawnerType.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/SpawnerType.cs @@ -1,4 +1,4 @@ -namespace pkNX.Structures.FlatBuffers; +namespace pkNX.Structures.FlatBuffers; public enum SpawnerType { diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/Time8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/Time8a.cs index 9187deb2..601f721b 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/Time8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/Time8a.cs @@ -1,4 +1,4 @@ -// ReSharper disable UnusedMember.Global +// ReSharper disable UnusedMember.Global namespace pkNX.Structures.FlatBuffers; diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/Trigger8aUtil.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/Trigger8aUtil.cs index dc0d00d7..4ac3b930 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/Trigger8aUtil.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/Trigger8aUtil.cs @@ -1,81 +1,79 @@ -using System; +using System; using System.Collections.Generic; -using System.IO; using System.Linq; -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +public static class Trigger8aUtil { - public static class Trigger8aUtil + public static IEnumerable GetTriggerTableSummary(TriggerTable8a tab) { - public static IEnumerable GetTriggerTableSummary(TriggerTable8a tab) + foreach (var trg in tab.Table) { - foreach (var trg in tab.Table) - { - yield return "Trigger:"; - foreach (var line in GetTriggerSummary(trg)) - yield return $"\t{line}"; - } - } - - public static IEnumerable GetTriggerSummary(Trigger8a trg) - { - yield return "Meta:"; - yield return $"\t{GetTriggerMetaSummary(trg.Meta)}"; - yield return "Conditions:"; - foreach (var line in GetTriggerConditionsSummary(trg.Conditions)) + yield return "Trigger:"; + foreach (var line in GetTriggerSummary(trg)) yield return $"\t{line}"; - yield return "Commands:"; - foreach (var line in GetTriggerCommandsSummary(trg.Commands)) - yield return $"\t{line}"; - } - - public static string GetTriggerMetaSummary(TriggerMeta8a meta) - { - if (meta.Unused_01 != 0) - throw new ArgumentException("TriggerMeta has unused field set?"); - - var argsSummary = GetTriggerArgsSummary(meta.TriggerMetaArg1, meta.TriggerMetaArg2, meta.TriggerMetaArg3); - - if (Enum.IsDefined(typeof(TriggerType8a), meta.TriggerTypeID)) - return $"{meta.TriggerTypeID}({argsSummary})"; - else - return $"0x{(ulong)meta.TriggerTypeID:X16}({argsSummary})"; - } - - public static IEnumerable GetTriggerConditionsSummary(IEnumerable conds) - { - foreach (var cond in conds) - yield return $"{Condition8aUtil.GetConditionTypeSummary(cond)}: {Condition8aUtil.GetConditionSummary(cond)}"; - } - - public static IEnumerable GetTriggerCommandsSummary(IEnumerable cmds) - { - foreach (var cmd in cmds) - yield return GetTriggerCommandSummary(cmd); - } - - public static string GetTriggerCommandSummary(TriggerCommand8a cmd) - { - var argsSummary = GetTriggerArgsSummary(cmd.Arguments); - - if (Enum.IsDefined(typeof(TriggerCommandType8a), cmd.CommandTypeID)) - return $"{cmd.CommandTypeID}({argsSummary})"; - else - return $"0x{(ulong)cmd.CommandTypeID:X16}({argsSummary})"; - } - - public static string GetTriggerArgsSummary(params string[] args) - { - var firstEmpty = -1; - for (var i = 0; i < args.Length; i++) - { - if (firstEmpty >= 0 && !string.IsNullOrEmpty(args[i])) - throw new ArgumentException($"Invalid TriggerArg at index {i}!"); - else if (firstEmpty < 0 && string.IsNullOrEmpty(args[i])) - firstEmpty = i; - } - - return string.Join(", ", args.Select(s => $"\"{s}\"").Take(firstEmpty >= 0 ? firstEmpty : args.Length)); } } + + public static IEnumerable GetTriggerSummary(Trigger8a trg) + { + yield return "Meta:"; + yield return $"\t{GetTriggerMetaSummary(trg.Meta)}"; + yield return "Conditions:"; + foreach (var line in GetTriggerConditionsSummary(trg.Conditions)) + yield return $"\t{line}"; + yield return "Commands:"; + foreach (var line in GetTriggerCommandsSummary(trg.Commands)) + yield return $"\t{line}"; + } + + public static string GetTriggerMetaSummary(TriggerMeta8a meta) + { + if (meta.Unused_01 != 0) + throw new ArgumentException("TriggerMeta has unused field set?"); + + var argsSummary = GetTriggerArgsSummary(meta.TriggerMetaArg1, meta.TriggerMetaArg2, meta.TriggerMetaArg3); + + if (Enum.IsDefined(typeof(TriggerType8a), meta.TriggerTypeID)) + return $"{meta.TriggerTypeID}({argsSummary})"; + else + return $"0x{(ulong)meta.TriggerTypeID:X16}({argsSummary})"; + } + + public static IEnumerable GetTriggerConditionsSummary(IEnumerable conds) + { + foreach (var cond in conds) + yield return $"{Condition8aUtil.GetConditionTypeSummary(cond)}: {Condition8aUtil.GetConditionSummary(cond)}"; + } + + public static IEnumerable GetTriggerCommandsSummary(IEnumerable cmds) + { + foreach (var cmd in cmds) + yield return GetTriggerCommandSummary(cmd); + } + + public static string GetTriggerCommandSummary(TriggerCommand8a cmd) + { + var argsSummary = GetTriggerArgsSummary(cmd.Arguments); + + if (Enum.IsDefined(typeof(TriggerCommandType8a), cmd.CommandTypeID)) + return $"{cmd.CommandTypeID}({argsSummary})"; + else + return $"0x{(ulong)cmd.CommandTypeID:X16}({argsSummary})"; + } + + public static string GetTriggerArgsSummary(params string[] args) + { + var firstEmpty = -1; + for (var i = 0; i < args.Length; i++) + { + if (firstEmpty >= 0 && !string.IsNullOrEmpty(args[i])) + throw new ArgumentException($"Invalid TriggerArg at index {i}!"); + else if (firstEmpty < 0 && string.IsNullOrEmpty(args[i])) + firstEmpty = i; + } + + return string.Join(", ", args.Select(s => $"\"{s}\"").Take(firstEmpty >= 0 ? firstEmpty : args.Length)); + } } diff --git a/pkNX.Structures.FlatBuffers/Arceus/Util/Weather8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Util/Weather8a.cs index 3cc4f169..c68ea11e 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Util/Weather8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Util/Weather8a.cs @@ -1,4 +1,4 @@ -namespace pkNX.Structures.FlatBuffers; +namespace pkNX.Structures.FlatBuffers; // ReSharper disable UnusedMember.Global diff --git a/pkNX.Structures.FlatBuffers/Arceus/Waza8a.cs b/pkNX.Structures.FlatBuffers/Arceus/Waza8a.cs index 80951cfb..4b481a88 100644 --- a/pkNX.Structures.FlatBuffers/Arceus/Waza8a.cs +++ b/pkNX.Structures.FlatBuffers/Arceus/Waza8a.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global diff --git a/pkNX.Structures.FlatBuffers/FlatBufferConverter.cs b/pkNX.Structures.FlatBuffers/FlatBufferConverter.cs index 3037e3fc..754b25bc 100644 --- a/pkNX.Structures.FlatBuffers/FlatBufferConverter.cs +++ b/pkNX.Structures.FlatBuffers/FlatBufferConverter.cs @@ -2,51 +2,50 @@ using System.IO; using FlatSharp; -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +public static class FlatBufferConverter { - public static class FlatBufferConverter + public static T[] DeserializeFrom(string[] files) where T : class { - public static T[] DeserializeFrom(string[] files) where T : class + var result = new T[files.Length]; + for (int i = 0; i < result.Length; i++) { - var result = new T[files.Length]; - for (int i = 0; i < result.Length; i++) - { - var file = files[i]; - result[i] = DeserializeFrom(file); - } - return result; + var file = files[i]; + result[i] = DeserializeFrom(file); } + return result; + } - public static byte[][] SerializeFrom(T[] obj) where T : class + public static byte[][] SerializeFrom(T[] obj) where T : class + { + var result = new byte[obj.Length][]; + for (int i = 0; i < result.Length; i++) { - var result = new byte[obj.Length][]; - for (int i = 0; i < result.Length; i++) - { - var file = obj[i]; - result[i] = SerializeFrom(file); - } - return result; + var file = obj[i]; + result[i] = SerializeFrom(file); } + return result; + } - public static T DeserializeFrom(string file) where T : class - { - var data = File.ReadAllBytes(file); - return DeserializeFrom(data); - } + public static T DeserializeFrom(string file) where T : class + { + var data = File.ReadAllBytes(file); + return DeserializeFrom(data); + } - public static T DeserializeFrom(byte[] data) where T : class - { - return FlatBufferSerializer.Default.Parse(data); - } + public static T DeserializeFrom(byte[] data) where T : class + { + return FlatBufferSerializer.Default.Parse(data); + } - public static byte[] SerializeFrom(T obj) where T : class - { - var size = FlatBufferSerializer.Default.GetMaxSize(obj); - var data = new byte[size]; - var result = FlatBufferSerializer.Default.Serialize(obj, data); - if (result != data.Length) - Array.Resize(ref data, result); - return data; - } + public static byte[] SerializeFrom(T obj) where T : class + { + var size = FlatBufferSerializer.Default.GetMaxSize(obj); + var data = new byte[size]; + var result = FlatBufferSerializer.Default.Serialize(obj, data); + if (result != data.Length) + Array.Resize(ref data, result); + return data; } } diff --git a/pkNX.Structures.FlatBuffers/Gen7/EncounterArchive7b.cs b/pkNX.Structures.FlatBuffers/Gen7/EncounterArchive7b.cs index ac2bbfbf..01be3a67 100644 --- a/pkNX.Structures.FlatBuffers/Gen7/EncounterArchive7b.cs +++ b/pkNX.Structures.FlatBuffers/Gen7/EncounterArchive7b.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,72 +8,71 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterArchive7b { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterArchive7b - { - [FlatBufferItem(0)] public EncounterTable7b[] EncounterTables { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterTable7b - { - [FlatBufferItem(00)] public ulong ZoneID { get; set; } - [FlatBufferItem(01)] public int TrainerRankMin { get; set; } - [FlatBufferItem(02)] public int TrainerRankMax { get; set; } - - [FlatBufferItem(03)] public bool GroundSpawnAllowed { get; set; } - [FlatBufferItem(04)] public int GroundSpawnCountMax { get; set; } - [FlatBufferItem(05)] public int GroundSpawnDuration { get; set; } - [FlatBufferItem(06)] public int GroundTableEncounterRate { get; set; } - [FlatBufferItem(07)] public int GroundTableLevelMin { get; set; } - [FlatBufferItem(08)] public int GroundTableLevelMax { get; set; } - [FlatBufferItem(09)] public int GroundTableRandChanceTotal { get; set; } - [FlatBufferItem(10)] public EncounterSlot7b[] GroundTable { get; set; } - - [FlatBufferItem(11)] public bool WaterSpawnAllowed { get; set; } - [FlatBufferItem(12)] public int WaterSpawnCountMax { get; set; } - [FlatBufferItem(13)] public int WaterSpawnDuration { get; set; } - [FlatBufferItem(14)] public int WaterTableEncounterRate { get; set; } - [FlatBufferItem(15)] public int WaterTableLevelMin { get; set; } - [FlatBufferItem(16)] public int WaterTableLevelMax { get; set; } - [FlatBufferItem(17)] public int WaterTableRandChanceTotal { get; set; } - [FlatBufferItem(18)] public EncounterSlot7b[] WaterTable { get; set; } - - [FlatBufferItem(19)] public int OldRodTableEncounterRate { get; set; } - [FlatBufferItem(20)] public int OldRodTableLevelMin { get; set; } - [FlatBufferItem(21)] public int OldRodTableLevelMax { get; set; } - [FlatBufferItem(22)] public int OldRodTableRandChanceTotal { get; set; } - [FlatBufferItem(23)] public EncounterSlot7b[] OldRodTable { get; set; } - - [FlatBufferItem(24)] public int GoodRodTableEncounterRate { get; set; } - [FlatBufferItem(25)] public int GoodRodTableLevelMin { get; set; } - [FlatBufferItem(26)] public int GoodRodTableLevelMax { get; set; } - [FlatBufferItem(27)] public int GoodRodTableRandChanceTotal { get; set; } - [FlatBufferItem(28)] public EncounterSlot7b[] GoodRodTable { get; set; } - - [FlatBufferItem(29)] public int SuperRodTableEncounterRate { get; set; } - [FlatBufferItem(30)] public int SuperRodTableLevelMin { get; set; } - [FlatBufferItem(31)] public int SuperRodTableLevelMax { get; set; } - [FlatBufferItem(32)] public int SuperRodTableRandChanceTotal { get; set; } - [FlatBufferItem(33)] public EncounterSlot7b[] SuperRodTable { get; set; } - - [FlatBufferItem(34)] public bool SkySpawnAllowed { get; set; } - [FlatBufferItem(35)] public int SkySpawnCountMax { get; set; } - [FlatBufferItem(36)] public int SkySpawnDuration { get; set; } - [FlatBufferItem(37)] public int SkyTableEncounterRate { get; set; } - [FlatBufferItem(38)] public int SkyTableLevelMin { get; set; } - [FlatBufferItem(39)] public int SkyTableLevelMax { get; set; } - [FlatBufferItem(40)] public int SkyTableRandChanceTotal { get; set; } - [FlatBufferItem(41)] public EncounterSlot7b[] SkyTable { get; set; } - } - - [FlatBufferTable] - public class EncounterSlot7b - { - [FlatBufferItem(0)] public int Probability { get; set; } - [FlatBufferItem(1)] public int Species { get; set; } - [FlatBufferItem(2)] public short Form { get; set; } - } + [FlatBufferItem(0)] public EncounterTable7b[] EncounterTables { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterTable7b +{ + [FlatBufferItem(00)] public ulong ZoneID { get; set; } + [FlatBufferItem(01)] public int TrainerRankMin { get; set; } + [FlatBufferItem(02)] public int TrainerRankMax { get; set; } + + [FlatBufferItem(03)] public bool GroundSpawnAllowed { get; set; } + [FlatBufferItem(04)] public int GroundSpawnCountMax { get; set; } + [FlatBufferItem(05)] public int GroundSpawnDuration { get; set; } + [FlatBufferItem(06)] public int GroundTableEncounterRate { get; set; } + [FlatBufferItem(07)] public int GroundTableLevelMin { get; set; } + [FlatBufferItem(08)] public int GroundTableLevelMax { get; set; } + [FlatBufferItem(09)] public int GroundTableRandChanceTotal { get; set; } + [FlatBufferItem(10)] public EncounterSlot7b[] GroundTable { get; set; } + + [FlatBufferItem(11)] public bool WaterSpawnAllowed { get; set; } + [FlatBufferItem(12)] public int WaterSpawnCountMax { get; set; } + [FlatBufferItem(13)] public int WaterSpawnDuration { get; set; } + [FlatBufferItem(14)] public int WaterTableEncounterRate { get; set; } + [FlatBufferItem(15)] public int WaterTableLevelMin { get; set; } + [FlatBufferItem(16)] public int WaterTableLevelMax { get; set; } + [FlatBufferItem(17)] public int WaterTableRandChanceTotal { get; set; } + [FlatBufferItem(18)] public EncounterSlot7b[] WaterTable { get; set; } + + [FlatBufferItem(19)] public int OldRodTableEncounterRate { get; set; } + [FlatBufferItem(20)] public int OldRodTableLevelMin { get; set; } + [FlatBufferItem(21)] public int OldRodTableLevelMax { get; set; } + [FlatBufferItem(22)] public int OldRodTableRandChanceTotal { get; set; } + [FlatBufferItem(23)] public EncounterSlot7b[] OldRodTable { get; set; } + + [FlatBufferItem(24)] public int GoodRodTableEncounterRate { get; set; } + [FlatBufferItem(25)] public int GoodRodTableLevelMin { get; set; } + [FlatBufferItem(26)] public int GoodRodTableLevelMax { get; set; } + [FlatBufferItem(27)] public int GoodRodTableRandChanceTotal { get; set; } + [FlatBufferItem(28)] public EncounterSlot7b[] GoodRodTable { get; set; } + + [FlatBufferItem(29)] public int SuperRodTableEncounterRate { get; set; } + [FlatBufferItem(30)] public int SuperRodTableLevelMin { get; set; } + [FlatBufferItem(31)] public int SuperRodTableLevelMax { get; set; } + [FlatBufferItem(32)] public int SuperRodTableRandChanceTotal { get; set; } + [FlatBufferItem(33)] public EncounterSlot7b[] SuperRodTable { get; set; } + + [FlatBufferItem(34)] public bool SkySpawnAllowed { get; set; } + [FlatBufferItem(35)] public int SkySpawnCountMax { get; set; } + [FlatBufferItem(36)] public int SkySpawnDuration { get; set; } + [FlatBufferItem(37)] public int SkyTableEncounterRate { get; set; } + [FlatBufferItem(38)] public int SkyTableLevelMin { get; set; } + [FlatBufferItem(39)] public int SkyTableLevelMax { get; set; } + [FlatBufferItem(40)] public int SkyTableRandChanceTotal { get; set; } + [FlatBufferItem(41)] public EncounterSlot7b[] SkyTable { get; set; } +} + +[FlatBufferTable] +public class EncounterSlot7b +{ + [FlatBufferItem(0)] public int Probability { get; set; } + [FlatBufferItem(1)] public int Species { get; set; } + [FlatBufferItem(2)] public short Form { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen7/EncounterTable7bUtil.cs b/pkNX.Structures.FlatBuffers/Gen7/EncounterTable7bUtil.cs index f0c350bd..954bd774 100644 --- a/pkNX.Structures.FlatBuffers/Gen7/EncounterTable7bUtil.cs +++ b/pkNX.Structures.FlatBuffers/Gen7/EncounterTable7bUtil.cs @@ -1,76 +1,75 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +public static class EncounterTable7bUtil { - public static class EncounterTable7bUtil + public static IEnumerable GetLines(EncounterArchive7b t, string[] names, string[] species) { - public static IEnumerable GetLines(EncounterArchive7b t, string[] names, string[] species) + for (var i = 0; i < t.EncounterTables.Length; i++) { - for (var i = 0; i < t.EncounterTables.Length; i++) - { - var enc = t.EncounterTables[i]; - yield return $"{i:000} - {names[i]}"; + var enc = t.EncounterTables[i]; + yield return $"{i:000} - {names[i]}"; - if (enc.GroundTableEncounterRate != 0) - { - yield return nameof(enc.GroundTable); - yield return GetSubSummary(enc.GroundTableLevelMin, enc.GroundTableLevelMax, enc.GroundTableEncounterRate, enc.GroundSpawnCountMax); - foreach (var line in GetLines(enc.GroundTable, species)) - yield return line; - } - if (enc.WaterTableEncounterRate != 0) - { - yield return nameof(enc.WaterTable); - yield return GetSubSummary(enc.WaterTableLevelMin, enc.WaterTableLevelMax, enc.WaterTableEncounterRate, enc.WaterSpawnCountMax); - foreach (var line in GetLines(enc.WaterTable, species)) - yield return line; - } - if (enc.OldRodTableEncounterRate != 0) - { - yield return nameof(enc.OldRodTable); - yield return GetSubSummary(enc.OldRodTableLevelMin, enc.OldRodTableLevelMax, enc.OldRodTableEncounterRate); - foreach (var line in GetLines(enc.OldRodTable, species)) - yield return line; - } - if (enc.GoodRodTableEncounterRate != 0) - { - yield return nameof(enc.GoodRodTable); - yield return GetSubSummary(enc.GoodRodTableLevelMin, enc.GoodRodTableLevelMax, enc.GoodRodTableEncounterRate); - foreach (var line in GetLines(enc.GoodRodTable, species)) - yield return line; - } - if (enc.SuperRodTableEncounterRate != 0) - { - yield return nameof(enc.SuperRodTable); - yield return GetSubSummary(enc.SuperRodTableLevelMin, enc.SuperRodTableLevelMax, enc.SuperRodTableEncounterRate); - foreach (var line in GetLines(enc.SuperRodTable, species)) - yield return line; - } - if (enc.SkyTableEncounterRate != 0) - { - yield return nameof(enc.SkyTable); - yield return GetSubSummary(enc.SkyTableLevelMin, enc.SkyTableLevelMax, enc.SkyTableEncounterRate, enc.SkySpawnCountMax); - foreach (var line in GetLines(enc.SkyTable, species)) - yield return line; - } - yield return string.Empty; + if (enc.GroundTableEncounterRate != 0) + { + yield return nameof(enc.GroundTable); + yield return GetSubSummary(enc.GroundTableLevelMin, enc.GroundTableLevelMax, enc.GroundTableEncounterRate, enc.GroundSpawnCountMax); + foreach (var line in GetLines(enc.GroundTable, species)) + yield return line; } - } - - private static string GetSubSummary(int min, int max, int rate) => $"lv{min}-{max}, rate: {rate}"; - private static string GetSubSummary(int min, int max, int rate, int count) => GetSubSummary(min, max, rate) + $", max count: {count}"; - - private static IEnumerable GetLines(IReadOnlyList arr, IReadOnlyList species) - { - for (var i = 0; i < arr.Count; i++) + if (enc.WaterTableEncounterRate != 0) { - var slot = arr[i]; - if (slot.Species == 0) - continue; - string form = slot.Form == 0 ? string.Empty : $"-{slot.Form}"; - yield return $"{i:00}\t{species[slot.Species]}{form}\t{slot.Probability}"; + yield return nameof(enc.WaterTable); + yield return GetSubSummary(enc.WaterTableLevelMin, enc.WaterTableLevelMax, enc.WaterTableEncounterRate, enc.WaterSpawnCountMax); + foreach (var line in GetLines(enc.WaterTable, species)) + yield return line; + } + if (enc.OldRodTableEncounterRate != 0) + { + yield return nameof(enc.OldRodTable); + yield return GetSubSummary(enc.OldRodTableLevelMin, enc.OldRodTableLevelMax, enc.OldRodTableEncounterRate); + foreach (var line in GetLines(enc.OldRodTable, species)) + yield return line; + } + if (enc.GoodRodTableEncounterRate != 0) + { + yield return nameof(enc.GoodRodTable); + yield return GetSubSummary(enc.GoodRodTableLevelMin, enc.GoodRodTableLevelMax, enc.GoodRodTableEncounterRate); + foreach (var line in GetLines(enc.GoodRodTable, species)) + yield return line; + } + if (enc.SuperRodTableEncounterRate != 0) + { + yield return nameof(enc.SuperRodTable); + yield return GetSubSummary(enc.SuperRodTableLevelMin, enc.SuperRodTableLevelMax, enc.SuperRodTableEncounterRate); + foreach (var line in GetLines(enc.SuperRodTable, species)) + yield return line; + } + if (enc.SkyTableEncounterRate != 0) + { + yield return nameof(enc.SkyTable); + yield return GetSubSummary(enc.SkyTableLevelMin, enc.SkyTableLevelMax, enc.SkyTableEncounterRate, enc.SkySpawnCountMax); + foreach (var line in GetLines(enc.SkyTable, species)) + yield return line; } yield return string.Empty; } } + + private static string GetSubSummary(int min, int max, int rate) => $"lv{min}-{max}, rate: {rate}"; + private static string GetSubSummary(int min, int max, int rate, int count) => GetSubSummary(min, max, rate) + $", max count: {count}"; + + private static IEnumerable GetLines(IReadOnlyList arr, IReadOnlyList species) + { + for (var i = 0; i < arr.Count; i++) + { + var slot = arr[i]; + if (slot.Species == 0) + continue; + string form = slot.Form == 0 ? string.Empty : $"-{slot.Form}"; + yield return $"{i:00}\t{species[slot.Species]}{form}\t{slot.Probability}"; + } + yield return string.Empty; + } } diff --git a/pkNX.Structures.FlatBuffers/Gen7/ShopInventory.cs b/pkNX.Structures.FlatBuffers/Gen7/ShopInventory.cs index 2fc7e75f..c55690e2 100644 --- a/pkNX.Structures.FlatBuffers/Gen7/ShopInventory.cs +++ b/pkNX.Structures.FlatBuffers/Gen7/ShopInventory.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel; using System.Linq; using FlatSharp.Attributes; @@ -10,151 +10,150 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class ShopInventory { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class ShopInventory - { - [FlatBufferItem(0)] public Shop1[] Shop1 { get; set; } - [FlatBufferItem(1)] public Shop2[] Shop2 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class Shop1 - { - [FlatBufferItem(0)] public ulong Hash { get; set; } - [FlatBufferItem(1)] public Inventory Inventory { get; set; } - - public override string ToString() => $"{Hash:X16} - {Inventory}"; - - public readonly Dictionary LGPE = new() - { - { 14688060730225415067, "Celadon Department Store [TMs]" }, - { 04251032178319698087, "Celadon Department Store [Evolution Stones]" }, - }; - - public readonly Dictionary SWSH = new() - { - // Galar - { 0x1F3FF031A3A24490, "Poké Mart [0 Badges, Before Catching Tutorial]" }, - { 0x8E308F85B43038B4, "Motostoke [Upper Tier, TMs]" }, - { 0x8E309085B4303A67, "Hammerlocke [West, TMs]" }, - { 0x8E309185B4303C1A, "Hammerlocke [East, TMs]" }, - { 0x8E309285B4303DCD, "Wyndon [North, TMs]" }, - { 0x8E308B85B43031E8, "Battle Tower [TMs]" }, - { 0xCBD67969D873539B, "Motostoke [Lower Tier, Miscellaneous]" }, - { 0xCBD67869D87351E8, "Hammerlocke [South, Miscellaneous]" }, - { 0xCBD67B69D8735701, "Wyndon [South, Miscellaneous]" }, - { 0x04D7046DA09D3C78, "Hulbury [Herb Shop]" }, - { 0x4B2F9E98DDCB0707, "Hulbury [Incense Shop]" }, - { 0xE379CDF67A297070, "Wedgehurst [Berry Shop]" }, - { 0x3FD7A44219BF30BB, "Hammerlocke [South, BP Shop]" }, - { 0x3FD7A34219BF2F08, "Battle Tower [Battle Items]" }, - { 0x3FD7A64219BF3421, "Battle Tower [Nature Mints]" }, - // 0xD1BEA92EAAE52B5A -- Wishing Piece + X Items... unused? - - // Wild Area - // next 84 tables are all Ingredient Sellers with similar inventories that rotate daily; don't bother labeling (why hardcode everything GF?) - { 0xD1BEAA2EAAE52D0D, "Watt Trader 1 [Net Ball]" }, - { 0xD1BEA72EAAE527F4, "Watt Trader 1 [Dive Ball]" }, - { 0xD1BEA82EAAE529A7, "Watt Trader 1 [Nest Ball]" }, - { 0xD1BEA52EAAE5248E, "Watt Trader 1 [Repeat Ball]" }, - { 0xD1BEA62EAAE52641, "Watt Trader 1 [Timer Ball]" }, - { 0xD1BEA32EAAE52128, "Watt Trader 1 [Luxury Ball]" }, - { 0xD1BEA42EAAE522DB, "Watt Trader 1 [Dusk Ball]" }, - { 0xD1BEA12EAAE51DC2, "Watt Trader 1 [Heal Ball]" }, - { 0xD1BEA22EAAE51F75, "Watt Trader 1 [Quick Ball]" }, - - { 0xD1C20F2EAAE80E83, "Watt Trader 2 [Net Ball]" }, - { 0xD1C20E2EAAE80CD0, "Watt Trader 2 [Dive Ball]" }, - { 0xD1C2112EAAE811E9, "Watt Trader 2 [Nest Ball]" }, - { 0xD1C2102EAAE81036, "Watt Trader 2 [Repeat Ball]" }, - { 0xD1C2132EAAE8154F, "Watt Trader 2 [Timer Ball]" }, - { 0xD1C2122EAAE8139C, "Watt Trader 2 [Luxury Ball]" }, - { 0xD1C2152EAAE818B5, "Watt Trader 2 [Dusk Ball]" }, - { 0xD1C2142EAAE81702, "Watt Trader 2 [Heal Ball]" }, - { 0xD1C2172EAAE81C1B, "Watt Trader 2 [Quick Ball]" }, - - { 0xD1C2162EAAE81A68, "Watt Trader 3 [Net Ball]" }, - { 0xD1B79D2EAADEF848, "Watt Trader 3 [Dive Ball]" }, - { 0xD1B79E2EAADEF9FB, "Watt Trader 3 [Nest Ball]" }, - { 0xD1B79F2EAADEFBAE, "Watt Trader 3 [Repeat Ball]" }, - { 0xD1B7A02EAADEFD61, "Watt Trader 3 [Timer Ball]" }, - { 0xD1B7A12EAADEFF14, "Watt Trader 3 [Luxury Ball]" }, - { 0xD1B7A22EAADF00C7, "Watt Trader 3 [Dusk Ball]" }, - { 0xD1B7A32EAADF027A, "Watt Trader 3 [Heal Ball]" }, - { 0xD1B7A42EAADF042D, "Watt Trader 3 [Quick Ball]" }, - - { 0xD1B7952EAADEEAB0, "Watt Trader 4 [Net Ball]" }, - { 0xD1B7962EAADEEC63, "Watt Trader 4 [Dive Ball]" }, - { 0xD1BB232EAAE211D1, "Watt Trader 4 [Nest Ball]" }, - { 0xD1BB222EAAE2101E, "Watt Trader 4 [Repeat Ball]" }, - { 0xD1BB212EAAE20E6B, "Watt Trader 4 [Timer Ball]" }, - { 0xD1BB202EAAE20CB8, "Watt Trader 4 [Luxury Ball]" }, - { 0xD1BB272EAAE2189D, "Watt Trader 4 [Dusk Ball]" }, - { 0xD1BB262EAAE216EA, "Watt Trader 4 [Heal Ball]" }, - { 0xD1BB252EAAE21537, "Watt Trader 4 [Quick Ball]" }, - - { 0xD1BB242EAAE21384, "Watt Trader 5 [Net Ball]" }, - { 0xD1BB1B2EAAE20439, "Watt Trader 5 [Dive Ball]" }, - { 0xD1BB1A2EAAE20286, "Watt Trader 5 [Nest Ball]" }, - { 0xD1CC212EAAF0819E, "Watt Trader 5 [Repeat Ball]" }, - { 0xD1CC222EAAF08351, "Watt Trader 5 [Timer Ball]" }, - { 0xD1CC1F2EAAF07E38, "Watt Trader 5 [Luxury Ball]" }, - { 0xD1CC202EAAF07FEB, "Watt Trader 5 [Dusk Ball]" }, - { 0xD1CC252EAAF0886A, "Watt Trader 5 [Heal Ball]" }, - { 0xD1CC262EAAF08A1D, "Watt Trader 5 [Quick Ball]" }, - - { 0xD1CC232EAAF08504, "Watt Trader 6 [Net Ball]" }, - { 0xD1CC242EAAF086B7, "Watt Trader 6 [Dive Ball]" }, - { 0xD1CC192EAAF07406, "Watt Trader 6 [Repeat Ball]" }, - { 0xD1CC1A2EAAF075B9, "Watt Trader 6 [Quick Ball]" }, - { 0xD1CFA72EAAF39B27, "Watt Trader 6 [Heal Ball]" }, - - // Isle of Armor - { 0x5870C0165650F6A5, "Fields of Honor [Berry Shop]" }, - - // Crown Tundra - { 0x81DA6390A03C7E3F, "Freezington [Peddler]" }, - { 0x813C350B0B777943, "Snowslide Slope [Today's Highlight, TR00-TR09]" }, - { 0x813C360B0B777AF6, "Snowslide Slope [Today's Highlight, TR10-TR19]" }, - { 0x813C370B0B777CA9, "Snowslide Slope [Today's Highlight, TR20-TR29]" }, - { 0x813C380B0B777E5C, "Snowslide Slope [Today's Highlight, TR30-TR39]" }, - { 0x813C390B0B77800F, "Snowslide Slope [Today's Highlight, TR40-TR49]" }, - { 0x813C3A0B0B7781C2, "Snowslide Slope [Today's Highlight, TR50-TR59]" }, - { 0x813C3B0B0B778375, "Snowslide Slope [Today's Highlight, TR60-TR69]" }, - { 0x813C3C0B0B778528, "Snowslide Slope [Today's Highlight, TR70-TR79]" }, - { 0x813C3D0B0B7786DB, "Snowslide Slope [Today's Highlight, TR80-TR89]" }, - { 0x813F3A0B0B79B799, "Snowslide Slope [Today's Highlight, TR90-TR99]" }, - { 0xF49C86F8683842BF, "Max Lair [Dynite Ore Trader]" }, - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class Shop2 - { - [FlatBufferItem(0)] public ulong Hash { get; set; } - [FlatBufferItem(1)] public Inventory[] Inventories { get; set; } - - public override string ToString() => $"{Hash:X16} - {string.Join(", ", Inventories.Select(z => z.ToString()))}"; - - public readonly Dictionary LGPE = new() - { - { 0x66CA73B2966BB871, "Poké Mart Inventories [0-8 Badges]" }, - }; - - public readonly Dictionary SWSH = new() - { - { 0x66CA73B2966BB871, "Poké Mart Inventories [0-8 Badges]" }, - { 0x5870BD165650F18C, "Fields of Honor [Watt Trader, 0-8 Badges]" }, - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class Inventory - { - [FlatBufferItem(0)] public int[] Items { get; set; } - - public override string ToString() => $"{string.Join(",", Items.Select(z => z.ToString()))}"; - } + [FlatBufferItem(0)] public Shop1[] Shop1 { get; set; } + [FlatBufferItem(1)] public Shop2[] Shop2 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class Shop1 +{ + [FlatBufferItem(0)] public ulong Hash { get; set; } + [FlatBufferItem(1)] public Inventory Inventory { get; set; } + + public override string ToString() => $"{Hash:X16} - {Inventory}"; + + public readonly Dictionary LGPE = new() + { + { 14688060730225415067, "Celadon Department Store [TMs]" }, + { 04251032178319698087, "Celadon Department Store [Evolution Stones]" }, + }; + + public readonly Dictionary SWSH = new() + { + // Galar + { 0x1F3FF031A3A24490, "Poké Mart [0 Badges, Before Catching Tutorial]" }, + { 0x8E308F85B43038B4, "Motostoke [Upper Tier, TMs]" }, + { 0x8E309085B4303A67, "Hammerlocke [West, TMs]" }, + { 0x8E309185B4303C1A, "Hammerlocke [East, TMs]" }, + { 0x8E309285B4303DCD, "Wyndon [North, TMs]" }, + { 0x8E308B85B43031E8, "Battle Tower [TMs]" }, + { 0xCBD67969D873539B, "Motostoke [Lower Tier, Miscellaneous]" }, + { 0xCBD67869D87351E8, "Hammerlocke [South, Miscellaneous]" }, + { 0xCBD67B69D8735701, "Wyndon [South, Miscellaneous]" }, + { 0x04D7046DA09D3C78, "Hulbury [Herb Shop]" }, + { 0x4B2F9E98DDCB0707, "Hulbury [Incense Shop]" }, + { 0xE379CDF67A297070, "Wedgehurst [Berry Shop]" }, + { 0x3FD7A44219BF30BB, "Hammerlocke [South, BP Shop]" }, + { 0x3FD7A34219BF2F08, "Battle Tower [Battle Items]" }, + { 0x3FD7A64219BF3421, "Battle Tower [Nature Mints]" }, + // 0xD1BEA92EAAE52B5A -- Wishing Piece + X Items... unused? + + // Wild Area + // next 84 tables are all Ingredient Sellers with similar inventories that rotate daily; don't bother labeling (why hardcode everything GF?) + { 0xD1BEAA2EAAE52D0D, "Watt Trader 1 [Net Ball]" }, + { 0xD1BEA72EAAE527F4, "Watt Trader 1 [Dive Ball]" }, + { 0xD1BEA82EAAE529A7, "Watt Trader 1 [Nest Ball]" }, + { 0xD1BEA52EAAE5248E, "Watt Trader 1 [Repeat Ball]" }, + { 0xD1BEA62EAAE52641, "Watt Trader 1 [Timer Ball]" }, + { 0xD1BEA32EAAE52128, "Watt Trader 1 [Luxury Ball]" }, + { 0xD1BEA42EAAE522DB, "Watt Trader 1 [Dusk Ball]" }, + { 0xD1BEA12EAAE51DC2, "Watt Trader 1 [Heal Ball]" }, + { 0xD1BEA22EAAE51F75, "Watt Trader 1 [Quick Ball]" }, + + { 0xD1C20F2EAAE80E83, "Watt Trader 2 [Net Ball]" }, + { 0xD1C20E2EAAE80CD0, "Watt Trader 2 [Dive Ball]" }, + { 0xD1C2112EAAE811E9, "Watt Trader 2 [Nest Ball]" }, + { 0xD1C2102EAAE81036, "Watt Trader 2 [Repeat Ball]" }, + { 0xD1C2132EAAE8154F, "Watt Trader 2 [Timer Ball]" }, + { 0xD1C2122EAAE8139C, "Watt Trader 2 [Luxury Ball]" }, + { 0xD1C2152EAAE818B5, "Watt Trader 2 [Dusk Ball]" }, + { 0xD1C2142EAAE81702, "Watt Trader 2 [Heal Ball]" }, + { 0xD1C2172EAAE81C1B, "Watt Trader 2 [Quick Ball]" }, + + { 0xD1C2162EAAE81A68, "Watt Trader 3 [Net Ball]" }, + { 0xD1B79D2EAADEF848, "Watt Trader 3 [Dive Ball]" }, + { 0xD1B79E2EAADEF9FB, "Watt Trader 3 [Nest Ball]" }, + { 0xD1B79F2EAADEFBAE, "Watt Trader 3 [Repeat Ball]" }, + { 0xD1B7A02EAADEFD61, "Watt Trader 3 [Timer Ball]" }, + { 0xD1B7A12EAADEFF14, "Watt Trader 3 [Luxury Ball]" }, + { 0xD1B7A22EAADF00C7, "Watt Trader 3 [Dusk Ball]" }, + { 0xD1B7A32EAADF027A, "Watt Trader 3 [Heal Ball]" }, + { 0xD1B7A42EAADF042D, "Watt Trader 3 [Quick Ball]" }, + + { 0xD1B7952EAADEEAB0, "Watt Trader 4 [Net Ball]" }, + { 0xD1B7962EAADEEC63, "Watt Trader 4 [Dive Ball]" }, + { 0xD1BB232EAAE211D1, "Watt Trader 4 [Nest Ball]" }, + { 0xD1BB222EAAE2101E, "Watt Trader 4 [Repeat Ball]" }, + { 0xD1BB212EAAE20E6B, "Watt Trader 4 [Timer Ball]" }, + { 0xD1BB202EAAE20CB8, "Watt Trader 4 [Luxury Ball]" }, + { 0xD1BB272EAAE2189D, "Watt Trader 4 [Dusk Ball]" }, + { 0xD1BB262EAAE216EA, "Watt Trader 4 [Heal Ball]" }, + { 0xD1BB252EAAE21537, "Watt Trader 4 [Quick Ball]" }, + + { 0xD1BB242EAAE21384, "Watt Trader 5 [Net Ball]" }, + { 0xD1BB1B2EAAE20439, "Watt Trader 5 [Dive Ball]" }, + { 0xD1BB1A2EAAE20286, "Watt Trader 5 [Nest Ball]" }, + { 0xD1CC212EAAF0819E, "Watt Trader 5 [Repeat Ball]" }, + { 0xD1CC222EAAF08351, "Watt Trader 5 [Timer Ball]" }, + { 0xD1CC1F2EAAF07E38, "Watt Trader 5 [Luxury Ball]" }, + { 0xD1CC202EAAF07FEB, "Watt Trader 5 [Dusk Ball]" }, + { 0xD1CC252EAAF0886A, "Watt Trader 5 [Heal Ball]" }, + { 0xD1CC262EAAF08A1D, "Watt Trader 5 [Quick Ball]" }, + + { 0xD1CC232EAAF08504, "Watt Trader 6 [Net Ball]" }, + { 0xD1CC242EAAF086B7, "Watt Trader 6 [Dive Ball]" }, + { 0xD1CC192EAAF07406, "Watt Trader 6 [Repeat Ball]" }, + { 0xD1CC1A2EAAF075B9, "Watt Trader 6 [Quick Ball]" }, + { 0xD1CFA72EAAF39B27, "Watt Trader 6 [Heal Ball]" }, + + // Isle of Armor + { 0x5870C0165650F6A5, "Fields of Honor [Berry Shop]" }, + + // Crown Tundra + { 0x81DA6390A03C7E3F, "Freezington [Peddler]" }, + { 0x813C350B0B777943, "Snowslide Slope [Today's Highlight, TR00-TR09]" }, + { 0x813C360B0B777AF6, "Snowslide Slope [Today's Highlight, TR10-TR19]" }, + { 0x813C370B0B777CA9, "Snowslide Slope [Today's Highlight, TR20-TR29]" }, + { 0x813C380B0B777E5C, "Snowslide Slope [Today's Highlight, TR30-TR39]" }, + { 0x813C390B0B77800F, "Snowslide Slope [Today's Highlight, TR40-TR49]" }, + { 0x813C3A0B0B7781C2, "Snowslide Slope [Today's Highlight, TR50-TR59]" }, + { 0x813C3B0B0B778375, "Snowslide Slope [Today's Highlight, TR60-TR69]" }, + { 0x813C3C0B0B778528, "Snowslide Slope [Today's Highlight, TR70-TR79]" }, + { 0x813C3D0B0B7786DB, "Snowslide Slope [Today's Highlight, TR80-TR89]" }, + { 0x813F3A0B0B79B799, "Snowslide Slope [Today's Highlight, TR90-TR99]" }, + { 0xF49C86F8683842BF, "Max Lair [Dynite Ore Trader]" }, + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class Shop2 +{ + [FlatBufferItem(0)] public ulong Hash { get; set; } + [FlatBufferItem(1)] public Inventory[] Inventories { get; set; } + + public override string ToString() => $"{Hash:X16} - {string.Join(", ", Inventories.Select(z => z.ToString()))}"; + + public readonly Dictionary LGPE = new() + { + { 0x66CA73B2966BB871, "Poké Mart Inventories [0-8 Badges]" }, + }; + + public readonly Dictionary SWSH = new() + { + { 0x66CA73B2966BB871, "Poké Mart Inventories [0-8 Badges]" }, + { 0x5870BD165650F18C, "Fields of Honor [Watt Trader, 0-8 Badges]" }, + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class Inventory +{ + [FlatBufferItem(0)] public int[] Items { get; set; } + + public override string ToString() => $"{string.Join(",", Items.Select(z => z.ToString()))}"; } diff --git a/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerPoke8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerPoke8Archive.cs index 72546f94..8e4db2f0 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerPoke8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerPoke8Archive.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,42 +8,41 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers -{ - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class BattleTowerPoke8Archive : IFlatBufferArchive - { - [FlatBufferItem(0)] public BattleTowerPoke8[] Table { get; set; } - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class BattleTowerPoke8 - { - [FlatBufferItem(00)] public bool Field_00 { get; set; } - [FlatBufferItem(01)] public bool Field_01 { get; set; } - [FlatBufferItem(02)] public bool Field_02 { get; set; } - [FlatBufferItem(03)] public uint Field_03 { get; set; } - [FlatBufferItem(04)] public bool Field_04 { get; set; } - [FlatBufferItem(05)] public bool Field_05 { get; set; } - [FlatBufferItem(06)] public bool Field_06 { get; set; } - [FlatBufferItem(07)] public uint Form { get; set; } - [FlatBufferItem(08)] public uint Field_08 { get; set; } - [FlatBufferItem(09)] public uint HeldItem { get; set; } - [FlatBufferItem(10)] public uint Species { get; set; } - [FlatBufferItem(11)] public uint EntryID { get; set; } - [FlatBufferItem(12)] public uint Field_0C { get; set; } - [FlatBufferItem(13)] public uint Nature { get; set; } - [FlatBufferItem(14)] public uint Field_0E { get; set; } - [FlatBufferItem(15)] public uint IV_HP { get; set; } - [FlatBufferItem(16)] public uint IV_ATK { get; set; } - [FlatBufferItem(17)] public uint IV_DEF { get; set; } - [FlatBufferItem(18)] public uint IV_SPA { get; set; } - [FlatBufferItem(19)] public uint IV_SPD { get; set; } - [FlatBufferItem(20)] public uint IV_SPE { get; set; } - [FlatBufferItem(21)] public uint Field_15 { get; set; } - [FlatBufferItem(22)] public uint Move0 { get; set; } - [FlatBufferItem(23)] public uint Move1 { get; set; } - [FlatBufferItem(24)] public uint Move2 { get; set; } - [FlatBufferItem(25)] public uint Move3 { get; set; } - } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class BattleTowerPoke8Archive : IFlatBufferArchive +{ + [FlatBufferItem(0)] public BattleTowerPoke8[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class BattleTowerPoke8 +{ + [FlatBufferItem(00)] public bool Field_00 { get; set; } + [FlatBufferItem(01)] public bool Field_01 { get; set; } + [FlatBufferItem(02)] public bool Field_02 { get; set; } + [FlatBufferItem(03)] public uint Field_03 { get; set; } + [FlatBufferItem(04)] public bool Field_04 { get; set; } + [FlatBufferItem(05)] public bool Field_05 { get; set; } + [FlatBufferItem(06)] public bool Field_06 { get; set; } + [FlatBufferItem(07)] public uint Form { get; set; } + [FlatBufferItem(08)] public uint Field_08 { get; set; } + [FlatBufferItem(09)] public uint HeldItem { get; set; } + [FlatBufferItem(10)] public uint Species { get; set; } + [FlatBufferItem(11)] public uint EntryID { get; set; } + [FlatBufferItem(12)] public uint Field_0C { get; set; } + [FlatBufferItem(13)] public uint Nature { get; set; } + [FlatBufferItem(14)] public uint Field_0E { get; set; } + [FlatBufferItem(15)] public uint IV_HP { get; set; } + [FlatBufferItem(16)] public uint IV_ATK { get; set; } + [FlatBufferItem(17)] public uint IV_DEF { get; set; } + [FlatBufferItem(18)] public uint IV_SPA { get; set; } + [FlatBufferItem(19)] public uint IV_SPD { get; set; } + [FlatBufferItem(20)] public uint IV_SPE { get; set; } + [FlatBufferItem(21)] public uint Field_15 { get; set; } + [FlatBufferItem(22)] public uint Move0 { get; set; } + [FlatBufferItem(23)] public uint Move1 { get; set; } + [FlatBufferItem(24)] public uint Move2 { get; set; } + [FlatBufferItem(25)] public uint Move3 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerTrainer8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerTrainer8Archive.cs index 245d2715..e4d5edea 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerTrainer8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/BattleTower/BattleTowerTrainer8Archive.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,22 +8,21 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers -{ - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class BattleTowerTrainer8Archive - { - [FlatBufferItem(0)] public BattleTowerTrainer8[] Entries { get; set; } - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class BattleTowerTrainer8 - { - [FlatBufferItem(0)] public ulong Hash0 { get; set; } - [FlatBufferItem(1)] public ulong Hash1 { get; set; } - [FlatBufferItem(2)] public ushort EntryID { get; set; } - [FlatBufferItem(3)] public ushort Field_03 { get; set; } - [FlatBufferItem(4)] public ushort Field_04 { get; set; } - [FlatBufferItem(5)] public ushort[] Choices { get; set; } - } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class BattleTowerTrainer8Archive +{ + [FlatBufferItem(0)] public BattleTowerTrainer8[] Entries { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class BattleTowerTrainer8 +{ + [FlatBufferItem(0)] public ulong Hash0 { get; set; } + [FlatBufferItem(1)] public ulong Hash1 { get; set; } + [FlatBufferItem(2)] public ushort EntryID { get; set; } + [FlatBufferItem(3)] public ushort Field_03 { get; set; } + [FlatBufferItem(4)] public ushort Field_04 { get; set; } + [FlatBufferItem(5)] public ushort[] Choices { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Gift/EncounterGift8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Gift/EncounterGift8Archive.cs index c5454098..e7490176 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Gift/EncounterGift8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Gift/EncounterGift8Archive.cs @@ -8,11 +8,10 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterGift8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterGift8Archive : IFlatBufferArchive - { - [FlatBufferItem(0)] public EncounterGift8[] Table { get; set; } - } + [FlatBufferItem(0)] public EncounterGift8[] Table { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Gift/GiftEncounter8.cs b/pkNX.Structures.FlatBuffers/Gen8/Gift/GiftEncounter8.cs index 0943ad8a..e5597d00 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Gift/GiftEncounter8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Gift/GiftEncounter8.cs @@ -11,122 +11,121 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterGift8 { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterGift8 + [FlatBufferItem(00)] public int IsEgg { get; set; } + [FlatBufferItem(01)] public byte Form { get; set; } + [FlatBufferItem(02)] public byte DynamaxLevel { get; set; } + [FlatBufferItem(03)] public int BallItemID { get; set; } + [FlatBufferItem(04)] public byte Field_04 { get; set; } + [FlatBufferItem(05)] public ulong Hash1 { get; set; } + [FlatBufferItem(06)] public bool CanGigantamax { get; set; } + [FlatBufferItem(07)] public int HeldItem { get; set; } + [FlatBufferItem(08)] public byte Level { get; set; } + [FlatBufferItem(09)] public int Species { get; set; } + [FlatBufferItem(10)] public byte Field_0A { get; set; } + [FlatBufferItem(11)] public byte MemoryCode { get; set; } + [FlatBufferItem(12)] public ushort MemoryData { get; set; } + [FlatBufferItem(13)] public byte MemoryFeel { get; set; } + [FlatBufferItem(14)] public byte MemoryLevel { get; set; } + [FlatBufferItem(15)] public ulong OtNameID { get; set; } + [FlatBufferItem(16)] public int OtGender { get; set; } + [FlatBufferItem(17)] public int ShinyLock { get; set; } + [FlatBufferItem(18)] public int Nature { get; set; } + [FlatBufferItem(19)] public byte Gender { get; set; } + [FlatBufferItem(20)] public sbyte IV_SPE { get; set; } + [FlatBufferItem(21)] public sbyte IV_ATK { get; set; } + [FlatBufferItem(22)] public sbyte IV_DEF { get; set; } + [FlatBufferItem(23)] public sbyte IV_HP { get; set; } + [FlatBufferItem(24)] public sbyte IV_SPA { get; set; } + [FlatBufferItem(25)] public sbyte IV_SPD { get; set; } + [FlatBufferItem(26)] public int Ability { get; set; } + [FlatBufferItem(27)] public int SpecialMove { get; set; } + + public Species SpeciesID => (Species)Species; + + public static readonly int[] BallToItem = { - [FlatBufferItem(00)] public int IsEgg { get; set; } - [FlatBufferItem(01)] public byte Form { get; set; } - [FlatBufferItem(02)] public byte DynamaxLevel { get; set; } - [FlatBufferItem(03)] public int BallItemID { get; set; } - [FlatBufferItem(04)] public byte Field_04 { get; set; } - [FlatBufferItem(05)] public ulong Hash1 { get; set; } - [FlatBufferItem(06)] public bool CanGigantamax { get; set; } - [FlatBufferItem(07)] public int HeldItem { get; set; } - [FlatBufferItem(08)] public byte Level { get; set; } - [FlatBufferItem(09)] public int Species { get; set; } - [FlatBufferItem(10)] public byte Field_0A { get; set; } - [FlatBufferItem(11)] public byte MemoryCode { get; set; } - [FlatBufferItem(12)] public ushort MemoryData { get; set; } - [FlatBufferItem(13)] public byte MemoryFeel { get; set; } - [FlatBufferItem(14)] public byte MemoryLevel { get; set; } - [FlatBufferItem(15)] public ulong OtNameID { get; set; } - [FlatBufferItem(16)] public int OtGender { get; set; } - [FlatBufferItem(17)] public int ShinyLock { get; set; } - [FlatBufferItem(18)] public int Nature { get; set; } - [FlatBufferItem(19)] public byte Gender { get; set; } - [FlatBufferItem(20)] public sbyte IV_SPE { get; set; } - [FlatBufferItem(21)] public sbyte IV_ATK { get; set; } - [FlatBufferItem(22)] public sbyte IV_DEF { get; set; } - [FlatBufferItem(23)] public sbyte IV_HP { get; set; } - [FlatBufferItem(24)] public sbyte IV_SPA { get; set; } - [FlatBufferItem(25)] public sbyte IV_SPD { get; set; } - [FlatBufferItem(26)] public int Ability { get; set; } - [FlatBufferItem(27)] public int SpecialMove { get; set; } + 000, // None + 001, // Master + 002, // Ultra + 003, // Great + 004, // Poke + 005, // Safari + 006, // Net + 007, // Dive + 008, // Nest + 009, // Repeat + 010, // Timer + 011, // Luxury + 012, // Premier + 013, // Dusk + 014, // Heal + 015, // Quick + 016, // Cherish + 492, // Fast + 493, // Level + 494, // Lure + 495, // Heavy + 496, // Love + 497, // Friend + 498, // Moon + 499, // Sport + 576, // Dream + 851, // Beast + }; - public Species SpeciesID => (Species)Species; + public Ball Ball + { + get => (Ball)Array.IndexOf(BallToItem, BallItemID); + set => BallItemID = BallToItem[(int)value]; + } - public static readonly int[] BallToItem = + public int[] IVs + { + get => new int[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; + set { - 000, // None - 001, // Master - 002, // Ultra - 003, // Great - 004, // Poke - 005, // Safari - 006, // Net - 007, // Dive - 008, // Nest - 009, // Repeat - 010, // Timer - 011, // Luxury - 012, // Premier - 013, // Dusk - 014, // Heal - 015, // Quick - 016, // Cherish - 492, // Fast - 493, // Level - 494, // Lure - 495, // Heavy - 496, // Love - 497, // Friend - 498, // Moon - 499, // Sport - 576, // Dream - 851, // Beast - }; - - public Ball Ball - { - get => (Ball)Array.IndexOf(BallToItem, BallItemID); - set => BallItemID = BallToItem[(int)value]; - } - - public int[] IVs - { - get => new int[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; - set - { - if (value?.Length != 6) return; - IV_HP = (sbyte)value[0]; - IV_ATK = (sbyte)value[1]; - IV_DEF = (sbyte)value[2]; - IV_SPE = (sbyte)value[3]; - IV_SPA = (sbyte)value[4]; - IV_SPD = (sbyte)value[5]; - } - } - - public string GetSummary(IReadOnlyList species) - { - var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; - var ability = Ability switch - { - 0 => string.Empty, - 3 => ", Ability = 4", - _ => $", Ability = {Ability}", - }; - - var ivs = IVs[0] switch - { - 31 when IVs.All(z => z == 31) => ", FlawlessIVCount = 6", - -1 when IVs.All(z => z == -1) => string.Empty, - -4 => ", FlawlessIVCount = 3", - _ => $", IVs = new[]{{{string.Join(",", IVs)}}}", - }; - - var gender = (FixedGender)Gender == FixedGender.Random ? string.Empty : $", Gender = {Gender - 1}"; - var nature = Nature == (int)Structures.Nature.Random25 ? string.Empty : $", Nature = Nature.{(Nature)Nature}"; - var altform = Form == 0 ? string.Empty : $", Form = {Form:00}"; - var shiny = (Shiny)ShinyLock == Shiny.Random ? string.Empty : $", Shiny = {(Shiny)ShinyLock}"; - var giga = !CanGigantamax ? string.Empty : ", CanGigantamax = true"; - var dyna = DynamaxLevel == 0 ? string.Empty : $", DynamaxLevel = {DynamaxLevel}"; - var ball = Ball == Ball.Poke ? string.Empty : $", Ball = {(int)Ball}"; - - return - $" new(SWSH) {{ Gift = true, Species = {Species:000}, Level = {Level:00}, Location = -01{ivs}{shiny}{gender}{ability}{nature}{altform}{giga}{dyna}{ball} }},{comment}"; + if (value?.Length != 6) return; + IV_HP = (sbyte)value[0]; + IV_ATK = (sbyte)value[1]; + IV_DEF = (sbyte)value[2]; + IV_SPE = (sbyte)value[3]; + IV_SPA = (sbyte)value[4]; + IV_SPD = (sbyte)value[5]; } } + + public string GetSummary(IReadOnlyList species) + { + var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; + var ability = Ability switch + { + 0 => string.Empty, + 3 => ", Ability = 4", + _ => $", Ability = {Ability}", + }; + + var ivs = IVs[0] switch + { + 31 when IVs.All(z => z == 31) => ", FlawlessIVCount = 6", + -1 when IVs.All(z => z == -1) => string.Empty, + -4 => ", FlawlessIVCount = 3", + _ => $", IVs = new[]{{{string.Join(",", IVs)}}}", + }; + + var gender = (FixedGender)Gender == FixedGender.Random ? string.Empty : $", Gender = {Gender - 1}"; + var nature = Nature == (int)Structures.Nature.Random25 ? string.Empty : $", Nature = Nature.{(Nature)Nature}"; + var altform = Form == 0 ? string.Empty : $", Form = {Form:00}"; + var shiny = (Shiny)ShinyLock == Shiny.Random ? string.Empty : $", Shiny = {(Shiny)ShinyLock}"; + var giga = !CanGigantamax ? string.Empty : ", CanGigantamax = true"; + var dyna = DynamaxLevel == 0 ? string.Empty : $", DynamaxLevel = {DynamaxLevel}"; + var ball = Ball == Ball.Poke ? string.Empty : $", Ball = {(int)Ball}"; + + return + $" new(SWSH) {{ Gift = true, Species = {Species:000}, Level = {Level:00}, Location = -01{ivs}{shiny}{gender}{ability}{nature}{altform}{giga}{dyna}{ball} }},{comment}"; + } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterNest8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterNest8Archive.cs index 8a6173ed..bfb9a741 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterNest8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterNest8Archive.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -11,183 +11,182 @@ // ReSharper disable UnusedMember.Global #nullable disable -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterNest8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterNest8Archive : IFlatBufferArchive + [FlatBufferItem(0)] public EncounterNest8Table[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterNest8Table +{ + [FlatBufferItem(0)] public ulong TableID { get; set; } + [FlatBufferItem(1)] public int GameVersion { get; set; } + [FlatBufferItem(2)] public EncounterNest8[] Entries { get; set; } + + public string GetSummarySimple() { - [FlatBufferItem(0)] public EncounterNest8Table[] Table { get; set; } + var tableID = TableID.ToString("X16"); + var tableData = TableUtil.GetTable(Entries); + + return tableID + Environment.NewLine + tableData + Environment.NewLine; } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterNest8Table + public IEnumerable GetSummary(IReadOnlyList species, int index) { - [FlatBufferItem(0)] public ulong TableID { get; set; } - [FlatBufferItem(1)] public int GameVersion { get; set; } - [FlatBufferItem(2)] public EncounterNest8[] Entries { get; set; } - - public string GetSummarySimple() + foreach (var entry in Entries) { - var tableID = TableID.ToString("X16"); - var tableData = TableUtil.GetTable(Entries); - - return tableID + Environment.NewLine + tableData + Environment.NewLine; + foreach (var summary in Summary(entry)) + yield return summary; } - public IEnumerable GetSummary(IReadOnlyList species, int index) + yield return string.Empty; + + IEnumerable Summary(EncounterNest8 e) { - foreach (var entry in Entries) + var comment = $" // {species[e.Species]}{(e.Form == 0 ? string.Empty : "-" + e.Form)}"; + var gender = e.Gender == 0 ? string.Empty : $", Gender = {e.Gender - 1}"; + var altform = e.Form == 0 ? string.Empty : $", Form = {e.Form}"; + var giga = !e.IsGigantamax ? string.Empty : ", CanGigantamax = true"; + var ability = e.Ability switch { - foreach (var summary in Summary(entry)) - yield return summary; - } + 2 => "A2", + 3 => "A3", + 4 => "A4", + _ => throw new Exception() + }; + var flawless = e.FlawlessIVs; - yield return string.Empty; + // calc min/max ranks + int min = e.MinRank; + int max = e.MaxRank; - IEnumerable Summary(EncounterNest8 e) + int curMin = -1; + for (int i = min; i >= 0 && i <= max; i++) { - var comment = $" // {species[e.Species]}{(e.Form == 0 ? string.Empty : "-" + e.Form)}"; - var gender = e.Gender == 0 ? string.Empty : $", Gender = {e.Gender - 1}"; - var altform = e.Form == 0 ? string.Empty : $", Form = {e.Form}"; - var giga = !e.IsGigantamax ? string.Empty : ", CanGigantamax = true"; - var ability = e.Ability switch + if (e.Probabilities[i] != 0) { - 2 => "A2", - 3 => "A3", - 4 => "A4", - _ => throw new Exception() - }; - var flawless = e.FlawlessIVs; + if (curMin == -1) + curMin = i; - // calc min/max ranks - int min = e.MinRank; - int max = e.MaxRank; - - int curMin = -1; - for (int i = min; i >= 0 && i <= max; i++) + if (i == max) + yield return $" new(Nest{index:000},{curMin},{i},{flawless}) {{ Species = {e.Species:000}, Ability = {ability}{gender}{altform}{giga} }},{comment}"; + } + else if (curMin != -1) { - if (e.Probabilities[i] != 0) - { - if (curMin == -1) - curMin = i; - - if (i == max) - yield return $" new(Nest{index:000},{curMin},{i},{flawless}) {{ Species = {e.Species:000}, Ability = {ability}{gender}{altform}{giga} }},{comment}"; - } - else if (curMin != -1) - { - yield return $" new(Nest{index:000},{curMin},{i - 1},{flawless}) {{ Species = {e.Species:000}, Ability = {ability}{gender}{altform}{giga} }},{comment}"; - curMin = -1; - } + yield return $" new(Nest{index:000},{curMin},{i - 1},{flawless}) {{ Species = {e.Species:000}, Ability = {ability}{gender}{altform}{giga} }},{comment}"; + curMin = -1; } } } + } - public IEnumerable GetPrettySummary(IReadOnlyList species, IReadOnlyList items, IReadOnlyList moves, IReadOnlyList tmtrs, - IReadOnlyList drop_tables, IReadOnlyList bonus_tables, int index) + public IEnumerable GetPrettySummary(IReadOnlyList species, IReadOnlyList items, IReadOnlyList moves, IReadOnlyList tmtrs, + IReadOnlyList drop_tables, IReadOnlyList bonus_tables, int index) + { + yield return $"Nest ID: {TableID}"; + Debug.WriteLine(index); + + foreach (var entry in Entries) { - yield return $"Nest ID: {TableID}"; - Debug.WriteLine(index); + foreach (var line in PrettySummary(entry)) + yield return $"\t{line}"; + } - foreach (var entry in Entries) + yield return string.Empty; + + IEnumerable PrettySummary(EncounterNest8 e) + { + var giga = e.IsGigantamax ? "Gigantamax " : string.Empty; + var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; + var rank = $"{e.MinRank + 1}-Star"; + yield return $"{rank} {giga}{species[e.Species]}{form}"; + yield return $"\tLv. {15 + (10 * e.MinRank)}-{20 + (10 * e.MaxRank)}"; + yield return $"\tGender: {new[] { "Random", "Male", "Female", "Genderless" }[e.Gender]}"; + + var ability = e.Ability switch { - foreach (var line in PrettySummary(entry)) - yield return $"\t{line}"; + 2 => "A2", + 3 => "A3", + 4 => "A4", + _ => throw new Exception() + }; + yield return $"\tAbility: {ability}"; + yield return "\tSelection Probabilities:"; + for (var i = 0; i < e.Probabilities.Length; i++) + { + if (e.Probabilities[i] != 0) + yield return $"\t\t{i + 1}-Star Desired: {e.Probabilities[i]:00}%"; } + yield return "\tDrops:"; + foreach (var entry in GetOrderedDrops(drop_tables, e.DropTableID, e.FlawlessIVs)) + yield return $"\t\t{entry.Values[e.FlawlessIVs],3}% {GetItemName(entry.Item)}"; + + yield return "\tBonus Drops:"; + foreach (var entry in GetOrderedDrops(bonus_tables, e.BonusTableID, e.FlawlessIVs)) + yield return $"\t\t{entry.Values[e.FlawlessIVs]} x {GetItemName(entry.Item)}"; + yield return string.Empty; - - IEnumerable PrettySummary(EncounterNest8 e) - { - var giga = e.IsGigantamax ? "Gigantamax " : string.Empty; - var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; - var rank = $"{e.MinRank + 1}-Star"; - yield return $"{rank} {giga}{species[e.Species]}{form}"; - yield return $"\tLv. {15 + (10 * e.MinRank)}-{20 + (10 * e.MaxRank)}"; - yield return $"\tGender: {new[] { "Random", "Male", "Female", "Genderless" }[e.Gender]}"; - - var ability = e.Ability switch - { - 2 => "A2", - 3 => "A3", - 4 => "A4", - _ => throw new Exception() - }; - yield return $"\tAbility: {ability}"; - yield return "\tSelection Probabilities:"; - for (var i = 0; i < e.Probabilities.Length; i++) - { - if (e.Probabilities[i] != 0) - yield return $"\t\t{i + 1}-Star Desired: {e.Probabilities[i]:00}%"; - } - - yield return "\tDrops:"; - foreach (var entry in GetOrderedDrops(drop_tables, e.DropTableID, e.FlawlessIVs)) - yield return $"\t\t{entry.Values[e.FlawlessIVs],3}% {GetItemName(entry.Item)}"; - - yield return "\tBonus Drops:"; - foreach (var entry in GetOrderedDrops(bonus_tables, e.BonusTableID, e.FlawlessIVs)) - yield return $"\t\t{entry.Values[e.FlawlessIVs]} x {GetItemName(entry.Item)}"; - - yield return string.Empty; - } - - IEnumerable GetOrderedDrops(IReadOnlyList rewards, ulong tableID, int encounterRank) - { - var table = rewards.First(t => t.TableID == tableID); - var list = table.Rewards - .Where(d => encounterRank < d.Values.Length && d.Values[encounterRank] != 0) - .OrderByDescending(d => d.Values[encounterRank]) - .ThenBy(d => GetItemName(d.Item)); - - foreach (var entry in list) - yield return entry; - } - - string GetItemName(uint itemID) - { - if (itemID is >= 1130 and < 1230) // TR - return $"{items[(int)itemID]} {moves[tmtrs[100 + (int)itemID - 1130]]}"; - return items[(int)itemID]; - } } - } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterNest8 - { - [FlatBufferItem(00)] public int EntryIndex { get; set; } - [FlatBufferItem(01)] public int Species { get; set; } - [FlatBufferItem(02)] public int Form { get; set; } - [FlatBufferItem(03)] public ulong LevelTableID { get; set; } - [FlatBufferItem(04)] public byte Ability { get; set; } - [FlatBufferItem(05)] public bool IsGigantamax { get; set; } - [FlatBufferItem(06)] public ulong DropTableID { get; set; } - [FlatBufferItem(07)] public ulong BonusTableID { get; set; } - [FlatBufferItem(08)] public uint[] Probabilities { get; set; } - [FlatBufferItem(09)] public byte Gender { get; set; } - [FlatBufferItem(10)] public byte FlawlessIVs { get; set; } - - public Species SpeciesID => (Species)Species; - - public FixedAbility AbilityPermitted + IEnumerable GetOrderedDrops(IReadOnlyList rewards, ulong tableID, int encounterRank) { - get => (FixedAbility)Ability; - set => Ability = (byte)value; + var table = rewards.First(t => t.TableID == tableID); + var list = table.Rewards + .Where(d => encounterRank < d.Values.Length && d.Values[encounterRank] != 0) + .OrderByDescending(d => d.Values[encounterRank]) + .ThenBy(d => GetItemName(d.Item)); + + foreach (var entry in list) + yield return entry; } - public int MinRank => Array.FindIndex(Probabilities, z => z != 0); - public int MaxRank => Array.FindLastIndex(Probabilities, z => z != 0); - - public override string ToString() => $"{EntryIndex:00} - {Species:000}"; - } - - public enum FixedAbility - { - Ability1 = 0, - Ability2 = 1, - AbilityH = 2, - Ability1_2 = 3, - Any = 4, + string GetItemName(uint itemID) + { + if (itemID is >= 1130 and < 1230) // TR + return $"{items[(int)itemID]} {moves[tmtrs[100 + (int)itemID - 1130]]}"; + return items[(int)itemID]; + } } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterNest8 +{ + [FlatBufferItem(00)] public int EntryIndex { get; set; } + [FlatBufferItem(01)] public int Species { get; set; } + [FlatBufferItem(02)] public int Form { get; set; } + [FlatBufferItem(03)] public ulong LevelTableID { get; set; } + [FlatBufferItem(04)] public byte Ability { get; set; } + [FlatBufferItem(05)] public bool IsGigantamax { get; set; } + [FlatBufferItem(06)] public ulong DropTableID { get; set; } + [FlatBufferItem(07)] public ulong BonusTableID { get; set; } + [FlatBufferItem(08)] public uint[] Probabilities { get; set; } + [FlatBufferItem(09)] public byte Gender { get; set; } + [FlatBufferItem(10)] public byte FlawlessIVs { get; set; } + + public Species SpeciesID => (Species)Species; + + public FixedAbility AbilityPermitted + { + get => (FixedAbility)Ability; + set => Ability = (byte)value; + } + + public int MinRank => Array.FindIndex(Probabilities, z => z != 0); + public int MaxRank => Array.FindLastIndex(Probabilities, z => z != 0); + + public override string ToString() => $"{EntryIndex:00} - {Species:000}"; +} + +public enum FixedAbility +{ + Ability1 = 0, + Ability2 = 1, + AbilityH = 2, + Ability1_2 = 3, + Any = 4, +} diff --git a/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterUnderground8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterUnderground8Archive.cs index b01c49d9..83ac7c7c 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterUnderground8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Nest/EncounterUnderground8Archive.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -8,56 +8,55 @@ // ReSharper disable UnusedMember.Global #nullable disable -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterUnderground8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterUnderground8Archive : IFlatBufferArchive + [FlatBufferItem(0)] public EncounterUnderground8[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterUnderground8 +{ + [FlatBufferItem(00)] public bool HasFlagRequirement { get; set; } + [FlatBufferItem(01)] public ulong FlagRequirementID { get; set; } + [FlatBufferItem(02)] public byte Field_02 { get; set; } // all zero, Gender? + [FlatBufferItem(03)] public byte Form { get; set; } + [FlatBufferItem(04)] public uint GigantamaxState { get; set; } + [FlatBufferItem(05)] public uint Ball { get; set; } + [FlatBufferItem(06)] public uint IndexNum { get; set; } + [FlatBufferItem(07)] public uint Level { get; set; } + [FlatBufferItem(08)] public int Species { get; set; } + [FlatBufferItem(09)] public ulong UiMessageID { get; set; } + [FlatBufferItem(10)] public uint OT_Gender { get; set; } + [FlatBufferItem(11)] public byte Version { get; set; } + [FlatBufferItem(12)] public uint Shiny { get; set; } + [FlatBufferItem(13)] public sbyte IV_SPE { get; set; } + [FlatBufferItem(14)] public sbyte IV_ATK { get; set; } + [FlatBufferItem(15)] public sbyte IV_DEF { get; set; } + [FlatBufferItem(16)] public sbyte IV_HP { get; set; } + [FlatBufferItem(17)] public sbyte IV_SPA { get; set; } + [FlatBufferItem(18)] public sbyte IV_SPD { get; set; } + [FlatBufferItem(19)] public uint Ability { get; set; } // 1,2,4 + [FlatBufferItem(20)] public byte Field_14 { get; set; } // ultra beasts only, selectability + [FlatBufferItem(21)] public uint Move0 { get; set; } + [FlatBufferItem(22)] public uint Move1 { get; set; } + [FlatBufferItem(23)] public uint Move2 { get; set; } + [FlatBufferItem(24)] public uint Move3 { get; set; } + + public int Gender => 0; // Random + public bool IsGigantamax => GigantamaxState == 2; + + public override string ToString() => $"{IndexNum:00} - {Species:000}"; + + public string GetSummary(IReadOnlyList species) { - [FlatBufferItem(0)] public EncounterUnderground8[] Table { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterUnderground8 - { - [FlatBufferItem(00)] public bool HasFlagRequirement { get; set; } - [FlatBufferItem(01)] public ulong FlagRequirementID { get; set; } - [FlatBufferItem(02)] public byte Field_02 { get; set; } // all zero, Gender? - [FlatBufferItem(03)] public byte Form { get; set; } - [FlatBufferItem(04)] public uint GigantamaxState { get; set; } - [FlatBufferItem(05)] public uint Ball { get; set; } - [FlatBufferItem(06)] public uint IndexNum { get; set; } - [FlatBufferItem(07)] public uint Level { get; set; } - [FlatBufferItem(08)] public int Species { get; set; } - [FlatBufferItem(09)] public ulong UiMessageID { get; set; } - [FlatBufferItem(10)] public uint OT_Gender { get; set; } - [FlatBufferItem(11)] public byte Version { get; set; } - [FlatBufferItem(12)] public uint Shiny { get; set; } - [FlatBufferItem(13)] public sbyte IV_SPE { get; set; } - [FlatBufferItem(14)] public sbyte IV_ATK { get; set; } - [FlatBufferItem(15)] public sbyte IV_DEF { get; set; } - [FlatBufferItem(16)] public sbyte IV_HP { get; set; } - [FlatBufferItem(17)] public sbyte IV_SPA { get; set; } - [FlatBufferItem(18)] public sbyte IV_SPD { get; set; } - [FlatBufferItem(19)] public uint Ability { get; set; } // 1,2,4 - [FlatBufferItem(20)] public byte Field_14 { get; set; } // ultra beasts only, selectability - [FlatBufferItem(21)] public uint Move0 { get; set; } - [FlatBufferItem(22)] public uint Move1 { get; set; } - [FlatBufferItem(23)] public uint Move2 { get; set; } - [FlatBufferItem(24)] public uint Move3 { get; set; } - - public int Gender => 0; // Random - public bool IsGigantamax => GigantamaxState == 2; - - public override string ToString() => $"{IndexNum:00} - {Species:000}"; - - public string GetSummary(IReadOnlyList species) - { - var gender = Gender == 0 ? string.Empty : $", Gender = {Gender - 1}"; - var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; - var moves = $", Moves = new[] {{{Move0:000},{Move1:000},{Move2:000},{Move3:000}}}"; - var game = Version != 0 ? Version == 1 ? ", Version = GameVersion.SW" : ", Version = GameVersion.SH" : ""; - var g = IsGigantamax ? ", CanGigantamax = true" : ""; - return $" new({Species:000},{Form},{Level:00}) {{ Ability = A{Ability}{gender}{moves}{g}{game} }},{comment}"; - } + var gender = Gender == 0 ? string.Empty : $", Gender = {Gender - 1}"; + var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; + var moves = $", Moves = new[] {{{Move0:000},{Move1:000},{Move2:000},{Move3:000}}}"; + var game = Version != 0 ? Version == 1 ? ", Version = GameVersion.SW" : ", Version = GameVersion.SH" : ""; + var g = IsGigantamax ? ", CanGigantamax = true" : ""; + return $" new({Species:000},{Form},{Level:00}) {{ Ability = A{Ability}{gender}{moves}{g}{game} }},{comment}"; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleCrystalEncounter8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleCrystalEncounter8Archive.cs index 4d18a22b..8549b415 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleCrystalEncounter8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleCrystalEncounter8Archive.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -11,198 +11,197 @@ // ReSharper disable UnusedMember.Global #nullable disable -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleCrystalEncounter8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleCrystalEncounter8Archive : IFlatBufferArchive - { - [FlatBufferItem(0)] public NestHoleCrystalEncounter8Table[] Table { get; set; } - } + [FlatBufferItem(0)] public NestHoleCrystalEncounter8Table[] Table { get; set; } +} - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleCrystalEncounter8Table - { - [FlatBufferItem(0)] public ulong TableID { get; set; } - [FlatBufferItem(1)] public uint GameVersion { get; set; } - [FlatBufferItem(2)] public NestHoleCrystalEncounter8[] Entries { get; set; } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleCrystalEncounter8Table +{ + [FlatBufferItem(0)] public ulong TableID { get; set; } + [FlatBufferItem(1)] public uint GameVersion { get; set; } + [FlatBufferItem(2)] public NestHoleCrystalEncounter8[] Entries { get; set; } - public IEnumerable GetPrettySummary(IReadOnlyList species, IReadOnlyList items, IReadOnlyList moves, IReadOnlyList tmtrs, - IReadOnlyList nest_drop_tables, IReadOnlyList nest_bonus_tables, IReadOnlyList dist_drop_tables, IReadOnlyList dist_bonus_tables, int index) + public IEnumerable GetPrettySummary(IReadOnlyList species, IReadOnlyList items, IReadOnlyList moves, IReadOnlyList tmtrs, + IReadOnlyList nest_drop_tables, IReadOnlyList nest_bonus_tables, IReadOnlyList dist_drop_tables, IReadOnlyList dist_bonus_tables, int index) + { + var drop_tables = nest_drop_tables.Concat(dist_drop_tables).ToArray(); + var bonus_tables = nest_bonus_tables.Concat(dist_bonus_tables).ToArray(); + + Debug.WriteLine(index); + + for (uint i = 0; i < Entries.Length; i++) { - var drop_tables = nest_drop_tables.Concat(dist_drop_tables).ToArray(); - var bonus_tables = nest_bonus_tables.Concat(dist_bonus_tables).ToArray(); - - Debug.WriteLine(index); - - for (uint i = 0; i < Entries.Length; i++) - { - if (Entries[i].Species == 0) - continue; - yield return $"Dynamax Crystal: {GetItemName(1279 + i)}"; - foreach (var line in PrettySummary(Entries[i])) - yield return $"\t{line}"; - } - - yield return string.Empty; - - IEnumerable PrettySummary(NestHoleCrystalEncounter8 e) - { - var encounter_rank = GetEncounterRank(e.Level); // TODO: How is this actually encoded? - var giga = e.IsGigantamax ? "Gigantamax " : string.Empty; - var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; - var rank = $"{encounter_rank}-Star"; - yield return $"{rank} {giga}{species[e.Species]}{form}"; - yield return $"\tLv. {e.Level}"; - yield return $"\tDynamax Level: {e.DynamaxLevel}"; - yield return $"\tDynamax Boost: {e.DynamaxBoost:0.0}x"; - yield return $"\tIVs: {e.IV_HP}/{e.IV_ATK}/{e.IV_DEF}/{e.IV_SPA}/{e.IV_SPD}/{e.IV_SPE}"; - /*yield return $"\tGender: {new[] { "Random", "Male", "Female", "Genderless" }[e.Gender]}"; - - var ability = e.Ability switch - { - 3 => "Hidden", - 4 => "Any", - _ => throw new Exception() - }; - yield return $"\tAbility: {ability}";*/ - - yield return "\tMoves:"; - if (e.Move0 != 0) yield return $"\t\t- {moves[(int)e.Move0]}"; - if (e.Move1 != 0) yield return $"\t\t- {moves[(int)e.Move1]}"; - if (e.Move2 != 0) yield return $"\t\t- {moves[(int)e.Move2]}"; - if (e.Move3 != 0) yield return $"\t\t- {moves[(int)e.Move3]}"; - - yield return "\tDrops:"; - foreach (var entry in GetOrderedDrops(drop_tables, e.DropTableID, encounter_rank - 1)) - yield return $"\t\t{entry.Values[encounter_rank - 1],3}% {GetItemName(entry.Item)}"; - - yield return "\tBonus Drops:"; - foreach (var entry in GetOrderedDrops(bonus_tables, e.BonusTableID, encounter_rank - 1)) - yield return $"\t\t{entry.Values[encounter_rank - 1]} x {GetItemName(entry.Item)}"; - - yield return string.Empty; - } - - IEnumerable GetOrderedDrops(IReadOnlyList rewards, ulong tableID, int encounterRank) - { - var table = rewards.First(t => t.TableID == tableID); - var list = table.Rewards - .Where(d => d.Values[encounterRank] != 0) - .OrderByDescending(d => d.Values[encounterRank]) - .ThenBy(d => GetItemName(d.Item)); - - foreach (var entry in list) - yield return entry; - } - - string GetItemName(uint itemID) - { - if (itemID is >= 1130 and < 1230) // TR - return $"{items[(int)itemID]} {moves[tmtrs[100 + (int)itemID - 1130]]}"; - return items[(int)itemID]; - } + if (Entries[i].Species == 0) + continue; + yield return $"Dynamax Crystal: {GetItemName(1279 + i)}"; + foreach (var line in PrettySummary(Entries[i])) + yield return $"\t{line}"; } - private static int GetEncounterRank(int level) => level switch - { - >= 15 and <= 20 => 1, - >= 25 and <= 30 => 2, - >= 35 and <= 40 => 3, - >= 45 and <= 50 => 4, - >= 55 and <= 60 => 5, - _ => 0, - }; + yield return string.Empty; - public IEnumerable GetSummary(IReadOnlyList species, IReadOnlyList items) + IEnumerable PrettySummary(NestHoleCrystalEncounter8 e) { - for (uint i = 0; i < Entries.Length; i++) + var encounter_rank = GetEncounterRank(e.Level); // TODO: How is this actually encoded? + var giga = e.IsGigantamax ? "Gigantamax " : string.Empty; + var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; + var rank = $"{encounter_rank}-Star"; + yield return $"{rank} {giga}{species[e.Species]}{form}"; + yield return $"\tLv. {e.Level}"; + yield return $"\tDynamax Level: {e.DynamaxLevel}"; + yield return $"\tDynamax Boost: {e.DynamaxBoost:0.0}x"; + yield return $"\tIVs: {e.IV_HP}/{e.IV_ATK}/{e.IV_DEF}/{e.IV_SPA}/{e.IV_SPD}/{e.IV_SPE}"; + /*yield return $"\tGender: {new[] { "Random", "Male", "Female", "Genderless" }[e.Gender]}"; + + var ability = e.Ability switch { - if (Entries[i].Species == 0) - continue; - yield return Summary(Entries[i], i); - } + 3 => "Hidden", + 4 => "Any", + _ => throw new Exception() + }; + yield return $"\tAbility: {ability}";*/ + + yield return "\tMoves:"; + if (e.Move0 != 0) yield return $"\t\t- {moves[(int)e.Move0]}"; + if (e.Move1 != 0) yield return $"\t\t- {moves[(int)e.Move1]}"; + if (e.Move2 != 0) yield return $"\t\t- {moves[(int)e.Move2]}"; + if (e.Move3 != 0) yield return $"\t\t- {moves[(int)e.Move3]}"; + + yield return "\tDrops:"; + foreach (var entry in GetOrderedDrops(drop_tables, e.DropTableID, encounter_rank - 1)) + yield return $"\t\t{entry.Values[encounter_rank - 1],3}% {GetItemName(entry.Item)}"; + + yield return "\tBonus Drops:"; + foreach (var entry in GetOrderedDrops(bonus_tables, e.BonusTableID, encounter_rank - 1)) + yield return $"\t\t{entry.Values[encounter_rank - 1]} x {GetItemName(entry.Item)}"; + yield return string.Empty; - - string Summary(NestHoleCrystalEncounter8 e, uint x) - { - // Comment - var crystal = items[(int)(1279 + x)]; - var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; - var gprefix = e.IsGigantamax ? "Gigantamax " : string.Empty; - var comment = $"{crystal} {gprefix}{species[e.Species]}{form}"; - - var ability = e.Ability switch - { - 0 => "A0", // 1 - 1 => "A1", // 2 - 2 => "A2", // H - 3 => "A3", // 1/2 only - 4 => "A4", // 1/2/H - _ => throw new Exception() - }; - - // Constructor - var spec = $"Species = {e.Species:000}"; - var lvl = $", Level = {e.Level:00}"; - const string loc = ", Location = 126"; - var abil = $", Ability = {ability}"; - var dyna = $", DynamaxLevel = {e.DynamaxLevel}"; - var moves = $", Moves = new[] {{{e.Move0:000},{e.Move1:000},{e.Move2:000},{e.Move3:000}}}"; - var ivs = $", IVs = new[] {{{e.IV_HP},{e.IV_ATK},{e.IV_DEF},{e.IV_SPE},{e.IV_SPA},{e.IV_SPD}}}"; - var altform = e.Form == 0 ? string.Empty : $", Form = {e.Form}"; - var giga = !e.IsGigantamax ? string.Empty : ", CanGigantamax = true"; - - return $" new() {{ {spec}{lvl}{abil}{loc}{ivs}{dyna}{moves}{altform}{giga} }}, // {comment}"; - } } - public string GetSummarySimple() + IEnumerable GetOrderedDrops(IReadOnlyList rewards, ulong tableID, int encounterRank) { - var tableID = TableID.ToString("X16"); - var tableData = TableUtil.GetTable(Entries); + var table = rewards.First(t => t.TableID == tableID); + var list = table.Rewards + .Where(d => d.Values[encounterRank] != 0) + .OrderByDescending(d => d.Values[encounterRank]) + .ThenBy(d => GetItemName(d.Item)); - return tableID + Environment.NewLine + tableData + Environment.NewLine; + foreach (var entry in list) + yield return entry; + } + + string GetItemName(uint itemID) + { + if (itemID is >= 1130 and < 1230) // TR + return $"{items[(int)itemID]} {moves[tmtrs[100 + (int)itemID - 1130]]}"; + return items[(int)itemID]; } } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleCrystalEncounter8 + private static int GetEncounterRank(int level) => level switch { - [FlatBufferItem(00)] public int EntryIndex { get; set; } - [FlatBufferItem(01)] public int Species { get; set; } - [FlatBufferItem(02)] public int Form { get; set; } - [FlatBufferItem(03)] public int Level { get; set; } - [FlatBufferItem(04)] public byte DynamaxLevel { get; set; } - [FlatBufferItem(05)] public byte Ability { get; set; } - [FlatBufferItem(06)] public bool IsGigantamax { get; set; } - [FlatBufferItem(07)] public ulong DropTableID { get; set; } - [FlatBufferItem(08)] public ulong BonusTableID { get; set; } - [FlatBufferItem(09)] public byte Field_09 { get; set; } - [FlatBufferItem(10)] public byte Field_0A { get; set; } - [FlatBufferItem(11)] public byte Field_0B { get; set; } - [FlatBufferItem(12)] public byte Field_0C { get; set; } - [FlatBufferItem(13)] public byte Field_0D { get; set; } - [FlatBufferItem(14)] public byte Nature { get; set; } - [FlatBufferItem(15)] public short IV_HP { get; set; } - [FlatBufferItem(16)] public short IV_ATK { get; set; } - [FlatBufferItem(17)] public short IV_DEF { get; set; } - [FlatBufferItem(18)] public short IV_SPA { get; set; } - [FlatBufferItem(19)] public short IV_SPD { get; set; } - [FlatBufferItem(20)] public short IV_SPE { get; set; } - [FlatBufferItem(21)] public uint Field_15 { get; set; } - [FlatBufferItem(22)] public uint Move0 { get; set; } - [FlatBufferItem(23)] public uint Move1 { get; set; } - [FlatBufferItem(24)] public uint Move2 { get; set; } - [FlatBufferItem(25)] public uint Move3 { get; set; } - [FlatBufferItem(26)] public float DynamaxBoost { get; set; } - [FlatBufferItem(27)] public uint Field_1B { get; set; } - [FlatBufferItem(28)] public uint Field_1C { get; set; } - [FlatBufferItem(29)] public uint Field_1D { get; set; } // Shield - [FlatBufferItem(30)] public uint Field_1E { get; set; } // % only if move - [FlatBufferItem(31)] public uint Field_1F { get; set; } // Move ID - [FlatBufferItem(32)] public uint Field_20 { get; set; } // Shield only if move - [FlatBufferItem(33)] public uint Field_21 { get; set; } // % only if move - [FlatBufferItem(34)] public uint Field_22 { get; set; } // Move ID - [FlatBufferItem(35)] public uint Field_23 { get; set; } // shield? only if move + >= 15 and <= 20 => 1, + >= 25 and <= 30 => 2, + >= 35 and <= 40 => 3, + >= 45 and <= 50 => 4, + >= 55 and <= 60 => 5, + _ => 0, + }; + + public IEnumerable GetSummary(IReadOnlyList species, IReadOnlyList items) + { + for (uint i = 0; i < Entries.Length; i++) + { + if (Entries[i].Species == 0) + continue; + yield return Summary(Entries[i], i); + } + yield return string.Empty; + + string Summary(NestHoleCrystalEncounter8 e, uint x) + { + // Comment + var crystal = items[(int)(1279 + x)]; + var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; + var gprefix = e.IsGigantamax ? "Gigantamax " : string.Empty; + var comment = $"{crystal} {gprefix}{species[e.Species]}{form}"; + + var ability = e.Ability switch + { + 0 => "A0", // 1 + 1 => "A1", // 2 + 2 => "A2", // H + 3 => "A3", // 1/2 only + 4 => "A4", // 1/2/H + _ => throw new Exception() + }; + + // Constructor + var spec = $"Species = {e.Species:000}"; + var lvl = $", Level = {e.Level:00}"; + const string loc = ", Location = 126"; + var abil = $", Ability = {ability}"; + var dyna = $", DynamaxLevel = {e.DynamaxLevel}"; + var moves = $", Moves = new[] {{{e.Move0:000},{e.Move1:000},{e.Move2:000},{e.Move3:000}}}"; + var ivs = $", IVs = new[] {{{e.IV_HP},{e.IV_ATK},{e.IV_DEF},{e.IV_SPE},{e.IV_SPA},{e.IV_SPD}}}"; + var altform = e.Form == 0 ? string.Empty : $", Form = {e.Form}"; + var giga = !e.IsGigantamax ? string.Empty : ", CanGigantamax = true"; + + return $" new() {{ {spec}{lvl}{abil}{loc}{ivs}{dyna}{moves}{altform}{giga} }}, // {comment}"; + } + } + + public string GetSummarySimple() + { + var tableID = TableID.ToString("X16"); + var tableData = TableUtil.GetTable(Entries); + + return tableID + Environment.NewLine + tableData + Environment.NewLine; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleCrystalEncounter8 +{ + [FlatBufferItem(00)] public int EntryIndex { get; set; } + [FlatBufferItem(01)] public int Species { get; set; } + [FlatBufferItem(02)] public int Form { get; set; } + [FlatBufferItem(03)] public int Level { get; set; } + [FlatBufferItem(04)] public byte DynamaxLevel { get; set; } + [FlatBufferItem(05)] public byte Ability { get; set; } + [FlatBufferItem(06)] public bool IsGigantamax { get; set; } + [FlatBufferItem(07)] public ulong DropTableID { get; set; } + [FlatBufferItem(08)] public ulong BonusTableID { get; set; } + [FlatBufferItem(09)] public byte Field_09 { get; set; } + [FlatBufferItem(10)] public byte Field_0A { get; set; } + [FlatBufferItem(11)] public byte Field_0B { get; set; } + [FlatBufferItem(12)] public byte Field_0C { get; set; } + [FlatBufferItem(13)] public byte Field_0D { get; set; } + [FlatBufferItem(14)] public byte Nature { get; set; } + [FlatBufferItem(15)] public short IV_HP { get; set; } + [FlatBufferItem(16)] public short IV_ATK { get; set; } + [FlatBufferItem(17)] public short IV_DEF { get; set; } + [FlatBufferItem(18)] public short IV_SPA { get; set; } + [FlatBufferItem(19)] public short IV_SPD { get; set; } + [FlatBufferItem(20)] public short IV_SPE { get; set; } + [FlatBufferItem(21)] public uint Field_15 { get; set; } + [FlatBufferItem(22)] public uint Move0 { get; set; } + [FlatBufferItem(23)] public uint Move1 { get; set; } + [FlatBufferItem(24)] public uint Move2 { get; set; } + [FlatBufferItem(25)] public uint Move3 { get; set; } + [FlatBufferItem(26)] public float DynamaxBoost { get; set; } + [FlatBufferItem(27)] public uint Field_1B { get; set; } + [FlatBufferItem(28)] public uint Field_1C { get; set; } + [FlatBufferItem(29)] public uint Field_1D { get; set; } // Shield + [FlatBufferItem(30)] public uint Field_1E { get; set; } // % only if move + [FlatBufferItem(31)] public uint Field_1F { get; set; } // Move ID + [FlatBufferItem(32)] public uint Field_20 { get; set; } // Shield only if move + [FlatBufferItem(33)] public uint Field_21 { get; set; } // % only if move + [FlatBufferItem(34)] public uint Field_22 { get; set; } // Move ID + [FlatBufferItem(35)] public uint Field_23 { get; set; } // shield? only if move +} diff --git a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionEncounter8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionEncounter8Archive.cs index e3eab370..576b7e87 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionEncounter8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionEncounter8Archive.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; @@ -11,217 +11,216 @@ // ReSharper disable UnusedMember.Global #nullable disable -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleDistributionEncounter8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleDistributionEncounter8Archive : IFlatBufferArchive - { - [FlatBufferItem(0)] public NestHoleDistributionEncounter8Table[] Table { get; set; } - } + [FlatBufferItem(0)] public NestHoleDistributionEncounter8Table[] Table { get; set; } +} - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleDistributionEncounter8Table - { - [FlatBufferItem(0)] public ulong TableID { get; set; } - [FlatBufferItem(1)] public uint GameVersion { get; set; } - [FlatBufferItem(2)] public byte Field_02 { get; set; } - [FlatBufferItem(3)] public byte EncounterRate { get; set; } - [FlatBufferItem(4)] public NestHoleDistributionEncounter8[] Entries { get; set; } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleDistributionEncounter8Table +{ + [FlatBufferItem(0)] public ulong TableID { get; set; } + [FlatBufferItem(1)] public uint GameVersion { get; set; } + [FlatBufferItem(2)] public byte Field_02 { get; set; } + [FlatBufferItem(3)] public byte EncounterRate { get; set; } + [FlatBufferItem(4)] public NestHoleDistributionEncounter8[] Entries { get; set; } - public IEnumerable GetPrettySummary(IReadOnlyList species, IReadOnlyList items, IReadOnlyList moves, IReadOnlyList tmtrs, - IReadOnlyList nest_drop_tables, IReadOnlyList nest_bonus_tables, IReadOnlyList dist_drop_tables, IReadOnlyList dist_bonus_tables, int index) + public IEnumerable GetPrettySummary(IReadOnlyList species, IReadOnlyList items, IReadOnlyList moves, IReadOnlyList tmtrs, + IReadOnlyList nest_drop_tables, IReadOnlyList nest_bonus_tables, IReadOnlyList dist_drop_tables, IReadOnlyList dist_bonus_tables, int index) + { + var drop_tables = nest_drop_tables.Concat(dist_drop_tables).ToArray(); + var bonus_tables = nest_bonus_tables.Concat(dist_bonus_tables).ToArray(); + + yield return $"Nest ID: {TableID}"; + Debug.WriteLine(index); + + foreach (var entry in Entries) { - var drop_tables = nest_drop_tables.Concat(dist_drop_tables).ToArray(); - var bonus_tables = nest_bonus_tables.Concat(dist_bonus_tables).ToArray(); - - yield return $"Nest ID: {TableID}"; - Debug.WriteLine(index); - - foreach (var entry in Entries) - { - foreach (var line in PrettySummary(entry)) - yield return $"\t{line}"; - } - - yield return string.Empty; - - IEnumerable PrettySummary(NestHoleDistributionEncounter8 e) - { - if (!e.Exists) - yield break; - - var giga = e.IsGigantamax ? "Gigantamax " : string.Empty; - var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; - var rank = $"{e.MinRank + 1}-Star"; - yield return $"{rank} {giga}{species[e.Species]}{form}"; - yield return $"\tLv. {e.Level}"; - if (e.Field_13 == 6 && e.Field_14 == 6) // related to whether or not the raid boss can be caught; enums/bitflags? - yield return "\tCatchable: No"; - if (e.ShinyLock == 1) - yield return "\tShiny: Never"; - else if (e.ShinyLock == 2) - yield return "\tShiny: Always"; - yield return $"\tDynamax Level: {e.DynamaxLevel}"; - yield return $"\tDynamax Boost: {e.DynamaxBoost:0.0}x"; - /*yield return $"\tGender: {new[] { "Random", "Male", "Female", "Genderless" }[e.Gender]}"; - - var ability = e.Ability switch - { - 3 => "Hidden", - 4 => "Any", - _ => throw new Exception() - }; - yield return $"\tAbility: {ability}";*/ - - yield return "\tMoves:"; - if (e.Move0 != 0) yield return $"\t\t- {moves[(int)e.Move0]}"; - if (e.Move1 != 0) yield return $"\t\t- {moves[(int)e.Move1]}"; - if (e.Move2 != 0) yield return $"\t\t- {moves[(int)e.Move2]}"; - if (e.Move3 != 0) yield return $"\t\t- {moves[(int)e.Move3]}"; - - yield return "\tSelection Probabilities:"; - for (var i = 0; i < e.Probabilities.Length; i++) - { - if (e.Probabilities[i] != 0) - yield return $"\t\t{i + 1}-Star Desired: {e.Probabilities[i]:00}%"; - } - - yield return "\tDrops:"; - var dropTable = e.MinRank; - foreach (var entry in GetOrderedDrops(drop_tables, e.DropTableID, dropTable)) - yield return $"\t\t{entry.Values[e.MinRank],3}% {GetItemName(entry.Item)}"; - - yield return "\tBonus Drops:"; - foreach (var entry in GetOrderedDrops(bonus_tables, e.BonusTableID, dropTable)) - yield return $"\t\t{entry.Values[e.MinRank]} x {GetItemName(entry.Item)}"; - - yield return string.Empty; - } - - IEnumerable GetOrderedDrops(IReadOnlyList rewards, ulong tableID, int encounterRank) - { - var table = rewards.First(t => t.TableID == tableID); - var list = table.Rewards - .Where(d => d.Values[encounterRank] != 0) - .OrderByDescending(d => d.Values[encounterRank]) - .ThenBy(d => GetItemName(d.Item)); - - foreach (var entry in list) - yield return entry; - } - - string GetItemName(uint itemID) - { - if (itemID is >= 1130 and < 1230) // TR - return $"{items[(int)itemID]} {moves[tmtrs[100 + (int)itemID - 1130]]}"; - return items[(int)itemID]; - } + foreach (var line in PrettySummary(entry)) + yield return $"\t{line}"; } - public IEnumerable GetSummary(IReadOnlyList species, int index) + yield return string.Empty; + + IEnumerable PrettySummary(NestHoleDistributionEncounter8 e) { - foreach (var entry in Entries) + if (!e.Exists) + yield break; + + var giga = e.IsGigantamax ? "Gigantamax " : string.Empty; + var form = e.Form != 0 ? $"-{e.Form}" : string.Empty; + var rank = $"{e.MinRank + 1}-Star"; + yield return $"{rank} {giga}{species[e.Species]}{form}"; + yield return $"\tLv. {e.Level}"; + if (e.Field_13 == 6 && e.Field_14 == 6) // related to whether or not the raid boss can be caught; enums/bitflags? + yield return "\tCatchable: No"; + if (e.ShinyLock == 1) + yield return "\tShiny: Never"; + else if (e.ShinyLock == 2) + yield return "\tShiny: Always"; + yield return $"\tDynamax Level: {e.DynamaxLevel}"; + yield return $"\tDynamax Boost: {e.DynamaxBoost:0.0}x"; + /*yield return $"\tGender: {new[] { "Random", "Male", "Female", "Genderless" }[e.Gender]}"; + + var ability = e.Ability switch { - if (entry.Exists) - yield return Summary(entry, index); + 3 => "Hidden", + 4 => "Any", + _ => throw new Exception() + }; + yield return $"\tAbility: {ability}";*/ + + yield return "\tMoves:"; + if (e.Move0 != 0) yield return $"\t\t- {moves[(int)e.Move0]}"; + if (e.Move1 != 0) yield return $"\t\t- {moves[(int)e.Move1]}"; + if (e.Move2 != 0) yield return $"\t\t- {moves[(int)e.Move2]}"; + if (e.Move3 != 0) yield return $"\t\t- {moves[(int)e.Move3]}"; + + yield return "\tSelection Probabilities:"; + for (var i = 0; i < e.Probabilities.Length; i++) + { + if (e.Probabilities[i] != 0) + yield return $"\t\t{i + 1}-Star Desired: {e.Probabilities[i]:00}%"; } + + yield return "\tDrops:"; + var dropTable = e.MinRank; + foreach (var entry in GetOrderedDrops(drop_tables, e.DropTableID, dropTable)) + yield return $"\t\t{entry.Values[e.MinRank],3}% {GetItemName(entry.Item)}"; + + yield return "\tBonus Drops:"; + foreach (var entry in GetOrderedDrops(bonus_tables, e.BonusTableID, dropTable)) + yield return $"\t\t{entry.Values[e.MinRank]} x {GetItemName(entry.Item)}"; + yield return string.Empty; - - string Summary(NestHoleDistributionEncounter8 e, int encounterIndex) - { - var comment = $" // {species[e.Species]}{(e.Form == 0 ? string.Empty : "-" + e.Form)}"; - var gender = e.Gender == 0 ? string.Empty : $", Gender = {e.Gender - 1}"; - var altform = e.Form == 0 ? string.Empty : $", Form = {e.Form}"; - var istr = $", Index = {encounterIndex}"; - var giga = !e.IsGigantamax ? string.Empty : ", CanGigantamax = true"; - var moves = $", Moves = new({e.Move0:000}, {e.Move1:000}, {e.Move2:000}, {e.Move3:000})"; - var shiny = e.ShinyLock switch - { - 0 => string.Empty, - 1 => ", Shiny = Shiny.Never", - 2 => ", Shiny = Shiny.Always", - _ => throw new Exception() - }; - var ability = e.Ability switch - { - 0 => "A0", // 1 - 1 => "A1", // 2 - 2 => "A2", // H - 3 => "A3", // 1/2 only - 4 => "A4", // 1/2/H - _ => throw new Exception() - }; - - // calc min/max ranks - int min = e.MinRank; - int max = e.MaxRank; - for (int i = min; i < max; i++) - { - if (e.Probabilities[i] == 0) - throw new Exception(); - } - var flawless = e.FlawlessIVs; - var line = $" new({e.Level:00},{e.DynamaxLevel:00},{flawless}) {{ Species = {e.Species:000}, Ability = {ability}{moves}{istr}{gender}{altform}{giga}{shiny} }},{comment}"; - if (e.Field_13 == 6 && e.Field_14 == 6) - line = line.Insert(12, "//").Remove(10, 2); // comment out uncatchable encounters - return line; - } } - public string GetSummarySimple() + IEnumerable GetOrderedDrops(IReadOnlyList rewards, ulong tableID, int encounterRank) { - var tableID = TableID.ToString("X16"); - var tableData = TableUtil.GetTable(Entries); + var table = rewards.First(t => t.TableID == tableID); + var list = table.Rewards + .Where(d => d.Values[encounterRank] != 0) + .OrderByDescending(d => d.Values[encounterRank]) + .ThenBy(d => GetItemName(d.Item)); - return tableID + Environment.NewLine + tableData + Environment.NewLine; + foreach (var entry in list) + yield return entry; + } + + string GetItemName(uint itemID) + { + if (itemID is >= 1130 and < 1230) // TR + return $"{items[(int)itemID]} {moves[tmtrs[100 + (int)itemID - 1130]]}"; + return items[(int)itemID]; } } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleDistributionEncounter8 + public IEnumerable GetSummary(IReadOnlyList species, int index) { - [FlatBufferItem(00)] public int EntryIndex { get; set; } - [FlatBufferItem(01)] public int Species { get; set; } - [FlatBufferItem(02)] public int Form { get; set; } - [FlatBufferItem(03)] public int Level { get; set; } - [FlatBufferItem(04)] public ushort DynamaxLevel { get; set; } - [FlatBufferItem(05)] public uint Field_05 { get; set; } // probably EVs - [FlatBufferItem(06)] public uint Field_06 { get; set; } - [FlatBufferItem(07)] public uint Field_07 { get; set; } - [FlatBufferItem(08)] public uint Field_08 { get; set; } - [FlatBufferItem(09)] public uint Field_09 { get; set; } - [FlatBufferItem(10)] public uint Field_0A { get; set; } - [FlatBufferItem(11)] public byte Ability { get; set; } - [FlatBufferItem(12)] public bool IsGigantamax { get; set; } - [FlatBufferItem(13)] public ulong DropTableID { get; set; } - [FlatBufferItem(14)] public ulong BonusTableID { get; set; } - [FlatBufferItem(15)] public int[] Probabilities { get; set; } - [FlatBufferItem(16)] public byte Gender { get; set; } - [FlatBufferItem(17)] public byte FlawlessIVs { get; set; } - [FlatBufferItem(18)] public byte ShinyLock { get; set; } - [FlatBufferItem(19)] public byte Field_13 { get; set; } // 3/4 - [FlatBufferItem(20)] public byte Field_14 { get; set; } // 3/4/5 -- +1 for second entries - [FlatBufferItem(21)] public byte Nature { get; set; } - [FlatBufferItem(22)] public int Field_16 { get; set; } - [FlatBufferItem(23)] public uint Move0 { get; set; } - [FlatBufferItem(24)] public uint Move1 { get; set; } - [FlatBufferItem(25)] public uint Move2 { get; set; } - [FlatBufferItem(26)] public uint Move3 { get; set; } - [FlatBufferItem(27)] public float DynamaxBoost { get; set; } - [FlatBufferItem(28)] public uint Field_1C { get; set; } - [FlatBufferItem(29)] public uint Field_1D { get; set; } - [FlatBufferItem(30)] public uint Field_1E { get; set; } // Shield - [FlatBufferItem(31)] public uint Field_1F { get; set; } // % only if move - [FlatBufferItem(32)] public uint Field_20 { get; set; } // Move ID - [FlatBufferItem(33)] public uint Field_21 { get; set; } // Shield only if move - [FlatBufferItem(34)] public uint Field_22 { get; set; } // % only if move - [FlatBufferItem(35)] public uint Field_23 { get; set; } // Move ID - [FlatBufferItem(36)] public uint Field_24 { get; set; } // shield? only if move + foreach (var entry in Entries) + { + if (entry.Exists) + yield return Summary(entry, index); + } + yield return string.Empty; - public int MinRank => Array.FindIndex(Probabilities, z => z != 0); - public int MaxRank => Array.FindLastIndex(Probabilities, z => z != 0); - public bool Exists => Probabilities.Any(z => z != 0); + string Summary(NestHoleDistributionEncounter8 e, int encounterIndex) + { + var comment = $" // {species[e.Species]}{(e.Form == 0 ? string.Empty : "-" + e.Form)}"; + var gender = e.Gender == 0 ? string.Empty : $", Gender = {e.Gender - 1}"; + var altform = e.Form == 0 ? string.Empty : $", Form = {e.Form}"; + var istr = $", Index = {encounterIndex}"; + var giga = !e.IsGigantamax ? string.Empty : ", CanGigantamax = true"; + var moves = $", Moves = new({e.Move0:000}, {e.Move1:000}, {e.Move2:000}, {e.Move3:000})"; + var shiny = e.ShinyLock switch + { + 0 => string.Empty, + 1 => ", Shiny = Shiny.Never", + 2 => ", Shiny = Shiny.Always", + _ => throw new Exception() + }; + var ability = e.Ability switch + { + 0 => "A0", // 1 + 1 => "A1", // 2 + 2 => "A2", // H + 3 => "A3", // 1/2 only + 4 => "A4", // 1/2/H + _ => throw new Exception() + }; - public override string ToString() => $"[{MinRank},{MaxRank}] {(Species)Species}-{Form}"; + // calc min/max ranks + int min = e.MinRank; + int max = e.MaxRank; + for (int i = min; i < max; i++) + { + if (e.Probabilities[i] == 0) + throw new Exception(); + } + var flawless = e.FlawlessIVs; + var line = $" new({e.Level:00},{e.DynamaxLevel:00},{flawless}) {{ Species = {e.Species:000}, Ability = {ability}{moves}{istr}{gender}{altform}{giga}{shiny} }},{comment}"; + if (e.Field_13 == 6 && e.Field_14 == 6) + line = line.Insert(12, "//").Remove(10, 2); // comment out uncatchable encounters + return line; + } + } + + public string GetSummarySimple() + { + var tableID = TableID.ToString("X16"); + var tableData = TableUtil.GetTable(Entries); + + return tableID + Environment.NewLine + tableData + Environment.NewLine; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleDistributionEncounter8 +{ + [FlatBufferItem(00)] public int EntryIndex { get; set; } + [FlatBufferItem(01)] public int Species { get; set; } + [FlatBufferItem(02)] public int Form { get; set; } + [FlatBufferItem(03)] public int Level { get; set; } + [FlatBufferItem(04)] public ushort DynamaxLevel { get; set; } + [FlatBufferItem(05)] public uint Field_05 { get; set; } // probably EVs + [FlatBufferItem(06)] public uint Field_06 { get; set; } + [FlatBufferItem(07)] public uint Field_07 { get; set; } + [FlatBufferItem(08)] public uint Field_08 { get; set; } + [FlatBufferItem(09)] public uint Field_09 { get; set; } + [FlatBufferItem(10)] public uint Field_0A { get; set; } + [FlatBufferItem(11)] public byte Ability { get; set; } + [FlatBufferItem(12)] public bool IsGigantamax { get; set; } + [FlatBufferItem(13)] public ulong DropTableID { get; set; } + [FlatBufferItem(14)] public ulong BonusTableID { get; set; } + [FlatBufferItem(15)] public int[] Probabilities { get; set; } + [FlatBufferItem(16)] public byte Gender { get; set; } + [FlatBufferItem(17)] public byte FlawlessIVs { get; set; } + [FlatBufferItem(18)] public byte ShinyLock { get; set; } + [FlatBufferItem(19)] public byte Field_13 { get; set; } // 3/4 + [FlatBufferItem(20)] public byte Field_14 { get; set; } // 3/4/5 -- +1 for second entries + [FlatBufferItem(21)] public byte Nature { get; set; } + [FlatBufferItem(22)] public int Field_16 { get; set; } + [FlatBufferItem(23)] public uint Move0 { get; set; } + [FlatBufferItem(24)] public uint Move1 { get; set; } + [FlatBufferItem(25)] public uint Move2 { get; set; } + [FlatBufferItem(26)] public uint Move3 { get; set; } + [FlatBufferItem(27)] public float DynamaxBoost { get; set; } + [FlatBufferItem(28)] public uint Field_1C { get; set; } + [FlatBufferItem(29)] public uint Field_1D { get; set; } + [FlatBufferItem(30)] public uint Field_1E { get; set; } // Shield + [FlatBufferItem(31)] public uint Field_1F { get; set; } // % only if move + [FlatBufferItem(32)] public uint Field_20 { get; set; } // Move ID + [FlatBufferItem(33)] public uint Field_21 { get; set; } // Shield only if move + [FlatBufferItem(34)] public uint Field_22 { get; set; } // % only if move + [FlatBufferItem(35)] public uint Field_23 { get; set; } // Move ID + [FlatBufferItem(36)] public uint Field_24 { get; set; } // shield? only if move + + public int MinRank => Array.FindIndex(Probabilities, z => z != 0); + public int MaxRank => Array.FindLastIndex(Probabilities, z => z != 0); + public bool Exists => Probabilities.Any(z => z != 0); + + public override string ToString() => $"[{MinRank},{MaxRank}] {(Species)Species}-{Form}"; +} diff --git a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionReward8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionReward8Archive.cs index 7b158464..6f236fec 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionReward8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleDistributionReward8Archive.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,46 +8,45 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleDistributionReward8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleDistributionReward8Archive : IFlatBufferArchive + [FlatBufferItem(0)] public NestHoleDistributionReward8Table[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleDistributionReward8Table : INestHoleRewardTable +{ + [FlatBufferItem(0)] public ulong TableID { get; set; } + [FlatBufferItem(1)] public NestHoleDistributionReward8[] Entries { get; set; } + + public INestHoleReward[] Rewards => Entries; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleDistributionReward8 : INestHoleReward +{ + [FlatBufferItem(0)] public byte Value0 { get; set; } + [FlatBufferItem(1)] public byte Value1 { get; set; } + [FlatBufferItem(2)] public byte Value2 { get; set; } + [FlatBufferItem(3)] public byte Value3 { get; set; } + [FlatBufferItem(4)] public byte Value4 { get; set; } + [FlatBufferItem(5)] public ushort ItemID { get; set; } + + public uint Item => ItemID; + + public uint[] Values { - [FlatBufferItem(0)] public NestHoleDistributionReward8Table[] Table { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleDistributionReward8Table : INestHoleRewardTable - { - [FlatBufferItem(0)] public ulong TableID { get; set; } - [FlatBufferItem(1)] public NestHoleDistributionReward8[] Entries { get; set; } - - public INestHoleReward[] Rewards => Entries; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleDistributionReward8 : INestHoleReward - { - [FlatBufferItem(0)] public byte Value0 { get; set; } - [FlatBufferItem(1)] public byte Value1 { get; set; } - [FlatBufferItem(2)] public byte Value2 { get; set; } - [FlatBufferItem(3)] public byte Value3 { get; set; } - [FlatBufferItem(4)] public byte Value4 { get; set; } - [FlatBufferItem(5)] public ushort ItemID { get; set; } - - public uint Item => ItemID; - - public uint[] Values + get => new uint[] { Value0, Value1, Value2, Value3, Value4 }; + set { - get => new uint[] { Value0, Value1, Value2, Value3, Value4 }; - set - { - Value0 = (byte)value[0]; - Value1 = (byte)value[1]; - Value2 = (byte)value[2]; - Value3 = (byte)value[3]; - Value4 = (byte)value[4]; - } + Value0 = (byte)value[0]; + Value1 = (byte)value[1]; + Value2 = (byte)value[2]; + Value3 = (byte)value[3]; + Value4 = (byte)value[4]; } } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleLevel8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleLevel8Archive.cs index 8f683597..8e8f0e7b 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleLevel8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleLevel8Archive.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,25 +8,24 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleLevel8Archive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleLevel8Archive - { - [FlatBufferItem(0)] public NestHoleLevel8Table[] Tables { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleLevel8Table - { - [FlatBufferItem(0)] public ulong TableID { get; set; } - [FlatBufferItem(1)] public NestHoleLevel8[] Entries { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleLevel8 - { - [FlatBufferItem(0)] public uint MinLevel { get; set; } - [FlatBufferItem(1)] public uint MaxLevel { get; set; } - } + [FlatBufferItem(0)] public NestHoleLevel8Table[] Tables { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleLevel8Table +{ + [FlatBufferItem(0)] public ulong TableID { get; set; } + [FlatBufferItem(1)] public NestHoleLevel8[] Entries { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleLevel8 +{ + [FlatBufferItem(0)] public uint MinLevel { get; set; } + [FlatBufferItem(1)] public uint MaxLevel { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleReward8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleReward8Archive.cs index f0b7844a..3d8543c0 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleReward8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Nest/NestHoleReward8Archive.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,45 +8,44 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleReward8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleReward8Archive : IFlatBufferArchive - { - [FlatBufferItem(0)] public NestHoleReward8Table[] Table { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleReward8Table : INestHoleRewardTable - { - [FlatBufferItem(0)] public ulong TableID { get; set; } - [FlatBufferItem(1)] public NestHoleReward8[] Entries { get; set; } - - [Browsable(false)] - public INestHoleReward[] Rewards => Entries; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class NestHoleReward8 : INestHoleReward - { - [FlatBufferItem(0)] public uint EntryID { get; set; } - [FlatBufferItem(1)] public uint ItemID { get; set; } - [FlatBufferItem(2)] public uint[] Values { get; set; } - - public uint Item => ItemID; - - public override string ToString() => $"{EntryID:0} - {ItemID:0000}"; - } - - public interface INestHoleReward - { - uint Item { get; } - uint[] Values { get; set; } - } - - public interface INestHoleRewardTable - { - ulong TableID { get; set; } - INestHoleReward[] Rewards { get; } - } + [FlatBufferItem(0)] public NestHoleReward8Table[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleReward8Table : INestHoleRewardTable +{ + [FlatBufferItem(0)] public ulong TableID { get; set; } + [FlatBufferItem(1)] public NestHoleReward8[] Entries { get; set; } + + [Browsable(false)] + public INestHoleReward[] Rewards => Entries; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class NestHoleReward8 : INestHoleReward +{ + [FlatBufferItem(0)] public uint EntryID { get; set; } + [FlatBufferItem(1)] public uint ItemID { get; set; } + [FlatBufferItem(2)] public uint[] Values { get; set; } + + public uint Item => ItemID; + + public override string ToString() => $"{EntryID:0} - {ItemID:0000}"; +} + +public interface INestHoleReward +{ + uint Item { get; } + uint[] Values { get; set; } +} + +public interface INestHoleRewardTable +{ + ulong TableID { get; set; } + INestHoleReward[] Rewards { get; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/ArchiveContent.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/ArchiveContent.cs index 51bedd79..52658085 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/ArchiveContent.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/ArchiveContent.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,19 +8,18 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers -{ - // archive_contents.bin -- 7707 entry table (file, files) - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class ArchiveContents : IFlatBufferArchive - { - [FlatBufferItem(00)] public ArchiveContent[] Table { get; set; } - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class ArchiveContent - { - [FlatBufferItem(00)] public ulong Hash { get; set; } - [FlatBufferItem(01)] public string Hashes { get; set; } - } +// archive_contents.bin -- 7707 entry table (file, files) +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class ArchiveContents : IFlatBufferArchive +{ + [FlatBufferItem(00)] public ArchiveContent[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class ArchiveContent +{ + [FlatBufferItem(00)] public ulong Hash { get; set; } + [FlatBufferItem(01)] public string Hashes { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/CellTable.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/CellTable.cs index 83e1313e..bac2cfce 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/CellTable.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/CellTable.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using System.Text; using FlatSharp; using FlatSharp.Attributes; @@ -10,80 +10,79 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// poke_memory_data.prmb and others +// this is oddly similar to the map data FlatBuffer, assumed the same schema to encode an excel table? +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class CellTable { - // poke_memory_data.prmb and others - // this is oddly similar to the map data FlatBuffer, assumed the same schema to encode an excel table? - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class CellTable - { - [FlatBufferItem(0)] public CellMetaQuad[] QuadTable { get; set; } - [FlatBufferItem(1)] public CellUnion[] MainTable { get; set; } - [FlatBufferItem(2)] public CellMetaHashes[] DualTable { get; set; } + [FlatBufferItem(0)] public CellMetaQuad[] QuadTable { get; set; } + [FlatBufferItem(1)] public CellUnion[] MainTable { get; set; } + [FlatBufferItem(2)] public CellMetaHashes[] DualTable { get; set; } - public string[] Dump(int cellsPerRow, char tab = '\t') + public string[] Dump(int cellsPerRow, char tab = '\t') + { + var result = new string[MainTable.Length / cellsPerRow]; + for (int i = 0; i < result.Length; i++) { - var result = new string[MainTable.Length / cellsPerRow]; - for (int i = 0; i < result.Length; i++) + var index = i * cellsPerRow; + var sb = new StringBuilder(); + for (int j = 0; j < cellsPerRow; j++) { - var index = i * cellsPerRow; - var sb = new StringBuilder(); - for (int j = 0; j < cellsPerRow; j++) - { - if (j != 0) - sb.Append(tab); - sb.Append(MainTable[index + j]); - } - result[i] = sb.ToString(); + if (j != 0) + sb.Append(tab); + sb.Append(MainTable[index + j]); } - return result; + result[i] = sb.ToString(); } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class CellMetaQuad - { - [FlatBufferItem(0)] public int Field0 { get; set; } - [FlatBufferItem(1)] public int Field1 { get; set; } - [FlatBufferItem(2)] public int Field2 { get; set; } - [FlatBufferItem(3)] public int Field3 { get; set; } - - public override string ToString() => $"{Field0}|{Field1}|{Field2}|{Field3}"; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class CellUnion - { -#nullable enable - [FlatBufferItem(0)] public FlatBufferUnion? Field1 { get; set; } -#nullable disable - public override string ToString() => Field1?.Discriminator switch - { - 1 => Field1.Item1.ToString(), - 2 => Field1.Item3.ToString(), - 4 => Field1.Item4.ToString(), - _ => "Empty", - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellInt { [FlatBufferItem(0)] public int Value { get; set; } public override string ToString() => Value.ToString(); } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellBool { [FlatBufferItem(0)] public bool Flag { get; set; } public override string ToString() => Flag.ToString(); } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellString { [FlatBufferItem(0)] public string Name { get; set; } public override string ToString() => Name; } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellHash { [FlatBufferItem(0)] public ulong Hash { get; set; } public override string ToString() => Hash.ToString("X16"); } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class CellMetaHashes - { - [FlatBufferItem(0)] public ulong Hash { get; set; } - [FlatBufferItem(1)] public CellHashTuple[] Pairs { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class CellHashTuple - { - [FlatBufferItem(0)] public ulong Hash0 { get; set; } - [FlatBufferItem(1)] public ulong Hash1 { get; set; } - - public override string ToString() => $"{Hash0:X16} {Hash1:X16}"; + return result; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class CellMetaQuad +{ + [FlatBufferItem(0)] public int Field0 { get; set; } + [FlatBufferItem(1)] public int Field1 { get; set; } + [FlatBufferItem(2)] public int Field2 { get; set; } + [FlatBufferItem(3)] public int Field3 { get; set; } + + public override string ToString() => $"{Field0}|{Field1}|{Field2}|{Field3}"; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class CellUnion +{ +#nullable enable + [FlatBufferItem(0)] public FlatBufferUnion? Field1 { get; set; } +#nullable disable + public override string ToString() => Field1?.Discriminator switch + { + 1 => Field1.Item1.ToString(), + 2 => Field1.Item3.ToString(), + 4 => Field1.Item4.ToString(), + _ => "Empty", + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellInt { [FlatBufferItem(0)] public int Value { get; set; } public override string ToString() => Value.ToString(); } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellBool { [FlatBufferItem(0)] public bool Flag { get; set; } public override string ToString() => Flag.ToString(); } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellString { [FlatBufferItem(0)] public string Name { get; set; } public override string ToString() => Name; } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class CellHash { [FlatBufferItem(0)] public ulong Hash { get; set; } public override string ToString() => Hash.ToString("X16"); } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class CellMetaHashes +{ + [FlatBufferItem(0)] public ulong Hash { get; set; } + [FlatBufferItem(1)] public CellHashTuple[] Pairs { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class CellHashTuple +{ + [FlatBufferItem(0)] public ulong Hash0 { get; set; } + [FlatBufferItem(1)] public ulong Hash1 { get; set; } + + public override string ToString() => $"{Hash0:X16} {Hash1:X16}"; +} diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/MapData8.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/MapData8.cs index 078b74c1..94a149e7 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/MapData8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/MapData8.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -9,62 +9,61 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// map_data.prmb +// map_placement_data.prmb +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class MapContainer { - // map_data.prmb - // map_placement_data.prmb - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class MapContainer - { - [FlatBufferItem(0)] public SubTable0[] Field0 { get; set; } - [FlatBufferItem(1)] public MapUnion[] Field1 { get; set; } - [FlatBufferItem(2)] public SubTable2[] Field2 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class SubTable0 - { - [FlatBufferItem(0)] public int Field0 { get; set; } - [FlatBufferItem(1)] public int Field1 { get; set; } - [FlatBufferItem(2)] public int Field2 { get; set; } - [FlatBufferItem(3)] public int Field3 { get; set; } - - public override string ToString() => $"{Field0}|{Field1}|{Field2}|{Field3}"; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class MapUnion - { -#nullable enable - [FlatBufferItem(0)] public FlatBufferUnion? Field1 { get; set; } -#nullable disable - public override string ToString() => Field1?.Discriminator switch - { - 1 => Field1.Item1.ToString(), - 2 => Field1.Item3.ToString(), - 4 => Field1.Item4.ToString(), - _ => "Empty", - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_1 {[FlatBufferItem(0)] public int Value { get; set; } } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_2 {[FlatBufferItem(0)] public byte Dummy { get; set; } } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_3 {[FlatBufferItem(0)] public string Name { get; set; } } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_4 {[FlatBufferItem(0)] public ulong Hash { get; set; } } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class SubTable2 - { - [FlatBufferItem(0)] public ulong Hash { get; set; } - [FlatBufferItem(1)] public DualHash[] Pairs { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class DualHash - { - [FlatBufferItem(0)] public ulong Hash0 { get; set; } - [FlatBufferItem(1)] public ulong Hash1 { get; set; } - - public override string ToString() => $"{Hash0:X16} {Hash1:X16}"; - } + [FlatBufferItem(0)] public SubTable0[] Field0 { get; set; } + [FlatBufferItem(1)] public MapUnion[] Field1 { get; set; } + [FlatBufferItem(2)] public SubTable2[] Field2 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class SubTable0 +{ + [FlatBufferItem(0)] public int Field0 { get; set; } + [FlatBufferItem(1)] public int Field1 { get; set; } + [FlatBufferItem(2)] public int Field2 { get; set; } + [FlatBufferItem(3)] public int Field3 { get; set; } + + public override string ToString() => $"{Field0}|{Field1}|{Field2}|{Field3}"; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class MapUnion +{ +#nullable enable + [FlatBufferItem(0)] public FlatBufferUnion? Field1 { get; set; } +#nullable disable + public override string ToString() => Field1?.Discriminator switch + { + 1 => Field1.Item1.ToString(), + 2 => Field1.Item3.ToString(), + 4 => Field1.Item4.ToString(), + _ => "Empty", + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_1 {[FlatBufferItem(0)] public int Value { get; set; } } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_2 {[FlatBufferItem(0)] public byte Dummy { get; set; } } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_3 {[FlatBufferItem(0)] public string Name { get; set; } } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] public class ST1_4 {[FlatBufferItem(0)] public ulong Hash { get; set; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class SubTable2 +{ + [FlatBufferItem(0)] public ulong Hash { get; set; } + [FlatBufferItem(1)] public DualHash[] Pairs { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class DualHash +{ + [FlatBufferItem(0)] public ulong Hash0 { get; set; } + [FlatBufferItem(1)] public ulong Hash1 { get; set; } + + public override string ToString() => $"{Hash0:X16} {Hash1:X16}"; } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/PokeResourceTable.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/PokeResourceTable.cs index 0a05ce88..c9df7e2b 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/PokeResourceTable.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/PokeResourceTable.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/Rental8.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/Rental8.cs index 747d5036..0557f770 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/Rental8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/Rental8.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,45 +8,44 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class Rental8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class Rental8Archive : IFlatBufferArchive - { - [FlatBufferItem(00)] public Rental8[] Table { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class Rental8 - { - [FlatBufferItem(00)] public byte EV_SPE { get; set; } - [FlatBufferItem(01)] public byte EV_ATK { get; set; } - [FlatBufferItem(02)] public byte EV_DEF { get; set; } - [FlatBufferItem(03)] public byte EV_HP { get; set; } - [FlatBufferItem(04)] public byte EV_SPA { get; set; } - [FlatBufferItem(05)] public byte EV_SPD { get; set; } - [FlatBufferItem(06)] public byte Form { get; set; } - [FlatBufferItem(07)] public int Ball { get; set; } - [FlatBufferItem(08)] public ulong Hash1 { get; set; } - [FlatBufferItem(09)] public int Item { get; set; } - [FlatBufferItem(10)] public byte Level { get; set; } - [FlatBufferItem(11)] public int Species { get; set; } - [FlatBufferItem(12)] public ulong Hash2 { get; set; } - [FlatBufferItem(13)] public uint TrainerID { get; set; } // maybe?? no entries have this - [FlatBufferItem(14)] public int Nature { get; set; } - [FlatBufferItem(15)] public int Gender { get; set; } - [FlatBufferItem(16)] public sbyte IV_SPE { get; set; } - [FlatBufferItem(17)] public sbyte IV_ATK { get; set; } - [FlatBufferItem(18)] public sbyte IV_DEF { get; set; } - [FlatBufferItem(19)] public sbyte IV_HP { get; set; } - [FlatBufferItem(20)] public sbyte IV_SPA { get; set; } - [FlatBufferItem(21)] public sbyte IV_SPD { get; set; } - [FlatBufferItem(22)] public int Ability { get; set; } // 0,1,2(Hidden) - [FlatBufferItem(23)] public int Move1 { get; set; } - [FlatBufferItem(24)] public int Move2 { get; set; } - [FlatBufferItem(25)] public int Move3 { get; set; } - [FlatBufferItem(26)] public int Move4 { get; set; } - - public Species SpeciesID => (Species)Species; - } + [FlatBufferItem(00)] public Rental8[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class Rental8 +{ + [FlatBufferItem(00)] public byte EV_SPE { get; set; } + [FlatBufferItem(01)] public byte EV_ATK { get; set; } + [FlatBufferItem(02)] public byte EV_DEF { get; set; } + [FlatBufferItem(03)] public byte EV_HP { get; set; } + [FlatBufferItem(04)] public byte EV_SPA { get; set; } + [FlatBufferItem(05)] public byte EV_SPD { get; set; } + [FlatBufferItem(06)] public byte Form { get; set; } + [FlatBufferItem(07)] public int Ball { get; set; } + [FlatBufferItem(08)] public ulong Hash1 { get; set; } + [FlatBufferItem(09)] public int Item { get; set; } + [FlatBufferItem(10)] public byte Level { get; set; } + [FlatBufferItem(11)] public int Species { get; set; } + [FlatBufferItem(12)] public ulong Hash2 { get; set; } + [FlatBufferItem(13)] public uint TrainerID { get; set; } // maybe?? no entries have this + [FlatBufferItem(14)] public int Nature { get; set; } + [FlatBufferItem(15)] public int Gender { get; set; } + [FlatBufferItem(16)] public sbyte IV_SPE { get; set; } + [FlatBufferItem(17)] public sbyte IV_ATK { get; set; } + [FlatBufferItem(18)] public sbyte IV_DEF { get; set; } + [FlatBufferItem(19)] public sbyte IV_HP { get; set; } + [FlatBufferItem(20)] public sbyte IV_SPA { get; set; } + [FlatBufferItem(21)] public sbyte IV_SPD { get; set; } + [FlatBufferItem(22)] public int Ability { get; set; } // 0,1,2(Hidden) + [FlatBufferItem(23)] public int Move1 { get; set; } + [FlatBufferItem(24)] public int Move2 { get; set; } + [FlatBufferItem(25)] public int Move3 { get; set; } + [FlatBufferItem(26)] public int Move4 { get; set; } + + public Species SpeciesID => (Species)Species; } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/ScriptMeta.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/ScriptMeta.cs index 64fa5dff..c57453c7 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/ScriptMeta.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/ScriptMeta.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,20 +8,19 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers -{ - // script_id_record.bin - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class ScriptMeta : IFlatBufferArchive - { - [FlatBufferItem(0)] public ScriptMetaEntry[] Table { get; set; } - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class ScriptMetaEntry - { - [FlatBufferItem(0)] public ulong Hash { get; set; } - [FlatBufferItem(1)] public string PathAMX { get; set; } - [FlatBufferItem(2)] public string PathText { get; set; } - } +// script_id_record.bin +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class ScriptMeta : IFlatBufferArchive +{ + [FlatBufferItem(0)] public ScriptMetaEntry[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class ScriptMetaEntry +{ + [FlatBufferItem(0)] public ulong Hash { get; set; } + [FlatBufferItem(1)] public string PathAMX { get; set; } + [FlatBufferItem(2)] public string PathText { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/SymbolBehavior.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/SymbolBehavior.cs index 1465c461..a2f0355e 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/SymbolBehavior.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/SymbolBehavior.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -8,65 +8,64 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// symbol_encount_mons_param.bin +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class SymbolBehaveRoot : IFlatBufferArchive { - // symbol_encount_mons_param.bin - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class SymbolBehaveRoot : IFlatBufferArchive - { - [FlatBufferItem(00)] public SymbolBehave[] Table { get; set; } = Array.Empty(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class SymbolBehave - { - public Species Species => (Species)SpeciesID; - - [FlatBufferItem(00)] public float Field_00 {get; set;} - [FlatBufferItem(01)] public float Field_01 {get; set;} - [FlatBufferItem(02)] public string ModelPart {get; set;} = ""; - [FlatBufferItem(03)] public float Field_03 {get; set;} - [FlatBufferItem(04)] public ulong Hash1 {get; set;} - [FlatBufferItem(05)] public ulong Hash2 {get; set;} - [FlatBufferItem(06)] public float HitboxRadius {get; set;} - [FlatBufferItem(07)] public float Field_07 {get; set;} - [FlatBufferItem(08)] public float Field_08 {get; set;} // unused default, assumed float - [FlatBufferItem(09)] public float Field_09 {get; set;} - [FlatBufferItem(10)] public int Form {get; set;} - [FlatBufferItem(11)] public byte Field_11 {get; set;} - [FlatBufferItem(12)] public byte Field_12 {get; set;} // unused default, assumed byte - [FlatBufferItem(13)] public int SpeciesID {get; set;} - [FlatBufferItem(14)] public byte Field_14 {get; set;} // unused default, assumed byte - [FlatBufferItem(15)] public byte Field_15 {get; set;} // unused default, assumed byte - [FlatBufferItem(16)] public float Field_16 {get; set;} - [FlatBufferItem(17)] public float Field_17 {get; set;} - [FlatBufferItem(18)] public int Field_18 {get; set;} - [FlatBufferItem(19)] public float Field_19 {get; set;} - [FlatBufferItem(20)] public float Field_20 {get; set;} - [FlatBufferItem(21)] public float Field_21 {get; set;} - [FlatBufferItem(22)] public string SpeciesNameJPN {get; set;} = ""; // internal name - [FlatBufferItem(23)] public float Field_23 {get; set;} - [FlatBufferItem(24)] public float Field_24 {get; set;} - [FlatBufferItem(25)] public float Field_25 {get; set;} - [FlatBufferItem(26)] public float Field_26 {get; set;} - [FlatBufferItem(27)] public float GrassShakeRadius {get; set;} - [FlatBufferItem(28)] public float Field_28 {get; set;} // unused default, assumed float - [FlatBufferItem(29)] public int Field_29 {get; set;} - [FlatBufferItem(30)] public int Field_30 {get; set;} // unused default, assumed int - [FlatBufferItem(31)] public string Behavior {get; set;} = ""; - [FlatBufferItem(32)] public int Field_32 {get; set;} - [FlatBufferItem(33)] public int Field_33 {get; set;} // unused default, assumed int - [FlatBufferItem(34)] public int Field_34 {get; set;} // unused default, assumed int - [FlatBufferItem(35)] public int Field_35 {get; set;} // unused default, assumed int - [FlatBufferItem(36)] public int Field_36 {get; set; } // unused default, assumed int - [FlatBufferItem(37)] public float Field_37 {get; set;} - [FlatBufferItem(38)] public float Field_38 {get; set;} - [FlatBufferItem(39)] public float Field_39 {get; set;} - [FlatBufferItem(40)] public float Field_40 {get; set;} - [FlatBufferItem(41)] public float Field_41 {get; set;} - [FlatBufferItem(42)] public float Field_42 {get; set;} // unused default, assumed float - [FlatBufferItem(43)] public float Field_43 {get; set;} // unused default, assumed float - [FlatBufferItem(44)] public float Field_44 {get; set;} - [FlatBufferItem(45)] public float Field_45 {get; set;} - } + [FlatBufferItem(00)] public SymbolBehave[] Table { get; set; } = Array.Empty(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class SymbolBehave +{ + public Species Species => (Species)SpeciesID; + + [FlatBufferItem(00)] public float Field_00 {get; set;} + [FlatBufferItem(01)] public float Field_01 {get; set;} + [FlatBufferItem(02)] public string ModelPart {get; set;} = ""; + [FlatBufferItem(03)] public float Field_03 {get; set;} + [FlatBufferItem(04)] public ulong Hash1 {get; set;} + [FlatBufferItem(05)] public ulong Hash2 {get; set;} + [FlatBufferItem(06)] public float HitboxRadius {get; set;} + [FlatBufferItem(07)] public float Field_07 {get; set;} + [FlatBufferItem(08)] public float Field_08 {get; set;} // unused default, assumed float + [FlatBufferItem(09)] public float Field_09 {get; set;} + [FlatBufferItem(10)] public int Form {get; set;} + [FlatBufferItem(11)] public byte Field_11 {get; set;} + [FlatBufferItem(12)] public byte Field_12 {get; set;} // unused default, assumed byte + [FlatBufferItem(13)] public int SpeciesID {get; set;} + [FlatBufferItem(14)] public byte Field_14 {get; set;} // unused default, assumed byte + [FlatBufferItem(15)] public byte Field_15 {get; set;} // unused default, assumed byte + [FlatBufferItem(16)] public float Field_16 {get; set;} + [FlatBufferItem(17)] public float Field_17 {get; set;} + [FlatBufferItem(18)] public int Field_18 {get; set;} + [FlatBufferItem(19)] public float Field_19 {get; set;} + [FlatBufferItem(20)] public float Field_20 {get; set;} + [FlatBufferItem(21)] public float Field_21 {get; set;} + [FlatBufferItem(22)] public string SpeciesNameJPN {get; set;} = ""; // internal name + [FlatBufferItem(23)] public float Field_23 {get; set;} + [FlatBufferItem(24)] public float Field_24 {get; set;} + [FlatBufferItem(25)] public float Field_25 {get; set;} + [FlatBufferItem(26)] public float Field_26 {get; set;} + [FlatBufferItem(27)] public float GrassShakeRadius {get; set;} + [FlatBufferItem(28)] public float Field_28 {get; set;} // unused default, assumed float + [FlatBufferItem(29)] public int Field_29 {get; set;} + [FlatBufferItem(30)] public int Field_30 {get; set;} // unused default, assumed int + [FlatBufferItem(31)] public string Behavior {get; set;} = ""; + [FlatBufferItem(32)] public int Field_32 {get; set;} + [FlatBufferItem(33)] public int Field_33 {get; set;} // unused default, assumed int + [FlatBufferItem(34)] public int Field_34 {get; set;} // unused default, assumed int + [FlatBufferItem(35)] public int Field_35 {get; set;} // unused default, assumed int + [FlatBufferItem(36)] public int Field_36 {get; set; } // unused default, assumed int + [FlatBufferItem(37)] public float Field_37 {get; set;} + [FlatBufferItem(38)] public float Field_38 {get; set;} + [FlatBufferItem(39)] public float Field_39 {get; set;} + [FlatBufferItem(40)] public float Field_40 {get; set;} + [FlatBufferItem(41)] public float Field_41 {get; set;} + [FlatBufferItem(42)] public float Field_42 {get; set;} // unused default, assumed float + [FlatBufferItem(43)] public float Field_43 {get; set;} // unused default, assumed float + [FlatBufferItem(44)] public float Field_44 {get; set;} + [FlatBufferItem(45)] public float Field_45 {get; set;} } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/Waza8.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/Waza8.cs index e5da8254..8aa6467d 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/Waza8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/Waza8.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -7,111 +7,110 @@ // ReSharper disable UnusedMember.Global #nullable disable -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class Waza8 : IMove { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class Waza8 : IMove + public byte[] Write() => FlatBufferConverter.SerializeFrom(this); + + // Type mismatch; FlatBuffer must use the correct struct type for each field + // We need to alias these and hide them from any PropertyGrid, so mark Browsable(false). + + [FlatBufferItem(00)] public uint Version { get; set; } + [FlatBufferItem(01)] public uint MoveID { get; set; } + [FlatBufferItem(02)] public bool CanUseMove { get; set; } + [FlatBufferItem(03), Browsable(false)] public byte FType { get; set; } + [FlatBufferItem(04), Browsable(false)] public byte FQuality { get; set; } + [FlatBufferItem(05), Browsable(false)] public byte FCategory { get; set; } + [FlatBufferItem(06), Browsable(false)] public byte FPower { get; set; } + [FlatBufferItem(07), Browsable(false)] public byte FAccuracy { get; set; } + [FlatBufferItem(08), Browsable(false)] public byte FPP { get; set; } + [FlatBufferItem(09), Browsable(false)] public byte FPriority { get; set; } + [FlatBufferItem(10), Browsable(false)] public byte FHitMin { get; set; } + [FlatBufferItem(11), Browsable(false)] public byte FHitMax { get; set; } + [FlatBufferItem(12), Browsable(false)] public ushort FInflict { get; set; } + [FlatBufferItem(13), Browsable(false)] public byte FInflictPercent { get; set; } + [FlatBufferItem(14), Browsable(false)] public byte FRawInflictCount { get; set; } + [FlatBufferItem(15), Browsable(false)] public byte FTurnMin { get; set; } + [FlatBufferItem(16), Browsable(false)] public byte FTurnMax { get; set; } + [FlatBufferItem(17), Browsable(false)] public byte FCritStage { get; set; } + [FlatBufferItem(18), Browsable(false)] public byte FFlinch { get; set; } + [FlatBufferItem(19), Browsable(false)] public ushort FEffectSequence { get; set; } + [FlatBufferItem(20), Browsable(false)] public byte FRecoil { get; set; } + [FlatBufferItem(21), Browsable(false)] public byte FRawHealing { get; set; } + [FlatBufferItem(22), Browsable(false)] public byte FRawTarget { get; set; } + [FlatBufferItem(23), Browsable(false)] public byte FStat1 { get; set; } + [FlatBufferItem(24), Browsable(false)] public byte FStat2 { get; set; } + [FlatBufferItem(25), Browsable(false)] public byte FStat3 { get; set; } + [FlatBufferItem(26), Browsable(false)] public byte FStat1Stage { get; set; } + [FlatBufferItem(27), Browsable(false)] public byte FStat2Stage { get; set; } + [FlatBufferItem(28), Browsable(false)] public byte FStat3Stage { get; set; } + [FlatBufferItem(29), Browsable(false)] public byte FStat1Percent { get; set; } + [FlatBufferItem(30), Browsable(false)] public byte FStat2Percent { get; set; } + [FlatBufferItem(31), Browsable(false)] public byte FStat3Percent { get; set; } + [FlatBufferItem(32)] public byte GigantamaxPower { get; set; } + [FlatBufferItem(33)] public bool Flag_MakesContact { get; set; } + [FlatBufferItem(34)] public bool Flag_Charge { get; set; } + [FlatBufferItem(35)] public bool Flag_Recharge { get; set; } + [FlatBufferItem(36)] public bool Flag_Protect { get; set; } + [FlatBufferItem(37)] public bool Flag_Reflectable { get; set; } + [FlatBufferItem(38)] public bool Flag_Snatch { get; set; } + [FlatBufferItem(39)] public bool Flag_Mirror { get; set; } + [FlatBufferItem(40)] public bool Flag_Punch { get; set; } + [FlatBufferItem(41)] public bool Flag_Sound { get; set; } + [FlatBufferItem(42)] public bool Flag_Gravity { get; set; } + [FlatBufferItem(43)] public bool Flag_Defrost { get; set; } + [FlatBufferItem(44)] public bool Flag_DistanceTriple { get; set; } + [FlatBufferItem(45)] public bool Flag_Heal { get; set; } + [FlatBufferItem(46)] public bool Flag_IgnoreSubstitute { get; set; } + [FlatBufferItem(47)] public bool Flag_FailSkyBattle { get; set; } + [FlatBufferItem(48)] public bool Flag_AnimateAlly { get; set; } + [FlatBufferItem(49)] public bool Flag_Dance { get; set; } + [FlatBufferItem(50)] public bool Flag_Metronome { get; set; } + + public int Type { get => FType; set => FType = (byte)value; } + public int Quality { get => FQuality ; set => FQuality = (byte)value; } + public int Category { get => FCategory ; set => FCategory = (byte)value; } + public int Power { get => FPower ; set => FPower = (byte)value; } + public int Accuracy { get => FAccuracy ; set => FAccuracy = (byte)value; } + public int PP { get => FPP ; set => FPP = (byte)value; } + public int Priority { get => FPriority ; set => FPriority = (byte)value; } + public int HitMin { get => FHitMin ; set => FHitMin = (byte)value; } + public int HitMax { get => FHitMax ; set => FHitMax = (byte)value; } + public int Inflict { get => FInflict ; set => FInflict = (ushort)value; } + public int InflictPercent { get => FInflictPercent ; set => FInflictPercent = (byte)value; } + public int TurnMin { get => FTurnMin ; set => FTurnMin = (byte)value; } + public int TurnMax { get => FTurnMax ; set => FTurnMax = (byte)value; } + public int CritStage { get => FCritStage ; set => FCritStage = (byte)value; } + public int Flinch { get => FFlinch ; set => FFlinch = (byte)value; } + public int EffectSequence { get => FEffectSequence ; set => FEffectSequence = (ushort)value; } + public int Recoil { get => FRecoil ; set => FRecoil = (byte)value; } + public int Stat1 { get => FStat1 ; set => FStat1 = (byte)value; } + public int Stat2 { get => FStat2 ; set => FStat2 = (byte)value; } + public int Stat3 { get => FStat3 ; set => FStat3 = (byte)value; } + public int Stat1Stage { get => FStat1Stage ; set => FStat1Stage = (byte)value; } + public int Stat2Stage { get => FStat2Stage ; set => FStat2Stage = (byte)value; } + public int Stat3Stage { get => FStat3Stage ; set => FStat3Stage = (byte)value; } + public int Stat1Percent { get => FStat1Percent ; set => FStat1Percent = (byte)value; } + public int Stat2Percent { get => FStat2Percent ; set => FStat2Percent = (byte)value; } + public int Stat3Percent { get => FStat3Percent ; set => FStat3Percent = (byte)value; } + + public MoveInflictDuration InflictCount { - public byte[] Write() => FlatBufferConverter.SerializeFrom(this); + get => (MoveInflictDuration)FRawInflictCount; + set => FRawInflictCount = (byte)value; + } - // Type mismatch; FlatBuffer must use the correct struct type for each field - // We need to alias these and hide them from any PropertyGrid, so mark Browsable(false). + public Heal Healing + { + get => (Heal)FRawHealing; + set => FRawHealing = (byte)value; + } - [FlatBufferItem(00)] public uint Version { get; set; } - [FlatBufferItem(01)] public uint MoveID { get; set; } - [FlatBufferItem(02)] public bool CanUseMove { get; set; } - [FlatBufferItem(03), Browsable(false)] public byte FType { get; set; } - [FlatBufferItem(04), Browsable(false)] public byte FQuality { get; set; } - [FlatBufferItem(05), Browsable(false)] public byte FCategory { get; set; } - [FlatBufferItem(06), Browsable(false)] public byte FPower { get; set; } - [FlatBufferItem(07), Browsable(false)] public byte FAccuracy { get; set; } - [FlatBufferItem(08), Browsable(false)] public byte FPP { get; set; } - [FlatBufferItem(09), Browsable(false)] public byte FPriority { get; set; } - [FlatBufferItem(10), Browsable(false)] public byte FHitMin { get; set; } - [FlatBufferItem(11), Browsable(false)] public byte FHitMax { get; set; } - [FlatBufferItem(12), Browsable(false)] public ushort FInflict { get; set; } - [FlatBufferItem(13), Browsable(false)] public byte FInflictPercent { get; set; } - [FlatBufferItem(14), Browsable(false)] public byte FRawInflictCount { get; set; } - [FlatBufferItem(15), Browsable(false)] public byte FTurnMin { get; set; } - [FlatBufferItem(16), Browsable(false)] public byte FTurnMax { get; set; } - [FlatBufferItem(17), Browsable(false)] public byte FCritStage { get; set; } - [FlatBufferItem(18), Browsable(false)] public byte FFlinch { get; set; } - [FlatBufferItem(19), Browsable(false)] public ushort FEffectSequence { get; set; } - [FlatBufferItem(20), Browsable(false)] public byte FRecoil { get; set; } - [FlatBufferItem(21), Browsable(false)] public byte FRawHealing { get; set; } - [FlatBufferItem(22), Browsable(false)] public byte FRawTarget { get; set; } - [FlatBufferItem(23), Browsable(false)] public byte FStat1 { get; set; } - [FlatBufferItem(24), Browsable(false)] public byte FStat2 { get; set; } - [FlatBufferItem(25), Browsable(false)] public byte FStat3 { get; set; } - [FlatBufferItem(26), Browsable(false)] public byte FStat1Stage { get; set; } - [FlatBufferItem(27), Browsable(false)] public byte FStat2Stage { get; set; } - [FlatBufferItem(28), Browsable(false)] public byte FStat3Stage { get; set; } - [FlatBufferItem(29), Browsable(false)] public byte FStat1Percent { get; set; } - [FlatBufferItem(30), Browsable(false)] public byte FStat2Percent { get; set; } - [FlatBufferItem(31), Browsable(false)] public byte FStat3Percent { get; set; } - [FlatBufferItem(32)] public byte GigantamaxPower { get; set; } - [FlatBufferItem(33)] public bool Flag_MakesContact { get; set; } - [FlatBufferItem(34)] public bool Flag_Charge { get; set; } - [FlatBufferItem(35)] public bool Flag_Recharge { get; set; } - [FlatBufferItem(36)] public bool Flag_Protect { get; set; } - [FlatBufferItem(37)] public bool Flag_Reflectable { get; set; } - [FlatBufferItem(38)] public bool Flag_Snatch { get; set; } - [FlatBufferItem(39)] public bool Flag_Mirror { get; set; } - [FlatBufferItem(40)] public bool Flag_Punch { get; set; } - [FlatBufferItem(41)] public bool Flag_Sound { get; set; } - [FlatBufferItem(42)] public bool Flag_Gravity { get; set; } - [FlatBufferItem(43)] public bool Flag_Defrost { get; set; } - [FlatBufferItem(44)] public bool Flag_DistanceTriple { get; set; } - [FlatBufferItem(45)] public bool Flag_Heal { get; set; } - [FlatBufferItem(46)] public bool Flag_IgnoreSubstitute { get; set; } - [FlatBufferItem(47)] public bool Flag_FailSkyBattle { get; set; } - [FlatBufferItem(48)] public bool Flag_AnimateAlly { get; set; } - [FlatBufferItem(49)] public bool Flag_Dance { get; set; } - [FlatBufferItem(50)] public bool Flag_Metronome { get; set; } - - public int Type { get => FType; set => FType = (byte)value; } - public int Quality { get => FQuality ; set => FQuality = (byte)value; } - public int Category { get => FCategory ; set => FCategory = (byte)value; } - public int Power { get => FPower ; set => FPower = (byte)value; } - public int Accuracy { get => FAccuracy ; set => FAccuracy = (byte)value; } - public int PP { get => FPP ; set => FPP = (byte)value; } - public int Priority { get => FPriority ; set => FPriority = (byte)value; } - public int HitMin { get => FHitMin ; set => FHitMin = (byte)value; } - public int HitMax { get => FHitMax ; set => FHitMax = (byte)value; } - public int Inflict { get => FInflict ; set => FInflict = (ushort)value; } - public int InflictPercent { get => FInflictPercent ; set => FInflictPercent = (byte)value; } - public int TurnMin { get => FTurnMin ; set => FTurnMin = (byte)value; } - public int TurnMax { get => FTurnMax ; set => FTurnMax = (byte)value; } - public int CritStage { get => FCritStage ; set => FCritStage = (byte)value; } - public int Flinch { get => FFlinch ; set => FFlinch = (byte)value; } - public int EffectSequence { get => FEffectSequence ; set => FEffectSequence = (ushort)value; } - public int Recoil { get => FRecoil ; set => FRecoil = (byte)value; } - public int Stat1 { get => FStat1 ; set => FStat1 = (byte)value; } - public int Stat2 { get => FStat2 ; set => FStat2 = (byte)value; } - public int Stat3 { get => FStat3 ; set => FStat3 = (byte)value; } - public int Stat1Stage { get => FStat1Stage ; set => FStat1Stage = (byte)value; } - public int Stat2Stage { get => FStat2Stage ; set => FStat2Stage = (byte)value; } - public int Stat3Stage { get => FStat3Stage ; set => FStat3Stage = (byte)value; } - public int Stat1Percent { get => FStat1Percent ; set => FStat1Percent = (byte)value; } - public int Stat2Percent { get => FStat2Percent ; set => FStat2Percent = (byte)value; } - public int Stat3Percent { get => FStat3Percent ; set => FStat3Percent = (byte)value; } - - public MoveInflictDuration InflictCount - { - get => (MoveInflictDuration)FRawInflictCount; - set => FRawInflictCount = (byte)value; - } - - public Heal Healing - { - get => (Heal)FRawHealing; - set => FRawHealing = (byte)value; - } - - public MoveTarget Target - { - get => (MoveTarget)FRawTarget; - set => FRawTarget = (byte)value; - } + public MoveTarget Target + { + get => (MoveTarget)FRawTarget; + set => FRawTarget = (byte)value; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Other/WeatherEntry.cs b/pkNX.Structures.FlatBuffers/Gen8/Other/WeatherEntry.cs index 9b0561b4..e25320f8 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Other/WeatherEntry.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Other/WeatherEntry.cs @@ -8,65 +8,64 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// field\param\weather\weather_data.bin +// field\param\weather\weather_data_alt.bin +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class WeatherTable : IFlatBufferArchive { - // field\param\weather\weather_data.bin - // field\param\weather\weather_data_alt.bin - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class WeatherTable : IFlatBufferArchive - { - [FlatBufferItem(0)] public WeatherEntry[] Table { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class WeatherEntry - { - [FlatBufferItem(00)] public byte Field_00 { get; set; } // all except 0 - [FlatBufferItem(01)] public int[] Field_01 { get; set; } // unused in main, used in _alt - [FlatBufferItem(02)] public string[] Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } // entry 2 3 4 5 6 7 8 - [FlatBufferItem(04)] public float Field_04 { get; set; } // entry 2 3 4 5 6 7 8 - [FlatBufferItem(05)] public float Field_05 { get; set; } // entry 2 3 4 5 6 7 8 9 10 11 12 14 - [FlatBufferItem(06)] public float Field_06 { get; set; } // unused - [FlatBufferItem(07)] public float Field_07 { get; set; } // entry 2 3 - [FlatBufferItem(08)] public float Field_08 { get; set; } // entry 2 3 7 - [FlatBufferItem(09)] public uint Field_09 { get; set; } - [FlatBufferItem(10)] public uint Field_10 { get; set; } - [FlatBufferItem(11)] public float Field_11 { get; set; } // entry 1 2 3 4 5 7 8 10 11 12 13 14 - [FlatBufferItem(12)] public PentaFloat Field_12 { get; set; } - [FlatBufferItem(13)] public float[] Field_13 { get; set; } - [FlatBufferItem(14)] public float[] Field_14 { get; set; } - [FlatBufferItem(15)] public QuadFloatSet Field_15 { get; set; } - [FlatBufferItem(16)] public QuadFloatSet Field_16 { get; set; } - [FlatBufferItem(17)] public PentaFloat Field_17 { get; set; } - [FlatBufferItem(18)] public float Field_18 { get; set; } // entry 1 2 3 4 5 7 8 10 11 12 13 14 - [FlatBufferItem(19)] public float Field_19 { get; set; } - [FlatBufferItem(20)] public float Field_20 { get; set; } - [FlatBufferItem(21)] public float[] Field_21 { get; set; } - [FlatBufferItem(22)] public float[] Field_22 { get; set; } - [FlatBufferItem(23)] public int[] Field_23 { get; set; } - [FlatBufferItem(24)] public byte Field_24 { get; set; } // entry 9 10 11 12 13 14 - [FlatBufferItem(25)] public uint Field_25 { get; set; } // unused - [FlatBufferItem(26)] public uint Field_26 { get; set; } // unused - [FlatBufferItem(27)] public byte Field_27 { get; set; } // entry 6 - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PentaFloat - { - [FlatBufferItem(00)] public float Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class QuadFloatSet - { - [FlatBufferItem(00)] public float[] Field_00 { get; set; } - [FlatBufferItem(01)] public float[] Field_01 { get; set; } - [FlatBufferItem(02)] public float[] Field_02 { get; set; } - [FlatBufferItem(03)] public float[] Field_03 { get; set; } - } + [FlatBufferItem(0)] public WeatherEntry[] Table { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class WeatherEntry +{ + [FlatBufferItem(00)] public byte Field_00 { get; set; } // all except 0 + [FlatBufferItem(01)] public int[] Field_01 { get; set; } // unused in main, used in _alt + [FlatBufferItem(02)] public string[] Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } // entry 2 3 4 5 6 7 8 + [FlatBufferItem(04)] public float Field_04 { get; set; } // entry 2 3 4 5 6 7 8 + [FlatBufferItem(05)] public float Field_05 { get; set; } // entry 2 3 4 5 6 7 8 9 10 11 12 14 + [FlatBufferItem(06)] public float Field_06 { get; set; } // unused + [FlatBufferItem(07)] public float Field_07 { get; set; } // entry 2 3 + [FlatBufferItem(08)] public float Field_08 { get; set; } // entry 2 3 7 + [FlatBufferItem(09)] public uint Field_09 { get; set; } + [FlatBufferItem(10)] public uint Field_10 { get; set; } + [FlatBufferItem(11)] public float Field_11 { get; set; } // entry 1 2 3 4 5 7 8 10 11 12 13 14 + [FlatBufferItem(12)] public PentaFloat Field_12 { get; set; } + [FlatBufferItem(13)] public float[] Field_13 { get; set; } + [FlatBufferItem(14)] public float[] Field_14 { get; set; } + [FlatBufferItem(15)] public QuadFloatSet Field_15 { get; set; } + [FlatBufferItem(16)] public QuadFloatSet Field_16 { get; set; } + [FlatBufferItem(17)] public PentaFloat Field_17 { get; set; } + [FlatBufferItem(18)] public float Field_18 { get; set; } // entry 1 2 3 4 5 7 8 10 11 12 13 14 + [FlatBufferItem(19)] public float Field_19 { get; set; } + [FlatBufferItem(20)] public float Field_20 { get; set; } + [FlatBufferItem(21)] public float[] Field_21 { get; set; } + [FlatBufferItem(22)] public float[] Field_22 { get; set; } + [FlatBufferItem(23)] public int[] Field_23 { get; set; } + [FlatBufferItem(24)] public byte Field_24 { get; set; } // entry 9 10 11 12 13 14 + [FlatBufferItem(25)] public uint Field_25 { get; set; } // unused + [FlatBufferItem(26)] public uint Field_26 { get; set; } // unused + [FlatBufferItem(27)] public byte Field_27 { get; set; } // entry 6 +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PentaFloat +{ + [FlatBufferItem(00)] public float Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class QuadFloatSet +{ + [FlatBufferItem(00)] public float[] Field_00 { get; set; } + [FlatBufferItem(01)] public float[] Field_01 { get; set; } + [FlatBufferItem(02)] public float[] Field_02 { get; set; } + [FlatBufferItem(03)] public float[] Field_03 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8Archive.cs index 277a472c..ac26221b 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8Archive.cs @@ -8,44 +8,43 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementArea8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementArea8Archive : IFlatBufferArchive - { - [FlatBufferItem(00)] public PlacementZone8[] Table { get; set; } = Array.Empty(); - [FlatBufferItem(01)] public ulong Hash { get; set; } - [FlatBufferItem(02)] public string Description { get; set; } = ""; - [FlatBufferItem(03)] public string OtherDescription { get; set; } = ""; - [FlatBufferItem(04)] public PlacementArea8_F04 Unknown { get; set; } = new(); - [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get; set; } - [FlatBufferItem(08)] public float Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(09)] public float Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(10)] public float Field_10 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(11)] public float Field_11 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(12)] public float Field_12 { get; set; } - [FlatBufferItem(13)] public float Field_13 { get; set; } - [FlatBufferItem(14)] public float Field_14 { get; set; } - [FlatBufferItem(15)] public float Field_15 { get; set; } - [FlatBufferItem(16)] public float Field_16 { get; set; } - [FlatBufferItem(17)] public float Field_17 { get; set; } - [FlatBufferItem(18)] public float Field_18 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(19)] public float Field_19 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(20)] public float Field_20 { get; set; } - [FlatBufferItem(21)] public float Field_21 { get; set; } - [FlatBufferItem(22)] public float Field_22 { get; set; } - [FlatBufferItem(23)] public float Field_23 { get; set; } - [FlatBufferItem(24)] public PlacementArea8_F24 Field_24 { get; set; } = new(); - [FlatBufferItem(25)] public uint Field_25 { get; set; } // 3000 - [FlatBufferItem(26)] public float Field_26 { get; set; } - [FlatBufferItem(27)] public byte Field_27 { get; set; } - [FlatBufferItem(28)] public byte Field_28 { get; set; } - [FlatBufferItem(29)] public byte Field_29 { get; set; } // present in a_d0101 - [FlatBufferItem(30)] public byte Field_30 { get; set; } - [FlatBufferItem(31)] public float Field_31 { get; set; } - [FlatBufferItem(32)] public float Field_32 { get; set; } - [FlatBufferItem(33)] public byte Field_33 { get; set; } - } + [FlatBufferItem(00)] public PlacementZone8[] Table { get; set; } = Array.Empty(); + [FlatBufferItem(01)] public ulong Hash { get; set; } + [FlatBufferItem(02)] public string Description { get; set; } = ""; + [FlatBufferItem(03)] public string OtherDescription { get; set; } = ""; + [FlatBufferItem(04)] public PlacementArea8_F04 Unknown { get; set; } = new(); + [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get; set; } + [FlatBufferItem(08)] public float Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(09)] public float Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(10)] public float Field_10 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(11)] public float Field_11 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(12)] public float Field_12 { get; set; } + [FlatBufferItem(13)] public float Field_13 { get; set; } + [FlatBufferItem(14)] public float Field_14 { get; set; } + [FlatBufferItem(15)] public float Field_15 { get; set; } + [FlatBufferItem(16)] public float Field_16 { get; set; } + [FlatBufferItem(17)] public float Field_17 { get; set; } + [FlatBufferItem(18)] public float Field_18 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(19)] public float Field_19 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(20)] public float Field_20 { get; set; } + [FlatBufferItem(21)] public float Field_21 { get; set; } + [FlatBufferItem(22)] public float Field_22 { get; set; } + [FlatBufferItem(23)] public float Field_23 { get; set; } + [FlatBufferItem(24)] public PlacementArea8_F24 Field_24 { get; set; } = new(); + [FlatBufferItem(25)] public uint Field_25 { get; set; } // 3000 + [FlatBufferItem(26)] public float Field_26 { get; set; } + [FlatBufferItem(27)] public byte Field_27 { get; set; } + [FlatBufferItem(28)] public byte Field_28 { get; set; } + [FlatBufferItem(29)] public byte Field_29 { get; set; } // present in a_d0101 + [FlatBufferItem(30)] public byte Field_30 { get; set; } + [FlatBufferItem(31)] public float Field_31 { get; set; } + [FlatBufferItem(32)] public float Field_32 { get; set; } + [FlatBufferItem(33)] public byte Field_33 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F04.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F04.cs index dc67e47e..d438f36d 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F04.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F04.cs @@ -7,25 +7,24 @@ // ReSharper disable UnusedMember.Global #nullable disable -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementArea8_F04 { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementArea8_F04 - { - [FlatBufferItem(00)] public float Field_00 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets - [FlatBufferItem(01)] public float Field_01 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets - [FlatBufferItem(02)] public float Field_02 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets + [FlatBufferItem(00)] public float Field_00 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets + [FlatBufferItem(01)] public float Field_01 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets + [FlatBufferItem(02)] public float Field_02 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets - [FlatBufferItem(03)] public float Field_03 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets - [FlatBufferItem(04)] public float Field_04 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets - [FlatBufferItem(05)] public float Field_05 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets + [FlatBufferItem(03)] public float Field_03 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets + [FlatBufferItem(04)] public float Field_04 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets + [FlatBufferItem(05)] public float Field_05 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get; set; } - [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get; set; } + [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public ulong Field_09 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets - [FlatBufferItem(10)] public ulong Field_10 { get; set; } - [FlatBufferItem(11)] public ulong Field_11 { get; set; } - } + [FlatBufferItem(09)] public ulong Field_09 { get; set; } // unused, assumed to be same shape as other v3f-hash triplets + [FlatBufferItem(10)] public ulong Field_10 { get; set; } + [FlatBufferItem(11)] public ulong Field_11 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F24.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F24.cs index 1b3eac3c..eb8531e1 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F24.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/PlacementArea8_F24.cs @@ -6,25 +6,24 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementArea8_F24 { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementArea8_F24 - { - [FlatBufferItem(00)] public byte Field_00 { get; set; } - [FlatBufferItem(01)] public PlacementAreaUnknownTiny8 Field_01 { get; set; } = new(); - [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(00)] public byte Field_00 { get; set; } + [FlatBufferItem(01)] public PlacementAreaUnknownTiny8 Field_01 { get; set; } = new(); + [FlatBufferItem(02)] public float Field_02 { get; set; } - public override string ToString() => $"{Field_00}, {Field_02}: {Field_01}"; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementAreaUnknownTiny8 - { - [FlatBufferItem(00)] public float Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - - public override string ToString() => $"{Field_00}, {Field_01}, {Field_02}"; - } + public override string ToString() => $"{Field_00}, {Field_02}: {Field_01}"; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementAreaUnknownTiny8 +{ + [FlatBufferItem(00)] public float Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + + public override string ToString() => $"{Field_00}, {Field_01}, {Field_02}"; } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8AdvancedTipHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8AdvancedTipHolder.cs index 6d69ef57..768c77a6 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8AdvancedTipHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8AdvancedTipHolder.cs @@ -9,70 +9,69 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8AdvancedTipHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8AdvancedTipHolder - { - [FlatBufferItem(00)] public PlacementZone8AdvancedTip Field_00 { get; set; } - [FlatBufferItem(01)] public uint Field_01 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(02)] public uint Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(03)] public ulong SignHash { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8AdvancedTip - { - [FlatBufferItem(00)] public PlacementZone8_F14 Field_00 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F14 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } - [FlatBufferItem(01)] public string NameModel { get; set; } - [FlatBufferItem(02)] public string NameAnimation { get; set; } // none have this - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public string Field_05 { get; set; } // none have this - [FlatBufferItem(06)] public string Field_06 { get; set; } // none have this - [FlatBufferItem(07)] public float Field_07 { get; set; } - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(11)] public PlacementZone8_F14_B Field_11 { get; set; } - [FlatBufferItem(12)] public uint Field_12 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(13)] public PlacementZone8_F14_B Field_13 { get; set; } - [FlatBufferItem(14)] public PlacementZone8_F14_Union Field_14 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F14_B - { - [FlatBufferItem(00)] public uint Field_00 { get; set; } // 2 - [FlatBufferItem(01)] public float Field_01 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F14_Union - { - [FlatBufferItem(00)] public bool Field_00 { get; set; } = true; - [FlatBufferItem(01)] public PlacementZone8_F14_Sub Field_01 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F14_Sub - { - [FlatBufferItem(00)] public float Field_00 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(01)] public float Field_01 { get; set; } - } + [FlatBufferItem(00)] public PlacementZone8AdvancedTip Field_00 { get; set; } + [FlatBufferItem(01)] public uint Field_01 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(02)] public uint Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(03)] public ulong SignHash { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8AdvancedTip +{ + [FlatBufferItem(00)] public PlacementZone8_F14 Field_00 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F14 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } + [FlatBufferItem(01)] public string NameModel { get; set; } + [FlatBufferItem(02)] public string NameAnimation { get; set; } // none have this + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public string Field_05 { get; set; } // none have this + [FlatBufferItem(06)] public string Field_06 { get; set; } // none have this + [FlatBufferItem(07)] public float Field_07 { get; set; } + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(11)] public PlacementZone8_F14_B Field_11 { get; set; } + [FlatBufferItem(12)] public uint Field_12 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(13)] public PlacementZone8_F14_B Field_13 { get; set; } + [FlatBufferItem(14)] public PlacementZone8_F14_Union Field_14 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F14_B +{ + [FlatBufferItem(00)] public uint Field_00 { get; set; } // 2 + [FlatBufferItem(01)] public float Field_01 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F14_Union +{ + [FlatBufferItem(00)] public bool Field_00 { get; set; } = true; + [FlatBufferItem(01)] public PlacementZone8_F14_Sub Field_01 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F14_Sub +{ + [FlatBufferItem(00)] public float Field_00 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(01)] public float Field_01 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8BerryTreeHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8BerryTreeHolder.cs index 9f19ab3b..adbdcf2c 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8BerryTreeHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8BerryTreeHolder.cs @@ -8,70 +8,69 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8BerryTreeHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8BerryTreeHolder - { - [FlatBufferItem(00)] public PlacementZone8_F22_0 Field_00 { get; set; } = new(); // meta - [FlatBufferItem(01)] public PlacementZone8BerryTreeRandom[] Field_01 { get; set; } = Array.Empty(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F22_0 - { - [FlatBufferItem(00)] public PlacementZone8_F22_0_0 Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F22_0_0 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public string Field_01 { get; set; } = ""; // none have this - [FlatBufferItem(02)] public string Field_02 { get; set; } = ""; // none have this - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public string Field_05 { get; set; } = ""; // none have this - [FlatBufferItem(06)] public string Field_06 { get; set; } = ""; // none have this - [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public float Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(09)] public float Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(10)] public float Field_10 { get; set; } - [FlatBufferItem(11)] public PlacementZone8_F22_Sub Field_11 { get; set; } = new(); - [FlatBufferItem(12)] public uint Field_12 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(13)] public PlacementZone8_F22_Sub Field_13 { get; set; } = new(); - [FlatBufferItem(14)] public PlacementZone8_F22_BoolObject14 Field_14 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F22_Sub - { - [FlatBufferItem(00)] public uint Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } // unused in all - [FlatBufferItem(02)] public float Field_02 { get; set; } // unused in all - [FlatBufferItem(03)] public float Field_03 { get; set; } // unused in all - [FlatBufferItem(04)] public float Field_04 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F22_BoolObject14 - { - [FlatBufferItem(0)] public byte Type { get; set; } - [FlatBufferItem(1)] public PlacementZone_F22_Inner Object { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone_F22_Inner - { - [FlatBufferItem(00)] public float Field_00 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(01)] public float Field_01 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8BerryTreeRandom - { - [FlatBufferItem(0)] public ulong Hash { get; set; } - [FlatBufferItem(1)] public uint Rate { get; set; } - [FlatBufferItem(2)] public uint Quantity { get; set; } // always 1? - } + [FlatBufferItem(00)] public PlacementZone8_F22_0 Field_00 { get; set; } = new(); // meta + [FlatBufferItem(01)] public PlacementZone8BerryTreeRandom[] Field_01 { get; set; } = Array.Empty(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F22_0 +{ + [FlatBufferItem(00)] public PlacementZone8_F22_0_0 Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F22_0_0 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public string Field_01 { get; set; } = ""; // none have this + [FlatBufferItem(02)] public string Field_02 { get; set; } = ""; // none have this + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public string Field_05 { get; set; } = ""; // none have this + [FlatBufferItem(06)] public string Field_06 { get; set; } = ""; // none have this + [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public float Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(09)] public float Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(10)] public float Field_10 { get; set; } + [FlatBufferItem(11)] public PlacementZone8_F22_Sub Field_11 { get; set; } = new(); + [FlatBufferItem(12)] public uint Field_12 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(13)] public PlacementZone8_F22_Sub Field_13 { get; set; } = new(); + [FlatBufferItem(14)] public PlacementZone8_F22_BoolObject14 Field_14 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F22_Sub +{ + [FlatBufferItem(00)] public uint Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } // unused in all + [FlatBufferItem(02)] public float Field_02 { get; set; } // unused in all + [FlatBufferItem(03)] public float Field_03 { get; set; } // unused in all + [FlatBufferItem(04)] public float Field_04 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F22_BoolObject14 +{ + [FlatBufferItem(0)] public byte Type { get; set; } + [FlatBufferItem(1)] public PlacementZone_F22_Inner Object { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone_F22_Inner +{ + [FlatBufferItem(00)] public float Field_00 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(01)] public float Field_01 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8BerryTreeRandom +{ + [FlatBufferItem(0)] public ulong Hash { get; set; } + [FlatBufferItem(1)] public uint Rate { get; set; } + [FlatBufferItem(2)] public uint Quantity { get; set; } // always 1? } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8EnvironmentHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8EnvironmentHolder.cs index 861862c7..a4933493 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8EnvironmentHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8EnvironmentHolder.cs @@ -8,23 +8,22 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers -{ - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8EnvironmentHolder - { - [FlatBufferItem(00)] public PlacementZone8_F10 Field_00 { get; set; } = new(); - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F10 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public PlacementZone8_V3f[] Field_01 { get; set; } = Array.Empty(); - [FlatBufferItem(02)] public string PlayName { get; set; } = ""; - [FlatBufferItem(03)] public string StopName { get; set; } = ""; - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public int Field_05 { get; set; } - [FlatBufferItem(06)] public int Field_06 { get; set; } - } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8EnvironmentHolder +{ + [FlatBufferItem(00)] public PlacementZone8_F10 Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F10 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public PlacementZone8_V3f[] Field_01 { get; set; } = Array.Empty(); + [FlatBufferItem(02)] public string PlayName { get; set; } = ""; + [FlatBufferItem(03)] public string StopName { get; set; } = ""; + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public int Field_05 { get; set; } + [FlatBufferItem(06)] public int Field_06 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FieldItemHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FieldItemHolder.cs index e8cbd4a8..d9731e65 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FieldItemHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FieldItemHolder.cs @@ -8,33 +8,32 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8FieldItemHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8FieldItemHolder - { - [FlatBufferItem(00)] public PlacementZone8FieldItem Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8FieldItem - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public string Field_02 { get; set; } = ""; - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public ulong Hash_05 { get; set; } - [FlatBufferItem(06)] public ulong[] Flags { get; set; } = Array.Empty(); - [FlatBufferItem(07)] public uint[] Items { get; set; } = Array.Empty(); - [FlatBufferItem(08)] public byte Quantity { get; set; } - [FlatBufferItem(09)] public PlacementZone8FieldItem_A Field_09 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8FieldItem_A - { - [FlatBufferItem(00)] public bool Field_00 { get; set; } - [FlatBufferItem(01)] public FlatDummyObject Field_01 { get; set; } = new(); - } + [FlatBufferItem(00)] public PlacementZone8FieldItem Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8FieldItem +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public string Field_02 { get; set; } = ""; + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public ulong Hash_05 { get; set; } + [FlatBufferItem(06)] public ulong[] Flags { get; set; } = Array.Empty(); + [FlatBufferItem(07)] public uint[] Items { get; set; } = Array.Empty(); + [FlatBufferItem(08)] public byte Quantity { get; set; } + [FlatBufferItem(09)] public PlacementZone8FieldItem_A Field_09 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8FieldItem_A +{ + [FlatBufferItem(00)] public bool Field_00 { get; set; } + [FlatBufferItem(01)] public FlatDummyObject Field_01 { get; set; } = new(); } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FishingPointHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FishingPointHolder.cs index 2de63732..7269af0f 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FishingPointHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FishingPointHolder.cs @@ -6,29 +6,28 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8FishingPointHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8FishingPointHolder - { - [FlatBufferItem(00)] public PlacementZone8FishingPoint Object { get; set; } = new(); + [FlatBufferItem(00)] public PlacementZone8FishingPoint Object { get; set; } = new(); - public override string ToString() => $"{Object.Identifier}" + (Object.IterateForSlotsExceptLastN == 0 ? "" : $" SkipLast{Object.IterateForSlotsExceptLastN}"); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8FishingPoint - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get; set; } - - [FlatBufferItem(08), Description("When iterating over slots to pick a random one, the iteration will skip the last (value) amount of slots.")] - public uint IterateForSlotsExceptLastN { get; set; } - } + public override string ToString() => $"{Object.Identifier}" + (Object.IterateForSlotsExceptLastN == 0 ? "" : $" SkipLast{Object.IterateForSlotsExceptLastN}"); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8FishingPoint +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get; set; } + + [FlatBufferItem(08), Description("When iterating over slots to pick a random one, the iteration will skip the last (value) amount of slots.")] + public uint IterateForSlotsExceptLastN { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FlightAnchorHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FlightAnchorHolder.cs index e40d175f..7417b902 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FlightAnchorHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8FlightAnchorHolder.cs @@ -6,19 +6,18 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers -{ - // player flying to location - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8FlightAnchorHolder - { - [FlatBufferItem(00)] public PlacementZone8FlightAnchor FlightAnchor { get; set; } = new(); - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8FlightAnchor - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Placement { get; set; } = new(); - [FlatBufferItem(01)] public ulong UnlockFlagHash { get; set; } - } +// player flying to location +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8FlightAnchorHolder +{ + [FlatBufferItem(00)] public PlacementZone8FlightAnchor FlightAnchor { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8FlightAnchor +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Placement { get; set; } = new(); + [FlatBufferItem(01)] public ulong UnlockFlagHash { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8HiddenItemHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8HiddenItemHolder.cs index 55d2bd37..e365ce66 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8HiddenItemHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8HiddenItemHolder.cs @@ -8,40 +8,39 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8HiddenItemHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8HiddenItemHolder - { - [FlatBufferItem(00)] public PlacementZone8HiddenItem Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8HiddenItem - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public PlacementZone8HiddenItemValue Field_01 { get; set; } = new(); - [FlatBufferItem(02)] public PlacementZone8HiddenItemChance[] Field_02 { get; set; } = Array.Empty(); - [FlatBufferItem(03)] public int Field_03 { get; set; } - [FlatBufferItem(04)] public uint Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8HiddenItemValue - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } // unused - [FlatBufferItem(02)] public float Field_02 { get; set; } // unused - [FlatBufferItem(03)] public float Field_03 { get; set; } // unused - [FlatBufferItem(04)] public float Field_04 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8HiddenItemChance - { - [FlatBufferItem(00)] public ulong Hash { get; set; } - [FlatBufferItem(01)] public int Chance { get; set; } - [FlatBufferItem(02)] public int Quantity { get; set; } - } + [FlatBufferItem(00)] public PlacementZone8HiddenItem Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8HiddenItem +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public PlacementZone8HiddenItemValue Field_01 { get; set; } = new(); + [FlatBufferItem(02)] public PlacementZone8HiddenItemChance[] Field_02 { get; set; } = Array.Empty(); + [FlatBufferItem(03)] public int Field_03 { get; set; } + [FlatBufferItem(04)] public uint Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8HiddenItemValue +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } // unused + [FlatBufferItem(02)] public float Field_02 { get; set; } // unused + [FlatBufferItem(03)] public float Field_03 { get; set; } // unused + [FlatBufferItem(04)] public float Field_04 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8HiddenItemChance +{ + [FlatBufferItem(00)] public ulong Hash { get; set; } + [FlatBufferItem(01)] public int Chance { get; set; } + [FlatBufferItem(02)] public int Quantity { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8IKStepHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8IKStepHolder.cs index 5d239d10..95a9eace 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8IKStepHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8IKStepHolder.cs @@ -7,42 +7,41 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// IK_Step +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8IKStepHolder { - // IK_Step - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8IKStepHolder - { - [FlatBufferItem(00)] public PlacementZone8_F25 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public byte Field_01 { get; set; } - [FlatBufferItem(02)] public byte Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(03)] public byte Field_03 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F25 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong Field_01 { get; set; } - [FlatBufferItem(02)] public PlacementZone8_F25_X Field_02 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F25_X - { - [FlatBufferItem(00)] public uint Field_00 { get; set; } - [FlatBufferItem(01)] public uint Field_01 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - - [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(03)] public float Field_03 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(04)] public float Field_04 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - - [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } + [FlatBufferItem(00)] public PlacementZone8_F25 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public byte Field_01 { get; set; } + [FlatBufferItem(02)] public byte Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(03)] public byte Field_03 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F25 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong Field_01 { get; set; } + [FlatBufferItem(02)] public PlacementZone8_F25_X Field_02 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F25_X +{ + [FlatBufferItem(00)] public uint Field_00 { get; set; } + [FlatBufferItem(01)] public uint Field_01 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + + [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(03)] public float Field_03 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(04)] public float Field_04 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + + [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8LadderHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8LadderHolder.cs index 50802d36..d6d18d41 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8LadderHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8LadderHolder.cs @@ -6,30 +6,29 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8LadderHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8LadderHolder - { - [FlatBufferItem(00)] public PlacementZone8Ladder Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8Ladder - { - [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(1)] public PlacementZone8_F23_Sub Field_01 { get; set; } = new(); - [FlatBufferItem(2)] public int Field_02 { get; set; } // 1 - [FlatBufferItem(3)] public int Field_03 { get; set; } // 10 - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F23_Sub - { - [FlatBufferItem(00)] public int Field_00 { get; set; } // 10 or -20 - [FlatBufferItem(01)] public float Field_01 { get; set; } // unused - [FlatBufferItem(02)] public float Field_02 { get; set; } // unused - [FlatBufferItem(03)] public float Field_03 { get; set; } // unused - [FlatBufferItem(04)] public float Field_04 { get; set; } // 10 - } + [FlatBufferItem(00)] public PlacementZone8Ladder Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8Ladder +{ + [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(1)] public PlacementZone8_F23_Sub Field_01 { get; set; } = new(); + [FlatBufferItem(2)] public int Field_02 { get; set; } // 1 + [FlatBufferItem(3)] public int Field_03 { get; set; } // 10 +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F23_Sub +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } // 10 or -20 + [FlatBufferItem(01)] public float Field_01 { get; set; } // unused + [FlatBufferItem(02)] public float Field_02 { get; set; } // unused + [FlatBufferItem(03)] public float Field_03 { get; set; } // unused + [FlatBufferItem(04)] public float Field_04 { get; set; } // 10 } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8MovementPathHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8MovementPathHolder.cs index c1aed75e..4d158306 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8MovementPathHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8MovementPathHolder.cs @@ -8,28 +8,27 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8MovementPathHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8MovementPathHolder - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong PathName { get; set; } - [FlatBufferItem(02)] public uint Field_02 { get; set; } - [FlatBufferItem(03)] public uint Field_03 { get; set; } - [FlatBufferItem(04)] public bool Field_04 { get; set; } - [FlatBufferItem(05)] public PlacementZone8_V3f[] Field_05 { get; set; } = Array.Empty(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_V3f - { - [FlatBufferItem(00)] public float LocationX { get; set; } - [FlatBufferItem(01)] public float LocationY { get; set; } - [FlatBufferItem(02)] public float LocationZ { get; set; } - - public string Location3f => $"({LocationX}, {LocationY}, {LocationZ})"; - - public override string ToString() => Location3f; - } + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong PathName { get; set; } + [FlatBufferItem(02)] public uint Field_02 { get; set; } + [FlatBufferItem(03)] public uint Field_03 { get; set; } + [FlatBufferItem(04)] public bool Field_04 { get; set; } + [FlatBufferItem(05)] public PlacementZone8_V3f[] Field_05 { get; set; } = Array.Empty(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_V3f +{ + [FlatBufferItem(00)] public float LocationX { get; set; } + [FlatBufferItem(01)] public float LocationY { get; set; } + [FlatBufferItem(02)] public float LocationZ { get; set; } + + public string Location3f => $"({LocationX}, {LocationY}, {LocationZ})"; + + public override string ToString() => Location3f; } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NPCHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NPCHolder.cs index af3c8ff4..16057771 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NPCHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NPCHolder.cs @@ -7,26 +7,25 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers -{ - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8NPCHolder - { - [FlatBufferItem(00)] public PlacementZone8NPC Field_00 { get; set; } = new(); - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8NPC - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public ulong Message { get; set; } - [FlatBufferItem(03)] public uint Field_03 { get; set; } - [FlatBufferItem(04)] public ulong WorkValue { get; set; } - [FlatBufferItem(05)] public uint Field_05 { get; set; } - [FlatBufferItem(06)] public uint Field_06 { get; set; } - [FlatBufferItem(07)] public byte Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public byte Byte_08 { get; set; } - [FlatBufferItem(09)] public ulong Hash_09 { get; set; } - } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8NPCHolder +{ + [FlatBufferItem(00)] public PlacementZone8NPC Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8NPC +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public ulong Message { get; set; } + [FlatBufferItem(03)] public uint Field_03 { get; set; } + [FlatBufferItem(04)] public ulong WorkValue { get; set; } + [FlatBufferItem(05)] public uint Field_05 { get; set; } + [FlatBufferItem(06)] public uint Field_06 { get; set; } + [FlatBufferItem(07)] public byte Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public byte Byte_08 { get; set; } + [FlatBufferItem(09)] public ulong Hash_09 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NestHoleHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NestHoleHolder.cs index 5738c2db..c44c523b 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NestHoleHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8NestHoleHolder.cs @@ -7,69 +7,68 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8NestHoleHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8NestHoleHolder - { - [FlatBufferItem(00)] public PlacementZone8_F21_A Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public bool Field_01 { get; set; } - [FlatBufferItem(02)] public int Field_02 { get; set; } // 0,2,6,270,64,12 - [FlatBufferItem(03)] public ulong Common { get; set; } - [FlatBufferItem(04)] public ulong Rare { get; set; } - [FlatBufferItem(05)] public bool Field_05 { get; set; } + [FlatBufferItem(00)] public PlacementZone8_F21_A Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public bool Field_01 { get; set; } + [FlatBufferItem(02)] public int Field_02 { get; set; } // 0,2,6,270,64,12 + [FlatBufferItem(03)] public ulong Common { get; set; } + [FlatBufferItem(04)] public ulong Rare { get; set; } + [FlatBufferItem(05)] public bool Field_05 { get; set; } - [Description("If a flag hash is specified, the savefile value must be true in order for the nest to be enabled.")] - [FlatBufferItem(06)] public ulong EnableSpawns { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F21_A - { - [FlatBufferItem(00)] public PlacementZone8_F21_B Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F21_B - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public string Field_01 { get; set; } = ""; // none have this - [FlatBufferItem(02)] public string Field_02 { get; set; } = ""; // none have this - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public string Field_05 { get; set; } = ""; // none have this - [FlatBufferItem(06)] public string Field_06 { get; set; } = ""; // none have this - [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public float Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(09)] public float Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(10)] public float Field_10 { get; set; } - [FlatBufferItem(11)] public PlacementZone8_F21_IntFloat Field_11 { get; set; } = new(); - [FlatBufferItem(12)] public uint Field_12 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(13)] public PlacementZone8_F21_IntFloat Field_13 { get; set; } = new(); - [FlatBufferItem(14)] public PlacementZone8_F21_BoolObject14 Field_14 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F21_IntFloat - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } // unused in all - [FlatBufferItem(02)] public float Field_02 { get; set; } // unused in all - [FlatBufferItem(03)] public float Field_03 { get; set; } // unused in all - [FlatBufferItem(04)] public float Field_04 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F21_BoolObject14 - { - [FlatBufferItem(0)] public byte Type { get; set; } - [FlatBufferItem(1)] public PlacementZone_F21_Inner Object { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone_F21_Inner - { - [FlatBufferItem(00)] public float Field_00 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(01)] public float Field_01 { get; set; } - } + [Description("If a flag hash is specified, the savefile value must be true in order for the nest to be enabled.")] + [FlatBufferItem(06)] public ulong EnableSpawns { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F21_A +{ + [FlatBufferItem(00)] public PlacementZone8_F21_B Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F21_B +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public string Field_01 { get; set; } = ""; // none have this + [FlatBufferItem(02)] public string Field_02 { get; set; } = ""; // none have this + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public string Field_05 { get; set; } = ""; // none have this + [FlatBufferItem(06)] public string Field_06 { get; set; } = ""; // none have this + [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public float Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(09)] public float Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(10)] public float Field_10 { get; set; } + [FlatBufferItem(11)] public PlacementZone8_F21_IntFloat Field_11 { get; set; } = new(); + [FlatBufferItem(12)] public uint Field_12 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(13)] public PlacementZone8_F21_IntFloat Field_13 { get; set; } = new(); + [FlatBufferItem(14)] public PlacementZone8_F21_BoolObject14 Field_14 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F21_IntFloat +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } // unused in all + [FlatBufferItem(02)] public float Field_02 { get; set; } // unused in all + [FlatBufferItem(03)] public float Field_03 { get; set; } // unused in all + [FlatBufferItem(04)] public float Field_04 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F21_BoolObject14 +{ + [FlatBufferItem(0)] public byte Type { get; set; } + [FlatBufferItem(1)] public PlacementZone_F21_Inner Object { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone_F21_Inner +{ + [FlatBufferItem(00)] public float Field_00 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(01)] public float Field_01 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8OtherNPCHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8OtherNPCHolder.cs index 5a812d1b..74f3399a 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8OtherNPCHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8OtherNPCHolder.cs @@ -9,281 +9,280 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// more NPCs? Trainers? +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8OtherNPCHolder { - // more NPCs? Trainers? - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8OtherNPCHolder + [FlatBufferItem(00)] public PlacementZone8_F16 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public uint ModelVariant { get; set; } + [FlatBufferItem(02)] public ulong Hash_02 { get; set; } + [FlatBufferItem(03)] public ulong Hash_03 { get; set; } + [FlatBufferItem(04)] public PlacementZone8_F16_ArrayEntry[] Field_04 { get; set; } = Array.Empty(); // a_0201.bin[0].[76] @ AAE8 + [FlatBufferItem(05)] public ulong Hash_05 { get; set; } + [FlatBufferItem(06)] public bool Flag_06 { get; set; } + [FlatBufferItem(07)] public bool Flag_07 { get; set; } + [FlatBufferItem(08)] public uint Field_08 { get; set; } + [FlatBufferItem(09)] public FlatModelState State { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } + [FlatBufferItem(11)] public PlacementZone8_F02_Nine Field_11 { get; set; } = new(); + [FlatBufferItem(12)] public uint Field_12 { get; set; } + [FlatBufferItem(13)] public uint AnimationIndexPrimary { get; set; } + [FlatBufferItem(14)] public uint Field_14 { get; set; } + [FlatBufferItem(15)] public uint Field_15 { get; set; } + [FlatBufferItem(16)] public uint Field_16 { get; set; } + + public static readonly Dictionary Models = new() { - [FlatBufferItem(00)] public PlacementZone8_F16 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public uint ModelVariant { get; set; } - [FlatBufferItem(02)] public ulong Hash_02 { get; set; } - [FlatBufferItem(03)] public ulong Hash_03 { get; set; } - [FlatBufferItem(04)] public PlacementZone8_F16_ArrayEntry[] Field_04 { get; set; } = Array.Empty(); // a_0201.bin[0].[76] @ AAE8 - [FlatBufferItem(05)] public ulong Hash_05 { get; set; } - [FlatBufferItem(06)] public bool Flag_06 { get; set; } - [FlatBufferItem(07)] public bool Flag_07 { get; set; } - [FlatBufferItem(08)] public uint Field_08 { get; set; } - [FlatBufferItem(09)] public FlatModelState State { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - [FlatBufferItem(11)] public PlacementZone8_F02_Nine Field_11 { get; set; } = new(); - [FlatBufferItem(12)] public uint Field_12 { get; set; } - [FlatBufferItem(13)] public uint AnimationIndexPrimary { get; set; } - [FlatBufferItem(14)] public uint Field_14 { get; set; } - [FlatBufferItem(15)] public uint Field_15 { get; set; } - [FlatBufferItem(16)] public uint Field_16 { get; set; } + // { 0xFAB9E0BC5EB53C61, "???" }, // CROSS_SHADOW_CHR_0 + { 0x6E0EF08728A00183, "Allister" }, + { 0x6F31044210C526CA, "Artist" }, + { 0x17C135EB3A312C5A, "Avery" }, + { 0xF5A2F864A1EA03C8, "Backpacker" }, + { 0xC4BD80C146AF5526, "Ball Guy" }, + { 0x4D01D66AA548F0DC, "Bea" }, + { 0xF34C5E3BBF2CA12D, "Beauty" }, + { 0x3832B1FD10EA624C, "Bede" }, + { 0x405B1AFD1564C777, "Bede (Gym Leader)" }, + { 0x1E6D78B53BDAC273, "Black Belt" }, + { 0x75616746BD4D626C, "Cabbie" }, + { 0x5EC6DF381EF1AC4F, "Cafe Master" }, + { 0x4B75CAF6B6D9821E, "Cameraman" }, + { 0x46DD9B2B85198218, "Camping King" }, + { 0xAD1F1CBFF500E7EA, "Cara Liss" }, + { 0xCA7C32F9B2364791, "Chef" }, + { 0xEEF53504D3C99ABC, "Child (F)" }, + { 0x515246E1C4850AE9, "Child (M)" }, + { 0x2533395D8C92F2BC, "Clerk (F)" }, + { 0x9EF56DE5A7896E29, "Corviknight Taxi" }, + { 0xE27DD41A334B8864, "Dancer" }, + { 0x6DC9C4941B9DEA36, "Doctor (F)" }, + { 0xA222B32AE2D6DC90, "Doctor (M)" }, + { 0xA86E35CD887C7089, "Dojo Student (F)" }, + { 0xD3C3FECDA1097C14, "Dojo Student (M)" }, + { 0x0DD0DD66398138EA, "Fisher" }, + { 0xCC2FDFB1297BC7EC, "Gentleman" }, + { 0x519298AB56E81403, "Gordie" }, + { 0xA4E43DAB847A65AA, "Gym Challenger Cher" }, + { 0x3A67EB8C01B8787A, "Gym Challenger Corvin" }, + { 0x97381826E816D73F, "Gym Challenger Deneb" }, + { 0xFF82741CC62487EE, "Gym Challenger Dunne" }, + { 0xA8AA3D3DD9090944, "Gym Challenger Icla" }, + { 0xC694A45D0FA7419E, "Gym Challenger Izar" }, + { 0x9F4C7F98FBFE29A8, "Gym Challenger Kent" }, + { 0xB0A5D9D703DE8309, "Gym Challenger Phoebus" }, + { 0x7A61EE8827C20C2B, "Gym Challenger Pia" }, + { 0xC0102468F510883B, "Gym Challenger Polaire" }, + { 0xDB7E13D3072008FE, "Gym Challenger Terry" }, + { 0x93092A2DE60A30E1, "Gym Challenger Theemin" }, + { 0xEDAF14829B6758FA, "Gym Challenger Vega" }, + { 0x4B590544A749C33A, "Gym Challenger Wei" }, + { 0x8DDA7FF298142A66, "Gym Challenger Yue" }, + { 0xAD0CC990973D924C, "Gym Guide" }, + { 0x68E102B9B9C3FCD4, "Gym Trainer (Dark, F)" }, + { 0xE9AAC0E370028C31, "Gym Trainer (Dark, M)" }, + { 0x612098186DB5276E, "Gym Trainer (Dragon, F)" }, + { 0x8DDC3E562E04AEF7, "Gym Trainer (Dragon, M)" }, + { 0xBF61B6E222A4BDCA, "Gym Trainer (Fairy)" }, + { 0x1A6DC73645DA8730, "Gym Trainer (Fighting, F)" }, + { 0xD188F915AA965CBD, "Gym Trainer (Fighting, M)" }, + { 0x03CF766AAE0365E5, "Gym Trainer (Fire, F)" }, + { 0x2E48383E83C58108, "Gym Trainer (Fire, M)" }, + { 0xFD1B0B03A0284FEC, "Gym Trainer (Ghost, F)" }, + { 0x5F779CE090E2E699, "Gym Trainer (Ghost, M)" }, + { 0x7DB4774C9DC12CFF, "Gym Trainer (Grass, F)" }, + { 0xDB41A4BFA1C3F886, "Gym Trainer (Grass, M)" }, + { 0xE779C955C9EADEFE, "Gym Trainer (Ice, F)" }, + { 0x16E06B686F5DD107, "Gym Trainer (Ice, M)" }, + { 0x4785DFF8E04C7A6C, "Gym Trainer (Rock, F)" }, + { 0xA9E271D5D1071119, "Gym Trainer (Rock, M)" }, + { 0xE028414753629816, "Gym Trainer (Water)" }, + { 0x9521A8F7769EA2D1, "Hiker" }, + { 0x8A674F502E959F7C, "Honey" }, + { 0x2E8D2F2916BE7C7B, "Hop" }, + { 0x23D846291019B890, "Hop (Gym Outfit)" }, + { 0x2E53B82FF113D3D0, "Hop's Mother" }, + { 0x6778893672622C8E, "Hop's Poké Ball" }, + { 0x50F70038EB311D7F, "Hyde" }, + { 0x92F76E5098674167, "Jack" }, + { 0x9DAEC40F62597D12, "Kabu" }, + { 0xA03DC074D6206787, "Klara" }, + { 0xCBFEDC059EF3A979, "Lass" }, + { 0xC0BA5B7E2930D108, "League Staff (F)" }, + { 0x6E154F07B75792C8, "League Staff (F)" }, + { 0x964199AA536EB5E5, "League Staff (M)" }, + { 0x42C608079ECFCFD1, "League Staff (M)" }, + { 0xC157261277011D12, "Leon" }, + { 0xC8A60F127AC2B7FD, "Leon (Battle Tower)" }, + { 0x5492E0DC2DA3C026, "Macro Cosmos Employee (F)" }, + { 0x07C16BDC02736E97, "Macro Cosmos Employee (M)" }, + { 0xF44E0641A6E8EB9B, "Madame" }, + { 0x3D5AC2E3C57B98D1, "Marnie" }, + { 0x2C308CE3BBCE33CF, "Marnie (Gym Leader)" }, + { 0x337F59E3BF8F9F26, "Marnie (Gym Outfit)" }, + { 0x672FECC2B55DD125, "Mayor" }, + { 0xCBCF516D11FCA7CF, "Melony" }, + { 0x5B94E3278355861F, "Middle-Aged Man" }, + { 0xC988D3A9DF5B4916, "Middle-Aged Man (Bald)" }, + { 0xB921909A87577826, "Middle-Aged Woman" }, + { 0x45294E1089750AD0, "Milo" }, + { 0xE5C03B4E75AF7A06, "Model" }, + { 0x996C123D20B92166, "Mother" }, + { 0x4A601EA0934A667E, "Muscular Man" }, + { 0xE2081EDAED7AF5AB, "Musician" }, + { 0x09631C357ACCAF23, "Mustard" }, + { 0xFEADD33574274818, "Mustard (No Jacket)" }, + { 0x0711270D2F2871C3, "Nessa" }, + { 0xD9244B1D4E2EA67D, "Office Worker (F)" }, + { 0xA0727E7FCB024401, "Office Worker (M)" }, + { 0x65270056A7A9437D, "Old Man" }, + { 0xB172CE7745D249F0, "Old Woman" }, + { 0x70C43DC41CB92D6B, "Oleana" }, + { 0x929145895D09467D, "Opal" }, + { 0x43C7B6AD72ECEEE9, "Opal" }, + { 0x52711CEE970D947F, "Peonia" }, + { 0x15F141EE74D3611E, "Peony" }, + { 0x11C9205A1E955ADB, "Piers" }, + { 0x5A5B1E27FA6E0894, "Poké Kid (F)" }, + { 0xDB25DC51B0AE4AF1, "Poké Kid (M)" }, + { 0x87904B3A7D4E62E9, "Poké Mart Clerk" }, + { 0xB3A105D9796A7804, "Pokémon Breeder (F)" }, + { 0x89284405A3A85CE1, "Pokémon Breeder (M)" }, + { 0xA33132DF03F2EF24, "Pokémon Center Lady" }, + { 0x9D6F9780F555F4CB, "Police Officer" }, + { 0xA2C1EAC01CF8F115, "Postman" }, + { 0xED9863A48E9B02B1, "Preschooler (F)" }, + { 0x6CCEA57AD85C7354, "Preschooler (M)" }, + { 0xFF195704BFB8A00D, "Professor Magnolia" }, + { 0xF53DEE04B9CCA662, "Professor Magnolia" }, + { 0xE8C7CCFBFB33F29F, "Raihan" }, + { 0x46760CC68612DC3D, "Rail Staff" }, + { 0xC89044F25A853988, "Reporter" }, + { 0x8647F49FC658C046, "Rose" }, + { 0x8E70DD9FCAD3FEF1, "Rose (Casual)" }, + { 0xCDAA7C271FA2DB1F, "Rotomi" }, + { 0xAF66C64C8606E02A, "Rusted Sword" }, + { 0xAF66C94C8606E543, "Rusted Shield" }, + { 0x8D72924BAD918727, "Schoolboy" }, + { 0x0A466C0B77D1159E, "Schoolgirl" }, + { 0x69C39C997BCD88B4, "Shielbert" }, + { 0x98382B1AA21F4CD7, "Sonia" }, + { 0x91C2421A9F15A2AC, "Sonia (Lab Coat)" }, + { 0x072E0468EA46DC96, "Sordward" }, + { 0x4EAAD88E8CF613A9, "Swimmer (F)" }, + { 0x09589FAEEDCED86F, "Swimmer (M)" }, + { 0x7CC9EA6A85A2496F, "Team Yell Grunt (F)" }, + { 0x2C699C0B1880FFF6, "Team Yell Grunt (M)" }, + { 0x040C69585A07DB5A, "Team Yell Grunt (M)" }, + { 0xB7FE5C9AB8D8AC9A, "Villager (F)" }, + { 0x6C06C79A8E61C86B, "Villager (M)" }, + { 0x3897DF33903FCED3, "Worker (F)" }, + { 0xBFD8EDB294F9341A, "Worker (M)" }, + { 0x70F62EB0C1F197D6, "Young Man" }, + { 0x1369813DBDEFA5CF, "Young Woman" }, + { 0x0AADBADDC4027B3F, "Youngster" }, + }; - public static readonly Dictionary Models = new() - { - // { 0xFAB9E0BC5EB53C61, "???" }, // CROSS_SHADOW_CHR_0 - { 0x6E0EF08728A00183, "Allister" }, - { 0x6F31044210C526CA, "Artist" }, - { 0x17C135EB3A312C5A, "Avery" }, - { 0xF5A2F864A1EA03C8, "Backpacker" }, - { 0xC4BD80C146AF5526, "Ball Guy" }, - { 0x4D01D66AA548F0DC, "Bea" }, - { 0xF34C5E3BBF2CA12D, "Beauty" }, - { 0x3832B1FD10EA624C, "Bede" }, - { 0x405B1AFD1564C777, "Bede (Gym Leader)" }, - { 0x1E6D78B53BDAC273, "Black Belt" }, - { 0x75616746BD4D626C, "Cabbie" }, - { 0x5EC6DF381EF1AC4F, "Cafe Master" }, - { 0x4B75CAF6B6D9821E, "Cameraman" }, - { 0x46DD9B2B85198218, "Camping King" }, - { 0xAD1F1CBFF500E7EA, "Cara Liss" }, - { 0xCA7C32F9B2364791, "Chef" }, - { 0xEEF53504D3C99ABC, "Child (F)" }, - { 0x515246E1C4850AE9, "Child (M)" }, - { 0x2533395D8C92F2BC, "Clerk (F)" }, - { 0x9EF56DE5A7896E29, "Corviknight Taxi" }, - { 0xE27DD41A334B8864, "Dancer" }, - { 0x6DC9C4941B9DEA36, "Doctor (F)" }, - { 0xA222B32AE2D6DC90, "Doctor (M)" }, - { 0xA86E35CD887C7089, "Dojo Student (F)" }, - { 0xD3C3FECDA1097C14, "Dojo Student (M)" }, - { 0x0DD0DD66398138EA, "Fisher" }, - { 0xCC2FDFB1297BC7EC, "Gentleman" }, - { 0x519298AB56E81403, "Gordie" }, - { 0xA4E43DAB847A65AA, "Gym Challenger Cher" }, - { 0x3A67EB8C01B8787A, "Gym Challenger Corvin" }, - { 0x97381826E816D73F, "Gym Challenger Deneb" }, - { 0xFF82741CC62487EE, "Gym Challenger Dunne" }, - { 0xA8AA3D3DD9090944, "Gym Challenger Icla" }, - { 0xC694A45D0FA7419E, "Gym Challenger Izar" }, - { 0x9F4C7F98FBFE29A8, "Gym Challenger Kent" }, - { 0xB0A5D9D703DE8309, "Gym Challenger Phoebus" }, - { 0x7A61EE8827C20C2B, "Gym Challenger Pia" }, - { 0xC0102468F510883B, "Gym Challenger Polaire" }, - { 0xDB7E13D3072008FE, "Gym Challenger Terry" }, - { 0x93092A2DE60A30E1, "Gym Challenger Theemin" }, - { 0xEDAF14829B6758FA, "Gym Challenger Vega" }, - { 0x4B590544A749C33A, "Gym Challenger Wei" }, - { 0x8DDA7FF298142A66, "Gym Challenger Yue" }, - { 0xAD0CC990973D924C, "Gym Guide" }, - { 0x68E102B9B9C3FCD4, "Gym Trainer (Dark, F)" }, - { 0xE9AAC0E370028C31, "Gym Trainer (Dark, M)" }, - { 0x612098186DB5276E, "Gym Trainer (Dragon, F)" }, - { 0x8DDC3E562E04AEF7, "Gym Trainer (Dragon, M)" }, - { 0xBF61B6E222A4BDCA, "Gym Trainer (Fairy)" }, - { 0x1A6DC73645DA8730, "Gym Trainer (Fighting, F)" }, - { 0xD188F915AA965CBD, "Gym Trainer (Fighting, M)" }, - { 0x03CF766AAE0365E5, "Gym Trainer (Fire, F)" }, - { 0x2E48383E83C58108, "Gym Trainer (Fire, M)" }, - { 0xFD1B0B03A0284FEC, "Gym Trainer (Ghost, F)" }, - { 0x5F779CE090E2E699, "Gym Trainer (Ghost, M)" }, - { 0x7DB4774C9DC12CFF, "Gym Trainer (Grass, F)" }, - { 0xDB41A4BFA1C3F886, "Gym Trainer (Grass, M)" }, - { 0xE779C955C9EADEFE, "Gym Trainer (Ice, F)" }, - { 0x16E06B686F5DD107, "Gym Trainer (Ice, M)" }, - { 0x4785DFF8E04C7A6C, "Gym Trainer (Rock, F)" }, - { 0xA9E271D5D1071119, "Gym Trainer (Rock, M)" }, - { 0xE028414753629816, "Gym Trainer (Water)" }, - { 0x9521A8F7769EA2D1, "Hiker" }, - { 0x8A674F502E959F7C, "Honey" }, - { 0x2E8D2F2916BE7C7B, "Hop" }, - { 0x23D846291019B890, "Hop (Gym Outfit)" }, - { 0x2E53B82FF113D3D0, "Hop's Mother" }, - { 0x6778893672622C8E, "Hop's Pok Ball" }, - { 0x50F70038EB311D7F, "Hyde" }, - { 0x92F76E5098674167, "Jack" }, - { 0x9DAEC40F62597D12, "Kabu" }, - { 0xA03DC074D6206787, "Klara" }, - { 0xCBFEDC059EF3A979, "Lass" }, - { 0xC0BA5B7E2930D108, "League Staff (F)" }, - { 0x6E154F07B75792C8, "League Staff (F)" }, - { 0x964199AA536EB5E5, "League Staff (M)" }, - { 0x42C608079ECFCFD1, "League Staff (M)" }, - { 0xC157261277011D12, "Leon" }, - { 0xC8A60F127AC2B7FD, "Leon (Battle Tower)" }, - { 0x5492E0DC2DA3C026, "Macro Cosmos Employee (F)" }, - { 0x07C16BDC02736E97, "Macro Cosmos Employee (M)" }, - { 0xF44E0641A6E8EB9B, "Madame" }, - { 0x3D5AC2E3C57B98D1, "Marnie" }, - { 0x2C308CE3BBCE33CF, "Marnie (Gym Leader)" }, - { 0x337F59E3BF8F9F26, "Marnie (Gym Outfit)" }, - { 0x672FECC2B55DD125, "Mayor" }, - { 0xCBCF516D11FCA7CF, "Melony" }, - { 0x5B94E3278355861F, "Middle-Aged Man" }, - { 0xC988D3A9DF5B4916, "Middle-Aged Man (Bald)" }, - { 0xB921909A87577826, "Middle-Aged Woman" }, - { 0x45294E1089750AD0, "Milo" }, - { 0xE5C03B4E75AF7A06, "Model" }, - { 0x996C123D20B92166, "Mother" }, - { 0x4A601EA0934A667E, "Muscular Man" }, - { 0xE2081EDAED7AF5AB, "Musician" }, - { 0x09631C357ACCAF23, "Mustard" }, - { 0xFEADD33574274818, "Mustard (No Jacket)" }, - { 0x0711270D2F2871C3, "Nessa" }, - { 0xD9244B1D4E2EA67D, "Office Worker (F)" }, - { 0xA0727E7FCB024401, "Office Worker (M)" }, - { 0x65270056A7A9437D, "Old Man" }, - { 0xB172CE7745D249F0, "Old Woman" }, - { 0x70C43DC41CB92D6B, "Oleana" }, - { 0x929145895D09467D, "Opal" }, - { 0x43C7B6AD72ECEEE9, "Opal" }, - { 0x52711CEE970D947F, "Peonia" }, - { 0x15F141EE74D3611E, "Peony" }, - { 0x11C9205A1E955ADB, "Piers" }, - { 0x5A5B1E27FA6E0894, "Pok Kid (F)" }, - { 0xDB25DC51B0AE4AF1, "Pok Kid (M)" }, - { 0x87904B3A7D4E62E9, "Pok Mart Clerk" }, - { 0xB3A105D9796A7804, "Pokmon Breeder (F)" }, - { 0x89284405A3A85CE1, "Pokmon Breeder (M)" }, - { 0xA33132DF03F2EF24, "Pokmon Center Lady" }, - { 0x9D6F9780F555F4CB, "Police Officer" }, - { 0xA2C1EAC01CF8F115, "Postman" }, - { 0xED9863A48E9B02B1, "Preschooler (F)" }, - { 0x6CCEA57AD85C7354, "Preschooler (M)" }, - { 0xFF195704BFB8A00D, "Professor Magnolia" }, - { 0xF53DEE04B9CCA662, "Professor Magnolia" }, - { 0xE8C7CCFBFB33F29F, "Raihan" }, - { 0x46760CC68612DC3D, "Rail Staff" }, - { 0xC89044F25A853988, "Reporter" }, - { 0x8647F49FC658C046, "Rose" }, - { 0x8E70DD9FCAD3FEF1, "Rose (Casual)" }, - { 0xCDAA7C271FA2DB1F, "Rotomi" }, - { 0xAF66C64C8606E02A, "Rusted Sword" }, - { 0xAF66C94C8606E543, "Rusted Shield" }, - { 0x8D72924BAD918727, "Schoolboy" }, - { 0x0A466C0B77D1159E, "Schoolgirl" }, - { 0x69C39C997BCD88B4, "Shielbert" }, - { 0x98382B1AA21F4CD7, "Sonia" }, - { 0x91C2421A9F15A2AC, "Sonia (Lab Coat)" }, - { 0x072E0468EA46DC96, "Sordward" }, - { 0x4EAAD88E8CF613A9, "Swimmer (F)" }, - { 0x09589FAEEDCED86F, "Swimmer (M)" }, - { 0x7CC9EA6A85A2496F, "Team Yell Grunt (F)" }, - { 0x2C699C0B1880FFF6, "Team Yell Grunt (M)" }, - { 0x040C69585A07DB5A, "Team Yell Grunt (M)" }, - { 0xB7FE5C9AB8D8AC9A, "Villager (F)" }, - { 0x6C06C79A8E61C86B, "Villager (M)" }, - { 0x3897DF33903FCED3, "Worker (F)" }, - { 0xBFD8EDB294F9341A, "Worker (M)" }, - { 0x70F62EB0C1F197D6, "Young Man" }, - { 0x1369813DBDEFA5CF, "Young Woman" }, - { 0x0AADBADDC4027B3F, "Youngster" }, - }; - - public override string ToString() - { - var ident = Field_00.Field_00.Identifier; - var hashModel = Field_00.Field_00.HashModel; - var name = Models.TryGetValue(hashModel, out var model) ? model : hashModel.ToString("X16"); - return $"{name}: {ident.HashObjectName:X16} v{ModelVariant} @ {ident.Location3f}"; - } - - public PlacementZone8OtherNPCHolder Clone() => new() - { - Field_00 = Field_00.Clone(), - ModelVariant = ModelVariant, - Hash_02 = Hash_02, - Hash_03 = Hash_03, - Field_04 = Field_04, - Hash_05 = Hash_05, - Flag_06 = Flag_06, - Flag_07 = Flag_07, - Field_08 = Field_08, - State = State, - Field_10 = Field_10, - Field_11 = Field_11.Clone(), - Field_12 = Field_12, - AnimationIndexPrimary = AnimationIndexPrimary, - Field_14 = Field_14, - Field_15 = Field_15, - Field_16 = Field_16, - }; + public override string ToString() + { + var ident = Field_00.Field_00.Identifier; + var hashModel = Field_00.Field_00.HashModel; + var name = Models.TryGetValue(hashModel, out var model) ? model : hashModel.ToString("X16"); + return $"{name}: {ident.HashObjectName:X16} v{ModelVariant} @ {ident.Location3f}"; } - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F16_ArrayEntry + public PlacementZone8OtherNPCHolder Clone() => new() { - [FlatBufferItem(00)] public uint Field_00 { get; set; } - [FlatBufferItem(01)] public uint Field_01 { get; set; } - [FlatBufferItem(02)] public uint Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public byte Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } - } - - [FlatBufferEnum(typeof(uint))] - public enum FlatModelState : uint - { - Standing = 0, - Sitting = 2, - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F16 - { - [FlatBufferItem(00)] public PlacementZone8_F16_A Field_00 { get; set; } = new(); - - public PlacementZone8_F16 Clone() => new() - { - Field_00 = Field_00.Clone(), - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F16_A - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public ulong HashModel { get; set; } - [FlatBufferItem(03)] public ulong Hash_03 { get; set; } - [FlatBufferItem(04)] public PlacementZone8_F16_IntFloat Field_04 { get; set; } = new(); - [FlatBufferItem(05)] public bool Flag_05 { get; set; } - [FlatBufferItem(06)] public ulong HashMessage { get; set; } - [FlatBufferItem(07)] public PlacementZone8_F16_IntFloat Field_07 { get; set; } = new(); - - public PlacementZone8_F16_A Clone() => new() - { - Identifier = Identifier.Clone(), - Hash_01 = Hash_01, - HashModel = HashModel, - Hash_03 = Hash_03, - Field_04 = Field_04.Clone(), - Flag_05 = Flag_05, - HashMessage = HashMessage, - Field_07 = Field_07.Clone(), - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F16_IntFloat - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - - public PlacementZone8_F16_IntFloat Clone() => new() - { - Field_00 = Field_00, - Field_01 = Field_01, - Field_02 = Field_02, - Field_03 = Field_03, - Field_04 = Field_04 - }; - } + Field_00 = Field_00.Clone(), + ModelVariant = ModelVariant, + Hash_02 = Hash_02, + Hash_03 = Hash_03, + Field_04 = Field_04, + Hash_05 = Hash_05, + Flag_06 = Flag_06, + Flag_07 = Flag_07, + Field_08 = Field_08, + State = State, + Field_10 = Field_10, + Field_11 = Field_11.Clone(), + Field_12 = Field_12, + AnimationIndexPrimary = AnimationIndexPrimary, + Field_14 = Field_14, + Field_15 = Field_15, + Field_16 = Field_16, + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F16_ArrayEntry +{ + [FlatBufferItem(00)] public uint Field_00 { get; set; } + [FlatBufferItem(01)] public uint Field_01 { get; set; } + [FlatBufferItem(02)] public uint Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public byte Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } +} + +[FlatBufferEnum(typeof(uint))] +public enum FlatModelState : uint +{ + Standing = 0, + Sitting = 2, +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F16 +{ + [FlatBufferItem(00)] public PlacementZone8_F16_A Field_00 { get; set; } = new(); + + public PlacementZone8_F16 Clone() => new() + { + Field_00 = Field_00.Clone(), + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F16_A +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public ulong HashModel { get; set; } + [FlatBufferItem(03)] public ulong Hash_03 { get; set; } + [FlatBufferItem(04)] public PlacementZone8_F16_IntFloat Field_04 { get; set; } = new(); + [FlatBufferItem(05)] public bool Flag_05 { get; set; } + [FlatBufferItem(06)] public ulong HashMessage { get; set; } + [FlatBufferItem(07)] public PlacementZone8_F16_IntFloat Field_07 { get; set; } = new(); + + public PlacementZone8_F16_A Clone() => new() + { + Identifier = Identifier.Clone(), + Hash_01 = Hash_01, + HashModel = HashModel, + Hash_03 = Hash_03, + Field_04 = Field_04.Clone(), + Flag_05 = Flag_05, + HashMessage = HashMessage, + Field_07 = Field_07.Clone(), + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F16_IntFloat +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + + public PlacementZone8_F16_IntFloat Clone() => new() + { + Field_00 = Field_00, + Field_01 = Field_01, + Field_02 = Field_02, + Field_03 = Field_03, + Field_04 = Field_04 + }; } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8ParticleHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8ParticleHolder.cs index 9e954271..5280cff6 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8ParticleHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8ParticleHolder.cs @@ -6,21 +6,20 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8ParticleHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8ParticleHolder - { - [FlatBufferItem(00)] public PlacementZone8Particle Field_00 { get; set; } = new(); + [FlatBufferItem(00)] public PlacementZone8Particle Field_00 { get; set; } = new(); - public override string ToString() => Field_00.ParticleFile; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8Particle - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public string ParticleFile { get; set; } = ""; - [FlatBufferItem(02)] public uint Number { get; set; } // 1200 for birds? - } + public override string ToString() => Field_00.ParticleFile; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8Particle +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public string ParticleFile { get; set; } = ""; + [FlatBufferItem(02)] public uint Number { get; set; } // 1200 for birds? } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PokeCenterSpawnAnchorHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PokeCenterSpawnAnchorHolder.cs index f6c8e9d8..533051a9 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PokeCenterSpawnAnchorHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PokeCenterSpawnAnchorHolder.cs @@ -6,17 +6,16 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers -{ - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8PokeCenterSpawnAnchorHolder - { - [FlatBufferItem(00)] public PlacementZone8_F12 Field_00 { get; set; } = new(); - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F12 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8PokeCenterSpawnAnchorHolder +{ + [FlatBufferItem(00)] public PlacementZone8_F12 Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F12 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PopupHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PopupHolder.cs index 33a6b38a..9c771661 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PopupHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8PopupHolder.cs @@ -8,47 +8,46 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8PopupHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8PopupHolder - { - [FlatBufferItem(00)] public PlacementZone8_F24 Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F24 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public PlacementZone8_F24_IntFloat Field_01 { get; set; } = new(); - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } - [FlatBufferItem(06)] public ulong Hash_06 { get; set; } - [FlatBufferItem(07)] public string Field_07 { get; set; } = ""; // none have this - [FlatBufferItem(08)] public PlacementZone8_F24_Table[] Hash_08 { get; set; } = Array.Empty(); - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - [FlatBufferItem(11)] public float Field_11 { get; set; } - [FlatBufferItem(12)] public ulong Hash_12 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F24_Table - { - [FlatBufferItem(00)] public ulong Hash_00 { get; set; } - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public uint Field_02 { get; set; } // multiples of 10, usually +10 from previous entry. - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F24_IntFloat - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - } + [FlatBufferItem(00)] public PlacementZone8_F24 Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F24 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public PlacementZone8_F24_IntFloat Field_01 { get; set; } = new(); + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } + [FlatBufferItem(06)] public ulong Hash_06 { get; set; } + [FlatBufferItem(07)] public string Field_07 { get; set; } = ""; // none have this + [FlatBufferItem(08)] public PlacementZone8_F24_Table[] Hash_08 { get; set; } = Array.Empty(); + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } + [FlatBufferItem(11)] public float Field_11 { get; set; } + [FlatBufferItem(12)] public ulong Hash_12 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F24_Table +{ + [FlatBufferItem(00)] public ulong Hash_00 { get; set; } + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public uint Field_02 { get; set; } // multiples of 10, usually +10 from previous entry. +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F24_IntFloat +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8QuadrantHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8QuadrantHolder.cs index 78a6d22c..a839fdd6 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8QuadrantHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8QuadrantHolder.cs @@ -7,36 +7,35 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// highplace? +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8QuadrantHolder { - // highplace? - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8QuadrantHolder - { - [FlatBufferItem(00)] public PlacementZone8_F17 Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F17 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public PlacementZone8_F17_Sub Field_02 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F17_Sub - { - [FlatBufferItem(00)] public uint Field_00 { get; set; } // 1 or 2 - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } + [FlatBufferItem(00)] public PlacementZone8_F17 Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F17 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public PlacementZone8_F17_Sub Field_02 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F17_Sub +{ + [FlatBufferItem(00)] public uint Field_00 { get; set; } // 1 or 2 + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8RotomRallyEntry.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8RotomRallyEntry.cs index 496604ff..6a7699c9 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8RotomRallyEntry.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8RotomRallyEntry.cs @@ -6,13 +6,12 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// No maps have data for this. +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8RotomRallyEntry { - // No maps have data for this. - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8RotomRallyEntry - { - [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(1)] public uint Field_01 { get; set; } - } + [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(1)] public uint Field_01 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SpeciesHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SpeciesHolder.cs index 5d908248..7505c2a6 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SpeciesHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SpeciesHolder.cs @@ -7,175 +7,174 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8SpeciesHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8SpeciesHolder + [FlatBufferItem(00)] public PlacementZone8_F02 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public PlacementZone8_F02_Field1 Field_01 { get; set; } = new(); + + [Description("Species Model to load")] + [FlatBufferItem(02)] public uint Species { get; set; } + [Description("Form Model to load")] + [FlatBufferItem(03)] public uint Form { get; set; } + [Description("Gender Model to load: Male and Genderless 0, Female 1")] + [FlatBufferItem(04)] public uint Gender { get; set; } + + [Description("Color Model to load: Normal 0, Shiny 1")] + [FlatBufferItem(05)] public uint Shiny { get; set; } + [FlatBufferItem(06)] public uint Unused2 { get; set; } + + [FlatBufferItem(07)] public ulong Hash_07 { get; set; } + [FlatBufferItem(08)] public ulong Hash_08 { get; set; } + [FlatBufferItem(09)] public ulong Hash_09 { get; set; } + [FlatBufferItem(10)] public FlatDummyEntry[] Field_10 { get; set; } = Array.Empty(); // none have this + [FlatBufferItem(11)] public float Field_11 { get; set; } + [FlatBufferItem(12)] public PlacementZone8_F02_Nine Field_12 { get; set; } = new(); + [FlatBufferItem(13)] public int Field_13 { get; set; } // 0, 1, 3, 4 + [FlatBufferItem(14)] public int Field_14 { get; set; } // 6, 11, 14 or 0 + [FlatBufferItem(15)] public byte Num_15 { get; set; } // 0 or 1 (bool?) + + public override string ToString() => $"{(Species)Species}{(Form != 0 ? $"-{Form}" : "")}"; + + public PlacementZone8SpeciesHolder() { } + + public PlacementZone8SpeciesHolder Clone() => new(this); + + public PlacementZone8SpeciesHolder(PlacementZone8SpeciesHolder other) : this() { - [FlatBufferItem(00)] public PlacementZone8_F02 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public PlacementZone8_F02_Field1 Field_01 { get; set; } = new(); + Field_00 = other.Field_00.Clone(); + Field_01 = other.Field_01.Clone(); + Field_12 = other.Field_12.Clone(); - [Description("Species Model to load")] - [FlatBufferItem(02)] public uint Species { get; set; } - [Description("Form Model to load")] - [FlatBufferItem(03)] public uint Form { get; set; } - [Description("Gender Model to load: Male and Genderless 0, Female 1")] - [FlatBufferItem(04)] public uint Gender { get; set; } - - [Description("Color Model to load: Normal 0, Shiny 1")] - [FlatBufferItem(05)] public uint Shiny { get; set; } - [FlatBufferItem(06)] public uint Unused2 { get; set; } - - [FlatBufferItem(07)] public ulong Hash_07 { get; set; } - [FlatBufferItem(08)] public ulong Hash_08 { get; set; } - [FlatBufferItem(09)] public ulong Hash_09 { get; set; } - [FlatBufferItem(10)] public FlatDummyEntry[] Field_10 { get; set; } = Array.Empty(); // none have this - [FlatBufferItem(11)] public float Field_11 { get; set; } - [FlatBufferItem(12)] public PlacementZone8_F02_Nine Field_12 { get; set; } = new(); - [FlatBufferItem(13)] public int Field_13 { get; set; } // 0, 1, 3, 4 - [FlatBufferItem(14)] public int Field_14 { get; set; } // 6, 11, 14 or 0 - [FlatBufferItem(15)] public byte Num_15 { get; set; } // 0 or 1 (bool?) - - public override string ToString() => $"{(Species)Species}{(Form != 0 ? $"-{Form}" : "")}"; - - public PlacementZone8SpeciesHolder() { } - - public PlacementZone8SpeciesHolder Clone() => new(this); - - public PlacementZone8SpeciesHolder(PlacementZone8SpeciesHolder other) : this() - { - Field_00 = other.Field_00.Clone(); - Field_01 = other.Field_01.Clone(); - Field_12 = other.Field_12.Clone(); - - Species = other.Species; - Form = other.Form; - Gender = other.Gender; - Shiny = other.Shiny; - Unused2 = other.Unused2; - Hash_07 = other.Hash_07; - Hash_08 = other.Hash_08; - Hash_09 = other.Hash_09; - Field_11 = other.Field_11; - Field_13 = other.Field_13; - Field_14 = other.Field_14; - Num_15 = other.Num_15; - } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F02_Nine - { - [FlatBufferItem(00)] public byte Field_00 { get; set; } - [FlatBufferItem(01)] public byte Field_01 { get; set; } - [FlatBufferItem(02)] public byte Field_02 { get; set; } - [FlatBufferItem(03)] public uint Field_03 { get; set; } // either 0 or 1, for only 3 objects in the game - [FlatBufferItem(04)] public ulong Hash_04 { get; set; } - [FlatBufferItem(05)] public byte Field_05 { get; set; } - [FlatBufferItem(06)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(07)] public ulong Hash_07 { get; set; } - [FlatBufferItem(08)] public uint AnimationIndexSecondary { get; set; } - [FlatBufferItem(09)] public uint Field_09 { get; set; } - - public PlacementZone8_F02_Nine Clone() => new() - { - Field_00 = Field_00, - Field_01 = Field_01, - Field_02 = Field_02, - Field_03 = Field_03, - Hash_04 = Hash_04, - Field_05 = Field_05, - Field_06 = Field_06, - Hash_07 = Hash_07, - AnimationIndexSecondary = AnimationIndexSecondary, - Field_09 = Field_09, - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F02 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public ulong Hash_02 { get; set; } - [FlatBufferItem(03)] public ulong Hash_03 { get; set; } - [FlatBufferItem(04)] public ulong Hash_04 { get; set; } - [FlatBufferItem(05)] public uint Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(06)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(07)] public uint Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public uint Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(09)] public FlatDummyObject Field_09 { get; set; } = new(); // no fields present in any existing - [FlatBufferItem(10)] public uint Field_10 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(11)] public FlatDummyObject Field_11 { get; set; } = new(); // no fields present in any existing - [FlatBufferItem(12)] public ulong Hash_12 { get; set; } - - public PlacementZone8_F02 Clone() => new() - { - Field_00 = Field_00.Clone(), - Hash_01 = Hash_01, - Hash_02 = Hash_02, - Hash_03 = Hash_03, - Hash_04 = Hash_04, - Field_05 = Field_05, - Field_06 = Field_06, - Field_07 = Field_07, - Field_08 = Field_08, - Field_09 = Field_09.Clone(), - Field_10 = Field_10, - Field_11 = Field_11.Clone(), - Hash_12 = Hash_12, - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F02_Field1 - { - [FlatBufferItem(00)] public PlacementZone8_F02_Inner Field_00 { get; set; } = new(); - - public PlacementZone8_F02_Field1 Clone() => new() { Field_00 = Field_00.Clone() }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F02_Inner - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public ulong Hash_02 { get; set; } - [FlatBufferItem(03)] public ulong Hash_03 { get; set; } - [FlatBufferItem(04)] public PlacementZone8_F02_IntFloat Field_04 { get; set; } = new(); - [FlatBufferItem(05)] public byte Num_05 { get; set; } // 0 or 1 (bool?) - [FlatBufferItem(06)] public ulong Hash_06 { get; set; } - [FlatBufferItem(07)] public PlacementZone8_F02_IntFloat Field_07 { get; set; } = new(); - - public PlacementZone8_F02_Inner Clone() => new() - { - Field_00 = Field_00.Clone(), - Hash_01 = Hash_01, - Hash_02 = Hash_02, - Hash_03 = Hash_03, - Field_04 = Field_04.Clone(), - Num_05 = Num_05, - Hash_06 = Hash_06, - Field_07 = Field_07.Clone(), - }; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F02_IntFloat - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - - public PlacementZone8_F02_IntFloat Clone() => new() - { - Field_00 = Field_00, - Field_01 = Field_01, - Field_02 = Field_02, - Field_03 = Field_03, - Field_04 = Field_04, - }; + Species = other.Species; + Form = other.Form; + Gender = other.Gender; + Shiny = other.Shiny; + Unused2 = other.Unused2; + Hash_07 = other.Hash_07; + Hash_08 = other.Hash_08; + Hash_09 = other.Hash_09; + Field_11 = other.Field_11; + Field_13 = other.Field_13; + Field_14 = other.Field_14; + Num_15 = other.Num_15; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F02_Nine +{ + [FlatBufferItem(00)] public byte Field_00 { get; set; } + [FlatBufferItem(01)] public byte Field_01 { get; set; } + [FlatBufferItem(02)] public byte Field_02 { get; set; } + [FlatBufferItem(03)] public uint Field_03 { get; set; } // either 0 or 1, for only 3 objects in the game + [FlatBufferItem(04)] public ulong Hash_04 { get; set; } + [FlatBufferItem(05)] public byte Field_05 { get; set; } + [FlatBufferItem(06)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(07)] public ulong Hash_07 { get; set; } + [FlatBufferItem(08)] public uint AnimationIndexSecondary { get; set; } + [FlatBufferItem(09)] public uint Field_09 { get; set; } + + public PlacementZone8_F02_Nine Clone() => new() + { + Field_00 = Field_00, + Field_01 = Field_01, + Field_02 = Field_02, + Field_03 = Field_03, + Hash_04 = Hash_04, + Field_05 = Field_05, + Field_06 = Field_06, + Hash_07 = Hash_07, + AnimationIndexSecondary = AnimationIndexSecondary, + Field_09 = Field_09, + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F02 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public ulong Hash_02 { get; set; } + [FlatBufferItem(03)] public ulong Hash_03 { get; set; } + [FlatBufferItem(04)] public ulong Hash_04 { get; set; } + [FlatBufferItem(05)] public uint Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(06)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(07)] public uint Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public uint Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(09)] public FlatDummyObject Field_09 { get; set; } = new(); // no fields present in any existing + [FlatBufferItem(10)] public uint Field_10 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(11)] public FlatDummyObject Field_11 { get; set; } = new(); // no fields present in any existing + [FlatBufferItem(12)] public ulong Hash_12 { get; set; } + + public PlacementZone8_F02 Clone() => new() + { + Field_00 = Field_00.Clone(), + Hash_01 = Hash_01, + Hash_02 = Hash_02, + Hash_03 = Hash_03, + Hash_04 = Hash_04, + Field_05 = Field_05, + Field_06 = Field_06, + Field_07 = Field_07, + Field_08 = Field_08, + Field_09 = Field_09.Clone(), + Field_10 = Field_10, + Field_11 = Field_11.Clone(), + Hash_12 = Hash_12, + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F02_Field1 +{ + [FlatBufferItem(00)] public PlacementZone8_F02_Inner Field_00 { get; set; } = new(); + + public PlacementZone8_F02_Field1 Clone() => new() { Field_00 = Field_00.Clone() }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F02_Inner +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public ulong Hash_02 { get; set; } + [FlatBufferItem(03)] public ulong Hash_03 { get; set; } + [FlatBufferItem(04)] public PlacementZone8_F02_IntFloat Field_04 { get; set; } = new(); + [FlatBufferItem(05)] public byte Num_05 { get; set; } // 0 or 1 (bool?) + [FlatBufferItem(06)] public ulong Hash_06 { get; set; } + [FlatBufferItem(07)] public PlacementZone8_F02_IntFloat Field_07 { get; set; } = new(); + + public PlacementZone8_F02_Inner Clone() => new() + { + Field_00 = Field_00.Clone(), + Hash_01 = Hash_01, + Hash_02 = Hash_02, + Hash_03 = Hash_03, + Field_04 = Field_04.Clone(), + Num_05 = Num_05, + Hash_06 = Hash_06, + Field_07 = Field_07.Clone(), + }; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F02_IntFloat +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + + public PlacementZone8_F02_IntFloat Clone() => new() + { + Field_00 = Field_00, + Field_01 = Field_01, + Field_02 = Field_02, + Field_03 = Field_03, + Field_04 = Field_04, + }; +} \ No newline at end of file diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StaticObjectsHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StaticObjectsHolder.cs index 4436a4fc..cb3d1562 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StaticObjectsHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StaticObjectsHolder.cs @@ -9,59 +9,58 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8StaticObjectsHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8StaticObjectsHolder + [FlatBufferItem(0)] public PlacementZoneStaticObject8 Object { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneStaticObject8 +{ + [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); + [FlatBufferItem(1)] public uint Field_01 { get; set; } + [FlatBufferItem(2)] public uint Rate { get; set; } // usually 100, but + [FlatBufferItem(3)] public uint Field_03 { get; set; } + [FlatBufferItem(4)] public byte Field_04 { get; set; } + [FlatBufferItem(5)] public PlacementZoneStaticObjectSpawn8[] Spawns { get; set; } = Array.Empty(); + [FlatBufferItem(6)] public PlacementZoneStaticObjectUnknown8 Field_06 { get; set; } = new(); + [FlatBufferItem(7)] public PlacementZoneStaticObjectUnknown8 Field_07 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneStaticObjectSpawn8 +{ + [FlatBufferItem(0)] public ulong SpawnID { get; set; } + [FlatBufferItem(1)] public string Behavior { get; set; } = ""; // passed to Lua script for animating + [FlatBufferItem(2)] public ulong Field_02 { get; set; } // default hash for all, likely empty string + [FlatBufferItem(3)] public uint Field_03 { get; set; } + [FlatBufferItem(4)] public PlacementZoneStaticObjectUnknown8 Field_04 { get; set; } = new(); + + public IEnumerable GetSummary(EncounterStatic8[] statics, IReadOnlyList species) { - [FlatBufferItem(0)] public PlacementZoneStaticObject8 Object { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneStaticObject8 - { - [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); - [FlatBufferItem(1)] public uint Field_01 { get; set; } - [FlatBufferItem(2)] public uint Rate { get; set; } // usually 100, but - [FlatBufferItem(3)] public uint Field_03 { get; set; } - [FlatBufferItem(4)] public byte Field_04 { get; set; } - [FlatBufferItem(5)] public PlacementZoneStaticObjectSpawn8[] Spawns { get; set; } = Array.Empty(); - [FlatBufferItem(6)] public PlacementZoneStaticObjectUnknown8 Field_06 { get; set; } = new(); - [FlatBufferItem(7)] public PlacementZoneStaticObjectUnknown8 Field_07 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneStaticObjectSpawn8 - { - [FlatBufferItem(0)] public ulong SpawnID { get; set; } - [FlatBufferItem(1)] public string Behavior { get; set; } = ""; // passed to Lua script for animating - [FlatBufferItem(2)] public ulong Field_02 { get; set; } // default hash for all, likely empty string - [FlatBufferItem(3)] public uint Field_03 { get; set; } - [FlatBufferItem(4)] public PlacementZoneStaticObjectUnknown8 Field_04 { get; set; } = new(); - - public IEnumerable GetSummary(EncounterStatic8[] statics, IReadOnlyList species) - { - var index = Array.FindIndex(statics, z => z.EncounterID == SpawnID); - var enc = statics[index]; - yield return $"{species[enc.Species]}{(enc.Form == 0 ? string.Empty : "-" + enc.Form)} Lv. {enc.Level}"; - yield return $"Index: {index}"; - yield return $"EncounterID: {SpawnID:X016}"; - if (Field_02 != 0xCBF29CE484222645) - yield return $"Hash: {Field_02:X16}"; - yield return $"Value: {Field_03}"; - yield return $"Unknown: {Field_04}"; - } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneStaticObjectUnknown8 - { - [FlatBufferItem(0)] public uint Field_00 { get; set; } - [FlatBufferItem(1)] public float Field_01 { get; set; } // unused, assumed same shape as other i4f - [FlatBufferItem(2)] public float Field_02 { get; set; } // unused, assumed same shape as other i4f - [FlatBufferItem(3)] public float Field_03 { get; set; } // unused, assumed same shape as other i4f - [FlatBufferItem(4)] public float Field_04 { get; set; } - - public override string ToString() => $"{Field_00} {Field_01} {Field_02} {Field_03} {Field_04}"; + var index = Array.FindIndex(statics, z => z.EncounterID == SpawnID); + var enc = statics[index]; + yield return $"{species[enc.Species]}{(enc.Form == 0 ? string.Empty : "-" + enc.Form)} Lv. {enc.Level}"; + yield return $"Index: {index}"; + yield return $"EncounterID: {SpawnID:X016}"; + if (Field_02 != 0xCBF29CE484222645) + yield return $"Hash: {Field_02:X16}"; + yield return $"Value: {Field_03}"; + yield return $"Unknown: {Field_04}"; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneStaticObjectUnknown8 +{ + [FlatBufferItem(0)] public uint Field_00 { get; set; } + [FlatBufferItem(1)] public float Field_01 { get; set; } // unused, assumed same shape as other i4f + [FlatBufferItem(2)] public float Field_02 { get; set; } // unused, assumed same shape as other i4f + [FlatBufferItem(3)] public float Field_03 { get; set; } // unused, assumed same shape as other i4f + [FlatBufferItem(4)] public float Field_04 { get; set; } + + public override string ToString() => $"{Field_00} {Field_01} {Field_02} {Field_03} {Field_04}"; +} diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StepJumpHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StepJumpHolder.cs index e3f42e55..77d810e1 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StepJumpHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8StepJumpHolder.cs @@ -6,21 +6,20 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers -{ - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8StepJumpHolder - { - [FlatBufferItem(00)] public PlacementZone8StepJump Field_00 { get; set; } = new(); - } +namespace pkNX.Structures.FlatBuffers; - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8StepJump - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - } +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8StepJumpHolder +{ + [FlatBufferItem(00)] public PlacementZone8StepJump Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8StepJump +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SymbolSpawnHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SymbolSpawnHolder.cs index d02dda6b..79788dce 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SymbolSpawnHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8SymbolSpawnHolder.cs @@ -6,41 +6,40 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// wild encounter spawner? +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8SymbolSpawnHolder { - // wild encounter spawner? - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8SymbolSpawnHolder - { - [FlatBufferItem(00)] public PlacementZone8SymbolSpawn Object { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8SymbolSpawn - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); - [FlatBufferItem(01)] public int Field_01 { get; set; } - [FlatBufferItem(02)] public PlacementZone8_F20_Sub Field_02 { get; set; } = new(); - [FlatBufferItem(03)] public PlacementZone8_F20_Sub Field_03 { get; set; } = new(); - [FlatBufferItem(04)] public PlacementZone8_F20_Sub Field_04 { get; set; } = new(); - [FlatBufferItem(05)] public PlacementZone8_F20_Sub Field_05 { get; set; } = new(); - [FlatBufferItem(06)] public int Field_06 { get; set; } - [FlatBufferItem(07)] public ulong SymbolHash { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F20_Sub - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } // unused - [FlatBufferItem(02)] public float Field_02 { get; set; } // unused - [FlatBufferItem(03)] public float Field_03 { get; set; } // unused - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } // unused - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get; set; } // unused - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } + [FlatBufferItem(00)] public PlacementZone8SymbolSpawn Object { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8SymbolSpawn +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Identifier { get; set; } = new(); + [FlatBufferItem(01)] public int Field_01 { get; set; } + [FlatBufferItem(02)] public PlacementZone8_F20_Sub Field_02 { get; set; } = new(); + [FlatBufferItem(03)] public PlacementZone8_F20_Sub Field_03 { get; set; } = new(); + [FlatBufferItem(04)] public PlacementZone8_F20_Sub Field_04 { get; set; } = new(); + [FlatBufferItem(05)] public PlacementZone8_F20_Sub Field_05 { get; set; } = new(); + [FlatBufferItem(06)] public int Field_06 { get; set; } + [FlatBufferItem(07)] public ulong SymbolHash { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F20_Sub +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } // unused + [FlatBufferItem(02)] public float Field_02 { get; set; } // unused + [FlatBufferItem(03)] public float Field_03 { get; set; } // unused + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } // unused + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get; set; } // unused + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerHolder.cs index c993fa57..d7dc30c9 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerHolder.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global @@ -9,85 +8,84 @@ // ReSharper disable UnusedMember.Global #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8TrainerHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8TrainerHolder - { - [FlatBufferItem(00)] public PlacementZone8_F08 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public ulong TrainerID { get; set; } - [FlatBufferItem(03)] public ulong Hash_03 { get; set; } - [FlatBufferItem(04)] public ulong MovementPath { get; set; } - [FlatBufferItem(05)] public PlacementZone8_F08_ArrayEntry[] Unknown { get; set; } = Array.Empty(); - [FlatBufferItem(06)] public uint Field_06 { get; set; } - [FlatBufferItem(07)] public PlacementZone8_F08_Nine Field_07 { get; set; } = new(); - [FlatBufferItem(08)] public uint Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(09)] public uint Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(10)] public uint Field_10 { get; set; } - [FlatBufferItem(11)] public uint Field_11 { get; set; } - [FlatBufferItem(12)] public uint Field_12 { get; set; } + [FlatBufferItem(00)] public PlacementZone8_F08 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public ulong TrainerID { get; set; } + [FlatBufferItem(03)] public ulong Hash_03 { get; set; } + [FlatBufferItem(04)] public ulong MovementPath { get; set; } + [FlatBufferItem(05)] public PlacementZone8_F08_ArrayEntry[] Unknown { get; set; } = Array.Empty(); + [FlatBufferItem(06)] public uint Field_06 { get; set; } + [FlatBufferItem(07)] public PlacementZone8_F08_Nine Field_07 { get; set; } = new(); + [FlatBufferItem(08)] public uint Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(09)] public uint Field_09 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(10)] public uint Field_10 { get; set; } + [FlatBufferItem(11)] public uint Field_11 { get; set; } + [FlatBufferItem(12)] public uint Field_12 { get; set; } - public override string ToString() - { - var hashModel = Field_00.Field_00.HashModel; - var name = PlacementZone8OtherNPCHolder.Models.TryGetValue(hashModel, out var model) ? model : hashModel.ToString("X16"); - return name; - } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F08_ArrayEntry + public override string ToString() { - // same as PlacementZone8_F16_ArrayEntry - [FlatBufferItem(00)] public uint Field_00 { get; set; } - [FlatBufferItem(01)] public uint Field_01 { get; set; } - [FlatBufferItem(02)] public uint Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public byte Field_04 { get; set; } - [FlatBufferItem(05)] public ulong Field_05 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F08_Nine - { - [FlatBufferItem(0)] public byte Field_00 { get; set; } - [FlatBufferItem(1)] public byte Field_01 { get; set; } - [FlatBufferItem(2)] public byte Field_02 { get; set; } - [FlatBufferItem(3)] public uint Field_03 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(4)] public ulong Hash_04 { get; set; } - [FlatBufferItem(5)] public byte Field_05 { get; set; } - [FlatBufferItem(6)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(7)] public ulong Hash_07 { get; set; } - [FlatBufferItem(8)] public uint Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F08 - { - [FlatBufferItem(0)] public PlacementZone8_F08_A Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F08_A - { - [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(1)] public ulong Hash_01 { get; set; } - [FlatBufferItem(2)] public ulong HashModel { get; set; } - [FlatBufferItem(3)] public ulong Hash_03 { get; set; } - [FlatBufferItem(4)] public PlacementZone8_F08_IntFloat Field_04 { get; set; } = new(); - [FlatBufferItem(5)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(6)] public ulong Hash_06 { get; set; } - [FlatBufferItem(7)] public PlacementZone8_F08_IntFloat Field_07 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F08_IntFloat - { - [FlatBufferItem(0)] public int Field_00 { get; set; } - [FlatBufferItem(1)] public float Field_01 { get; set; } - [FlatBufferItem(2)] public float Field_02 { get; set; } - [FlatBufferItem(3)] public float Field_03 { get; set; } - [FlatBufferItem(4)] public float Field_04 { get; set; } + var hashModel = Field_00.Field_00.HashModel; + var name = PlacementZone8OtherNPCHolder.Models.TryGetValue(hashModel, out var model) ? model : hashModel.ToString("X16"); + return name; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F08_ArrayEntry +{ + // same as PlacementZone8_F16_ArrayEntry + [FlatBufferItem(00)] public uint Field_00 { get; set; } + [FlatBufferItem(01)] public uint Field_01 { get; set; } + [FlatBufferItem(02)] public uint Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public byte Field_04 { get; set; } + [FlatBufferItem(05)] public ulong Field_05 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F08_Nine +{ + [FlatBufferItem(0)] public byte Field_00 { get; set; } + [FlatBufferItem(1)] public byte Field_01 { get; set; } + [FlatBufferItem(2)] public byte Field_02 { get; set; } + [FlatBufferItem(3)] public uint Field_03 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(4)] public ulong Hash_04 { get; set; } + [FlatBufferItem(5)] public byte Field_05 { get; set; } + [FlatBufferItem(6)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(7)] public ulong Hash_07 { get; set; } + [FlatBufferItem(8)] public uint Field_08 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F08 +{ + [FlatBufferItem(0)] public PlacementZone8_F08_A Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F08_A +{ + [FlatBufferItem(0)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(1)] public ulong Hash_01 { get; set; } + [FlatBufferItem(2)] public ulong HashModel { get; set; } + [FlatBufferItem(3)] public ulong Hash_03 { get; set; } + [FlatBufferItem(4)] public PlacementZone8_F08_IntFloat Field_04 { get; set; } = new(); + [FlatBufferItem(5)] public uint Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(6)] public ulong Hash_06 { get; set; } + [FlatBufferItem(7)] public PlacementZone8_F08_IntFloat Field_07 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F08_IntFloat +{ + [FlatBufferItem(0)] public int Field_00 { get; set; } + [FlatBufferItem(1)] public float Field_01 { get; set; } + [FlatBufferItem(2)] public float Field_02 { get; set; } + [FlatBufferItem(3)] public float Field_03 { get; set; } + [FlatBufferItem(4)] public float Field_04 { get; set; } +} diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerTipHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerTipHolder.cs index 33db15eb..e7e99a08 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerTipHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TrainerTipHolder.cs @@ -6,55 +6,54 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8TrainerTipHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8TrainerTipHolder - { - [FlatBufferItem(00)] public PlacementZoneTrainerTip Field_00 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneTrainerTip - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public ulong Field_05 { get; set; } - [FlatBufferItem(06)] public PlacementZone8_F09 Field_06 { get; set; } = new(); - [FlatBufferItem(07)] public PlacementZone8_F09_Union Field_07 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F09 - { - [FlatBufferItem(00)] public uint Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get; set; } - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } - - // union? - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F09_Union - { - [FlatBufferItem(00)] public byte Field_00 { get; set; } - [FlatBufferItem(01)] public PlacementZone8_F09_Sub Field_06 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8_F09_Sub - { - [FlatBufferItem(0)] public float Field_00 { get; set; } - [FlatBufferItem(1)] public float Field_01 { get; set; } - } + [FlatBufferItem(00)] public PlacementZoneTrainerTip Field_00 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneTrainerTip +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public ulong Field_05 { get; set; } + [FlatBufferItem(06)] public PlacementZone8_F09 Field_06 { get; set; } = new(); + [FlatBufferItem(07)] public PlacementZone8_F09_Union Field_07 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F09 +{ + [FlatBufferItem(00)] public uint Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get; set; } + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } +} + +// union? +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F09_Union +{ + [FlatBufferItem(00)] public byte Field_00 { get; set; } + [FlatBufferItem(01)] public PlacementZone8_F09_Sub Field_06 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8_F09_Sub +{ + [FlatBufferItem(0)] public float Field_00 { get; set; } + [FlatBufferItem(1)] public float Field_01 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TriggerHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TriggerHolder.cs index c7141fad..f34a2882 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TriggerHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8TriggerHolder.cs @@ -6,58 +6,57 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// Trigger tiles? +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8TriggerHolder { - // Trigger tiles? - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8TriggerHolder - { - [FlatBufferItem(0)] public PlacementZone8Trigger Object { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8Trigger - { - [FlatBufferItem(0)] public PlacementZoneDeepX8 Field_00 { get; set; } = new(); - [FlatBufferItem(1)] public ulong TriggerName { get; set; } - [FlatBufferItem(2)] public uint Field_02 { get; set; } - [FlatBufferItem(3)] public PlacementZoneDeepY8 Field_03 { get; set; } = new(); - [FlatBufferItem(4)] public uint Field_04 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneDeepX8 - { - [FlatBufferItem(00)] public float Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } - - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get; set; } - [FlatBufferItem(08)] public float Field_08 { get; set; } - - [FlatBufferItem(09)] public ulong Field_09 { get; set; } - [FlatBufferItem(10)] public ulong Field_10 { get; set; } - [FlatBufferItem(11)] public ulong Field_11 { get; set; } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneDeepY8 - { - [FlatBufferItem(00)] public uint Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get; set; } - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get; set; } - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } + [FlatBufferItem(0)] public PlacementZone8Trigger Object { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8Trigger +{ + [FlatBufferItem(0)] public PlacementZoneDeepX8 Field_00 { get; set; } = new(); + [FlatBufferItem(1)] public ulong TriggerName { get; set; } + [FlatBufferItem(2)] public uint Field_02 { get; set; } + [FlatBufferItem(3)] public PlacementZoneDeepY8 Field_03 { get; set; } = new(); + [FlatBufferItem(4)] public uint Field_04 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneDeepX8 +{ + [FlatBufferItem(00)] public float Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } + + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get; set; } + [FlatBufferItem(08)] public float Field_08 { get; set; } + + [FlatBufferItem(09)] public ulong Field_09 { get; set; } + [FlatBufferItem(10)] public ulong Field_10 { get; set; } + [FlatBufferItem(11)] public ulong Field_11 { get; set; } +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneDeepY8 +{ + [FlatBufferItem(00)] public uint Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get; set; } + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get; set; } + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8UnitObjectHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8UnitObjectHolder.cs index 7f4db186..f0676b70 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8UnitObjectHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8UnitObjectHolder.cs @@ -7,65 +7,64 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +// Gates, Elevators, Tents, Flags, FossilRepair? +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8UnitObjectHolder { - // Gates, Elevators, Tents, Flags, FossilRepair? - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8UnitObjectHolder - { - [FlatBufferItem(00)] public PlacementZone8UnitObject Object { get; set; } = new(); + [FlatBufferItem(00)] public PlacementZone8UnitObject Object { get; set; } = new(); - public override string ToString() => Object.NameModel; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8UnitObject - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public string NameModel { get; set; } = ""; - [FlatBufferItem(02)] public string NameAnimation { get; set; } = ""; - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public string Field_05 { get; set; } = ""; // none have this - [FlatBufferItem(06)] public string Field_06 { get; set; } = ""; // none have this - [FlatBufferItem(07)] public float Field_07 { get; set; } - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - [FlatBufferItem(11)] public PlacementZoneDeepY8 Unknown { get; set; } = new(); - [FlatBufferItem(12)] public byte Number { get; set; } - [FlatBufferItem(13)] public PlacementZone8UnitObjectDetails Details { get; set; } = new(); - [FlatBufferItem(14)] public PlacementZone8UnitObjectToggle Dummy { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8UnitObjectDetails - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get; set; } - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get; set; } - [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } - - // probably a union, with only 1 object type used - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8UnitObjectToggle - { - [FlatBufferItem(00)] public bool Field_00 { get; set; } - [FlatBufferItem(01)] public PlacementZone8UnitObjectInner Field_01 { get; set; } = new(); - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8UnitObjectInner - { - [FlatBufferItem(00)] public float Field_00 { get; set; } // 50 for only 1 entry - [FlatBufferItem(01)] public float Field_01 { get; set; } - } + public override string ToString() => Object.NameModel; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8UnitObject +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public string NameModel { get; set; } = ""; + [FlatBufferItem(02)] public string NameAnimation { get; set; } = ""; + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public string Field_05 { get; set; } = ""; // none have this + [FlatBufferItem(06)] public string Field_06 { get; set; } = ""; // none have this + [FlatBufferItem(07)] public float Field_07 { get; set; } + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } + [FlatBufferItem(11)] public PlacementZoneDeepY8 Unknown { get; set; } = new(); + [FlatBufferItem(12)] public byte Number { get; set; } + [FlatBufferItem(13)] public PlacementZone8UnitObjectDetails Details { get; set; } = new(); + [FlatBufferItem(14)] public PlacementZone8UnitObjectToggle Dummy { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8UnitObjectDetails +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get; set; } + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get; set; } + [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } +} + +// probably a union, with only 1 object type used +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8UnitObjectToggle +{ + [FlatBufferItem(00)] public bool Field_00 { get; set; } + [FlatBufferItem(01)] public PlacementZone8UnitObjectInner Field_01 { get; set; } = new(); +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8UnitObjectInner +{ + [FlatBufferItem(00)] public float Field_00 { get; set; } // 50 for only 1 entry + [FlatBufferItem(01)] public float Field_01 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8WarpHolder.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8WarpHolder.cs index b37bc8e3..43defd31 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8WarpHolder.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/Holders/PlacementZone8WarpHolder.cs @@ -7,46 +7,45 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8WarpHolder { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8WarpHolder - { - [FlatBufferItem(00)] public PlacementZoneWarp8 Field_00 { get; set; } = new(); + [FlatBufferItem(00)] public PlacementZoneWarp8 Field_00 { get; set; } = new(); - public override string ToString() => $"{Field_00.NameAreaOther} via {Field_00.NameModel}"; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneWarp8 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong Hash_01 { get; set; } - [FlatBufferItem(02)] public string NameAreaOther { get; set; } = ""; - [FlatBufferItem(03)] public string NameModel { get; set; } = ""; - [FlatBufferItem(04)] public string NameAnimation { get; set; } = ""; - [FlatBufferItem(05)] public int Field_05 { get; set; } - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public bool Field_07 { get; set; } - [FlatBufferItem(08)] public ulong Hash_08 { get; set; } - [FlatBufferItem(09)] public PlacementZoneWarpDetails8 SubMeta { get; set; } = new(); - [FlatBufferItem(10)] public string NameSoundEffect1 { get; set; } = ""; - [FlatBufferItem(11)] public string NameSoundEffect2 { get; set; } = ""; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneWarpDetails8 - { - [FlatBufferItem(00)] public int Field_00 { get; set; } - [FlatBufferItem(01)] public float Field_01 { get; set; } - [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(03)] public float Field_03 { get; set; } - [FlatBufferItem(04)] public float Field_04 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(06)] public float Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused - [FlatBufferItem(08)] public float Field_08 { get; set; } - [FlatBufferItem(09)] public float Field_09 { get; set; } - [FlatBufferItem(10)] public float Field_10 { get; set; } - } + public override string ToString() => $"{Field_00.NameAreaOther} via {Field_00.NameModel}"; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneWarp8 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong Hash_01 { get; set; } + [FlatBufferItem(02)] public string NameAreaOther { get; set; } = ""; + [FlatBufferItem(03)] public string NameModel { get; set; } = ""; + [FlatBufferItem(04)] public string NameAnimation { get; set; } = ""; + [FlatBufferItem(05)] public int Field_05 { get; set; } + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public bool Field_07 { get; set; } + [FlatBufferItem(08)] public ulong Hash_08 { get; set; } + [FlatBufferItem(09)] public PlacementZoneWarpDetails8 SubMeta { get; set; } = new(); + [FlatBufferItem(10)] public string NameSoundEffect1 { get; set; } = ""; + [FlatBufferItem(11)] public string NameSoundEffect2 { get; set; } = ""; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneWarpDetails8 +{ + [FlatBufferItem(00)] public int Field_00 { get; set; } + [FlatBufferItem(01)] public float Field_01 { get; set; } + [FlatBufferItem(02)] public float Field_02 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(03)] public float Field_03 { get; set; } + [FlatBufferItem(04)] public float Field_04 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(05)] public float Field_05 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(06)] public float Field_06 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(07)] public float Field_07 { get => 0; set { if (value != 0) throw new ArgumentException("Not Observed"); } } // unused + [FlatBufferItem(08)] public float Field_08 { get; set; } + [FlatBufferItem(09)] public float Field_09 { get; set; } + [FlatBufferItem(10)] public float Field_10 { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/PlacementZone8.cs b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/PlacementZone8.cs index 3461a393..9123721c 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/PlacementZone8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Placement/Zone/PlacementZone8.cs @@ -8,175 +8,174 @@ // ReSharper disable UnusedType.Global // ReSharper disable UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZone8 { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZone8 + [FlatBufferItem(00)] public PlacementZoneMeta8 Meta { get; set; } = new(); + [FlatBufferItem(01)] public PlacementZone8UnitObjectHolder[] UnitObjects { get; set; } = Array.Empty(); + [FlatBufferItem(02)] public PlacementZone8SpeciesHolder[] Critters { get; set; } = Array.Empty(); + [FlatBufferItem(03)] public PlacementZone8WarpHolder[] Warps { get; set; } = Array.Empty(); + [FlatBufferItem(04)] public PlacementZone8StepJumpHolder[] StepJumps { get; set; } = Array.Empty(); + [FlatBufferItem(05)] public PlacementZone8ParticleHolder[] Particles { get; set; } = Array.Empty(); + [FlatBufferItem(06)] public PlacementZone8FieldItemHolder[] FieldItems { get; set; } = Array.Empty(); + [FlatBufferItem(07)] public PlacementZone8TriggerHolder[] Triggers { get; set; } = Array.Empty(); + [FlatBufferItem(08)] public PlacementZone8TrainerHolder[] Trainers { get; set; } = Array.Empty(); + [FlatBufferItem(09)] public PlacementZone8TrainerTipHolder[] TrainerTips { get; set; } = Array.Empty(); + [FlatBufferItem(10)] public PlacementZone8EnvironmentHolder[] Environments { get; set; } = Array.Empty(); + [FlatBufferItem(11)] public PlacementZone8FlightAnchorHolder[] FlyTo { get; set; } = Array.Empty(); + [FlatBufferItem(12)] public PlacementZone8PokeCenterSpawnAnchorHolder[] PokeCenterAnchor { get; set; } = Array.Empty(); + [FlatBufferItem(13)] public PlacementZone8NPCHolder[] NPCType1 { get; set; } = Array.Empty(); + [FlatBufferItem(14)] public PlacementZone8AdvancedTipHolder[] AdvancedTips { get; set; } = Array.Empty(); + [FlatBufferItem(15)] public PlacementZone8MovementPathHolder[] Paths { get; set; } = Array.Empty(); + [FlatBufferItem(16)] public PlacementZone8OtherNPCHolder[] NPCType2 { get; set; } = Array.Empty(); + [FlatBufferItem(17)] public PlacementZone8QuadrantHolder[] Quadrants { get; set; } = Array.Empty(); + [FlatBufferItem(18)] public PlacementZone8FishingPointHolder[] FishingPoint { get; set; } = Array.Empty(); + [FlatBufferItem(19)] public PlacementZone8HiddenItemHolder[] HiddenItems { get; set; } = Array.Empty(); + [FlatBufferItem(20)] public PlacementZone8SymbolSpawnHolder[] Symbols { get; set; } = Array.Empty(); + [FlatBufferItem(21)] public PlacementZone8NestHoleHolder[] Nests { get; set; } = Array.Empty(); + [FlatBufferItem(22)] public PlacementZone8BerryTreeHolder[] BerryTrees { get; set; } = Array.Empty(); + [FlatBufferItem(23)] public PlacementZone8LadderHolder[] Ladders { get; set; } = Array.Empty(); + [FlatBufferItem(24)] public PlacementZone8PopupHolder[] Popups { get; set; } = Array.Empty(); + [FlatBufferItem(25)] public PlacementZone8IKStepHolder[] IKStep { get; set; } = Array.Empty(); + [FlatBufferItem(26)] public PlacementZone8StaticObjectsHolder[] StaticObjects { get; set; } = Array.Empty(); + [FlatBufferItem(27)] public PlacementZone8RotomRallyEntry[] RotomRally { get; set; } = Array.Empty(); + + public override string ToString() => Meta.ZoneID.ToString("X16"); + + // More tables exist here + + public IEnumerable GetSummary(EncounterStatic8[] statics, + IReadOnlyList species, + IReadOnlyDictionary zone_names, + IReadOnlyDictionary zone_descs, + IReadOnlyDictionary objects, + IReadOnlyList weathers) { - [FlatBufferItem(00)] public PlacementZoneMeta8 Meta { get; set; } = new(); - [FlatBufferItem(01)] public PlacementZone8UnitObjectHolder[] UnitObjects { get; set; } = Array.Empty(); - [FlatBufferItem(02)] public PlacementZone8SpeciesHolder[] Critters { get; set; } = Array.Empty(); - [FlatBufferItem(03)] public PlacementZone8WarpHolder[] Warps { get; set; } = Array.Empty(); - [FlatBufferItem(04)] public PlacementZone8StepJumpHolder[] StepJumps { get; set; } = Array.Empty(); - [FlatBufferItem(05)] public PlacementZone8ParticleHolder[] Particles { get; set; } = Array.Empty(); - [FlatBufferItem(06)] public PlacementZone8FieldItemHolder[] FieldItems { get; set; } = Array.Empty(); - [FlatBufferItem(07)] public PlacementZone8TriggerHolder[] Triggers { get; set; } = Array.Empty(); - [FlatBufferItem(08)] public PlacementZone8TrainerHolder[] Trainers { get; set; } = Array.Empty(); - [FlatBufferItem(09)] public PlacementZone8TrainerTipHolder[] TrainerTips { get; set; } = Array.Empty(); - [FlatBufferItem(10)] public PlacementZone8EnvironmentHolder[] Environments { get; set; } = Array.Empty(); - [FlatBufferItem(11)] public PlacementZone8FlightAnchorHolder[] FlyTo { get; set; } = Array.Empty(); - [FlatBufferItem(12)] public PlacementZone8PokeCenterSpawnAnchorHolder[] PokeCenterAnchor { get; set; } = Array.Empty(); - [FlatBufferItem(13)] public PlacementZone8NPCHolder[] NPCType1 { get; set; } = Array.Empty(); - [FlatBufferItem(14)] public PlacementZone8AdvancedTipHolder[] AdvancedTips { get; set; } = Array.Empty(); - [FlatBufferItem(15)] public PlacementZone8MovementPathHolder[] Paths { get; set; } = Array.Empty(); - [FlatBufferItem(16)] public PlacementZone8OtherNPCHolder[] NPCType2 { get; set; } = Array.Empty(); - [FlatBufferItem(17)] public PlacementZone8QuadrantHolder[] Quadrants { get; set; } = Array.Empty(); - [FlatBufferItem(18)] public PlacementZone8FishingPointHolder[] FishingPoint { get; set; } = Array.Empty(); - [FlatBufferItem(19)] public PlacementZone8HiddenItemHolder[] HiddenItems { get; set; } = Array.Empty(); - [FlatBufferItem(20)] public PlacementZone8SymbolSpawnHolder[] Symbols { get; set; } = Array.Empty(); - [FlatBufferItem(21)] public PlacementZone8NestHoleHolder[] Nests { get; set; } = Array.Empty(); - [FlatBufferItem(22)] public PlacementZone8BerryTreeHolder[] BerryTrees { get; set; } = Array.Empty(); - [FlatBufferItem(23)] public PlacementZone8LadderHolder[] Ladders { get; set; } = Array.Empty(); - [FlatBufferItem(24)] public PlacementZone8PopupHolder[] Popups { get; set; } = Array.Empty(); - [FlatBufferItem(25)] public PlacementZone8IKStepHolder[] IKStep { get; set; } = Array.Empty(); - [FlatBufferItem(26)] public PlacementZone8StaticObjectsHolder[] StaticObjects { get; set; } = Array.Empty(); - [FlatBufferItem(27)] public PlacementZone8RotomRallyEntry[] RotomRally { get; set; } = Array.Empty(); + var zoneID = Meta.ZoneID; + var name = zone_names[zoneID]; + yield return zone_descs.TryGetValue(zoneID, out var desc) + ? $"{name} ({desc}):" + : $"{name}:"; - public override string ToString() => Meta.ZoneID.ToString("X16"); - - // More tables exist here - - public IEnumerable GetSummary(EncounterStatic8[] statics, - IReadOnlyList species, - IReadOnlyDictionary zone_names, - IReadOnlyDictionary zone_descs, - IReadOnlyDictionary objects, - IReadOnlyList weathers) + foreach (var sym in Symbols) { - var zoneID = Meta.ZoneID; - var name = zone_names[zoneID]; - yield return zone_descs.TryGetValue(zoneID, out var desc) - ? $"{name} ({desc}):" - : $"{name}:"; - - foreach (var sym in Symbols) + var obj = sym.Object; + var ident = obj.Identifier; + yield return $" {objects[ident.HashObjectName]}:"; + yield return $" Location: {ident.Location3f}"; + if (obj.SymbolHash is (0xCBF29CE484222645 or 0)) { - var obj = sym.Object; - var ident = obj.Identifier; - yield return $" {objects[ident.HashObjectName]}:"; - yield return $" Location: {ident.Location3f}"; - if (obj.SymbolHash is (0xCBF29CE484222645 or 0)) - { - yield return " No symbols."; // shouldn't hit here, if we have a holder we should have a symbol to hold. - break; - } - - var line = $"SymbolHash: {obj.SymbolHash:X16}, ObjectHash:{obj.Identifier.HashObjectName:X16}, {nameof(PlacementZone8SymbolSpawn.Field_06)}: {obj.Field_06}, {nameof(PlacementZone8SymbolSpawn.Field_01)}: {obj.Field_01}"; - yield return $" {line}"; + yield return " No symbols."; // shouldn't hit here, if we have a holder we should have a symbol to hold. + break; } - foreach (var so in StaticObjects) - { - var obj = so.Object; - var ident = obj.Identifier; - yield return $" {objects[ident.HashObjectName]}:"; - yield return $" Location: {ident.Location3f}"; - if (obj.Spawns.Length == 0) - { - yield return " No spawns."; // shouldn't hit here, if we have a holder we should have a spawn to hold. - break; - } + var line = $"SymbolHash: {obj.SymbolHash:X16}, ObjectHash:{obj.Identifier.HashObjectName:X16}, {nameof(PlacementZone8SymbolSpawn.Field_06)}: {obj.Field_06}, {nameof(PlacementZone8SymbolSpawn.Field_01)}: {obj.Field_01}"; + yield return $" {line}"; + } - var s = obj.Spawns; - var first = s[0]; - var spawnId = first.SpawnID; - if (Array.TrueForAll(s, z => z.SpawnID == spawnId)) + foreach (var so in StaticObjects) + { + var obj = so.Object; + var ident = obj.Identifier; + yield return $" {objects[ident.HashObjectName]}:"; + yield return $" Location: {ident.Location3f}"; + if (obj.Spawns.Length == 0) + { + yield return " No spawns."; // shouldn't hit here, if we have a holder we should have a spawn to hold. + break; + } + + var s = obj.Spawns; + var first = s[0]; + var spawnId = first.SpawnID; + if (Array.TrueForAll(s, z => z.SpawnID == spawnId)) + { + yield return " All Weather:"; + foreach (var line in first.GetSummary(statics, species)) + yield return $" {line}"; + } + else + { + for (var i = 0; i < s.Length; i++) { - yield return " All Weather:"; - foreach (var line in first.GetSummary(statics, species)) + yield return $" {weathers[i]}:"; + foreach (var line in s[i].GetSummary(statics, species)) yield return $" {line}"; } - else - { - for (var i = 0; i < s.Length; i++) - { - yield return $" {weathers[i]}:"; - foreach (var line in s[i].GetSummary(statics, species)) - yield return $" {line}"; - } - } } - - yield return string.Empty; - } - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneMeta8 - { - [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); - [FlatBufferItem(01)] public ulong ZoneID { get; set; } - [FlatBufferItem(02)] public ulong Hash_02 { get; set; } - [FlatBufferItem(03)] public string Field_03 { get; set; } = ""; // none have this - [FlatBufferItem(04)] public uint Field_04 { get; set; } - [FlatBufferItem(05)] public string Music { get; set; } = ""; - [FlatBufferItem(06)] public float Field_06 { get; set; } - [FlatBufferItem(07)] public ulong Hash_07 { get; set; } - [FlatBufferItem(08)] public ulong Hash_08 { get; set; } - [FlatBufferItem(09)] public ulong Hash_09 { get; set; } - [FlatBufferItem(10)] public byte Field_10 { get; set; } - [FlatBufferItem(11)] public byte Field_11 { get; set; } - [FlatBufferItem(12)] public ulong Hash_12 { get; set; } - [FlatBufferItem(13)] public byte Field_13 { get; set; } - [FlatBufferItem(14)] public byte Field_14 { get; set; } - [FlatBufferItem(15)] public int Num_15 { get; set; } - - public override string ToString() => $"{Field_00.HashObjectName:X16}"; - } - - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class PlacementZoneMetaTripleXYZ8 - { - [FlatBufferItem(00)] public float LocationX { get; set; } - [FlatBufferItem(01)] public float LocationY { get; set; } - [FlatBufferItem(02)] public float LocationZ { get; set; } - [FlatBufferItem(03)] public float RotationX { get; set; } // assumed - [FlatBufferItem(04)] public float RotationY { get; set; } - [FlatBufferItem(05)] public float RotationZ { get; set; } // assumed - [FlatBufferItem(06)] public float ScaleX { get; set; } - [FlatBufferItem(07)] public float ScaleY { get; set; } - [FlatBufferItem(08)] public float ScaleZ { get; set; } - [FlatBufferItem(09)] public ulong HashObjectName { get; set; } - [FlatBufferItem(10)] public ulong Hash_10 { get; set; } - [FlatBufferItem(11)] public ulong Hash_11 { get; set; } - - public string Location3f => $"({LocationX}, {LocationY}, {LocationZ})"; - - public void Upscale(float factor) - { - ScaleX *= factor; - ScaleY *= factor; - ScaleZ *= factor; } - public void ResetScale() => ScaleX = ScaleY = ScaleZ = 1; - - public override string ToString() => $"{HashObjectName:X16} @ {Location3f}"; - - public PlacementZoneMetaTripleXYZ8 Clone() => new() - { - LocationX = LocationX, - LocationY = LocationY, - LocationZ = LocationZ, - RotationX = RotationX, - RotationY = RotationY, - RotationZ = RotationZ, - ScaleX = ScaleX, - ScaleY = ScaleY, - ScaleZ = ScaleZ, - HashObjectName = HashObjectName, - Hash_10 = Hash_10, - Hash_11 = Hash_11, - }; + yield return string.Empty; } } + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneMeta8 +{ + [FlatBufferItem(00)] public PlacementZoneMetaTripleXYZ8 Field_00 { get; set; } = new(); + [FlatBufferItem(01)] public ulong ZoneID { get; set; } + [FlatBufferItem(02)] public ulong Hash_02 { get; set; } + [FlatBufferItem(03)] public string Field_03 { get; set; } = ""; // none have this + [FlatBufferItem(04)] public uint Field_04 { get; set; } + [FlatBufferItem(05)] public string Music { get; set; } = ""; + [FlatBufferItem(06)] public float Field_06 { get; set; } + [FlatBufferItem(07)] public ulong Hash_07 { get; set; } + [FlatBufferItem(08)] public ulong Hash_08 { get; set; } + [FlatBufferItem(09)] public ulong Hash_09 { get; set; } + [FlatBufferItem(10)] public byte Field_10 { get; set; } + [FlatBufferItem(11)] public byte Field_11 { get; set; } + [FlatBufferItem(12)] public ulong Hash_12 { get; set; } + [FlatBufferItem(13)] public byte Field_13 { get; set; } + [FlatBufferItem(14)] public byte Field_14 { get; set; } + [FlatBufferItem(15)] public int Num_15 { get; set; } + + public override string ToString() => $"{Field_00.HashObjectName:X16}"; +} + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class PlacementZoneMetaTripleXYZ8 +{ + [FlatBufferItem(00)] public float LocationX { get; set; } + [FlatBufferItem(01)] public float LocationY { get; set; } + [FlatBufferItem(02)] public float LocationZ { get; set; } + [FlatBufferItem(03)] public float RotationX { get; set; } // assumed + [FlatBufferItem(04)] public float RotationY { get; set; } + [FlatBufferItem(05)] public float RotationZ { get; set; } // assumed + [FlatBufferItem(06)] public float ScaleX { get; set; } + [FlatBufferItem(07)] public float ScaleY { get; set; } + [FlatBufferItem(08)] public float ScaleZ { get; set; } + [FlatBufferItem(09)] public ulong HashObjectName { get; set; } + [FlatBufferItem(10)] public ulong Hash_10 { get; set; } + [FlatBufferItem(11)] public ulong Hash_11 { get; set; } + + public string Location3f => $"({LocationX}, {LocationY}, {LocationZ})"; + + public void Upscale(float factor) + { + ScaleX *= factor; + ScaleY *= factor; + ScaleZ *= factor; + } + + public void ResetScale() => ScaleX = ScaleY = ScaleZ = 1; + + public override string ToString() => $"{HashObjectName:X16} @ {Location3f}"; + + public PlacementZoneMetaTripleXYZ8 Clone() => new() + { + LocationX = LocationX, + LocationY = LocationY, + LocationZ = LocationZ, + RotationX = RotationX, + RotationY = RotationY, + RotationZ = RotationZ, + ScaleX = ScaleX, + ScaleY = ScaleY, + ScaleZ = ScaleZ, + HashObjectName = HashObjectName, + Hash_10 = Hash_10, + Hash_11 = Hash_11, + }; +} diff --git a/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8.cs b/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8.cs index 3202a91d..569c2f7c 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8.cs @@ -10,139 +10,138 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterStatic8 { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterStatic8 + [FlatBufferItem(00)] public ulong BackgroundFarTypeID { get; set; } + [FlatBufferItem(01)] public ulong BackgroundNearTypeID { get; set; } + [FlatBufferItem(02)] public byte EV_SPE { get; set; } + [FlatBufferItem(03)] public byte EV_ATK { get; set; } + [FlatBufferItem(04)] public byte EV_DEF { get; set; } + [FlatBufferItem(05)] public byte EV_HP { get; set; } + [FlatBufferItem(06)] public byte EV_SPA { get; set; } + [FlatBufferItem(07)] public byte EV_SPD { get; set; } + [FlatBufferItem(08)] public byte Form { get; set; } + [FlatBufferItem(09)] public byte DynamaxLevel { get; set; } + [FlatBufferItem(10)] public int Field_0A { get; set; } + [FlatBufferItem(11)] public ulong EncounterID { get; set; } + [FlatBufferItem(12)] public byte Field_0C { get; set; } + [FlatBufferItem(13)] public bool CanGigantamax { get; set; } + [FlatBufferItem(14)] public int HeldItem { get; set; } + [FlatBufferItem(15)] public byte Level { get; set; } + [FlatBufferItem(16)] public Scenario EncounterScenario { get; set; } + [FlatBufferItem(17)] public int Species { get; set; } + [FlatBufferItem(18)] public uint ShinyLock { get; set; } + [FlatBufferItem(19)] public uint Nature { get; set; } + [FlatBufferItem(20)] public byte Gender { get; set; } + [FlatBufferItem(21)] public sbyte IV_SPE { get; set; } + [FlatBufferItem(22)] public sbyte IV_ATK { get; set; } + [FlatBufferItem(23)] public sbyte IV_DEF { get; set; } + [FlatBufferItem(24)] public sbyte IV_HP { get; set; } + [FlatBufferItem(25)] public sbyte IV_SPA { get; set; } + [FlatBufferItem(26)] public sbyte IV_SPD { get; set; } + [FlatBufferItem(27)] public int Ability { get; set; } + [FlatBufferItem(28)] public int Move0 { get; set; } + [FlatBufferItem(29)] public int Move1 { get; set; } + [FlatBufferItem(30)] public int Move2 { get; set; } + [FlatBufferItem(31)] public int Move3 { get; set; } + + public Species SpeciesID => (Species)Species; + + public int[] IVs { - [FlatBufferItem(00)] public ulong BackgroundFarTypeID { get; set; } - [FlatBufferItem(01)] public ulong BackgroundNearTypeID { get; set; } - [FlatBufferItem(02)] public byte EV_SPE { get; set; } - [FlatBufferItem(03)] public byte EV_ATK { get; set; } - [FlatBufferItem(04)] public byte EV_DEF { get; set; } - [FlatBufferItem(05)] public byte EV_HP { get; set; } - [FlatBufferItem(06)] public byte EV_SPA { get; set; } - [FlatBufferItem(07)] public byte EV_SPD { get; set; } - [FlatBufferItem(08)] public byte Form { get; set; } - [FlatBufferItem(09)] public byte DynamaxLevel { get; set; } - [FlatBufferItem(10)] public int Field_0A { get; set; } - [FlatBufferItem(11)] public ulong EncounterID { get; set; } - [FlatBufferItem(12)] public byte Field_0C { get; set; } - [FlatBufferItem(13)] public bool CanGigantamax { get; set; } - [FlatBufferItem(14)] public int HeldItem { get; set; } - [FlatBufferItem(15)] public byte Level { get; set; } - [FlatBufferItem(16)] public Scenario EncounterScenario { get; set; } - [FlatBufferItem(17)] public int Species { get; set; } - [FlatBufferItem(18)] public uint ShinyLock { get; set; } - [FlatBufferItem(19)] public uint Nature { get; set; } - [FlatBufferItem(20)] public byte Gender { get; set; } - [FlatBufferItem(21)] public sbyte IV_SPE { get; set; } - [FlatBufferItem(22)] public sbyte IV_ATK { get; set; } - [FlatBufferItem(23)] public sbyte IV_DEF { get; set; } - [FlatBufferItem(24)] public sbyte IV_HP { get; set; } - [FlatBufferItem(25)] public sbyte IV_SPA { get; set; } - [FlatBufferItem(26)] public sbyte IV_SPD { get; set; } - [FlatBufferItem(27)] public int Ability { get; set; } - [FlatBufferItem(28)] public int Move0 { get; set; } - [FlatBufferItem(29)] public int Move1 { get; set; } - [FlatBufferItem(30)] public int Move2 { get; set; } - [FlatBufferItem(31)] public int Move3 { get; set; } - - public Species SpeciesID => (Species)Species; - - public int[] IVs + get => new int[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; + set { - get => new int[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; - set - { - if (value?.Length != 6) return; - IV_HP = (sbyte)value[0]; - IV_ATK = (sbyte)value[1]; - IV_DEF = (sbyte)value[2]; - IV_SPE = (sbyte)value[3]; - IV_SPA = (sbyte)value[4]; - IV_SPD = (sbyte)value[5]; - } - } - - public int[] Moves - { - get => new[] { Move0, Move1, Move2, Move3 }; - set - { - if (value?.Length != 4) return; - Move0 = value[0]; - Move1 = value[1]; - Move2 = value[2]; - Move3 = value[3]; - } - } - -#pragma warning disable CA1027 // Mark enums with FlagsAttribute - [FlatBufferEnum(typeof(byte))] - public enum FixedGender -#pragma warning restore CA1027 // Mark enums with FlagsAttribute - { - Random = 0, - Male = 1, - Female = 2, - Genderless = Random, - } - - // scenarios that are set for specific story encounters, most don't work on encounters that are not meant to have them - [FlatBufferEnum(typeof(int))] - public enum Scenario - { - None, - Legendary_Pokemon, - _2, - _3, - Eternatus, - Eternamax_Eternatus_1, - Eternamax_Eternatus_2, - Zacian_Zamazenta_Fog, - Motostoke_Gym_Challenge, - Max_Raid_Battle_1, - Max_Raid_Battle_2, - Max_Raid_Battle_3, - Max_Raid_Battle_4, - Zacian_Zamazenta_Boss, - Fast_Slowpoke, - Regigigas_Raid_Battle, - Special_Raid_Battle, - Calyrex, - Glastrier_Spectrier, - Calyrex_Fusion, - } - - public string GetSummary(IReadOnlyList species) - { - var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; - var ability = Ability switch - { - 0 => string.Empty, - 3 => ", Ability = 4", - _ => $", Ability = {Ability}", - }; - - var ivs = IVs[0] switch - { - 31 when IVs.All(z => z == 31) => ", FlawlessIVCount = 6", - -1 when IVs.All(z => z == -1) => string.Empty, - -4 => ", FlawlessIVCount = 3", - _ => $", IVs = new[]{{{string.Join(",", IVs)}}}", - }; - - var gender = Gender == (int)FixedGender.Random ? string.Empty : $", Gender = {Gender - 1}"; - var nature = (Nature)Nature == Structures.Nature.Random25 ? string.Empty : $", Nature = Nature.{(Nature)Nature}"; - var altform = Form == 0 ? string.Empty : $", Form = {Form:00}"; - var moves = Move0 == 0 ? string.Empty : $", Moves = new[] {{{Move0:000},{Move1:000},{Move2:000},{Move3:000}}}"; - var shiny = (Shiny)ShinyLock == Shiny.Random ? string.Empty : $", Shiny = {(Shiny)ShinyLock}"; - var giga = !CanGigantamax ? string.Empty : ", CanGigantamax = true"; - var dyna = DynamaxLevel == 0 ? string.Empty : $", DynamaxLevel = {DynamaxLevel}"; - - return - $" new(SWSH) {{ Species = {Species:000}, Level = {Level:00}, Location = -01{moves}{ivs}{shiny}{gender}{ability}{nature}{altform}{giga}{dyna} }},{comment}"; + if (value?.Length != 6) return; + IV_HP = (sbyte)value[0]; + IV_ATK = (sbyte)value[1]; + IV_DEF = (sbyte)value[2]; + IV_SPE = (sbyte)value[3]; + IV_SPA = (sbyte)value[4]; + IV_SPD = (sbyte)value[5]; } } + + public int[] Moves + { + get => new[] { Move0, Move1, Move2, Move3 }; + set + { + if (value?.Length != 4) return; + Move0 = value[0]; + Move1 = value[1]; + Move2 = value[2]; + Move3 = value[3]; + } + } + +#pragma warning disable CA1027 // Mark enums with FlagsAttribute + [FlatBufferEnum(typeof(byte))] + public enum FixedGender +#pragma warning restore CA1027 // Mark enums with FlagsAttribute + { + Random = 0, + Male = 1, + Female = 2, + Genderless = Random, + } + + // scenarios that are set for specific story encounters, most don't work on encounters that are not meant to have them + [FlatBufferEnum(typeof(int))] + public enum Scenario + { + None, + Legendary_Pokemon, + _2, + _3, + Eternatus, + Eternamax_Eternatus_1, + Eternamax_Eternatus_2, + Zacian_Zamazenta_Fog, + Motostoke_Gym_Challenge, + Max_Raid_Battle_1, + Max_Raid_Battle_2, + Max_Raid_Battle_3, + Max_Raid_Battle_4, + Zacian_Zamazenta_Boss, + Fast_Slowpoke, + Regigigas_Raid_Battle, + Special_Raid_Battle, + Calyrex, + Glastrier_Spectrier, + Calyrex_Fusion, + } + + public string GetSummary(IReadOnlyList species) + { + var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; + var ability = Ability switch + { + 0 => string.Empty, + 3 => ", Ability = 4", + _ => $", Ability = {Ability}", + }; + + var ivs = IVs[0] switch + { + 31 when IVs.All(z => z == 31) => ", FlawlessIVCount = 6", + -1 when IVs.All(z => z == -1) => string.Empty, + -4 => ", FlawlessIVCount = 3", + _ => $", IVs = new[]{{{string.Join(",", IVs)}}}", + }; + + var gender = Gender == (int)FixedGender.Random ? string.Empty : $", Gender = {Gender - 1}"; + var nature = (Nature)Nature == Structures.Nature.Random25 ? string.Empty : $", Nature = Nature.{(Nature)Nature}"; + var altform = Form == 0 ? string.Empty : $", Form = {Form:00}"; + var moves = Move0 == 0 ? string.Empty : $", Moves = new[] {{{Move0:000},{Move1:000},{Move2:000},{Move3:000}}}"; + var shiny = (Shiny)ShinyLock == Shiny.Random ? string.Empty : $", Shiny = {(Shiny)ShinyLock}"; + var giga = !CanGigantamax ? string.Empty : ", CanGigantamax = true"; + var dyna = DynamaxLevel == 0 ? string.Empty : $", DynamaxLevel = {DynamaxLevel}"; + + return + $" new(SWSH) {{ Species = {Species:000}, Level = {Level:00}, Location = -01{moves}{ivs}{shiny}{gender}{ability}{nature}{altform}{giga}{dyna} }},{comment}"; + } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8Archive.cs index 244b19ee..9775b1d5 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Static/EncounterStatic8Archive.cs @@ -6,11 +6,10 @@ // ReSharper disable UnusedType.Global #nullable disable -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterStatic8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterStatic8Archive : IFlatBufferArchive - { - [FlatBufferItem(0)] public EncounterStatic8[] Table { get; set; } - } + [FlatBufferItem(0)] public EncounterStatic8[] Table { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8.cs b/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8.cs index d73191de..01ba91a1 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Linq; @@ -11,134 +11,133 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterTrade8 { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterTrade8 + [FlatBufferItem(00)] public byte Form { get; set; } + [FlatBufferItem(01)] public byte DynamaxLevel { get; set; } + [FlatBufferItem(02)] public int BallItemID { get; set; } + [FlatBufferItem(03)] public int Field_03 { get; set; } + [FlatBufferItem(04)] public ulong Hash0 { get; set; } + [FlatBufferItem(05)] public bool CanGigantamax { get; set; } + [FlatBufferItem(06)] public int HeldItem { get; set; } + [FlatBufferItem(07)] public byte Level { get; set; } + [FlatBufferItem(08)] public int Species { get; set; } + [FlatBufferItem(09)] public ulong Hash1 { get; set; } + [FlatBufferItem(10)] public int TrainerID { get; set; } + [FlatBufferItem(11)] public byte Memory { get; set; } + [FlatBufferItem(12)] public ushort TextVar { get; set; } + [FlatBufferItem(13)] public byte Feeling { get; set; } + [FlatBufferItem(14)] public byte Intensity { get; set; } + [FlatBufferItem(15)] public ulong Hash2 { get; set; } + [FlatBufferItem(16)] public byte OTGender { get; set; } + [FlatBufferItem(17)] public byte RequiredForm { get; set; } + [FlatBufferItem(18)] public int RequiredSpecies { get; set; } + [FlatBufferItem(19)] public int RequiredNature { get; set; } + [FlatBufferItem(20)] public byte UnknownRequirement { get; set; } // all 0; we know this field is a trade requirement, but unsure what exactly + [FlatBufferItem(21)] public int ShinyLock { get; set; } + [FlatBufferItem(22)] public int Nature { get; set; } + [FlatBufferItem(23)] public byte Gender { get; set; } + [FlatBufferItem(24)] public sbyte IV_SPE { get; set; } + [FlatBufferItem(25)] public sbyte IV_ATK { get; set; } + [FlatBufferItem(26)] public sbyte IV_DEF { get; set; } + [FlatBufferItem(27)] public sbyte IV_HP { get; set; } + [FlatBufferItem(28)] public sbyte IV_SPA { get; set; } + [FlatBufferItem(29)] public sbyte IV_SPD { get; set; } + [FlatBufferItem(30)] public byte AbilityNumber { get; set; } + [FlatBufferItem(31)] public ushort Relearn1 { get; set; } + [FlatBufferItem(32)] public ushort Relearn2 { get; set; } + [FlatBufferItem(33)] public ushort Relearn3 { get; set; } + [FlatBufferItem(34)] public ushort Relearn4 { get; set; } + + public Species SpeciesID => (Species)Species; + + public static readonly int[] BallToItem = { - [FlatBufferItem(00)] public byte Form { get; set; } - [FlatBufferItem(01)] public byte DynamaxLevel { get; set; } - [FlatBufferItem(02)] public int BallItemID { get; set; } - [FlatBufferItem(03)] public int Field_03 { get; set; } - [FlatBufferItem(04)] public ulong Hash0 { get; set; } - [FlatBufferItem(05)] public bool CanGigantamax { get; set; } - [FlatBufferItem(06)] public int HeldItem { get; set; } - [FlatBufferItem(07)] public byte Level { get; set; } - [FlatBufferItem(08)] public int Species { get; set; } - [FlatBufferItem(09)] public ulong Hash1 { get; set; } - [FlatBufferItem(10)] public int TrainerID { get; set; } - [FlatBufferItem(11)] public byte Memory { get; set; } - [FlatBufferItem(12)] public ushort TextVar { get; set; } - [FlatBufferItem(13)] public byte Feeling { get; set; } - [FlatBufferItem(14)] public byte Intensity { get; set; } - [FlatBufferItem(15)] public ulong Hash2 { get; set; } - [FlatBufferItem(16)] public byte OTGender { get; set; } - [FlatBufferItem(17)] public byte RequiredForm { get; set; } - [FlatBufferItem(18)] public int RequiredSpecies { get; set; } - [FlatBufferItem(19)] public int RequiredNature { get; set; } - [FlatBufferItem(20)] public byte UnknownRequirement { get; set; } // all 0; we know this field is a trade requirement, but unsure what exactly - [FlatBufferItem(21)] public int ShinyLock { get; set; } - [FlatBufferItem(22)] public int Nature { get; set; } - [FlatBufferItem(23)] public byte Gender { get; set; } - [FlatBufferItem(24)] public sbyte IV_SPE { get; set; } - [FlatBufferItem(25)] public sbyte IV_ATK { get; set; } - [FlatBufferItem(26)] public sbyte IV_DEF { get; set; } - [FlatBufferItem(27)] public sbyte IV_HP { get; set; } - [FlatBufferItem(28)] public sbyte IV_SPA { get; set; } - [FlatBufferItem(29)] public sbyte IV_SPD { get; set; } - [FlatBufferItem(30)] public byte AbilityNumber { get; set; } - [FlatBufferItem(31)] public ushort Relearn1 { get; set; } - [FlatBufferItem(32)] public ushort Relearn2 { get; set; } - [FlatBufferItem(33)] public ushort Relearn3 { get; set; } - [FlatBufferItem(34)] public ushort Relearn4 { get; set; } + 000, // None + 001, // Master + 002, // Ultra + 003, // Great + 004, // Poke + 005, // Safari + 006, // Net + 007, // Dive + 008, // Nest + 009, // Repeat + 010, // Timer + 011, // Luxury + 012, // Premier + 013, // Dusk + 014, // Heal + 015, // Quick + 016, // Cherish + 492, // Fast + 493, // Level + 494, // Lure + 495, // Heavy + 496, // Love + 497, // Friend + 498, // Moon + 499, // Sport + 576, // Dream + 851, // Beast + }; - public Species SpeciesID => (Species)Species; + public Ball Ball + { + get => (Ball)Array.IndexOf(BallToItem, BallItemID); + set => BallItemID = BallToItem[(int)value]; + } - public static readonly int[] BallToItem = + public int[] IVs + { + get => new int[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; + set { - 000, // None - 001, // Master - 002, // Ultra - 003, // Great - 004, // Poke - 005, // Safari - 006, // Net - 007, // Dive - 008, // Nest - 009, // Repeat - 010, // Timer - 011, // Luxury - 012, // Premier - 013, // Dusk - 014, // Heal - 015, // Quick - 016, // Cherish - 492, // Fast - 493, // Level - 494, // Lure - 495, // Heavy - 496, // Love - 497, // Friend - 498, // Moon - 499, // Sport - 576, // Dream - 851, // Beast - }; - - public Ball Ball - { - get => (Ball)Array.IndexOf(BallToItem, BallItemID); - set => BallItemID = BallToItem[(int)value]; - } - - public int[] IVs - { - get => new int[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; - set - { - if (value?.Length != 6) return; - IV_HP = (sbyte)value[0]; - IV_ATK = (sbyte)value[1]; - IV_DEF = (sbyte)value[2]; - IV_SPE = (sbyte)value[3]; - IV_SPA = (sbyte)value[4]; - IV_SPD = (sbyte)value[5]; - } - } - - public string GetSummary(IReadOnlyList species) - { - var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; - const string iv = ", IVs = TradeIVs"; - - var ability = AbilityNumber switch - { - 0 => " ", - 3 => "Ability = 4, ", - _ => $"Ability = {AbilityNumber}, ", - }; - - var ivs = IVs[0] switch - { - 31 when IVs.All(z => z == 31) => ", FlawlessIVCount = 6", - -1 when IVs.All(z => z == -1) => string.Empty, - -4 => ", FlawlessIVCount = 3", - _ => iv, - }; - - var otgender = $", OTGender = {OTGender}"; - var gender = Gender == (int)FixedGender.Random ? string.Empty : $", Gender = {Gender - 1}"; - var nature = Nature == (int)Structures.Nature.Random25 ? string.Empty : $", Nature = Nature.{(Nature)Nature}"; - var altform = Form == 0 ? string.Empty : $", Form = {Form:00}"; - var shiny = ShinyLock == (int)Shiny.Never ? string.Empty : $", Shiny = {(Shiny)ShinyLock}"; - var giga = !CanGigantamax ? string.Empty : ", CanGigantamax = true"; - var tid = $"TID7 = {TrainerID}"; - var dyna = $", DynamaxLevel = {DynamaxLevel}"; - var relearn = Relearn1 == 0 ? " " : $", Relearn = new[] {{{Relearn1:000},{Relearn2:000},{Relearn3:000},{Relearn4:000}}}"; - var ball = Ball == Ball.Poke ? string.Empty : $", Ball = {Ball}"; - - return - $" new({Species:000},{Level:00},{Memory:00},{TextVar:000},{Feeling:00},{Intensity}) {{ {ability}{tid}{ivs}{dyna}{otgender}{gender}{shiny}{nature}{giga}{relearn}{altform}{ball} }},{comment}"; + if (value?.Length != 6) return; + IV_HP = (sbyte)value[0]; + IV_ATK = (sbyte)value[1]; + IV_DEF = (sbyte)value[2]; + IV_SPE = (sbyte)value[3]; + IV_SPA = (sbyte)value[4]; + IV_SPD = (sbyte)value[5]; } } + + public string GetSummary(IReadOnlyList species) + { + var comment = $" // {species[Species]}{(Form == 0 ? string.Empty : "-" + Form)}"; + const string iv = ", IVs = TradeIVs"; + + var ability = AbilityNumber switch + { + 0 => " ", + 3 => "Ability = 4, ", + _ => $"Ability = {AbilityNumber}, ", + }; + + var ivs = IVs[0] switch + { + 31 when IVs.All(z => z == 31) => ", FlawlessIVCount = 6", + -1 when IVs.All(z => z == -1) => string.Empty, + -4 => ", FlawlessIVCount = 3", + _ => iv, + }; + + var otgender = $", OTGender = {OTGender}"; + var gender = Gender == (int)FixedGender.Random ? string.Empty : $", Gender = {Gender - 1}"; + var nature = Nature == (int)Structures.Nature.Random25 ? string.Empty : $", Nature = Nature.{(Nature)Nature}"; + var altform = Form == 0 ? string.Empty : $", Form = {Form:00}"; + var shiny = ShinyLock == (int)Shiny.Never ? string.Empty : $", Shiny = {(Shiny)ShinyLock}"; + var giga = !CanGigantamax ? string.Empty : ", CanGigantamax = true"; + var tid = $"TID7 = {TrainerID}"; + var dyna = $", DynamaxLevel = {DynamaxLevel}"; + var relearn = Relearn1 == 0 ? " " : $", Relearn = new[] {{{Relearn1:000},{Relearn2:000},{Relearn3:000},{Relearn4:000}}}"; + var ball = Ball == Ball.Poke ? string.Empty : $", Ball = {Ball}"; + + return + $" new({Species:000},{Level:00},{Memory:00},{TextVar:000},{Feeling:00},{Intensity}) {{ {ability}{tid}{ivs}{dyna}{otgender}{gender}{shiny}{nature}{giga}{relearn}{altform}{ball} }},{comment}"; + } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8Archive.cs b/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8Archive.cs index 2b54f09f..87ca886a 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8Archive.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Trade/EncounterTrade8Archive.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,11 +8,10 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterTrade8Archive : IFlatBufferArchive { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterTrade8Archive : IFlatBufferArchive - { - [FlatBufferItem(0)] public EncounterTrade8[] Table { get; set; } - } + [FlatBufferItem(0)] public EncounterTrade8[] Table { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterArchive8.cs b/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterArchive8.cs index 5c77c425..1158a405 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterArchive8.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterArchive8.cs @@ -1,4 +1,4 @@ -using System.ComponentModel; +using System.ComponentModel; using FlatSharp.Attributes; // ReSharper disable UnusedAutoPropertyAccessor.Global // ReSharper disable ClassNeverInstantiated.Global @@ -8,35 +8,34 @@ #nullable disable #pragma warning disable CA1819 // Properties should not return arrays -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class EncounterArchive8 { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class EncounterArchive8 - { - [FlatBufferItem(0)] public uint Field_00 { get; set; } - [FlatBufferItem(1)] public EncounterTable8[] EncounterTables { get; set; } - } - - [FlatBufferTable] - public class EncounterTable8 - { - [FlatBufferItem(0)] public ulong ZoneID { get; set; } - [FlatBufferItem(1)] public EncounterSubTable8[] SubTables { get; set; } - } - - [FlatBufferTable] - public class EncounterSubTable8 - { - [FlatBufferItem(0)] public byte LevelMin { get; set; } - [FlatBufferItem(1)] public byte LevelMax { get; set; } - [FlatBufferItem(2)] public EncounterSlot8[] Slots { get; set; } - } - - [FlatBufferTable] - public class EncounterSlot8 - { - [FlatBufferItem(0)] public byte Probability { get; set; } - [FlatBufferItem(1)] public int Species { get; set; } - [FlatBufferItem(2)] public byte Form { get; set; } - } + [FlatBufferItem(0)] public uint Field_00 { get; set; } + [FlatBufferItem(1)] public EncounterTable8[] EncounterTables { get; set; } +} + +[FlatBufferTable] +public class EncounterTable8 +{ + [FlatBufferItem(0)] public ulong ZoneID { get; set; } + [FlatBufferItem(1)] public EncounterSubTable8[] SubTables { get; set; } +} + +[FlatBufferTable] +public class EncounterSubTable8 +{ + [FlatBufferItem(0)] public byte LevelMin { get; set; } + [FlatBufferItem(1)] public byte LevelMax { get; set; } + [FlatBufferItem(2)] public EncounterSlot8[] Slots { get; set; } +} + +[FlatBufferTable] +public class EncounterSlot8 +{ + [FlatBufferItem(0)] public byte Probability { get; set; } + [FlatBufferItem(1)] public int Species { get; set; } + [FlatBufferItem(2)] public byte Form { get; set; } } diff --git a/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterTable8Util.cs b/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterTable8Util.cs index 6678d314..719f054f 100644 --- a/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterTable8Util.cs +++ b/pkNX.Structures.FlatBuffers/Gen8/Wild/EncounterTable8Util.cs @@ -1,417 +1,412 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using static pkNX.Structures.FlatBuffers.EncounterTable8Util.SWSHSlotType; -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +public static class EncounterTable8Util { - public static class EncounterTable8Util + public static byte[][] GetBytes(IReadOnlyDictionary zone_loc, IReadOnlyDictionary zone_type, EncounterArchive8 t, bool hiddenTreeFix = false) { - public static byte[][] GetBytes(IReadOnlyDictionary zone_loc, IReadOnlyDictionary zone_type, EncounterArchive8 t, bool hiddenTreeFix = false) + var result = new List(); + foreach (var zone in t.EncounterTables) { - var result = new List(); - foreach (var zone in t.EncounterTables) - { - var entry = GetDumpable(zone, zone_loc, zone_type); - if (entry.Slots.Count == 0) - continue; - result.Add(entry); - } - - if (hiddenTreeFix) - { - // The Berry Trees in Bridge Field are right against the map boundary, and can be accessed on the adjacent Map ID (Stony Wilderness) - // Copy the two Berry Tree encounters from Bridge to Stony, as these aren't overworld (wandering) crossover encounters. - var bridge = result.Find(z => z.Location == 142); - var stony = result.Find(z => z.Location == 144); - - foreach (var s in bridge.Slots.Where(z => z.EncounterType == SWSHEncounterType.Shaking_Trees)) - stony.Slots.Add(s); - } - - return result.ConvertAll(z => z.Serialize()).ToArray(); + var entry = GetDumpable(zone, zone_loc, zone_type); + if (entry.Slots.Count == 0) + continue; + result.Add(entry); } - private static DumpableLocation GetDumpable(EncounterTable8 zone, IReadOnlyDictionary zoneLoc, IReadOnlyDictionary zoneType) + if (hiddenTreeFix) { - // Don't dump data that we can't correlate to a zone - if (!zoneLoc.TryGetValue(zone.ZoneID, out var tmp)) - return DumpableLocation.Empty; + // The Berry Trees in Bridge Field are right against the map boundary, and can be accessed on the adjacent Map ID (Stony Wilderness) + // Copy the two Berry Tree encounters from Bridge to Stony, as these aren't overworld (wandering) crossover encounters. + var bridge = result.Find(z => z.Location == 142); + var stony = result.Find(z => z.Location == 144); + if (bridge is null) + throw new ArgumentException("Bridge Field not found"); + if (stony is null) + throw new ArgumentException("Stony Wilderness not found"); - // Try to get the table type. Skip inaccessible tables. - if (!zoneType.TryGetValue(zone.ZoneID, out var slottype) || slottype == (byte)Inaccessible) - return DumpableLocation.Empty; + var slots = bridge.Slots; + stony.Slots.AddRange(slots.Where(z => z.EncounterType == SWSHEncounterType.Shaking_Trees)); + } - byte locID = tmp; - var list = new List(); - for (int i = 0; i < zone.SubTables.Length; i++) + return result.ConvertAll(z => z.Serialize()).ToArray(); + } + + private static DumpableLocation GetDumpable(EncounterTable8 zone, IReadOnlyDictionary zoneLoc, IReadOnlyDictionary zoneType) + { + // Don't dump data that we can't correlate to a zone + if (!zoneLoc.TryGetValue(zone.ZoneID, out var tmp)) + return DumpableLocation.Empty; + + // Try to get the table type. Skip inaccessible tables. + if (!zoneType.TryGetValue(zone.ZoneID, out var slottype) || slottype == (byte)Inaccessible) + return DumpableLocation.Empty; + + byte locID = tmp; + var list = new List(); + for (int i = 0; i < zone.SubTables.Length; i++) + { + var weather = (SWSHEncounterType)(1 << i); + + if (!IsPermittedWeather(locID, weather, slottype)) + continue; + + var table = zone.SubTables[i]; + var min = table.LevelMin; + var max = table.LevelMax; + foreach (var s in table.Slots) { - var weather = (SWSHEncounterType)(1 << i); - - if (!IsPermittedWeather(locID, weather, slottype)) + if (s.Species == 0) continue; - var table = zone.SubTables[i]; - var min = table.LevelMin; - var max = table.LevelMax; - foreach (var s in table.Slots) - { - if (s.Species == 0) - continue; - - var s8 = new Slot8(s.Species, s.Form, min, max) {EncounterType = weather}; - var match = list.Find(z => z.Equals(s8)); - if (match == null) - list.Add(s8); - else - match.EncounterType |= weather; - } - } - - return new DumpableLocation(list, locID, slottype); - } - - private static bool IsPermittedWeather(byte locID, SWSHEncounterType weather, byte slotType) - { - // Only keep fishing slots for any encounters that are FishingOnly. - if (slotType == (byte)OnlyFishing) - return weather == SWSHEncounterType.Fishing; - - // Otherwise, keep all fishing and shaking tree encounters. - if (weather is SWSHEncounterType.Shaking_Trees or SWSHEncounterType.Fishing) - return true; - - // If we didn't find the weather in the general table, only allow Normal. - if (!WeatherbyArea.TryGetValue(locID, out var permit)) - permit = SWSHEncounterType.Normal; - if (permit.HasFlag(weather)) - return true; - - // Check bleed conditions otherwise. - return IsWeatherBleedPossible((SWSHSlotType)slotType, permit, locID); - } - - private static bool IsWeatherBleedPossible(SWSHSlotType type, SWSHEncounterType permit, int location) => type switch - { - SymbolMain or SymbolMain2 or SymbolMain3 => WeatherBleedSymbol .TryGetValue(location, out var weather) && weather.HasFlag(permit), - HiddenMain or HiddenMain2 => WeatherBleedHiddenGrass .TryGetValue(location, out var weather) && weather.HasFlag(permit), - Surfing => WeatherBleedSymbolSurfing .TryGetValue(location, out var weather) && weather.HasFlag(permit), - Sharpedo => WeatherBleedSymbolSharpedo.TryGetValue(location, out var weather) && weather.HasFlag(permit), - _ => false - }; - - private class DumpableLocation - { - public static readonly DumpableLocation Empty = new(new List(), 0, 0); - - public readonly List Slots; - public readonly byte Location; - public readonly byte SlotType; - - public DumpableLocation(List slots, byte location, byte slotType) - { - Slots = slots; - Location = location; - SlotType = slotType; - } - - public byte[] Serialize() => SerializeSlot8(Location, Slots, SlotType); - } - - private static byte[] SerializeSlot8(byte locID, IEnumerable list, byte slotType) - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - int ctr = 0; - bw.Write(locID); - bw.Write((byte) 0); // count tmp - var groups = list.GroupBy(z => (int) z.EncounterType | (z.Min << 16) | (z.Max << 24)); - foreach (var g in groups) - { - var slots = g.ToArray(); - var type = g.Key & 0xFFFF; - var min = (g.Key >> 16) & 0xFF; - var max = g.Key >> 24; - bw.Write((ushort) type); - bw.Write((byte) min); - bw.Write((byte) max); - bw.Write((byte) slots.Length); - bw.Write(slotType); - - foreach (var slot in slots) - bw.Write((ushort)(slot.Species | (slot.Form << 11))); - ctr += slots.Length; - } - - bw.BaseStream.Seek(1, SeekOrigin.Begin); - bw.Write((byte) ctr); - return ms.ToArray(); - } - - [Flags] -#pragma warning disable RCS1154 // Sort enum members. - private enum SWSHEncounterType -#pragma warning restore RCS1154 // Sort enum members. - { - None = 0, - Normal = 1, - Overcast = 1 << 1, - Raining = 1 << 2, - Thunderstorm = 1 << 3, - Intense_Sun = 1 << 4, - Snowing = 1 << 5, - Snowstorm = 1 << 6, - Sandstorm = 1 << 7, - Heavy_Fog = 1 << 8, - Shaking_Trees = 1 << 9, - Fishing = 1 << 10, - - All = Normal | Overcast | Raining | Thunderstorm | Intense_Sun | Snowing | Snowstorm | Sandstorm | Heavy_Fog, - Stormy = Raining | Thunderstorm, - Icy = Snowing | Snowstorm, - All_IoA = Normal | Overcast | Stormy | Intense_Sun | Sandstorm | Heavy_Fog, // IoA can have everything but snow - All_CT = Normal | Overcast | Stormy | Intense_Sun | Icy | Heavy_Fog, // CT can have everything but sand - No_Sun_Sand = Normal | Overcast | Stormy | Icy | Heavy_Fog, // Everything but sand and sun - All_Ballimere = Normal | Overcast | Stormy | Intense_Sun | Snowing | Heavy_Fog, // All Ballimere Lake weather - } - - public enum SWSHSlotType : ushort - { - SymbolMain, - SymbolMain2, - SymbolMain3, - - HiddenMain, // Table with the tree/fishing slots - HiddenMain2, - - Surfing, - Surfing2, - Sky, - Sky2, - Ground, - Ground2, - Sharpedo, - - OnlyFishing, - Inaccessible, - } - - private class Slot8 : IEquatable - { - public readonly int Species; - public readonly int Form; - public readonly int Min; - public readonly int Max; - public SWSHEncounterType EncounterType; - - public Slot8(int s, int f, int n, int x) - { - Species = s; - Form = f; - Min = n; - Max = x; - } - - public bool Equals(Slot8? other) - { - if (other is null) return false; - if (ReferenceEquals(this, other)) return true; - return Species == other.Species && Form == other.Form && Min == other.Min && Max == other.Max; - } - - public override bool Equals(object? obj) - { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - return obj.GetType() == GetType() && Equals((Slot8) obj); - } - - public override int GetHashCode() - { - unchecked - { - var hashCode = Species; - hashCode = (hashCode * 397) ^ Form; - hashCode = (hashCode * 397) ^ Min; - hashCode = (hashCode * 397) ^ Max; - return hashCode; - } + var s8 = new Slot8(s.Species, s.Form, min, max) {EncounterType = weather}; + var match = list.Find(z => z.Equals(s8)); + if (match == null) + list.Add(s8); + else + match.EncounterType |= weather; } } - public static IEnumerable GetLines(EncounterArchive8 t, IReadOnlyDictionary zone_names, string[] subtable_names, string[] species) - { - for (var i = 0; i < t.EncounterTables.Length; i++) - { - var enc = t.EncounterTables[i]; - bool known = zone_names.TryGetValue(enc.ZoneID, out var zoneName); - if (!known) - zoneName = enc.ZoneID.ToString("X16"); - yield return $"{i:000} - {zoneName}:"; + return new DumpableLocation(list, locID, slottype); + } - if (enc.SubTables.Length != 0) - { - var j = 0; - const int NUM_WEATHER_TABLES = 9; - if (AllWeatherTablesIdentical(enc.SubTables, NUM_WEATHER_TABLES)) - { - foreach (var line in GetSubTableSummary(enc.SubTables[0], "All Weather", species)) - yield return $"\t{line}"; - j = NUM_WEATHER_TABLES; - } - - while (j < enc.SubTables.Length) - { - foreach (var line in GetSubTableSummary(enc.SubTables[j], subtable_names[j], species)) - yield return $"\t{line}"; - j++; - } - } - - yield return string.Empty; - } - } - - private static IEnumerable GetSubTableSummary(EncounterSubTable8 subtable, string name, string[] species) - { - if (subtable.LevelMin == 0 || subtable.LevelMax == 0) yield break; - - yield return $"{name} ({GetSubSummary(subtable.LevelMin, subtable.LevelMax)}):"; - foreach (var line in GetLines(subtable.Slots, species)) - yield return $"\t{line}"; - } - - private static bool AllWeatherTablesIdentical(EncounterSubTable8[] subtables, int numWeatherTables) - { - if (subtables.Length < numWeatherTables) throw new ArgumentException(); - var first_table = subtables[0]; - for (var i = 1; i < numWeatherTables; i++) - { - var cur_table = subtables[i]; - if (cur_table.LevelMin != first_table.LevelMin) return false; - if (cur_table.LevelMax != first_table.LevelMax) return false; - if (cur_table.Slots.Length != first_table.Slots.Length) return false; - for (var j = 0; j < cur_table.Slots.Length; j++) - { - if (cur_table.Slots[j].Species != first_table.Slots[j].Species) return false; - if (cur_table.Slots[j].Form != first_table.Slots[j].Form) return false; - if (cur_table.Slots[j].Probability != first_table.Slots[j].Probability) return false; - } - } + private static bool IsPermittedWeather(byte locID, SWSHEncounterType weather, byte slotType) + { + // Only keep fishing slots for any encounters that are FishingOnly. + if (slotType == (byte)OnlyFishing) + return weather == SWSHEncounterType.Fishing; + // Otherwise, keep all fishing and shaking tree encounters. + if (weather is SWSHEncounterType.Shaking_Trees or SWSHEncounterType.Fishing) return true; + + // If we didn't find the weather in the general table, only allow Normal. + if (!WeatherbyArea.TryGetValue(locID, out var permit)) + permit = SWSHEncounterType.Normal; + if (permit.HasFlag(weather)) + return true; + + // Check bleed conditions otherwise. + return IsWeatherBleedPossible((SWSHSlotType)slotType, permit, locID); + } + + private static bool IsWeatherBleedPossible(SWSHSlotType type, SWSHEncounterType permit, int location) => type switch + { + SymbolMain or SymbolMain2 or SymbolMain3 => WeatherBleedSymbol .TryGetValue(location, out var weather) && weather.HasFlag(permit), + HiddenMain or HiddenMain2 => WeatherBleedHiddenGrass .TryGetValue(location, out var weather) && weather.HasFlag(permit), + Surfing => WeatherBleedSymbolSurfing .TryGetValue(location, out var weather) && weather.HasFlag(permit), + Sharpedo => WeatherBleedSymbolSharpedo.TryGetValue(location, out var weather) && weather.HasFlag(permit), + _ => false + }; + + private class DumpableLocation + { + public static readonly DumpableLocation Empty = new(new List(), 0, 0); + + public readonly List Slots; + public readonly byte Location; + public readonly byte SlotType; + + public DumpableLocation(List slots, byte location, byte slotType) + { + Slots = slots; + Location = location; + SlotType = slotType; } - private static string GetSubSummary(int min, int max) => $"Lv. {min}-{max}"; + public byte[] Serialize() => SerializeSlot8(Location, Slots, SlotType); + } - private static IEnumerable GetLines(IReadOnlyList arr, IReadOnlyList species) + private static byte[] SerializeSlot8(byte locID, IEnumerable list, byte slotType) + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + int ctr = 0; + bw.Write(locID); + bw.Write((byte) 0); // count tmp + var groups = list.GroupBy(z => (int) z.EncounterType | (z.Min << 16) | (z.Max << 24)); + foreach (var g in groups) { - foreach (var slot in arr.OrderByDescending(sl => sl.Probability)) + var slots = g.ToArray(); + var type = g.Key & 0xFFFF; + var min = (g.Key >> 16) & 0xFF; + var max = g.Key >> 24; + bw.Write((ushort) type); + bw.Write((byte) min); + bw.Write((byte) max); + bw.Write((byte) slots.Length); + bw.Write(slotType); + + foreach (var slot in slots) + bw.Write((ushort)(slot.Species | (slot.Form << 11))); + ctr += slots.Length; + } + + bw.BaseStream.Seek(1, SeekOrigin.Begin); + bw.Write((byte) ctr); + return ms.ToArray(); + } + + [Flags] +#pragma warning disable RCS1154 // Sort enum members. + private enum SWSHEncounterType +#pragma warning restore RCS1154 // Sort enum members. + { + None = 0, + Normal = 1, + Overcast = 1 << 1, + Raining = 1 << 2, + Thunderstorm = 1 << 3, + Intense_Sun = 1 << 4, + Snowing = 1 << 5, + Snowstorm = 1 << 6, + Sandstorm = 1 << 7, + Heavy_Fog = 1 << 8, + Shaking_Trees = 1 << 9, + Fishing = 1 << 10, + + All = Normal | Overcast | Raining | Thunderstorm | Intense_Sun | Snowing | Snowstorm | Sandstorm | Heavy_Fog, + Stormy = Raining | Thunderstorm, + Icy = Snowing | Snowstorm, + All_IoA = Normal | Overcast | Stormy | Intense_Sun | Sandstorm | Heavy_Fog, // IoA can have everything but snow + All_CT = Normal | Overcast | Stormy | Intense_Sun | Icy | Heavy_Fog, // CT can have everything but sand + No_Sun_Sand = Normal | Overcast | Stormy | Icy | Heavy_Fog, // Everything but sand and sun + All_Ballimere = Normal | Overcast | Stormy | Intense_Sun | Snowing | Heavy_Fog, // All Ballimere Lake weather + } + + public enum SWSHSlotType : ushort + { + SymbolMain, + SymbolMain2, + SymbolMain3, + + HiddenMain, // Table with the tree/fishing slots + HiddenMain2, + + Surfing, + Surfing2, + Sky, + Sky2, + Ground, + Ground2, + Sharpedo, + + OnlyFishing, + Inaccessible, + } + + private class Slot8 : IEquatable + { + public readonly int Species; + public readonly int Form; + public readonly int Min; + public readonly int Max; + public SWSHEncounterType EncounterType; + + public Slot8(int s, int f, int n, int x) + { + Species = s; + Form = f; + Min = n; + Max = x; + } + + public bool Equals(Slot8? other) + { + if (other is null) return false; + if (ReferenceEquals(this, other)) return true; + return Species == other.Species && Form == other.Form && Min == other.Min && Max == other.Max; + } + + public override bool Equals(object? obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + return obj.GetType() == GetType() && Equals((Slot8) obj); + } + + public override int GetHashCode() => HashCode.Combine(Species, Form, Min, Max); + } + + public static IEnumerable GetLines(EncounterArchive8 t, IReadOnlyDictionary zone_names, string[] subtable_names, string[] species) + { + for (var i = 0; i < t.EncounterTables.Length; i++) + { + var enc = t.EncounterTables[i]; + bool known = zone_names.TryGetValue(enc.ZoneID, out var zoneName); + if (!known) + zoneName = enc.ZoneID.ToString("X16"); + yield return $"{i:000} - {zoneName}:"; + + if (enc.SubTables.Length != 0) { - if (slot.Species == 0) - continue; - string form = slot.Form == 0 ? string.Empty : $"-{slot.Form}"; - var spec_form = $"{species[slot.Species]}{form}"; - yield return $"- {spec_form,-12}\t{slot.Probability:00}%"; + var j = 0; + const int NUM_WEATHER_TABLES = 9; + if (AllWeatherTablesIdentical(enc.SubTables, NUM_WEATHER_TABLES)) + { + foreach (var line in GetSubTableSummary(enc.SubTables[0], "All Weather", species)) + yield return $"\t{line}"; + j = NUM_WEATHER_TABLES; + } + + while (j < enc.SubTables.Length) + { + foreach (var line in GetSubTableSummary(enc.SubTables[j], subtable_names[j], species)) + yield return $"\t{line}"; + j++; + } } yield return string.Empty; } - - private static readonly Dictionary WeatherbyArea = new() - { - { 68, SWSHEncounterType.Intense_Sun }, // Route 6 - { 88, SWSHEncounterType.Snowing }, // Route 8 (Steamdrift Way) - { 90, SWSHEncounterType.Snowing }, // Route 9 - { 92, SWSHEncounterType.Snowing }, // Route 9 (Circhester Bay) - { 94, SWSHEncounterType.Overcast }, // Route 9 (Outer Spikemuth) - { 106, SWSHEncounterType.Snowstorm }, // Route 10 - { 122, SWSHEncounterType.All }, // Rolling Fields - { 124, SWSHEncounterType.All }, // Dappled Grove - { 126, SWSHEncounterType.All }, // Watchtower Ruins - { 128, SWSHEncounterType.All }, // East Lake Axewell - { 130, SWSHEncounterType.All }, // West Lake Axewell - { 132, SWSHEncounterType.All }, // Axew's Eye - { 134, SWSHEncounterType.All }, // South Lake Miloch - { 136, SWSHEncounterType.All }, // Giant's Seat - { 138, SWSHEncounterType.All }, // North Lake Miloch - { 140, SWSHEncounterType.All }, // Motostoke Riverbank - { 142, SWSHEncounterType.All }, // Bridge Field - { 144, SWSHEncounterType.All }, // Stony Wilderness - { 146, SWSHEncounterType.All }, // Dusty Bowl - { 148, SWSHEncounterType.All }, // Giant's Mirror - { 150, SWSHEncounterType.All }, // Hammerlocke Hills - { 152, SWSHEncounterType.All }, // Giant's Cap - { 154, SWSHEncounterType.All }, // Lake of Outrage - { 164, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Fields of Honor - { 166, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Soothing Wetlands - { 168, SWSHEncounterType.All_IoA }, // Forest of Focus - { 170, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Challenge Beach - { 174, SWSHEncounterType.All_IoA }, // Challenge Road - { 178, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Loop Lagoon - { 180, SWSHEncounterType.All_IoA }, // Training Lowlands - { 184, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Raining | SWSHEncounterType.Sandstorm | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Potbottom Desert - { 186, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Workout Sea - { 188, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Stepping-Stone Sea - { 190, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Insular Sea - { 192, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Honeycalm Sea - { 194, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Honeycalm Island - { 204, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Slippery Slope - { 208, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Frostpoint Field - { 210, SWSHEncounterType.All_CT }, // Giant's Bed - { 212, SWSHEncounterType.All_CT }, // Old Cemetery - { 214, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Snowslide Slope - { 216, SWSHEncounterType.Overcast }, // Tunnel to the Top - { 218, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Path to the Peak - { 222, SWSHEncounterType.All_CT }, // Giant's Foot - { 224, SWSHEncounterType.Overcast }, // Roaring-Sea Caves - { 226, SWSHEncounterType.No_Sun_Sand }, // Frigid Sea - { 228, SWSHEncounterType.All_CT }, // Three-Point Pass - { 230, SWSHEncounterType.All_Ballimere }, // Ballimere Lake - { 232, SWSHEncounterType.Overcast }, // Lakeside Cave - }; - - /// - /// Weather types that may bleed into each location from adjacent locations for standard symbol encounter slots. - /// - private static readonly Dictionary WeatherBleedSymbol = new() - { - { 166, SWSHEncounterType.All_IoA }, // Soothing Wetlands from Forest of Focus - { 170, SWSHEncounterType.All_IoA }, // Challenge Beach from Forest of Focus - { 182, SWSHEncounterType.All_IoA }, // Warm-Up Tunnel from Training Lowlands - { 208, SWSHEncounterType.All_CT }, // Frostpoint Field from Giant's Bed - { 216, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Tunnel to the Top from Path to the Peak - { 224, SWSHEncounterType.All_CT }, // Roaring-Sea Caves from Three-Point Pass - { 230, SWSHEncounterType.All_CT }, // Ballimere Lake from Giant's Bed - { 232, SWSHEncounterType.All_Ballimere }, // Lakeside Cave from Ballimere Lake - }; - - /// - /// Weather types that may bleed into each location from adjacent locations for surfing symbol encounter slots. - /// - private static readonly Dictionary WeatherBleedSymbolSurfing = new() - { - { 192, SWSHEncounterType.All_IoA }, // Honeycalm Sea from Training Lowlands - }; - - /// - /// Weather types that may bleed into each location from adjacent locations for Sharpedo symbol encounter slots. - /// - private static readonly Dictionary WeatherBleedSymbolSharpedo = new() - { - { 192, SWSHEncounterType.All_IoA }, // Honeycalm Sea from Training Lowlands - }; - - /// - /// Weather types that may bleed into each location from adjacent locations, for standard hidden grass encounter slots. - /// - private static readonly Dictionary WeatherBleedHiddenGrass = new() - { - { 166, SWSHEncounterType.All_IoA }, // Soothing Wetlands from Forest of Focus - { 170, SWSHEncounterType.All_IoA }, // Challenge Beach from Forest of Focus - { 208, SWSHEncounterType.All_CT }, // Frostpoint Field from Giant's Bed - { 230, SWSHEncounterType.All_CT }, // Ballimere Lake from Giant's Bed - }; } + + private static IEnumerable GetSubTableSummary(EncounterSubTable8 subtable, string name, string[] species) + { + if (subtable.LevelMin == 0 || subtable.LevelMax == 0) yield break; + + yield return $"{name} ({GetSubSummary(subtable.LevelMin, subtable.LevelMax)}):"; + foreach (var line in GetLines(subtable.Slots, species)) + yield return $"\t{line}"; + } + + private static bool AllWeatherTablesIdentical(EncounterSubTable8[] subtables, int numWeatherTables) + { + if (numWeatherTables >= subtables.Length) + throw new ArgumentOutOfRangeException(nameof(numWeatherTables), numWeatherTables, message: "Must be less than the number of sub-tables"); + + var first_table = subtables[0]; + for (var i = 1; i < numWeatherTables; i++) + { + var cur_table = subtables[i]; + if (cur_table.LevelMin != first_table.LevelMin) return false; + if (cur_table.LevelMax != first_table.LevelMax) return false; + if (cur_table.Slots.Length != first_table.Slots.Length) return false; + for (var j = 0; j < cur_table.Slots.Length; j++) + { + if (cur_table.Slots[j].Species != first_table.Slots[j].Species) return false; + if (cur_table.Slots[j].Form != first_table.Slots[j].Form) return false; + if (cur_table.Slots[j].Probability != first_table.Slots[j].Probability) return false; + } + } + + return true; + } + + private static string GetSubSummary(int min, int max) => $"Lv. {min}-{max}"; + + private static IEnumerable GetLines(IReadOnlyList arr, IReadOnlyList species) + { + foreach (var slot in arr.OrderByDescending(sl => sl.Probability)) + { + if (slot.Species == 0) + continue; + string form = slot.Form == 0 ? string.Empty : $"-{slot.Form}"; + var spec_form = $"{species[slot.Species]}{form}"; + yield return $"- {spec_form,-12}\t{slot.Probability:00}%"; + } + + yield return string.Empty; + } + + private static readonly Dictionary WeatherbyArea = new() + { + { 68, SWSHEncounterType.Intense_Sun }, // Route 6 + { 88, SWSHEncounterType.Snowing }, // Route 8 (Steamdrift Way) + { 90, SWSHEncounterType.Snowing }, // Route 9 + { 92, SWSHEncounterType.Snowing }, // Route 9 (Circhester Bay) + { 94, SWSHEncounterType.Overcast }, // Route 9 (Outer Spikemuth) + { 106, SWSHEncounterType.Snowstorm }, // Route 10 + { 122, SWSHEncounterType.All }, // Rolling Fields + { 124, SWSHEncounterType.All }, // Dappled Grove + { 126, SWSHEncounterType.All }, // Watchtower Ruins + { 128, SWSHEncounterType.All }, // East Lake Axewell + { 130, SWSHEncounterType.All }, // West Lake Axewell + { 132, SWSHEncounterType.All }, // Axew's Eye + { 134, SWSHEncounterType.All }, // South Lake Miloch + { 136, SWSHEncounterType.All }, // Giant's Seat + { 138, SWSHEncounterType.All }, // North Lake Miloch + { 140, SWSHEncounterType.All }, // Motostoke Riverbank + { 142, SWSHEncounterType.All }, // Bridge Field + { 144, SWSHEncounterType.All }, // Stony Wilderness + { 146, SWSHEncounterType.All }, // Dusty Bowl + { 148, SWSHEncounterType.All }, // Giant's Mirror + { 150, SWSHEncounterType.All }, // Hammerlocke Hills + { 152, SWSHEncounterType.All }, // Giant's Cap + { 154, SWSHEncounterType.All }, // Lake of Outrage + { 164, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Fields of Honor + { 166, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Soothing Wetlands + { 168, SWSHEncounterType.All_IoA }, // Forest of Focus + { 170, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Challenge Beach + { 174, SWSHEncounterType.All_IoA }, // Challenge Road + { 178, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Loop Lagoon + { 180, SWSHEncounterType.All_IoA }, // Training Lowlands + { 184, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Raining | SWSHEncounterType.Sandstorm | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Potbottom Desert + { 186, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Workout Sea + { 188, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Stepping-Stone Sea + { 190, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Insular Sea + { 192, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Honeycalm Sea + { 194, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Stormy | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Heavy_Fog }, // Honeycalm Island + { 204, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Slippery Slope + { 208, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Frostpoint Field + { 210, SWSHEncounterType.All_CT }, // Giant's Bed + { 212, SWSHEncounterType.All_CT }, // Old Cemetery + { 214, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Snowslide Slope + { 216, SWSHEncounterType.Overcast }, // Tunnel to the Top + { 218, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Path to the Peak + { 222, SWSHEncounterType.All_CT }, // Giant's Foot + { 224, SWSHEncounterType.Overcast }, // Roaring-Sea Caves + { 226, SWSHEncounterType.No_Sun_Sand }, // Frigid Sea + { 228, SWSHEncounterType.All_CT }, // Three-Point Pass + { 230, SWSHEncounterType.All_Ballimere }, // Ballimere Lake + { 232, SWSHEncounterType.Overcast }, // Lakeside Cave + }; + + /// + /// Weather types that may bleed into each location from adjacent locations for standard symbol encounter slots. + /// + private static readonly Dictionary WeatherBleedSymbol = new() + { + { 166, SWSHEncounterType.All_IoA }, // Soothing Wetlands from Forest of Focus + { 170, SWSHEncounterType.All_IoA }, // Challenge Beach from Forest of Focus + { 182, SWSHEncounterType.All_IoA }, // Warm-Up Tunnel from Training Lowlands + { 208, SWSHEncounterType.All_CT }, // Frostpoint Field from Giant's Bed + { 216, SWSHEncounterType.Normal | SWSHEncounterType.Overcast | SWSHEncounterType.Intense_Sun | SWSHEncounterType.Icy | SWSHEncounterType.Heavy_Fog }, // Tunnel to the Top from Path to the Peak + { 224, SWSHEncounterType.All_CT }, // Roaring-Sea Caves from Three-Point Pass + { 230, SWSHEncounterType.All_CT }, // Ballimere Lake from Giant's Bed + { 232, SWSHEncounterType.All_Ballimere }, // Lakeside Cave from Ballimere Lake + }; + + /// + /// Weather types that may bleed into each location from adjacent locations for surfing symbol encounter slots. + /// + private static readonly Dictionary WeatherBleedSymbolSurfing = new() + { + { 192, SWSHEncounterType.All_IoA }, // Honeycalm Sea from Training Lowlands + }; + + /// + /// Weather types that may bleed into each location from adjacent locations for Sharpedo symbol encounter slots. + /// + private static readonly Dictionary WeatherBleedSymbolSharpedo = new() + { + { 192, SWSHEncounterType.All_IoA }, // Honeycalm Sea from Training Lowlands + }; + + /// + /// Weather types that may bleed into each location from adjacent locations, for standard hidden grass encounter slots. + /// + private static readonly Dictionary WeatherBleedHiddenGrass = new() + { + { 166, SWSHEncounterType.All_IoA }, // Soothing Wetlands from Forest of Focus + { 170, SWSHEncounterType.All_IoA }, // Challenge Beach from Forest of Focus + { 208, SWSHEncounterType.All_CT }, // Frostpoint Field from Giant's Bed + { 230, SWSHEncounterType.All_CT }, // Ballimere Lake from Giant's Bed + }; } diff --git a/pkNX.Structures.FlatBuffers/IFlatBufferArchive.cs b/pkNX.Structures.FlatBuffers/IFlatBufferArchive.cs index b29f2e87..ddc9090e 100644 --- a/pkNX.Structures.FlatBuffers/IFlatBufferArchive.cs +++ b/pkNX.Structures.FlatBuffers/IFlatBufferArchive.cs @@ -1,7 +1,6 @@ -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +public interface IFlatBufferArchive where T : class { - public interface IFlatBufferArchive where T : class - { - T[] Table { get; set; } - } -} \ No newline at end of file + T[] Table { get; set; } +} diff --git a/pkNX.Structures.FlatBuffers/Util/FlatDummyEntry.cs b/pkNX.Structures.FlatBuffers/Util/FlatDummyEntry.cs index 8619019f..233a516b 100644 --- a/pkNX.Structures.FlatBuffers/Util/FlatDummyEntry.cs +++ b/pkNX.Structures.FlatBuffers/Util/FlatDummyEntry.cs @@ -3,13 +3,12 @@ using FlatSharp.Attributes; // ReSharper disable ClassNeverInstantiated.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class FlatDummyEntry { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class FlatDummyEntry - { - // Throw on ctor as all arrays of this object type should never have any entries. - public FlatDummyEntry() => throw new ArgumentException("Cannot create an instance of a dummy object."); - public override string ToString() => "UNUSED ARRAY"; - } + // Throw on ctor as all arrays of this object type should never have any entries. + public FlatDummyEntry() => throw new ArgumentException("Cannot create an instance of a dummy object."); + public override string ToString() => "UNUSED ARRAY"; } diff --git a/pkNX.Structures.FlatBuffers/Util/FlatDummyObject.cs b/pkNX.Structures.FlatBuffers/Util/FlatDummyObject.cs index 7f94d659..b4ef276c 100644 --- a/pkNX.Structures.FlatBuffers/Util/FlatDummyObject.cs +++ b/pkNX.Structures.FlatBuffers/Util/FlatDummyObject.cs @@ -5,25 +5,24 @@ // ReSharper disable ClassNeverInstantiated.Global // ReSharper disable once UnusedMember.Global -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +[FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] +public class FlatDummyObject { - [FlatBufferTable, TypeConverter(typeof(ExpandableObjectConverter))] - public class FlatDummyObject + // Throw on first (fake) field set action to ensure the deserialized data has no fields. + [FlatBufferItem(0), Browsable(false), DebuggerBrowsable(DebuggerBrowsableState.Never)] + public byte Field_00 { - // Throw on first (fake) field set action to ensure the deserialized data has no fields. - [FlatBufferItem(0), Browsable(false), DebuggerBrowsable(DebuggerBrowsableState.Never)] - public byte Field_00 + get => 0; + set { - get => 0; - set - { - if (value != 0) - throw new ArgumentException("This should always be an empty object, and not have a valid vTable."); - } + if (value != 0) + throw new ArgumentException("This should always be an empty object, and not have a valid vTable."); } - - public override string ToString() => "UNUSED OBJECT: NO FIELD DATA"; - - public FlatDummyObject Clone() => this; } + + public override string ToString() => "UNUSED OBJECT: NO FIELD DATA"; + + public FlatDummyObject Clone() => this; } diff --git a/pkNX.Structures.FlatBuffers/Util/FlatDumper.cs b/pkNX.Structures.FlatBuffers/Util/FlatDumper.cs index 96dbda43..189afcf3 100644 --- a/pkNX.Structures.FlatBuffers/Util/FlatDumper.cs +++ b/pkNX.Structures.FlatBuffers/Util/FlatDumper.cs @@ -1,28 +1,27 @@ using System.IO; -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +public static class FlatDumper { - public static class FlatDumper + public static string GetTable(string path) where T1 : class, IFlatBufferArchive where T2 : class { - public static string GetTable(string path) where T1 : class, IFlatBufferArchive where T2 : class - { - var data = File.ReadAllBytes(path); - return GetTable(data); - } + var data = File.ReadAllBytes(path); + return GetTable(data); + } - public static string GetTable(byte[] data) where T1 : class, IFlatBufferArchive where T2 : class - { - var obj = FlatBufferConverter.DeserializeFrom(data); - var table = obj.Table; - return TableUtil.GetTable(table); - } + public static string GetTable(byte[] data) where T1 : class, IFlatBufferArchive where T2 : class + { + var obj = FlatBufferConverter.DeserializeFrom(data); + var table = obj.Table; + return TableUtil.GetTable(table); + } - public static string GetSchema() where T : class, new() - { - var t = typeof(T); - var obj = new T(); - var dump = new FlatSchemaDump(obj); - return dump.GetSingleFileSchema(t); - } + public static string GetSchema() where T : class, new() + { + var t = typeof(T); + var obj = new T(); + var dump = new FlatSchemaDump(obj); + return dump.GetSingleFileSchema(t); } } diff --git a/pkNX.Structures.FlatBuffers/Util/FlatSchemaDump.cs b/pkNX.Structures.FlatBuffers/Util/FlatSchemaDump.cs index 1ce91399..bd8f8717 100644 --- a/pkNX.Structures.FlatBuffers/Util/FlatSchemaDump.cs +++ b/pkNX.Structures.FlatBuffers/Util/FlatSchemaDump.cs @@ -3,147 +3,146 @@ using System.Linq; using System.Reflection; -namespace pkNX.Structures.FlatBuffers +namespace pkNX.Structures.FlatBuffers; + +/// +/// Note: does not support creating schemas for fixed size inline struct arrays. +/// +public class FlatSchemaDump { - /// - /// Note: does not support creating schemas for fixed size inline struct arrays. - /// - public class FlatSchemaDump - { - public readonly List GeneratedSchemas = new(); - private readonly List GeneratedClasses = new(); + public readonly List GeneratedSchemas = new(); + private readonly List GeneratedClasses = new(); - public FlatSchemaDump(object obj) => Recurse(obj.GetType()); + public FlatSchemaDump(object obj) => Recurse(obj.GetType()); - public string GetSingleFileSchema(Type type) => -$@"namespace {type.Namespace}; + public string GetSingleFileSchema(Type type) => + $@"namespace {type.Namespace}; {string.Join(Environment.NewLine + Environment.NewLine, GeneratedSchemas)} root_type {GetName(type)};"; - private void Recurse(Type t) - { - var type = GetType(t); - if ((type.IsValueType && !type.IsEnum) || type == typeof(string)) - return; - var name = GetName(type); - if (GeneratedClasses.Contains(name)) - return; + private void Recurse(Type t) + { + var type = GetType(t); + if ((type.IsValueType && !type.IsEnum) || type == typeof(string)) + return; + var name = GetName(type); + if (GeneratedClasses.Contains(name)) + return; - if (type.IsEnum) - AddEnum(type, name); - else if (type.IsGenericType) - AddGeneric(type, name); - else - AddTable(type, name); - } + if (type.IsEnum) + AddEnum(type, name); + else if (type.IsGenericType) + AddGeneric(type, name); + else + AddTable(type, name); + } - private void AddTable(Type type, string name) - { - var props = type.GetTypeInfo().DeclaredProperties.ToArray(); - var lines = props.Select(GetPropLine); + private void AddTable(Type type, string name) + { + var props = type.GetTypeInfo().DeclaredProperties.ToArray(); + var lines = props.Select(GetPropLine); - var schema = -@$"table {name} {{ + var schema = + @$"table {name} {{ {string.Join(Environment.NewLine + " ", lines)} }}"; - GeneratedClasses.Add(name); - GeneratedSchemas.Add(schema); + GeneratedClasses.Add(name); + GeneratedSchemas.Add(schema); - foreach (var p in props) - Recurse(p.PropertyType); - } + foreach (var p in props) + Recurse(p.PropertyType); + } - private void AddGeneric(Type type, string name) - { - // Create a union schema first, then execute the inner types. - var types = type.GenericTypeArguments; - var names = types.Select(z => GetName(GetType(z))); - var schema = $"union {name} {{ {string.Join(", ", names)} }}"; - GeneratedClasses.Add(name); - GeneratedSchemas.Add(schema); + private void AddGeneric(Type type, string name) + { + // Create a union schema first, then execute the inner types. + var types = type.GenericTypeArguments; + var names = types.Select(z => GetName(GetType(z))); + var schema = $"union {name} {{ {string.Join(", ", names)} }}"; + GeneratedClasses.Add(name); + GeneratedSchemas.Add(schema); - foreach (var t in types) - Recurse(t); - } + foreach (var t in types) + Recurse(t); + } - private void AddEnum(Type type, string name) - { - var underlying = type.GetEnumUnderlyingType(); - var underlyingName = Aliases[underlying]; - var kvps = GetEnumMembers(type); - var schema = $@"enum {GetName(type)} : {underlyingName} {{ + private void AddEnum(Type type, string name) + { + var underlying = type.GetEnumUnderlyingType(); + var underlyingName = Aliases[underlying]; + var kvps = GetEnumMembers(type); + var schema = $@"enum {GetName(type)} : {underlyingName} {{ {string.Join(Environment.NewLine + " ", kvps)} }}"; - GeneratedClasses.Add(name); - GeneratedSchemas.Add(schema); - } - - private static IEnumerable GetEnumMembers(Type type) - { - var names = type.GetEnumNames(); - var values = type.GetEnumValues(); // not index-able, for shame. need to iterate - int ctr = 0; - foreach (var v in values) - { - var name = names[ctr++]; - var value = Convert.ChangeType(v, Type.GetTypeCode(type)); - yield return $"{name} = {value},"; - } - } - - private static Type GetType(Type t) - { - if (t.IsArray) - t = t.GetElementType() ?? throw new NullReferenceException("Array type should not be null."); - if (t.Namespace == "Generated") - return t.BaseType ?? throw new NullReferenceException("Base type should not be null."); - return t; - } - - private static string GetName(Type t) - { - var name = t.Name; - if (!name.Contains('`')) - return name; - // generated class names get normalized - if (!t.IsGenericType) - return t.Name; - - var types = t.GenericTypeArguments; - var names = types.Select(z => GetName(GetType(z))); - var typeConcat = string.Concat(names); - return t.Name.Replace("`", "") + typeConcat; - } - - private static string GetPropLine(PropertyInfo p) - { - var name = p.Name; - var type = p.PropertyType; - bool array = type.IsArray; - - var realType = GetType(type); - if (!Aliases.TryGetValue(realType, out var tn)) - tn = GetName(realType); - if (array) - tn = $"[{tn}]"; - return $"{name}:{tn};"; - } - - private static readonly Dictionary Aliases = new() - { - { typeof(byte), "ubyte" }, - { typeof(sbyte), "sbyte" }, - { typeof(short), "short" }, - { typeof(ushort), "ushort" }, - { typeof(int), "int" }, - { typeof(uint), "uint" }, - { typeof(long), "long" }, - { typeof(ulong), "ulong" }, - { typeof(float), "float" }, - { typeof(double), "double" }, - { typeof(bool), "bool" }, - { typeof(string), "string" }, - }; + GeneratedClasses.Add(name); + GeneratedSchemas.Add(schema); } + + private static IEnumerable GetEnumMembers(Type type) + { + var names = type.GetEnumNames(); + var values = type.GetEnumValues(); // not index-able, for shame. need to iterate + int ctr = 0; + foreach (var v in values) + { + var name = names[ctr++]; + var value = Convert.ChangeType(v, Type.GetTypeCode(type)); + yield return $"{name} = {value},"; + } + } + + private static Type GetType(Type t) + { + if (t.IsArray) + t = t.GetElementType() ?? throw new NullReferenceException("Array type should not be null."); + if (t.Namespace == "Generated") + return t.BaseType ?? throw new NullReferenceException("Base type should not be null."); + return t; + } + + private static string GetName(Type t) + { + var name = t.Name; + if (!name.Contains('`')) + return name; + // generated class names get normalized + if (!t.IsGenericType) + return t.Name; + + var types = t.GenericTypeArguments; + var names = types.Select(z => GetName(GetType(z))); + var typeConcat = string.Concat(names); + return t.Name.Replace("`", "") + typeConcat; + } + + private static string GetPropLine(PropertyInfo p) + { + var name = p.Name; + var type = p.PropertyType; + bool array = type.IsArray; + + var realType = GetType(type); + if (!Aliases.TryGetValue(realType, out var tn)) + tn = GetName(realType); + if (array) + tn = $"[{tn}]"; + return $"{name}:{tn};"; + } + + private static readonly Dictionary Aliases = new() + { + { typeof(byte), "ubyte" }, + { typeof(sbyte), "sbyte" }, + { typeof(short), "short" }, + { typeof(ushort), "ushort" }, + { typeof(int), "int" }, + { typeof(uint), "uint" }, + { typeof(long), "long" }, + { typeof(ulong), "ulong" }, + { typeof(float), "float" }, + { typeof(double), "double" }, + { typeof(bool), "bool" }, + { typeof(string), "string" }, + }; } diff --git a/pkNX.Structures.FlatBuffers/pkNX.Structures.FlatBuffers.csproj b/pkNX.Structures.FlatBuffers/pkNX.Structures.FlatBuffers.csproj index 9212767d..d6f652d0 100644 --- a/pkNX.Structures.FlatBuffers/pkNX.Structures.FlatBuffers.csproj +++ b/pkNX.Structures.FlatBuffers/pkNX.Structures.FlatBuffers.csproj @@ -1,7 +1,7 @@ - netstandard2.0;net461 + net6.0 Data Structures - With FlatBuffers! 10 enable @@ -9,8 +9,6 @@ - - diff --git a/pkNX.Structures/ArrayUtil.cs b/pkNX.Structures/ArrayUtil.cs index e364c2ff..6fb212ed 100644 --- a/pkNX.Structures/ArrayUtil.cs +++ b/pkNX.Structures/ArrayUtil.cs @@ -1,243 +1,242 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Array reusable logic +/// +public static class ArrayUtil { + public static bool IsRangeAll(this T[] data, T value, int offset, int length) where T : IEquatable + { + int start = offset + length - 1; + int end = offset; + for (int i = start; i >= end; i--) + { + if (!data[i].Equals(value)) + return false; + } + + return true; + } + + public static byte[] Slice(this byte[] src, int offset, int length) + { + byte[] data = new byte[length]; + Buffer.BlockCopy(src, offset, data, 0, data.Length); + return data; + } + + public static byte[] SliceEnd(this byte[] src, int offset) + { + int length = src.Length - offset; + byte[] data = new byte[length]; + Buffer.BlockCopy(src, offset, data, 0, data.Length); + return data; + } + + public static T[] Slice(this T[] src, int offset, int length) + { + var data = new T[length]; + Array.Copy(src, offset, data, 0, data.Length); + return data; + } + + public static T[] SliceEnd(this T[] src, int offset) + { + int length = src.Length - offset; + var data = new T[length]; + Array.Copy(src, offset, data, 0, data.Length); + return data; + } + + public static bool WithinRange(int value, int min, int max) => min <= value && value < max; + + public static T[][] Split(this T[] data, int size) + { + var result = new T[data.Length / size][]; + for (int i = 0; i < data.Length; i += size) + result[i / size] = data.Slice(i, size); + return result; + } + + public static IEnumerable EnumerateSplit(T[] bin, int size, int start = 0) + { + for (int i = start; i < bin.Length; i += size) + yield return bin.Slice(i, size); + } + + public static IEnumerable EnumerateSplit(T[] bin, int size, int start, int end) + { + if (end < 0) + end = bin.Length; + for (int i = start; i < end; i += size) + yield return bin.Slice(i, size); + } + + public static bool[] GitBitFlagArray(byte[] data, int offset, int count) + { + bool[] result = new bool[count]; + for (int i = 0; i < result.Length; i++) + result[i] = (data[offset + (i >> 3)] >> (i & 7) & 0x1) == 1; + return result; + } + + public static void SetBitFlagArray(byte[] data, int offset, bool[] value) + { + for (int i = 0; i < value.Length; i++) + { + var ofs = offset + (i >> 3); + var mask = (1 << (i & 7)); + if (value[i]) + data[ofs] |= (byte)mask; + else + data[ofs] &= (byte)~mask; + } + } + + public static byte[] SetBitFlagArray(bool[] value) + { + byte[] data = new byte[value.Length / 8]; + SetBitFlagArray(data, 0, value); + return data; + } + /// - /// Array reusable logic + /// Copies a list to the destination list, with an option to copy to a starting point. /// - public static class ArrayUtil + /// Source list to copy from + /// Destination list/array + /// Criteria for skipping a slot + /// Starting point to copy to + /// Count of copied. + public static int CopyTo(this IEnumerable list, IList dest, Func skip, int start = 0) { - public static bool IsRangeAll(this T[] data, T value, int offset, int length) where T : IEquatable + int ctr = start; + int skipped = 0; + foreach (var z in list) { - int start = offset + length - 1; - int end = offset; - for (int i = start; i >= end; i--) - { - if (!data[i].Equals(value)) - return false; - } - - return true; + // seek forward to next open slot + int next = FindNextValidIndex(dest, skip, ctr); + if (next == -1) + break; + skipped += next - ctr; + ctr = next; + dest[ctr++] = z; } + return ctr - start - skipped; + } - public static byte[] Slice(this byte[] src, int offset, int length) + public static int FindNextValidIndex(IList dest, Func skip, int ctr) + { + while (true) { - byte[] data = new byte[length]; - Buffer.BlockCopy(src, offset, data, 0, data.Length); - return data; - } - - public static byte[] SliceEnd(this byte[] src, int offset) - { - int length = src.Length - offset; - byte[] data = new byte[length]; - Buffer.BlockCopy(src, offset, data, 0, data.Length); - return data; - } - - public static T[] Slice(this T[] src, int offset, int length) - { - var data = new T[length]; - Array.Copy(src, offset, data, 0, data.Length); - return data; - } - - public static T[] SliceEnd(this T[] src, int offset) - { - int length = src.Length - offset; - var data = new T[length]; - Array.Copy(src, offset, data, 0, data.Length); - return data; - } - - public static bool WithinRange(int value, int min, int max) => min <= value && value < max; - - public static T[][] Split(this T[] data, int size) - { - var result = new T[data.Length / size][]; - for (int i = 0; i < data.Length; i += size) - result[i / size] = data.Slice(i, size); - return result; - } - - public static IEnumerable EnumerateSplit(T[] bin, int size, int start = 0) - { - for (int i = start; i < bin.Length; i += size) - yield return bin.Slice(i, size); - } - - public static IEnumerable EnumerateSplit(T[] bin, int size, int start, int end) - { - if (end < 0) - end = bin.Length; - for (int i = start; i < end; i += size) - yield return bin.Slice(i, size); - } - - public static bool[] GitBitFlagArray(byte[] data, int offset, int count) - { - bool[] result = new bool[count]; - for (int i = 0; i < result.Length; i++) - result[i] = (data[offset + (i >> 3)] >> (i & 7) & 0x1) == 1; - return result; - } - - public static void SetBitFlagArray(byte[] data, int offset, bool[] value) - { - for (int i = 0; i < value.Length; i++) - { - var ofs = offset + (i >> 3); - var mask = (1 << (i & 7)); - if (value[i]) - data[ofs] |= (byte)mask; - else - data[ofs] &= (byte)~mask; - } - } - - public static byte[] SetBitFlagArray(bool[] value) - { - byte[] data = new byte[value.Length / 8]; - SetBitFlagArray(data, 0, value); - return data; - } - - /// - /// Copies a list to the destination list, with an option to copy to a starting point. - /// - /// Source list to copy from - /// Destination list/array - /// Criteria for skipping a slot - /// Starting point to copy to - /// Count of copied. - public static int CopyTo(this IEnumerable list, IList dest, Func skip, int start = 0) - { - int ctr = start; - int skipped = 0; - foreach (var z in list) - { - // seek forward to next open slot - int next = FindNextValidIndex(dest, skip, ctr); - if (next == -1) - break; - skipped += next - ctr; - ctr = next; - dest[ctr++] = z; - } - return ctr - start - skipped; - } - - public static int FindNextValidIndex(IList dest, Func skip, int ctr) - { - while (true) - { - if ((uint)ctr >= dest.Count) - return -1; - var exist = dest[ctr]; - if (exist == null || !skip(exist)) - return ctr; - ctr++; - } - } - - /// - /// Copies an list to the destination list, with an option to copy to a starting point. - /// - /// Typed object to copy - /// Source list to copy from - /// Destination list/array - /// Starting point to copy to - /// Count of copied. - public static int CopyTo(this IEnumerable list, IList dest, int start = 0) - { - int ctr = start; - foreach (var z in list) - { - if ((uint)ctr >= dest.Count) - break; - dest[ctr++] = z; - } - return ctr - start; - } - - internal static T[] ConcatAll(params T[][] arr) - { - int len = 0; - foreach (var a in arr) - len += a.Length; - - var result = new T[len]; - - int ctr = 0; - foreach (var a in arr) - { - a.CopyTo(result, ctr); - ctr += a.Length; - } - - return result; - } - - internal static T[] ConcatAll(T[] arr1, T[] arr2) - { - int len = arr1.Length + arr2.Length; - var result = new T[len]; - arr1.CopyTo(result, 0); - arr2.CopyTo(result, arr1.Length); - return result; - } - - internal static T[] ConcatAll(T[] arr1, T[] arr2, T[] arr3) - { - int len = arr1.Length + arr2.Length + arr3.Length; - var result = new T[len]; - arr1.CopyTo(result, 0); - arr2.CopyTo(result, arr1.Length); - arr3.CopyTo(result, arr1.Length + arr2.Length); - return result; - } - - internal static T[] ConcatAll(T[] arr1, T[] arr2, ReadOnlySpan arr3) - { - int len = arr1.Length + arr2.Length + arr3.Length; - var result = new T[len]; - arr1.CopyTo(result, 0); - arr2.CopyTo(result, arr1.Length); - arr3.CopyTo(result.AsSpan(arr1.Length + arr2.Length)); - return result; + if ((uint)ctr >= dest.Count) + return -1; + var exist = dest[ctr]; + if (exist == null || !skip(exist)) + return ctr; + ctr++; } } - public static class ArrayUtilsExt + /// + /// Copies an list to the destination list, with an option to copy to a starting point. + /// + /// Typed object to copy + /// Source list to copy from + /// Destination list/array + /// Starting point to copy to + /// Count of copied. + public static int CopyTo(this IEnumerable list, IList dest, int start = 0) { - public static TSource[] Append(this TSource[] first, TSource second, params TSource[] third) + int ctr = start; + foreach (var z in list) { - return ArrayUtil.ConcatAll(first, new[] { second }, third); - } - - public static TSource[] Remove(this TSource[] first, TSource toRemove) - { - var list = first.ToList(); - list.Remove(toRemove); - return list.ToArray(); + if ((uint)ctr >= dest.Count) + break; + dest[ctr++] = z; } + return ctr - start; } - public static class FlagUtil + internal static T[] ConcatAll(params T[][] arr) { - public static bool GetFlag(byte[] arr, int offset, int bitIndex) + int len = 0; + foreach (var a in arr) + len += a.Length; + + var result = new T[len]; + + int ctr = 0; + foreach (var a in arr) { - bitIndex &= 7; // ensure bit access is 0-7 - return (arr[offset] >> bitIndex & 1) != 0; + a.CopyTo(result, ctr); + ctr += a.Length; } - public static void SetFlag(byte[] arr, int offset, int bitIndex, bool value) - { - bitIndex &= 7; // ensure bit access is 0-7 - arr[offset] &= (byte)~(1 << bitIndex); - arr[offset] |= (byte)((value ? 1 : 0) << bitIndex); - } + return result; } -} \ No newline at end of file + + internal static T[] ConcatAll(T[] arr1, T[] arr2) + { + int len = arr1.Length + arr2.Length; + var result = new T[len]; + arr1.CopyTo(result, 0); + arr2.CopyTo(result, arr1.Length); + return result; + } + + internal static T[] ConcatAll(T[] arr1, T[] arr2, T[] arr3) + { + int len = arr1.Length + arr2.Length + arr3.Length; + var result = new T[len]; + arr1.CopyTo(result, 0); + arr2.CopyTo(result, arr1.Length); + arr3.CopyTo(result, arr1.Length + arr2.Length); + return result; + } + + internal static T[] ConcatAll(T[] arr1, T[] arr2, ReadOnlySpan arr3) + { + int len = arr1.Length + arr2.Length + arr3.Length; + var result = new T[len]; + arr1.CopyTo(result, 0); + arr2.CopyTo(result, arr1.Length); + arr3.CopyTo(result.AsSpan(arr1.Length + arr2.Length)); + return result; + } +} + +public static class ArrayUtilsExt +{ + public static TSource[] Append(this TSource[] first, TSource second, params TSource[] third) + { + return ArrayUtil.ConcatAll(first, new[] { second }, third); + } + + public static TSource[] Remove(this TSource[] first, TSource toRemove) + { + var list = first.ToList(); + list.Remove(toRemove); + return list.ToArray(); + } +} + +public static class FlagUtil +{ + public static bool GetFlag(byte[] arr, int offset, int bitIndex) + { + bitIndex &= 7; // ensure bit access is 0-7 + return (arr[offset] >> bitIndex & 1) != 0; + } + + public static void SetFlag(byte[] arr, int offset, int bitIndex, bool value) + { + bitIndex &= 7; // ensure bit access is 0-7 + arr[offset] &= (byte)~(1 << bitIndex); + arr[offset] |= (byte)((value ? 1 : 0) << bitIndex); + } +} diff --git a/pkNX.Structures/CodePattern.cs b/pkNX.Structures/CodePattern.cs index f05cf7ff..da94259a 100644 --- a/pkNX.Structures/CodePattern.cs +++ b/pkNX.Structures/CodePattern.cs @@ -1,89 +1,88 @@ -using System; +using System; using System.Diagnostics; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static class CodePattern { - public static class CodePattern + /// + /// Finds a provided within the supplied . + /// + /// Array to look in + /// Pattern to look for + /// Starting offset to look from + /// Amount of entries to look through + /// Index the pattern occurs at; if not found, returns -1. + public static int IndexOfBytes(byte[] array, byte[] pattern, int startIndex = 0, int length = -1) { - /// - /// Finds a provided within the supplied . - /// - /// Array to look in - /// Pattern to look for - /// Starting offset to look from - /// Amount of entries to look through - /// Index the pattern occurs at; if not found, returns -1. - public static int IndexOfBytes(byte[] array, byte[] pattern, int startIndex = 0, int length = -1) + int len = pattern.Length; + int endIndex = length > 0 + ? startIndex + length + : array.Length - len - startIndex; + + endIndex = Math.Min(array.Length - pattern.Length, endIndex); + + int i = startIndex; + int j = 0; + while (true) { - int len = pattern.Length; - int endIndex = length > 0 - ? startIndex + length - : array.Length - len - startIndex; - - endIndex = Math.Min(array.Length - pattern.Length, endIndex); - - int i = startIndex; - int j = 0; - while (true) + if (pattern[j] != array[i + j]) { - if (pattern[j] != array[i + j]) - { - if (++i == endIndex) - return -1; - j = 0; - } - else if (++j == len) - { - return i; - } + if (++i == endIndex) + return -1; + j = 0; + } + else if (++j == len) + { + return i; } } - - /// - /// Finds a provided within the supplied . - /// - /// Array to look in - /// Pattern to look for - /// Wildcard byte to be ignored, incrementally as bitflags. - /// Starting offset to look from - /// Amount of entries to look through - /// Index the pattern occurs at; if not found, returns -1. - public static int IndexOfPattern(byte[] array, byte[] pattern, ulong wildCard, int startIndex = 0, int length = -1) - { - Debug.Assert(pattern.Length <= 8*sizeof(ulong)); - - int len = pattern.Length; - int endIndex = length > 0 - ? startIndex + length - : array.Length - len - startIndex; - - endIndex = Math.Min(array.Length - pattern.Length, endIndex); - - int i = startIndex; - int j = 0; - while (true) - { - if (pattern[j] != array[i + j] && ((wildCard >> j) & 1) == 0) - { - if (++i == endIndex) - return -1; - j = 0; - } - else if (++j == len) - { - return i; - } - } - } - - /// - /// byte pattern which precedes the TMHM list. This list is the tail end of item IDs for each TM(01->100). - /// - public static readonly byte[] TMHM_GG = - { - 0xA0, 0x01, 0xA1, 0x01, 0xA2, 0x01, 0xA3, 0x01, - 0x6A, 0x02, 0x6B, 0x02, 0x6C, 0x02, 0xB2, 0x02, - 0xB3, 0x02, 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, - }; } + + /// + /// Finds a provided within the supplied . + /// + /// Array to look in + /// Pattern to look for + /// Wildcard byte to be ignored, incrementally as bitflags. + /// Starting offset to look from + /// Amount of entries to look through + /// Index the pattern occurs at; if not found, returns -1. + public static int IndexOfPattern(byte[] array, byte[] pattern, ulong wildCard, int startIndex = 0, int length = -1) + { + Debug.Assert(pattern.Length <= 8*sizeof(ulong)); + + int len = pattern.Length; + int endIndex = length > 0 + ? startIndex + length + : array.Length - len - startIndex; + + endIndex = Math.Min(array.Length - pattern.Length, endIndex); + + int i = startIndex; + int j = 0; + while (true) + { + if (pattern[j] != array[i + j] && ((wildCard >> j) & 1) == 0) + { + if (++i == endIndex) + return -1; + j = 0; + } + else if (++j == len) + { + return i; + } + } + } + + /// + /// byte pattern which precedes the TMHM list. This list is the tail end of item IDs for each TM(01->100). + /// + public static readonly byte[] TMHM_GG = + { + 0xA0, 0x01, 0xA1, 0x01, 0xA2, 0x01, 0xA3, 0x01, + 0x6A, 0x02, 0x6B, 0x02, 0x6C, 0x02, 0xB2, 0x02, + 0xB3, 0x02, 0xB4, 0x02, 0xB5, 0x02, 0xB6, 0x02, + }; } diff --git a/pkNX.Structures/Converters/DropTableConverter.cs b/pkNX.Structures/Converters/DropTableConverter.cs index c3e1fa40..9bbec5d4 100644 --- a/pkNX.Structures/Converters/DropTableConverter.cs +++ b/pkNX.Structures/Converters/DropTableConverter.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; +using System; using System.ComponentModel; -using System.Globalization; -using System.Linq; -using System.Text; namespace pkNX.Structures; @@ -17,4 +13,4 @@ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContex { return new StandardValuesCollection(DropTableHashes); } -} \ No newline at end of file +} diff --git a/pkNX.Structures/Converters/ItemConverter.cs b/pkNX.Structures/Converters/ItemConverter.cs index a482dd51..62ce8f96 100644 --- a/pkNX.Structures/Converters/ItemConverter.cs +++ b/pkNX.Structures/Converters/ItemConverter.cs @@ -1,9 +1,6 @@ -using System; -using System.Collections.Generic; +using System; using System.ComponentModel; using System.Globalization; -using System.Linq; -using System.Text; namespace pkNX.Structures; @@ -40,4 +37,4 @@ public override StandardValuesCollection GetStandardValues(ITypeDescriptorContex { return new StandardValuesCollection(ItemNames); } -} \ No newline at end of file +} diff --git a/pkNX.Structures/Dumpers/PersonalDumper.cs b/pkNX.Structures/Dumpers/PersonalDumper.cs index fc402739..968276e5 100644 --- a/pkNX.Structures/Dumpers/PersonalDumper.cs +++ b/pkNX.Structures/Dumpers/PersonalDumper.cs @@ -1,281 +1,279 @@ -using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class PersonalDumperSWSH : PersonalDumper { - public class PersonalDumperSWSH : PersonalDumper + protected override void AddTMs(List lines, IMovesInfo_1 pi, string specCode) { - protected override void AddTMs(List lines, IMovesInfo_1 pi, string specCode) - { - base.AddTMs(lines, pi, specCode); - AddTRs(lines, pi, specCode); - } - - private void AddTRs(List lines, IMovesInfo_1 pi, string specCode) - { - if (!(TMIndexes?.Count > 0)) - return; - var tmhm = pi.TMHM; - int count = 0; - lines.Add("TRs:"); - for (int i = 0; i < 100; i++) - { - if (!tmhm[100 + i]) - continue; - var move = TMIndexes[100 + i]; - lines.Add($"- [TR{i:00}] {Moves[move]}"); - count++; - - MoveSpeciesLearn[move].Add(specCode); - } - if (count == 0) - lines.Add("None!"); - } + base.AddTMs(lines, pi, specCode); + AddTRs(lines, pi, specCode); } - public class PersonalDumperSettings + private void AddTRs(List lines, IMovesInfo_1 pi, string specCode) { - public bool Stats { get; set; } = true; - public bool Learn { get; set; } = true; - public bool Egg { get; set; } = true; - public bool TMHM { get; set; } = true; - public bool Tutor { get; set; } = true; - public bool Evo { get; set; } = true; - public bool Dex { get; set; } // Skipped to reduce dumped file size - } - - public class PersonalDumper - { - public bool HasAbilities { get; set; } = true; - public bool HasItems { get; set; } = true; - - public IReadOnlyList Abilities { private get; set; } - public IReadOnlyList Types { private get; set; } - public IReadOnlyList Items { private get; set; } - public IReadOnlyList Colors { private get; set; } - public IReadOnlyList EggGroups { private get; set; } - public IReadOnlyList ExpGroups { private get; set; } - public IReadOnlyList EntryNames { private get; set; } - public IReadOnlyList Moves { protected get; set; } - public IReadOnlyList Species { private get; set; } - public IReadOnlyList ZukanA { private get; set; } - public IReadOnlyList ZukanB { private get; set; } - - public IReadOnlyList EntryLearnsets { private get; set; } - public IReadOnlyList EntryEggMoves { private get; set; } - public IReadOnlyList Evos { private get; set; } - public IReadOnlyList TMIndexes { protected get; set; } - - private static readonly string[] AbilitySuffix = { " (1)", " (2)", " (H)" }; - private static readonly string[] ItemPrefix = { "Item 1 (50%)", "Item 2 (5%)", "Item 3 (1%)" }; - - public IReadOnlyList> MoveSpeciesLearn { get; private set; } - - public PersonalDumperSettings Settings = new(); - - public List Dump(IPersonalTable table) + if (!(TMIndexes?.Count > 0)) + return; + var tmhm = pi.TMHM; + int count = 0; + lines.Add("TRs:"); + for (int i = 0; i < 100; i++) { - var lines = new List(); - var ml = new List[Moves.Count]; - for (int i = 0; i < ml.Length; i++) - ml[i] = new List(); - MoveSpeciesLearn = ml; + if (!tmhm[100 + i]) + continue; + var move = TMIndexes[100 + i]; + lines.Add($"- [TR{i:00}] {Moves[move]}"); + count++; - for (ushort species = 0; species <= table.MaxSpeciesID; species++) - { - var spec = table[species]; - for (byte form = 0; form < spec.FormCount; form++) - AddDump(lines, table, species, form); - } - return lines; - } - - public void AddDump(List lines, IPersonalTable table, ushort species, byte form) - { - var index = table.GetFormIndex(species, form); - var entry = table[index]; - string name = EntryNames[index]; - AddDump(lines, entry, index, name, species, form); - lines.Add(""); - } - - private void AddDump(List lines, IPersonalInfo pi, int entry, string name, int species, int form) - { - if (pi is IPersonalInfoSWSH { IsPresentInGame: false }) - return; - - var specCode = pi.FormCount > 1 ? $"{Species[species]}-{form}" : $"{Species[species]}"; - - if (Settings.Stats) - AddPersonalLines(lines, pi, entry, name, specCode); - if (Settings.Learn) - AddLearnsets(lines, entry, specCode); - if (Settings.Egg) - AddEggMoves(lines, species, form, specCode); - if (Settings.TMHM && pi is IMovesInfo_1 mi) - AddTMs(lines, mi, specCode); - if (Settings.Tutor && pi is IMovesInfo_2 mi2) - AddArmorTutors(lines, mi2, specCode); - if (Settings.Evo) - AddEvolutions(lines, entry); - if (Settings.Dex) - AddZukan(lines, entry); - } - - private void AddZukan(List lines, int entry) - { - if (entry >= Species.Count) - return; - lines.Add(ZukanA[entry].Replace("\\n", " ")); - lines.Add(ZukanB[entry].Replace("\\n", " ")); - } - - protected virtual void AddTMs(List lines, IMovesInfo_1 pi, string SpecCode) - { - var tmhm = pi.TMHM; - int count = 0; - lines.Add("TMs:"); - for (int i = 0; i < 100; i++) - { - if (!tmhm[i]) - continue; - var move = TMIndexes[i]; - lines.Add($"- [TM{i:00}] {Moves[move]}"); - count++; - - MoveSpeciesLearn[move].Add(SpecCode); - } - if (count == 0) - lines.Add("None!"); - } - - protected virtual void AddArmorTutors(List lines, IMovesInfo_2 pi, string SpecCode) - { - var armor = pi.SpecialTutors[0]; - int count = 0; - lines.Add("Armor Tutors:"); - for (int i = 0; i < armor.Length; i++) - { - if (!armor[i]) - continue; - var move = Legal.Tutors_SWSH_1[i]; - lines.Add($"- {Moves[move]}"); - count++; - - MoveSpeciesLearn[move].Add(SpecCode); - } - if (count == 0) - lines.Add("None!"); - } - - private void AddLearnsets(List lines, int entry, string specCode) - { - if (!(EntryLearnsets?.Count > 0)) - return; - var learn = EntryLearnsets[entry]; - if (learn.Moves.Length == 0) - return; - - lines.Add("Level Up Moves:"); - for (int i = 0; i < learn.Moves.Length; i++) - { - var move = learn.Moves[i]; - var level = learn.Levels[i]; - lines.Add($"- [{level:00}] {Moves[move]}"); - MoveSpeciesLearn[move].Add(specCode); - } - } - - private void AddEggMoves(List lines, int species, int form, string specCode) - { - if (!(EntryEggMoves?.Count > 0)) - return; - var egg = EntryEggMoves[species]; - if (egg is EggMoves7 e7 && form > 0) - egg = EntryEggMoves[e7.FormTableIndex + form - 1]; - if (egg.Moves.Length == 0) - return; - - lines.Add("Egg Moves:"); - foreach (var move in egg.Moves) - { - lines.Add($"- {Moves[move]}"); - MoveSpeciesLearn[move].Add(specCode); - } - } - - private void AddEvolutions(List lines, int entry) - { - if (!(Evos?.Count > 0)) - return; - var evo = Evos[entry]; - var evo2 = evo.PossibleEvolutions.Where(z => z.Species != 0).ToArray(); - if (evo2.Length == 0) - return; - - var msg = evo2.Select(z => $"Evolves into {Species[z.Species]}-{z.Form} @ {z.Level} ({z.Method}) [{z.Argument}]"); - lines.AddRange(msg); - } - - private void AddPersonalLines(List lines, IPersonalInfo pi, int entry, string name, string specCode) - { - Debug.WriteLine($"Dumping {specCode}"); - lines.Add("======"); - lines.Add($"{entry:000} - {name} (Stage: {pi.EvoStage})"); - lines.Add("======"); - if (pi is IPersonalInfoSWSH s) - { - if (s.DexIndexRegional != 0) - lines.Add($"Galar Dex: #{s.DexIndexRegional:000}"); - if (s.ArmorDexIndex != 0) - lines.Add($"Armor Dex: #{s.ArmorDexIndex:000}"); - if (s.CrownDexIndex != 0) - lines.Add($"Crown Dex: #{s.CrownDexIndex:000}"); - if (s.DexIndexRegional == 0 && s.ArmorDexIndex == 0 && s.CrownDexIndex == 0) - lines.Add("Galar Dex: Foreign"); - - if (s.CanNotDynamax) - lines.Add("Can Not Dynamax!"); - } - lines.Add($"Base Stats: {pi.HP}.{pi.ATK}.{pi.DEF}.{pi.SPA}.{pi.SPD}.{pi.SPE} (BST: {pi.GetBaseStatTotal()})"); - lines.Add($"EV Yield: {pi.EV_HP}.{pi.EV_ATK}.{pi.EV_DEF}.{pi.EV_SPA}.{pi.EV_SPD}.{pi.EV_SPE}"); - lines.Add($"Gender Ratio: {pi.Gender}"); - lines.Add($"Catch Rate: {pi.CatchRate}"); - - if (HasAbilities) - { - string msg = string.Empty; - for (int j = 0; j < pi.GetNumAbilities(); ++j) - msg += Abilities[pi.GetAbilityAtIndex(j)] + AbilitySuffix[j] + " | "; - - lines.Add($"Abilities: {msg}"); - } - - lines.Add(string.Format(pi.Type1 != pi.Type2 - ? "Type: {0} / {1}" - : "Type: {0}", Types[(int)pi.Type1], Types[(int)pi.Type2])); - - if (HasItems) - { - int[] items = new int[pi.GetNumItems()]; - pi.GetItems(items); - if (items.Distinct().Count() == 1) - lines.Add($"Items: {Items[pi.Item1]}"); - else - lines.AddRange(items.Select((z, j) => $"{ItemPrefix[j]}: {Items[z]}")); - } - - lines.Add($"EXP Group: {ExpGroups[pi.EXPGrowth]}"); - lines.Add(string.Format(pi.EggGroup1 != pi.EggGroup2 - ? "Egg Group: {0} / {1}" - : "Egg Group: {0}", EggGroups[pi.EggGroup1], EggGroups[pi.EggGroup2])); - - if (pi is IPersonalEgg_1 eggInfo) - lines.Add($"Hatch Cycles: {eggInfo.HatchCycles}"); - - lines.Add($"Height: {(decimal)pi.Height / 100:00.00}m, Weight: {(decimal)pi.Weight / 10:000.0}kg, Color: {Colors[pi.Color]}"); + MoveSpeciesLearn[move].Add(specCode); } + if (count == 0) + lines.Add("None!"); + } +} + +public class PersonalDumperSettings +{ + public bool Stats { get; set; } = true; + public bool Learn { get; set; } = true; + public bool Egg { get; set; } = true; + public bool TMHM { get; set; } = true; + public bool Tutor { get; set; } = true; + public bool Evo { get; set; } = true; + public bool Dex { get; set; } // Skipped to reduce dumped file size +} + +public class PersonalDumper +{ + public bool HasAbilities { get; set; } = true; + public bool HasItems { get; set; } = true; + + public IReadOnlyList Abilities { private get; set; } + public IReadOnlyList Types { private get; set; } + public IReadOnlyList Items { private get; set; } + public IReadOnlyList Colors { private get; set; } + public IReadOnlyList EggGroups { private get; set; } + public IReadOnlyList ExpGroups { private get; set; } + public IReadOnlyList EntryNames { private get; set; } + public IReadOnlyList Moves { protected get; set; } + public IReadOnlyList Species { private get; set; } + public IReadOnlyList ZukanA { private get; set; } + public IReadOnlyList ZukanB { private get; set; } + + public IReadOnlyList EntryLearnsets { private get; set; } + public IReadOnlyList EntryEggMoves { private get; set; } + public IReadOnlyList Evos { private get; set; } + public IReadOnlyList TMIndexes { protected get; set; } + + private static readonly string[] AbilitySuffix = { " (1)", " (2)", " (H)" }; + private static readonly string[] ItemPrefix = { "Item 1 (50%)", "Item 2 (5%)", "Item 3 (1%)" }; + + public IReadOnlyList> MoveSpeciesLearn { get; private set; } + + public PersonalDumperSettings Settings = new(); + + public List Dump(IPersonalTable table) + { + var lines = new List(); + var ml = new List[Moves.Count]; + for (int i = 0; i < ml.Length; i++) + ml[i] = new List(); + MoveSpeciesLearn = ml; + + for (ushort species = 0; species <= table.MaxSpeciesID; species++) + { + var spec = table[species]; + for (byte form = 0; form < spec.FormCount; form++) + AddDump(lines, table, species, form); + } + return lines; + } + + public void AddDump(List lines, IPersonalTable table, ushort species, byte form) + { + var index = table.GetFormIndex(species, form); + var entry = table[index]; + string name = EntryNames[index]; + AddDump(lines, entry, index, name, species, form); + lines.Add(""); + } + + private void AddDump(List lines, IPersonalInfo pi, int entry, string name, int species, int form) + { + if (pi is IPersonalInfoSWSH { IsPresentInGame: false }) + return; + + var specCode = pi.FormCount > 1 ? $"{Species[species]}-{form}" : $"{Species[species]}"; + + if (Settings.Stats) + AddPersonalLines(lines, pi, entry, name, specCode); + if (Settings.Learn) + AddLearnsets(lines, entry, specCode); + if (Settings.Egg) + AddEggMoves(lines, species, form, specCode); + if (Settings.TMHM && pi is IMovesInfo_1 mi) + AddTMs(lines, mi, specCode); + if (Settings.Tutor && pi is IMovesInfo_2 mi2) + AddArmorTutors(lines, mi2, specCode); + if (Settings.Evo) + AddEvolutions(lines, entry); + if (Settings.Dex) + AddZukan(lines, entry); + } + + private void AddZukan(List lines, int entry) + { + if (entry >= Species.Count) + return; + lines.Add(ZukanA[entry].Replace("\\n", " ")); + lines.Add(ZukanB[entry].Replace("\\n", " ")); + } + + protected virtual void AddTMs(List lines, IMovesInfo_1 pi, string SpecCode) + { + var tmhm = pi.TMHM; + int count = 0; + lines.Add("TMs:"); + for (int i = 0; i < 100; i++) + { + if (!tmhm[i]) + continue; + var move = TMIndexes[i]; + lines.Add($"- [TM{i:00}] {Moves[move]}"); + count++; + + MoveSpeciesLearn[move].Add(SpecCode); + } + if (count == 0) + lines.Add("None!"); + } + + protected virtual void AddArmorTutors(List lines, IMovesInfo_2 pi, string SpecCode) + { + var armor = pi.SpecialTutors[0]; + int count = 0; + lines.Add("Armor Tutors:"); + for (int i = 0; i < armor.Length; i++) + { + if (!armor[i]) + continue; + var move = Legal.Tutors_SWSH_1[i]; + lines.Add($"- {Moves[move]}"); + count++; + + MoveSpeciesLearn[move].Add(SpecCode); + } + if (count == 0) + lines.Add("None!"); + } + + private void AddLearnsets(List lines, int entry, string specCode) + { + if (!(EntryLearnsets?.Count > 0)) + return; + var learn = EntryLearnsets[entry]; + if (learn.Moves.Length == 0) + return; + + lines.Add("Level Up Moves:"); + for (int i = 0; i < learn.Moves.Length; i++) + { + var move = learn.Moves[i]; + var level = learn.Levels[i]; + lines.Add($"- [{level:00}] {Moves[move]}"); + MoveSpeciesLearn[move].Add(specCode); + } + } + + private void AddEggMoves(List lines, int species, int form, string specCode) + { + if (!(EntryEggMoves?.Count > 0)) + return; + var egg = EntryEggMoves[species]; + if (egg is EggMoves7 e7 && form > 0) + egg = EntryEggMoves[e7.FormTableIndex + form - 1]; + if (egg.Moves.Length == 0) + return; + + lines.Add("Egg Moves:"); + foreach (var move in egg.Moves) + { + lines.Add($"- {Moves[move]}"); + MoveSpeciesLearn[move].Add(specCode); + } + } + + private void AddEvolutions(List lines, int entry) + { + if (!(Evos?.Count > 0)) + return; + var evo = Evos[entry]; + var evo2 = evo.PossibleEvolutions.Where(z => z.Species != 0).ToArray(); + if (evo2.Length == 0) + return; + + var msg = evo2.Select(z => $"Evolves into {Species[z.Species]}-{z.Form} @ {z.Level} ({z.Method}) [{z.Argument}]"); + lines.AddRange(msg); + } + + private void AddPersonalLines(List lines, IPersonalInfo pi, int entry, string name, string specCode) + { + Debug.WriteLine($"Dumping {specCode}"); + lines.Add("======"); + lines.Add($"{entry:000} - {name} (Stage: {pi.EvoStage})"); + lines.Add("======"); + if (pi is IPersonalInfoSWSH s) + { + if (s.DexIndexRegional != 0) + lines.Add($"Galar Dex: #{s.DexIndexRegional:000}"); + if (s.ArmorDexIndex != 0) + lines.Add($"Armor Dex: #{s.ArmorDexIndex:000}"); + if (s.CrownDexIndex != 0) + lines.Add($"Crown Dex: #{s.CrownDexIndex:000}"); + if (s.DexIndexRegional == 0 && s.ArmorDexIndex == 0 && s.CrownDexIndex == 0) + lines.Add("Galar Dex: Foreign"); + + if (s.CanNotDynamax) + lines.Add("Can Not Dynamax!"); + } + lines.Add($"Base Stats: {pi.HP}.{pi.ATK}.{pi.DEF}.{pi.SPA}.{pi.SPD}.{pi.SPE} (BST: {pi.GetBaseStatTotal()})"); + lines.Add($"EV Yield: {pi.EV_HP}.{pi.EV_ATK}.{pi.EV_DEF}.{pi.EV_SPA}.{pi.EV_SPD}.{pi.EV_SPE}"); + lines.Add($"Gender Ratio: {pi.Gender}"); + lines.Add($"Catch Rate: {pi.CatchRate}"); + + if (HasAbilities) + { + string msg = string.Empty; + for (int j = 0; j < pi.GetNumAbilities(); ++j) + msg += Abilities[pi.GetAbilityAtIndex(j)] + AbilitySuffix[j] + " | "; + + lines.Add($"Abilities: {msg}"); + } + + lines.Add(string.Format(pi.Type1 != pi.Type2 + ? "Type: {0} / {1}" + : "Type: {0}", Types[(int)pi.Type1], Types[(int)pi.Type2])); + + if (HasItems) + { + int[] items = new int[pi.GetNumItems()]; + pi.GetItems(items); + if (items.Distinct().Count() == 1) + lines.Add($"Items: {Items[pi.Item1]}"); + else + lines.AddRange(items.Select((z, j) => $"{ItemPrefix[j]}: {Items[z]}")); + } + + lines.Add($"EXP Group: {ExpGroups[pi.EXPGrowth]}"); + lines.Add(string.Format(pi.EggGroup1 != pi.EggGroup2 + ? "Egg Group: {0} / {1}" + : "Egg Group: {0}", EggGroups[pi.EggGroup1], EggGroups[pi.EggGroup2])); + + if (pi is IPersonalEgg_1 eggInfo) + lines.Add($"Hatch Cycles: {eggInfo.HatchCycles}"); + + lines.Add($"Height: {(decimal)pi.Height / 100:00.00}m, Weight: {(decimal)pi.Weight / 10:000.0}kg, Color: {Colors[pi.Color]}"); } } diff --git a/pkNX.Structures/EggMove/EggMoves.cs b/pkNX.Structures/EggMove/EggMoves.cs index 00829a79..0fa494cc 100644 --- a/pkNX.Structures/EggMove/EggMoves.cs +++ b/pkNX.Structures/EggMove/EggMoves.cs @@ -1,11 +1,10 @@ -using System.Linq; +using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class EggMoves { - public abstract class EggMoves - { - public readonly int[] Moves; - protected EggMoves(int[] moves) => Moves = moves; - public bool GetHasEggMove(int move) => Moves.Contains(move); - } -} \ No newline at end of file + public readonly int[] Moves; + protected EggMoves(int[] moves) => Moves = moves; + public bool GetHasEggMove(int move) => Moves.Contains(move); +} diff --git a/pkNX.Structures/EggMove/EggMoves2.cs b/pkNX.Structures/EggMove/EggMoves2.cs index ac131881..0fec474b 100644 --- a/pkNX.Structures/EggMove/EggMoves2.cs +++ b/pkNX.Structures/EggMove/EggMoves2.cs @@ -1,28 +1,27 @@ -using System; +using System; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class EggMoves2 : EggMoves { - public sealed class EggMoves2 : EggMoves + private EggMoves2(byte[] data) : base(data.Select(i => (int)i).ToArray()) { } + + public static EggMoves[] GetArray(byte[] data, int count) { - private EggMoves2(byte[] data) : base(data.Select(i => (int)i).ToArray()) { } - - public static EggMoves[] GetArray(byte[] data, int count) + int[] ptrs = new int[count + 1]; + int baseOffset = (data[1] << 8 | data[0]) - (count * 2); + for (int i = 1; i < ptrs.Length; i++) { - int[] ptrs = new int[count + 1]; - int baseOffset = (data[1] << 8 | data[0]) - (count * 2); - for (int i = 1; i < ptrs.Length; i++) - { - var ofs = (i - 1) * 2; - ptrs[i] = (data[ofs + 1] << 8 | data[ofs]) - baseOffset; - } - - EggMoves[] entries = new EggMoves[count + 1]; - entries[0] = new EggMoves2(Array.Empty()); - for (int i = 1; i < entries.Length; i++) - entries[i] = new EggMoves2(data.Skip(ptrs[i]).TakeWhile(b => b != 0xFF).ToArray()); - - return entries; + var ofs = (i - 1) * 2; + ptrs[i] = (data[ofs + 1] << 8 | data[ofs]) - baseOffset; } + + EggMoves[] entries = new EggMoves[count + 1]; + entries[0] = new EggMoves2(Array.Empty()); + for (int i = 1; i < entries.Length; i++) + entries[i] = new EggMoves2(data.Skip(ptrs[i]).TakeWhile(b => b != 0xFF).ToArray()); + + return entries; } -} \ No newline at end of file +} diff --git a/pkNX.Structures/EggMove/EggMoves6.cs b/pkNX.Structures/EggMove/EggMoves6.cs index eac40d9b..e46f94c0 100644 --- a/pkNX.Structures/EggMove/EggMoves6.cs +++ b/pkNX.Structures/EggMove/EggMoves6.cs @@ -1,31 +1,30 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class EggMoves6 : EggMoves { - public sealed class EggMoves6 : EggMoves + private static readonly EggMoves6 None = new(Array.Empty()); + + private EggMoves6(int[] moves) : base(moves) { } + + private static EggMoves6 Get(byte[] data) { - private static readonly EggMoves6 None = new(Array.Empty()); + if (data.Length < 2 || data.Length % 2 != 0) + return None; - private EggMoves6(int[] moves) : base(moves) { } - - private static EggMoves6 Get(byte[] data) - { - if (data.Length < 2 || data.Length % 2 != 0) - return None; - - int count = BitConverter.ToInt16(data, 0); - var moves = new int[count]; - for (int i = 0; i < moves.Length; i++) - moves[i] = BitConverter.ToInt16(data, 2 + (i * 2)); - return new EggMoves6(moves); - } - - public static EggMoves6[] GetArray(byte[][] entries) - { - EggMoves6[] data = new EggMoves6[entries.Length]; - for (int i = 0; i < data.Length; i++) - data[i] = Get(entries[i]); - return data; - } + int count = BitConverter.ToInt16(data, 0); + var moves = new int[count]; + for (int i = 0; i < moves.Length; i++) + moves[i] = BitConverter.ToInt16(data, 2 + (i * 2)); + return new EggMoves6(moves); } -} \ No newline at end of file + + public static EggMoves6[] GetArray(byte[][] entries) + { + EggMoves6[] data = new EggMoves6[entries.Length]; + for (int i = 0; i < data.Length; i++) + data[i] = Get(entries[i]); + return data; + } +} diff --git a/pkNX.Structures/EggMove/EggMoves7.cs b/pkNX.Structures/EggMove/EggMoves7.cs index 683623e5..e00c4c16 100644 --- a/pkNX.Structures/EggMove/EggMoves7.cs +++ b/pkNX.Structures/EggMove/EggMoves7.cs @@ -1,51 +1,50 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class EggMoves7 : EggMoves { - public sealed class EggMoves7 : EggMoves + private static readonly EggMoves7 None = new(Array.Empty()); + public readonly int FormTableIndex; + + private EggMoves7(int[] moves, int formIndex = 0) : base(moves) => FormTableIndex = formIndex; + + private static EggMoves7 Get(byte[] data) { - private static readonly EggMoves7 None = new(Array.Empty()); - public readonly int FormTableIndex; + if (data.Length < 4 || data.Length % 2 != 0) + return None; - private EggMoves7(int[] moves, int formIndex = 0) : base(moves) => FormTableIndex = formIndex; - - private static EggMoves7 Get(byte[] data) - { - if (data.Length < 4 || data.Length % 2 != 0) - return None; - - int formIndex = BitConverter.ToInt16(data, 0); - int count = BitConverter.ToInt16(data, 2); - var moves = new int[count]; - for (int i = 0; i < moves.Length; i++) - moves[i] = BitConverter.ToInt16(data, 4 + (i * 2)); - return new EggMoves7(moves, formIndex); - } - - public static EggMoves7[] GetArray(byte[][] entries) - { - EggMoves7[] data = new EggMoves7[entries.Length]; - for (int i = 0; i < data.Length; i++) - data[i] = Get(entries[i]); - return data; - } - - private byte[] Set() - { - var data = new byte[2 + 2 + (2 *Moves.Length)]; - BitConverter.GetBytes((ushort)FormTableIndex).CopyTo(data, 0); - BitConverter.GetBytes((ushort)Moves.Length).CopyTo(data, 2); - for (int i = 0; i < Moves.Length; i++) - BitConverter.GetBytes((ushort)Moves[i]).CopyTo(data, 4 + (2*i)); - return data; - } - - public static byte[][] SetArray(EggMoves7[] entries) - { - byte[][] data = new byte[entries.Length][]; - for (int i = 0; i < data.Length; i++) - data[i] = entries[i].Set(); - return data; - } + int formIndex = BitConverter.ToInt16(data, 0); + int count = BitConverter.ToInt16(data, 2); + var moves = new int[count]; + for (int i = 0; i < moves.Length; i++) + moves[i] = BitConverter.ToInt16(data, 4 + (i * 2)); + return new EggMoves7(moves, formIndex); } -} \ No newline at end of file + + public static EggMoves7[] GetArray(byte[][] entries) + { + EggMoves7[] data = new EggMoves7[entries.Length]; + for (int i = 0; i < data.Length; i++) + data[i] = Get(entries[i]); + return data; + } + + private byte[] Set() + { + var data = new byte[2 + 2 + (2 *Moves.Length)]; + BitConverter.GetBytes((ushort)FormTableIndex).CopyTo(data, 0); + BitConverter.GetBytes((ushort)Moves.Length).CopyTo(data, 2); + for (int i = 0; i < Moves.Length; i++) + BitConverter.GetBytes((ushort)Moves[i]).CopyTo(data, 4 + (2*i)); + return data; + } + + public static byte[][] SetArray(EggMoves7[] entries) + { + byte[][] data = new byte[entries.Length][]; + for (int i = 0; i < data.Length; i++) + data[i] = entries[i].Set(); + return data; + } +} diff --git a/pkNX.Structures/Encounter/EncounterGift.cs b/pkNX.Structures/Encounter/EncounterGift.cs index 188f8b33..5976784f 100644 --- a/pkNX.Structures/Encounter/EncounterGift.cs +++ b/pkNX.Structures/Encounter/EncounterGift.cs @@ -1,43 +1,42 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class EncounterGift { - public abstract class EncounterGift + protected readonly byte[] Data; + protected EncounterGift(byte[] data) => Data = data; + public virtual byte[] Write() => (byte[])Data.Clone(); + + public abstract Species Species { get; set; } + public virtual int HeldItem { get; set; } + public abstract int Level { get; set; } + public abstract int Form { get; set; } + public abstract FixedGender Gender { get; set; } + + public virtual Nature Nature { get; set; } = Nature.Random; + public virtual int Ability { get; set; } + public virtual bool ShinyLock { get; set; } + + public virtual bool IV3 { get; set; } + public virtual int[] RelearnMoves { get; set; } = Array.Empty(); + public abstract Shiny Shiny { get; set; } + + public abstract int IV_HP { get; set; } + public abstract int IV_ATK { get; set; } + public abstract int IV_DEF { get; set; } + public abstract int IV_SPE { get; set; } + public abstract int IV_SPA { get; set; } + public abstract int IV_SPD { get; set; } + + public int[] IVs { - protected readonly byte[] Data; - protected EncounterGift(byte[] data) => Data = data; - public virtual byte[] Write() => (byte[])Data.Clone(); - - public abstract Species Species { get; set; } - public virtual int HeldItem { get; set; } - public abstract int Level { get; set; } - public abstract int Form { get; set; } - public abstract FixedGender Gender { get; set; } - - public virtual Nature Nature { get; set; } = Nature.Random; - public virtual int Ability { get; set; } - public virtual bool ShinyLock { get; set; } - - public virtual bool IV3 { get; set; } - public virtual int[] RelearnMoves { get; set; } = Array.Empty(); - public abstract Shiny Shiny { get; set; } - - public abstract int IV_HP { get; set; } - public abstract int IV_ATK { get; set; } - public abstract int IV_DEF { get; set; } - public abstract int IV_SPE { get; set; } - public abstract int IV_SPA { get; set; } - public abstract int IV_SPD { get; set; } - - public int[] IVs + get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; + set { - get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; - set - { - if (value?.Length != 6) return; - IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; - IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; - } + if (value?.Length != 6) return; + IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; + IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } } } diff --git a/pkNX.Structures/Encounter/EncounterStatic.cs b/pkNX.Structures/Encounter/EncounterStatic.cs index 46a01107..07608c8e 100644 --- a/pkNX.Structures/Encounter/EncounterStatic.cs +++ b/pkNX.Structures/Encounter/EncounterStatic.cs @@ -1,96 +1,95 @@ -using System; +using System; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class EncounterStatic { - public abstract class EncounterStatic + protected readonly byte[] Data; + protected EncounterStatic(byte[] data) => Data = data; + public virtual byte[] Write() => (byte[])Data.Clone(); + + public abstract Species Species { get; set; } + public virtual int HeldItem { get; set; } + public abstract int Level { get; set; } + public abstract int Form { get; set; } + public abstract FixedGender Gender { get; set; } + + public virtual Nature Nature { get; set; } = Nature.Random; + public virtual int Ability { get; set; } + public virtual bool ShinyLock { get; set; } + + public virtual bool IV3 { get; set; } + public virtual int[] RelearnMoves { get; set; } = Array.Empty(); + public abstract Shiny Shiny { get; set; } + + public virtual int IV_HP { get; set; } = -1; + public virtual int IV_ATK { get; set; } = -1; + public virtual int IV_DEF { get; set; } = -1; + public virtual int IV_SPE { get; set; } = -1; + public virtual int IV_SPA { get; set; } = -1; + public virtual int IV_SPD { get; set; } = -1; + public virtual int EV_HP { get; set; } + public virtual int EV_ATK { get; set; } + public virtual int EV_DEF { get; set; } + public virtual int EV_SPE { get; set; } + public virtual int EV_SPA { get; set; } + public virtual int EV_SPD { get; set; } + + public int[] IVs { - protected readonly byte[] Data; - protected EncounterStatic(byte[] data) => Data = data; - public virtual byte[] Write() => (byte[])Data.Clone(); - - public abstract Species Species { get; set; } - public virtual int HeldItem { get; set; } - public abstract int Level { get; set; } - public abstract int Form { get; set; } - public abstract FixedGender Gender { get; set; } - - public virtual Nature Nature { get; set; } = Nature.Random; - public virtual int Ability { get; set; } - public virtual bool ShinyLock { get; set; } - - public virtual bool IV3 { get; set; } - public virtual int[] RelearnMoves { get; set; } = Array.Empty(); - public abstract Shiny Shiny { get; set; } - - public virtual int IV_HP { get; set; } = -1; - public virtual int IV_ATK { get; set; } = -1; - public virtual int IV_DEF { get; set; } = -1; - public virtual int IV_SPE { get; set; } = -1; - public virtual int IV_SPA { get; set; } = -1; - public virtual int IV_SPD { get; set; } = -1; - public virtual int EV_HP { get; set; } - public virtual int EV_ATK { get; set; } - public virtual int EV_DEF { get; set; } - public virtual int EV_SPE { get; set; } - public virtual int EV_SPA { get; set; } - public virtual int EV_SPD { get; set; } - - public int[] IVs + get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; + set { - get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; - set - { - if (value?.Length != 6) return; - IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; - IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; - } - } - - public int[] EVs - { - get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; - set - { - if (value?.Length != 6) return; - EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; - EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; - } - } - - public string GetSummary() - { - var str = $"new EncounterStatic {{ Species = {Species:000}, Level = {Level:00}, Location = -01, "; - if (Ability != 0) - str += $"Ability = {1 << (Ability - 1)}, "; - if (ShinyLock) - str += "Shiny = false, "; - - if (IV3) - { - str += "IV3 = true, "; - } - else if (IVs.Any(z => z >= 0)) - { - var iv = IVs.Select(z => z >= 0 ? $"{z:00}" : "-1"); - str += $"IVs = new[] {{{string.Join(",", iv)}}}, "; - } - if (RelearnMoves.Any(z => z != 0)) - { - var mv = RelearnMoves.Select(z => $"{z:000}"); - str += $"Relearn = new[] {{{string.Join(",", mv)}}}, "; - } - if (Form != 0) - str += $"Form = {Form}, "; - if (Gender != 0) - str += $"Gender = {Gender - 1}, "; - if (HeldItem > 0) - str += $"HeldItem = {HeldItem}, "; - if (Nature is >= 0 and < Nature.Random25) - str += $"Nature = {Nature - 1}, "; - - str += " },"; - return str; + if (value?.Length != 6) return; + IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; + IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } } + + public int[] EVs + { + get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; + set + { + if (value?.Length != 6) return; + EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; + EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; + } + } + + public string GetSummary() + { + var str = $"new EncounterStatic {{ Species = {Species:000}, Level = {Level:00}, Location = -01, "; + if (Ability != 0) + str += $"Ability = {1 << (Ability - 1)}, "; + if (ShinyLock) + str += "Shiny = false, "; + + if (IV3) + { + str += "IV3 = true, "; + } + else if (IVs.Any(z => z >= 0)) + { + var iv = IVs.Select(z => z >= 0 ? $"{z:00}" : "-1"); + str += $"IVs = new[] {{{string.Join(",", iv)}}}, "; + } + if (RelearnMoves.Any(z => z != 0)) + { + var mv = RelearnMoves.Select(z => $"{z:000}"); + str += $"Relearn = new[] {{{string.Join(",", mv)}}}, "; + } + if (Form != 0) + str += $"Form = {Form}, "; + if (Gender != 0) + str += $"Gender = {Gender - 1}, "; + if (HeldItem > 0) + str += $"HeldItem = {HeldItem}, "; + if (Nature is >= 0 and < Nature.Random25) + str += $"Nature = {Nature - 1}, "; + + str += " },"; + return str; + } } diff --git a/pkNX.Structures/Encounter/EncounterTrade.cs b/pkNX.Structures/Encounter/EncounterTrade.cs index 3b23d9bc..4f1f4123 100644 --- a/pkNX.Structures/Encounter/EncounterTrade.cs +++ b/pkNX.Structures/Encounter/EncounterTrade.cs @@ -1,45 +1,44 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class EncounterTrade { - public abstract class EncounterTrade + protected readonly byte[] Data; + + protected EncounterTrade(byte[] data) => Data = data; + + public virtual byte[] Write() => (byte[])Data.Clone(); + + public abstract Species Species { get; set; } + public virtual int HeldItem { get; set; } + public abstract int Level { get; set; } + public abstract int Form { get; set; } + public abstract FixedGender Gender { get; set; } + + public virtual Nature Nature { get; set; } = Nature.Random; + public virtual int Ability { get; set; } + public virtual bool ShinyLock { get; set; } + + public virtual bool IV3 { get; set; } + public virtual int[] RelearnMoves { get; set; } = Array.Empty(); + public abstract Shiny Shiny { get; set; } + + public abstract int IV_HP { get; set; } + public abstract int IV_ATK { get; set; } + public abstract int IV_DEF { get; set; } + public abstract int IV_SPE { get; set; } + public abstract int IV_SPA { get; set; } + public abstract int IV_SPD { get; set; } + + public int[] IVs { - protected readonly byte[] Data; - - protected EncounterTrade(byte[] data) => Data = data; - - public virtual byte[] Write() => (byte[])Data.Clone(); - - public abstract Species Species { get; set; } - public virtual int HeldItem { get; set; } - public abstract int Level { get; set; } - public abstract int Form { get; set; } - public abstract FixedGender Gender { get; set; } - - public virtual Nature Nature { get; set; } = Nature.Random; - public virtual int Ability { get; set; } - public virtual bool ShinyLock { get; set; } - - public virtual bool IV3 { get; set; } - public virtual int[] RelearnMoves { get; set; } = Array.Empty(); - public abstract Shiny Shiny { get; set; } - - public abstract int IV_HP { get; set; } - public abstract int IV_ATK { get; set; } - public abstract int IV_DEF { get; set; } - public abstract int IV_SPE { get; set; } - public abstract int IV_SPA { get; set; } - public abstract int IV_SPD { get; set; } - - public int[] IVs + get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; + set { - get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; - set - { - if (value?.Length != 6) return; - IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; - IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; - } + if (value?.Length != 6) return; + IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; + IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; } } } diff --git a/pkNX.Structures/Encounter/FixedGender.cs b/pkNX.Structures/Encounter/FixedGender.cs index 3a547aaa..08038495 100644 --- a/pkNX.Structures/Encounter/FixedGender.cs +++ b/pkNX.Structures/Encounter/FixedGender.cs @@ -1,13 +1,11 @@ -namespace pkNX.Structures -{ +namespace pkNX.Structures; #pragma warning disable CA1027 // Mark enums with FlagsAttribute - public enum FixedGender : byte +public enum FixedGender : byte #pragma warning restore CA1027 // Mark enums with FlagsAttribute - { - Random = 0, - Male = 1, - Female = 2, +{ + Random = 0, + Male = 1, + Female = 2, - Genderless = Random, - } -} \ No newline at end of file + Genderless = Random, +} diff --git a/pkNX.Structures/Encounter/Gen6/EncounterGift6AO.cs b/pkNX.Structures/Encounter/Gen6/EncounterGift6AO.cs index 464149a6..3413bc02 100644 --- a/pkNX.Structures/Encounter/Gen6/EncounterGift6AO.cs +++ b/pkNX.Structures/Encounter/Gen6/EncounterGift6AO.cs @@ -1,47 +1,46 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class EncounterGift6AO : EncounterGift { - public class EncounterGift6AO : EncounterGift - { - public const int SIZE = 0x24; - public EncounterGift6AO(byte[] data = null) : base(data ?? new byte[SIZE]) { } + public const int SIZE = 0x24; + public EncounterGift6AO(byte[] data = null) : base(data ?? new byte[SIZE]) { } - public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } - public int Unk02 { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } - public override int Form { get => Data[0x04]; set => Data[0x04] = (byte)value; } - public override int Level { get => Data[0x05]; set => Data[0x05] = (byte)value; } - public override int Ability { get => (sbyte)Data[0x06]; set => Data[0x06] = (byte)value; } - public override Nature Nature { get => (Nature)Data[0x07]; set => Data[0x07] = (byte)value; } - public override Shiny Shiny { get => (Shiny)Data[0x08]; set => Data[0x08] = (byte)value; } + public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } + public int Unk02 { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } + public override int Form { get => Data[0x04]; set => Data[0x04] = (byte)value; } + public override int Level { get => Data[0x05]; set => Data[0x05] = (byte)value; } + public override int Ability { get => (sbyte)Data[0x06]; set => Data[0x06] = (byte)value; } + public override Nature Nature { get => (Nature)Data[0x07]; set => Data[0x07] = (byte)value; } + public override Shiny Shiny { get => (Shiny)Data[0x08]; set => Data[0x08] = (byte)value; } - // padding? - public int Unk09 { get => Data[0x09]; set => Data[0x09] = (byte)value; } - public int Unk0A { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public int Unk0B { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } + // padding? + public int Unk09 { get => Data[0x09]; set => Data[0x09] = (byte)value; } + public int Unk0A { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public int Unk0B { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } - public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } - public override FixedGender Gender { get => (FixedGender)Data[0x10]; set => Data[0x10] = (byte)value; } + public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } + public override FixedGender Gender { get => (FixedGender)Data[0x10]; set => Data[0x10] = (byte)value; } - // padding? - public int Unk11 { get => (sbyte)Data[0x11]; set => Data[0x11] = (byte)value; } - public short MetLocation { get => BitConverter.ToInt16(Data, 0x12); set => BitConverter.GetBytes(value).CopyTo(Data, 0x12); } - public int Move { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } + // padding? + public int Unk11 { get => (sbyte)Data[0x11]; set => Data[0x11] = (byte)value; } + public short MetLocation { get => BitConverter.ToInt16(Data, 0x12); set => BitConverter.GetBytes(value).CopyTo(Data, 0x12); } + public int Move { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } - public override int IV_HP { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } - public override int IV_ATK { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } - public override int IV_DEF { get => (sbyte)Data[0x18]; set => Data[0x18] = (byte)value; } - public override int IV_SPA { get => (sbyte)Data[0x19]; set => Data[0x19] = (byte)value; } - public override int IV_SPD { get => (sbyte)Data[0x1A]; set => Data[0x1A] = (byte)value; } - public override int IV_SPE { get => (sbyte)Data[0x1B]; set => Data[0x1B] = (byte)value; } + public override int IV_HP { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } + public override int IV_ATK { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } + public override int IV_DEF { get => (sbyte)Data[0x18]; set => Data[0x18] = (byte)value; } + public override int IV_SPA { get => (sbyte)Data[0x19]; set => Data[0x19] = (byte)value; } + public override int IV_SPD { get => (sbyte)Data[0x1A]; set => Data[0x1A] = (byte)value; } + public override int IV_SPE { get => (sbyte)Data[0x1B]; set => Data[0x1B] = (byte)value; } - public int CNT_Cool { get => (sbyte)Data[0x1C]; set => Data[0x1C] = (byte)value; } - public int CNT_Beauty { get => (sbyte)Data[0x1D]; set => Data[0x1D] = (byte)value; } - public int CNT_Cute { get => (sbyte)Data[0x1E]; set => Data[0x1E] = (byte)value; } - public int CNT_Smart { get => (sbyte)Data[0x1F]; set => Data[0x1F] = (byte)value; } - public int CNT_Tough { get => (sbyte)Data[0x20]; set => Data[0x20] = (byte)value; } - public int CNT_Sheen { get => (sbyte)Data[0x21]; set => Data[0x21] = (byte)value; } + public int CNT_Cool { get => (sbyte)Data[0x1C]; set => Data[0x1C] = (byte)value; } + public int CNT_Beauty { get => (sbyte)Data[0x1D]; set => Data[0x1D] = (byte)value; } + public int CNT_Cute { get => (sbyte)Data[0x1E]; set => Data[0x1E] = (byte)value; } + public int CNT_Smart { get => (sbyte)Data[0x1F]; set => Data[0x1F] = (byte)value; } + public int CNT_Tough { get => (sbyte)Data[0x20]; set => Data[0x20] = (byte)value; } + public int CNT_Sheen { get => (sbyte)Data[0x21]; set => Data[0x21] = (byte)value; } - public int Unk22 { get => (sbyte)Data[0x22]; set => Data[0x22] = (byte)value; } - } -} \ No newline at end of file + public int Unk22 { get => (sbyte)Data[0x22]; set => Data[0x22] = (byte)value; } +} diff --git a/pkNX.Structures/Encounter/Gen6/EncounterGift6XY.cs b/pkNX.Structures/Encounter/Gen6/EncounterGift6XY.cs index b3b1b0dd..8825b5c4 100644 --- a/pkNX.Structures/Encounter/Gen6/EncounterGift6XY.cs +++ b/pkNX.Structures/Encounter/Gen6/EncounterGift6XY.cs @@ -1,36 +1,35 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class EncounterGift6XY : EncounterGift { - public class EncounterGift6XY : EncounterGift - { - public const int SIZE = 0x18; - public EncounterGift6XY(byte[] data = null) : base(data ?? new byte[SIZE]) { } + public const int SIZE = 0x18; + public EncounterGift6XY(byte[] data = null) : base(data ?? new byte[SIZE]) { } - public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } - public int Unk_02 { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } - public override int Form { get => Data[0x04]; set => Data[0x04] = (byte) value; } - public override int Level { get => Data[0x05]; set => Data[0x05] = (byte)value; } - public override int Ability { get => (sbyte)Data[0x06]; set => Data[0x06] = (byte)value; } - public override Nature Nature { get => (Nature)Data[0x07]; set => Data[0x07] = (byte)value; } - public override Shiny Shiny { get => (Shiny)Data[0x08]; set => Data[0x08] = (byte)value; } + public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } + public int Unk_02 { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } + public override int Form { get => Data[0x04]; set => Data[0x04] = (byte) value; } + public override int Level { get => Data[0x05]; set => Data[0x05] = (byte)value; } + public override int Ability { get => (sbyte)Data[0x06]; set => Data[0x06] = (byte)value; } + public override Nature Nature { get => (Nature)Data[0x07]; set => Data[0x07] = (byte)value; } + public override Shiny Shiny { get => (Shiny)Data[0x08]; set => Data[0x08] = (byte)value; } - // padding - public int Unk_09 { get => Data[0x09]; set => Data[0x09] = (byte)value; } - public int Unk_0A { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public int Unk_0B { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } + // padding + public int Unk_09 { get => Data[0x09]; set => Data[0x09] = (byte)value; } + public int Unk_0A { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public int Unk_0B { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } - public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } - public override FixedGender Gender { get => (FixedGender)Data[0x10]; set => Data[0x10] = (byte)value; } + public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } + public override FixedGender Gender { get => (FixedGender)Data[0x10]; set => Data[0x10] = (byte)value; } - public override int IV_HP { get => (sbyte)Data[0x11]; set => Data[0x11] = (byte)value; } - public override int IV_ATK { get => (sbyte)Data[0x12]; set => Data[0x12] = (byte)value; } - public override int IV_DEF { get => (sbyte)Data[0x13]; set => Data[0x13] = (byte)value; } - public override int IV_SPA { get => (sbyte)Data[0x14]; set => Data[0x14] = (byte)value; } - public override int IV_SPD { get => (sbyte)Data[0x15]; set => Data[0x15] = (byte)value; } - public override int IV_SPE { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } + public override int IV_HP { get => (sbyte)Data[0x11]; set => Data[0x11] = (byte)value; } + public override int IV_ATK { get => (sbyte)Data[0x12]; set => Data[0x12] = (byte)value; } + public override int IV_DEF { get => (sbyte)Data[0x13]; set => Data[0x13] = (byte)value; } + public override int IV_SPA { get => (sbyte)Data[0x14]; set => Data[0x14] = (byte)value; } + public override int IV_SPD { get => (sbyte)Data[0x15]; set => Data[0x15] = (byte)value; } + public override int IV_SPE { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } - // padding - public int Unk_17 { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } - } -} \ No newline at end of file + // padding + public int Unk_17 { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } +} diff --git a/pkNX.Structures/Encounter/Gen6/EncounterStatic6.cs b/pkNX.Structures/Encounter/Gen6/EncounterStatic6.cs index aad7cc40..c183db08 100644 --- a/pkNX.Structures/Encounter/Gen6/EncounterStatic6.cs +++ b/pkNX.Structures/Encounter/Gen6/EncounterStatic6.cs @@ -1,50 +1,49 @@ -using System; +using System; -namespace pkNX.Structures.Encounter +namespace pkNX.Structures.Encounter; + +public sealed class EncounterStatic6 : EncounterStatic { - public sealed class EncounterStatic6 : EncounterStatic + private const int SIZE = 0xC; + public EncounterStatic6(byte[] data = null) : base(data ?? new byte[SIZE]) { } + + public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x0); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0); } + public override int Form { get => Data[0x2]; set => Data[0x2] = (byte)value; } + public override int Level { get => Data[0x3]; set => Data[0x3] = (byte)value; } + + public override int HeldItem { - private const int SIZE = 0xC; - public EncounterStatic6(byte[] data = null) : base(data ?? new byte[SIZE]) { } + get => Math.Max(0, (int)BitConverter.ToInt16(Data, 0x4)); + set => BitConverter.GetBytes((short)(value <= 0 ? -1 : value)).CopyTo(Data, 0x4); + } - public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x0); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0); } - public override int Form { get => Data[0x2]; set => Data[0x2] = (byte)value; } - public override int Level { get => Data[0x3]; set => Data[0x3] = (byte)value; } + public override Shiny Shiny + { + get => (Shiny)(Data[0x6] & 3); + set => Data[0x6] = (byte)((Data[0x6] & ~3) | ((byte)value & 3)); + } - public override int HeldItem - { - get => Math.Max(0, (int)BitConverter.ToInt16(Data, 0x4)); - set => BitConverter.GetBytes((short)(value <= 0 ? -1 : value)).CopyTo(Data, 0x4); - } + public override FixedGender Gender + { + get => (FixedGender)((Data[0x6] & 0x0C) >> 2); + set => Data[0x6] = (byte)((Data[0x6] & ~0xC) | (((byte)value & 3) << 2)); + } - public override Shiny Shiny - { - get => (Shiny)(Data[0x6] & 3); - set => Data[0x6] = (byte)((Data[0x6] & ~3) | ((byte)value & 3)); - } + public override int Ability + { + get => (Data[0x6] & 0x70) >> 4; + set => Data[0x6] = (byte)((Data[0x6] & ~0x70) | ((value & 7) << 4)); + } - public override FixedGender Gender - { - get => (FixedGender)((Data[0x6] & 0x0C) >> 2); - set => Data[0x6] = (byte)((Data[0x6] & ~0xC) | (((byte)value & 3) << 2)); - } + public override bool IV3 + { + get => (Data[0x7] & 1) >> 0 == 1; + set => Data[0x7] = (byte)((Data[0x7] & ~1) | (value ? 1 : 0)); + } - public override int Ability - { - get => (Data[0x6] & 0x70) >> 4; - set => Data[0x6] = (byte)((Data[0x6] & ~0x70) | ((value & 7) << 4)); - } - - public override bool IV3 - { - get => (Data[0x7] & 1) >> 0 == 1; - set => Data[0x7] = (byte)((Data[0x7] & ~1) | (value ? 1 : 0)); - } - - public bool IV3_1 - { - get => (Data[0x7] & 2) >> 1 == 1; - set => Data[0x7] = (byte)((Data[0x7] & ~2) | (value ? 2 : 0)); - } + public bool IV3_1 + { + get => (Data[0x7] & 2) >> 1 == 1; + set => Data[0x7] = (byte)((Data[0x7] & ~2) | (value ? 2 : 0)); } } diff --git a/pkNX.Structures/Encounter/Gen7/EncounterGift7.cs b/pkNX.Structures/Encounter/Gen7/EncounterGift7.cs index 15f9a2e4..f8b666db 100644 --- a/pkNX.Structures/Encounter/Gen7/EncounterGift7.cs +++ b/pkNX.Structures/Encounter/Gen7/EncounterGift7.cs @@ -1,33 +1,32 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class EncounterGift7 : EncounterGift { - public class EncounterGift7 : EncounterGift - { - public const int SIZE = 0x14; - public EncounterGift7(byte[] data = null) : base(data ?? new byte[SIZE]) { } + public const int SIZE = 0x14; + public EncounterGift7(byte[] data = null) : base(data ?? new byte[SIZE]) { } - public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x0); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0); } - public override int Form { get => Data[0x2]; set => Data[0x2] = (byte)value; } - public override int Level { get => Data[0x3]; set => Data[0x3] = (byte)value; } + public override Species Species { get => (Species)BitConverter.ToUInt16(Data, 0x0); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0); } + public override int Form { get => Data[0x2]; set => Data[0x2] = (byte)value; } + public override int Level { get => Data[0x3]; set => Data[0x3] = (byte)value; } - public override Shiny Shiny { get => (Shiny)Data[0x4]; set => Data[0x4] = (byte)value; } - public override FixedGender Gender { get => (FixedGender)Data[0x5]; set => Data[0x5] = (byte)value; } - public override int Ability { get => (sbyte)Data[0x6]; set => Data[0x6] = (byte)value; } - public override Nature Nature { get => (Nature)Data[0x7]; set => Data[0x7] = (byte)value; } + public override Shiny Shiny { get => (Shiny)Data[0x4]; set => Data[0x4] = (byte)value; } + public override FixedGender Gender { get => (FixedGender)Data[0x5]; set => Data[0x5] = (byte)value; } + public override int Ability { get => (sbyte)Data[0x6]; set => Data[0x6] = (byte)value; } + public override Nature Nature { get => (Nature)Data[0x7]; set => Data[0x7] = (byte)value; } - public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x8); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x8); } + public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x8); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x8); } - public bool IsEgg { get => Data[0xA] == 1; set => Data[0xA] = value ? (byte)1 : (byte)0; } + public bool IsEgg { get => Data[0xA] == 1; set => Data[0xA] = value ? (byte)1 : (byte)0; } - public int SpecialMove { get => BitConverter.ToUInt16(Data, 0xC); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xC); } + public int SpecialMove { get => BitConverter.ToUInt16(Data, 0xC); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xC); } - public override bool IV3 => (sbyte)Data[0xE] < 0 && (sbyte)Data[0xE] + 1 == -3; - public override int IV_HP { get; set; } = -1; - public override int IV_ATK { get; set; } = -1; - public override int IV_DEF { get; set; } = -1; - public override int IV_SPE { get; set; } = -1; - public override int IV_SPA { get; set; } = -1; - public override int IV_SPD { get; set; } = -1; - } -} \ No newline at end of file + public override bool IV3 => (sbyte)Data[0xE] < 0 && (sbyte)Data[0xE] + 1 == -3; + public override int IV_HP { get; set; } = -1; + public override int IV_ATK { get; set; } = -1; + public override int IV_DEF { get; set; } = -1; + public override int IV_SPE { get; set; } = -1; + public override int IV_SPA { get; set; } = -1; + public override int IV_SPD { get; set; } = -1; +} diff --git a/pkNX.Structures/Encounter/Gen7/EncounterGift7b.cs b/pkNX.Structures/Encounter/Gen7/EncounterGift7b.cs index 56027f65..d561f783 100644 --- a/pkNX.Structures/Encounter/Gen7/EncounterGift7b.cs +++ b/pkNX.Structures/Encounter/Gen7/EncounterGift7b.cs @@ -1,74 +1,73 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class EncounterGift7b : EncounterGift { - public class EncounterGift7b : EncounterGift + public const int SIZE = 0x20; + public EncounterGift7b(byte[] data = null) : base(data ?? new byte[SIZE]) { } + + public ulong Hash => BitConverter.ToUInt64(Data, 0); + + public override Species Species { - public const int SIZE = 0x20; - public EncounterGift7b(byte[] data = null) : base(data ?? new byte[SIZE]) { } + get => (Species)BitConverter.ToUInt16(Data, 0x08); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); + } - public ulong Hash => BitConverter.ToUInt64(Data, 0); + public override int Form { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public override int Level { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } - public override Species Species + public override Shiny Shiny // 0 = Random, 1 = Always, 2 = Never + { + get => (Shiny)(Data[0x0C] & 3); + set => Data[0x0C] = (byte)((Data[0x0C] & ~3) | ((byte)value & 3)); + } + + public override FixedGender Gender // 0 = Random, 1 = Male, 2 = Female, 3 = Panic + { + get => (FixedGender)(Data[0x0D] & 3); + set => Data[0x0D] = (byte)((Data[0x0D] & ~3) | ((byte)value & 3)); + } + + public override Nature Nature { get => (Nature)Data[0x0E]; set => Data[0x0E] = (byte)value; } // 25 = random (sets the nature rand to 1) + public override int Ability { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } // 0 = rand + + public int SpecialMove // sub_71002B7AD0 checks nonzero, pushes move + { + get => BitConverter.ToUInt16(Data, 0x10); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); + } + + public override int IV_HP { get => (sbyte)Data[0x12]; set => Data[0x12] = (byte)value; } + public override int IV_ATK { get => (sbyte)Data[0x13]; set => Data[0x13] = (byte)value; } + public override int IV_DEF { get => (sbyte)Data[0x14]; set => Data[0x14] = (byte)value; } + public override int IV_SPA { get => (sbyte)Data[0x15]; set => Data[0x15] = (byte)value; } + public override int IV_SPD { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } + public override int IV_SPE { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } + + public int AV_HP { get => (sbyte)Data[0x18]; set => Data[0x18] = (byte)value; } + public int AV_ATK { get => (sbyte)Data[0x19]; set => Data[0x19] = (byte)value; } + public int AV_DEF { get => (sbyte)Data[0x1A]; set => Data[0x1A] = (byte)value; } + public int AV_SPA { get => (sbyte)Data[0x1B]; set => Data[0x1B] = (byte)value; } + public int AV_SPD { get => (sbyte)Data[0x1C]; set => Data[0x1C] = (byte)value; } + public int AV_SPE { get => (sbyte)Data[0x1D]; set => Data[0x1D] = (byte)value; } + + public override int[] RelearnMoves + { + get => new int[] { - get => (Species)BitConverter.ToUInt16(Data, 0x08); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); - } - - public override int Form { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public override int Level { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } - - public override Shiny Shiny // 0 = Random, 1 = Always, 2 = Never + BitConverter.ToUInt16(Data, 0x18), + BitConverter.ToUInt16(Data, 0x1A), + BitConverter.ToUInt16(Data, 0x1C), + BitConverter.ToUInt16(Data, 0x1E), + }; + set { - get => (Shiny)(Data[0x0C] & 3); - set => Data[0x0C] = (byte)((Data[0x0C] & ~3) | ((byte)value & 3)); - } - - public override FixedGender Gender // 0 = Random, 1 = Male, 2 = Female, 3 = Panic - { - get => (FixedGender)(Data[0x0D] & 3); - set => Data[0x0D] = (byte)((Data[0x0D] & ~3) | ((byte)value & 3)); - } - - public override Nature Nature { get => (Nature)Data[0x0E]; set => Data[0x0E] = (byte)value; } // 25 = random (sets the nature rand to 1) - public override int Ability { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } // 0 = rand - - public int SpecialMove // sub_71002B7AD0 checks nonzero, pushes move - { - get => BitConverter.ToUInt16(Data, 0x10); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); - } - - public override int IV_HP { get => (sbyte)Data[0x12]; set => Data[0x12] = (byte)value; } - public override int IV_ATK { get => (sbyte)Data[0x13]; set => Data[0x13] = (byte)value; } - public override int IV_DEF { get => (sbyte)Data[0x14]; set => Data[0x14] = (byte)value; } - public override int IV_SPA { get => (sbyte)Data[0x15]; set => Data[0x15] = (byte)value; } - public override int IV_SPD { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } - public override int IV_SPE { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } - - public int AV_HP { get => (sbyte)Data[0x18]; set => Data[0x18] = (byte)value; } - public int AV_ATK { get => (sbyte)Data[0x19]; set => Data[0x19] = (byte)value; } - public int AV_DEF { get => (sbyte)Data[0x1A]; set => Data[0x1A] = (byte)value; } - public int AV_SPA { get => (sbyte)Data[0x1B]; set => Data[0x1B] = (byte)value; } - public int AV_SPD { get => (sbyte)Data[0x1C]; set => Data[0x1C] = (byte)value; } - public int AV_SPE { get => (sbyte)Data[0x1D]; set => Data[0x1D] = (byte)value; } - - public override int[] RelearnMoves - { - get => new int[] - { - BitConverter.ToUInt16(Data, 0x18), - BitConverter.ToUInt16(Data, 0x1A), - BitConverter.ToUInt16(Data, 0x1C), - BitConverter.ToUInt16(Data, 0x1E), - }; - set - { - if (value?.Length != 4) - return; - for (int i = 0; i < 4; i++) - BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, 0x18 + (i * 2)); - } + if (value?.Length != 4) + return; + for (int i = 0; i < 4; i++) + BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, 0x18 + (i * 2)); } } } diff --git a/pkNX.Structures/Encounter/Gen7/EncounterStatic7.cs b/pkNX.Structures/Encounter/Gen7/EncounterStatic7.cs index 136aee73..c88a7b4c 100644 --- a/pkNX.Structures/Encounter/Gen7/EncounterStatic7.cs +++ b/pkNX.Structures/Encounter/Gen7/EncounterStatic7.cs @@ -1,134 +1,133 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class EncounterStatic7 : EncounterStatic { - public sealed class EncounterStatic7 : EncounterStatic + public const int SIZE = 0x38; + public EncounterStatic7(byte[] data = null) : base(data ?? new byte[SIZE]) { } + + public override Species Species { - public const int SIZE = 0x38; - public EncounterStatic7(byte[] data = null) : base(data ?? new byte[SIZE]) { } - - public override Species Species - { - get => (Species)BitConverter.ToUInt16(Data, 0x0); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0); - } - - public override int Form - { - get => Data[0x2]; - set => Data[0x2] = (byte)value; - } - - public override int Level - { - get => Data[0x3]; - set => Data[0x3] = (byte)value; - } - - public override int HeldItem - { - get => Math.Max(0, (int)BitConverter.ToInt16(Data, 0x4)); - set => BitConverter.GetBytes((short)(value <= 0 ? -1 : value)).CopyTo(Data, 0x4); - } - - public override Shiny Shiny - { - get => (Shiny) (Data[0x6] & 3); - set => Data[0x6] = (byte)((Data[0x6] & ~3) | ((byte)value & 3)); - } - - public override FixedGender Gender - { - get => (FixedGender)((Data[0x6] & 0x0C) >> 2); - set => Data[0x6] = (byte)((Data[0x6] & ~0xC) | (((byte)value & 3) << 2)); - } - - public override int Ability - { - get => (Data[0x6] & 0x70) >> 4; - set => Data[0x6] = (byte)((Data[0x6] & ~0x70) | ((value & 7) << 4)); - } - - public bool Unk7_0 - { - get => (Data[0x7] & 1) >> 0 == 1; - set => Data[0x7] = (byte)((Data[0x7] & ~1) | (value ? 1 : 0)); - } - - public bool Unk7_1 - { - get => (Data[0x7] & 2) >> 1 == 1; - set => Data[0x7] = (byte)((Data[0x7] & ~2) | (value ? 2 : 0)); - } - - public int Map - { - get => BitConverter.ToInt16(Data, 0x8) - 1; - set => BitConverter.GetBytes((short)(value + 1)).CopyTo(Data, 0x8); - } - - public override int[] RelearnMoves - { - get => new int[] - { - BitConverter.ToUInt16(Data, 0xC), - BitConverter.ToUInt16(Data, 0xE), - BitConverter.ToUInt16(Data, 0x10), - BitConverter.ToUInt16(Data, 0x12), - }; - set - { - if (value.Length != 4) - return; - for (int i = 0; i < 4; i++) - BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, 0xC + (i * 2)); - } - } - - public override Nature Nature - { - get => (Nature)Data[0x14]; - set => Data[0x14] = (byte)value; - } - - public override int IV_HP { get => (sbyte)Data[0x15]; set => Data[0x15] = (byte)value; } - public override int IV_ATK { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } - public override int IV_DEF { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } - public override int IV_SPA { get => (sbyte)Data[0x18]; set => Data[0x18] = (byte)value; } - public override int IV_SPD { get => (sbyte)Data[0x19]; set => Data[0x19] = (byte)value; } - public override int IV_SPE { get => (sbyte)Data[0x1A]; set => Data[0x1A] = (byte)value; } - - public override int EV_HP { get => (sbyte)Data[0x1B]; set => Data[0x1B] = (byte)value; } - public override int EV_ATK { get => (sbyte)Data[0x1C]; set => Data[0x1C] = (byte)value; } - public override int EV_DEF { get => (sbyte)Data[0x1D]; set => Data[0x1D] = (byte)value; } - public override int EV_SPA { get => (sbyte)Data[0x1E]; set => Data[0x1E] = (byte)value; } - public override int EV_SPD { get => (sbyte)Data[0x1F]; set => Data[0x1F] = (byte)value; } - public override int EV_SPE { get => (sbyte)Data[0x20]; set => Data[0x20] = (byte)value; } - - public int Aura - { - get => Data[0x25]; - set => Data[0x25] = (byte)value; - } - - public int Allies - { - get => Data[0x27]; - set => Data[0x27] = (byte)value; - } - - public int Ally1 - { - get => Data[0x28]; - set => Data[0x28] = (byte)value; - } - - public int Ally2 - { - get => Data[0x2C]; - set => Data[0x2C] = (byte)value; - } - - public override bool IV3 => (sbyte)Data[0x15] < 0 && (sbyte)Data[0x15] + 1 == -3; + get => (Species)BitConverter.ToUInt16(Data, 0x0); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0); } + + public override int Form + { + get => Data[0x2]; + set => Data[0x2] = (byte)value; + } + + public override int Level + { + get => Data[0x3]; + set => Data[0x3] = (byte)value; + } + + public override int HeldItem + { + get => Math.Max(0, (int)BitConverter.ToInt16(Data, 0x4)); + set => BitConverter.GetBytes((short)(value <= 0 ? -1 : value)).CopyTo(Data, 0x4); + } + + public override Shiny Shiny + { + get => (Shiny) (Data[0x6] & 3); + set => Data[0x6] = (byte)((Data[0x6] & ~3) | ((byte)value & 3)); + } + + public override FixedGender Gender + { + get => (FixedGender)((Data[0x6] & 0x0C) >> 2); + set => Data[0x6] = (byte)((Data[0x6] & ~0xC) | (((byte)value & 3) << 2)); + } + + public override int Ability + { + get => (Data[0x6] & 0x70) >> 4; + set => Data[0x6] = (byte)((Data[0x6] & ~0x70) | ((value & 7) << 4)); + } + + public bool Unk7_0 + { + get => (Data[0x7] & 1) >> 0 == 1; + set => Data[0x7] = (byte)((Data[0x7] & ~1) | (value ? 1 : 0)); + } + + public bool Unk7_1 + { + get => (Data[0x7] & 2) >> 1 == 1; + set => Data[0x7] = (byte)((Data[0x7] & ~2) | (value ? 2 : 0)); + } + + public int Map + { + get => BitConverter.ToInt16(Data, 0x8) - 1; + set => BitConverter.GetBytes((short)(value + 1)).CopyTo(Data, 0x8); + } + + public override int[] RelearnMoves + { + get => new int[] + { + BitConverter.ToUInt16(Data, 0xC), + BitConverter.ToUInt16(Data, 0xE), + BitConverter.ToUInt16(Data, 0x10), + BitConverter.ToUInt16(Data, 0x12), + }; + set + { + if (value.Length != 4) + return; + for (int i = 0; i < 4; i++) + BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, 0xC + (i * 2)); + } + } + + public override Nature Nature + { + get => (Nature)Data[0x14]; + set => Data[0x14] = (byte)value; + } + + public override int IV_HP { get => (sbyte)Data[0x15]; set => Data[0x15] = (byte)value; } + public override int IV_ATK { get => (sbyte)Data[0x16]; set => Data[0x16] = (byte)value; } + public override int IV_DEF { get => (sbyte)Data[0x17]; set => Data[0x17] = (byte)value; } + public override int IV_SPA { get => (sbyte)Data[0x18]; set => Data[0x18] = (byte)value; } + public override int IV_SPD { get => (sbyte)Data[0x19]; set => Data[0x19] = (byte)value; } + public override int IV_SPE { get => (sbyte)Data[0x1A]; set => Data[0x1A] = (byte)value; } + + public override int EV_HP { get => (sbyte)Data[0x1B]; set => Data[0x1B] = (byte)value; } + public override int EV_ATK { get => (sbyte)Data[0x1C]; set => Data[0x1C] = (byte)value; } + public override int EV_DEF { get => (sbyte)Data[0x1D]; set => Data[0x1D] = (byte)value; } + public override int EV_SPA { get => (sbyte)Data[0x1E]; set => Data[0x1E] = (byte)value; } + public override int EV_SPD { get => (sbyte)Data[0x1F]; set => Data[0x1F] = (byte)value; } + public override int EV_SPE { get => (sbyte)Data[0x20]; set => Data[0x20] = (byte)value; } + + public int Aura + { + get => Data[0x25]; + set => Data[0x25] = (byte)value; + } + + public int Allies + { + get => Data[0x27]; + set => Data[0x27] = (byte)value; + } + + public int Ally1 + { + get => Data[0x28]; + set => Data[0x28] = (byte)value; + } + + public int Ally2 + { + get => Data[0x2C]; + set => Data[0x2C] = (byte)value; + } + + public override bool IV3 => (sbyte)Data[0x15] < 0 && (sbyte)Data[0x15] + 1 == -3; } diff --git a/pkNX.Structures/Encounter/Gen7/EncounterStatic7b.cs b/pkNX.Structures/Encounter/Gen7/EncounterStatic7b.cs index fd37a29e..3a5ec392 100644 --- a/pkNX.Structures/Encounter/Gen7/EncounterStatic7b.cs +++ b/pkNX.Structures/Encounter/Gen7/EncounterStatic7b.cs @@ -1,110 +1,109 @@ -using System; +using System; using System.Runtime.InteropServices; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class EncounterStatic7b : EncounterStatic { - public sealed class EncounterStatic7b : EncounterStatic + public const int SIZE = 0x40; + public EncounterStatic7b(byte[] data = null) : base(data ?? new byte[SIZE]) { } + + public ulong Hash => BitConverter.ToUInt64(Data, 0); + + public override Species Species { - public const int SIZE = 0x40; - public EncounterStatic7b(byte[] data = null) : base(data ?? new byte[SIZE]) { } + get => (Species)BitConverter.ToUInt16(Data, 0x08); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); + } - public ulong Hash => BitConverter.ToUInt64(Data, 0); + public override int Form { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public override int Level { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } - public override Species Species + public override Shiny Shiny // 0 = 0x3..., 1 = 0x2, 2 = 0x1 + { + get => (Shiny)(Data[0x0C] & 3); + set => Data[0x0C] = (byte)((Data[0x0C] & ~3) | ((byte)value & 3)); + } + + public override FixedGender Gender // 0 = Random, 1 = Male, 2 = Female, 3 = Panic + { + get => (FixedGender)(Data[0x0D] & 3); + set => Data[0x0D] = (byte)((Data[0x0D] & ~3) | ((byte)value & 3)); + } + + public override Nature Nature { get => (Nature)Data[0x0E]; set => Data[0x0E] = (byte)value; } // 25 = random (sets the nature rand to 1) + public override int Ability { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } + + public uint[] Ptrs // 0x10-0x1F -- are these text line references? + { + get => new[] { - get => (Species)BitConverter.ToUInt16(Data, 0x08); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); - } + BitConverter.ToUInt32(Data, 0x10), + BitConverter.ToUInt32(Data, 0x14), + BitConverter.ToUInt32(Data, 0x18), + BitConverter.ToUInt32(Data, 0x1C), + }; + set { } + } - public override int Form { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public override int Level { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } - - public override Shiny Shiny // 0 = 0x3..., 1 = 0x2, 2 = 0x1 + public override int[] RelearnMoves // 0x20-0x27 -- these are actually just moves + { + get => new int[] { - get => (Shiny)(Data[0x0C] & 3); - set => Data[0x0C] = (byte)((Data[0x0C] & ~3) | ((byte)value & 3)); - } - - public override FixedGender Gender // 0 = Random, 1 = Male, 2 = Female, 3 = Panic + BitConverter.ToUInt16(Data, 0x20), + BitConverter.ToUInt16(Data, 0x22), + BitConverter.ToUInt16(Data, 0x24), + BitConverter.ToUInt16(Data, 0x26), + }; + set { - get => (FixedGender)(Data[0x0D] & 3); - set => Data[0x0D] = (byte)((Data[0x0D] & ~3) | ((byte)value & 3)); - } - - public override Nature Nature { get => (Nature)Data[0x0E]; set => Data[0x0E] = (byte)value; } // 25 = random (sets the nature rand to 1) - public override int Ability { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } - - public uint[] Ptrs // 0x10-0x1F -- are these text line references? - { - get => new[] - { - BitConverter.ToUInt32(Data, 0x10), - BitConverter.ToUInt32(Data, 0x14), - BitConverter.ToUInt32(Data, 0x18), - BitConverter.ToUInt32(Data, 0x1C), - }; - set { } - } - - public override int[] RelearnMoves // 0x20-0x27 -- these are actually just moves - { - get => new int[] - { - BitConverter.ToUInt16(Data, 0x20), - BitConverter.ToUInt16(Data, 0x22), - BitConverter.ToUInt16(Data, 0x24), - BitConverter.ToUInt16(Data, 0x26), - }; - set - { - if (value?.Length != 4) - return; - for (int i = 0; i < 4; i++) - BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, 0x20 + (i * 2)); - } - } - - public int V1 - { - get => BitConverter.ToInt16(Data, 0x28); - set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x28); - } - - public int V2 - { - get => BitConverter.ToInt16(Data, 0x2A); - set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x2A); - } - - // 0x2C-0x31 - public override int IV_HP { get => (sbyte)Data[0x2C]; set => Data[0x2C] = (byte)value; } - public override int IV_ATK { get => (sbyte)Data[0x2D]; set => Data[0x2D] = (byte)value; } - public override int IV_DEF { get => (sbyte)Data[0x2E]; set => Data[0x2E] = (byte)value; } - public override int IV_SPA { get => (sbyte)Data[0x2F]; set => Data[0x2F] = (byte)value; } - public override int IV_SPD { get => (sbyte)Data[0x30]; set => Data[0x30] = (byte)value; } - public override int IV_SPE { get => (sbyte)Data[0x31]; set => Data[0x31] = (byte)value; } - - // 0x32-0x37 - public override int EV_HP { get => (sbyte)Data[0x32]; set => Data[0x32] = (byte)value; } - public override int EV_ATK { get => (sbyte)Data[0x33]; set => Data[0x33] = (byte)value; } - public override int EV_DEF { get => (sbyte)Data[0x34]; set => Data[0x34] = (byte)value; } - public override int EV_SPA { get => (sbyte)Data[0x35]; set => Data[0x35] = (byte)value; } - public override int EV_SPD { get => (sbyte)Data[0x36]; set => Data[0x36] = (byte)value; } - public override int EV_SPE { get => (sbyte)Data[0x37]; set => Data[0x37] = (byte)value; } - - // Stat Boost levels/flags - public int Boost_ATK { get => (sbyte)Data[0x38]; set => Data[0x38] = (byte)value; } - public int Boost_DEF { get => (sbyte)Data[0x39]; set => Data[0x39] = (byte)value; } - public int Boost_SPA { get => (sbyte)Data[0x3A]; set => Data[0x3A] = (byte)value; } - public int Boost_SPD { get => (sbyte)Data[0x3B]; set => Data[0x3B] = (byte)value; } - public int Boost_SPE { get => (sbyte)Data[0x3C]; set => Data[0x3C] = (byte)value; } - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)] - public byte[] UnknownFlags; // 0x3D-0x3F - - public string Dump() - { - return $"new EncounterStatic {{ Species = {Species:000}, Level = {Level:00}, Location = -1, Ability = {Ability:0}, Shiny = Shiny.{Shiny} }},"; + if (value?.Length != 4) + return; + for (int i = 0; i < 4; i++) + BitConverter.GetBytes((ushort)value[i]).CopyTo(Data, 0x20 + (i * 2)); } } + + public int V1 + { + get => BitConverter.ToInt16(Data, 0x28); + set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x28); + } + + public int V2 + { + get => BitConverter.ToInt16(Data, 0x2A); + set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x2A); + } + + // 0x2C-0x31 + public override int IV_HP { get => (sbyte)Data[0x2C]; set => Data[0x2C] = (byte)value; } + public override int IV_ATK { get => (sbyte)Data[0x2D]; set => Data[0x2D] = (byte)value; } + public override int IV_DEF { get => (sbyte)Data[0x2E]; set => Data[0x2E] = (byte)value; } + public override int IV_SPA { get => (sbyte)Data[0x2F]; set => Data[0x2F] = (byte)value; } + public override int IV_SPD { get => (sbyte)Data[0x30]; set => Data[0x30] = (byte)value; } + public override int IV_SPE { get => (sbyte)Data[0x31]; set => Data[0x31] = (byte)value; } + + // 0x32-0x37 + public override int EV_HP { get => (sbyte)Data[0x32]; set => Data[0x32] = (byte)value; } + public override int EV_ATK { get => (sbyte)Data[0x33]; set => Data[0x33] = (byte)value; } + public override int EV_DEF { get => (sbyte)Data[0x34]; set => Data[0x34] = (byte)value; } + public override int EV_SPA { get => (sbyte)Data[0x35]; set => Data[0x35] = (byte)value; } + public override int EV_SPD { get => (sbyte)Data[0x36]; set => Data[0x36] = (byte)value; } + public override int EV_SPE { get => (sbyte)Data[0x37]; set => Data[0x37] = (byte)value; } + + // Stat Boost levels/flags + public int Boost_ATK { get => (sbyte)Data[0x38]; set => Data[0x38] = (byte)value; } + public int Boost_DEF { get => (sbyte)Data[0x39]; set => Data[0x39] = (byte)value; } + public int Boost_SPA { get => (sbyte)Data[0x3A]; set => Data[0x3A] = (byte)value; } + public int Boost_SPD { get => (sbyte)Data[0x3B]; set => Data[0x3B] = (byte)value; } + public int Boost_SPE { get => (sbyte)Data[0x3C]; set => Data[0x3C] = (byte)value; } + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x3)] + public byte[] UnknownFlags; // 0x3D-0x3F + + public string Dump() + { + return $"new EncounterStatic {{ Species = {Species:000}, Level = {Level:00}, Location = -1, Ability = {Ability:0}, Shiny = Shiny.{Shiny} }},"; + } } diff --git a/pkNX.Structures/Encounter/Gen7/EncounterTrade7b.cs b/pkNX.Structures/Encounter/Gen7/EncounterTrade7b.cs index c718e867..37b45620 100644 --- a/pkNX.Structures/Encounter/Gen7/EncounterTrade7b.cs +++ b/pkNX.Structures/Encounter/Gen7/EncounterTrade7b.cs @@ -1,156 +1,155 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class EncounterTrade7b : EncounterTrade { - public class EncounterTrade7b : EncounterTrade + public const int SIZE = 0x58; + public EncounterTrade7b(byte[] data = null) : base(data ?? new byte[SIZE]) { } + + // game loops over all trades to find which one is being offered + public ulong HashTradeID => BitConverter.ToUInt64(Data, 0x00); + + public override Species Species { - public const int SIZE = 0x58; - public EncounterTrade7b(byte[] data = null) : base(data ?? new byte[SIZE]) { } - - // game loops over all trades to find which one is being offered - public ulong HashTradeID => BitConverter.ToUInt64(Data, 0x00); - - public override Species Species - { - get => (Species)BitConverter.ToUInt16(Data, 0x08); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); - } - - public override int Form { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public override int Level { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } // minimum level? - - public override Shiny Shiny { get => Shiny.Random; set { } } // Ignored - - // Value randomness - /* val:8 - * unused:7 - * randAny:1 (signed bit) - */ - private int GetIV(int index) - { - var val = BitConverter.ToUInt16(Data, 0xE + (2 * index)); - return val == 0x8000 ? -1 : val; - } - - private void SetIV(int index, int value) - { - if ((uint) value > 31) - value = 0x8000; - BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xE + (2 * index)); - } - - public override int IV_HP { get => GetIV(0); set => SetIV(0, value); } - public override int IV_ATK { get => GetIV(1); set => SetIV(1, value); } - public override int IV_DEF { get => GetIV(2); set => SetIV(2, value); } - public override int IV_SPA { get => GetIV(3); set => SetIV(3, value); } - public override int IV_SPD { get => GetIV(4); set => SetIV(4, value); } - public override int IV_SPE { get => GetIV(5); set => SetIV(5, value); } - - // Value randomness - /* val:8 - * unused:6 - * randUpToVal:1 - * randAny:1 - */ - private int AVP_HP { get => BitConverter.ToInt16(Data, 0x1A); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x1A); } - private int AVP_ATK { get => BitConverter.ToInt16(Data, 0x1C); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x1C); } - private int AVP_DEF { get => BitConverter.ToInt16(Data, 0x1E); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x1E); } - private int AVP_SPA { get => BitConverter.ToInt16(Data, 0x20); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x20); } - private int AVP_SPD { get => BitConverter.ToInt16(Data, 0x22); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x22); } - private int AVP_SPE { get => BitConverter.ToInt16(Data, 0x24); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x24); } - - public int AV_HP { get => AVP_HP & 0xFF; set => AVP_HP = (AVP_HP & 0xFF00) | (byte)value; } - public int AV_ATK { get => AVP_ATK & 0xFF; set => AVP_ATK = (AVP_ATK & 0xFF00) | (byte)value; } - public int AV_DEF { get => AVP_DEF & 0xFF; set => AVP_DEF = (AVP_DEF & 0xFF00) | (byte)value; } - public int AV_SPA { get => AVP_SPA & 0xFF; set => AVP_SPA = (AVP_SPA & 0xFF00) | (byte)value; } - public int AV_SPD { get => AVP_SPD & 0xFF; set => AVP_SPD = (AVP_SPD & 0xFF00) | (byte)value; } - public int AV_SPE { get => AVP_SPE & 0xFF; set => AVP_SPE = (AVP_SPE & 0xFF00) | (byte)value; } - - public bool AV_HPRand { get => AVP_HP == -32768; set => AVP_HP = value ? 0x8000 : AVP_HP & 0x7FFF; } - public bool AV_ATKRand { get => AVP_ATK == -32768; set => AVP_ATK = value ? 0x8000 : AVP_ATK & 0x7FFF; } - public bool AV_DEFRand { get => AVP_DEF == -32768; set => AVP_DEF = value ? 0x8000 : AVP_DEF & 0x7FFF; } - public bool AV_SPARand { get => AVP_SPA == -32768; set => AVP_SPA = value ? 0x8000 : AVP_SPA & 0x7FFF; } - public bool AV_SPDRand { get => AVP_SPD == -32768; set => AVP_SPD = value ? 0x8000 : AVP_SPD & 0x7FFF; } - public bool AV_SPERand { get => AVP_SPE == -32768; set => AVP_SPE = value ? 0x8000 : AVP_SPE & 0x7FFF; } - - public bool AV_HPRandUpTo { get => (AVP_HP & 0x4000) != 0; set => AVP_HP = value ? 0x4000 | (AVP_HP & 0xFF) : AVP_HP & 0xBFFF; } - public bool AV_ATKRandUpTo { get => (AVP_ATK & 0x4000) != 0; set => AVP_ATK = value ? 0x4000 | (AVP_ATK & 0xFF) : AVP_ATK & 0xBFFF; } - public bool AV_DEFRandUpTo { get => (AVP_DEF & 0x4000) != 0; set => AVP_DEF = value ? 0x4000 | (AVP_DEF & 0xFF) : AVP_DEF & 0xBFFF; } - public bool AV_SPARandUpTo { get => (AVP_SPA & 0x4000) != 0; set => AVP_SPA = value ? 0x4000 | (AVP_SPA & 0xFF) : AVP_SPA & 0xBFFF; } - public bool AV_SPDRandUpTo { get => (AVP_SPD & 0x4000) != 0; set => AVP_SPD = value ? 0x4000 | (AVP_SPD & 0xFF) : AVP_SPD & 0xBFFF; } - public bool AV_SPERandUpTo { get => (AVP_SPE & 0x4000) != 0; set => AVP_SPE = value ? 0x4000 | (AVP_SPE & 0xFF) : AVP_SPE & 0xBFFF; } - - public override FixedGender Gender - { - get - { - var val = BitConverter.ToInt16(Data, 0x26); - if (val < 0) - return FixedGender.Random; - return (FixedGender)(val + 1); - } - set - { - if (value == FixedGender.Random) - value = unchecked((FixedGender) 0x8000); - else - value--; - BitConverter.GetBytes((short) value).CopyTo(Data, 0x26); - } - } - - public override Nature Nature - { - get - { - var val = BitConverter.ToInt16(Data, 0x28); - if (val < 0) - return Nature.Random; - return (Nature) val; - } - set - { - if (value == Nature.Random) - value = unchecked((Nature)0x8000); - BitConverter.GetBytes((short) value).CopyTo(Data, 0x28); - } - } - - public int OT_Gender { get => BitConverter.ToInt16(Data, 0x2A); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x2A); } - public uint TrainerID { get => BitConverter.ToUInt32(Data, 0x2C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x2C); } - - public ulong HashTradeStringOTName => BitConverter.ToUInt64(Data, 0x30); - - // 0x38-0x40 are languageIDs to figure out which language to use (do indexOf current save language -> language message file) - - public Species RequiredSpecies - { - get => (Species)BitConverter.ToUInt16(Data, 0x42); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x42); - } - - public int RequiredForm - { - get => BitConverter.ToUInt16(Data, 0x44); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x44); - } - - // what are these? not referenced - public sbyte UV_HP { get => (sbyte)Data[0x46]; set => Data[0x46] = (byte)value; } - public sbyte UV_ATK { get => (sbyte)Data[0x47]; set => Data[0x47] = (byte)value; } - public sbyte UV_DEF { get => (sbyte)Data[0x48]; set => Data[0x48] = (byte)value; } - public sbyte UV_SPA { get => (sbyte)Data[0x49]; set => Data[0x49] = (byte)value; } - public sbyte UV_SPD { get => (sbyte)Data[0x4A]; set => Data[0x4A] = (byte)value; } - public sbyte UV_SPE { get => (sbyte)Data[0x4B]; set => Data[0x4B] = (byte)value; } - - public ulong HashTradeStringNickname => BitConverter.ToUInt64(Data, 0x50); - - public static int Ball => 4; + get => (Species)BitConverter.ToUInt16(Data, 0x08); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } - public enum OptionalTradeValue : short + public override int Form { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public override int Level { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } // minimum level? + + public override Shiny Shiny { get => Shiny.Random; set { } } // Ignored + + // Value randomness + /* val:8 + * unused:7 + * randAny:1 (signed bit) + */ + private int GetIV(int index) { - Random = unchecked((short)0x8000), - RandRange = 0x4000, + var val = BitConverter.ToUInt16(Data, 0xE + (2 * index)); + return val == 0x8000 ? -1 : val; } + + private void SetIV(int index, int value) + { + if ((uint) value > 31) + value = 0x8000; + BitConverter.GetBytes((ushort)value).CopyTo(Data, 0xE + (2 * index)); + } + + public override int IV_HP { get => GetIV(0); set => SetIV(0, value); } + public override int IV_ATK { get => GetIV(1); set => SetIV(1, value); } + public override int IV_DEF { get => GetIV(2); set => SetIV(2, value); } + public override int IV_SPA { get => GetIV(3); set => SetIV(3, value); } + public override int IV_SPD { get => GetIV(4); set => SetIV(4, value); } + public override int IV_SPE { get => GetIV(5); set => SetIV(5, value); } + + // Value randomness + /* val:8 + * unused:6 + * randUpToVal:1 + * randAny:1 + */ + private int AVP_HP { get => BitConverter.ToInt16(Data, 0x1A); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x1A); } + private int AVP_ATK { get => BitConverter.ToInt16(Data, 0x1C); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x1C); } + private int AVP_DEF { get => BitConverter.ToInt16(Data, 0x1E); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x1E); } + private int AVP_SPA { get => BitConverter.ToInt16(Data, 0x20); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x20); } + private int AVP_SPD { get => BitConverter.ToInt16(Data, 0x22); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x22); } + private int AVP_SPE { get => BitConverter.ToInt16(Data, 0x24); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x24); } + + public int AV_HP { get => AVP_HP & 0xFF; set => AVP_HP = (AVP_HP & 0xFF00) | (byte)value; } + public int AV_ATK { get => AVP_ATK & 0xFF; set => AVP_ATK = (AVP_ATK & 0xFF00) | (byte)value; } + public int AV_DEF { get => AVP_DEF & 0xFF; set => AVP_DEF = (AVP_DEF & 0xFF00) | (byte)value; } + public int AV_SPA { get => AVP_SPA & 0xFF; set => AVP_SPA = (AVP_SPA & 0xFF00) | (byte)value; } + public int AV_SPD { get => AVP_SPD & 0xFF; set => AVP_SPD = (AVP_SPD & 0xFF00) | (byte)value; } + public int AV_SPE { get => AVP_SPE & 0xFF; set => AVP_SPE = (AVP_SPE & 0xFF00) | (byte)value; } + + public bool AV_HPRand { get => AVP_HP == -32768; set => AVP_HP = value ? 0x8000 : AVP_HP & 0x7FFF; } + public bool AV_ATKRand { get => AVP_ATK == -32768; set => AVP_ATK = value ? 0x8000 : AVP_ATK & 0x7FFF; } + public bool AV_DEFRand { get => AVP_DEF == -32768; set => AVP_DEF = value ? 0x8000 : AVP_DEF & 0x7FFF; } + public bool AV_SPARand { get => AVP_SPA == -32768; set => AVP_SPA = value ? 0x8000 : AVP_SPA & 0x7FFF; } + public bool AV_SPDRand { get => AVP_SPD == -32768; set => AVP_SPD = value ? 0x8000 : AVP_SPD & 0x7FFF; } + public bool AV_SPERand { get => AVP_SPE == -32768; set => AVP_SPE = value ? 0x8000 : AVP_SPE & 0x7FFF; } + + public bool AV_HPRandUpTo { get => (AVP_HP & 0x4000) != 0; set => AVP_HP = value ? 0x4000 | (AVP_HP & 0xFF) : AVP_HP & 0xBFFF; } + public bool AV_ATKRandUpTo { get => (AVP_ATK & 0x4000) != 0; set => AVP_ATK = value ? 0x4000 | (AVP_ATK & 0xFF) : AVP_ATK & 0xBFFF; } + public bool AV_DEFRandUpTo { get => (AVP_DEF & 0x4000) != 0; set => AVP_DEF = value ? 0x4000 | (AVP_DEF & 0xFF) : AVP_DEF & 0xBFFF; } + public bool AV_SPARandUpTo { get => (AVP_SPA & 0x4000) != 0; set => AVP_SPA = value ? 0x4000 | (AVP_SPA & 0xFF) : AVP_SPA & 0xBFFF; } + public bool AV_SPDRandUpTo { get => (AVP_SPD & 0x4000) != 0; set => AVP_SPD = value ? 0x4000 | (AVP_SPD & 0xFF) : AVP_SPD & 0xBFFF; } + public bool AV_SPERandUpTo { get => (AVP_SPE & 0x4000) != 0; set => AVP_SPE = value ? 0x4000 | (AVP_SPE & 0xFF) : AVP_SPE & 0xBFFF; } + + public override FixedGender Gender + { + get + { + var val = BitConverter.ToInt16(Data, 0x26); + if (val < 0) + return FixedGender.Random; + return (FixedGender)(val + 1); + } + set + { + if (value == FixedGender.Random) + value = unchecked((FixedGender) 0x8000); + else + value--; + BitConverter.GetBytes((short) value).CopyTo(Data, 0x26); + } + } + + public override Nature Nature + { + get + { + var val = BitConverter.ToInt16(Data, 0x28); + if (val < 0) + return Nature.Random; + return (Nature) val; + } + set + { + if (value == Nature.Random) + value = unchecked((Nature)0x8000); + BitConverter.GetBytes((short) value).CopyTo(Data, 0x28); + } + } + + public int OT_Gender { get => BitConverter.ToInt16(Data, 0x2A); set => BitConverter.GetBytes((short)value).CopyTo(Data, 0x2A); } + public uint TrainerID { get => BitConverter.ToUInt32(Data, 0x2C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x2C); } + + public ulong HashTradeStringOTName => BitConverter.ToUInt64(Data, 0x30); + + // 0x38-0x40 are languageIDs to figure out which language to use (do indexOf current save language -> language message file) + + public Species RequiredSpecies + { + get => (Species)BitConverter.ToUInt16(Data, 0x42); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x42); + } + + public int RequiredForm + { + get => BitConverter.ToUInt16(Data, 0x44); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x44); + } + + // what are these? not referenced + public sbyte UV_HP { get => (sbyte)Data[0x46]; set => Data[0x46] = (byte)value; } + public sbyte UV_ATK { get => (sbyte)Data[0x47]; set => Data[0x47] = (byte)value; } + public sbyte UV_DEF { get => (sbyte)Data[0x48]; set => Data[0x48] = (byte)value; } + public sbyte UV_SPA { get => (sbyte)Data[0x49]; set => Data[0x49] = (byte)value; } + public sbyte UV_SPD { get => (sbyte)Data[0x4A]; set => Data[0x4A] = (byte)value; } + public sbyte UV_SPE { get => (sbyte)Data[0x4B]; set => Data[0x4B] = (byte)value; } + + public ulong HashTradeStringNickname => BitConverter.ToUInt64(Data, 0x50); + + public static int Ball => 4; +} + +public enum OptionalTradeValue : short +{ + Random = unchecked((short)0x8000), + RandRange = 0x4000, } diff --git a/pkNX.Structures/Encounter/Nature.cs b/pkNX.Structures/Encounter/Nature.cs index 31e0a3b2..65be0669 100644 --- a/pkNX.Structures/Encounter/Nature.cs +++ b/pkNX.Structures/Encounter/Nature.cs @@ -1,39 +1,38 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum Nature : sbyte { - public enum Nature : sbyte - { - Random = -1, + Random = -1, - Hardy, - Lonely, - Brave, - Adamant, - Naughty, - Bold, + Hardy, + Lonely, + Brave, + Adamant, + Naughty, + Bold, - Docile, - Relaxed, - Impish, - Lax, - Timid, - Hasty, + Docile, + Relaxed, + Impish, + Lax, + Timid, + Hasty, - Serious, - Jolly, - Naive, - Modest, - Mild, - Quiet, + Serious, + Jolly, + Naive, + Modest, + Mild, + Quiet, - Bashful, - Rash, - Calm, - Gentle, - Sassy, - Careful, + Bashful, + Rash, + Calm, + Gentle, + Sassy, + Careful, - Quirky, + Quirky, - Random25 = 25, - } + Random25 = 25, } diff --git a/pkNX.Structures/Encounter/Shiny.cs b/pkNX.Structures/Encounter/Shiny.cs index 1245a7e1..bdde7d82 100644 --- a/pkNX.Structures/Encounter/Shiny.cs +++ b/pkNX.Structures/Encounter/Shiny.cs @@ -1,20 +1,19 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum Shiny : byte { - public enum Shiny : byte - { - /// - /// PID is purely random; can be shiny or not shiny. - /// - Random = 0, + /// + /// PID is purely random; can be shiny or not shiny. + /// + Random = 0, - /// - /// PID is randomly created and forced to be shiny. - /// - Always = 1, + /// + /// PID is randomly created and forced to be shiny. + /// + Always = 1, - /// - /// PID is randomly created and forced to be not shiny. - /// - Never = 2, - } -} \ No newline at end of file + /// + /// PID is randomly created and forced to be not shiny. + /// + Never = 2, +} diff --git a/pkNX.Structures/Evolution/EvolutionMethod.cs b/pkNX.Structures/Evolution/EvolutionMethod.cs index 18049771..2c7fbfd5 100644 --- a/pkNX.Structures/Evolution/EvolutionMethod.cs +++ b/pkNX.Structures/Evolution/EvolutionMethod.cs @@ -1,66 +1,65 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Criteria for evolving to this branch in the +/// +/// Evolution Method +/// Evolve to Species +/// Destination Form +/// Conditional Argument (different from ) +/// Conditional Argument (different from ) +/// Indicates if a level up is required to trigger evolution. +public class EvolutionMethod { - /// - /// Criteria for evolving to this branch in the - /// - /// Evolution Method - /// Evolve to Species - /// Destination Form - /// Conditional Argument (different from ) - /// Conditional Argument (different from ) - /// Indicates if a level up is required to trigger evolution. - public class EvolutionMethod + public EvolutionMethod Copy(int species = -1) { - public EvolutionMethod Copy(int species = -1) + if (species < 0) + species = Species; + + return new EvolutionMethod { - if (species < 0) - species = Species; - - return new EvolutionMethod - { - Method = Method, - Species = (ushort)species, - Form = Form, - Argument = Argument, - Level = Level - }; - } - - public bool HasData => Species != 0; - - /// Evolve to Species - public ushort Species { get; set; } - - /// Conditional Argument (different from ) - public ushort Argument { get; set; } - - /// Evolution Method - public EvolutionType Method { get; set; } - - /// Destination Form - public byte Form { get; set; } - - /// Conditional Argument (different from ) - public byte Level { get; set; } - - public override string ToString() => $"{(Species)Species}-{Form} [{Argument}] @ {Level}{(RequiresLevelUp ? "X" : "")}"; - - /// Is if the evolved form isn't modified. Special consideration for , which forces 1. - private const byte AnyForm = byte.MaxValue; - - public bool RequiresLevelUp => Method.IsLevelUpRequired(); - - /// - /// Returns the form that the Pokémon will have after evolution. - /// - /// Un-evolved Form ID - public byte GetDestinationForm(byte form) - { - if (Method == EvolutionType.LevelUpFormFemale1) - return 1; - if (Form == AnyForm) - return form; - return Form; - } + Method = Method, + Species = (ushort)species, + Form = Form, + Argument = Argument, + Level = Level + }; } -} \ No newline at end of file + + public bool HasData => Species != 0; + + /// Evolve to Species + public ushort Species { get; set; } + + /// Conditional Argument (different from ) + public ushort Argument { get; set; } + + /// Evolution Method + public EvolutionType Method { get; set; } + + /// Destination Form + public byte Form { get; set; } + + /// Conditional Argument (different from ) + public byte Level { get; set; } + + public override string ToString() => $"{(Species)Species}-{Form} [{Argument}] @ {Level}{(RequiresLevelUp ? "X" : "")}"; + + /// Is if the evolved form isn't modified. Special consideration for , which forces 1. + private const byte AnyForm = byte.MaxValue; + + public bool RequiresLevelUp => Method.IsLevelUpRequired(); + + /// + /// Returns the form that the Pokémon will have after evolution. + /// + /// Un-evolved Form ID + public byte GetDestinationForm(byte form) + { + if (Method == EvolutionType.LevelUpFormFemale1) + return 1; + if (Form == AnyForm) + return form; + return Form; + } +} diff --git a/pkNX.Structures/Evolution/EvolutionSet.cs b/pkNX.Structures/Evolution/EvolutionSet.cs index 661393ea..eefeeca1 100644 --- a/pkNX.Structures/Evolution/EvolutionSet.cs +++ b/pkNX.Structures/Evolution/EvolutionSet.cs @@ -1,15 +1,14 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Table of Evolution Branch Entries +/// +public abstract class EvolutionSet { - /// - /// Table of Evolution Branch Entries - /// - public abstract class EvolutionSet - { - public EvolutionMethod[] PossibleEvolutions; - public abstract byte[] Write(); + public EvolutionMethod[] PossibleEvolutions; + public abstract byte[] Write(); - protected EvolutionSet() => PossibleEvolutions = Array.Empty(); - } + protected EvolutionSet() => PossibleEvolutions = Array.Empty(); } diff --git a/pkNX.Structures/Evolution/EvolutionSet6.cs b/pkNX.Structures/Evolution/EvolutionSet6.cs index c7dafcdc..30162a85 100644 --- a/pkNX.Structures/Evolution/EvolutionSet6.cs +++ b/pkNX.Structures/Evolution/EvolutionSet6.cs @@ -1,53 +1,52 @@ -using System; +using System; using System.Collections.Generic; using System.IO; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Generation 6 Evolution Branch Entries +/// +public class EvolutionSet6 : EvolutionSet { - /// - /// Generation 6 Evolution Branch Entries - /// - public class EvolutionSet6 : EvolutionSet + private const int ENTRY_SIZE = 6; + private const int ENTRY_COUNT = 8; + public const int SIZE = ENTRY_COUNT * ENTRY_SIZE; + private static readonly HashSet argEvos = new() { 6, 8, 16, 17, 18, 19, 20, 21, 22, 29, 30, 32, 33, 34 }; + + public EvolutionSet6(byte[] data) { - private const int ENTRY_SIZE = 6; - private const int ENTRY_COUNT = 8; - public const int SIZE = ENTRY_COUNT * ENTRY_SIZE; - private static readonly HashSet argEvos = new() { 6, 8, 16, 17, 18, 19, 20, 21, 22, 29, 30, 32, 33, 34 }; - - public EvolutionSet6(byte[] data) - { - if (data.Length != SIZE) - return; - PossibleEvolutions = data.GetArray(GetEvo, SIZE); - } - - private static EvolutionMethod GetEvo(byte[] data, int offset) - { - var method = (EvolutionType)BitConverter.ToUInt16(data, offset + 0); - var level = (byte)BitConverter.ToUInt16(data, offset + 2); - - var evo = new EvolutionMethod - { - Method = method, - Argument = (argEvos.Contains((int)method) ? (byte)0 : level), // Argument is used by both Level argument and Item/Move/etc. Clear if appropriate. - Species = BitConverter.ToUInt16(data, offset + 4), - Level = level, - }; - - return evo; - } - - public override byte[] Write() - { - using MemoryStream ms = new MemoryStream(); - using BinaryWriter bw = new BinaryWriter(ms); - foreach (EvolutionMethod evo in PossibleEvolutions) - { - bw.Write((ushort)evo.Method); - bw.Write((ushort)evo.Argument); - bw.Write((ushort)evo.Species); - } - return ms.ToArray(); - } + if (data.Length != SIZE) + return; + PossibleEvolutions = data.GetArray(GetEvo, SIZE); } -} \ No newline at end of file + + private static EvolutionMethod GetEvo(byte[] data, int offset) + { + var method = (EvolutionType)BitConverter.ToUInt16(data, offset + 0); + var level = (byte)BitConverter.ToUInt16(data, offset + 2); + + var evo = new EvolutionMethod + { + Method = method, + Argument = (argEvos.Contains((int)method) ? (byte)0 : level), // Argument is used by both Level argument and Item/Move/etc. Clear if appropriate. + Species = BitConverter.ToUInt16(data, offset + 4), + Level = level, + }; + + return evo; + } + + public override byte[] Write() + { + using MemoryStream ms = new MemoryStream(); + using BinaryWriter bw = new BinaryWriter(ms); + foreach (EvolutionMethod evo in PossibleEvolutions) + { + bw.Write((ushort)evo.Method); + bw.Write((ushort)evo.Argument); + bw.Write((ushort)evo.Species); + } + return ms.ToArray(); + } +} diff --git a/pkNX.Structures/Evolution/EvolutionSet7.cs b/pkNX.Structures/Evolution/EvolutionSet7.cs index 6f940b0e..5dedd3d3 100644 --- a/pkNX.Structures/Evolution/EvolutionSet7.cs +++ b/pkNX.Structures/Evolution/EvolutionSet7.cs @@ -3,65 +3,64 @@ using System.IO; using static System.Buffers.Binary.BinaryPrimitives; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class EvolutionSet7 : EvolutionSet { - public class EvolutionSet7 : EvolutionSet + private const int ENTRY_SIZE = 8; + public const int MAX_ENTRY_COUNT = 8; + public const int SIZE = MAX_ENTRY_COUNT * ENTRY_SIZE; + + public EvolutionSet7(ReadOnlySpan data) { - private const int ENTRY_SIZE = 8; - public const int MAX_ENTRY_COUNT = 8; - public const int SIZE = MAX_ENTRY_COUNT * ENTRY_SIZE; - - public EvolutionSet7(ReadOnlySpan data) - { - if (data.Length != SIZE) - return; - PossibleEvolutions = data.GetArray(ReadEvolution, ENTRY_SIZE); - } - - public override byte[] Write() - { - using MemoryStream ms = new(); - using BinaryWriter bw = new(ms); - foreach (EvolutionMethod evo in PossibleEvolutions) - { - bw.Write((ushort)evo.Method); - bw.Write((ushort)evo.Argument); - bw.Write((ushort)evo.Species); - bw.Write((sbyte)evo.Form); - bw.Write((byte)evo.Level); - } - return ms.ToArray(); - } - - private static EvolutionMethod ReadEvolution(ReadOnlySpan entry) - { - return new() - { - Method = (EvolutionType)entry[0], - Argument = ReadUInt16LittleEndian(entry[2..]), - Species = ReadUInt16LittleEndian(entry[4..]), - Form = SByteToByte((sbyte)entry[6]), - Level = entry[7] - }; - } - - public static IReadOnlyList GetArray(BinLinkerAccessor data) - { - var evos = new EvolutionMethod[data.Length][]; - for (int i = 0; i < evos.Length; i++) - evos[i] = data[i].GetArray(ReadEvolution, ENTRY_SIZE); - return evos; - } - - /// - /// For evo set 7 sbyte is used for form, -1 means no forms are present. - /// The remaining code expects to work with 0 for all base forms. - /// This clamps the sbyte range to 0<>128, removing the negative range. - /// - private static byte SByteToByte(sbyte b) - { - return (byte)Math.Max(b, (sbyte)0); - } - + if (data.Length != SIZE) + return; + PossibleEvolutions = data.GetArray(ReadEvolution, ENTRY_SIZE); } -} \ No newline at end of file + + public override byte[] Write() + { + using MemoryStream ms = new(); + using BinaryWriter bw = new(ms); + foreach (EvolutionMethod evo in PossibleEvolutions) + { + bw.Write((ushort)evo.Method); + bw.Write((ushort)evo.Argument); + bw.Write((ushort)evo.Species); + bw.Write((sbyte)evo.Form); + bw.Write((byte)evo.Level); + } + return ms.ToArray(); + } + + private static EvolutionMethod ReadEvolution(ReadOnlySpan entry) + { + return new() + { + Method = (EvolutionType)entry[0], + Argument = ReadUInt16LittleEndian(entry[2..]), + Species = ReadUInt16LittleEndian(entry[4..]), + Form = SByteToByte((sbyte)entry[6]), + Level = entry[7] + }; + } + + public static IReadOnlyList GetArray(BinLinkerAccessor data) + { + var evos = new EvolutionMethod[data.Length][]; + for (int i = 0; i < evos.Length; i++) + evos[i] = data[i].GetArray(ReadEvolution, ENTRY_SIZE); + return evos; + } + + /// + /// For evo set 7 sbyte is used for form, -1 means no forms are present. + /// The remaining code expects to work with 0 for all base forms. + /// This clamps the sbyte range to 0<>128, removing the negative range. + /// + private static byte SByteToByte(sbyte b) + { + return (byte)Math.Max(b, (sbyte)0); + } + +} diff --git a/pkNX.Structures/Evolution/EvolutionSet8.cs b/pkNX.Structures/Evolution/EvolutionSet8.cs index e7df3e9e..bee28deb 100644 --- a/pkNX.Structures/Evolution/EvolutionSet8.cs +++ b/pkNX.Structures/Evolution/EvolutionSet8.cs @@ -3,54 +3,53 @@ using System.IO; using static System.Buffers.Binary.BinaryPrimitives; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class EvolutionSet8 : EvolutionSet { - public class EvolutionSet8 : EvolutionSet + private const int ENTRY_SIZE = 8; + public const int MAX_ENTRY_COUNT = 9; + public const int SIZE = MAX_ENTRY_COUNT * ENTRY_SIZE; + + public EvolutionSet8(ReadOnlySpan data) { - private const int ENTRY_SIZE = 8; - public const int MAX_ENTRY_COUNT = 9; - public const int SIZE = MAX_ENTRY_COUNT * ENTRY_SIZE; - - public EvolutionSet8(ReadOnlySpan data) - { - if (data.Length != SIZE) - return; - PossibleEvolutions = data.GetArray(ReadEvolution, ENTRY_SIZE); - } - - public override byte[] Write() - { - using MemoryStream ms = new(); - using BinaryWriter bw = new(ms); - foreach (EvolutionMethod evo in PossibleEvolutions) - { - bw.Write((ushort)evo.Method); - bw.Write((ushort)evo.Argument); - bw.Write((ushort)evo.Species); - bw.Write((sbyte)evo.Form); - bw.Write((byte)evo.Level); - } - return ms.ToArray(); - } - - private static EvolutionMethod ReadEvolution(ReadOnlySpan entry) - { - return new() - { - Method = (EvolutionType)ReadUInt16LittleEndian(entry[0..]), - Argument = ReadUInt16LittleEndian(entry[2..]), - Species = ReadUInt16LittleEndian(entry[4..]), - Form = entry[6], - Level = entry[7] - }; - } - - public static IReadOnlyList GetArray(BinLinkerAccessor data) - { - var evos = new EvolutionMethod[data.Length][]; - for (int i = 0; i < evos.Length; i++) - evos[i] = data[i].GetArray(ReadEvolution, ENTRY_SIZE); - return evos; - } + if (data.Length != SIZE) + return; + PossibleEvolutions = data.GetArray(ReadEvolution, ENTRY_SIZE); } -} \ No newline at end of file + + public override byte[] Write() + { + using MemoryStream ms = new(); + using BinaryWriter bw = new(ms); + foreach (EvolutionMethod evo in PossibleEvolutions) + { + bw.Write((ushort)evo.Method); + bw.Write((ushort)evo.Argument); + bw.Write((ushort)evo.Species); + bw.Write((sbyte)evo.Form); + bw.Write((byte)evo.Level); + } + return ms.ToArray(); + } + + private static EvolutionMethod ReadEvolution(ReadOnlySpan entry) + { + return new() + { + Method = (EvolutionType)ReadUInt16LittleEndian(entry[0..]), + Argument = ReadUInt16LittleEndian(entry[2..]), + Species = ReadUInt16LittleEndian(entry[4..]), + Form = entry[6], + Level = entry[7] + }; + } + + public static IReadOnlyList GetArray(BinLinkerAccessor data) + { + var evos = new EvolutionMethod[data.Length][]; + for (int i = 0; i < evos.Length; i++) + evos[i] = data[i].GetArray(ReadEvolution, ENTRY_SIZE); + return evos; + } +} diff --git a/pkNX.Structures/Evolution/EvolutionType.cs b/pkNX.Structures/Evolution/EvolutionType.cs index 57b47aa5..317708ef 100644 --- a/pkNX.Structures/Evolution/EvolutionType.cs +++ b/pkNX.Structures/Evolution/EvolutionType.cs @@ -1,209 +1,207 @@ -using System.Diagnostics; using System; using static pkNX.Structures.EvolutionType; using static pkNX.Structures.EvolutionTypeArgumentType; using System.Collections.Generic; -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum EvolutionType : byte { - public enum EvolutionType : byte - { - None = 0, - LevelUpFriendship = 1, - LevelUpFriendshipMorning = 2, - LevelUpFriendshipNight = 3, - LevelUp = 4, - Trade = 5, - TradeHeldItem = 6, - TradeShelmetKarrablast = 7, - UseItem = 8, - LevelUpATK = 9, - LevelUpAeqD = 10, - LevelUpDEF = 11, - LevelUpECl5 = 12, - LevelUpECgeq5 = 13, - LevelUpNinjask = 14, - LevelUpShedinja = 15, - LevelUpBeauty = 16, - UseItemMale = 17, - UseItemFemale = 18, - LevelUpHeldItemDay = 19, - LevelUpHeldItemNight = 20, - LevelUpKnowMove = 21, - LevelUpWithTeammate = 22, - LevelUpMale = 23, - LevelUpFemale = 24, - LevelUpElectric = 25, - LevelUpForest = 26, - LevelUpCold = 27, - LevelUpInverted = 28, - LevelUpAffection50MoveType = 29, - LevelUpMoveType = 30, - LevelUpWeather = 31, - LevelUpMorning = 32, - LevelUpNight = 33, - LevelUpFormFemale1 = 34, - UNUSED = 35, - LevelUpVersion = 36, - LevelUpVersionDay = 37, - LevelUpVersionNight = 38, - LevelUpSummit = 39, - LevelUpDusk = 40, - LevelUpWormhole = 41, - UseItemWormhole = 42, - CriticalHitsInBattle = 43, // Sirfetch'd - HitPointsLostInBattle = 44, // Runerigus - Spin = 45, // Alcremie - LevelUpNatureAmped = 46, // Toxtricity - LevelUpNatureLowKey = 47, // Toxtricity - TowerOfDarkness = 48, // Urshifu - TowerOfWaters = 49, // Urshifu - UseItemFullMoon = 50, // Ursaluna - UseAgileStyleMoves = 51, // Wyrdeer - UseStrongStyleMoves = 52, // Overqwil - RecoilDamageMale = 53, // Basculegion-0 - RecoilDamageFemale = 54, // Basculegion-1 - } - - public enum EvolutionTypeArgumentType - { - NoArg, - Level, - Items, - Moves, - Species, - Stat, - Type, - Version, - } - - public static class EvolutionTypeExtensions - { - public static bool IsTrade(this EvolutionType t) => t is Trade or TradeHeldItem or TradeShelmetKarrablast; - - public static bool IsLevelUpRequired(this EvolutionType type) => type switch - { - None => false, - LevelUpFriendship => true, - LevelUpFriendshipMorning => true, - LevelUpFriendshipNight => true, - LevelUp => true, - Trade => false, - TradeHeldItem => false, - TradeShelmetKarrablast => false, - UseItem => false, - LevelUpATK => true, - LevelUpAeqD => true, - LevelUpDEF => true, - LevelUpECl5 => true, - LevelUpECgeq5 => true, - LevelUpNinjask => true, - LevelUpShedinja => true, - LevelUpBeauty => true, - UseItemMale => false, - UseItemFemale => false, - LevelUpHeldItemDay => true, - LevelUpHeldItemNight => true, - LevelUpKnowMove => true, - LevelUpWithTeammate => true, - LevelUpMale => true, - LevelUpFemale => true, - LevelUpElectric => true, - LevelUpForest => true, - LevelUpCold => true, - LevelUpInverted => true, - LevelUpAffection50MoveType => true, - LevelUpMoveType => true, - LevelUpWeather => true, - LevelUpMorning => true, - LevelUpNight => true, - LevelUpFormFemale1 => true, - UNUSED => false, - LevelUpVersion => true, - LevelUpVersionDay => true, - LevelUpVersionNight => true, - LevelUpSummit => true, - LevelUpDusk => true, - LevelUpWormhole => true, - UseItemWormhole => false, - CriticalHitsInBattle => false, - HitPointsLostInBattle => false, - Spin => false, - LevelUpNatureAmped => true, - LevelUpNatureLowKey => true, - TowerOfDarkness => false, - TowerOfWaters => false, - UseItemFullMoon => false, - UseAgileStyleMoves => false, - UseStrongStyleMoves => false, - RecoilDamageMale => false, - RecoilDamageFemale => false, - _ => throw new ArgumentOutOfRangeException(nameof(type), type, null), - }; - - private static readonly Dictionary ArgType = new() - { - [None] = NoArg, - [LevelUpFriendship] = NoArg, - [LevelUpFriendshipMorning] = NoArg, - [LevelUpFriendshipNight] = NoArg, - [LevelUp] = Level, - [Trade] = NoArg, - [TradeHeldItem] = Items, - [TradeShelmetKarrablast] = NoArg, - [UseItem] = Items, - - [LevelUpATK] = Level, - [LevelUpAeqD] = Level, - [LevelUpDEF] = Level, - [LevelUpECl5] = Level, - [LevelUpECgeq5] = Level, - [LevelUpNinjask] = Level, - [LevelUpShedinja] = Level, - [LevelUpBeauty] = Stat, - - [UseItemMale] = Items, - [UseItemFemale] = Items, - [LevelUpHeldItemDay] = Items, - [LevelUpHeldItemNight] = Items, - [LevelUpKnowMove] = Moves, - [LevelUpWithTeammate] = EvolutionTypeArgumentType.Species, - [LevelUpMale] = Level, - [LevelUpFemale] = Level, - [LevelUpElectric] = NoArg, - [LevelUpForest] = NoArg, - [LevelUpCold] = NoArg, - [LevelUpInverted] = NoArg, - [LevelUpAffection50MoveType] = EvolutionTypeArgumentType.Type, - - [LevelUpMoveType] = EvolutionTypeArgumentType.Type, - [LevelUpWeather] = Level, - [LevelUpMorning] = Level, - [LevelUpNight] = Level, - [LevelUpFormFemale1] = Level, - [UNUSED] = NoArg, - [LevelUpVersion] = EvolutionTypeArgumentType.Version, - [LevelUpVersionDay] = EvolutionTypeArgumentType.Version, - [LevelUpVersionNight] = EvolutionTypeArgumentType.Version, - [LevelUpSummit] = Level, - [LevelUpDusk] = Level, - [LevelUpWormhole] = Level, - [UseItemWormhole] = Items, - - [CriticalHitsInBattle] = EvolutionTypeArgumentType.Version, - [HitPointsLostInBattle] = EvolutionTypeArgumentType.Version, - [Spin] = NoArg, - [LevelUpNatureAmped] = NoArg, - [LevelUpNatureLowKey] = NoArg, - [TowerOfDarkness] = NoArg, - [TowerOfWaters] = NoArg, - [UseItemFullMoon] = Items, // Ursaluna - [UseAgileStyleMoves] = NoArg, // Wyrdeer - [UseStrongStyleMoves] = NoArg, // Overqwil - [RecoilDamageMale] = NoArg, // Basculegion-0 - [RecoilDamageFemale] = NoArg, // Basculegion-1 - }; - - public static EvolutionTypeArgumentType GetArgType(this EvolutionType t) => ArgType[t]; - } + None = 0, + LevelUpFriendship = 1, + LevelUpFriendshipMorning = 2, + LevelUpFriendshipNight = 3, + LevelUp = 4, + Trade = 5, + TradeHeldItem = 6, + TradeShelmetKarrablast = 7, + UseItem = 8, + LevelUpATK = 9, + LevelUpAeqD = 10, + LevelUpDEF = 11, + LevelUpECl5 = 12, + LevelUpECgeq5 = 13, + LevelUpNinjask = 14, + LevelUpShedinja = 15, + LevelUpBeauty = 16, + UseItemMale = 17, + UseItemFemale = 18, + LevelUpHeldItemDay = 19, + LevelUpHeldItemNight = 20, + LevelUpKnowMove = 21, + LevelUpWithTeammate = 22, + LevelUpMale = 23, + LevelUpFemale = 24, + LevelUpElectric = 25, + LevelUpForest = 26, + LevelUpCold = 27, + LevelUpInverted = 28, + LevelUpAffection50MoveType = 29, + LevelUpMoveType = 30, + LevelUpWeather = 31, + LevelUpMorning = 32, + LevelUpNight = 33, + LevelUpFormFemale1 = 34, + UNUSED = 35, + LevelUpVersion = 36, + LevelUpVersionDay = 37, + LevelUpVersionNight = 38, + LevelUpSummit = 39, + LevelUpDusk = 40, + LevelUpWormhole = 41, + UseItemWormhole = 42, + CriticalHitsInBattle = 43, // Sirfetch'd + HitPointsLostInBattle = 44, // Runerigus + Spin = 45, // Alcremie + LevelUpNatureAmped = 46, // Toxtricity + LevelUpNatureLowKey = 47, // Toxtricity + TowerOfDarkness = 48, // Urshifu + TowerOfWaters = 49, // Urshifu + UseItemFullMoon = 50, // Ursaluna + UseAgileStyleMoves = 51, // Wyrdeer + UseStrongStyleMoves = 52, // Overqwil + RecoilDamageMale = 53, // Basculegion-0 + RecoilDamageFemale = 54, // Basculegion-1 +} + +public enum EvolutionTypeArgumentType +{ + NoArg, + Level, + Items, + Moves, + Species, + Stat, + Type, + Version, +} + +public static class EvolutionTypeExtensions +{ + public static bool IsTrade(this EvolutionType t) => t is Trade or TradeHeldItem or TradeShelmetKarrablast; + + public static bool IsLevelUpRequired(this EvolutionType type) => type switch + { + None => false, + LevelUpFriendship => true, + LevelUpFriendshipMorning => true, + LevelUpFriendshipNight => true, + LevelUp => true, + Trade => false, + TradeHeldItem => false, + TradeShelmetKarrablast => false, + UseItem => false, + LevelUpATK => true, + LevelUpAeqD => true, + LevelUpDEF => true, + LevelUpECl5 => true, + LevelUpECgeq5 => true, + LevelUpNinjask => true, + LevelUpShedinja => true, + LevelUpBeauty => true, + UseItemMale => false, + UseItemFemale => false, + LevelUpHeldItemDay => true, + LevelUpHeldItemNight => true, + LevelUpKnowMove => true, + LevelUpWithTeammate => true, + LevelUpMale => true, + LevelUpFemale => true, + LevelUpElectric => true, + LevelUpForest => true, + LevelUpCold => true, + LevelUpInverted => true, + LevelUpAffection50MoveType => true, + LevelUpMoveType => true, + LevelUpWeather => true, + LevelUpMorning => true, + LevelUpNight => true, + LevelUpFormFemale1 => true, + UNUSED => false, + LevelUpVersion => true, + LevelUpVersionDay => true, + LevelUpVersionNight => true, + LevelUpSummit => true, + LevelUpDusk => true, + LevelUpWormhole => true, + UseItemWormhole => false, + CriticalHitsInBattle => false, + HitPointsLostInBattle => false, + Spin => false, + LevelUpNatureAmped => true, + LevelUpNatureLowKey => true, + TowerOfDarkness => false, + TowerOfWaters => false, + UseItemFullMoon => false, + UseAgileStyleMoves => false, + UseStrongStyleMoves => false, + RecoilDamageMale => false, + RecoilDamageFemale => false, + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null), + }; + + private static readonly Dictionary ArgType = new() + { + [None] = NoArg, + [LevelUpFriendship] = NoArg, + [LevelUpFriendshipMorning] = NoArg, + [LevelUpFriendshipNight] = NoArg, + [LevelUp] = Level, + [Trade] = NoArg, + [TradeHeldItem] = Items, + [TradeShelmetKarrablast] = NoArg, + [UseItem] = Items, + + [LevelUpATK] = Level, + [LevelUpAeqD] = Level, + [LevelUpDEF] = Level, + [LevelUpECl5] = Level, + [LevelUpECgeq5] = Level, + [LevelUpNinjask] = Level, + [LevelUpShedinja] = Level, + [LevelUpBeauty] = Stat, + + [UseItemMale] = Items, + [UseItemFemale] = Items, + [LevelUpHeldItemDay] = Items, + [LevelUpHeldItemNight] = Items, + [LevelUpKnowMove] = Moves, + [LevelUpWithTeammate] = EvolutionTypeArgumentType.Species, + [LevelUpMale] = Level, + [LevelUpFemale] = Level, + [LevelUpElectric] = NoArg, + [LevelUpForest] = NoArg, + [LevelUpCold] = NoArg, + [LevelUpInverted] = NoArg, + [LevelUpAffection50MoveType] = EvolutionTypeArgumentType.Type, + + [LevelUpMoveType] = EvolutionTypeArgumentType.Type, + [LevelUpWeather] = Level, + [LevelUpMorning] = Level, + [LevelUpNight] = Level, + [LevelUpFormFemale1] = Level, + [UNUSED] = NoArg, + [LevelUpVersion] = EvolutionTypeArgumentType.Version, + [LevelUpVersionDay] = EvolutionTypeArgumentType.Version, + [LevelUpVersionNight] = EvolutionTypeArgumentType.Version, + [LevelUpSummit] = Level, + [LevelUpDusk] = Level, + [LevelUpWormhole] = Level, + [UseItemWormhole] = Items, + + [CriticalHitsInBattle] = EvolutionTypeArgumentType.Version, + [HitPointsLostInBattle] = EvolutionTypeArgumentType.Version, + [Spin] = NoArg, + [LevelUpNatureAmped] = NoArg, + [LevelUpNatureLowKey] = NoArg, + [TowerOfDarkness] = NoArg, + [TowerOfWaters] = NoArg, + [UseItemFullMoon] = Items, // Ursaluna + [UseAgileStyleMoves] = NoArg, // Wyrdeer + [UseStrongStyleMoves] = NoArg, // Overqwil + [RecoilDamageMale] = NoArg, // Basculegion-0 + [RecoilDamageFemale] = NoArg, // Basculegion-1 + }; + + public static EvolutionTypeArgumentType GetArgType(this EvolutionType t) => ArgType[t]; } diff --git a/pkNX.Structures/Evolution/SeedPokeTable.cs b/pkNX.Structures/Evolution/SeedPokeTable.cs index eb350d27..f70d5c02 100644 --- a/pkNX.Structures/Evolution/SeedPokeTable.cs +++ b/pkNX.Structures/Evolution/SeedPokeTable.cs @@ -1,35 +1,34 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class SeedPokeTable { - public sealed class SeedPokeTable + private readonly ushort[] Table; + + public SeedPokeTable(byte[] data) { - private readonly ushort[] Table; + Table = new ushort[data.Length/2]; + for (int i = 0; i < Table.Length; i++) + Table[i] = BitConverter.ToUInt16(data, i * 2); + } - public SeedPokeTable(byte[] data) - { - Table = new ushort[data.Length/2]; - for (int i = 0; i < Table.Length; i++) - Table[i] = BitConverter.ToUInt16(data, i * 2); - } + public ushort this[int index] => Table[index]; - public ushort this[int index] => Table[index]; + public byte[] Write() + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + foreach (var seed in Table) + bw.Write(seed); + return ms.ToArray(); + } - public byte[] Write() - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - foreach (var seed in Table) - bw.Write(seed); - return ms.ToArray(); - } - - public IEnumerable Dump(string[] specNames) - { - return Table.Select((t, i) => $"{i:000}\t{specNames[i]}\t{specNames[t]}"); - } + public IEnumerable Dump(string[] specNames) + { + return Table.Select((t, i) => $"{i:000}\t{specNames[i]}\t{specNames[t]}"); } } diff --git a/pkNX.Structures/Evolution/ZukanEvolutionTable.cs b/pkNX.Structures/Evolution/ZukanEvolutionTable.cs index 845b223f..ed42f530 100644 --- a/pkNX.Structures/Evolution/ZukanEvolutionTable.cs +++ b/pkNX.Structures/Evolution/ZukanEvolutionTable.cs @@ -1,39 +1,38 @@ -using System; +using System; using System.IO; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class ZukanEvolutionTable { - public sealed class ZukanEvolutionTable + private const int SIZE = 0x14; + private readonly ushort[][] Table; + + public ZukanEvolutionTable(byte[] data) { - private const int SIZE = 0x14; - private readonly ushort[][] Table; + if (data.Length % SIZE != 0) + throw new ArgumentException(nameof(data) + " length should be a multiple of " + SIZE); - public ZukanEvolutionTable(byte[] data) + Table = new ushort[data.Length / SIZE][]; + for (int i = 0; i < Table.Length; i++) { - if (data.Length % SIZE != 0) - throw new ArgumentException(nameof(data) + " length should be a multiple of " + SIZE); - - Table = new ushort[data.Length / SIZE][]; - for (int i = 0; i < Table.Length; i++) - { - var evos = new ushort[(SIZE / 2) - 1]; - for (int j = 0; j < evos.Length; j++) - evos[i] = BitConverter.ToUInt16(data, (i * SIZE) + (j * 2)); - } - } - - public byte[] Write() - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - foreach (var t in Table) - { - foreach (var e in t) - bw.Write(e); - bw.Write(t.Count(x => x != 0)); - } - return ms.ToArray(); + var evos = new ushort[(SIZE / 2) - 1]; + for (int j = 0; j < evos.Length; j++) + evos[i] = BitConverter.ToUInt16(data, (i * SIZE) + (j * 2)); } } + + public byte[] Write() + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + foreach (var t in Table) + { + foreach (var e in t) + bw.Write(e); + bw.Write(t.Count(x => x != 0)); + } + return ms.ToArray(); + } } diff --git a/pkNX.Structures/GameUtil.cs b/pkNX.Structures/GameUtil.cs index b45001a1..185db131 100644 --- a/pkNX.Structures/GameUtil.cs +++ b/pkNX.Structures/GameUtil.cs @@ -1,219 +1,218 @@ -using System; +using System; using System.Linq; using static pkNX.Structures.GameVersion; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Utility class for logic. +/// +public static class GameUtil { /// - /// Utility class for logic. + /// List of possible values that are stored in PKM data. /// - public static class GameUtil + /// Ordered roughly by most recent games first. + public static readonly GameVersion[] GameVersions = ((GameVersion[])Enum.GetValues(typeof(GameVersion))).Where(z => z is < RB and > 0).Reverse().ToArray(); + + /// + /// Indicates if the value is a value used by the games or is an aggregate indicator. + /// + /// Game to check + public static bool IsValidSavedVersion(this GameVersion game) => game is > 0 and <= RB; + + /// Determines the Version Grouping of an input Version ID + /// Version of which to determine the group + /// Version Group Identifier or Invalid if type cannot be determined. + public static GameVersion GetMetLocationVersionGroup(GameVersion Version) { - /// - /// List of possible values that are stored in PKM data. - /// - /// Ordered roughly by most recent games first. - public static readonly GameVersion[] GameVersions = ((GameVersion[])Enum.GetValues(typeof(GameVersion))).Where(z => z is < RB and > 0).Reverse().ToArray(); - - /// - /// Indicates if the value is a value used by the games or is an aggregate indicator. - /// - /// Game to check - public static bool IsValidSavedVersion(this GameVersion game) => game is > 0 and <= RB; - - /// Determines the Version Grouping of an input Version ID - /// Version of which to determine the group - /// Version Group Identifier or Invalid if type cannot be determined. - public static GameVersion GetMetLocationVersionGroup(GameVersion Version) + return Version switch { - return Version switch - { - // Sidegame - CXD => CXD, - GO => GO, - // Gen1 - RBY => RBY, - RD => RBY, - BU => RBY, - YW => RBY, - GN => RBY, - // Gen2 - GS => GSC, - GD => GSC, - SV => GSC, - C => GSC, - // Gen3 - R => RS, - S => RS, - E => E, - FR => FR, - LG => FR, - // Gen4 - D => DP, - P => DP, - Pt => Pt, - HG => HGSS, - SS => HGSS, - // Gen5 - B => BW, - W => BW, - B2 => B2W2, - W2 => B2W2, - // Gen6 - X => XY, - Y => XY, - OR => ORAS, - AS => ORAS, - // Gen7 - SN => SM, - MN => SM, - US => USUM, - UM => USUM, - GP => GG, - GE => GG, - // Gen8 - SW => SWSH, - SH => SWSH, - PLA => PLA, - _ => Invalid - }; - } - - /// - /// Gets a Version ID from the end of that Generation - /// - /// Generation ID - /// Version ID from requested generation. If none, return . - public static GameVersion GetVersion(int generation) - { - return generation switch - { - 1 => RBY, - 2 => C, - 3 => E, - 4 => SS, - 5 => W2, - 6 => AS, - 7 => UM, - 8 => PLA, - _ => Invalid - }; - } - - /// - /// Gets the Generation the belongs to. - /// - /// Game to retrieve the generation for - /// Generation ID - public static int GetGeneration(this GameVersion game) - { - if (Gen1.Contains(game)) return 1; - if (Gen2.Contains(game)) return 2; - if (Gen3.Contains(game)) return 3; - if (Gen4.Contains(game)) return 4; - if (Gen5.Contains(game)) return 5; - if (Gen6.Contains(game)) return 6; - if (Gen7.Contains(game)) return 7; - if (Gen8.Contains(game)) return 8; - return -1; - } - - /// - /// Gets the Generation the belongs to. - /// - /// Game to retrieve the generation for - /// Generation ID - public static int GetMaxSpeciesID(this GameVersion game) - { - if (Gen1.Contains(game)) return 151; - if (Gen2.Contains(game)) return 251; - if (Gen3.Contains(game)) return 384; - if (Gen4.Contains(game)) return 493; - if (Gen5.Contains(game)) return 649; - if (Gen6.Contains(game)) return Legal.MaxSpeciesID_6; - if (Gen7.Contains(game) || Gen7b.Contains(game)) - { - if (SM.Contains(game)) - return 802; - if (USUM.Contains(game)) - return 807; - return Legal.MaxSpeciesID_7_GG; - } - if (Gen8.Contains(game)) - { - if (SWSH.Contains(game)) - return Legal.MaxSpeciesID_8; - return Legal.MaxSpeciesID_8a; - } - return -1; - } - - /// - /// Checks if the version (or subset versions) is equivalent to . - /// - /// Version (set) - /// Individual version - public static bool Contains(this GameVersion g1, int g2) => g1.Contains((GameVersion)g2); - - /// - /// Checks if the version (or subset versions) is equivalent to . - /// - /// Version (set) - /// Individual version - public static bool Contains(this GameVersion g1, GameVersion g2) - { - if (g1 == g2 || g1 == Any) - return true; - - return g1 switch - { - RB => g2 is RD or BU or GN, - RBY or Stadium => RB.Contains(g2) || g2 == YW, - Gen1 => RBY.Contains(g2) || g2 == Stadium, - - GS => g2 is GD or SV, - GSC or Stadium2 => GS.Contains(g2) || g2 == C, - Gen2 => GSC.Contains(g2) || g2 == Stadium2, - - RS => g2 is R or S, - RSE => RS.Contains(g2) || g2 == E, - FRLG => g2 is FR or LG, - COLO or XD => g2 == CXD, - CXD => g2 is COLO or XD, - RSBOX => RS.Contains(g2) || g2 == E || FRLG.Contains(g2), - Gen3 => RSE.Contains(g2) || FRLG.Contains(g2) || CXD.Contains(g2) || g2 == RSBOX, - - DP => g2 is D or P, - HGSS => g2 is HG or SS, - DPPt => DP.Contains(g2) || g2 == Pt, - BATREV => DP.Contains(g2) || g2 == Pt || HGSS.Contains(g2), - Gen4 => DPPt.Contains(g2) || HGSS.Contains(g2) || g2 == BATREV, - - BW => g2 is B or W, - B2W2 => g2 is B2 or W2, - Gen5 => BW.Contains(g2) || B2W2.Contains(g2), - - XY => g2 is X or Y, - ORAS => g2 is OR or AS, - - Gen6 => XY.Contains(g2) || ORAS.Contains(g2), - SM => g2 is SN or MN, - USUM => g2 is US or UM, - GG => g2 is GP or GE, - Gen7 => SM.Contains(g2) || USUM.Contains(g2), - Gen7b => GG.Contains(g2) || GO == g2, - - SWSH => g2 is SW or SH, - PLA => g2 is PLA, - Gen8 => SWSH.Contains(g2) || PLA.Contains(g2), - _ => false, - }; - } - - /// - /// List of possible values within the provided . - /// - /// Generation to look within - public static GameVersion[] GetVersionsInGeneration(int generation) => GameVersions.Where(z => z.GetGeneration() == generation).ToArray(); + // Sidegame + CXD => CXD, + GO => GO, + // Gen1 + RBY => RBY, + RD => RBY, + BU => RBY, + YW => RBY, + GN => RBY, + // Gen2 + GS => GSC, + GD => GSC, + SV => GSC, + C => GSC, + // Gen3 + R => RS, + S => RS, + E => E, + FR => FR, + LG => FR, + // Gen4 + D => DP, + P => DP, + Pt => Pt, + HG => HGSS, + SS => HGSS, + // Gen5 + B => BW, + W => BW, + B2 => B2W2, + W2 => B2W2, + // Gen6 + X => XY, + Y => XY, + OR => ORAS, + AS => ORAS, + // Gen7 + SN => SM, + MN => SM, + US => USUM, + UM => USUM, + GP => GG, + GE => GG, + // Gen8 + SW => SWSH, + SH => SWSH, + PLA => PLA, + _ => Invalid + }; } + + /// + /// Gets a Version ID from the end of that Generation + /// + /// Generation ID + /// Version ID from requested generation. If none, return . + public static GameVersion GetVersion(int generation) + { + return generation switch + { + 1 => RBY, + 2 => C, + 3 => E, + 4 => SS, + 5 => W2, + 6 => AS, + 7 => UM, + 8 => PLA, + _ => Invalid + }; + } + + /// + /// Gets the Generation the belongs to. + /// + /// Game to retrieve the generation for + /// Generation ID + public static int GetGeneration(this GameVersion game) + { + if (Gen1.Contains(game)) return 1; + if (Gen2.Contains(game)) return 2; + if (Gen3.Contains(game)) return 3; + if (Gen4.Contains(game)) return 4; + if (Gen5.Contains(game)) return 5; + if (Gen6.Contains(game)) return 6; + if (Gen7.Contains(game)) return 7; + if (Gen8.Contains(game)) return 8; + return -1; + } + + /// + /// Gets the Generation the belongs to. + /// + /// Game to retrieve the generation for + /// Generation ID + public static int GetMaxSpeciesID(this GameVersion game) + { + if (Gen1.Contains(game)) return 151; + if (Gen2.Contains(game)) return 251; + if (Gen3.Contains(game)) return 384; + if (Gen4.Contains(game)) return 493; + if (Gen5.Contains(game)) return 649; + if (Gen6.Contains(game)) return Legal.MaxSpeciesID_6; + if (Gen7.Contains(game) || Gen7b.Contains(game)) + { + if (SM.Contains(game)) + return 802; + if (USUM.Contains(game)) + return 807; + return Legal.MaxSpeciesID_7_GG; + } + if (Gen8.Contains(game)) + { + if (SWSH.Contains(game)) + return Legal.MaxSpeciesID_8; + return Legal.MaxSpeciesID_8a; + } + return -1; + } + + /// + /// Checks if the version (or subset versions) is equivalent to . + /// + /// Version (set) + /// Individual version + public static bool Contains(this GameVersion g1, int g2) => g1.Contains((GameVersion)g2); + + /// + /// Checks if the version (or subset versions) is equivalent to . + /// + /// Version (set) + /// Individual version + public static bool Contains(this GameVersion g1, GameVersion g2) + { + if (g1 == g2 || g1 == Any) + return true; + + return g1 switch + { + RB => g2 is RD or BU or GN, + RBY or Stadium => RB.Contains(g2) || g2 == YW, + Gen1 => RBY.Contains(g2) || g2 == Stadium, + + GS => g2 is GD or SV, + GSC or Stadium2 => GS.Contains(g2) || g2 == C, + Gen2 => GSC.Contains(g2) || g2 == Stadium2, + + RS => g2 is R or S, + RSE => RS.Contains(g2) || g2 == E, + FRLG => g2 is FR or LG, + COLO or XD => g2 == CXD, + CXD => g2 is COLO or XD, + RSBOX => RS.Contains(g2) || g2 == E || FRLG.Contains(g2), + Gen3 => RSE.Contains(g2) || FRLG.Contains(g2) || CXD.Contains(g2) || g2 == RSBOX, + + DP => g2 is D or P, + HGSS => g2 is HG or SS, + DPPt => DP.Contains(g2) || g2 == Pt, + BATREV => DP.Contains(g2) || g2 == Pt || HGSS.Contains(g2), + Gen4 => DPPt.Contains(g2) || HGSS.Contains(g2) || g2 == BATREV, + + BW => g2 is B or W, + B2W2 => g2 is B2 or W2, + Gen5 => BW.Contains(g2) || B2W2.Contains(g2), + + XY => g2 is X or Y, + ORAS => g2 is OR or AS, + + Gen6 => XY.Contains(g2) || ORAS.Contains(g2), + SM => g2 is SN or MN, + USUM => g2 is US or UM, + GG => g2 is GP or GE, + Gen7 => SM.Contains(g2) || USUM.Contains(g2), + Gen7b => GG.Contains(g2) || GO == g2, + + SWSH => g2 is SW or SH, + PLA => g2 is PLA, + Gen8 => SWSH.Contains(g2) || PLA.Contains(g2), + _ => false, + }; + } + + /// + /// List of possible values within the provided . + /// + /// Generation to look within + public static GameVersion[] GetVersionsInGeneration(int generation) => GameVersions.Where(z => z.GetGeneration() == generation).ToArray(); } diff --git a/pkNX.Structures/GameVersion.cs b/pkNX.Structures/GameVersion.cs index 0df2cfc5..e20b6576 100644 --- a/pkNX.Structures/GameVersion.cs +++ b/pkNX.Structures/GameVersion.cs @@ -1,471 +1,470 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Game Version ID enum shared between actual Version IDs and lumped version groupings. +/// +public enum GameVersion { + #region Indicators for method empty arguments & result indication. Not stored values. + Invalid = -2, + Any = -1, + Unknown = 0, + #endregion + + // The following values are IDs stored within PKM data, and can also identify individual games. + + #region Gen3 /// - /// Game Version ID enum shared between actual Version IDs and lumped version groupings. + /// Pokémon Sapphire (GBA) /// - public enum GameVersion - { - #region Indicators for method empty arguments & result indication. Not stored values. - Invalid = -2, - Any = -1, - Unknown = 0, - #endregion - - // The following values are IDs stored within PKM data, and can also identify individual games. - - #region Gen3 - /// - /// Pokémon Sapphire (GBA) - /// - S = 1, - - /// - /// Pokémon Ruby (GBA) - /// - R = 2, - - /// - /// Pokémon Emerald (GBA) - /// - E = 3, - - /// - /// Pokémon FireRed (GBA) - /// - FR = 4, - - /// - /// Pokémon LeafGreen (GBA) - /// - LG = 5, - - /// - /// Pokémon Colosseum & Pokémon XD (GameCube) - /// - CXD = 15, - #endregion - - #region Gen4 - /// - /// Pokémon Diamond (NDS) - /// - D = 10, - - /// - /// Pokémon Pearl (NDS) - /// - P = 11, - - /// - /// Pokémon Platinum (NDS) - /// - Pt = 12, - - /// - /// Pokémon Heart Gold (NDS) - /// - HG = 7, - - /// - /// Pokémon Soul Silver (NDS) - /// - SS = 8, - #endregion - - #region Gen5 - /// - /// Pokémon White (NDS) - /// - W = 20, - - /// - /// Pokémon Black (NDS) - /// - B = 21, - - /// - /// Pokémon White 2 (NDS) - /// - W2 = 22, - - /// - /// Pokémon Black 2 (NDS) - /// - B2 = 23, - #endregion - - #region Gen6 - /// - /// Pokémon X (3DS) - /// - X = 24, - - /// - /// Pokémon Y (3DS) - /// - Y = 25, - - /// - /// Pokémon Alpha Sapphire (3DS) - /// - AS = 26, - - /// - /// Pokémon Omega Ruby (3DS) - /// - OR = 27, - #endregion - - #region Gen7 - /// - /// Pokémon Sun (3DS) - /// - SN = 30, - - /// - /// Pokémon Moon (3DS) - /// - MN = 31, - - /// - /// Pokémon Ultra Sun (3DS) - /// - US = 32, - - /// - /// Pokémon Ultra Moon (3DS) - /// - UM = 33, - #endregion - - /// - /// Pokémon GO (GO -> Lets Go transfers) - /// - GO = 34, - - #region Virtual Console (3DS) Gen1 - /// - /// Pokémon Red (3DS Virtual Console) - /// - RD = 35, - - /// - /// Pokémon Green[JP]/Blue[INT] (3DS Virtual Console) - /// - GN = 36, - - /// - /// Pokémon Blue[JP] (3DS Virtual Console) - /// - BU = 37, - - /// - /// Pokémon Yellow [JP] (3DS Virtual Console) - /// - YW = 38, - #endregion - - #region Virtual Console (3DS) Gen2 - /// - /// Pokémon Gold (3DS Virtual Console) - /// - GD = 39, - - /// - /// Pokémon Silver (3DS Virtual Console) - /// - SV = 40, - - /// - /// Pokémon Crystal (3DS Virtual Console) - /// - C = 41, - #endregion - - #region Nintendo Switch - /// - /// Pokémon Let's Go Pikachu (NX) - /// - GP = 42, - - /// - /// Pokémon Let's Go Eevee (NX) - /// - GE = 43, - - /// - /// Pokémon Sword (NX) - /// - SW = 44, - - /// - /// Pokémon Shield (NX) - /// - SH = 45, - - PLA, - HOME, - BD, - SP, - - #endregion - - // The following values are not actually stored values in pkm data, - // These values are assigned within PKHeX as properties for various logic branching. - - #region Game Groupings (SaveFile type, roughly) - /// - /// Pokémon Red & Blue identifier. - /// - /// - /// - /// - RB, - - /// - /// Pokémon Red/Blue/Yellow identifier. - /// - /// - /// - /// - /// - RBY, - - /// - /// Pokémon Gold & Silver identifier. - /// - /// - /// - GS, - - /// - /// Pokémon Gold/Silver/Crystal identifier. - /// - /// - /// - /// - GSC, - - /// - /// Pokémon Ruby & Sapphire identifier. - /// - /// - /// - RS, - - /// - /// Pokémon Ruby/Sapphire/Emerald identifier. - /// - /// - /// - /// - RSE, - - /// - /// Pokémon FireRed/LeafGreen identifier. - /// - /// - /// - FRLG, - - /// - /// Pokémon Box Ruby & Sapphire identifier. - /// - RSBOX, - - /// - /// Pokémon Colosseum identifier. - /// - /// - /// Also used to mark Colosseum-only origin data as this game shares a version ID with - COLO, - - /// - /// Pokémon XD identifier. - /// - /// - /// Also used to mark XD-only origin data as this game shares a version ID with - XD, - - /// - /// Pokémon Diamond & Pearl identifier. - /// - /// - /// - DP, - - /// - /// Pokémon Diamond/Pearl/Platinum version group. - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - /// - DPPt, - - /// - /// Pokémon Heart Gold & Soul Silver identifier. - /// - /// - /// - HGSS, - - /// - /// Pokémon Battle Revolution identifier. - /// - BATREV, - - /// - /// Pokémon Black & White version group. - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - BW, - - /// - /// Pokémon Black 2 & White 2 version group. - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - B2W2, - - /// - /// Pokémon X & Y - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - XY, - - /// - /// Pokémon Omega Ruby & Alpha Sapphire Demo identifier. - /// - /// - ORASDEMO, - - /// - /// Pokémon Omega Ruby & Alpha Sapphire version group. - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - ORAS, - - /// - /// Pokémon Sun & Moon - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - SM, - - /// - /// Pokémon Sun & Moon Demo identifier. - /// - /// - SMDEMO, - - /// - /// Pokémon Ultra Sun & Ultra Moon - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - USUM, - - /// - /// Pokémon Let's Go Pikachu & Eevee - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - GG, - - /// - /// Pokémon Sword & Shield - /// - /// Used to lump data from the associated games as data assets are shared. - /// - /// - SWSH, - - /// - /// Generation 1 Games - /// - /// - Gen1, - - /// - /// Generation 2 Games - /// - /// - Gen2, - - /// - /// Generation 3 Games - /// - /// - /// - Gen3, - - /// - /// Generation 4 Games - /// - /// - /// - Gen4, - - /// - /// Generation 5 Games - /// - /// - /// - Gen5, - - /// - /// Generation 6 Games - /// - /// - /// - Gen6, - - /// - /// Generation 7 Games on the Nintendo 3DS - /// - /// - /// - Gen7, - - /// - /// Generation 7 Games on the Nintendo Switch - /// - /// - /// - Gen7b, - - /// - /// Generation 8 Games - /// - /// - /// - Gen8, - - /// - /// Pocket Monsters Stadium data origin identifier - /// - StadiumJ, - - /// - /// Pokémon Stadium data origin identifier - /// - Stadium, - - /// - /// Pokémon Stadium 2 data origin identifier - /// - Stadium2, - #endregion - } + S = 1, + + /// + /// Pokémon Ruby (GBA) + /// + R = 2, + + /// + /// Pokémon Emerald (GBA) + /// + E = 3, + + /// + /// Pokémon FireRed (GBA) + /// + FR = 4, + + /// + /// Pokémon LeafGreen (GBA) + /// + LG = 5, + + /// + /// Pokémon Colosseum & Pokémon XD (GameCube) + /// + CXD = 15, + #endregion + + #region Gen4 + /// + /// Pokémon Diamond (NDS) + /// + D = 10, + + /// + /// Pokémon Pearl (NDS) + /// + P = 11, + + /// + /// Pokémon Platinum (NDS) + /// + Pt = 12, + + /// + /// Pokémon Heart Gold (NDS) + /// + HG = 7, + + /// + /// Pokémon Soul Silver (NDS) + /// + SS = 8, + #endregion + + #region Gen5 + /// + /// Pokémon White (NDS) + /// + W = 20, + + /// + /// Pokémon Black (NDS) + /// + B = 21, + + /// + /// Pokémon White 2 (NDS) + /// + W2 = 22, + + /// + /// Pokémon Black 2 (NDS) + /// + B2 = 23, + #endregion + + #region Gen6 + /// + /// Pokémon X (3DS) + /// + X = 24, + + /// + /// Pokémon Y (3DS) + /// + Y = 25, + + /// + /// Pokémon Alpha Sapphire (3DS) + /// + AS = 26, + + /// + /// Pokémon Omega Ruby (3DS) + /// + OR = 27, + #endregion + + #region Gen7 + /// + /// Pokémon Sun (3DS) + /// + SN = 30, + + /// + /// Pokémon Moon (3DS) + /// + MN = 31, + + /// + /// Pokémon Ultra Sun (3DS) + /// + US = 32, + + /// + /// Pokémon Ultra Moon (3DS) + /// + UM = 33, + #endregion + + /// + /// Pokémon GO (GO -> Lets Go transfers) + /// + GO = 34, + + #region Virtual Console (3DS) Gen1 + /// + /// Pokémon Red (3DS Virtual Console) + /// + RD = 35, + + /// + /// Pokémon Green[JP]/Blue[INT] (3DS Virtual Console) + /// + GN = 36, + + /// + /// Pokémon Blue[JP] (3DS Virtual Console) + /// + BU = 37, + + /// + /// Pokémon Yellow [JP] (3DS Virtual Console) + /// + YW = 38, + #endregion + + #region Virtual Console (3DS) Gen2 + /// + /// Pokémon Gold (3DS Virtual Console) + /// + GD = 39, + + /// + /// Pokémon Silver (3DS Virtual Console) + /// + SV = 40, + + /// + /// Pokémon Crystal (3DS Virtual Console) + /// + C = 41, + #endregion + + #region Nintendo Switch + /// + /// Pokémon Let's Go Pikachu (NX) + /// + GP = 42, + + /// + /// Pokémon Let's Go Eevee (NX) + /// + GE = 43, + + /// + /// Pokémon Sword (NX) + /// + SW = 44, + + /// + /// Pokémon Shield (NX) + /// + SH = 45, + + PLA, + HOME, + BD, + SP, + + #endregion + + // The following values are not actually stored values in pkm data, + // These values are assigned within PKHeX as properties for various logic branching. + + #region Game Groupings (SaveFile type, roughly) + /// + /// Pokémon Red & Blue identifier. + /// + /// + /// + /// + RB, + + /// + /// Pokémon Red/Blue/Yellow identifier. + /// + /// + /// + /// + /// + RBY, + + /// + /// Pokémon Gold & Silver identifier. + /// + /// + /// + GS, + + /// + /// Pokémon Gold/Silver/Crystal identifier. + /// + /// + /// + /// + GSC, + + /// + /// Pokémon Ruby & Sapphire identifier. + /// + /// + /// + RS, + + /// + /// Pokémon Ruby/Sapphire/Emerald identifier. + /// + /// + /// + /// + RSE, + + /// + /// Pokémon FireRed/LeafGreen identifier. + /// + /// + /// + FRLG, + + /// + /// Pokémon Box Ruby & Sapphire identifier. + /// + RSBOX, + + /// + /// Pokémon Colosseum identifier. + /// + /// + /// Also used to mark Colosseum-only origin data as this game shares a version ID with + COLO, + + /// + /// Pokémon XD identifier. + /// + /// + /// Also used to mark XD-only origin data as this game shares a version ID with + XD, + + /// + /// Pokémon Diamond & Pearl identifier. + /// + /// + /// + DP, + + /// + /// Pokémon Diamond/Pearl/Platinum version group. + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + /// + DPPt, + + /// + /// Pokémon Heart Gold & Soul Silver identifier. + /// + /// + /// + HGSS, + + /// + /// Pokémon Battle Revolution identifier. + /// + BATREV, + + /// + /// Pokémon Black & White version group. + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + BW, + + /// + /// Pokémon Black 2 & White 2 version group. + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + B2W2, + + /// + /// Pokémon X & Y + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + XY, + + /// + /// Pokémon Omega Ruby & Alpha Sapphire Demo identifier. + /// + /// + ORASDEMO, + + /// + /// Pokémon Omega Ruby & Alpha Sapphire version group. + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + ORAS, + + /// + /// Pokémon Sun & Moon + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + SM, + + /// + /// Pokémon Sun & Moon Demo identifier. + /// + /// + SMDEMO, + + /// + /// Pokémon Ultra Sun & Ultra Moon + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + USUM, + + /// + /// Pokémon Let's Go Pikachu & Eevee + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + GG, + + /// + /// Pokémon Sword & Shield + /// + /// Used to lump data from the associated games as data assets are shared. + /// + /// + SWSH, + + /// + /// Generation 1 Games + /// + /// + Gen1, + + /// + /// Generation 2 Games + /// + /// + Gen2, + + /// + /// Generation 3 Games + /// + /// + /// + Gen3, + + /// + /// Generation 4 Games + /// + /// + /// + Gen4, + + /// + /// Generation 5 Games + /// + /// + /// + Gen5, + + /// + /// Generation 6 Games + /// + /// + /// + Gen6, + + /// + /// Generation 7 Games on the Nintendo 3DS + /// + /// + /// + Gen7, + + /// + /// Generation 7 Games on the Nintendo Switch + /// + /// + /// + Gen7b, + + /// + /// Generation 8 Games + /// + /// + /// + Gen8, + + /// + /// Pocket Monsters Stadium data origin identifier + /// + StadiumJ, + + /// + /// Pokémon Stadium data origin identifier + /// + Stadium, + + /// + /// Pokémon Stadium 2 data origin identifier + /// + Stadium2, + #endregion } diff --git a/pkNX.Structures/Item/BattlePocket.cs b/pkNX.Structures/Item/BattlePocket.cs index 6cba8c27..b53a8bba 100644 --- a/pkNX.Structures/Item/BattlePocket.cs +++ b/pkNX.Structures/Item/BattlePocket.cs @@ -1,14 +1,13 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum BattlePocket : byte { - [Flags] - public enum BattlePocket : byte - { - None, - Ball = 1 << 0, - Boosts = 1 << 1, - Restore = 1 << 2, - Misc = 1 << 3, - } -} \ No newline at end of file + None, + Ball = 1 << 0, + Boosts = 1 << 1, + Restore = 1 << 2, + Misc = 1 << 3, +} diff --git a/pkNX.Structures/Item/BattleStatusFlags.cs b/pkNX.Structures/Item/BattleStatusFlags.cs index c68d477e..24b3a000 100644 --- a/pkNX.Structures/Item/BattleStatusFlags.cs +++ b/pkNX.Structures/Item/BattleStatusFlags.cs @@ -1,50 +1,49 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum BattleStatusFlags : byte { - [Flags] - public enum BattleStatusFlags : byte - { - None, + None, - /// - /// Sleep - /// - SLP = 1 << 0, + /// + /// Sleep + /// + SLP = 1 << 0, - /// - /// Poison - /// - PSN = 1 << 1, + /// + /// Poison + /// + PSN = 1 << 1, - /// - /// Burn - /// - BRN = 1 << 2, + /// + /// Burn + /// + BRN = 1 << 2, - /// - /// Freeze - /// - FRZ = 1 << 3, + /// + /// Freeze + /// + FRZ = 1 << 3, - /// - /// Paralysis - /// - PAR = 1 << 4, + /// + /// Paralysis + /// + PAR = 1 << 4, - /// - /// Confusion - /// - CFZ = 1 << 5, + /// + /// Confusion + /// + CFZ = 1 << 5, - /// - /// Infatuation - /// - INF = 1 << 6, + /// + /// Infatuation + /// + INF = 1 << 6, - /// - /// Guard Spec. - /// - GSP = 1 << 7, - } + /// + /// Guard Spec. + /// + GSP = 1 << 7, } diff --git a/pkNX.Structures/Item/Item.cs b/pkNX.Structures/Item/Item.cs index 83da6353..50573225 100644 --- a/pkNX.Structures/Item/Item.cs +++ b/pkNX.Structures/Item/Item.cs @@ -1,151 +1,150 @@ -using System.ComponentModel; +using System.ComponentModel; using System.Runtime.InteropServices; -namespace pkNX.Structures +namespace pkNX.Structures; + +[StructLayout(LayoutKind.Sequential)] +public class Item { - [StructLayout(LayoutKind.Sequential)] - public class Item + public byte[] Write() => this.ToBytesClass(); + public static Item FromBytes(byte[] data) => data.ToClass(); + + private const string Battle = "Battle"; + private const string Field = "Field"; + private const string Mart = "Mart"; + private const string Heal = "Heal"; + + #region Structure + private ushort Price; + + [Category(Battle)] + public byte HeldEffect { get; set; } + + public byte HeldArgument { get; set; } + public byte NaturalGiftEffect { get; set; } + public byte FlingEffect { get; set; } + public byte FlingPower { get; set; } + public byte NaturalGiftPower { get; set; } + public ushort Packed { get; set; } + + [Category(Field), Description("Routine # to call when used; 0=unusable.")] + public byte EffectField { get; set; } + + [Category(Battle), Description("Routine # to call when used; 0=unusable.")] + public byte EffectBattle { get; set; } // Battle Type + + public byte Unk_0xC { get; set; } // 0 or 1 + public byte Unk_0xD { get; set; } // Classification (0-3 Battle, 4 Balls, 5 Mail) + private byte Consumable { get; set; } + public byte SortIndex { get; set; } + public BattleStatusFlags CureInflict { get; set; } // Bitflags + private byte Boost0; // Revive 1, Sacred Ash 3, Rare Candy 5, EvoStone 8, upper4 for BoostAtk + private byte Boost1; // DEF, SPA + private byte Boost2; // SPD, SPE + private byte Boost3; // ACC, CRIT PPUpFlags + public ItemFlags1 FunctionFlags0 { get; set; } + public ItemFlags2 FunctionFlags1 { get; set; } + + [Category(Field), Description("Adds EVs to the HP stat.")] + public sbyte EVHP { get; set; } + + [Category(Field), Description("Adds EVs to the Attack stat.")] + public sbyte EVATK { get; set; } + + [Category(Field), Description("Adds EVs to the Defense stat.")] + public sbyte EVDEF { get; set; } + + [Category(Field), Description("Adds EVs to the Speed stat.")] + public sbyte EVSPE { get; set; } + + [Category(Field), Description("Adds EVs to the Sp. Attack stat.")] + public sbyte EVSPA { get; set; } + + [Category(Field), Description("Adds EVs to the Sp. Defense stat.")] + public sbyte EVSPD { get; set; } + + [Category(Heal), Description("Determines the healing percent, or if a flat value is used."), RefreshProperties(RefreshProperties.All)] + public Heal HealAmount { get; set; } + + [Category(Field), Description("PP to be added to the move's current PP if used.")] + public byte PPGain { get; set; } + + public sbyte Friendship1 { get; set; } + public sbyte Friendship2 { get; set; } + public sbyte Friendship3 { get; set; } + public byte _0x23, _0x24; + #endregion + + [Category(Mart), RefreshProperties(RefreshProperties.All)] + public int BuyPrice { get => Price * 10; set => Price = (ushort)(value / 10); } + + [Category(Mart), ReadOnly(true)] + public int SellPrice { get => Price * 5; set => Price = (ushort)(value / 5); } + + [Category(Battle)] + public int NaturalGiftType { get => Packed & 0x1F; set => Packed = (ushort)((NaturalGiftEffect & ~0x1F) | value); } + + [Category(Battle)] + public bool Flag1 { get => ((Packed >> 5) & 1) == 1; set => Packed = (ushort)((Packed & ~(1 << 5)) | ((value ? 1 : 0) << 5)); } + + [Category(Battle)] + public bool Flag2 { get => ((Packed >> 6) & 1) == 1; set => Packed = (ushort)((Packed & ~(1 << 6)) | ((value ? 1 : 0) << 6)); } + + [Category(Field)] + public int PocketField { get => (Packed >> 7) & 0xF; set => Packed = (ushort)((Packed & 0xF87F) | ((value & 0xF) << 7)); } + + [Category(Battle)] + public BattlePocket PocketBattle { get => (BattlePocket)(Packed >> 11); set => Packed = (ushort)((Packed & 0x077F) | (((byte)value & 0x1F) << 11)); } + + [Category(Field)] + public bool Revive { get => ((Boost0 >> 0) & 1) == 0; set => Boost0 = (byte)((Boost0 & ~(1 << 0)) | ((value ? 1 : 0) << 0)); } + + [Category(Field)] + public bool ReviveAll { get => ((Boost0 >> 1) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 1)) | ((value ? 1 : 0) << 1)); } + + [Category(Field)] + public bool LevelUp { get => ((Boost0 >> 2) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 2)) | ((value ? 1 : 0) << 2)); } + + [Category(Field)] + public bool EvoStone { get => ((Boost0 >> 3) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 3)) | ((value ? 1 : 0) << 3)); } + + [Category(Battle)] + public int BoostATK { get => Boost0 >> 4; set => Boost0 = (byte)((Boost0 & 0xF) | (value << 4)); } + + [Category(Battle)] + public int BoostDEF { get => Boost1 & 0xF; set => Boost1 = (byte)((Boost1 & ~0xF) | (value & 0xF)); } + + [Category(Battle)] + public int BoostSPA { get => Boost1 >> 4; set => Boost1 = (byte)((Boost1 & 0xF) | (value << 4)); } + + [Category(Battle)] + public int BoostSPD { get => Boost2 & 0xF; set => Boost2 = (byte)((Boost2 & ~0xF) | (value & 0xF)); } + + [Category(Battle)] + public int BoostSPE { get => Boost2 >> 4; set => Boost2 = (byte)((Boost2 & 0xF) | (value << 4)); } + + [Category(Battle)] + public int BoostACC { get => Boost3 & 0xF; set => Boost3 = (byte)((Boost3 & ~0xF) | (value & 0xF)); } + + [Category(Battle)] + public int BoostCRIT { get => (Boost3 >> 4) & 3; set => Boost3 = (byte)((Boost3 & ~0x30) | ((value & 3) << 4)); } + + [Category(Battle)] + public int BoostPP1 { get => (Boost3 >> 6) & 1; set => Boost3 = (byte)((Boost3 & 0xBF) | ((value & 1) << 6)); } + + [Category(Battle)] + public int BoostPPMax { get => (Boost3 >> 7) & 1; set => Boost3 = (byte)((Boost3 & 0x7F) | ((value & 1) << 7)); } + + [Category(Heal), Description("Raw value of the Heal enum."), RefreshProperties(RefreshProperties.All)] + public int HealValue { - public byte[] Write() => this.ToBytesClass(); - public static Item FromBytes(byte[] data) => data.ToClass(); - - private const string Battle = "Battle"; - private const string Field = "Field"; - private const string Mart = "Mart"; - private const string Heal = "Heal"; - - #region Structure - private ushort Price; - - [Category(Battle)] - public byte HeldEffect { get; set; } - - public byte HeldArgument { get; set; } - public byte NaturalGiftEffect { get; set; } - public byte FlingEffect { get; set; } - public byte FlingPower { get; set; } - public byte NaturalGiftPower { get; set; } - public ushort Packed { get; set; } - - [Category(Field), Description("Routine # to call when used; 0=unusable.")] - public byte EffectField { get; set; } - - [Category(Battle), Description("Routine # to call when used; 0=unusable.")] - public byte EffectBattle { get; set; } // Battle Type - - public byte Unk_0xC { get; set; } // 0 or 1 - public byte Unk_0xD { get; set; } // Classification (0-3 Battle, 4 Balls, 5 Mail) - private byte Consumable { get; set; } - public byte SortIndex { get; set; } - public BattleStatusFlags CureInflict { get; set; } // Bitflags - private byte Boost0; // Revive 1, Sacred Ash 3, Rare Candy 5, EvoStone 8, upper4 for BoostAtk - private byte Boost1; // DEF, SPA - private byte Boost2; // SPD, SPE - private byte Boost3; // ACC, CRIT PPUpFlags - public ItemFlags1 FunctionFlags0 { get; set; } - public ItemFlags2 FunctionFlags1 { get; set; } - - [Category(Field), Description("Adds EVs to the HP stat.")] - public sbyte EVHP { get; set; } - - [Category(Field), Description("Adds EVs to the Attack stat.")] - public sbyte EVATK { get; set; } - - [Category(Field), Description("Adds EVs to the Defense stat.")] - public sbyte EVDEF { get; set; } - - [Category(Field), Description("Adds EVs to the Speed stat.")] - public sbyte EVSPE { get; set; } - - [Category(Field), Description("Adds EVs to the Sp. Attack stat.")] - public sbyte EVSPA { get; set; } - - [Category(Field), Description("Adds EVs to the Sp. Defense stat.")] - public sbyte EVSPD { get; set; } - - [Category(Heal), Description("Determines the healing percent, or if a flat value is used."), RefreshProperties(RefreshProperties.All)] - public Heal HealAmount { get; set; } - - [Category(Field), Description("PP to be added to the move's current PP if used.")] - public byte PPGain { get; set; } - - public sbyte Friendship1 { get; set; } - public sbyte Friendship2 { get; set; } - public sbyte Friendship3 { get; set; } - public byte _0x23, _0x24; - #endregion - - [Category(Mart), RefreshProperties(RefreshProperties.All)] - public int BuyPrice { get => Price * 10; set => Price = (ushort)(value / 10); } - - [Category(Mart), ReadOnly(true)] - public int SellPrice { get => Price * 5; set => Price = (ushort)(value / 5); } - - [Category(Battle)] - public int NaturalGiftType { get => Packed & 0x1F; set => Packed = (ushort)((NaturalGiftEffect & ~0x1F) | value); } - - [Category(Battle)] - public bool Flag1 { get => ((Packed >> 5) & 1) == 1; set => Packed = (ushort)((Packed & ~(1 << 5)) | ((value ? 1 : 0) << 5)); } - - [Category(Battle)] - public bool Flag2 { get => ((Packed >> 6) & 1) == 1; set => Packed = (ushort)((Packed & ~(1 << 6)) | ((value ? 1 : 0) << 6)); } - - [Category(Field)] - public int PocketField { get => (Packed >> 7) & 0xF; set => Packed = (ushort)((Packed & 0xF87F) | ((value & 0xF) << 7)); } - - [Category(Battle)] - public BattlePocket PocketBattle { get => (BattlePocket)(Packed >> 11); set => Packed = (ushort)((Packed & 0x077F) | (((byte)value & 0x1F) << 11)); } - - [Category(Field)] - public bool Revive { get => ((Boost0 >> 0) & 1) == 0; set => Boost0 = (byte)((Boost0 & ~(1 << 0)) | ((value ? 1 : 0) << 0)); } - - [Category(Field)] - public bool ReviveAll { get => ((Boost0 >> 1) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 1)) | ((value ? 1 : 0) << 1)); } - - [Category(Field)] - public bool LevelUp { get => ((Boost0 >> 2) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 2)) | ((value ? 1 : 0) << 2)); } - - [Category(Field)] - public bool EvoStone { get => ((Boost0 >> 3) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 3)) | ((value ? 1 : 0) << 3)); } - - [Category(Battle)] - public int BoostATK { get => Boost0 >> 4; set => Boost0 = (byte)((Boost0 & 0xF) | (value << 4)); } - - [Category(Battle)] - public int BoostDEF { get => Boost1 & 0xF; set => Boost1 = (byte)((Boost1 & ~0xF) | (value & 0xF)); } - - [Category(Battle)] - public int BoostSPA { get => Boost1 >> 4; set => Boost1 = (byte)((Boost1 & 0xF) | (value << 4)); } - - [Category(Battle)] - public int BoostSPD { get => Boost2 & 0xF; set => Boost2 = (byte)((Boost2 & ~0xF) | (value & 0xF)); } - - [Category(Battle)] - public int BoostSPE { get => Boost2 >> 4; set => Boost2 = (byte)((Boost2 & 0xF) | (value << 4)); } - - [Category(Battle)] - public int BoostACC { get => Boost3 & 0xF; set => Boost3 = (byte)((Boost3 & ~0xF) | (value & 0xF)); } - - [Category(Battle)] - public int BoostCRIT { get => (Boost3 >> 4) & 3; set => Boost3 = (byte)((Boost3 & ~0x30) | ((value & 3) << 4)); } - - [Category(Battle)] - public int BoostPP1 { get => (Boost3 >> 6) & 1; set => Boost3 = (byte)((Boost3 & 0xBF) | ((value & 1) << 6)); } - - [Category(Battle)] - public int BoostPPMax { get => (Boost3 >> 7) & 1; set => Boost3 = (byte)((Boost3 & 0x7F) | ((value & 1) << 7)); } - - [Category(Heal), Description("Raw value of the Heal enum."), RefreshProperties(RefreshProperties.All)] - public int HealValue - { - get => (int)HealAmount; - set => HealAmount = (Heal)value; - } - - [Category(Heal), Description("Item is consumed when used."), RefreshProperties(RefreshProperties.All)] - public bool UseConsume { get => (Consumable & 0xF) != 0; set => Consumable = (byte)((Consumable & 0xF0) | (value ? 1 : 0)); } - - [Category(Heal), Description("Item is not consumed when used."), RefreshProperties(RefreshProperties.All)] - public bool UseKeep { get => (Consumable & 0xF0) != 0; set => Consumable = (byte)((Consumable & 0x0F) | (value ? 0x10 : 0)); } + get => (int)HealAmount; + set => HealAmount = (Heal)value; } + + [Category(Heal), Description("Item is consumed when used."), RefreshProperties(RefreshProperties.All)] + public bool UseConsume { get => (Consumable & 0xF) != 0; set => Consumable = (byte)((Consumable & 0xF0) | (value ? 1 : 0)); } + + [Category(Heal), Description("Item is not consumed when used."), RefreshProperties(RefreshProperties.All)] + public bool UseKeep { get => (Consumable & 0xF0) != 0; set => Consumable = (byte)((Consumable & 0x0F) | (value ? 0x10 : 0)); } } diff --git a/pkNX.Structures/Item/Item8.cs b/pkNX.Structures/Item/Item8.cs index b86488bc..d19012c8 100644 --- a/pkNX.Structures/Item/Item8.cs +++ b/pkNX.Structures/Item/Item8.cs @@ -1,154 +1,153 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Item8 { - public class Item8 + private const int SIZE = 0x30; + public readonly int ItemID; + public readonly byte[] Data; + + public Item8(int id, byte[] data) { - private const int SIZE = 0x30; - public readonly int ItemID; - public readonly byte[] Data; - - public Item8(int id, byte[] data) - { - ItemID = id; - Data = data; - } - - public uint Price - { - get => BitConverter.ToUInt32(Data, 0x00); - set => BitConverter.GetBytes(value).CopyTo(Data, 0x00); - } - - public uint PriceWatts - { - get => BitConverter.ToUInt32(Data, 0x04); - set => BitConverter.GetBytes(value).CopyTo(Data, 0x04); - } - - public uint PriceAlternate // BP, Dynite Ore - { - get => BitConverter.ToUInt32(Data, 0x08); - set => BitConverter.GetBytes(value).CopyTo(Data, 0x08); - } - - public PouchID Pouch - { - get => (PouchID)(Data[0x11] & 0xF); - set => Data[0x11] = (byte)((Data[0x11] & 0xF0) | ((byte)value & 0xF)); - } - - public byte EffectField - { - get => Data[0x13]; - set => Data[0x13] = value; - } - - public int ItemSprite - { - get => BitConverter.ToInt16(Data, 0x1A); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1A); - } - - public GroupIndexType GroupType - { - get => (GroupIndexType)Data[0x1C]; - set => Data[0x1C] = (byte)value; - } - - public bool CanUseOnPokemon - { - get => Data[0x15] == 1; - set => Data[0x15] = (byte)(value ? 1 : 0); - } - - public byte GroupIndex - { - get => Data[0x1D]; - set => Data[0x1D] = value; - } - - public byte Boost0 - { - get => Data[0x1F]; - set => Data[0x1F] = value; - } - - public byte Boost1 - { - get => Data[0x20]; - set => Data[0x20] = value; - } - - public byte Boost2 - { - get => Data[0x21]; - set => Data[0x21] = value; - } - - public byte Boost3 - { - get => Data[0x22]; - set => Data[0x22] = value; - } - - public static Item8[] GetArray(byte[] bin) - { - int numEntries = BitConverter.ToUInt16(bin, 0); - int maxEntryIndex = BitConverter.ToUInt16(bin, 4); - int entriesStart = (int)BitConverter.ToUInt32(bin, 0x40); - var result = new Item8[numEntries]; - for (var i = 0; i < result.Length; i++) - { - var entryIndex = BitConverter.ToUInt16(bin, 0x44 + (2 * i)); - if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } - result[i] = new Item8(i, bin.Slice(entriesStart + (entryIndex * SIZE), SIZE)); - } - - return result; - } - - public static byte[] SetArray(Item8[] array, byte[] bin) - { - bin = (byte[])bin.Clone(); - if (array.Length != BitConverter.ToInt16(bin, 0)) - throw new ArgumentException("Incompatible sizes"); - - int maxEntryIndex = BitConverter.ToUInt16(bin, 4); - int entriesStart = (int)BitConverter.ToUInt32(bin, 0x40); - for (int i = 0; i < array.Length; i++) - { - var entryIndex = BitConverter.ToUInt16(bin, 0x44 + (2 * i)); - if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } - - var data = array[i].Data; - data.CopyTo(bin, entriesStart + (entryIndex * SIZE)); - } - - return bin; - } - - public enum PouchID : byte - { - Medicine, - Balls, - Battle, - Berries, - Items, - TMs, - Treasures, - Ingredients, - Key, - } - - public enum GroupIndexType : byte - { - None = 0, - Ball = 1, - _2 = 2, // unused? - Berries = 3, - TM = 4, - Gems = 5, // only for Normal Gem, rest are unused items - } + ItemID = id; + Data = data; } -} \ No newline at end of file + + public uint Price + { + get => BitConverter.ToUInt32(Data, 0x00); + set => BitConverter.GetBytes(value).CopyTo(Data, 0x00); + } + + public uint PriceWatts + { + get => BitConverter.ToUInt32(Data, 0x04); + set => BitConverter.GetBytes(value).CopyTo(Data, 0x04); + } + + public uint PriceAlternate // BP, Dynite Ore + { + get => BitConverter.ToUInt32(Data, 0x08); + set => BitConverter.GetBytes(value).CopyTo(Data, 0x08); + } + + public PouchID Pouch + { + get => (PouchID)(Data[0x11] & 0xF); + set => Data[0x11] = (byte)((Data[0x11] & 0xF0) | ((byte)value & 0xF)); + } + + public byte EffectField + { + get => Data[0x13]; + set => Data[0x13] = value; + } + + public int ItemSprite + { + get => BitConverter.ToInt16(Data, 0x1A); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1A); + } + + public GroupIndexType GroupType + { + get => (GroupIndexType)Data[0x1C]; + set => Data[0x1C] = (byte)value; + } + + public bool CanUseOnPokemon + { + get => Data[0x15] == 1; + set => Data[0x15] = (byte)(value ? 1 : 0); + } + + public byte GroupIndex + { + get => Data[0x1D]; + set => Data[0x1D] = value; + } + + public byte Boost0 + { + get => Data[0x1F]; + set => Data[0x1F] = value; + } + + public byte Boost1 + { + get => Data[0x20]; + set => Data[0x20] = value; + } + + public byte Boost2 + { + get => Data[0x21]; + set => Data[0x21] = value; + } + + public byte Boost3 + { + get => Data[0x22]; + set => Data[0x22] = value; + } + + public static Item8[] GetArray(byte[] bin) + { + int numEntries = BitConverter.ToUInt16(bin, 0); + int maxEntryIndex = BitConverter.ToUInt16(bin, 4); + int entriesStart = (int)BitConverter.ToUInt32(bin, 0x40); + var result = new Item8[numEntries]; + for (var i = 0; i < result.Length; i++) + { + var entryIndex = BitConverter.ToUInt16(bin, 0x44 + (2 * i)); + if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } + result[i] = new Item8(i, bin.Slice(entriesStart + (entryIndex * SIZE), SIZE)); + } + + return result; + } + + public static byte[] SetArray(Item8[] array, byte[] bin) + { + bin = (byte[])bin.Clone(); + if (array.Length != BitConverter.ToInt16(bin, 0)) + throw new ArgumentException("Incompatible sizes"); + + int maxEntryIndex = BitConverter.ToUInt16(bin, 4); + int entriesStart = (int)BitConverter.ToUInt32(bin, 0x40); + for (int i = 0; i < array.Length; i++) + { + var entryIndex = BitConverter.ToUInt16(bin, 0x44 + (2 * i)); + if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } + + var data = array[i].Data; + data.CopyTo(bin, entriesStart + (entryIndex * SIZE)); + } + + return bin; + } + + public enum PouchID : byte + { + Medicine, + Balls, + Battle, + Berries, + Items, + TMs, + Treasures, + Ingredients, + Key, + } + + public enum GroupIndexType : byte + { + None = 0, + Ball = 1, + _2 = 2, // unused? + Berries = 3, + TM = 4, + Gems = 5, // only for Normal Gem, rest are unused items + } +} diff --git a/pkNX.Structures/Item/Item8a.cs b/pkNX.Structures/Item/Item8a.cs index ed47ec8c..2c0ea5ce 100644 --- a/pkNX.Structures/Item/Item8a.cs +++ b/pkNX.Structures/Item/Item8a.cs @@ -1,194 +1,193 @@ -using System; +using System; using System.ComponentModel; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Item8a { - public class Item8a + private const int SIZE = 0x3C; + public readonly int ItemID; + public readonly byte[] Data; + + private const string Battle = "Battle"; + private const string Field = "Field"; + private const string Mart = "Mart"; + private const string Heal = "Heal"; + + public Item8a(int id, byte[] data) => (ItemID, Data) = (id, data); + + public uint Price { get => BitConverter.ToUInt32(Data, 0x00); set => BitConverter.GetBytes(value).CopyTo(Data, 0x00); } + public uint PriceWatts { get => BitConverter.ToUInt32(Data, 0x04); set => BitConverter.GetBytes(value).CopyTo(Data, 0x04); } + public uint MeritPrice { get => BitConverter.ToUInt32(Data, 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, 0x08); } + public byte BattleEffect { get => Data[0x0C]; set => Data[0x0C] = value; } + public byte BattleArg { get => Data[0x0D]; set => Data[0x0D] = value; } + public byte BerryValue { get => Data[0x0F]; set => Data[0x0F] = value; } + public byte Unk_0x10 { get => Data[0x10]; set => Data[0x10] = value; } + public PouchID8a Pouch { - private const int SIZE = 0x3C; - public readonly int ItemID; - public readonly byte[] Data; + get => (PouchID8a)(Data[0x11] & 0xF); + set => Data[0x11] = (byte)((Data[0x11] & 0xF0) | ((byte)value & 0xF)); + } - private const string Battle = "Battle"; - private const string Field = "Field"; - private const string Mart = "Mart"; - private const string Heal = "Heal"; + public ItemFlags8a Unknown + { + get => (ItemFlags8a)(Data[0x11] >> 4); + set => Data[0x11] = (byte)((Data[0x11] & 0x0F) | (((byte)value & 0xF) << 4)); + } - public Item8a(int id, byte[] data) => (ItemID, Data) = (id, data); + public byte FlingPower { get => Data[0x12]; set => Data[0x12] = value; } + public FieldItemType Unk_0x13 { get => (FieldItemType)Data[0x13]; set => Data[0x13] = (byte)value; } + public BattlePouch8a BattlePouch { get => (BattlePouch8a)Data[0x14]; set => Data[0x14] = (byte)value; } + public bool CanUse { get => Data[0x15] != 0; set => Data[0x15] = (byte)(value ? 1 : 0); } + public ItemType8a ItemType { get => (ItemType8a)Data[0x16]; set => Data[0x16] = (byte)value; } + public byte Unk_0x17 { get => Data[0x17]; set => Data[0x17] = value; } + public byte SortIndex { get => Data[0x18]; set => Data[0x18] = value; } + // 0x19 align + public short ItemSprite { get => BitConverter.ToInt16(Data, 0x1A); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1A); } + public ushort MaxQuantity { get => BitConverter.ToUInt16(Data, 0x1C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1C); } + public ushort Percentage { get => BitConverter.ToUInt16(Data, 0x1E); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1E); } + public ItemClass8a ItemGroup { get => (ItemClass8a)Data[0x20]; set => Data[0x20] = (byte)value; } + public byte Variant { get => Data[0x21]; set => Data[0x21] = value; } + // 22 unused + // 23 unused + public BattleStatusFlags CureInflict { get => (BattleStatusFlags)Data[0x24]; set => Data[0x24] = (byte)value; } + public byte BallID { get => Data[0x24]; set => Data[0x24] = value; } // same offset as above + public byte Boost0 { get => Data[0x25]; set => Data[0x25] = value; } + public byte Boost1 { get => Data[0x26]; set => Data[0x26] = value; } + public byte Boost2 { get => Data[0x27]; set => Data[0x27] = value; } + public byte Boost3 { get => Data[0x28]; set => Data[0x28] = value; } + public ItemFlags1 FunctionFlags0 { get => (ItemFlags1)Data[0x29]; set => Data[0x29] = (byte)value; } + public ItemFlags2 FunctionFlags1 { get => (ItemFlags2)Data[0x2A]; set => Data[0x2A] = (byte)value; } + public sbyte EVHP { get => (sbyte)Data[0x2B]; set => Data[0x2B] = (byte)value; } + public sbyte EVATK { get => (sbyte)Data[0x2C]; set => Data[0x2C] = (byte)value; } + public sbyte EVDEF { get => (sbyte)Data[0x2D]; set => Data[0x2D] = (byte)value; } + public sbyte EVSPE { get => (sbyte)Data[0x2E]; set => Data[0x2E] = (byte)value; } + public sbyte EVSPA { get => (sbyte)Data[0x2F]; set => Data[0x2F] = (byte)value; } + public sbyte EVSPD { get => (sbyte)Data[0x30]; set => Data[0x30] = (byte)value; } + public Heal HealAmount { get => (Heal)Data[0x31]; set => Data[0x31] = (byte)value; } + public byte PPGain { get => Data[0x32]; set => Data[0x32] = value; } + public sbyte FriendshipGain1 { get => (sbyte)Data[0x33]; set => Data[0x33] = (byte)value; } + public sbyte FriendshipGain2 { get => (sbyte)Data[0x34]; set => Data[0x34] = (byte)value; } + public sbyte FriendshipGain3 { get => (sbyte)Data[0x35]; set => Data[0x35] = (byte)value; } + public byte Flags_36 { get => Data[0x36]; set => Data[0x36] = value; } + public byte EffectTurns1 { get => Data[0x37]; set => Data[0x37] = value; } // duration? + public byte EffectTurns2 { get => Data[0x38]; set => Data[0x38] = value; } // duration? + public byte EffectTurns3 { get => Data[0x39]; set => Data[0x39] = value; } // duration? + public sbyte StatChangeAmount { get => (sbyte)Data[0x3A]; set => Data[0x3A] = (byte)value; } + // 0x1B unused - public uint Price { get => BitConverter.ToUInt32(Data, 0x00); set => BitConverter.GetBytes(value).CopyTo(Data, 0x00); } - public uint PriceWatts { get => BitConverter.ToUInt32(Data, 0x04); set => BitConverter.GetBytes(value).CopyTo(Data, 0x04); } - public uint MeritPrice { get => BitConverter.ToUInt32(Data, 0x08); set => BitConverter.GetBytes(value).CopyTo(Data, 0x08); } - public byte BattleEffect { get => Data[0x0C]; set => Data[0x0C] = value; } - public byte BattleArg { get => Data[0x0D]; set => Data[0x0D] = value; } - public byte BerryValue { get => Data[0x0F]; set => Data[0x0F] = value; } - public byte Unk_0x10 { get => Data[0x10]; set => Data[0x10] = value; } - public PouchID8a Pouch + public static Item8a[] GetArray(byte[] bin) + { + int numEntries = BitConverter.ToUInt16(bin, 0); + int maxEntryIndex = BitConverter.ToUInt16(bin, 4); + int entriesStart = (int)BitConverter.ToUInt32(bin, 0x48); + var result = new Item8a[numEntries]; + for (var i = 0; i < result.Length; i++) { - get => (PouchID8a)(Data[0x11] & 0xF); - set => Data[0x11] = (byte)((Data[0x11] & 0xF0) | ((byte)value & 0xF)); + var entryIndex = BitConverter.ToUInt16(bin, 0x4C + (2 * i)); + if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } + result[i] = new Item8a(i, bin.Slice(entriesStart + (entryIndex * SIZE), SIZE)); } - public ItemFlags8a Unknown + return result; + } + + public static byte[] SetArray(Item8a[] array, byte[] bin) + { + bin = (byte[])bin.Clone(); + if (array.Length != BitConverter.ToInt16(bin, 0)) + throw new ArgumentException("Incompatible sizes"); + + int maxEntryIndex = BitConverter.ToUInt16(bin, 4); + int entriesStart = (int)BitConverter.ToUInt32(bin, 0x48); + for (int i = 0; i < array.Length; i++) { - get => (ItemFlags8a)(Data[0x11] >> 4); - set => Data[0x11] = (byte)((Data[0x11] & 0x0F) | (((byte)value & 0xF) << 4)); + var entryIndex = BitConverter.ToUInt16(bin, 0x4C + (2 * i)); + if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } + + var data = array[i].Data; + data.CopyTo(bin, entriesStart + (entryIndex * SIZE)); } - public byte FlingPower { get => Data[0x12]; set => Data[0x12] = value; } - public FieldItemType Unk_0x13 { get => (FieldItemType)Data[0x13]; set => Data[0x13] = (byte)value; } - public BattlePouch8a BattlePouch { get => (BattlePouch8a)Data[0x14]; set => Data[0x14] = (byte)value; } - public bool CanUse { get => Data[0x15] != 0; set => Data[0x15] = (byte)(value ? 1 : 0); } - public ItemType8a ItemType { get => (ItemType8a)Data[0x16]; set => Data[0x16] = (byte)value; } - public byte Unk_0x17 { get => Data[0x17]; set => Data[0x17] = value; } - public byte SortIndex { get => Data[0x18]; set => Data[0x18] = value; } - // 0x19 align - public short ItemSprite { get => BitConverter.ToInt16(Data, 0x1A); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1A); } - public ushort MaxQuantity { get => BitConverter.ToUInt16(Data, 0x1C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1C); } - public ushort Percentage { get => BitConverter.ToUInt16(Data, 0x1E); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1E); } - public ItemClass8a ItemGroup { get => (ItemClass8a)Data[0x20]; set => Data[0x20] = (byte)value; } - public byte Variant { get => Data[0x21]; set => Data[0x21] = value; } - // 22 unused - // 23 unused - public BattleStatusFlags CureInflict { get => (BattleStatusFlags)Data[0x24]; set => Data[0x24] = (byte)value; } - public byte BallID { get => Data[0x24]; set => Data[0x24] = value; } // same offset as above - public byte Boost0 { get => Data[0x25]; set => Data[0x25] = value; } - public byte Boost1 { get => Data[0x26]; set => Data[0x26] = value; } - public byte Boost2 { get => Data[0x27]; set => Data[0x27] = value; } - public byte Boost3 { get => Data[0x28]; set => Data[0x28] = value; } - public ItemFlags1 FunctionFlags0 { get => (ItemFlags1)Data[0x29]; set => Data[0x29] = (byte)value; } - public ItemFlags2 FunctionFlags1 { get => (ItemFlags2)Data[0x2A]; set => Data[0x2A] = (byte)value; } - public sbyte EVHP { get => (sbyte)Data[0x2B]; set => Data[0x2B] = (byte)value; } - public sbyte EVATK { get => (sbyte)Data[0x2C]; set => Data[0x2C] = (byte)value; } - public sbyte EVDEF { get => (sbyte)Data[0x2D]; set => Data[0x2D] = (byte)value; } - public sbyte EVSPE { get => (sbyte)Data[0x2E]; set => Data[0x2E] = (byte)value; } - public sbyte EVSPA { get => (sbyte)Data[0x2F]; set => Data[0x2F] = (byte)value; } - public sbyte EVSPD { get => (sbyte)Data[0x30]; set => Data[0x30] = (byte)value; } - public Heal HealAmount { get => (Heal)Data[0x31]; set => Data[0x31] = (byte)value; } - public byte PPGain { get => Data[0x32]; set => Data[0x32] = value; } - public sbyte FriendshipGain1 { get => (sbyte)Data[0x33]; set => Data[0x33] = (byte)value; } - public sbyte FriendshipGain2 { get => (sbyte)Data[0x34]; set => Data[0x34] = (byte)value; } - public sbyte FriendshipGain3 { get => (sbyte)Data[0x35]; set => Data[0x35] = (byte)value; } - public byte Flags_36 { get => Data[0x36]; set => Data[0x36] = value; } - public byte EffectTurns1 { get => Data[0x37]; set => Data[0x37] = value; } // duration? - public byte EffectTurns2 { get => Data[0x38]; set => Data[0x38] = value; } // duration? - public byte EffectTurns3 { get => Data[0x39]; set => Data[0x39] = value; } // duration? - public sbyte StatChangeAmount { get => (sbyte)Data[0x3A]; set => Data[0x3A] = (byte)value; } - // 0x1B unused - - public static Item8a[] GetArray(byte[] bin) - { - int numEntries = BitConverter.ToUInt16(bin, 0); - int maxEntryIndex = BitConverter.ToUInt16(bin, 4); - int entriesStart = (int)BitConverter.ToUInt32(bin, 0x48); - var result = new Item8a[numEntries]; - for (var i = 0; i < result.Length; i++) - { - var entryIndex = BitConverter.ToUInt16(bin, 0x4C + (2 * i)); - if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } - result[i] = new Item8a(i, bin.Slice(entriesStart + (entryIndex * SIZE), SIZE)); - } - - return result; - } - - public static byte[] SetArray(Item8a[] array, byte[] bin) - { - bin = (byte[])bin.Clone(); - if (array.Length != BitConverter.ToInt16(bin, 0)) - throw new ArgumentException("Incompatible sizes"); - - int maxEntryIndex = BitConverter.ToUInt16(bin, 4); - int entriesStart = (int)BitConverter.ToUInt32(bin, 0x48); - for (int i = 0; i < array.Length; i++) - { - var entryIndex = BitConverter.ToUInt16(bin, 0x4C + (2 * i)); - if (entryIndex >= maxEntryIndex) { throw new ArgumentException(); } - - var data = array[i].Data; - data.CopyTo(bin, entriesStart + (entryIndex * SIZE)); - } - - return bin; - } - - [Category(Field)] public bool Revive { get => ((Boost0 >> 0) & 1) == 0; set => Boost0 = (byte)((Boost0 & ~(1 << 0)) | ((value ? 1 : 0) << 0)); } - [Category(Field)] public bool ReviveAll { get => ((Boost0 >> 1) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 1)) | ((value ? 1 : 0) << 1)); } - [Category(Field)] public bool LevelUp { get => ((Boost0 >> 2) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 2)) | ((value ? 1 : 0) << 2)); } - [Category(Field)] public bool EvoStone { get => ((Boost0 >> 3) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 3)) | ((value ? 1 : 0) << 3)); } - [Category(Battle)] public int BoostATK { get => Boost0 >> 4; set => Boost0 = (byte)((Boost0 & 0xF) | (value << 4)); } - [Category(Battle)] public int BoostDEF { get => Boost1 & 0xF; set => Boost1 = (byte)((Boost1 & ~0xF) | (value & 0xF)); } - [Category(Battle)] public int BoostSPA { get => Boost1 >> 4; set => Boost1 = (byte)((Boost1 & 0xF) | (value << 4)); } - [Category(Battle)] public int BoostSPD { get => Boost2 & 0xF; set => Boost2 = (byte)((Boost2 & ~0xF) | (value & 0xF)); } - [Category(Battle)] public int BoostSPE { get => Boost2 >> 4; set => Boost2 = (byte)((Boost2 & 0xF) | (value << 4)); } - [Category(Battle)] public int BoostACC { get => Boost3 & 0xF; set => Boost3 = (byte)((Boost3 & ~0xF) | (value & 0xF)); } - [Category(Battle)] public int BoostCRIT { get => (Boost3 >> 4) & 3; set => Boost3 = (byte)((Boost3 & ~0x30) | ((value & 3) << 4)); } - [Category(Battle)] public int BoostPP1 { get => (Boost3 >> 6) & 1; set => Boost3 = (byte)((Boost3 & 0xBF) | ((value & 1) << 6)); } - [Category(Battle)] public int BoostPPMax { get => (Boost3 >> 7) & 1; set => Boost3 = (byte)((Boost3 & 0x7F) | ((value & 1) << 7)); } + return bin; } - public enum ItemClass8a - { - None, - Ball = 1, - Berry = 3, - TM = 4, - Gem = 6, - Charm = 14, - Plate = 15, - } - - public enum ItemType8a : byte - { - Pocket = 0, - Medicinal = 1, - Equip = 2, - Treasure = 3, - BattleItem = 4, - Ball = 5, - Mail = 6, - TM = 7, - Berry = 8, - Key = 9, - LegendItemUseBattle = 10, - LegendItemToss = 11, - Rare = 12, - Dummy = 255, - } - - public enum BattlePouch8a : byte - { - None = 0, - Balls = 1, - Use = 2, - } - - public enum PouchID8a : byte - { - Regular, - Key, - Recipe, - } - - [Flags] - public enum ItemFlags8a : byte - { - None = 0, - Flag1 = 1, - Flag2 = 2, - Flag4 = 4, - Flag8 = 8, - } - - public enum FieldItemType : byte - { - Inert, - Medicine = 1, - TM = 2, - Spray = 5, - Evolution = 6, - EscapeRope = 7, - Berry = 12, - FormChange = 15, - } + [Category(Field)] public bool Revive { get => ((Boost0 >> 0) & 1) == 0; set => Boost0 = (byte)((Boost0 & ~(1 << 0)) | ((value ? 1 : 0) << 0)); } + [Category(Field)] public bool ReviveAll { get => ((Boost0 >> 1) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 1)) | ((value ? 1 : 0) << 1)); } + [Category(Field)] public bool LevelUp { get => ((Boost0 >> 2) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 2)) | ((value ? 1 : 0) << 2)); } + [Category(Field)] public bool EvoStone { get => ((Boost0 >> 3) & 1) == 1; set => Boost0 = (byte)((Boost0 & ~(1 << 3)) | ((value ? 1 : 0) << 3)); } + [Category(Battle)] public int BoostATK { get => Boost0 >> 4; set => Boost0 = (byte)((Boost0 & 0xF) | (value << 4)); } + [Category(Battle)] public int BoostDEF { get => Boost1 & 0xF; set => Boost1 = (byte)((Boost1 & ~0xF) | (value & 0xF)); } + [Category(Battle)] public int BoostSPA { get => Boost1 >> 4; set => Boost1 = (byte)((Boost1 & 0xF) | (value << 4)); } + [Category(Battle)] public int BoostSPD { get => Boost2 & 0xF; set => Boost2 = (byte)((Boost2 & ~0xF) | (value & 0xF)); } + [Category(Battle)] public int BoostSPE { get => Boost2 >> 4; set => Boost2 = (byte)((Boost2 & 0xF) | (value << 4)); } + [Category(Battle)] public int BoostACC { get => Boost3 & 0xF; set => Boost3 = (byte)((Boost3 & ~0xF) | (value & 0xF)); } + [Category(Battle)] public int BoostCRIT { get => (Boost3 >> 4) & 3; set => Boost3 = (byte)((Boost3 & ~0x30) | ((value & 3) << 4)); } + [Category(Battle)] public int BoostPP1 { get => (Boost3 >> 6) & 1; set => Boost3 = (byte)((Boost3 & 0xBF) | ((value & 1) << 6)); } + [Category(Battle)] public int BoostPPMax { get => (Boost3 >> 7) & 1; set => Boost3 = (byte)((Boost3 & 0x7F) | ((value & 1) << 7)); } +} + +public enum ItemClass8a +{ + None, + Ball = 1, + Berry = 3, + TM = 4, + Gem = 6, + Charm = 14, + Plate = 15, +} + +public enum ItemType8a : byte +{ + Pocket = 0, + Medicinal = 1, + Equip = 2, + Treasure = 3, + BattleItem = 4, + Ball = 5, + Mail = 6, + TM = 7, + Berry = 8, + Key = 9, + LegendItemUseBattle = 10, + LegendItemToss = 11, + Rare = 12, + Dummy = 255, +} + +public enum BattlePouch8a : byte +{ + None = 0, + Balls = 1, + Use = 2, +} + +public enum PouchID8a : byte +{ + Regular, + Key, + Recipe, +} + +[Flags] +public enum ItemFlags8a : byte +{ + None = 0, + Flag1 = 1, + Flag2 = 2, + Flag4 = 4, + Flag8 = 8, +} + +public enum FieldItemType : byte +{ + Inert, + Medicine = 1, + TM = 2, + Spray = 5, + Evolution = 6, + EscapeRope = 7, + Berry = 12, + FormChange = 15, } diff --git a/pkNX.Structures/Item/ItemFlags1.cs b/pkNX.Structures/Item/ItemFlags1.cs index ccef4331..e9693c5d 100644 --- a/pkNX.Structures/Item/ItemFlags1.cs +++ b/pkNX.Structures/Item/ItemFlags1.cs @@ -1,18 +1,17 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum ItemFlags1 : byte { - [Flags] - public enum ItemFlags1 : byte - { - None, - RestorePP = 1 << 0, - RestorePPAll = 1 << 1, - RestoreHP = 1 << 2, - AddEVHP = 1 << 3, - AddEVAtk = 1 << 4, - AddEVDef = 1 << 5, - AddEVSpe = 1 << 6, - AddEVSpA = 1 << 7, - } -} \ No newline at end of file + None, + RestorePP = 1 << 0, + RestorePPAll = 1 << 1, + RestoreHP = 1 << 2, + AddEVHP = 1 << 3, + AddEVAtk = 1 << 4, + AddEVDef = 1 << 5, + AddEVSpe = 1 << 6, + AddEVSpA = 1 << 7, +} diff --git a/pkNX.Structures/Item/ItemFlags2.cs b/pkNX.Structures/Item/ItemFlags2.cs index 8afb6955..401e5258 100644 --- a/pkNX.Structures/Item/ItemFlags2.cs +++ b/pkNX.Structures/Item/ItemFlags2.cs @@ -1,18 +1,17 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum ItemFlags2 : byte { - [Flags] - public enum ItemFlags2 : byte - { - None, - AddEVSpD = 1 << 0, - AddEVAbove100 = 1 << 1, - AddFriendship1 = 1 << 2, - AddFriendship2 = 1 << 3, - AddFriendship3 = 1 << 4, - Unused1 = 1 << 5, - Unused2 = 1 << 6, - Unused3 = 1 << 7, - } -} \ No newline at end of file + None, + AddEVSpD = 1 << 0, + AddEVAbove100 = 1 << 1, + AddFriendship1 = 1 << 2, + AddFriendship2 = 1 << 3, + AddFriendship3 = 1 << 4, + Unused1 = 1 << 5, + Unused2 = 1 << 6, + Unused3 = 1 << 7, +} diff --git a/pkNX.Structures/Learnset/Learnset.cs b/pkNX.Structures/Learnset/Learnset.cs index 26db8361..49154771 100644 --- a/pkNX.Structures/Learnset/Learnset.cs +++ b/pkNX.Structures/Learnset/Learnset.cs @@ -1,103 +1,102 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class Learnset { - public abstract class Learnset + public int Count { get; protected set; } + public int[] Moves { get; protected set; } + public int[] Levels { get; protected set; } + + protected Learnset() { - public int Count { get; protected set; } - public int[] Moves { get; protected set; } - public int[] Levels { get; protected set; } + Moves = Array.Empty(); + Levels = Array.Empty(); + } - protected Learnset() + public abstract byte[] Write(); + + /// + /// Returns the moves a Pokémon can learn between the specified level range. + /// + /// Maximum level + /// Minimum level + /// Array of Move IDs + public int[] GetMoves(int maxLevel, int minLevel = 0) + { + if (minLevel <= 1 && maxLevel >= 100) + return Moves; + if (minLevel > maxLevel) + return Array.Empty(); + int start = Array.FindIndex(Levels, z => z >= minLevel); + if (start < 0) + return Array.Empty(); + int end = Array.FindLastIndex(Levels, z => z <= maxLevel); + if (end < 0) + return Array.Empty(); + int[] result = new int[end - start + 1]; + Array.Copy(Moves, start, result, 0, result.Length); + return result; + } + + /// Returns the moves a Pokémon would have if it were encountered at the specified level. + /// In Generation 1, it is not possible to learn any moves lower than these encounter moves. + /// The level the Pokémon was encountered at. + /// Array of Move IDs + public int[] GetEncounterMoves(int level) + { + const int count = 4; + IList moves = new int[count]; + int ctr = 0; + for (int i = 0; i < Moves.Length; i++) { - Moves = Array.Empty(); - Levels = Array.Empty(); + if (Levels[i] > level) + break; + int move = Moves[i]; + if (moves.Contains(move)) + continue; + + moves[ctr++] = move; + ctr &= 3; } + return (int[])moves; + } - public abstract byte[] Write(); + /// Returns the index of the lowest level move if the Pokémon were encountered at the specified level. + /// Helps determine the minimum level an encounter can be at. + /// The level the Pokémon was encountered at. + /// Array of Move IDs + public int GetMinMoveLevel(int level) + { + if (Levels.Length == 0) + return 1; - /// - /// Returns the moves a Pokémon can learn between the specified level range. - /// - /// Maximum level - /// Minimum level - /// Array of Move IDs - public int[] GetMoves(int maxLevel, int minLevel = 0) - { - if (minLevel <= 1 && maxLevel >= 100) - return Moves; - if (minLevel > maxLevel) - return Array.Empty(); - int start = Array.FindIndex(Levels, z => z >= minLevel); - if (start < 0) - return Array.Empty(); - int end = Array.FindLastIndex(Levels, z => z <= maxLevel); - if (end < 0) - return Array.Empty(); - int[] result = new int[end - start + 1]; - Array.Copy(Moves, start, result, 0, result.Length); - return result; - } + int end = Array.FindLastIndex(Levels, z => z <= level); + return Math.Max(end - 4, 1); + } - /// Returns the moves a Pokémon would have if it were encountered at the specified level. - /// In Generation 1, it is not possible to learn any moves lower than these encounter moves. - /// The level the Pokémon was encountered at. - /// Array of Move IDs - public int[] GetEncounterMoves(int level) - { - const int count = 4; - IList moves = new int[count]; - int ctr = 0; - for (int i = 0; i < Moves.Length; i++) - { - if (Levels[i] > level) - break; - int move = Moves[i]; - if (moves.Contains(move)) - continue; + /// Returns the level that a Pokémon can learn the specified move. + /// Move ID + /// Level the move is learned at. If the result is below 0, it cannot be learned by levelup. + public int GetLevelLearnMove(int move) + { + int index = Array.IndexOf(Moves, move); + return index < 0 ? index : Levels[index]; + } - moves[ctr++] = move; - ctr &= 3; - } - return (int[])moves; - } + public void Update(int[] moves, int[] levels) + { + Moves = moves; + Levels = levels; + Count = Moves.Length; + } - /// Returns the index of the lowest level move if the Pokémon were encountered at the specified level. - /// Helps determine the minimum level an encounter can be at. - /// The level the Pokémon was encountered at. - /// Array of Move IDs - public int GetMinMoveLevel(int level) - { - if (Levels.Length == 0) - return 1; - - int end = Array.FindLastIndex(Levels, z => z <= level); - return Math.Max(end - 4, 1); - } - - /// Returns the level that a Pokémon can learn the specified move. - /// Move ID - /// Level the move is learned at. If the result is below 0, it cannot be learned by levelup. - public int GetLevelLearnMove(int move) - { - int index = Array.IndexOf(Moves, move); - return index < 0 ? index : Levels[index]; - } - - public void Update(int[] moves, int[] levels) - { - Moves = moves; - Levels = levels; - Count = Moves.Length; - } - - public int[] GetHighPoweredMoves(int count, IReadOnlyList movedata) - { - var moves = Moves.OrderByDescending(move => movedata[move].Power).Distinct().Take(count).ToArray(); - Array.Resize(ref moves, count); - return moves; - } + public int[] GetHighPoweredMoves(int count, IReadOnlyList movedata) + { + var moves = Moves.OrderByDescending(move => movedata[move].Power).Distinct().Take(count).ToArray(); + Array.Resize(ref moves, count); + return moves; } } diff --git a/pkNX.Structures/Learnset/Learnset6.cs b/pkNX.Structures/Learnset/Learnset6.cs index 939ae4de..59b7020a 100644 --- a/pkNX.Structures/Learnset/Learnset6.cs +++ b/pkNX.Structures/Learnset/Learnset6.cs @@ -1,46 +1,45 @@ -using System; +using System; using System.IO; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Learnset6 : Learnset { - public class Learnset6 : Learnset + public Learnset6(byte[] data) { - public Learnset6(byte[] data) + if (data.Length < 4 || data.Length % 4 != 0) + { Count = 0; Levels = Moves = Array.Empty(); return; } + Count = (data.Length / 4) - 1; + Moves = new int[Count]; + Levels = new int[Count]; + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + for (int i = 0; i < Count; i++) { - if (data.Length < 4 || data.Length % 4 != 0) - { Count = 0; Levels = Moves = Array.Empty(); return; } - Count = (data.Length / 4) - 1; - Moves = new int[Count]; - Levels = new int[Count]; - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - for (int i = 0; i < Count; i++) - { - Moves[i] = br.ReadInt16(); - Levels[i] = br.ReadInt16(); - } - } - - public override byte[] Write() - { - Count = (ushort)Moves.Length; - using MemoryStream ms = new MemoryStream(); - using BinaryWriter bw = new BinaryWriter(ms); - for (int i = 0; i < Count; i++) - { - bw.Write((short)Moves[i]); - bw.Write((short)Levels[i]); - } - bw.Write(-1); - return ms.ToArray(); - } - - public static Learnset[] GetArray(byte[][] entries) - { - Learnset[] data = new Learnset[entries.Length]; - for (int i = 0; i < data.Length; i++) - data[i] = new Learnset6(entries[i]); - return data; + Moves[i] = br.ReadInt16(); + Levels[i] = br.ReadInt16(); } } -} \ No newline at end of file + + public override byte[] Write() + { + Count = (ushort)Moves.Length; + using MemoryStream ms = new MemoryStream(); + using BinaryWriter bw = new BinaryWriter(ms); + for (int i = 0; i < Count; i++) + { + bw.Write((short)Moves[i]); + bw.Write((short)Levels[i]); + } + bw.Write(-1); + return ms.ToArray(); + } + + public static Learnset[] GetArray(byte[][] entries) + { + Learnset[] data = new Learnset[entries.Length]; + for (int i = 0; i < data.Length; i++) + data[i] = new Learnset6(entries[i]); + return data; + } +} diff --git a/pkNX.Structures/Learnset/Learnset8.cs b/pkNX.Structures/Learnset/Learnset8.cs index 8d87bb89..2a7c1558 100644 --- a/pkNX.Structures/Learnset/Learnset8.cs +++ b/pkNX.Structures/Learnset/Learnset8.cs @@ -1,67 +1,66 @@ -using System; +using System; using System.IO; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Learnset8 : Learnset { - public class Learnset8 : Learnset + private const int SIZE = 0x104; + + public Learnset8(byte[] data) { - private const int SIZE = 0x104; - - public Learnset8(byte[] data) + // scan for count + int count = 0; + for (; count < SIZE / 4; count++) { - // scan for count - int count = 0; - for (; count < SIZE / 4; count++) - { - if (data[(count * 4) + 3] == 0xFF) // check 3rd byte of each u16/u16 tuple, level is never > 255 - break; - } - - Count = count; - if (Count == 0) - { - Levels = Moves = Array.Empty(); - return; - } - - Moves = new int[Count]; - Levels = new int[Count]; - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - for (int i = 0; i < Count; i++) - { - Moves[i] = br.ReadInt16(); - Levels[i] = br.ReadInt16(); - } + if (data[(count * 4) + 3] == 0xFF) // check 3rd byte of each u16/u16 tuple, level is never > 255 + break; } - public override byte[] Write() + Count = count; + if (Count == 0) { - Count = (ushort)Moves.Length; - using MemoryStream ms = new MemoryStream(); - using BinaryWriter bw = new BinaryWriter(ms); - for (int i = 0; i < Count; i++) - { - bw.Write((short)Moves[i]); - bw.Write((short)Levels[i]); - } - while (bw.BaseStream.Length != SIZE) - bw.Write(-1); - return ms.ToArray(); + Levels = Moves = Array.Empty(); + return; } - public byte[] WriteAsLearn6() + Moves = new int[Count]; + Levels = new int[Count]; + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + for (int i = 0; i < Count; i++) { - using var ms = new MemoryStream(); - using var br = new BinaryWriter(ms); - for (int j = 0; j < Moves.Length; j++) - { - br.Write((ushort)Moves[j]); - br.Write((ushort)Levels[j]); - } - - br.Write(-1); - return ms.ToArray(); + Moves[i] = br.ReadInt16(); + Levels[i] = br.ReadInt16(); } } -} \ No newline at end of file + + public override byte[] Write() + { + Count = (ushort)Moves.Length; + using MemoryStream ms = new MemoryStream(); + using BinaryWriter bw = new BinaryWriter(ms); + for (int i = 0; i < Count; i++) + { + bw.Write((short)Moves[i]); + bw.Write((short)Levels[i]); + } + while (bw.BaseStream.Length != SIZE) + bw.Write(-1); + return ms.ToArray(); + } + + public byte[] WriteAsLearn6() + { + using var ms = new MemoryStream(); + using var br = new BinaryWriter(ms); + for (int j = 0; j < Moves.Length; j++) + { + br.Write((ushort)Moves[j]); + br.Write((ushort)Levels[j]); + } + + br.Write(-1); + return ms.ToArray(); + } +} diff --git a/pkNX.Structures/Legality/Encounters.cs b/pkNX.Structures/Legality/Encounters.cs index a9b08e8b..126fb0a5 100644 --- a/pkNX.Structures/Legality/Encounters.cs +++ b/pkNX.Structures/Legality/Encounters.cs @@ -1,24 +1,23 @@ -using System.Linq; +using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static partial class Legal { - public static partial class Legal + public static readonly int[] BasicStarters_1 = { - public static readonly int[] BasicStarters_1 = - { - 001, 004, 007, 010, 013, 016, 029, 032, 041, 043, 060, 063, 066, 069, 074, 081, 092, 111, 116, 137, 147, - }; + 001, 004, 007, 010, 013, 016, 029, 032, 041, 043, 060, 063, 066, 069, 074, 081, 092, 111, 116, 137, 147, + }; - public static readonly int[] BasicStarters_6 = BasicStarters_1.Concat(new[] - { - 152, 155, 158, 172, 173, 174, 175, 179, 187, 220, 239, 240, 246, 252, 255, 258, 265, 270, 273, 280, 287, - 293, 298, 304, 328, 355, 363, 371, 374, 387, 390, 393, 396, 403, 406, 440, 443, 495, 498, 501, 506, 519, - 607, 610, 633, 650, 653, 656, 661, 664, 669, 679, 704, - }).ToArray(); + public static readonly int[] BasicStarters_6 = BasicStarters_1.Concat(new[] + { + 152, 155, 158, 172, 173, 174, 175, 179, 187, 220, 239, 240, 246, 252, 255, 258, 265, 270, 273, 280, 287, + 293, 298, 304, 328, 355, 363, 371, 374, 387, 390, 393, 396, 403, 406, 440, 443, 495, 498, 501, 506, 519, + 607, 610, 633, 650, 653, 656, 661, 664, 669, 679, 704, + }).ToArray(); - public static readonly int[] BasicStarters_7 = BasicStarters_6.Concat(new[] - { - 722, 725, 728, 731, 736, 761, 782, 789, - }).ToArray(); - } -} \ No newline at end of file + public static readonly int[] BasicStarters_7 = BasicStarters_6.Concat(new[] + { + 722, 725, 728, 731, 736, 761, 782, 789, + }).ToArray(); +} diff --git a/pkNX.Structures/Legality/GameInfo.cs b/pkNX.Structures/Legality/GameInfo.cs index fcddcfa9..f65bf310 100644 --- a/pkNX.Structures/Legality/GameInfo.cs +++ b/pkNX.Structures/Legality/GameInfo.cs @@ -1,124 +1,123 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Misc information pertaining to the game. +/// +public class GameInfo { - /// - /// Misc information pertaining to the game. - /// - public class GameInfo + public readonly GameVersion Game; + public readonly int Generation; + + public int MaxSpeciesID { get; private set; } + public int MaxItemID { get; private set; } + public int MaxMoveID { get; private set; } + public ushort[] HeldItems { get; private set; } + public int MaxAbilityID { get; private set; } + + public bool XY { get; private set; } + public bool AO { get; private set; } + public bool SM { get; private set; } + public bool USUM { get; private set; } + public bool GG { get; private set; } + public bool SWSH { get; private set; } + + public GameInfo(GameVersion game) { - public readonly GameVersion Game; - public readonly int Generation; - - public int MaxSpeciesID { get; private set; } - public int MaxItemID { get; private set; } - public int MaxMoveID { get; private set; } - public ushort[] HeldItems { get; private set; } - public int MaxAbilityID { get; private set; } - - public bool XY { get; private set; } - public bool AO { get; private set; } - public bool SM { get; private set; } - public bool USUM { get; private set; } - public bool GG { get; private set; } - public bool SWSH { get; private set; } - - public GameInfo(GameVersion game) - { - Game = game; - Generation = game.GetGeneration(); - GetInitMethod(game)(); - } - - private Action GetInitMethod(GameVersion game) - { - return game switch - { - GameVersion.XY => LoadXY, - GameVersion.ORASDEMO => LoadAO, - GameVersion.ORAS => LoadAO, - GameVersion.SMDEMO => LoadSM, - GameVersion.SM => LoadSM, - GameVersion.USUM => LoadUSUM, - GameVersion.GP => LoadGG, - GameVersion.GE => LoadGG, - GameVersion.GG => LoadGG, - GameVersion.SW => LoadSWSH, - GameVersion.SH => LoadSWSH, - GameVersion.SWSH => LoadSWSH, - GameVersion.PLA => LoadPLA, - _ => throw new ArgumentException(nameof(game)) - }; - } - - private void LoadXY() - { - XY = true; - MaxSpeciesID = Legal.MaxSpeciesID_6; - MaxMoveID = Legal.MaxMoveID_6_XY; - MaxItemID = Legal.MaxItemID_6_XY; - HeldItems = Legal.HeldItem_XY; - MaxAbilityID = Legal.MaxAbilityID_6_XY; - } - - private void LoadAO() - { - AO = true; - MaxSpeciesID = Legal.MaxSpeciesID_6; - MaxMoveID = Legal.MaxMoveID_6_AO; - MaxItemID = Legal.MaxItemID_6_AO; - HeldItems = Legal.HeldItem_AO; - MaxAbilityID = Legal.MaxAbilityID_6_AO; - } - - private void LoadSM() - { - SM = true; - MaxSpeciesID = Legal.MaxSpeciesID_7_SM; - MaxMoveID = Legal.MaxMoveID_7_SM; - MaxItemID = Legal.MaxItemID_7_SM; - HeldItems = Legal.HeldItems_SM; - MaxAbilityID = Legal.MaxAbilityID_7_SM; - } - - private void LoadUSUM() - { - USUM = true; - MaxSpeciesID = Legal.MaxSpeciesID_7_USUM; - MaxMoveID = Legal.MaxMoveID_7_USUM; - MaxItemID = Legal.MaxItemID_7_USUM; - HeldItems = Legal.HeldItems_USUM; - MaxAbilityID = Legal.MaxAbilityID_7_USUM; - } - - private void LoadGG() - { - GG = true; - MaxSpeciesID = Legal.MaxSpeciesID_7_GG; - MaxMoveID = Legal.MaxMoveID_7_GG; - MaxItemID = Legal.MaxItemID_7_GG; - HeldItems = new ushort[1]; - MaxAbilityID = Legal.MaxAbilityID_7_GG; - } - - private void LoadSWSH() - { - SWSH = true; - MaxSpeciesID = Legal.MaxSpeciesID_8; - MaxMoveID = Legal.MaxMoveID_8; - MaxItemID = Legal.MaxItemID_8; - HeldItems = Legal.HeldItems_SWSH; - MaxAbilityID = Legal.MaxAbilityID_8; - } - - private void LoadPLA() - { - SWSH = true; - MaxSpeciesID = Legal.MaxSpeciesID_8a; - MaxMoveID = Legal.MaxMoveID_8a; - MaxItemID = Legal.MaxItemID_8a; - HeldItems = Legal.HeldItems_SWSH; - MaxAbilityID = Legal.MaxAbilityID_8a; - } + Game = game; + Generation = game.GetGeneration(); + GetInitMethod(game)(); } -} + + private Action GetInitMethod(GameVersion game) + { + return game switch + { + GameVersion.XY => LoadXY, + GameVersion.ORASDEMO => LoadAO, + GameVersion.ORAS => LoadAO, + GameVersion.SMDEMO => LoadSM, + GameVersion.SM => LoadSM, + GameVersion.USUM => LoadUSUM, + GameVersion.GP => LoadGG, + GameVersion.GE => LoadGG, + GameVersion.GG => LoadGG, + GameVersion.SW => LoadSWSH, + GameVersion.SH => LoadSWSH, + GameVersion.SWSH => LoadSWSH, + GameVersion.PLA => LoadPLA, + _ => throw new ArgumentException(nameof(game)) + }; + } + + private void LoadXY() + { + XY = true; + MaxSpeciesID = Legal.MaxSpeciesID_6; + MaxMoveID = Legal.MaxMoveID_6_XY; + MaxItemID = Legal.MaxItemID_6_XY; + HeldItems = Legal.HeldItem_XY; + MaxAbilityID = Legal.MaxAbilityID_6_XY; + } + + private void LoadAO() + { + AO = true; + MaxSpeciesID = Legal.MaxSpeciesID_6; + MaxMoveID = Legal.MaxMoveID_6_AO; + MaxItemID = Legal.MaxItemID_6_AO; + HeldItems = Legal.HeldItem_AO; + MaxAbilityID = Legal.MaxAbilityID_6_AO; + } + + private void LoadSM() + { + SM = true; + MaxSpeciesID = Legal.MaxSpeciesID_7_SM; + MaxMoveID = Legal.MaxMoveID_7_SM; + MaxItemID = Legal.MaxItemID_7_SM; + HeldItems = Legal.HeldItems_SM; + MaxAbilityID = Legal.MaxAbilityID_7_SM; + } + + private void LoadUSUM() + { + USUM = true; + MaxSpeciesID = Legal.MaxSpeciesID_7_USUM; + MaxMoveID = Legal.MaxMoveID_7_USUM; + MaxItemID = Legal.MaxItemID_7_USUM; + HeldItems = Legal.HeldItems_USUM; + MaxAbilityID = Legal.MaxAbilityID_7_USUM; + } + + private void LoadGG() + { + GG = true; + MaxSpeciesID = Legal.MaxSpeciesID_7_GG; + MaxMoveID = Legal.MaxMoveID_7_GG; + MaxItemID = Legal.MaxItemID_7_GG; + HeldItems = new ushort[1]; + MaxAbilityID = Legal.MaxAbilityID_7_GG; + } + + private void LoadSWSH() + { + SWSH = true; + MaxSpeciesID = Legal.MaxSpeciesID_8; + MaxMoveID = Legal.MaxMoveID_8; + MaxItemID = Legal.MaxItemID_8; + HeldItems = Legal.HeldItems_SWSH; + MaxAbilityID = Legal.MaxAbilityID_8; + } + + private void LoadPLA() + { + SWSH = true; + MaxSpeciesID = Legal.MaxSpeciesID_8a; + MaxMoveID = Legal.MaxMoveID_8a; + MaxItemID = Legal.MaxItemID_8a; + HeldItems = Legal.HeldItems_SWSH; + MaxAbilityID = Legal.MaxAbilityID_8a; + } +} \ No newline at end of file diff --git a/pkNX.Structures/Legality/Item.cs b/pkNX.Structures/Legality/Item.cs index d03bfb49..86b71c16 100644 --- a/pkNX.Structures/Legality/Item.cs +++ b/pkNX.Structures/Legality/Item.cs @@ -1,46 +1,45 @@ -using System.Linq; +using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static partial class Legal { - public static partial class Legal + private static readonly int[] Items_HeldXY = { - private static readonly int[] Items_HeldXY = - { - /* 000, */ 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012, 013, 014, 015, 017, 018, 019, 020, 021, 022, - 023, 024, 025, 026, 027, 028, 029, 030, 031, 032, 033, 034, 035, - 036, 037, 038, 039, 040, 041, 042, 043, 044, 045, 046, 047, 048, 049, 050, 051, 052, 053, 054, 055, 056, 057, - 058, 059, 060, 061, 062, 063, 064, 065, 066, 067, 068, 069, 070, - 071, 072, 073, 074, 075, 076, 077, 078, 079, 080, 081, 082, 083, 084, 085, 086, 087, 088, 089, 090, 091, 092, - 093, 094, 099, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 112, 116, 117, 118, 119, 134, 135, 136, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, - 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, - 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, - 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, - 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, - 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, - 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, - 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, - 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 504, 537, 538, 539, 540, 541, 542, 543, 544, - 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, - 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 577, 580, 581, 582, 583, 584, - 585, 586, 587, 588, 589, 590, 591, 639, 640, 644, 645, 646, 647, - 648, 649, 650, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, - 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, - 684, 685, 686, 687, 688, 699, 704, 708, 709, 710, 711, 715, - }; + /* 000, */ 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012, 013, 014, 015, 017, 018, 019, 020, 021, 022, + 023, 024, 025, 026, 027, 028, 029, 030, 031, 032, 033, 034, 035, + 036, 037, 038, 039, 040, 041, 042, 043, 044, 045, 046, 047, 048, 049, 050, 051, 052, 053, 054, 055, 056, 057, + 058, 059, 060, 061, 062, 063, 064, 065, 066, 067, 068, 069, 070, + 071, 072, 073, 074, 075, 076, 077, 078, 079, 080, 081, 082, 083, 084, 085, 086, 087, 088, 089, 090, 091, 092, + 093, 094, 099, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 112, 116, 117, 118, 119, 134, 135, 136, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, + 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, + 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, + 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, + 210, 211, 212, 213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, + 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, + 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, + 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, + 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, + 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, + 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 504, 537, 538, 539, 540, 541, 542, 543, 544, + 545, 546, 547, 548, 549, 550, 551, 552, 553, 554, 555, 556, 557, + 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 577, 580, 581, 582, 583, 584, + 585, 586, 587, 588, 589, 590, 591, 639, 640, 644, 645, 646, 647, + 648, 649, 650, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661, 662, 663, 664, 665, 666, 667, 668, 669, 670, + 671, 672, 673, 674, 675, 676, 677, 678, 679, 680, 681, 682, 683, + 684, 685, 686, 687, 688, 699, 704, 708, 709, 710, 711, 715, + }; - private static readonly int[] Items_HeldAO = Items_HeldXY.Concat(new[] - { - 534, 535, - 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 767, 768, 769, 770, - }).ToArray(); + private static readonly int[] Items_HeldAO = Items_HeldXY.Concat(new[] + { + 534, 535, + 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 767, 768, 769, 770, + }).ToArray(); - private static readonly int[] Items_Ball = - { - 000, 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012, - 013, 014, 015, 016, 492, 493, 494, 495, 496, 497, 498, 499, 576, - }; - } + private static readonly int[] Items_Ball = + { + 000, 001, 002, 003, 004, 005, 006, 007, 008, 009, 010, 011, 012, + 013, 014, 015, 016, 492, 493, 494, 495, 496, 497, 498, 499, 576, + }; } diff --git a/pkNX.Structures/Legality/Legal.cs b/pkNX.Structures/Legality/Legal.cs index 3faf93e4..f5447b63 100644 --- a/pkNX.Structures/Legality/Legal.cs +++ b/pkNX.Structures/Legality/Legal.cs @@ -1,207 +1,206 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static partial class Legal { - public static partial class Legal + /// + /// Multiplies the current level with a scaling factor, returning a modified level. + /// + /// Current Level. + /// Modification factor. + /// Boosted (or reduced) level. + public static int GetModifiedLevel(int level, double factor) { - /// - /// Multiplies the current level with a scaling factor, returning a modified level. - /// - /// Current Level. - /// Modification factor. - /// Boosted (or reduced) level. - public static int GetModifiedLevel(int level, double factor) - { - int newlvl = (int)(level * factor); - return Math.Max(1, Math.Min(newlvl, 100)); - } - - public static int[] GetRandomItemList(GameVersion game) - { - if (GameVersion.XY.Contains(game)) - return Items_HeldXY.Concat(Items_Ball).Where(i => i != 0).ToArray(); - - if (GameVersion.ORAS.Contains(game) || game == GameVersion.ORASDEMO) - return Items_HeldAO.Concat(Items_Ball).Where(i => i != 0).ToArray(); - - if (GameVersion.SM.Contains(game) || GameVersion.USUM.Contains(game)) - return HeldItemsBuy_SM.Select(i => (int)i).Concat(Items_Ball).Where(i => i != 0).ToArray(); - - if (GameVersion.GG.Contains(game)) - return HeldItems_GG.Select(i => (int)i).Where(i => i != 0).ToArray(); - - if (GameVersion.SWSH.Contains(game)) - return HeldItems_SWSH.Select(i => (int)i).Where(i => i != 0).ToArray(); - - return new int[1]; - } - - public static Dictionary GetMegaDictionary(GameVersion game) - { - if (GameVersion.XY.Contains(game)) - return MegaDictionaryXY; - if (GameVersion.GG.Contains(game)) - return MegaDictionaryGG; - return MegaDictionaryAO; - } - - private static readonly Dictionary MegaDictionaryXY = new() - { - {003, new[] {659}}, // Venusaur @ Venusaurite - {006, new[] {660, 678}}, // Charizard @ Charizardite X/Y - {009, new[] {661}}, // Blastoise @ Blastoisinite - {065, new[] {679}}, // Alakazam @ Alakazite - {094, new[] {656}}, // Gengar @ Gengarite - {115, new[] {675}}, // Kangaskhan @ Kangaskhanite - {127, new[] {671}}, // Pinsir @ Pinsirite - {130, new[] {676}}, // Gyarados @ Gyaradosite - {142, new[] {672}}, // Aerodactyl @ Aerodactylite - {150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y - {181, new[] {658}}, // Ampharos @ Ampharosite - {212, new[] {670}}, // Scizor @ Scizorite - {214, new[] {680}}, // Heracross @ Heracronite - {229, new[] {666}}, // Houndoom @ Houndoominite - {248, new[] {669}}, // Tyranitar @ Tyranitarite - {257, new[] {664}}, // Blaziken @ Blazikenite - {282, new[] {657}}, // Gardevoir @ Gardevoirite - {303, new[] {681}}, // Mawile @ Mawilite - {306, new[] {667}}, // Aggron @ Aggronite - {308, new[] {665}}, // Medicham @ Medichamite - {310, new[] {682}}, // Manectric @ Manectite - {354, new[] {668}}, // Banette @ Banettite - {359, new[] {677}}, // Absol @ Absolite - {380, new[] {684}}, // Latias @ Latiasite - {381, new[] {685}}, // Latios @ Latiosite - {445, new[] {683}}, // Garchomp @ Garchompite - {448, new[] {673}}, // Lucario @ Lucarionite - {460, new[] {674}}, // Abomasnow @ Abomasite - }; - - private static readonly Dictionary MegaDictionaryAO = new() - { - {003, new[] {659}}, // Venusaur @ Venusaurite - {006, new[] {660, 678}}, // Charizard @ Charizardite X/Y - {009, new[] {661}}, // Blastoise @ Blastoisinite - {065, new[] {679}}, // Alakazam @ Alakazite - {094, new[] {656}}, // Gengar @ Gengarite - {115, new[] {675}}, // Kangaskhan @ Kangaskhanite - {127, new[] {671}}, // Pinsir @ Pinsirite - {130, new[] {676}}, // Gyarados @ Gyaradosite - {142, new[] {672}}, // Aerodactyl @ Aerodactylite - {150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y - {181, new[] {658}}, // Ampharos @ Ampharosite - {212, new[] {670}}, // Scizor @ Scizorite - {214, new[] {680}}, // Heracross @ Heracronite - {229, new[] {666}}, // Houndoom @ Houndoominite - {248, new[] {669}}, // Tyranitar @ Tyranitarite - {257, new[] {664}}, // Blaziken @ Blazikenite - {282, new[] {657}}, // Gardevoir @ Gardevoirite - {303, new[] {681}}, // Mawile @ Mawilite - {306, new[] {667}}, // Aggron @ Aggronite - {308, new[] {665}}, // Medicham @ Medichamite - {310, new[] {682}}, // Manectric @ Manectite - {354, new[] {668}}, // Banette @ Banettite - {359, new[] {677}}, // Absol @ Absolite - {380, new[] {684}}, // Latias @ Latiasite - {381, new[] {685}}, // Latios @ Latiosite - {445, new[] {683}}, // Garchomp @ Garchompite - {448, new[] {673}}, // Lucario @ Lucarionite - {460, new[] {674}}, // Abomasnow @ Abomasite - - {015, new[] {770}}, // Beedrill @ Beedrillite - {018, new[] {762}}, // Pidgeot @ Pidgeotite - {080, new[] {760}}, // Slowbro @ Slowbronite - {208, new[] {761}}, // Steelix @ Steelixite - {254, new[] {753}}, // Sceptile @ Sceptilite - {260, new[] {752}}, // Swampert @ Swampertite - {302, new[] {754}}, // Sableye @ Sablenite - {319, new[] {759}}, // Sharpedo @ Sharpedonite - {323, new[] {767}}, // Camerupt @ Cameruptite - {334, new[] {755}}, // Altaria @ Altarianite - {362, new[] {763}}, // Glalie @ Glalitite - {373, new[] {769}}, // Salamence @ Salamencite - {376, new[] {758}}, // Metagross @ Metagrossite - // Rayquaza requires Dragon Ascent, no Held Item - {428, new[] {768}}, // Lopunny @ Lopunnite - {475, new[] {756}}, // Gallade @ Galladite - {531, new[] {757}}, // Audino @ Audinite - {719, new[] {764}}, // Diancie @ Diancite - }; - - private static readonly Dictionary MegaDictionaryGG = new() - { - {003, new[] {659}}, // Venusaur @ Venusaurite - {006, new[] {660, 678}}, // Charizard @ Charizardite X/Y - {009, new[] {661}}, // Blastoise @ Blastoisinite - {065, new[] {679}}, // Alakazam @ Alakazite - {094, new[] {656}}, // Gengar @ Gengarite - {115, new[] {675}}, // Kangaskhan @ Kangaskhanite - {127, new[] {671}}, // Pinsir @ Pinsirite - {130, new[] {676}}, // Gyarados @ Gyaradosite - {142, new[] {672}}, // Aerodactyl @ Aerodactylite - {150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y - - {015, new[] {770}}, // Beedrill @ Beedrillite - {018, new[] {762}}, // Pidgeot @ Pidgeotite - {080, new[] {760}}, // Slowbro @ Slowbronite - }; - - public static int[] GetBannedMoves(GameVersion infoGame, int moveCount) - { - if (!GameVersion.GG.Contains(infoGame)) - return Array.Empty(); - - return Enumerable.Range(0, moveCount).Except(AllowedMovesGG).ToArray(); - } - - public static int[] GetAllowedMoves(GameVersion infoGame, int moveCount) - { - if (GameVersion.GG.Contains(infoGame)) - return AllowedMovesGG; - - return Enumerable.Range(0, moveCount).ToArray(); - } - - public static readonly HashSet BattleForms = new() - { - (int)Species.Castform, - (int)Species.Cherrim, - (int)Species.Darmanitan, - (int)Species.Meloetta, - (int)Species.Aegislash, - (int)Species.Xerneas, - (int)Species.Wishiwashi, - (int)Species.Mimikyu, - (int)Species.Cramorant, - (int)Species.Eiscue, - (int)Species.Morpeko, - (int)Species.Zacian, - (int)Species.Zamazenta, - (int)Species.Eternatus, - }; - - public static readonly HashSet BattleMegas = new() - { - // XY - (int)Species.Venusaur, (int)Species.Charizard, (int)Species.Blastoise, (int)Species.Alakazam, (int)Species.Gengar, - (int)Species.Kangaskhan, (int)Species.Pinsir, (int)Species.Gyarados, (int)Species.Aerodactyl, (int)Species.Mewtwo, - (int)Species.Ampharos, (int)Species.Scizor, (int)Species.Heracross, (int)Species.Houndoom, (int)Species.Tyranitar, - (int)Species.Blaziken, (int)Species.Gardevoir, (int)Species.Mawile, (int)Species.Aggron, (int)Species.Medicham, - (int)Species.Manectric, (int)Species.Banette, (int)Species.Absol, (int)Species.Latias, (int)Species.Latios, - (int)Species.Garchomp, (int)Species.Lucario, (int)Species.Abomasnow, - - // AO - (int)Species.Beedrill, (int)Species.Pidgeot, (int)Species.Slowbro, (int)Species.Steelix, - (int)Species.Sceptile, (int)Species.Swampert, (int)Species.Sableye, (int)Species.Sharpedo, (int)Species.Camerupt, - (int)Species.Altaria, (int)Species.Glalie, (int)Species.Salamence, (int)Species.Metagross, (int)Species.Rayquaza, - (int)Species.Lopunny, (int)Species.Gallade, - (int)Species.Audino, (int)Species.Diancie, - }; - - public static readonly HashSet BattlePrimals = new() { 382, 383 }; // Kyogre and Groudon - public static readonly HashSet BattleFusions = new() { 646, 800, 898 }; // Kyurem, Necrozma, Calyrex - public static HashSet BattleExclusiveForms = new(BattleForms.Concat(BattleMegas.Concat(BattlePrimals).Concat(BattleFusions))); + int newlvl = (int)(level * factor); + return Math.Max(1, Math.Min(newlvl, 100)); } + + public static int[] GetRandomItemList(GameVersion game) + { + if (GameVersion.XY.Contains(game)) + return Items_HeldXY.Concat(Items_Ball).Where(i => i != 0).ToArray(); + + if (GameVersion.ORAS.Contains(game) || game == GameVersion.ORASDEMO) + return Items_HeldAO.Concat(Items_Ball).Where(i => i != 0).ToArray(); + + if (GameVersion.SM.Contains(game) || GameVersion.USUM.Contains(game)) + return HeldItemsBuy_SM.Select(i => (int)i).Concat(Items_Ball).Where(i => i != 0).ToArray(); + + if (GameVersion.GG.Contains(game)) + return HeldItems_GG.Select(i => (int)i).Where(i => i != 0).ToArray(); + + if (GameVersion.SWSH.Contains(game)) + return HeldItems_SWSH.Select(i => (int)i).Where(i => i != 0).ToArray(); + + return new int[1]; + } + + public static Dictionary GetMegaDictionary(GameVersion game) + { + if (GameVersion.XY.Contains(game)) + return MegaDictionaryXY; + if (GameVersion.GG.Contains(game)) + return MegaDictionaryGG; + return MegaDictionaryAO; + } + + private static readonly Dictionary MegaDictionaryXY = new() + { + {003, new[] {659}}, // Venusaur @ Venusaurite + {006, new[] {660, 678}}, // Charizard @ Charizardite X/Y + {009, new[] {661}}, // Blastoise @ Blastoisinite + {065, new[] {679}}, // Alakazam @ Alakazite + {094, new[] {656}}, // Gengar @ Gengarite + {115, new[] {675}}, // Kangaskhan @ Kangaskhanite + {127, new[] {671}}, // Pinsir @ Pinsirite + {130, new[] {676}}, // Gyarados @ Gyaradosite + {142, new[] {672}}, // Aerodactyl @ Aerodactylite + {150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y + {181, new[] {658}}, // Ampharos @ Ampharosite + {212, new[] {670}}, // Scizor @ Scizorite + {214, new[] {680}}, // Heracross @ Heracronite + {229, new[] {666}}, // Houndoom @ Houndoominite + {248, new[] {669}}, // Tyranitar @ Tyranitarite + {257, new[] {664}}, // Blaziken @ Blazikenite + {282, new[] {657}}, // Gardevoir @ Gardevoirite + {303, new[] {681}}, // Mawile @ Mawilite + {306, new[] {667}}, // Aggron @ Aggronite + {308, new[] {665}}, // Medicham @ Medichamite + {310, new[] {682}}, // Manectric @ Manectite + {354, new[] {668}}, // Banette @ Banettite + {359, new[] {677}}, // Absol @ Absolite + {380, new[] {684}}, // Latias @ Latiasite + {381, new[] {685}}, // Latios @ Latiosite + {445, new[] {683}}, // Garchomp @ Garchompite + {448, new[] {673}}, // Lucario @ Lucarionite + {460, new[] {674}}, // Abomasnow @ Abomasite + }; + + private static readonly Dictionary MegaDictionaryAO = new() + { + {003, new[] {659}}, // Venusaur @ Venusaurite + {006, new[] {660, 678}}, // Charizard @ Charizardite X/Y + {009, new[] {661}}, // Blastoise @ Blastoisinite + {065, new[] {679}}, // Alakazam @ Alakazite + {094, new[] {656}}, // Gengar @ Gengarite + {115, new[] {675}}, // Kangaskhan @ Kangaskhanite + {127, new[] {671}}, // Pinsir @ Pinsirite + {130, new[] {676}}, // Gyarados @ Gyaradosite + {142, new[] {672}}, // Aerodactyl @ Aerodactylite + {150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y + {181, new[] {658}}, // Ampharos @ Ampharosite + {212, new[] {670}}, // Scizor @ Scizorite + {214, new[] {680}}, // Heracross @ Heracronite + {229, new[] {666}}, // Houndoom @ Houndoominite + {248, new[] {669}}, // Tyranitar @ Tyranitarite + {257, new[] {664}}, // Blaziken @ Blazikenite + {282, new[] {657}}, // Gardevoir @ Gardevoirite + {303, new[] {681}}, // Mawile @ Mawilite + {306, new[] {667}}, // Aggron @ Aggronite + {308, new[] {665}}, // Medicham @ Medichamite + {310, new[] {682}}, // Manectric @ Manectite + {354, new[] {668}}, // Banette @ Banettite + {359, new[] {677}}, // Absol @ Absolite + {380, new[] {684}}, // Latias @ Latiasite + {381, new[] {685}}, // Latios @ Latiosite + {445, new[] {683}}, // Garchomp @ Garchompite + {448, new[] {673}}, // Lucario @ Lucarionite + {460, new[] {674}}, // Abomasnow @ Abomasite + + {015, new[] {770}}, // Beedrill @ Beedrillite + {018, new[] {762}}, // Pidgeot @ Pidgeotite + {080, new[] {760}}, // Slowbro @ Slowbronite + {208, new[] {761}}, // Steelix @ Steelixite + {254, new[] {753}}, // Sceptile @ Sceptilite + {260, new[] {752}}, // Swampert @ Swampertite + {302, new[] {754}}, // Sableye @ Sablenite + {319, new[] {759}}, // Sharpedo @ Sharpedonite + {323, new[] {767}}, // Camerupt @ Cameruptite + {334, new[] {755}}, // Altaria @ Altarianite + {362, new[] {763}}, // Glalie @ Glalitite + {373, new[] {769}}, // Salamence @ Salamencite + {376, new[] {758}}, // Metagross @ Metagrossite + // Rayquaza requires Dragon Ascent, no Held Item + {428, new[] {768}}, // Lopunny @ Lopunnite + {475, new[] {756}}, // Gallade @ Galladite + {531, new[] {757}}, // Audino @ Audinite + {719, new[] {764}}, // Diancie @ Diancite + }; + + private static readonly Dictionary MegaDictionaryGG = new() + { + {003, new[] {659}}, // Venusaur @ Venusaurite + {006, new[] {660, 678}}, // Charizard @ Charizardite X/Y + {009, new[] {661}}, // Blastoise @ Blastoisinite + {065, new[] {679}}, // Alakazam @ Alakazite + {094, new[] {656}}, // Gengar @ Gengarite + {115, new[] {675}}, // Kangaskhan @ Kangaskhanite + {127, new[] {671}}, // Pinsir @ Pinsirite + {130, new[] {676}}, // Gyarados @ Gyaradosite + {142, new[] {672}}, // Aerodactyl @ Aerodactylite + {150, new[] {662, 663}}, // Mewtwo @ Mewtwonite X/Y + + {015, new[] {770}}, // Beedrill @ Beedrillite + {018, new[] {762}}, // Pidgeot @ Pidgeotite + {080, new[] {760}}, // Slowbro @ Slowbronite + }; + + public static int[] GetBannedMoves(GameVersion infoGame, int moveCount) + { + if (!GameVersion.GG.Contains(infoGame)) + return Array.Empty(); + + return Enumerable.Range(0, moveCount).Except(AllowedMovesGG).ToArray(); + } + + public static int[] GetAllowedMoves(GameVersion infoGame, int moveCount) + { + if (GameVersion.GG.Contains(infoGame)) + return AllowedMovesGG; + + return Enumerable.Range(0, moveCount).ToArray(); + } + + public static readonly HashSet BattleForms = new() + { + (int)Species.Castform, + (int)Species.Cherrim, + (int)Species.Darmanitan, + (int)Species.Meloetta, + (int)Species.Aegislash, + (int)Species.Xerneas, + (int)Species.Wishiwashi, + (int)Species.Mimikyu, + (int)Species.Cramorant, + (int)Species.Eiscue, + (int)Species.Morpeko, + (int)Species.Zacian, + (int)Species.Zamazenta, + (int)Species.Eternatus, + }; + + public static readonly HashSet BattleMegas = new() + { + // XY + (int)Species.Venusaur, (int)Species.Charizard, (int)Species.Blastoise, (int)Species.Alakazam, (int)Species.Gengar, + (int)Species.Kangaskhan, (int)Species.Pinsir, (int)Species.Gyarados, (int)Species.Aerodactyl, (int)Species.Mewtwo, + (int)Species.Ampharos, (int)Species.Scizor, (int)Species.Heracross, (int)Species.Houndoom, (int)Species.Tyranitar, + (int)Species.Blaziken, (int)Species.Gardevoir, (int)Species.Mawile, (int)Species.Aggron, (int)Species.Medicham, + (int)Species.Manectric, (int)Species.Banette, (int)Species.Absol, (int)Species.Latias, (int)Species.Latios, + (int)Species.Garchomp, (int)Species.Lucario, (int)Species.Abomasnow, + + // AO + (int)Species.Beedrill, (int)Species.Pidgeot, (int)Species.Slowbro, (int)Species.Steelix, + (int)Species.Sceptile, (int)Species.Swampert, (int)Species.Sableye, (int)Species.Sharpedo, (int)Species.Camerupt, + (int)Species.Altaria, (int)Species.Glalie, (int)Species.Salamence, (int)Species.Metagross, (int)Species.Rayquaza, + (int)Species.Lopunny, (int)Species.Gallade, + (int)Species.Audino, (int)Species.Diancie, + }; + + public static readonly HashSet BattlePrimals = new() { 382, 383 }; // Kyogre and Groudon + public static readonly HashSet BattleFusions = new() { 646, 800, 898 }; // Kyurem, Necrozma, Calyrex + public static HashSet BattleExclusiveForms = new(BattleForms.Concat(BattleMegas.Concat(BattlePrimals).Concat(BattleFusions))); } diff --git a/pkNX.Structures/Legality/Species.cs b/pkNX.Structures/Legality/Species.cs index 6a8abe54..5e17acb5 100644 --- a/pkNX.Structures/Legality/Species.cs +++ b/pkNX.Structures/Legality/Species.cs @@ -1,158 +1,157 @@ -using System.Linq; +using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static partial class Legal { - public static partial class Legal + public static readonly int[] FinalEvolutions_1 = { - public static readonly int[] FinalEvolutions_1 = - { - 003, 006, 009, 012, 015, 018, 020, 022, 024, 026, 028, 031, 034, 036, 038, 040, 045, 047, 049, 051, 053, 055, 057, 059, 062, 065, 068, 071, 073, 076, 078, 080, 083, 085, 087, 089, 091, - 094, 097, 099, 101, 103, 105, 106, 107, 110, 115, 119, 121, 122, 124, 127, 128, 130, 131, 132, 134, 135, 136, 139, 141, 142, 143, 149, - }; + 003, 006, 009, 012, 015, 018, 020, 022, 024, 026, 028, 031, 034, 036, 038, 040, 045, 047, 049, 051, 053, 055, 057, 059, 062, 065, 068, 071, 073, 076, 078, 080, 083, 085, 087, 089, 091, + 094, 097, 099, 101, 103, 105, 106, 107, 110, 115, 119, 121, 122, 124, 127, 128, 130, 131, 132, 134, 135, 136, 139, 141, 142, 143, 149, + }; - public static readonly int[] FinalEvolutions_6 = FinalEvolutions_1.Concat(new[] - { - 154, 157, 160, 162, 164, 166, 168, 169, 171, 178, 181, 182, 184, 185, 186, 189, 192, 195, 196, 197, 199, 201, 202, 203, 205, 206, 208, 210, 211, 212, 213, 214, 217, 219, 222, 224, 225, - 226, 227, 229, 230, 232, 234, 235, 237, 241, 242, 248, 254, 257, 260, 262, 264, 267, 269, 272, 275, 277, 279, 282, 284, 286, 289, 291, 292, 295, 297, 301, 302, 303, 306, 308, 310, 311, - 312, 313, 314, 317, 319, 321, 323, 324, 326, 327, 330, 332, 334, 335, 336, 337, 338, 340, 342, 344, 346, 348, 350, 351, 352, 354, 357, 358, 359, 362, 365, 367, 368, 369, 370, 373, 376, - 389, 392, 395, 398, 400, 402, 405, 407, 409, 411, 413, 414, 416, 417, 419, 421, 423, 424, 426, 428, 429, 430, 432, 435, 437, 441, 442, 445, 448, 450, 452, 454, 455, 457, 460, 461, 462, - 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 497, 500, 503, 505, 508, 510, 512, 514, 516, 518, 521, 523, 526, 528, 530, 531, 534, 537, 538, 539, - 542, 545, 547, 549, 550, 553, 555, 556, 558, 560, 561, 563, 565, 567, 569, 571, 573, 576, 579, 581, 584, 586, 587, 589, 591, 593, 594, 596, 598, 601, 604, 606, 609, 612, 614, 615, 617, - 618, 620, 621, 623, 625, 626, 628, 630, 631, 632, 635, 637, 652, 655, 658, 660, 663, 666, 668, 671, 673, 675, 676, 678, 681, 683, 685, 687, 689, 691, 693, 695, 697, 699, 700, 701, 702, - 703, 706, 707, 709, 711, 713, 715, - }).ToArray(); + public static readonly int[] FinalEvolutions_6 = FinalEvolutions_1.Concat(new[] + { + 154, 157, 160, 162, 164, 166, 168, 169, 171, 178, 181, 182, 184, 185, 186, 189, 192, 195, 196, 197, 199, 201, 202, 203, 205, 206, 208, 210, 211, 212, 213, 214, 217, 219, 222, 224, 225, + 226, 227, 229, 230, 232, 234, 235, 237, 241, 242, 248, 254, 257, 260, 262, 264, 267, 269, 272, 275, 277, 279, 282, 284, 286, 289, 291, 292, 295, 297, 301, 302, 303, 306, 308, 310, 311, + 312, 313, 314, 317, 319, 321, 323, 324, 326, 327, 330, 332, 334, 335, 336, 337, 338, 340, 342, 344, 346, 348, 350, 351, 352, 354, 357, 358, 359, 362, 365, 367, 368, 369, 370, 373, 376, + 389, 392, 395, 398, 400, 402, 405, 407, 409, 411, 413, 414, 416, 417, 419, 421, 423, 424, 426, 428, 429, 430, 432, 435, 437, 441, 442, 445, 448, 450, 452, 454, 455, 457, 460, 461, 462, + 463, 464, 465, 466, 467, 468, 469, 470, 471, 472, 473, 474, 475, 476, 477, 478, 479, 497, 500, 503, 505, 508, 510, 512, 514, 516, 518, 521, 523, 526, 528, 530, 531, 534, 537, 538, 539, + 542, 545, 547, 549, 550, 553, 555, 556, 558, 560, 561, 563, 565, 567, 569, 571, 573, 576, 579, 581, 584, 586, 587, 589, 591, 593, 594, 596, 598, 601, 604, 606, 609, 612, 614, 615, 617, + 618, 620, 621, 623, 625, 626, 628, 630, 631, 632, 635, 637, 652, 655, 658, 660, 663, 666, 668, 671, 673, 675, 676, 678, 681, 683, 685, 687, 689, 691, 693, 695, 697, 699, 700, 701, 702, + 703, 706, 707, 709, 711, 713, 715, + }).ToArray(); - public static readonly int[] FinalEvolutions_7 = FinalEvolutions_6.Concat(new[] - { - 724, 727, 730, 733, 735, 738, 740, 741, 743, 745, 746, 748, 750, 752, 754, 756, 758, 760, 763, 764, 765, 766, 768, 770, 771, 774, 775, 776, 777, 779, 780, 781, 784, - }).ToArray(); + public static readonly int[] FinalEvolutions_7 = FinalEvolutions_6.Concat(new[] + { + 724, 727, 730, 733, 735, 738, 740, 741, 743, 745, 746, 748, 750, 752, 754, 756, 758, 760, 763, 764, 765, 766, 768, 770, 771, 774, 775, 776, 777, 779, 780, 781, 784, + }).ToArray(); - public static readonly int[] FinalEvolutions_8 = FinalEvolutions_7.Concat(new[] - { - 812, 815, 818, 820, 823, 826, 828, 830, 832, 834, 836, 839, 841, 842, 844, 845, 847, 849, 851, 853, 855, 858, 861, 862, 863, 864, 865, 866, 867, 869, 870, 871, 873, 874, 875, 876, 877, - 879, 880, 881, 882, 883, 884, 887, - }).ToArray(); + public static readonly int[] FinalEvolutions_8 = FinalEvolutions_7.Concat(new[] + { + 812, 815, 818, 820, 823, 826, 828, 830, 832, 834, 836, 839, 841, 842, 844, 845, 847, 849, 851, 853, 855, 858, 861, 862, 863, 864, 865, 866, 867, 869, 870, 871, 873, 874, 875, 876, 877, + 879, 880, 881, 882, 883, 884, 887, + }).ToArray(); - public static readonly int[] Legendary_1 = - { - #region Legendary - 144, // Articuno - 145, // Zapdos - 146, // Moltres - 150, // Mewtwo - #endregion - }; + public static readonly int[] Legendary_1 = + { + #region Legendary + 144, // Articuno + 145, // Zapdos + 146, // Moltres + 150, // Mewtwo + #endregion + }; - public static readonly int[] Legendary_6 = Legendary_1.Concat(new[] - { - #region Legendary - 243, // Raikou - 244, // Entei - 245, // Suicune - 249, // Lugia - 250, // Ho-Oh - 377, // Regirock - 378, // Regice - 379, // Registeel - 380, // Latias - 381, // Latios - 382, // Kyogre - 383, // Groudon - 384, // Rayquaza - 480, // Uxie - 481, // Mesprit - 482, // Azelf - 483, // Dialga - 484, // Palkia - 485, // Heatran - 486, // Regigigas - 487, // Giratina - 488, // Cresselia - 638, // Cobalion - 639, // Terrakion - 640, // Virizion - 641, // Tornadus - 642, // Thundurus - 643, // Reshiram - 644, // Zekrom - 645, // Landorus - 646, // Kyurem - 716, // Xerneas - 717, // Yveltal - 718, // Zygarde - #endregion - }).ToArray(); + public static readonly int[] Legendary_6 = Legendary_1.Concat(new[] + { + #region Legendary + 243, // Raikou + 244, // Entei + 245, // Suicune + 249, // Lugia + 250, // Ho-Oh + 377, // Regirock + 378, // Regice + 379, // Registeel + 380, // Latias + 381, // Latios + 382, // Kyogre + 383, // Groudon + 384, // Rayquaza + 480, // Uxie + 481, // Mesprit + 482, // Azelf + 483, // Dialga + 484, // Palkia + 485, // Heatran + 486, // Regigigas + 487, // Giratina + 488, // Cresselia + 638, // Cobalion + 639, // Terrakion + 640, // Virizion + 641, // Tornadus + 642, // Thundurus + 643, // Reshiram + 644, // Zekrom + 645, // Landorus + 646, // Kyurem + 716, // Xerneas + 717, // Yveltal + 718, // Zygarde + #endregion + }).ToArray(); - public static readonly int[] Legendary_SM = Legendary_6.Concat(new[] - { - #region Legendary - 773, // Silvally - 785, // Tapu Koko - 786, // Tapu Lele - 787, // Tapu Bulu - 788, // Tapu Fini - 791, // Solgaleo - 792, // Lunala - 793, // Nihilego - 794, // Buzzwole - 795, // Pheromosa - 796, // Xurkitree - 797, // Celesteela - 798, // Kartana - 799, // Guzzlord - 800, // Necrozma - #endregion - }).ToArray(); + public static readonly int[] Legendary_SM = Legendary_6.Concat(new[] + { + #region Legendary + 773, // Silvally + 785, // Tapu Koko + 786, // Tapu Lele + 787, // Tapu Bulu + 788, // Tapu Fini + 791, // Solgaleo + 792, // Lunala + 793, // Nihilego + 794, // Buzzwole + 795, // Pheromosa + 796, // Xurkitree + 797, // Celesteela + 798, // Kartana + 799, // Guzzlord + 800, // Necrozma + #endregion + }).ToArray(); - public static readonly int[] Legendary_USUM = Legendary_SM.Concat(new[] { 804, 805, 806 }).ToArray(); // Poipole, Blacephalon, Stakataka + public static readonly int[] Legendary_USUM = Legendary_SM.Concat(new[] { 804, 805, 806 }).ToArray(); // Poipole, Blacephalon, Stakataka - public static readonly int[] Legendary_8 = Legendary_USUM.Concat(new[] - { - #region Legendary - 888, // Zacian - 889, // Zamazenta - 890, // Eternatus - 891, // Kubfu - 892, // Urshifu - 894, // Regieleki - 895, // Regidrago - 896, // Glastrier - 897, // Spectrier - 898, // Calyrex - #endregion - }).ToArray(); + public static readonly int[] Legendary_8 = Legendary_USUM.Concat(new[] + { + #region Legendary + 888, // Zacian + 889, // Zamazenta + 890, // Eternatus + 891, // Kubfu + 892, // Urshifu + 894, // Regieleki + 895, // Regidrago + 896, // Glastrier + 897, // Spectrier + 898, // Calyrex + #endregion + }).ToArray(); - public static readonly int[] Legendary_8a = Legendary_8.Concat(new[] { 905 }).ToArray(); + public static readonly int[] Legendary_8a = Legendary_8.Concat(new[] { 905 }).ToArray(); - public static readonly int[] Mythical_1 = { 151 }; // Mew + public static readonly int[] Mythical_1 = { 151 }; // Mew - public static readonly int[] Mythical_6 = Mythical_1.Concat(new[] - { - #region Mythical - 251, // Celebi - 385, // Jirachi - 386, // Deoxys - 489, // Phione - 490, // Manaphy - 491, // Darkrai - 492, // Shaymin - 493, // Arceus - 494, // Victini - 647, // Keldeo - 648, // Meloetta - 649, // Genesect - 719, // Diancie - 720, // Hoopa - 721, // Volcanion - #endregion - }).ToArray(); + public static readonly int[] Mythical_6 = Mythical_1.Concat(new[] + { + #region Mythical + 251, // Celebi + 385, // Jirachi + 386, // Deoxys + 489, // Phione + 490, // Manaphy + 491, // Darkrai + 492, // Shaymin + 493, // Arceus + 494, // Victini + 647, // Keldeo + 648, // Meloetta + 649, // Genesect + 719, // Diancie + 720, // Hoopa + 721, // Volcanion + #endregion + }).ToArray(); - public static readonly int[] Mythical_SM = Mythical_6.Concat(new[] { 801, 802 }).ToArray(); // Magearna, Marshadow + public static readonly int[] Mythical_SM = Mythical_6.Concat(new[] { 801, 802 }).ToArray(); // Magearna, Marshadow - public static readonly int[] Mythical_USUM = Mythical_SM.Concat(new[] { 807 }).ToArray(); // Zeraora + public static readonly int[] Mythical_USUM = Mythical_SM.Concat(new[] { 807 }).ToArray(); // Zeraora - public static readonly int[] Mythical_GG = Mythical_1.Concat(new[] { 809 }).ToArray(); // Melmetal + public static readonly int[] Mythical_GG = Mythical_1.Concat(new[] { 809 }).ToArray(); // Melmetal - public static readonly int[] Mythical_8 = Mythical_USUM.Concat(new[] { 809, 893 }).ToArray(); // Melmetal, Zarude - } + public static readonly int[] Mythical_8 = Mythical_USUM.Concat(new[] { 809, 893 }).ToArray(); // Melmetal, Zarude } diff --git a/pkNX.Structures/Legality/Tables/FormChangeUtil.cs b/pkNX.Structures/Legality/Tables/FormChangeUtil.cs index c8ebfb64..21a9ff75 100644 --- a/pkNX.Structures/Legality/Tables/FormChangeUtil.cs +++ b/pkNX.Structures/Legality/Tables/FormChangeUtil.cs @@ -25,7 +25,7 @@ public enum LearnOption } /// -/// Logic for checking if an entity can freely change . +/// Logic for checking if an entity can freely change form. /// public static class FormChangeUtil { diff --git a/pkNX.Structures/Legality/Tables/FormInfo.cs b/pkNX.Structures/Legality/Tables/FormInfo.cs index de9f693d..d71088f8 100644 --- a/pkNX.Structures/Legality/Tables/FormInfo.cs +++ b/pkNX.Structures/Legality/Tables/FormInfo.cs @@ -152,7 +152,7 @@ private static byte GetOutOfBattleFormCount_Impl(ushort species) (int)Keldeo => 2, // Ordinary Form, Resolute Form (int)Meloetta => 2, // Aria Form, Pirouette Form (int)Genesect => 5, // Normal, Electric, Fire, Ice, Water - (int)Flabb => 5, // Red Flower, Yellow Flower, Orange Flower, Blue Flower, White Flower + (int)Flabébé => 5, // Red Flower, Yellow Flower, Orange Flower, Blue Flower, White Flower (int)Floette => 6, // Red Flower, Yellow Flower, Orange Flower, Blue Flower, White Flower (int)Florges => 5, // Red Flower, Yellow Flower, Orange Flower, Blue Flower, White Flower @@ -409,7 +409,7 @@ public static bool IsLordForm(ushort species, byte form, int generation) private const int Vivillon3DSMaxWildFormID = 17; // 0-17 valid form indexes /// - /// Checks if the exists for the without having an associated index. + /// Checks if the exists for the without having an associated personal info index. /// /// Entity species /// Entity form @@ -427,12 +427,12 @@ public static bool IsLordForm(ushort species, byte form, int generation) }; /// - /// Checks if the data should have a drop-down selection visible for the value. + /// Checks if the entity data should have a drop-down selection visible for the form value. /// /// Game specific personal info /// ID - /// ID - /// True if has forms that can be provided by , otherwise false for none. + /// Form Index + /// True if has forms that can be provided by form list fetch, otherwise false for none. public static bool HasFormSelection(IPersonalInfo pi, ushort species, int format) { if (format <= 3 && species != (int)Unown) diff --git a/pkNX.Structures/Legality/Tables/Tables6.cs b/pkNX.Structures/Legality/Tables/Tables6.cs index 87a3d144..542afd3e 100644 --- a/pkNX.Structures/Legality/Tables/Tables6.cs +++ b/pkNX.Structures/Legality/Tables/Tables6.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace pkNX.Structures; @@ -552,4 +552,4 @@ public static partial class Legal 590, // Relic Crown 715, // Fairy Gem }); -} \ No newline at end of file +} diff --git a/pkNX.Structures/Legality/Tables/Tables7b.cs b/pkNX.Structures/Legality/Tables/Tables7b.cs index 1f726575..76b47ed9 100644 --- a/pkNX.Structures/Legality/Tables/Tables7b.cs +++ b/pkNX.Structures/Legality/Tables/Tables7b.cs @@ -275,4 +275,4 @@ public static partial class Legal }; #endregion -} \ No newline at end of file +} diff --git a/pkNX.Structures/Legality/Tables/Tables8.cs b/pkNX.Structures/Legality/Tables/Tables8.cs index 78eeee23..32a72608 100644 --- a/pkNX.Structures/Legality/Tables/Tables8.cs +++ b/pkNX.Structures/Legality/Tables/Tables8.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; using static pkNX.Structures.Species; @@ -734,4 +733,4 @@ public static partial class Legal 500, // Park Ball }); #endregion -} \ No newline at end of file +} diff --git a/pkNX.Structures/Legality/Trainers.cs b/pkNX.Structures/Legality/Trainers.cs index c6dda0da..60f0afeb 100644 --- a/pkNX.Structures/Legality/Trainers.cs +++ b/pkNX.Structures/Legality/Trainers.cs @@ -1,706 +1,705 @@ -using System.Linq; +using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static partial class Legal { - public static partial class Legal + public static readonly ushort[] Mega_XY = { - public static readonly ushort[] Mega_XY = - { - 003, 006, 009, 065, 080, 115, 127, 130, 142, 150, - 181, 212, 214, 229, 248, - 257, 282, 303, 306, 308, 310, 354, 359, 380, 381, - 445, 448, 460 - }; + 003, 006, 009, 065, 080, 115, 127, 130, 142, 150, + 181, 212, 214, 229, 248, + 257, 282, 303, 306, 308, 310, 354, 359, 380, 381, + 445, 448, 460 + }; - public static readonly ushort[] Mega_ORAS = Mega_XY.Concat(new ushort[] - { - 015, 018, 094, - 208, - 254, 260, 302, 319, 323, 334, 362, 373, 376, 384, - 428, 475, - 531, - 719 - }).ToArray(); + public static readonly ushort[] Mega_ORAS = Mega_XY.Concat(new ushort[] + { + 015, 018, 094, + 208, + 254, 260, 302, 319, 323, 334, 362, 373, 376, 384, + 428, 475, + 531, + 719 + }).ToArray(); - public static readonly int[] SpecialClasses_XY = - { - #region Classes - 000, // Pokémon Trainer - 001, // Pokémon Trainer - 004, // Leader - 018, // Team Flare - 019, // Team Flare - 020, // Team Flare - 021, // Team Flare - 022, // Team Flare - 035, // Elite Four - 036, // Elite Four - 037, // Elite Four - 038, // Elite Four - 039, // Leader - 040, // Leader - 041, // Leader - 042, // Leader - 043, // Leader - 044, // Leader - 045, // Leader - 053, // Champion - 055, // Pokémon Trainer - 056, // Pokémon Trainer - 057, // Pokémon Trainer - 064, // Battle Chatelaine - 065, // Battle Chatelaine - 066, // Battle Chatelaine - 067, // Battle Chatelaine - 081, // Team Flare - 102, // Pokémon Trainer - 103, // Pokémon Trainer - 104, // Pokémon Trainer - 105, // Pokémon Professor - 139, // Marchioness - 140, // Marquis - 141, // Marchioness - 142, // Marquis - 143, // Marquis - 144, // Marchioness - 145, // Marchioness - 146, // Marquis - 151, // Grand Duchess - 160, // Pokémon Trainer - 161, // Pokémon Trainer - 170, // Pokémon Trainer - 171, // Pokémon Trainer - 172, // Pokémon Trainer - 173, // Team Flare - 174, // Team Flare - 175, // Team Flare Boss - 176, // Successor - 177, // Leader - #endregion - }; + public static readonly int[] SpecialClasses_XY = + { + #region Classes + 000, // Pokémon Trainer + 001, // Pokémon Trainer + 004, // Leader + 018, // Team Flare + 019, // Team Flare + 020, // Team Flare + 021, // Team Flare + 022, // Team Flare + 035, // Elite Four + 036, // Elite Four + 037, // Elite Four + 038, // Elite Four + 039, // Leader + 040, // Leader + 041, // Leader + 042, // Leader + 043, // Leader + 044, // Leader + 045, // Leader + 053, // Champion + 055, // Pokémon Trainer + 056, // Pokémon Trainer + 057, // Pokémon Trainer + 064, // Battle Chatelaine + 065, // Battle Chatelaine + 066, // Battle Chatelaine + 067, // Battle Chatelaine + 081, // Team Flare + 102, // Pokémon Trainer + 103, // Pokémon Trainer + 104, // Pokémon Trainer + 105, // Pokémon Professor + 139, // Marchioness + 140, // Marquis + 141, // Marchioness + 142, // Marquis + 143, // Marquis + 144, // Marchioness + 145, // Marchioness + 146, // Marquis + 151, // Grand Duchess + 160, // Pokémon Trainer + 161, // Pokémon Trainer + 170, // Pokémon Trainer + 171, // Pokémon Trainer + 172, // Pokémon Trainer + 173, // Team Flare + 174, // Team Flare + 175, // Team Flare Boss + 176, // Successor + 177, // Leader + #endregion + }; - public static readonly int[] SpecialClasses_ORAS = - { - #region Classes - 064, // Battle Chatelaine - 065, // Battle Chatelaine - 066, // Battle Chatelaine - 067, // Battle Chatelaine - 127, // Pokémon Trainer - 128, // Pokémon Trainer - 174, // Aqua Leader - 175, // Aqua Admin - 178, // Magma Leader - 180, // Magma Admin - 182, // Magma Admin - 186, // Aqua Admin - 187, // Magma Admin - 192, // Pokémon Trainer - 194, // Elite Four - 195, // Elite Four - 196, // Elite Four - 197, // Elite Four - 198, // Champion - 200, // Leader - 201, // Leader - 202, // Leader - 203, // Leader - 204, // Leader - 205, // Leader - 206, // Leaders - 207, // Leader - 219, // Pokémon Trainer - 221, // Lorekeeper - 232, // Pokémon Trainer - 233, // Pokémon Trainer - 234, // Pokémon Trainer - 236, // Secret Base Expert - 267, // Pokémon Trainer - 268, // Sootopolitan - 270, // Pokémon Trainer - 271, // Pokémon Trainer - 272, // Pokémon Trainer - 273, // Elite Four - 274, // Elite Four - 275, // Elite Four - 276, // Elite Four - 277, // Champion - 278, // Pokémon Trainer - 279, // Pokémon Trainer - #endregion - }; + public static readonly int[] SpecialClasses_ORAS = + { + #region Classes + 064, // Battle Chatelaine + 065, // Battle Chatelaine + 066, // Battle Chatelaine + 067, // Battle Chatelaine + 127, // Pokémon Trainer + 128, // Pokémon Trainer + 174, // Aqua Leader + 175, // Aqua Admin + 178, // Magma Leader + 180, // Magma Admin + 182, // Magma Admin + 186, // Aqua Admin + 187, // Magma Admin + 192, // Pokémon Trainer + 194, // Elite Four + 195, // Elite Four + 196, // Elite Four + 197, // Elite Four + 198, // Champion + 200, // Leader + 201, // Leader + 202, // Leader + 203, // Leader + 204, // Leader + 205, // Leader + 206, // Leaders + 207, // Leader + 219, // Pokémon Trainer + 221, // Lorekeeper + 232, // Pokémon Trainer + 233, // Pokémon Trainer + 234, // Pokémon Trainer + 236, // Secret Base Expert + 267, // Pokémon Trainer + 268, // Sootopolitan + 270, // Pokémon Trainer + 271, // Pokémon Trainer + 272, // Pokémon Trainer + 273, // Elite Four + 274, // Elite Four + 275, // Elite Four + 276, // Elite Four + 277, // Champion + 278, // Pokémon Trainer + 279, // Pokémon Trainer + #endregion + }; - public static readonly int[] SpecialClasses_SM = - { - #region Classes - 000, // Pokémon Trainer - 001, // Pokémon Trainer - 030, // Pokémon Trainer - 031, // Island Kahuna - 038, // Captain - 040, // Pokémon Trainer - 041, // Pokémon Trainer - 043, // Captain - 044, // Captain - 045, // Captain - 046, // Captain - 047, // Captain - 048, // Captain - 049, // Island Kahuna - 050, // Island Kahuna - 051, // Island Kahuna - 071, // Aether President - 072, // Aether Branch Chief - 076, // Team Skull Boss - 077, // Pokémon Trainer - 078, // Team Skull Admin - 079, // Pokémon Trainer - 080, // Elite Four - 081, // Pokémon Trainer - 082, // Aether President - 083, // Pokémon Trainer - 084, // Pokémon Trainer - 085, // Pokémon Trainer - 086, // Pokémon Trainer - 087, // Pokémon Trainer - 088, // Pokémon Trainer - 089, // Pokémon Trainer - 090, // Pokémon Trainer - 091, // Pokémon Trainer - 092, // Pro Wrestler - 093, // Pokémon Trainer - 097, // Pokémon Trainer - 098, // Pokémon Trainer - 099, // Pokémon Trainer - 100, // Pokémon Trainer - 101, // Pokémon Trainer - 102, // Pokémon Trainer - 103, // Pokémon Trainer - 104, // Pokémon Trainer - 105, // Pokémon Trainer - 106, // Pokémon Trainer - 107, // Elite Four - 108, // Pokémon Trainer - 109, // Elite Four - 110, // Elite Four - 111, // Pokémon Professor - 128, // Pokémon Trainer - 139, // GAME FREAK - 140, // Pokémon Trainer - 141, // Island Kahuna - 142, // Captain - 143, // Pokémon Trainer - 150, // Pokémon Trainer - 153, // Captain - 154, // Pokémon Professor - 164, // Island Kahuna - 166, // Pokémon Trainer - 167, // Pokémon Trainer - 168, // Pokémon Trainer - 169, // Pokémon Trainer - 170, // Pokémon Trainer - 171, // Pokémon Trainer - 165, // Pokémon Professor - 183, // Battle Legend - 184, // Battle Legend - 185, // Aether Foundation - #endregion - }; + public static readonly int[] SpecialClasses_SM = + { + #region Classes + 000, // Pokémon Trainer + 001, // Pokémon Trainer + 030, // Pokémon Trainer + 031, // Island Kahuna + 038, // Captain + 040, // Pokémon Trainer + 041, // Pokémon Trainer + 043, // Captain + 044, // Captain + 045, // Captain + 046, // Captain + 047, // Captain + 048, // Captain + 049, // Island Kahuna + 050, // Island Kahuna + 051, // Island Kahuna + 071, // Aether President + 072, // Aether Branch Chief + 076, // Team Skull Boss + 077, // Pokémon Trainer + 078, // Team Skull Admin + 079, // Pokémon Trainer + 080, // Elite Four + 081, // Pokémon Trainer + 082, // Aether President + 083, // Pokémon Trainer + 084, // Pokémon Trainer + 085, // Pokémon Trainer + 086, // Pokémon Trainer + 087, // Pokémon Trainer + 088, // Pokémon Trainer + 089, // Pokémon Trainer + 090, // Pokémon Trainer + 091, // Pokémon Trainer + 092, // Pro Wrestler + 093, // Pokémon Trainer + 097, // Pokémon Trainer + 098, // Pokémon Trainer + 099, // Pokémon Trainer + 100, // Pokémon Trainer + 101, // Pokémon Trainer + 102, // Pokémon Trainer + 103, // Pokémon Trainer + 104, // Pokémon Trainer + 105, // Pokémon Trainer + 106, // Pokémon Trainer + 107, // Elite Four + 108, // Pokémon Trainer + 109, // Elite Four + 110, // Elite Four + 111, // Pokémon Professor + 128, // Pokémon Trainer + 139, // GAME FREAK + 140, // Pokémon Trainer + 141, // Island Kahuna + 142, // Captain + 143, // Pokémon Trainer + 150, // Pokémon Trainer + 153, // Captain + 154, // Pokémon Professor + 164, // Island Kahuna + 166, // Pokémon Trainer + 167, // Pokémon Trainer + 168, // Pokémon Trainer + 169, // Pokémon Trainer + 170, // Pokémon Trainer + 171, // Pokémon Trainer + 165, // Pokémon Professor + 183, // Battle Legend + 184, // Battle Legend + 185, // Aether Foundation + #endregion + }; - public static readonly int[] SpecialClasses_USUM = - { - #region Classes - 000, // Pokémon Trainer - 001, // Pokémon Trainer - 030, // Pokémon Trainer - 031, // Island Kahuna - 038, // Captain - 040, // Pokémon Trainer - 041, // Pokémon Trainer - 043, // Captain - 044, // Captain - 045, // Captain - 046, // Captain - 047, // Captain - 048, // Captain - 049, // Island Kahuna - 050, // Island Kahuna - 051, // Island Kahuna - 071, // Aether President - 072, // Aether Branch Chief - 076, // Team Skull Boss - 077, // Pokémon Trainer - 078, // Team Skull Admin - 079, // Pokémon Trainer - 080, // Elite Four - 081, // Pokémon Trainer - 082, // Aether President - 083, // Pokémon Trainer - 084, // Pokémon Trainer - 085, // Pokémon Trainer - 086, // Pokémon Trainer - 087, // Pokémon Trainer - 088, // Pokémon Trainer - 089, // Pokémon Trainer - 090, // Pokémon Trainer - 091, // Pokémon Trainer - 092, // Pro Wrestler - 093, // Pokémon Trainer - 097, // Pokémon Trainer - 098, // Pokémon Trainer - 099, // Pokémon Trainer - 100, // Pokémon Trainer - 101, // Pokémon Trainer - 102, // Pokémon Trainer - 103, // Pokémon Trainer - 104, // Pokémon Trainer - 105, // Pokémon Trainer - 106, // Pokémon Trainer - 107, // Elite Four - 108, // Pokémon Trainer - 109, // Elite Four - 110, // Elite Four - 111, // Pokémon Professor - 128, // Pokémon Trainer - 139, // GAME FREAK - 140, // Pokémon Trainer - 141, // Island Kahuna - 142, // Captain - 143, // Pokémon Trainer - 150, // Pokémon Trainer - 153, // Captain - 154, // Pokémon Professor - 164, // Island Kahuna - 166, // Pokémon Trainer - 167, // Pokémon Trainer - 168, // Pokémon Trainer - 169, // Pokémon Trainer - 170, // Pokémon Trainer - 171, // Pokémon Trainer - 165, // Pokémon Professor - 183, // Battle Legend - 184, // Battle Legend - 185, // Aether Foundation - 186, // Pokémon Trainer - 187, // Pokémon Trainer - 188, // Pokémon Trainer - 189, // Pokémon Trainer - 190, // Pokémon Trainer - 191, // Elite Four - 192, // Ultra Recon Squad - 193, // Ultra Recon Squad - 194, // Pokémon Trainer - 198, // Team Aqua - 199, // Team Galactic - 200, // Team Magma - 201, // Team Plasma - 202, // Team Flare - 205, // GAME FREAK - 206, // Team Rainbow Rocket - 207, // Pokémon Trainer - 219, // Pokémon Trainer - 220, // Aether President - 221, // Pokémon Trainer - 222, // Pokémon Trainer - #endregion - }; + public static readonly int[] SpecialClasses_USUM = + { + #region Classes + 000, // Pokémon Trainer + 001, // Pokémon Trainer + 030, // Pokémon Trainer + 031, // Island Kahuna + 038, // Captain + 040, // Pokémon Trainer + 041, // Pokémon Trainer + 043, // Captain + 044, // Captain + 045, // Captain + 046, // Captain + 047, // Captain + 048, // Captain + 049, // Island Kahuna + 050, // Island Kahuna + 051, // Island Kahuna + 071, // Aether President + 072, // Aether Branch Chief + 076, // Team Skull Boss + 077, // Pokémon Trainer + 078, // Team Skull Admin + 079, // Pokémon Trainer + 080, // Elite Four + 081, // Pokémon Trainer + 082, // Aether President + 083, // Pokémon Trainer + 084, // Pokémon Trainer + 085, // Pokémon Trainer + 086, // Pokémon Trainer + 087, // Pokémon Trainer + 088, // Pokémon Trainer + 089, // Pokémon Trainer + 090, // Pokémon Trainer + 091, // Pokémon Trainer + 092, // Pro Wrestler + 093, // Pokémon Trainer + 097, // Pokémon Trainer + 098, // Pokémon Trainer + 099, // Pokémon Trainer + 100, // Pokémon Trainer + 101, // Pokémon Trainer + 102, // Pokémon Trainer + 103, // Pokémon Trainer + 104, // Pokémon Trainer + 105, // Pokémon Trainer + 106, // Pokémon Trainer + 107, // Elite Four + 108, // Pokémon Trainer + 109, // Elite Four + 110, // Elite Four + 111, // Pokémon Professor + 128, // Pokémon Trainer + 139, // GAME FREAK + 140, // Pokémon Trainer + 141, // Island Kahuna + 142, // Captain + 143, // Pokémon Trainer + 150, // Pokémon Trainer + 153, // Captain + 154, // Pokémon Professor + 164, // Island Kahuna + 166, // Pokémon Trainer + 167, // Pokémon Trainer + 168, // Pokémon Trainer + 169, // Pokémon Trainer + 170, // Pokémon Trainer + 171, // Pokémon Trainer + 165, // Pokémon Professor + 183, // Battle Legend + 184, // Battle Legend + 185, // Aether Foundation + 186, // Pokémon Trainer + 187, // Pokémon Trainer + 188, // Pokémon Trainer + 189, // Pokémon Trainer + 190, // Pokémon Trainer + 191, // Elite Four + 192, // Ultra Recon Squad + 193, // Ultra Recon Squad + 194, // Pokémon Trainer + 198, // Team Aqua + 199, // Team Galactic + 200, // Team Magma + 201, // Team Plasma + 202, // Team Flare + 205, // GAME FREAK + 206, // Team Rainbow Rocket + 207, // Pokémon Trainer + 219, // Pokémon Trainer + 220, // Aether President + 221, // Pokémon Trainer + 222, // Pokémon Trainer + #endregion + }; - public static readonly int[] SpecialClasses_GG = - { - #region Classes - 000, // Pokémon Trainer [Trace, Standard] - 001, // Gym Leader [Brock] - 002, // Gym Leader [Misty] - 003, // Gym Leader [Lt. Surge] - 004, // Gym Leader [Erika] - 005, // Gym Leader [Sabrina] - 006, // Gym Leader [Koga] - 007, // Gym Leader [Blaine] - 008, // Pokémon Trainer [Red] - 009, // Pokémon Trainer [Blue] - 010, // Pokémon Trainer [Green] - 011, // Pokémon Trainer [Mina] - 012, // Team Rocket Boss [Giovanni] - 013, // Team Rocket Admin [Archer] - 014, // Team Rocket [Jessie] - 017, // Elite Four [Lorelei] - 018, // Elite Four [Bruno] - 019, // Elite Four [Agatha] - 020, // Elite Four [Lance] - 027, // Team Rocket [James] - 028, // Gym Leader [Giovanni] - 057, // Gym Leader [Blue] - 058, // Pokémon Trainer [Archer] - 061, // Champion [Trace] - 383, // Pokémon Trainer [Trace, Champion Title Defense] - #endregion - }; + public static readonly int[] SpecialClasses_GG = + { + #region Classes + 000, // Pokémon Trainer [Trace, Standard] + 001, // Gym Leader [Brock] + 002, // Gym Leader [Misty] + 003, // Gym Leader [Lt. Surge] + 004, // Gym Leader [Erika] + 005, // Gym Leader [Sabrina] + 006, // Gym Leader [Koga] + 007, // Gym Leader [Blaine] + 008, // Pokémon Trainer [Red] + 009, // Pokémon Trainer [Blue] + 010, // Pokémon Trainer [Green] + 011, // Pokémon Trainer [Mina] + 012, // Team Rocket Boss [Giovanni] + 013, // Team Rocket Admin [Archer] + 014, // Team Rocket [Jessie] + 017, // Elite Four [Lorelei] + 018, // Elite Four [Bruno] + 019, // Elite Four [Agatha] + 020, // Elite Four [Lance] + 027, // Team Rocket [James] + 028, // Gym Leader [Giovanni] + 057, // Gym Leader [Blue] + 058, // Pokémon Trainer [Archer] + 061, // Champion [Trace] + 383, // Pokémon Trainer [Trace, Champion Title Defense] + #endregion + }; - // - // Unused Trainer Classes in Let's Go, Pikachu! and Let's Go, Eevee!. - // Assigning these Trainer Classes to a Trainer crashes the game. - // A majority of these are Master Trainer related, and only used for multiplayer. They are not to be assigned to NPCs. - // - public static readonly int[] BlacklistedClasses_GG = Enumerable.Range(072, 311).Concat(new[] - { - #region CrashClasses - 032, // Pokémon Trainer - 033, // Pokémon Trainer - #endregion - }).ToArray(); + // + // Unused Trainer Classes in Let's Go, Pikachu! and Let's Go, Eevee!. + // Assigning these Trainer Classes to a Trainer crashes the game. + // A majority of these are Master Trainer related, and only used for multiplayer. They are not to be assigned to NPCs. + // + public static readonly int[] BlacklistedClasses_GG = Enumerable.Range(072, 311).Concat(new[] + { + #region CrashClasses + 032, // Pokémon Trainer + 033, // Pokémon Trainer + #endregion + }).ToArray(); - public static readonly int[] SpecialClasses_SWSH = - { - #region Classes - 004, // Champion [Leon] - 005, // Pokémon Trainer [Leon, Battle Tower] - 006, // Pokémon Trainer [Leon, Champion Cup Rematches] - 007, // Pokémon Trainer [Hop] - 008, // Pokémon Trainer [Hop, Gym Outfit] - 011, // Pokémon Trainer [Bede] - 012, // Gym Leader [Bede] - 013, // Pokémon Trainer [Marnie] - 014, // Pokémon Trainer [Marnie, Gym Outfit] - 015, // Gym Leader [Marnie] - 020, // Gym Leader [Milo] - 021, // Gym Leader [Nessa] - 022, // Gym Leader [Kabu] - 023, // Gym Leader [Bea] - 024, // Gym Leader [Allister] - 025, // Gym Leader [Opal] - 026, // Gym Leader [Gordie] - 027, // Gym Leader [Melony] - 028, // Gym Leader [Piers] - 029, // Gym Leader [Raihan] - 030, // Macro Cosmos’s [Oleana] - 032, // Macro Cosmos’s [Rose] - 074, // Pokémon Trainer [Sordward] - 075, // Pokémon Trainer [Shielbert] - 183, // GAME FREAK’s [Morimoto] - 184, // Pokémon Trainer [Max Raid Battle, Hop] - 185, // Pokémon Trainer [Max Raid Battle, Piers] - 188, // Pokémon Trainer [First Battle, Hop] - 199, // Pokémon Trainer [Final Battle, Hop] - 200, // Pokémon Trainer [Opal] - 205, // Gym Leader [Rematch, Nessa] - 206, // Gym Leader [Rematch, Raihan] - 207, // Gym Leader [Rematch, Allister] - 208, // Gym Leader [Rematch, Bea] - 209, // Gym Leader [Rematch, Milo] - 210, // Gym Leader [Champion Cup, Nessa] - 211, // Gym Leader [Champion Cup, Kabu] - 212, // Gym Leader [Champion Cup, Bea] - 213, // Gym Leader [Champion Cup, Allister] - 214, // Gym Leader [Champion Cup, Opal] - 215, // Gym Leader [Champion Cup, Gordie] - 216, // Gym Leader [Champion Cup, Melony] - 217, // Pokémon Trainer [Champion Cup, Piers] - 218, // Gym Leader [Champion Cup, Raihan] - 219, // Pokémon Trainer [Klara] - 220, // Pokémon Trainer [Avery] - 221, // Dojo Master [Mustard] - 222, // Dojo Master [Mustard, No Jacket] - 227, // Dojo Matron [Honey] - 228, // Pokémon Trainer [Peony] - 229, // Pokémon Trainer [Peonia] - 250, // Pokémon Trainer [Klara] - 251, // Pokémon Trainer [Avery] - 252, // Gym Leader [Avery] - 253, // Gym Leader [Klara] - #endregion - }; + public static readonly int[] SpecialClasses_SWSH = + { + #region Classes + 004, // Champion [Leon] + 005, // Pokémon Trainer [Leon, Battle Tower] + 006, // Pokémon Trainer [Leon, Champion Cup Rematches] + 007, // Pokémon Trainer [Hop] + 008, // Pokémon Trainer [Hop, Gym Outfit] + 011, // Pokémon Trainer [Bede] + 012, // Gym Leader [Bede] + 013, // Pokémon Trainer [Marnie] + 014, // Pokémon Trainer [Marnie, Gym Outfit] + 015, // Gym Leader [Marnie] + 020, // Gym Leader [Milo] + 021, // Gym Leader [Nessa] + 022, // Gym Leader [Kabu] + 023, // Gym Leader [Bea] + 024, // Gym Leader [Allister] + 025, // Gym Leader [Opal] + 026, // Gym Leader [Gordie] + 027, // Gym Leader [Melony] + 028, // Gym Leader [Piers] + 029, // Gym Leader [Raihan] + 030, // Macro Cosmos’s [Oleana] + 032, // Macro Cosmos’s [Rose] + 074, // Pokémon Trainer [Sordward] + 075, // Pokémon Trainer [Shielbert] + 183, // GAME FREAK’s [Morimoto] + 184, // Pokémon Trainer [Max Raid Battle, Hop] + 185, // Pokémon Trainer [Max Raid Battle, Piers] + 188, // Pokémon Trainer [First Battle, Hop] + 199, // Pokémon Trainer [Final Battle, Hop] + 200, // Pokémon Trainer [Opal] + 205, // Gym Leader [Rematch, Nessa] + 206, // Gym Leader [Rematch, Raihan] + 207, // Gym Leader [Rematch, Allister] + 208, // Gym Leader [Rematch, Bea] + 209, // Gym Leader [Rematch, Milo] + 210, // Gym Leader [Champion Cup, Nessa] + 211, // Gym Leader [Champion Cup, Kabu] + 212, // Gym Leader [Champion Cup, Bea] + 213, // Gym Leader [Champion Cup, Allister] + 214, // Gym Leader [Champion Cup, Opal] + 215, // Gym Leader [Champion Cup, Gordie] + 216, // Gym Leader [Champion Cup, Melony] + 217, // Pokémon Trainer [Champion Cup, Piers] + 218, // Gym Leader [Champion Cup, Raihan] + 219, // Pokémon Trainer [Klara] + 220, // Pokémon Trainer [Avery] + 221, // Dojo Master [Mustard] + 222, // Dojo Master [Mustard, No Jacket] + 227, // Dojo Matron [Honey] + 228, // Pokémon Trainer [Peony] + 229, // Pokémon Trainer [Peonia] + 250, // Pokémon Trainer [Klara] + 251, // Pokémon Trainer [Avery] + 252, // Gym Leader [Avery] + 253, // Gym Leader [Klara] + #endregion + }; - public static readonly int[] DoubleBattleClasses_SWSH = - { - #region DoubleBattleClasses - 072, // Reporter - 073, // Cameraman - 170, // Musician - 171, // Dancer - 172, // Rail Staff - 173, // Beauty - 175, // Office Worker [Male] - 176, // Office Worker [Female] - 178, // Team Yell [Male] - 179, // Gym Trainer [Dark, Male] - 180, // Doctor [Male] - 181, // Doctor [Female] - 186, // Pokémon Trainer [Sordward] - 187, // Pokémon Trainer [Shielbert] - 202, // Team Yell [Female] - 203, // Macro Cosmos’s [Male] - 204, // Macro Cosmos’s [Female] - 230, // Dojo Master [Galarian Star Tournament, Mustard] - 231, // Gym Leader [Galarian Star Tournament, Bede] - 232, // Gym Leader [Galarian Star Tournament, Marnie] - 233, // Pokémon Trainer [Galarian Star Tournament, Leon] - 234, // Gym Leader [Galarian Star Tournament, Kabu] - 235, // Gym Leader [Galarian Star Tournament, Nessa] - 236, // Pokémon Trainer [Galarian Star Tournament, Piers] - 237, // Gym Leader [Galarian Star Tournament, Allister] - 238, // Gym Leader [Galarian Star Tournament, Raihan] - 239, // Gym Leader [Galarian Star Tournament, Bea] - 240, // Pokémon Trainer [Galarian Star Tournament, Shielbert] - 241, // Pokémon Trainer [Galarian Star Tournament, Hop] - 242, // Gym Leader [Galarian Star Tournament, Melony] - 243, // Gym Leader [Galarian Star Tournament, Gordie] - 244, // Gym Leader [Galarian Star Tournament, Avery] - 245, // Gym Leader [Galarian Star Tournament, Klara] - 246, // Pokémon Trainer [Galarian Star Tournament, Peony] - 247, // Pokémon Trainer [Galarian Star Tournament, Sordward] - 248, // Gym Leader [Galarian Star Tournament, Milo] - 249, // Pokémon Trainer [Galarian Star Tournament, Opal] + public static readonly int[] DoubleBattleClasses_SWSH = + { + #region DoubleBattleClasses + 072, // Reporter + 073, // Cameraman + 170, // Musician + 171, // Dancer + 172, // Rail Staff + 173, // Beauty + 175, // Office Worker [Male] + 176, // Office Worker [Female] + 178, // Team Yell [Male] + 179, // Gym Trainer [Dark, Male] + 180, // Doctor [Male] + 181, // Doctor [Female] + 186, // Pokémon Trainer [Sordward] + 187, // Pokémon Trainer [Shielbert] + 202, // Team Yell [Female] + 203, // Macro Cosmos’s [Male] + 204, // Macro Cosmos’s [Female] + 230, // Dojo Master [Galarian Star Tournament, Mustard] + 231, // Gym Leader [Galarian Star Tournament, Bede] + 232, // Gym Leader [Galarian Star Tournament, Marnie] + 233, // Pokémon Trainer [Galarian Star Tournament, Leon] + 234, // Gym Leader [Galarian Star Tournament, Kabu] + 235, // Gym Leader [Galarian Star Tournament, Nessa] + 236, // Pokémon Trainer [Galarian Star Tournament, Piers] + 237, // Gym Leader [Galarian Star Tournament, Allister] + 238, // Gym Leader [Galarian Star Tournament, Raihan] + 239, // Gym Leader [Galarian Star Tournament, Bea] + 240, // Pokémon Trainer [Galarian Star Tournament, Shielbert] + 241, // Pokémon Trainer [Galarian Star Tournament, Hop] + 242, // Gym Leader [Galarian Star Tournament, Melony] + 243, // Gym Leader [Galarian Star Tournament, Gordie] + 244, // Gym Leader [Galarian Star Tournament, Avery] + 245, // Gym Leader [Galarian Star Tournament, Klara] + 246, // Pokémon Trainer [Galarian Star Tournament, Peony] + 247, // Pokémon Trainer [Galarian Star Tournament, Sordward] + 248, // Gym Leader [Galarian Star Tournament, Milo] + 249, // Pokémon Trainer [Galarian Star Tournament, Opal] - // These Trainer Classes are never assigned to Trainers, they're purely for display - 168, // Interviewers (Displayed when Trainer Classes 072 and 073 partake in a Double Battle) - 169, // Music Crew (Displayed when Trainer Classes 170 and 171 partake in a Double Battle) - 174, // Daring Couple (Displayed when Trainer Classes 172 and 173 partake in a Double Battle) - 177, // Colleagues (Displayed when Trainer Classes 175 and 176 partake in a Double Battle) - 182, // Medical Team (Displayed when Trainer Classes 180 and 181 partake in a Double Battle) - #endregion - }; + // These Trainer Classes are never assigned to Trainers, they're purely for display + 168, // Interviewers (Displayed when Trainer Classes 072 and 073 partake in a Double Battle) + 169, // Music Crew (Displayed when Trainer Classes 170 and 171 partake in a Double Battle) + 174, // Daring Couple (Displayed when Trainer Classes 172 and 173 partake in a Double Battle) + 177, // Colleagues (Displayed when Trainer Classes 175 and 176 partake in a Double Battle) + 182, // Medical Team (Displayed when Trainer Classes 180 and 181 partake in a Double Battle) + #endregion + }; - // - // Unused Trainer Classes in Sword and Shield. - // Consists of NPCs you can interact with but never battle. - // - public static readonly int[] UnusedClasses_SWSH = - { - #region UnusedClasses - 000, // Pokémon Trainer [Your Player] - 001, // Pokémon Trainer [Your Player] - 002, // きんにくじまん [T-Pose] - 003, // おかあさん [Mother] - 009, // じょしゅ [Sonia, Trench Coat] - 010, // じょしゅ [Sonia, Lab Coat] - 016, // おばさん [T-Pose] - 017, // ポケモンはかせ [Magnolia, Lab Coat] - 018, // ポケモンはかせ [Magnolia, Casual Dress] - 031, // Macro Cosmos’s [Rose, Casual Clothing] - 119, // Gym Challenger [T-Pose] - 121, // Gym Challenger [T-Pose] - 123, // Gym Challenger [T-Pose] - 125, // Gym Challenger [T-Pose] - 127, // Gym Challenger [T-Pose] - 129, // Gym Challenger [T-Pose] - 131, // Gym Challenger [T-Pose] - 133, // Gym Challenger [T-Pose] - 135, // Gym Challenger [T-Pose] - 137, // Gym Challenger [T-Pose] - 139, // Gym Challenger [T-Pose] - 141, // Gym Challenger [T-Pose] - 143, // Gym Challenger [T-Pose] - 145, // Gym Challenger [T-Pose] - 147, // Gym Challenger [T-Pose] - 148, // PCじょう [Pokémon Center Lady] - 149, // リーグしんぱんいん [League Referee] - 150, // カセキはかせ [Cara Liss] - 151, // Ball Guy [T-Pose] - 152, // てんいん [Poké Mart Clerk] - 153, // てんいん [T-Pose] - 155, // えんじ [Preschooler] - 156, // えんじ [Preschooler] - 157, // じどう [T-Pose] - 158, // じどう [T-Pose] - 159, // わかもの [T-Pose] - 160, // ちゅうねん [T-Pose] - 161, // ちゅうねん [T-Pose] - 162, // ろうじん [T-Pose] - 163, // ろうじん [T-Pose] - 164, // ちゅうねん [T-Pose] - 167, // Young Man [T-Pose] - 224, // Master Dojo [Male] -- functionally identical to 223 - 226, // Master Dojo [Female] -- functionally identical to 225 - #endregion - }; + // + // Unused Trainer Classes in Sword and Shield. + // Consists of NPCs you can interact with but never battle. + // + public static readonly int[] UnusedClasses_SWSH = + { + #region UnusedClasses + 000, // Pokémon Trainer [Your Player] + 001, // Pokémon Trainer [Your Player] + 002, // きんにくじまん [T-Pose] + 003, // おかあさん [Mother] + 009, // じょしゅ [Sonia, Trench Coat] + 010, // じょしゅ [Sonia, Lab Coat] + 016, // おばさん [T-Pose] + 017, // ポケモンはかせ [Magnolia, Lab Coat] + 018, // ポケモンはかせ [Magnolia, Casual Dress] + 031, // Macro Cosmos’s [Rose, Casual Clothing] + 119, // Gym Challenger [T-Pose] + 121, // Gym Challenger [T-Pose] + 123, // Gym Challenger [T-Pose] + 125, // Gym Challenger [T-Pose] + 127, // Gym Challenger [T-Pose] + 129, // Gym Challenger [T-Pose] + 131, // Gym Challenger [T-Pose] + 133, // Gym Challenger [T-Pose] + 135, // Gym Challenger [T-Pose] + 137, // Gym Challenger [T-Pose] + 139, // Gym Challenger [T-Pose] + 141, // Gym Challenger [T-Pose] + 143, // Gym Challenger [T-Pose] + 145, // Gym Challenger [T-Pose] + 147, // Gym Challenger [T-Pose] + 148, // PCじょう [Pokémon Center Lady] + 149, // リーグしんぱんいん [League Referee] + 150, // カセキはかせ [Cara Liss] + 151, // Ball Guy [T-Pose] + 152, // てんいん [Poké Mart Clerk] + 153, // てんいん [T-Pose] + 155, // えんじ [Preschooler] + 156, // えんじ [Preschooler] + 157, // じどう [T-Pose] + 158, // じどう [T-Pose] + 159, // わかもの [T-Pose] + 160, // ちゅうねん [T-Pose] + 161, // ちゅうねん [T-Pose] + 162, // ろうじん [T-Pose] + 163, // ろうじん [T-Pose] + 164, // ちゅうねん [T-Pose] + 167, // Young Man [T-Pose] + 224, // Master Dojo [Male] -- functionally identical to 223 + 226, // Master Dojo [Female] -- functionally identical to 225 + #endregion + }; - // - // Unused Trainer Classes in Sword and Shield. - // Assigning these Trainer Classes to a Trainer crashes the game. - // - public static readonly int[] CrashClasses_SWSH = - { - #region CrashClasses - 019, // ベテラントレーナー - 047, // Waitress - 068, // Stylist - 094, // Gym Leader - 095, // Gym Trainer - 096, // Gym Trainer - 097, // Gym Leader - 098, // Gym Trainer - 099, // Gym Trainer - 100, // Gym Leader - 101, // Gym Trainer - 102, // Gym Trainer - 103, // Gym Leader - 104, // Gym Trainer - 105, // Gym Trainer - 106, // Gym Leader - 107, // Gym Trainer - 108, // Gym Trainer - 109, // Gym Leader - 110, // Gym Trainer - 111, // Gym Trainer - 112, // Gym Leader - 113, // Gym Trainer - 114, // Gym Trainer - 115, // Gym Leader - 116, // Gym Trainer - 117, // Gym Trainer - 154, // はいたついん - 222, // Dojo Master [Mustard] -- this is used, but crashes if assigned to any other trainers - #endregion - }; + // + // Unused Trainer Classes in Sword and Shield. + // Assigning these Trainer Classes to a Trainer crashes the game. + // + public static readonly int[] CrashClasses_SWSH = + { + #region CrashClasses + 019, // ベテラントレーナー + 047, // Waitress + 068, // Stylist + 094, // Gym Leader + 095, // Gym Trainer + 096, // Gym Trainer + 097, // Gym Leader + 098, // Gym Trainer + 099, // Gym Trainer + 100, // Gym Leader + 101, // Gym Trainer + 102, // Gym Trainer + 103, // Gym Leader + 104, // Gym Trainer + 105, // Gym Trainer + 106, // Gym Leader + 107, // Gym Trainer + 108, // Gym Trainer + 109, // Gym Leader + 110, // Gym Trainer + 111, // Gym Trainer + 112, // Gym Leader + 113, // Gym Trainer + 114, // Gym Trainer + 115, // Gym Leader + 116, // Gym Trainer + 117, // Gym Trainer + 154, // はいたついん + 222, // Dojo Master [Mustard] -- this is used, but crashes if assigned to any other trainers + #endregion + }; - // - // Dummy Trainer Classes in Sword and Shield. - // No names are assigned to them. Could be preserved for future DLC, or could just be leftovers. - // - public static readonly int[] DummyClasses_SWSH = - { - #region DummyClasses - 254, // [~ 254] - 255, // [~ 255] - 256, // [~ 256] - 257, // [~ 257] - 258, // [~ 258] - 259, // [~ 259] - 260, // [~ 260] - 261, // [~ 261] - 262, // [~ 262] - 263, // [~ 263] - 264, // [~ 264] - 265, // [~ 265] - 266, // [~ 266] - 267, // [~ 267] - 268, // [~ 268] - 269, // [~ 269] - 270, // [~ 270] - #endregion - }; + // + // Dummy Trainer Classes in Sword and Shield. + // No names are assigned to them. Could be preserved for future DLC, or could just be leftovers. + // + public static readonly int[] DummyClasses_SWSH = + { + #region DummyClasses + 254, // [~ 254] + 255, // [~ 255] + 256, // [~ 256] + 257, // [~ 257] + 258, // [~ 258] + 259, // [~ 259] + 260, // [~ 260] + 261, // [~ 261] + 262, // [~ 262] + 263, // [~ 263] + 264, // [~ 264] + 265, // [~ 265] + 266, // [~ 266] + 267, // [~ 267] + 268, // [~ 268] + 269, // [~ 269] + 270, // [~ 270] + #endregion + }; - public static readonly int[] BlacklistedClasses_SWSH = DoubleBattleClasses_SWSH.Concat(UnusedClasses_SWSH).Concat(CrashClasses_SWSH).Concat(DummyClasses_SWSH).ToArray(); + public static readonly int[] BlacklistedClasses_SWSH = DoubleBattleClasses_SWSH.Concat(UnusedClasses_SWSH).Concat(CrashClasses_SWSH).Concat(DummyClasses_SWSH).ToArray(); - public static readonly int[] Model_XY = - { - #region Models - 018, // Aliana - 019, // Bryony - 020, // Celosia - 021, // Mable - 022, // Xerosic - 055, // Shauna - 056, // Tierno - 057, // Trevor - 081, // Lysandre - 102, // AZ - 103, // Calem - 104, // Serena - 105, // Sycamore - 175, // Lysandre (Mega Ring) - #endregion - }; + public static readonly int[] Model_XY = + { + #region Models + 018, // Aliana + 019, // Bryony + 020, // Celosia + 021, // Mable + 022, // Xerosic + 055, // Shauna + 056, // Tierno + 057, // Trevor + 081, // Lysandre + 102, // AZ + 103, // Calem + 104, // Serena + 105, // Sycamore + 175, // Lysandre (Mega Ring) + #endregion + }; - public static readonly int[] Model_AO = - { - #region Models - 127, // Brendan - 128, // May - 174, // Archie - 178, // Maxie - 192, // Wally - 198, // Steven - 219, // Steven (Multi Battle) - 221, // Zinnia (Lorekeeper) - 267, // Zinnia - 272, // Wally (Mega Pendant) - 277, // Steven (Rematch) - 278, // Brendan (Mega Bracelet) - 279, // May (Mega Bracelet) - #endregion - }; + public static readonly int[] Model_AO = + { + #region Models + 127, // Brendan + 128, // May + 174, // Archie + 178, // Maxie + 192, // Wally + 198, // Steven + 219, // Steven (Multi Battle) + 221, // Zinnia (Lorekeeper) + 267, // Zinnia + 272, // Wally (Mega Pendant) + 277, // Steven (Rematch) + 278, // Brendan (Mega Bracelet) + 279, // May (Mega Bracelet) + #endregion + }; - public static readonly int[] Z_Moves = - { - 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, - 695, 696, 697, 698, 699, 700, 701, 702, 703, 719, 723, 724, 725, 726, 727, 728 - }; + public static readonly int[] Z_Moves = + { + 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, + 695, 696, 697, 698, 699, 700, 701, 702, 703, 719, 723, 724, 725, 726, 727, 728 + }; - public static readonly int[] Max_Moves = - { - 743, // Max Guard - 757, // Max Flare - 758, // Max Flutterby - 759, // Max Lightning - 760, // Max Strike - 761, // Max Knuckle - 762, // Max Phantasm - 763, // Max Hailstorm - 764, // Max Ooze - 765, // Max Geyser - 766, // Max Airstream - 767, // Max Starfall - 768, // Max Wyrmwind - 769, // Max Mindstorm - 770, // Max Rockfall - 771, // Max Quake - 772, // Max Darkness - 773, // Max Overgrowth - 774, // Max Steelspike - }; + public static readonly int[] Max_Moves = + { + 743, // Max Guard + 757, // Max Flare + 758, // Max Flutterby + 759, // Max Lightning + 760, // Max Strike + 761, // Max Knuckle + 762, // Max Phantasm + 763, // Max Hailstorm + 764, // Max Ooze + 765, // Max Geyser + 766, // Max Airstream + 767, // Max Starfall + 768, // Max Wyrmwind + 769, // Max Mindstorm + 770, // Max Rockfall + 771, // Max Quake + 772, // Max Darkness + 773, // Max Overgrowth + 774, // Max Steelspike + }; - public static readonly int[] Taboo_Moves = - { - 165, // Struggle - 464, // Dark Void - 621, // Hyperspace Fury - 781, // Behemoth Blade - 782, // Behemoth Bash - }; + public static readonly int[] Taboo_Moves = + { + 165, // Struggle + 464, // Dark Void + 621, // Hyperspace Fury + 781, // Behemoth Blade + 782, // Behemoth Bash + }; - public static readonly int[] ImportantTrainers_XY = - { - 006, 021, 022, 023, 024, 025, 026, 076, 130, 131, 132, 175, 184, 185, 186, 187, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, - 275, 276, 277, 279, 303, 321, 322, 323, 324, 325, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 237, 348, 349, 350, 351, 435, 436, - 437, 438, 439, 503, 504, 505, 507, 511, 512, 513, 514, 515, 519, 520, 521, 525, 526, 559, 560, 561, 562, 573, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, - 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 604, 605, 606, 613 - }; + public static readonly int[] ImportantTrainers_XY = + { + 006, 021, 022, 023, 024, 025, 026, 076, 130, 131, 132, 175, 184, 185, 186, 187, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, + 275, 276, 277, 279, 303, 321, 322, 323, 324, 325, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 237, 348, 349, 350, 351, 435, 436, + 437, 438, 439, 503, 504, 505, 507, 511, 512, 513, 514, 515, 519, 520, 521, 525, 526, 559, 560, 561, 562, 573, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, + 590, 591, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 602, 604, 605, 606, 613 + }; - public static readonly int[] ImportantTrainers_ORAS = - { - 178, 231, 235, 236, 266, 271, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 518, 527, 528, 529, 530, 531, 532, 553, 554, 555, 556, 557, 561, 563, 567, 569, 570, 571, 572, - 583, 674, 675, 676, 677, 678, 679, 680, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 713, 856, 857, 898, 906, 907, 908, 909, 910, 911, - 912, 913, 942, 943, 944, 945, 946, 947 - }; + public static readonly int[] ImportantTrainers_ORAS = + { + 178, 231, 235, 236, 266, 271, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 518, 527, 528, 529, 530, 531, 532, 553, 554, 555, 556, 557, 561, 563, 567, 569, 570, 571, 572, + 583, 674, 675, 676, 677, 678, 679, 680, 683, 684, 685, 686, 687, 688, 689, 690, 691, 692, 693, 694, 695, 696, 697, 698, 699, 700, 701, 713, 856, 857, 898, 906, 907, 908, 909, 910, 911, + 912, 913, 942, 943, 944, 945, 946, 947 + }; - public static readonly int[] ImportantTrainers_SM = - { - 012, 013, 014, 023, 052, 074, 075, 076, 077, 078, 079, 089, 090, 129, 131, 132, 138, 144, 146, 149, 152, 153, 154, 155, 156, 158, 159, 160, 164, 167, 215, 216, 217, 218, 219, 220, 221, - 222, 235, 236, 238, 239, 240, 241, 349, 350, 351, 352, 356, 357, 358, 359, 360, 392, 396, 398, 400, 401, 403, 405, 409, 410, 412, 413, 414, 415, 416, 417, 418, 419, 435, 438, 439, 440, - 441, 447, 448, 449, 450, 451, 452, 467, 477, 478, 479, 480, 481, 482, 483, 484 - }; + public static readonly int[] ImportantTrainers_SM = + { + 012, 013, 014, 023, 052, 074, 075, 076, 077, 078, 079, 089, 090, 129, 131, 132, 138, 144, 146, 149, 152, 153, 154, 155, 156, 158, 159, 160, 164, 167, 215, 216, 217, 218, 219, 220, 221, + 222, 235, 236, 238, 239, 240, 241, 349, 350, 351, 352, 356, 357, 358, 359, 360, 392, 396, 398, 400, 401, 403, 405, 409, 410, 412, 413, 414, 415, 416, 417, 418, 419, 435, 438, 439, 440, + 441, 447, 448, 449, 450, 451, 452, 467, 477, 478, 479, 480, 481, 482, 483, 484 + }; - public static readonly int[] ImportantTrainers_USUM = - { - 012, 013, 014, 023, 052, 074, 075, 076, 077, 078, 079, 089, 090, 131, 132, 138, 144, 146, 149, 153, 154, 156, 159, 160, 215, 216, 217, 218, 219, 220, 221, 222, 235, 236, 238, 239, 240, - 241, 350, 351, 352, 356, 358, 359, 396, 398, 401, 405, 409, 410, 412, 415, 416, 417, 418, 419, 438, 439, 440, 441, 447, 448, 449, 450, 451, 452, 477, 478, 479, 480, 489, 490, 494, 495, - 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 541, 542, 543, 555, 556, 557, 558, 559, 560, 561, 562, 572, 573, 578, 580, 582, 583, 623, 630, 644, 645, 647, 648, 649, - 650, 651, 652 - }; + public static readonly int[] ImportantTrainers_USUM = + { + 012, 013, 014, 023, 052, 074, 075, 076, 077, 078, 079, 089, 090, 131, 132, 138, 144, 146, 149, 153, 154, 156, 159, 160, 215, 216, 217, 218, 219, 220, 221, 222, 235, 236, 238, 239, 240, + 241, 350, 351, 352, 356, 358, 359, 396, 398, 401, 405, 409, 410, 412, 415, 416, 417, 418, 419, 438, 439, 440, 441, 447, 448, 449, 450, 451, 452, 477, 478, 479, 480, 489, 490, 494, 495, + 496, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 541, 542, 543, 555, 556, 557, 558, 559, 560, 561, 562, 572, 573, 578, 580, 582, 583, 623, 630, 644, 645, 647, 648, 649, + 650, 651, 652 + }; - public static readonly int[] ImportantTrainers_GG = - { - 005, 007, 008, 009, 010, 011, 013, 014, 015, 016, 017, 018, 020, 021, 022, 023, 024, 025, 027, 028, 030, 031, 032, 033, 034, 035, 036, 037, 038, 039, 040, 041, 042, 043, 044, 045, 046, - 048, 049, 050, 051, 052, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 437, 439, 597, 601 - }; + public static readonly int[] ImportantTrainers_GG = + { + 005, 007, 008, 009, 010, 011, 013, 014, 015, 016, 017, 018, 020, 021, 022, 023, 024, 025, 027, 028, 030, 031, 032, 033, 034, 035, 036, 037, 038, 039, 040, 041, 042, 043, 044, 045, 046, + 048, 049, 050, 051, 052, 414, 415, 416, 417, 418, 419, 420, 421, 422, 423, 424, 425, 426, 427, 437, 439, 597, 601 + }; - public static readonly int[] ImportantTrainers_SWSH = - { - 032, 036, 037, 077, 078, 107, 108, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 143, 144, 145, 149, 153, 154, 155, 156, 157, 158, 175, 189, 190, - 191, 192, 193, 195, 196, 197, 198, 199, 202, 203, 204, 210, 211, 212, 213, 214, 215, 216, 221, 222, 225, 226, 227, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 248, 249, 250, 251, - 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 264, 265, 266, 267, 268, 269, 289, 315, 316, 317, 318, 319, 320, 321, 324, 325, 326, 327, 328, 329, 330, 374, 376, 414, 415, 416, - 417, 418, 419, 420, 431, 432, 433, 434, - }; - } + public static readonly int[] ImportantTrainers_SWSH = + { + 032, 036, 037, 077, 078, 107, 108, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 138, 143, 144, 145, 149, 153, 154, 155, 156, 157, 158, 175, 189, 190, + 191, 192, 193, 195, 196, 197, 198, 199, 202, 203, 204, 210, 211, 212, 213, 214, 215, 216, 221, 222, 225, 226, 227, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 264, 265, 266, 267, 268, 269, 289, 315, 316, 317, 318, 319, 320, 321, 324, 325, 326, 327, 328, 329, 330, 374, 376, 414, 415, 416, + 417, 418, 419, 420, 431, 432, 433, 434, + }; } diff --git a/pkNX.Structures/Maison/Maison6.cs b/pkNX.Structures/Maison/Maison6.cs index f1b9005a..8e92204f 100644 --- a/pkNX.Structures/Maison/Maison6.cs +++ b/pkNX.Structures/Maison/Maison6.cs @@ -1,88 +1,87 @@ -using System; +using System; using System.IO; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Maison6Trainer { - public class Maison6Trainer + public ushort Class; + public ushort Count; + public ushort[] Choices; + + public Maison6Trainer() { } + + public Maison6Trainer(byte[] data) { - public ushort Class; - public ushort Count; - public ushort[] Choices; - - public Maison6Trainer() { } - - public Maison6Trainer(byte[] data) - { - Class = BitConverter.ToUInt16(data, 0); - Count = BitConverter.ToUInt16(data, 2); - Choices = new ushort[Count]; - for (int i = 0; i < Count; i++) - Choices[i] = BitConverter.ToUInt16(data, 4 + (2 * i)); - } - - public byte[] Write() - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - bw.Write(Class); - bw.Write(Count); - foreach (ushort Choice in Choices) - bw.Write(Choice); - return ms.ToArray(); - } + Class = BitConverter.ToUInt16(data, 0); + Count = BitConverter.ToUInt16(data, 2); + Choices = new ushort[Count]; + for (int i = 0; i < Count; i++) + Choices[i] = BitConverter.ToUInt16(data, 4 + (2 * i)); } - public class Maison6Pokemon + public byte[] Write() { - public ushort Species; - public readonly ushort[] Moves = new ushort[4]; - private readonly byte EV; - public readonly bool[] EVs = new bool[6]; - public byte Nature; - public ushort Item; - public ushort Form; - - public int Move1 { get => Moves[0]; set => Moves[0] = (ushort)value; } - public int Move2 { get => Moves[1]; set => Moves[1] = (ushort)value; } - public int Move3 { get => Moves[2]; set => Moves[2] = (ushort)value; } - public int Move4 { get => Moves[3]; set => Moves[3] = (ushort)value; } - public bool HP { get => EVs[0]; set => EVs[0] = value; } - public bool ATK { get => EVs[1]; set => EVs[1] = value; } - public bool DEF { get => EVs[2]; set => EVs[2] = value; } - public bool SPE { get => EVs[3]; set => EVs[3] = value; } - public bool SPA { get => EVs[4]; set => EVs[4] = value; } - public bool SPD { get => EVs[5]; set => EVs[5] = value; } - - public Maison6Pokemon(byte[] data) - { - Species = BitConverter.ToUInt16(data, 0); - for (int i = 0; i < 4; i++) - Moves[i] = BitConverter.ToUInt16(data, 2 + (2 * i)); - EV = data[0xA]; - for (int i = 0; i < 6; i++) - EVs[i] = ((EV >> i) & 1) == 1; - Nature = data[0xB]; - Item = BitConverter.ToUInt16(data, 0xC); - Form = BitConverter.ToUInt16(data, 0xE); - } - - public byte[] Write() - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - bw.Write(Species); - foreach (ushort Move in Moves) - bw.Write(Move); - - int ev = EV & 0xC0; - for (int i = 0; i < EVs.Length; i++) - ev |= EVs[i] ? 1 << i : 0; - bw.Write((byte)ev); - - bw.Write(Nature); - bw.Write(Item); - bw.Write(Form); - return ms.ToArray(); - } + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + bw.Write(Class); + bw.Write(Count); + foreach (ushort Choice in Choices) + bw.Write(Choice); + return ms.ToArray(); + } +} + +public class Maison6Pokemon +{ + public ushort Species; + public readonly ushort[] Moves = new ushort[4]; + private readonly byte EV; + public readonly bool[] EVs = new bool[6]; + public byte Nature; + public ushort Item; + public ushort Form; + + public int Move1 { get => Moves[0]; set => Moves[0] = (ushort)value; } + public int Move2 { get => Moves[1]; set => Moves[1] = (ushort)value; } + public int Move3 { get => Moves[2]; set => Moves[2] = (ushort)value; } + public int Move4 { get => Moves[3]; set => Moves[3] = (ushort)value; } + public bool HP { get => EVs[0]; set => EVs[0] = value; } + public bool ATK { get => EVs[1]; set => EVs[1] = value; } + public bool DEF { get => EVs[2]; set => EVs[2] = value; } + public bool SPE { get => EVs[3]; set => EVs[3] = value; } + public bool SPA { get => EVs[4]; set => EVs[4] = value; } + public bool SPD { get => EVs[5]; set => EVs[5] = value; } + + public Maison6Pokemon(byte[] data) + { + Species = BitConverter.ToUInt16(data, 0); + for (int i = 0; i < 4; i++) + Moves[i] = BitConverter.ToUInt16(data, 2 + (2 * i)); + EV = data[0xA]; + for (int i = 0; i < 6; i++) + EVs[i] = ((EV >> i) & 1) == 1; + Nature = data[0xB]; + Item = BitConverter.ToUInt16(data, 0xC); + Form = BitConverter.ToUInt16(data, 0xE); + } + + public byte[] Write() + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + bw.Write(Species); + foreach (ushort Move in Moves) + bw.Write(Move); + + int ev = EV & 0xC0; + for (int i = 0; i < EVs.Length; i++) + ev |= EVs[i] ? 1 << i : 0; + bw.Write((byte)ev); + + bw.Write(Nature); + bw.Write(Item); + bw.Write(Form); + return ms.ToArray(); } } diff --git a/pkNX.Structures/MegaEvolution/MegaEvolutionMethod.cs b/pkNX.Structures/MegaEvolution/MegaEvolutionMethod.cs index 1ac73585..b200641d 100644 --- a/pkNX.Structures/MegaEvolution/MegaEvolutionMethod.cs +++ b/pkNX.Structures/MegaEvolution/MegaEvolutionMethod.cs @@ -1,10 +1,9 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum MegaEvolutionMethod { - public enum MegaEvolutionMethod - { - None = 0, - Item = 1, - DragonAscent = 2, - NoRequirement = 3, - } -} \ No newline at end of file + None = 0, + Item = 1, + DragonAscent = 2, + NoRequirement = 3, +} diff --git a/pkNX.Structures/MegaEvolution/MegaEvolutionSet.cs b/pkNX.Structures/MegaEvolution/MegaEvolutionSet.cs index 48004b44..9e233e47 100644 --- a/pkNX.Structures/MegaEvolution/MegaEvolutionSet.cs +++ b/pkNX.Structures/MegaEvolution/MegaEvolutionSet.cs @@ -1,70 +1,69 @@ -using System; +using System; using System.Diagnostics; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class MegaEvolutionSet { - public class MegaEvolutionSet + private readonly byte[] Data; + private const int OFS_FORM = 0; + private const int OFS_METHOD = 2; + private const int OFS_ARGUMENT = 4; + public const int SIZE = 8; + + public MegaEvolutionSet(byte[] data, int index) { - private readonly byte[] Data; - private const int OFS_FORM = 0; - private const int OFS_METHOD = 2; - private const int OFS_ARGUMENT = 4; - public const int SIZE = 8; + Debug.Assert(data.Length % SIZE == 0); + Data = new byte[SIZE]; + Array.Copy(data, index*SIZE, Data, 0, SIZE); + } - public MegaEvolutionSet(byte[] data, int index) - { - Debug.Assert(data.Length % SIZE == 0); - Data = new byte[SIZE]; - Array.Copy(data, index*SIZE, Data, 0, SIZE); - } + public static MegaEvolutionSet[] ReadArray(byte[] data) + { + var count = data.Length / SIZE; + var result = new MegaEvolutionSet[count]; + for (int i = 0; i < count; i++) + result[i] = new MegaEvolutionSet(data, i); + return result; + } - public static MegaEvolutionSet[] ReadArray(byte[] data) - { - var count = data.Length / SIZE; - var result = new MegaEvolutionSet[count]; - for (int i = 0; i < count; i++) - result[i] = new MegaEvolutionSet(data, i); - return result; - } + public static byte[] WriteArray(MegaEvolutionSet[] data) + { + return data.SelectMany(z => z.Write()).ToArray(); + } - public static byte[] WriteArray(MegaEvolutionSet[] data) - { - return data.SelectMany(z => z.Write()).ToArray(); - } + public int ToForm + { + get => BitConverter.ToUInt16(Data, OFS_FORM); + set => BitConverter.GetBytes((ushort) value).CopyTo(Data, OFS_FORM); + } - public int ToForm - { - get => BitConverter.ToUInt16(Data, OFS_FORM); - set => BitConverter.GetBytes((ushort) value).CopyTo(Data, OFS_FORM); - } + public int Method + { + get => BitConverter.ToUInt16(Data, OFS_METHOD); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, OFS_METHOD); + } - public int Method - { - get => BitConverter.ToUInt16(Data, OFS_METHOD); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, OFS_METHOD); - } + public int Argument + { + get => BitConverter.ToUInt16(Data, OFS_ARGUMENT); + set => BitConverter.GetBytes((ushort)value).CopyTo(Data, OFS_ARGUMENT); + } - public int Argument - { - get => BitConverter.ToUInt16(Data, OFS_ARGUMENT); - set => BitConverter.GetBytes((ushort)value).CopyTo(Data, OFS_ARGUMENT); - } + public void Clear() + { + for (int i = 0; i < Data.Length; i++) + Data[i] = 0; + } - public void Clear() - { - for (int i = 0; i < Data.Length; i++) - Data[i] = 0; - } + public byte[] Write() => (byte[])Data.Clone(); - public byte[] Write() => (byte[])Data.Clone(); + public void Write(byte[] data, int index) => Data.CopyTo(data, index * SIZE); - public void Write(byte[] data, int index) => Data.CopyTo(data, index * SIZE); - - public void RemoveRestrictions() - { - if (Method != (int) MegaEvolutionMethod.None) - Method = (int) MegaEvolutionMethod.NoRequirement; - } + public void RemoveRestrictions() + { + if (Method != (int) MegaEvolutionMethod.None) + Method = (int) MegaEvolutionMethod.NoRequirement; } } diff --git a/pkNX.Structures/Misc/Ball.cs b/pkNX.Structures/Misc/Ball.cs index da4a43b5..8abbaf1d 100644 --- a/pkNX.Structures/Misc/Ball.cs +++ b/pkNX.Structures/Misc/Ball.cs @@ -1,55 +1,54 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Ball IDs for the corresponding English ball name. +/// +public enum Ball : byte { - /// - /// Ball IDs for the corresponding English ball name. - /// - public enum Ball : byte - { - None = 0, + None = 0, - Master = 1, - Ultra = 2, - Great = 3, - Poke = 4, + Master = 1, + Ultra = 2, + Great = 3, + Poke = 4, - Safari = 5, + Safari = 5, - Net = 6, - Dive = 7, - Nest = 8, - Repeat = 9, - Timer = 10, - Luxury = 11, - Premier = 12, - Dusk = 13, - Heal = 14, - Quick = 15, + Net = 6, + Dive = 7, + Nest = 8, + Repeat = 9, + Timer = 10, + Luxury = 11, + Premier = 12, + Dusk = 13, + Heal = 14, + Quick = 15, - Cherish = 16, + Cherish = 16, - Fast = 17, - Level = 18, - Lure = 19, - Heavy = 20, - Love = 21, - Friend = 22, - Moon = 23, + Fast = 17, + Level = 18, + Lure = 19, + Heavy = 20, + Love = 21, + Friend = 22, + Moon = 23, - Sport = 24, - Dream = 25, - Beast = 26, + Sport = 24, + Dream = 25, + Beast = 26, - // Legends: Arceus - Strange = 27, - LAPoke = 28, - LAGreat = 29, - LAUltra = 30, - LAFeather = 31, - LAWing = 32, - LAJet = 33, - LAHeavy = 34, - LALeaden = 35, - LAGigaton = 36, - LAOrigin = 37, - } + // Legends: Arceus + Strange = 27, + LAPoke = 28, + LAGreat = 29, + LAUltra = 30, + LAFeather = 31, + LAWing = 32, + LAJet = 33, + LAHeavy = 34, + LALeaden = 35, + LAGigaton = 36, + LAOrigin = 37, } diff --git a/pkNX.Structures/Misc/CaptureReward.cs b/pkNX.Structures/Misc/CaptureReward.cs index e2f0b9bc..f591f966 100644 --- a/pkNX.Structures/Misc/CaptureReward.cs +++ b/pkNX.Structures/Misc/CaptureReward.cs @@ -1,113 +1,112 @@ -using System.Collections.Generic; +using System.Collections.Generic; using System.IO; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Rewards given by after capturing a Pokémon. +/// +/// They do this because the Pickup Ability no longer exists, and to ease the grind of marts. +public class CaptureRewardTable { - /// - /// Rewards given by after capturing a Pokémon. - /// - /// They do this because the Pickup Ability no longer exists, and to ease the grind of marts. - public class CaptureRewardTable + public List Table = new(); + + public CaptureRewardTable(byte[] data) { - public List Table = new(); + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + ReadHeader(br); + ReadEntries(br); + } - public CaptureRewardTable(byte[] data) - { - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - ReadHeader(br); - ReadEntries(br); - } + private void ReadEntries(BinaryReader br) + { + foreach (var g in Table) + ReadTable(br, g); + } - private void ReadEntries(BinaryReader br) - { - foreach (var g in Table) - ReadTable(br, g); - } + private static void ReadTable(BinaryReader br, CaptureRewardGroup g) + { + for (int i = 0; i < g.EntryCount; i++) + g.Entries.Add(ReadEntry(br)); + } - private static void ReadTable(BinaryReader br, CaptureRewardGroup g) - { - for (int i = 0; i < g.EntryCount; i++) - g.Entries.Add(ReadEntry(br)); - } + private static CaptureRewardEntry ReadEntry(BinaryReader br) => new() + { + Item = br.ReadInt32(), + Count = br.ReadInt32(), + Rate = br.ReadInt32(), + }; - private static CaptureRewardEntry ReadEntry(BinaryReader br) => new() + private void ReadHeader(BinaryReader br) + { + while (true) { - Item = br.ReadInt32(), - Count = br.ReadInt32(), - Rate = br.ReadInt32(), - }; - - private void ReadHeader(BinaryReader br) - { - while (true) + var count = br.ReadInt32(); + if (Table.Count != 0 && Table[^1].CaptureCount > count) { - var count = br.ReadInt32(); - if (Table.Count != 0 && Table[^1].CaptureCount > count) - { - br.BaseStream.Position -= 4; - break; - } - var entries = br.ReadInt32(); - var group = new CaptureRewardGroup(count, entries); - Table.Add(group); - } - } - - public byte[] Write() - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - foreach (var g in Table) - { - bw.Write(g.CaptureCount); - bw.Write(g.Entries.Count); // instead of using the read value, use the list count (allow modification) - } - foreach (var g in Table) - { - foreach (var e in g.Entries) - { - bw.Write(e.Item); - bw.Write(e.Count); - bw.Write(e.Rate); - } - } - return ms.ToArray(); - } - - public IEnumerable Dump(string[] itemNames) - { - foreach (var g in Table) - { - yield return "========"; - yield return $"Count: {g.CaptureCount}"; - yield return "========"; - foreach (var item in g.Entries) - yield return $"{item.Rate:00}%\tx{item.Count}\t{itemNames[item.Item]}"; - yield return ""; + br.BaseStream.Position -= 4; + break; } + var entries = br.ReadInt32(); + var group = new CaptureRewardGroup(count, entries); + Table.Add(group); } } - public class CaptureRewardGroup + public byte[] Write() { - public int CaptureCount; - public int EntryCount; - - public List Entries; - - public CaptureRewardGroup(int count, int entries) + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + foreach (var g in Table) { - CaptureCount = count; - EntryCount = entries; - Entries = new List(entries); + bw.Write(g.CaptureCount); + bw.Write(g.Entries.Count); // instead of using the read value, use the list count (allow modification) } + foreach (var g in Table) + { + foreach (var e in g.Entries) + { + bw.Write(e.Item); + bw.Write(e.Count); + bw.Write(e.Rate); + } + } + return ms.ToArray(); } - public class CaptureRewardEntry + public IEnumerable Dump(string[] itemNames) { - public int Item; - public int Count; - public int Rate; + foreach (var g in Table) + { + yield return "========"; + yield return $"Count: {g.CaptureCount}"; + yield return "========"; + foreach (var item in g.Entries) + yield return $"{item.Rate:00}%\tx{item.Count}\t{itemNames[item.Item]}"; + yield return ""; + } } } + +public class CaptureRewardGroup +{ + public int CaptureCount; + public int EntryCount; + + public List Entries; + + public CaptureRewardGroup(int count, int entries) + { + CaptureCount = count; + EntryCount = entries; + Entries = new List(entries); + } +} + +public class CaptureRewardEntry +{ + public int Item; + public int Count; + public int Rate; +} diff --git a/pkNX.Structures/Misc/Heal.cs b/pkNX.Structures/Misc/Heal.cs index 9f40b34b..74cd6523 100644 --- a/pkNX.Structures/Misc/Heal.cs +++ b/pkNX.Structures/Misc/Heal.cs @@ -1,15 +1,14 @@ -namespace pkNX.Structures -{ - /// - /// Indicates how much a heal item/move heals. - /// - /// Any other non-enumerated value will be treated as a fixed value heal equal to the value. - public enum Heal : byte - { - None = 0, +namespace pkNX.Structures; - Quarter = 253, - Half = 254, - Full = 255, - } +/// +/// Indicates how much a heal item/move heals. +/// +/// Any other non-enumerated value will be treated as a fixed value heal equal to the value. +public enum Heal : byte +{ + None = 0, + + Quarter = 253, + Half = 254, + Full = 255, } diff --git a/pkNX.Structures/Misc/Moves.cs b/pkNX.Structures/Misc/Moves.cs index 9e29f918..64b1c827 100644 --- a/pkNX.Structures/Misc/Moves.cs +++ b/pkNX.Structures/Misc/Moves.cs @@ -1,4 +1,4 @@ -namespace pkNX.Structures; +namespace pkNX.Structures; /// /// Move IDs for the corresponding English move name. diff --git a/pkNX.Structures/Misc/Species.cs b/pkNX.Structures/Misc/Species.cs index fa57bc62..efffc050 100644 --- a/pkNX.Structures/Misc/Species.cs +++ b/pkNX.Structures/Misc/Species.cs @@ -1,916 +1,915 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Species IDs for the corresponding English species name. +/// +public enum Species : ushort { - /// - /// Species IDs for the corresponding English species name. - /// - public enum Species : ushort - { - None, - Bulbasaur, - Ivysaur, - Venusaur, - Charmander, - Charmeleon, - Charizard, - Squirtle, - Wartortle, - Blastoise, - Caterpie, - Metapod, - Butterfree, - Weedle, - Kakuna, - Beedrill, - Pidgey, - Pidgeotto, - Pidgeot, - Rattata, - Raticate, - Spearow, - Fearow, - Ekans, - Arbok, - Pikachu, - Raichu, - Sandshrew, - Sandslash, - NidoranF, - Nidorina, - Nidoqueen, - NidoranM, - Nidorino, - Nidoking, - Clefairy, - Clefable, - Vulpix, - Ninetales, - Jigglypuff, - Wigglytuff, - Zubat, - Golbat, - Oddish, - Gloom, - Vileplume, - Paras, - Parasect, - Venonat, - Venomoth, - Diglett, - Dugtrio, - Meowth, - Persian, - Psyduck, - Golduck, - Mankey, - Primeape, - Growlithe, - Arcanine, - Poliwag, - Poliwhirl, - Poliwrath, - Abra, - Kadabra, - Alakazam, - Machop, - Machoke, - Machamp, - Bellsprout, - Weepinbell, - Victreebel, - Tentacool, - Tentacruel, - Geodude, - Graveler, - Golem, - Ponyta, - Rapidash, - Slowpoke, - Slowbro, - Magnemite, - Magneton, - Farfetchd, - Doduo, - Dodrio, - Seel, - Dewgong, - Grimer, - Muk, - Shellder, - Cloyster, - Gastly, - Haunter, - Gengar, - Onix, - Drowzee, - Hypno, - Krabby, - Kingler, - Voltorb, - Electrode, - Exeggcute, - Exeggutor, - Cubone, - Marowak, - Hitmonlee, - Hitmonchan, - Lickitung, - Koffing, - Weezing, - Rhyhorn, - Rhydon, - Chansey, - Tangela, - Kangaskhan, - Horsea, - Seadra, - Goldeen, - Seaking, - Staryu, - Starmie, - MrMime, - Scyther, - Jynx, - Electabuzz, - Magmar, - Pinsir, - Tauros, - Magikarp, - Gyarados, - Lapras, - Ditto, - Eevee, - Vaporeon, - Jolteon, - Flareon, - Porygon, - Omanyte, - Omastar, - Kabuto, - Kabutops, - Aerodactyl, - Snorlax, - Articuno, - Zapdos, - Moltres, - Dratini, - Dragonair, - Dragonite, - Mewtwo, - Mew, - Chikorita, - Bayleef, - Meganium, - Cyndaquil, - Quilava, - Typhlosion, - Totodile, - Croconaw, - Feraligatr, - Sentret, - Furret, - Hoothoot, - Noctowl, - Ledyba, - Ledian, - Spinarak, - Ariados, - Crobat, - Chinchou, - Lanturn, - Pichu, - Cleffa, - Igglybuff, - Togepi, - Togetic, - Natu, - Xatu, - Mareep, - Flaaffy, - Ampharos, - Bellossom, - Marill, - Azumarill, - Sudowoodo, - Politoed, - Hoppip, - Skiploom, - Jumpluff, - Aipom, - Sunkern, - Sunflora, - Yanma, - Wooper, - Quagsire, - Espeon, - Umbreon, - Murkrow, - Slowking, - Misdreavus, - Unown, - Wobbuffet, - Girafarig, - Pineco, - Forretress, - Dunsparce, - Gligar, - Steelix, - Snubbull, - Granbull, - Qwilfish, - Scizor, - Shuckle, - Heracross, - Sneasel, - Teddiursa, - Ursaring, - Slugma, - Magcargo, - Swinub, - Piloswine, - Corsola, - Remoraid, - Octillery, - Delibird, - Mantine, - Skarmory, - Houndour, - Houndoom, - Kingdra, - Phanpy, - Donphan, - Porygon2, - Stantler, - Smeargle, - Tyrogue, - Hitmontop, - Smoochum, - Elekid, - Magby, - Miltank, - Blissey, - Raikou, - Entei, - Suicune, - Larvitar, - Pupitar, - Tyranitar, - Lugia, - HoOh, - Celebi, - Treecko, - Grovyle, - Sceptile, - Torchic, - Combusken, - Blaziken, - Mudkip, - Marshtomp, - Swampert, - Poochyena, - Mightyena, - Zigzagoon, - Linoone, - Wurmple, - Silcoon, - Beautifly, - Cascoon, - Dustox, - Lotad, - Lombre, - Ludicolo, - Seedot, - Nuzleaf, - Shiftry, - Taillow, - Swellow, - Wingull, - Pelipper, - Ralts, - Kirlia, - Gardevoir, - Surskit, - Masquerain, - Shroomish, - Breloom, - Slakoth, - Vigoroth, - Slaking, - Nincada, - Ninjask, - Shedinja, - Whismur, - Loudred, - Exploud, - Makuhita, - Hariyama, - Azurill, - Nosepass, - Skitty, - Delcatty, - Sableye, - Mawile, - Aron, - Lairon, - Aggron, - Meditite, - Medicham, - Electrike, - Manectric, - Plusle, - Minun, - Volbeat, - Illumise, - Roselia, - Gulpin, - Swalot, - Carvanha, - Sharpedo, - Wailmer, - Wailord, - Numel, - Camerupt, - Torkoal, - Spoink, - Grumpig, - Spinda, - Trapinch, - Vibrava, - Flygon, - Cacnea, - Cacturne, - Swablu, - Altaria, - Zangoose, - Seviper, - Lunatone, - Solrock, - Barboach, - Whiscash, - Corphish, - Crawdaunt, - Baltoy, - Claydol, - Lileep, - Cradily, - Anorith, - Armaldo, - Feebas, - Milotic, - Castform, - Kecleon, - Shuppet, - Banette, - Duskull, - Dusclops, - Tropius, - Chimecho, - Absol, - Wynaut, - Snorunt, - Glalie, - Spheal, - Sealeo, - Walrein, - Clamperl, - Huntail, - Gorebyss, - Relicanth, - Luvdisc, - Bagon, - Shelgon, - Salamence, - Beldum, - Metang, - Metagross, - Regirock, - Regice, - Registeel, - Latias, - Latios, - Kyogre, - Groudon, - Rayquaza, - Jirachi, - Deoxys, - Turtwig, - Grotle, - Torterra, - Chimchar, - Monferno, - Infernape, - Piplup, - Prinplup, - Empoleon, - Starly, - Staravia, - Staraptor, - Bidoof, - Bibarel, - Kricketot, - Kricketune, - Shinx, - Luxio, - Luxray, - Budew, - Roserade, - Cranidos, - Rampardos, - Shieldon, - Bastiodon, - Burmy, - Wormadam, - Mothim, - Combee, - Vespiquen, - Pachirisu, - Buizel, - Floatzel, - Cherubi, - Cherrim, - Shellos, - Gastrodon, - Ambipom, - Drifloon, - Drifblim, - Buneary, - Lopunny, - Mismagius, - Honchkrow, - Glameow, - Purugly, - Chingling, - Stunky, - Skuntank, - Bronzor, - Bronzong, - Bonsly, - MimeJr, - Happiny, - Chatot, - Spiritomb, - Gible, - Gabite, - Garchomp, - Munchlax, - Riolu, - Lucario, - Hippopotas, - Hippowdon, - Skorupi, - Drapion, - Croagunk, - Toxicroak, - Carnivine, - Finneon, - Lumineon, - Mantyke, - Snover, - Abomasnow, - Weavile, - Magnezone, - Lickilicky, - Rhyperior, - Tangrowth, - Electivire, - Magmortar, - Togekiss, - Yanmega, - Leafeon, - Glaceon, - Gliscor, - Mamoswine, - PorygonZ, - Gallade, - Probopass, - Dusknoir, - Froslass, - Rotom, - Uxie, - Mesprit, - Azelf, - Dialga, - Palkia, - Heatran, - Regigigas, - Giratina, - Cresselia, - Phione, - Manaphy, - Darkrai, - Shaymin, - Arceus, - Victini, - Snivy, - Servine, - Serperior, - Tepig, - Pignite, - Emboar, - Oshawott, - Dewott, - Samurott, - Patrat, - Watchog, - Lillipup, - Herdier, - Stoutland, - Purrloin, - Liepard, - Pansage, - Simisage, - Pansear, - Simisear, - Panpour, - Simipour, - Munna, - Musharna, - Pidove, - Tranquill, - Unfezant, - Blitzle, - Zebstrika, - Roggenrola, - Boldore, - Gigalith, - Woobat, - Swoobat, - Drilbur, - Excadrill, - Audino, - Timburr, - Gurdurr, - Conkeldurr, - Tympole, - Palpitoad, - Seismitoad, - Throh, - Sawk, - Sewaddle, - Swadloon, - Leavanny, - Venipede, - Whirlipede, - Scolipede, - Cottonee, - Whimsicott, - Petilil, - Lilligant, - Basculin, - Sandile, - Krokorok, - Krookodile, - Darumaka, - Darmanitan, - Maractus, - Dwebble, - Crustle, - Scraggy, - Scrafty, - Sigilyph, - Yamask, - Cofagrigus, - Tirtouga, - Carracosta, - Archen, - Archeops, - Trubbish, - Garbodor, - Zorua, - Zoroark, - Minccino, - Cinccino, - Gothita, - Gothorita, - Gothitelle, - Solosis, - Duosion, - Reuniclus, - Ducklett, - Swanna, - Vanillite, - Vanillish, - Vanilluxe, - Deerling, - Sawsbuck, - Emolga, - Karrablast, - Escavalier, - Foongus, - Amoonguss, - Frillish, - Jellicent, - Alomomola, - Joltik, - Galvantula, - Ferroseed, - Ferrothorn, - Klink, - Klang, - Klinklang, - Tynamo, - Eelektrik, - Eelektross, - Elgyem, - Beheeyem, - Litwick, - Lampent, - Chandelure, - Axew, - Fraxure, - Haxorus, - Cubchoo, - Beartic, - Cryogonal, - Shelmet, - Accelgor, - Stunfisk, - Mienfoo, - Mienshao, - Druddigon, - Golett, - Golurk, - Pawniard, - Bisharp, - Bouffalant, - Rufflet, - Braviary, - Vullaby, - Mandibuzz, - Heatmor, - Durant, - Deino, - Zweilous, - Hydreigon, - Larvesta, - Volcarona, - Cobalion, - Terrakion, - Virizion, - Tornadus, - Thundurus, - Reshiram, - Zekrom, - Landorus, - Kyurem, - Keldeo, - Meloetta, - Genesect, - Chespin, - Quilladin, - Chesnaught, - Fennekin, - Braixen, - Delphox, - Froakie, - Frogadier, - Greninja, - Bunnelby, - Diggersby, - Fletchling, - Fletchinder, - Talonflame, - Scatterbug, - Spewpa, - Vivillon, - Litleo, - Pyroar, - Flabébé, - Floette, - Florges, - Skiddo, - Gogoat, - Pancham, - Pangoro, - Furfrou, - Espurr, - Meowstic, - Honedge, - Doublade, - Aegislash, - Spritzee, - Aromatisse, - Swirlix, - Slurpuff, - Inkay, - Malamar, - Binacle, - Barbaracle, - Skrelp, - Dragalge, - Clauncher, - Clawitzer, - Helioptile, - Heliolisk, - Tyrunt, - Tyrantrum, - Amaura, - Aurorus, - Sylveon, - Hawlucha, - Dedenne, - Carbink, - Goomy, - Sliggoo, - Goodra, - Klefki, - Phantump, - Trevenant, - Pumpkaboo, - Gourgeist, - Bergmite, - Avalugg, - Noibat, - Noivern, - Xerneas, - Yveltal, - Zygarde, - Diancie, - Hoopa, - Volcanion, - Rowlet, - Dartrix, - Decidueye, - Litten, - Torracat, - Incineroar, - Popplio, - Brionne, - Primarina, - Pikipek, - Trumbeak, - Toucannon, - Yungoos, - Gumshoos, - Grubbin, - Charjabug, - Vikavolt, - Crabrawler, - Crabominable, - Oricorio, - Cutiefly, - Ribombee, - Rockruff, - Lycanroc, - Wishiwashi, - Mareanie, - Toxapex, - Mudbray, - Mudsdale, - Dewpider, - Araquanid, - Fomantis, - Lurantis, - Morelull, - Shiinotic, - Salandit, - Salazzle, - Stufful, - Bewear, - Bounsweet, - Steenee, - Tsareena, - Comfey, - Oranguru, - Passimian, - Wimpod, - Golisopod, - Sandygast, - Palossand, - Pyukumuku, - TypeNull, - Silvally, - Minior, - Komala, - Turtonator, - Togedemaru, - Mimikyu, - Bruxish, - Drampa, - Dhelmise, - Jangmoo, - Hakamoo, - Kommoo, - TapuKoko, - TapuLele, - TapuBulu, - TapuFini, - Cosmog, - Cosmoem, - Solgaleo, - Lunala, - Nihilego, - Buzzwole, - Pheromosa, - Xurkitree, - Celesteela, - Kartana, - Guzzlord, - Necrozma, - Magearna, - Marshadow, - Poipole, - Naganadel, - Stakataka, - Blacephalon, - Zeraora, - Meltan, - Melmetal, - Grookey, - Thwackey, - Rillaboom, - Scorbunny, - Raboot, - Cinderace, - Sobble, - Drizzile, - Inteleon, - Skwovet, - Greedent, - Rookidee, - Corvisquire, - Corviknight, - Blipbug, - Dottler, - Orbeetle, - Nickit, - Thievul, - Gossifleur, - Eldegoss, - Wooloo, - Dubwool, - Chewtle, - Drednaw, - Yamper, - Boltund, - Rolycoly, - Carkol, - Coalossal, - Applin, - Flapple, - Appletun, - Silicobra, - Sandaconda, - Cramorant, - Arrokuda, - Barraskewda, - Toxel, - Toxtricity, - Sizzlipede, - Centiskorch, - Clobbopus, - Grapploct, - Sinistea, - Polteageist, - Hatenna, - Hattrem, - Hatterene, - Impidimp, - Morgrem, - Grimmsnarl, - Obstagoon, - Perrserker, - Cursola, - Sirfetchd, - MrRime, - Runerigus, - Milcery, - Alcremie, - Falinks, - Pincurchin, - Snom, - Frosmoth, - Stonjourner, - Eiscue, - Indeedee, - Morpeko, - Cufant, - Copperajah, - Dracozolt, - Arctozolt, - Dracovish, - Arctovish, - Duraludon, - Dreepy, - Drakloak, - Dragapult, - Zacian, - Zamazenta, - Eternatus, - Kubfu, - Urshifu, - Zarude, - Regieleki, - Regidrago, - Glastrier, - Spectrier, - Calyrex, - Wyrdeer, - Kleavor, - Ursaluna, - Basculegion, - Sneasler, - Overqwil, - Enamorus, - MAX_COUNT, - } + None, + Bulbasaur, + Ivysaur, + Venusaur, + Charmander, + Charmeleon, + Charizard, + Squirtle, + Wartortle, + Blastoise, + Caterpie, + Metapod, + Butterfree, + Weedle, + Kakuna, + Beedrill, + Pidgey, + Pidgeotto, + Pidgeot, + Rattata, + Raticate, + Spearow, + Fearow, + Ekans, + Arbok, + Pikachu, + Raichu, + Sandshrew, + Sandslash, + NidoranF, + Nidorina, + Nidoqueen, + NidoranM, + Nidorino, + Nidoking, + Clefairy, + Clefable, + Vulpix, + Ninetales, + Jigglypuff, + Wigglytuff, + Zubat, + Golbat, + Oddish, + Gloom, + Vileplume, + Paras, + Parasect, + Venonat, + Venomoth, + Diglett, + Dugtrio, + Meowth, + Persian, + Psyduck, + Golduck, + Mankey, + Primeape, + Growlithe, + Arcanine, + Poliwag, + Poliwhirl, + Poliwrath, + Abra, + Kadabra, + Alakazam, + Machop, + Machoke, + Machamp, + Bellsprout, + Weepinbell, + Victreebel, + Tentacool, + Tentacruel, + Geodude, + Graveler, + Golem, + Ponyta, + Rapidash, + Slowpoke, + Slowbro, + Magnemite, + Magneton, + Farfetchd, + Doduo, + Dodrio, + Seel, + Dewgong, + Grimer, + Muk, + Shellder, + Cloyster, + Gastly, + Haunter, + Gengar, + Onix, + Drowzee, + Hypno, + Krabby, + Kingler, + Voltorb, + Electrode, + Exeggcute, + Exeggutor, + Cubone, + Marowak, + Hitmonlee, + Hitmonchan, + Lickitung, + Koffing, + Weezing, + Rhyhorn, + Rhydon, + Chansey, + Tangela, + Kangaskhan, + Horsea, + Seadra, + Goldeen, + Seaking, + Staryu, + Starmie, + MrMime, + Scyther, + Jynx, + Electabuzz, + Magmar, + Pinsir, + Tauros, + Magikarp, + Gyarados, + Lapras, + Ditto, + Eevee, + Vaporeon, + Jolteon, + Flareon, + Porygon, + Omanyte, + Omastar, + Kabuto, + Kabutops, + Aerodactyl, + Snorlax, + Articuno, + Zapdos, + Moltres, + Dratini, + Dragonair, + Dragonite, + Mewtwo, + Mew, + Chikorita, + Bayleef, + Meganium, + Cyndaquil, + Quilava, + Typhlosion, + Totodile, + Croconaw, + Feraligatr, + Sentret, + Furret, + Hoothoot, + Noctowl, + Ledyba, + Ledian, + Spinarak, + Ariados, + Crobat, + Chinchou, + Lanturn, + Pichu, + Cleffa, + Igglybuff, + Togepi, + Togetic, + Natu, + Xatu, + Mareep, + Flaaffy, + Ampharos, + Bellossom, + Marill, + Azumarill, + Sudowoodo, + Politoed, + Hoppip, + Skiploom, + Jumpluff, + Aipom, + Sunkern, + Sunflora, + Yanma, + Wooper, + Quagsire, + Espeon, + Umbreon, + Murkrow, + Slowking, + Misdreavus, + Unown, + Wobbuffet, + Girafarig, + Pineco, + Forretress, + Dunsparce, + Gligar, + Steelix, + Snubbull, + Granbull, + Qwilfish, + Scizor, + Shuckle, + Heracross, + Sneasel, + Teddiursa, + Ursaring, + Slugma, + Magcargo, + Swinub, + Piloswine, + Corsola, + Remoraid, + Octillery, + Delibird, + Mantine, + Skarmory, + Houndour, + Houndoom, + Kingdra, + Phanpy, + Donphan, + Porygon2, + Stantler, + Smeargle, + Tyrogue, + Hitmontop, + Smoochum, + Elekid, + Magby, + Miltank, + Blissey, + Raikou, + Entei, + Suicune, + Larvitar, + Pupitar, + Tyranitar, + Lugia, + HoOh, + Celebi, + Treecko, + Grovyle, + Sceptile, + Torchic, + Combusken, + Blaziken, + Mudkip, + Marshtomp, + Swampert, + Poochyena, + Mightyena, + Zigzagoon, + Linoone, + Wurmple, + Silcoon, + Beautifly, + Cascoon, + Dustox, + Lotad, + Lombre, + Ludicolo, + Seedot, + Nuzleaf, + Shiftry, + Taillow, + Swellow, + Wingull, + Pelipper, + Ralts, + Kirlia, + Gardevoir, + Surskit, + Masquerain, + Shroomish, + Breloom, + Slakoth, + Vigoroth, + Slaking, + Nincada, + Ninjask, + Shedinja, + Whismur, + Loudred, + Exploud, + Makuhita, + Hariyama, + Azurill, + Nosepass, + Skitty, + Delcatty, + Sableye, + Mawile, + Aron, + Lairon, + Aggron, + Meditite, + Medicham, + Electrike, + Manectric, + Plusle, + Minun, + Volbeat, + Illumise, + Roselia, + Gulpin, + Swalot, + Carvanha, + Sharpedo, + Wailmer, + Wailord, + Numel, + Camerupt, + Torkoal, + Spoink, + Grumpig, + Spinda, + Trapinch, + Vibrava, + Flygon, + Cacnea, + Cacturne, + Swablu, + Altaria, + Zangoose, + Seviper, + Lunatone, + Solrock, + Barboach, + Whiscash, + Corphish, + Crawdaunt, + Baltoy, + Claydol, + Lileep, + Cradily, + Anorith, + Armaldo, + Feebas, + Milotic, + Castform, + Kecleon, + Shuppet, + Banette, + Duskull, + Dusclops, + Tropius, + Chimecho, + Absol, + Wynaut, + Snorunt, + Glalie, + Spheal, + Sealeo, + Walrein, + Clamperl, + Huntail, + Gorebyss, + Relicanth, + Luvdisc, + Bagon, + Shelgon, + Salamence, + Beldum, + Metang, + Metagross, + Regirock, + Regice, + Registeel, + Latias, + Latios, + Kyogre, + Groudon, + Rayquaza, + Jirachi, + Deoxys, + Turtwig, + Grotle, + Torterra, + Chimchar, + Monferno, + Infernape, + Piplup, + Prinplup, + Empoleon, + Starly, + Staravia, + Staraptor, + Bidoof, + Bibarel, + Kricketot, + Kricketune, + Shinx, + Luxio, + Luxray, + Budew, + Roserade, + Cranidos, + Rampardos, + Shieldon, + Bastiodon, + Burmy, + Wormadam, + Mothim, + Combee, + Vespiquen, + Pachirisu, + Buizel, + Floatzel, + Cherubi, + Cherrim, + Shellos, + Gastrodon, + Ambipom, + Drifloon, + Drifblim, + Buneary, + Lopunny, + Mismagius, + Honchkrow, + Glameow, + Purugly, + Chingling, + Stunky, + Skuntank, + Bronzor, + Bronzong, + Bonsly, + MimeJr, + Happiny, + Chatot, + Spiritomb, + Gible, + Gabite, + Garchomp, + Munchlax, + Riolu, + Lucario, + Hippopotas, + Hippowdon, + Skorupi, + Drapion, + Croagunk, + Toxicroak, + Carnivine, + Finneon, + Lumineon, + Mantyke, + Snover, + Abomasnow, + Weavile, + Magnezone, + Lickilicky, + Rhyperior, + Tangrowth, + Electivire, + Magmortar, + Togekiss, + Yanmega, + Leafeon, + Glaceon, + Gliscor, + Mamoswine, + PorygonZ, + Gallade, + Probopass, + Dusknoir, + Froslass, + Rotom, + Uxie, + Mesprit, + Azelf, + Dialga, + Palkia, + Heatran, + Regigigas, + Giratina, + Cresselia, + Phione, + Manaphy, + Darkrai, + Shaymin, + Arceus, + Victini, + Snivy, + Servine, + Serperior, + Tepig, + Pignite, + Emboar, + Oshawott, + Dewott, + Samurott, + Patrat, + Watchog, + Lillipup, + Herdier, + Stoutland, + Purrloin, + Liepard, + Pansage, + Simisage, + Pansear, + Simisear, + Panpour, + Simipour, + Munna, + Musharna, + Pidove, + Tranquill, + Unfezant, + Blitzle, + Zebstrika, + Roggenrola, + Boldore, + Gigalith, + Woobat, + Swoobat, + Drilbur, + Excadrill, + Audino, + Timburr, + Gurdurr, + Conkeldurr, + Tympole, + Palpitoad, + Seismitoad, + Throh, + Sawk, + Sewaddle, + Swadloon, + Leavanny, + Venipede, + Whirlipede, + Scolipede, + Cottonee, + Whimsicott, + Petilil, + Lilligant, + Basculin, + Sandile, + Krokorok, + Krookodile, + Darumaka, + Darmanitan, + Maractus, + Dwebble, + Crustle, + Scraggy, + Scrafty, + Sigilyph, + Yamask, + Cofagrigus, + Tirtouga, + Carracosta, + Archen, + Archeops, + Trubbish, + Garbodor, + Zorua, + Zoroark, + Minccino, + Cinccino, + Gothita, + Gothorita, + Gothitelle, + Solosis, + Duosion, + Reuniclus, + Ducklett, + Swanna, + Vanillite, + Vanillish, + Vanilluxe, + Deerling, + Sawsbuck, + Emolga, + Karrablast, + Escavalier, + Foongus, + Amoonguss, + Frillish, + Jellicent, + Alomomola, + Joltik, + Galvantula, + Ferroseed, + Ferrothorn, + Klink, + Klang, + Klinklang, + Tynamo, + Eelektrik, + Eelektross, + Elgyem, + Beheeyem, + Litwick, + Lampent, + Chandelure, + Axew, + Fraxure, + Haxorus, + Cubchoo, + Beartic, + Cryogonal, + Shelmet, + Accelgor, + Stunfisk, + Mienfoo, + Mienshao, + Druddigon, + Golett, + Golurk, + Pawniard, + Bisharp, + Bouffalant, + Rufflet, + Braviary, + Vullaby, + Mandibuzz, + Heatmor, + Durant, + Deino, + Zweilous, + Hydreigon, + Larvesta, + Volcarona, + Cobalion, + Terrakion, + Virizion, + Tornadus, + Thundurus, + Reshiram, + Zekrom, + Landorus, + Kyurem, + Keldeo, + Meloetta, + Genesect, + Chespin, + Quilladin, + Chesnaught, + Fennekin, + Braixen, + Delphox, + Froakie, + Frogadier, + Greninja, + Bunnelby, + Diggersby, + Fletchling, + Fletchinder, + Talonflame, + Scatterbug, + Spewpa, + Vivillon, + Litleo, + Pyroar, + Flabébé, + Floette, + Florges, + Skiddo, + Gogoat, + Pancham, + Pangoro, + Furfrou, + Espurr, + Meowstic, + Honedge, + Doublade, + Aegislash, + Spritzee, + Aromatisse, + Swirlix, + Slurpuff, + Inkay, + Malamar, + Binacle, + Barbaracle, + Skrelp, + Dragalge, + Clauncher, + Clawitzer, + Helioptile, + Heliolisk, + Tyrunt, + Tyrantrum, + Amaura, + Aurorus, + Sylveon, + Hawlucha, + Dedenne, + Carbink, + Goomy, + Sliggoo, + Goodra, + Klefki, + Phantump, + Trevenant, + Pumpkaboo, + Gourgeist, + Bergmite, + Avalugg, + Noibat, + Noivern, + Xerneas, + Yveltal, + Zygarde, + Diancie, + Hoopa, + Volcanion, + Rowlet, + Dartrix, + Decidueye, + Litten, + Torracat, + Incineroar, + Popplio, + Brionne, + Primarina, + Pikipek, + Trumbeak, + Toucannon, + Yungoos, + Gumshoos, + Grubbin, + Charjabug, + Vikavolt, + Crabrawler, + Crabominable, + Oricorio, + Cutiefly, + Ribombee, + Rockruff, + Lycanroc, + Wishiwashi, + Mareanie, + Toxapex, + Mudbray, + Mudsdale, + Dewpider, + Araquanid, + Fomantis, + Lurantis, + Morelull, + Shiinotic, + Salandit, + Salazzle, + Stufful, + Bewear, + Bounsweet, + Steenee, + Tsareena, + Comfey, + Oranguru, + Passimian, + Wimpod, + Golisopod, + Sandygast, + Palossand, + Pyukumuku, + TypeNull, + Silvally, + Minior, + Komala, + Turtonator, + Togedemaru, + Mimikyu, + Bruxish, + Drampa, + Dhelmise, + Jangmoo, + Hakamoo, + Kommoo, + TapuKoko, + TapuLele, + TapuBulu, + TapuFini, + Cosmog, + Cosmoem, + Solgaleo, + Lunala, + Nihilego, + Buzzwole, + Pheromosa, + Xurkitree, + Celesteela, + Kartana, + Guzzlord, + Necrozma, + Magearna, + Marshadow, + Poipole, + Naganadel, + Stakataka, + Blacephalon, + Zeraora, + Meltan, + Melmetal, + Grookey, + Thwackey, + Rillaboom, + Scorbunny, + Raboot, + Cinderace, + Sobble, + Drizzile, + Inteleon, + Skwovet, + Greedent, + Rookidee, + Corvisquire, + Corviknight, + Blipbug, + Dottler, + Orbeetle, + Nickit, + Thievul, + Gossifleur, + Eldegoss, + Wooloo, + Dubwool, + Chewtle, + Drednaw, + Yamper, + Boltund, + Rolycoly, + Carkol, + Coalossal, + Applin, + Flapple, + Appletun, + Silicobra, + Sandaconda, + Cramorant, + Arrokuda, + Barraskewda, + Toxel, + Toxtricity, + Sizzlipede, + Centiskorch, + Clobbopus, + Grapploct, + Sinistea, + Polteageist, + Hatenna, + Hattrem, + Hatterene, + Impidimp, + Morgrem, + Grimmsnarl, + Obstagoon, + Perrserker, + Cursola, + Sirfetchd, + MrRime, + Runerigus, + Milcery, + Alcremie, + Falinks, + Pincurchin, + Snom, + Frosmoth, + Stonjourner, + Eiscue, + Indeedee, + Morpeko, + Cufant, + Copperajah, + Dracozolt, + Arctozolt, + Dracovish, + Arctovish, + Duraludon, + Dreepy, + Drakloak, + Dragapult, + Zacian, + Zamazenta, + Eternatus, + Kubfu, + Urshifu, + Zarude, + Regieleki, + Regidrago, + Glastrier, + Spectrier, + Calyrex, + Wyrdeer, + Kleavor, + Ursaluna, + Basculegion, + Sneasler, + Overqwil, + Enamorus, + MAX_COUNT, } diff --git a/pkNX.Structures/Misc/TypeEffectiveness.cs b/pkNX.Structures/Misc/TypeEffectiveness.cs index 5913ce9d..daf5dd01 100644 --- a/pkNX.Structures/Misc/TypeEffectiveness.cs +++ b/pkNX.Structures/Misc/TypeEffectiveness.cs @@ -1,12 +1,10 @@ -namespace pkNX.Structures -{ +namespace pkNX.Structures; #pragma warning disable CA1027 // Mark enums with FlagsAttribute - public enum TypeEffectiveness : byte +public enum TypeEffectiveness : byte #pragma warning restore CA1027 // Mark enums with FlagsAttribute - { - Immune = 0, - NotVery = 2, - Normal = 4, - Super = 8, - } +{ + Immune = 0, + NotVery = 2, + Normal = 4, + Super = 8, } diff --git a/pkNX.Structures/Misc/Types.cs b/pkNX.Structures/Misc/Types.cs index 4eb8ca8d..43353d28 100644 --- a/pkNX.Structures/Misc/Types.cs +++ b/pkNX.Structures/Misc/Types.cs @@ -1,24 +1,23 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum Types : byte { - public enum Types : byte - { - Normal, - Fighting, - Flying, - Poison, - Ground, - Rock, - Bug, - Ghost, - Steel, - Fire, - Water, - Grass, - Electric, - Psychic, - Ice, - Dragon, - Dark, - Fairy, - } + Normal, + Fighting, + Flying, + Poison, + Ground, + Rock, + Bug, + Ghost, + Steel, + Fire, + Water, + Grass, + Electric, + Psychic, + Ice, + Dragon, + Dark, + Fairy, } diff --git a/pkNX.Structures/Move/Move.cs b/pkNX.Structures/Move/Move.cs index f519d629..7c5f5fe8 100644 --- a/pkNX.Structures/Move/Move.cs +++ b/pkNX.Structures/Move/Move.cs @@ -1,76 +1,75 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class Move3DS : IMove { - public abstract class Move3DS : IMove - { - protected readonly byte[] Data; - protected abstract int SIZE { get; } - protected Move3DS(byte[] data = null) => Data = data ?? new byte[SIZE]; + protected readonly byte[] Data; + protected abstract int SIZE { get; } + protected Move3DS(byte[] data = null) => Data = data ?? new byte[SIZE]; - public byte[] Write() => Data; + public byte[] Write() => Data; - public abstract int Type { get; set; } - public abstract int Quality { get; set; } - public abstract int Category { get; set; } - public abstract int Power { get; set; } - public abstract int Accuracy { get; set; } - public abstract int PP { get; set; } - public abstract int Priority { get; set; } - public abstract int HitMin { get; set; } - public abstract int HitMax { get; set; } - public abstract int Inflict { get; set; } - public abstract int InflictPercent { get; set; } - public abstract MoveInflictDuration InflictCount { get; set; } - public abstract int TurnMin { get; set; } - public abstract int TurnMax { get; set; } - public abstract int CritStage { get; set; } - public abstract int Flinch { get; set; } - public abstract int EffectSequence { get; set; } - public abstract int Recoil { get; set; } - public abstract Heal Healing { get; set; } - public abstract MoveTarget Target { get; set; } - public abstract int Stat1 { get; set; } - public abstract int Stat2 { get; set; } - public abstract int Stat3 { get; set; } - public abstract int Stat1Stage { get; set; } - public abstract int Stat2Stage { get; set; } - public abstract int Stat3Stage { get; set; } - public abstract int Stat1Percent { get; set; } - public abstract int Stat2Percent { get; set; } - public abstract int Stat3Percent { get; set; } - } + public abstract int Type { get; set; } + public abstract int Quality { get; set; } + public abstract int Category { get; set; } + public abstract int Power { get; set; } + public abstract int Accuracy { get; set; } + public abstract int PP { get; set; } + public abstract int Priority { get; set; } + public abstract int HitMin { get; set; } + public abstract int HitMax { get; set; } + public abstract int Inflict { get; set; } + public abstract int InflictPercent { get; set; } + public abstract MoveInflictDuration InflictCount { get; set; } + public abstract int TurnMin { get; set; } + public abstract int TurnMax { get; set; } + public abstract int CritStage { get; set; } + public abstract int Flinch { get; set; } + public abstract int EffectSequence { get; set; } + public abstract int Recoil { get; set; } + public abstract Heal Healing { get; set; } + public abstract MoveTarget Target { get; set; } + public abstract int Stat1 { get; set; } + public abstract int Stat2 { get; set; } + public abstract int Stat3 { get; set; } + public abstract int Stat1Stage { get; set; } + public abstract int Stat2Stage { get; set; } + public abstract int Stat3Stage { get; set; } + public abstract int Stat1Percent { get; set; } + public abstract int Stat2Percent { get; set; } + public abstract int Stat3Percent { get; set; } +} - public interface IMove - { - byte[] Write(); +public interface IMove +{ + byte[] Write(); - public int Type { get; set; } - public int Quality { get; set; } - public int Category { get; set; } - public int Power { get; set; } - public int Accuracy { get; set; } - public int PP { get; set; } - public int Priority { get; set; } - public int HitMin { get; set; } - public int HitMax { get; set; } - public int Inflict { get; set; } - public int InflictPercent { get; set; } - public MoveInflictDuration InflictCount { get; set; } - public int TurnMin { get; set; } - public int TurnMax { get; set; } - public int CritStage { get; set; } - public int Flinch { get; set; } - public int EffectSequence { get; set; } - public int Recoil { get; set; } - public Heal Healing { get; set; } - public MoveTarget Target { get; set; } - public int Stat1 { get; set; } - public int Stat2 { get; set; } - public int Stat3 { get; set; } - public int Stat1Stage { get; set; } - public int Stat2Stage { get; set; } - public int Stat3Stage { get; set; } - public int Stat1Percent { get; set; } - public int Stat2Percent { get; set; } - public int Stat3Percent { get; set; } - } -} \ No newline at end of file + public int Type { get; set; } + public int Quality { get; set; } + public int Category { get; set; } + public int Power { get; set; } + public int Accuracy { get; set; } + public int PP { get; set; } + public int Priority { get; set; } + public int HitMin { get; set; } + public int HitMax { get; set; } + public int Inflict { get; set; } + public int InflictPercent { get; set; } + public MoveInflictDuration InflictCount { get; set; } + public int TurnMin { get; set; } + public int TurnMax { get; set; } + public int CritStage { get; set; } + public int Flinch { get; set; } + public int EffectSequence { get; set; } + public int Recoil { get; set; } + public Heal Healing { get; set; } + public MoveTarget Target { get; set; } + public int Stat1 { get; set; } + public int Stat2 { get; set; } + public int Stat3 { get; set; } + public int Stat1Stage { get; set; } + public int Stat2Stage { get; set; } + public int Stat3Stage { get; set; } + public int Stat1Percent { get; set; } + public int Stat2Percent { get; set; } + public int Stat3Percent { get; set; } +} diff --git a/pkNX.Structures/Move/Move6.cs b/pkNX.Structures/Move/Move6.cs index 5c30b9a5..787d0d57 100644 --- a/pkNX.Structures/Move/Move6.cs +++ b/pkNX.Structures/Move/Move6.cs @@ -1,43 +1,42 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Move6 : Move3DS { - public class Move6 : Move3DS - { - protected override int SIZE => 0x22; - public Move6() { } - public Move6(byte[] data = null) : base(data) { } + protected override int SIZE => 0x22; + public Move6() { } + public Move6(byte[] data = null) : base(data) { } - public override int Type { get => Data[0x00]; set => Data[0x00] = (byte)value; } - public override int Quality { get => Data[0x01]; set => Data[0x01] = (byte)value; } - public override int Category { get => Data[0x02]; set => Data[0x02] = (byte)value; } - public override int Power { get => Data[0x03]; set => Data[0x03] = (byte)value; } - public override int Accuracy { get => Data[0x04]; set => Data[0x04] = (byte)value; } - public override int PP { get => Data[0x05]; set => Data[0x05] = (byte)value; } - public override int Priority { get => Data[0x06]; set => Data[0x06] = (byte)value; } - public override int HitMin { get => Data[0x07] & 0xF; set => Data[0x07] = (byte)(HitMax << 4 | value); } - public override int HitMax { get => Data[0x07] >> 4; set => Data[0x07] = (byte)(value << 4 | HitMin); } - public override int Inflict { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } - public override int InflictPercent { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public override MoveInflictDuration InflictCount { get => (MoveInflictDuration)Data[0x0B]; set => Data[0x0B] = (byte)value; } - public override int TurnMin { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } - public override int TurnMax { get => Data[0x0D]; set => Data[0x0D] = (byte)value; } - public override int CritStage { get => Data[0x0E]; set => Data[0x0E] = (byte)value; } - public override int Flinch { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } - public override int EffectSequence { get => BitConverter.ToUInt16(Data, 0x10); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); } - public override int Recoil { get => Data[0x12]; set => Data[0x12] = (byte)value; } - public override Heal Healing { get => (Heal)Data[0x13]; set => Data[0x13] = (byte)value; } - public override MoveTarget Target { get => (MoveTarget)Data[0x14]; set => Data[0x14] = (byte)value; } - public override int Stat1 { get => Data[0x15]; set => Data[0x15] = (byte)value; } - public override int Stat2 { get => Data[0x16]; set => Data[0x16] = (byte)value; } - public override int Stat3 { get => Data[0x17]; set => Data[0x17] = (byte)value; } - public override int Stat1Stage { get => Data[0x18]; set => Data[0x18] = (byte)value; } - public override int Stat2Stage { get => Data[0x19]; set => Data[0x19] = (byte)value; } - public override int Stat3Stage { get => Data[0x1A]; set => Data[0x1A] = (byte)value; } - public override int Stat1Percent { get => Data[0x1B]; set => Data[0x1B] = (byte)value; } - public override int Stat2Percent { get => Data[0x1C]; set => Data[0x1C] = (byte)value; } - public override int Stat3Percent { get => Data[0x1D]; set => Data[0x1D] = (byte)value; } + public override int Type { get => Data[0x00]; set => Data[0x00] = (byte)value; } + public override int Quality { get => Data[0x01]; set => Data[0x01] = (byte)value; } + public override int Category { get => Data[0x02]; set => Data[0x02] = (byte)value; } + public override int Power { get => Data[0x03]; set => Data[0x03] = (byte)value; } + public override int Accuracy { get => Data[0x04]; set => Data[0x04] = (byte)value; } + public override int PP { get => Data[0x05]; set => Data[0x05] = (byte)value; } + public override int Priority { get => Data[0x06]; set => Data[0x06] = (byte)value; } + public override int HitMin { get => Data[0x07] & 0xF; set => Data[0x07] = (byte)(HitMax << 4 | value); } + public override int HitMax { get => Data[0x07] >> 4; set => Data[0x07] = (byte)(value << 4 | HitMin); } + public override int Inflict { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } + public override int InflictPercent { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public override MoveInflictDuration InflictCount { get => (MoveInflictDuration)Data[0x0B]; set => Data[0x0B] = (byte)value; } + public override int TurnMin { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } + public override int TurnMax { get => Data[0x0D]; set => Data[0x0D] = (byte)value; } + public override int CritStage { get => Data[0x0E]; set => Data[0x0E] = (byte)value; } + public override int Flinch { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } + public override int EffectSequence { get => BitConverter.ToUInt16(Data, 0x10); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); } + public override int Recoil { get => Data[0x12]; set => Data[0x12] = (byte)value; } + public override Heal Healing { get => (Heal)Data[0x13]; set => Data[0x13] = (byte)value; } + public override MoveTarget Target { get => (MoveTarget)Data[0x14]; set => Data[0x14] = (byte)value; } + public override int Stat1 { get => Data[0x15]; set => Data[0x15] = (byte)value; } + public override int Stat2 { get => Data[0x16]; set => Data[0x16] = (byte)value; } + public override int Stat3 { get => Data[0x17]; set => Data[0x17] = (byte)value; } + public override int Stat1Stage { get => Data[0x18]; set => Data[0x18] = (byte)value; } + public override int Stat2Stage { get => Data[0x19]; set => Data[0x19] = (byte)value; } + public override int Stat3Stage { get => Data[0x1A]; set => Data[0x1A] = (byte)value; } + public override int Stat1Percent { get => Data[0x1B]; set => Data[0x1B] = (byte)value; } + public override int Stat2Percent { get => Data[0x1C]; set => Data[0x1C] = (byte)value; } + public override int Stat3Percent { get => Data[0x1D]; set => Data[0x1D] = (byte)value; } - public MoveFlag6 Flags { get => (MoveFlag6)BitConverter.ToUInt32(Data, 0x1E); set => BitConverter.GetBytes((uint)value).CopyTo(Data, 0x1E); } - } + public MoveFlag6 Flags { get => (MoveFlag6)BitConverter.ToUInt32(Data, 0x1E); set => BitConverter.GetBytes((uint)value).CopyTo(Data, 0x1E); } } diff --git a/pkNX.Structures/Move/Move7.cs b/pkNX.Structures/Move/Move7.cs index 10b82a4a..1f55fcf0 100644 --- a/pkNX.Structures/Move/Move7.cs +++ b/pkNX.Structures/Move/Move7.cs @@ -1,57 +1,56 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Move7 : Move3DS { - public class Move7 : Move3DS - { - protected override int SIZE => 0x28; - public Move7() { } - public Move7(byte[] data = null) : base(data) { } + protected override int SIZE => 0x28; + public Move7() { } + public Move7(byte[] data = null) : base(data) { } - public override int Type { get => Data[0x00]; set => Data[0x00] = (byte)value; } - public override int Quality { get => Data[0x01]; set => Data[0x01] = (byte)value; } - public override int Category { get => Data[0x02]; set => Data[0x02] = (byte)value; } - public override int Power { get => Data[0x03]; set => Data[0x03] = (byte)value; } - public override int Accuracy { get => Data[0x04]; set => Data[0x04] = (byte)value; } - public override int PP { get => Data[0x05]; set => Data[0x05] = (byte)value; } - public override int Priority { get => Data[0x06]; set => Data[0x06] = (byte)value; } - public override int HitMin { get => Data[0x07] & 0xF; set => Data[0x07] = (byte)(HitMax << 4 | value); } - public override int HitMax { get => Data[0x07] >> 4; set => Data[0x07] = (byte)(value << 4 | HitMin); } - public override int Inflict { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } - public override int InflictPercent { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public override MoveInflictDuration InflictCount { get => (MoveInflictDuration)Data[0x0B]; set => Data[0x0B] = (byte)value; } - public override int TurnMin { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } - public override int TurnMax { get => Data[0x0D]; set => Data[0x0D] = (byte)value; } - public override int CritStage { get => Data[0x0E]; set => Data[0x0E] = (byte)value; } - public override int Flinch { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } - public override int EffectSequence { get => BitConverter.ToUInt16(Data, 0x10); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); } - public override int Recoil { get => Data[0x12]; set => Data[0x12] = (byte)value; } - public override Heal Healing { get => (Heal)Data[0x13]; set => Data[0x13] = (byte)value; } - public override MoveTarget Target { get => (MoveTarget)Data[0x14]; set => Data[0x14] = (byte)value; } - public override int Stat1 { get => Data[0x15]; set => Data[0x15] = (byte)value; } - public override int Stat2 { get => Data[0x16]; set => Data[0x16] = (byte)value; } - public override int Stat3 { get => Data[0x17]; set => Data[0x17] = (byte)value; } - public override int Stat1Stage { get => Data[0x18]; set => Data[0x18] = (byte)value; } - public override int Stat2Stage { get => Data[0x19]; set => Data[0x19] = (byte)value; } - public override int Stat3Stage { get => Data[0x1A]; set => Data[0x1A] = (byte)value; } - public override int Stat1Percent { get => Data[0x1B]; set => Data[0x1B] = (byte)value; } - public override int Stat2Percent { get => Data[0x1C]; set => Data[0x1C] = (byte)value; } - public override int Stat3Percent { get => Data[0x1D]; set => Data[0x1D] = (byte)value; } + public override int Type { get => Data[0x00]; set => Data[0x00] = (byte)value; } + public override int Quality { get => Data[0x01]; set => Data[0x01] = (byte)value; } + public override int Category { get => Data[0x02]; set => Data[0x02] = (byte)value; } + public override int Power { get => Data[0x03]; set => Data[0x03] = (byte)value; } + public override int Accuracy { get => Data[0x04]; set => Data[0x04] = (byte)value; } + public override int PP { get => Data[0x05]; set => Data[0x05] = (byte)value; } + public override int Priority { get => Data[0x06]; set => Data[0x06] = (byte)value; } + public override int HitMin { get => Data[0x07] & 0xF; set => Data[0x07] = (byte)(HitMax << 4 | value); } + public override int HitMax { get => Data[0x07] >> 4; set => Data[0x07] = (byte)(value << 4 | HitMin); } + public override int Inflict { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } + public override int InflictPercent { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public override MoveInflictDuration InflictCount { get => (MoveInflictDuration)Data[0x0B]; set => Data[0x0B] = (byte)value; } + public override int TurnMin { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } + public override int TurnMax { get => Data[0x0D]; set => Data[0x0D] = (byte)value; } + public override int CritStage { get => Data[0x0E]; set => Data[0x0E] = (byte)value; } + public override int Flinch { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } + public override int EffectSequence { get => BitConverter.ToUInt16(Data, 0x10); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); } + public override int Recoil { get => Data[0x12]; set => Data[0x12] = (byte)value; } + public override Heal Healing { get => (Heal)Data[0x13]; set => Data[0x13] = (byte)value; } + public override MoveTarget Target { get => (MoveTarget)Data[0x14]; set => Data[0x14] = (byte)value; } + public override int Stat1 { get => Data[0x15]; set => Data[0x15] = (byte)value; } + public override int Stat2 { get => Data[0x16]; set => Data[0x16] = (byte)value; } + public override int Stat3 { get => Data[0x17]; set => Data[0x17] = (byte)value; } + public override int Stat1Stage { get => Data[0x18]; set => Data[0x18] = (byte)value; } + public override int Stat2Stage { get => Data[0x19]; set => Data[0x19] = (byte)value; } + public override int Stat3Stage { get => Data[0x1A]; set => Data[0x1A] = (byte)value; } + public override int Stat1Percent { get => Data[0x1B]; set => Data[0x1B] = (byte)value; } + public override int Stat2Percent { get => Data[0x1C]; set => Data[0x1C] = (byte)value; } + public override int Stat3Percent { get => Data[0x1D]; set => Data[0x1D] = (byte)value; } - public int ZMove { get => BitConverter.ToUInt16(Data, 0x1E); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1E); } // 32 - public int ZPower { get => Data[0x20]; set => Data[0x20] = (byte)value; } // 33 - public int ZEffect { get => Data[0x21]; set => Data[0x21] = (byte)value; } // 34 + public int ZMove { get => BitConverter.ToUInt16(Data, 0x1E); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1E); } // 32 + public int ZPower { get => Data[0x20]; set => Data[0x20] = (byte)value; } // 33 + public int ZEffect { get => Data[0x21]; set => Data[0x21] = (byte)value; } // 34 - public RefreshType RefreshAfflictType { get => (RefreshType)Data[0x22]; set => Data[0x22] = (byte)value; } // 35 - public int RefreshAfflictPercent { get => Data[0x23]; set => Data[0x23] = (byte)value; } // 36 + public RefreshType RefreshAfflictType { get => (RefreshType)Data[0x22]; set => Data[0x22] = (byte)value; } // 35 + public int RefreshAfflictPercent { get => Data[0x23]; set => Data[0x23] = (byte)value; } // 36 - public MoveFlag7 Flags { get => (MoveFlag7)BitConverter.ToUInt32(Data, 0x24); set => BitConverter.GetBytes((uint)value).CopyTo(Data, 0x24); } - } - - public class Move8Fake : Move7 - { - public uint Version { get; set; } - public uint MoveID { get; set; } - public bool CanUseMove { get; set; } - } + public MoveFlag7 Flags { get => (MoveFlag7)BitConverter.ToUInt32(Data, 0x24); set => BitConverter.GetBytes((uint)value).CopyTo(Data, 0x24); } +} + +public class Move8Fake : Move7 +{ + public uint Version { get; set; } + public uint MoveID { get; set; } + public bool CanUseMove { get; set; } } diff --git a/pkNX.Structures/Move/MoveFlag6.cs b/pkNX.Structures/Move/MoveFlag6.cs index 813c623a..36fea411 100644 --- a/pkNX.Structures/Move/MoveFlag6.cs +++ b/pkNX.Structures/Move/MoveFlag6.cs @@ -1,46 +1,45 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum MoveFlag6 : uint { - [Flags] - public enum MoveFlag6 : uint - { - None, + None, - MakesContact = 1u << 00, // Makes contact. - Charge = 1u << 01, // The user is unable to make a move between turns. - Recharge = 1u << 02, // If this move is successful, the user must recharge on the following turn and cannot make a move. - Protect = 1u << 03, // Blocked by Detect, Protect, Spiky Shield, and if not a Status move, King's Shield. - Reflectable = 1u << 04, // Bounced back to the original user by Magic Coat or the Magic Bounce Ability. - Snatch = 1u << 05, // Can be stolen from the original user and instead used by another Pokemon using Snatch. - Mirror = 1u << 06, // Can be copied by Mirror Move. - Punch = 1u << 07, // Power is multiplied when used by a Pokemon with the Iron Fist Ability. + MakesContact = 1u << 00, // Makes contact. + Charge = 1u << 01, // The user is unable to make a move between turns. + Recharge = 1u << 02, // If this move is successful, the user must recharge on the following turn and cannot make a move. + Protect = 1u << 03, // Blocked by Detect, Protect, Spiky Shield, and if not a Status move, King's Shield. + Reflectable = 1u << 04, // Bounced back to the original user by Magic Coat or the Magic Bounce Ability. + Snatch = 1u << 05, // Can be stolen from the original user and instead used by another Pokemon using Snatch. + Mirror = 1u << 06, // Can be copied by Mirror Move. + Punch = 1u << 07, // Power is multiplied when used by a Pokemon with the Iron Fist Ability. - Sound = 1u << 08, // Has no effect on Pokemon with the Soundproof Ability. - Gravity = 1u << 09, // Prevented from being executed or selected during Gravity's effect. - Defrost = 1u << 10, // Thaws the user if executed successfully while the user is frozen. - DistanceTriple = 1u << 11, // Can target a Pokemon positioned anywhere in a Triple Battle. - Heal = 1u << 12, // Prevented from being executed or selected during Heal Block's effect. - IgnoreSubstitute = 1u << 13, // Ignores a target's substitute. - FailSkyBattle = 1u << 14, // Prevented from being executed or selected in a Sky Battle. - AnimateAlly = 1u << 15, // Always animate the move when used on an ally. + Sound = 1u << 08, // Has no effect on Pokemon with the Soundproof Ability. + Gravity = 1u << 09, // Prevented from being executed or selected during Gravity's effect. + Defrost = 1u << 10, // Thaws the user if executed successfully while the user is frozen. + DistanceTriple = 1u << 11, // Can target a Pokemon positioned anywhere in a Triple Battle. + Heal = 1u << 12, // Prevented from being executed or selected during Heal Block's effect. + IgnoreSubstitute = 1u << 13, // Ignores a target's substitute. + FailSkyBattle = 1u << 14, // Prevented from being executed or selected in a Sky Battle. + AnimateAlly = 1u << 15, // Always animate the move when used on an ally. - F17 = 1u << 16, // Dancer in future games - F18 = 1u << 17, - F19 = 1u << 18, - F20 = 1u << 19, - F21 = 1u << 20, - F22 = 1u << 21, - F23 = 1u << 22, - F24 = 1u << 23, + F17 = 1u << 16, // Dancer in future games + F18 = 1u << 17, + F19 = 1u << 18, + F20 = 1u << 19, + F21 = 1u << 20, + F22 = 1u << 21, + F23 = 1u << 22, + F24 = 1u << 23, - F25 = 1u << 24, - F26 = 1u << 25, - F27 = 1u << 26, - F28 = 1u << 27, - F29 = 1u << 28, - F30 = 1u << 29, - F31 = 1u << 30, - F32 = 1u << 31, - } -} \ No newline at end of file + F25 = 1u << 24, + F26 = 1u << 25, + F27 = 1u << 26, + F28 = 1u << 27, + F29 = 1u << 28, + F30 = 1u << 29, + F31 = 1u << 30, + F32 = 1u << 31, +} diff --git a/pkNX.Structures/Move/MoveFlag7.cs b/pkNX.Structures/Move/MoveFlag7.cs index 4d8610c4..cd3e3316 100644 --- a/pkNX.Structures/Move/MoveFlag7.cs +++ b/pkNX.Structures/Move/MoveFlag7.cs @@ -1,46 +1,45 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum MoveFlag7 : uint { - [Flags] - public enum MoveFlag7 : uint - { - None, + None, - MakesContact = 1u << 00, // Makes contact. - Charge = 1u << 01, // The user is unable to make a move between turns. - Recharge = 1u << 02, // If this move is successful, the user must recharge on the following turn and cannot make a move. - Protect = 1u << 03, // Blocked by Detect, Protect, Spiky Shield, and if not a Status move, King's Shield. - Reflectable = 1u << 04, // Bounced back to the original user by Magic Coat or the Magic Bounce Ability. - Snatch = 1u << 05, // Can be stolen from the original user and instead used by another Pokemon using Snatch. - Mirror = 1u << 06, // Can be copied by Mirror Move. - Punch = 1u << 07, // Power is multiplied when used by a Pokemon with the Iron Fist Ability. + MakesContact = 1u << 00, // Makes contact. + Charge = 1u << 01, // The user is unable to make a move between turns. + Recharge = 1u << 02, // If this move is successful, the user must recharge on the following turn and cannot make a move. + Protect = 1u << 03, // Blocked by Detect, Protect, Spiky Shield, and if not a Status move, King's Shield. + Reflectable = 1u << 04, // Bounced back to the original user by Magic Coat or the Magic Bounce Ability. + Snatch = 1u << 05, // Can be stolen from the original user and instead used by another Pokemon using Snatch. + Mirror = 1u << 06, // Can be copied by Mirror Move. + Punch = 1u << 07, // Power is multiplied when used by a Pokemon with the Iron Fist Ability. - Sound = 1u << 08, // Has no effect on Pokemon with the Soundproof Ability. - Gravity = 1u << 09, // Prevented from being executed or selected during Gravity's effect. - Defrost = 1u << 10, // Thaws the user if executed successfully while the user is frozen. - DistanceTriple = 1u << 11, // Can target a Pokemon positioned anywhere in a Triple Battle. - Heal = 1u << 12, // Prevented from being executed or selected during Heal Block's effect. - IgnoreSubstitute = 1u << 13, // Ignores a target's substitute. - FailSkyBattle = 1u << 14, // Prevented from being executed or selected in a Sky Battle. - AnimateAlly = 1u << 15, // Always animate the move when used on an ally. + Sound = 1u << 08, // Has no effect on Pokemon with the Soundproof Ability. + Gravity = 1u << 09, // Prevented from being executed or selected during Gravity's effect. + Defrost = 1u << 10, // Thaws the user if executed successfully while the user is frozen. + DistanceTriple = 1u << 11, // Can target a Pokemon positioned anywhere in a Triple Battle. + Heal = 1u << 12, // Prevented from being executed or selected during Heal Block's effect. + IgnoreSubstitute = 1u << 13, // Ignores a target's substitute. + FailSkyBattle = 1u << 14, // Prevented from being executed or selected in a Sky Battle. + AnimateAlly = 1u << 15, // Always animate the move when used on an ally. - Dance = 1u << 16, // When used by a Pokemon, other Pokemon with the Dancer Ability can attempt to execute the same move. - F18 = 1u << 17, - F19 = 1u << 18, - F20 = 1u << 19, - F21 = 1u << 20, - F22 = 1u << 21, - F23 = 1u << 22, - F24 = 1u << 23, + Dance = 1u << 16, // When used by a Pokemon, other Pokemon with the Dancer Ability can attempt to execute the same move. + F18 = 1u << 17, + F19 = 1u << 18, + F20 = 1u << 19, + F21 = 1u << 20, + F22 = 1u << 21, + F23 = 1u << 22, + F24 = 1u << 23, - F25 = 1u << 24, - F26 = 1u << 25, - F27 = 1u << 26, - F28 = 1u << 27, - F29 = 1u << 28, - F30 = 1u << 29, - F31 = 1u << 30, - F32 = 1u << 31, - } -} \ No newline at end of file + F25 = 1u << 24, + F26 = 1u << 25, + F27 = 1u << 26, + F28 = 1u << 27, + F29 = 1u << 28, + F30 = 1u << 29, + F31 = 1u << 30, + F32 = 1u << 31, +} diff --git a/pkNX.Structures/Move/MoveFlagExtensions.cs b/pkNX.Structures/Move/MoveFlagExtensions.cs index e9d2f1d3..9599dd3a 100644 --- a/pkNX.Structures/Move/MoveFlagExtensions.cs +++ b/pkNX.Structures/Move/MoveFlagExtensions.cs @@ -1,15 +1,14 @@ -namespace pkNX.Structures -{ - public static class MoveFlagExtensions - { - public static bool HasFlagFast(this MoveFlag6 value, MoveFlag6 flag) - { - return (value & flag) != 0; - } +namespace pkNX.Structures; - public static bool HasFlagFast(this MoveFlag7 value, MoveFlag7 flag) - { - return (value & flag) != 0; - } +public static class MoveFlagExtensions +{ + public static bool HasFlagFast(this MoveFlag6 value, MoveFlag6 flag) + { + return (value & flag) != 0; } -} \ No newline at end of file + + public static bool HasFlagFast(this MoveFlag7 value, MoveFlag7 flag) + { + return (value & flag) != 0; + } +} diff --git a/pkNX.Structures/Move/MoveInflictDuration.cs b/pkNX.Structures/Move/MoveInflictDuration.cs index 316e2c98..9c944240 100644 --- a/pkNX.Structures/Move/MoveInflictDuration.cs +++ b/pkNX.Structures/Move/MoveInflictDuration.cs @@ -1,4 +1,4 @@ -namespace pkNX.Structures; +namespace pkNX.Structures; public enum MoveInflictDuration { diff --git a/pkNX.Structures/Move/MoveTarget.cs b/pkNX.Structures/Move/MoveTarget.cs index 1330b603..497e8f23 100644 --- a/pkNX.Structures/Move/MoveTarget.cs +++ b/pkNX.Structures/Move/MoveTarget.cs @@ -1,23 +1,22 @@ -namespace pkNX.Structures -{ - public enum MoveTarget : byte - { - // Specific target - AnyExceptSelf, - AllyOrSelf, - Ally, - Opponent, - AllAdjacent, - AllAdjacentOpponents, - AllAllies, - Self, - All, - RandomOpponent, +namespace pkNX.Structures; - // No pkm target - SideAll, - SideOpponent, - SideSelf, - Counter, - } -} \ No newline at end of file +public enum MoveTarget : byte +{ + // Specific target + AnyExceptSelf, + AllyOrSelf, + Ally, + Opponent, + AllAdjacent, + AllAdjacentOpponents, + AllAllies, + Self, + All, + RandomOpponent, + + // No pkm target + SideAll, + SideOpponent, + SideSelf, + Counter, +} diff --git a/pkNX.Structures/Move/RefreshType.cs b/pkNX.Structures/Move/RefreshType.cs index f11ae531..4cc16269 100644 --- a/pkNX.Structures/Move/RefreshType.cs +++ b/pkNX.Structures/Move/RefreshType.cs @@ -1,11 +1,10 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum RefreshType : byte { - public enum RefreshType : byte - { - None, - Disheveled, - Mud, - Dust, - Dry, - } -} \ No newline at end of file + None, + Disheveled, + Mud, + Dust, + Dry, +} diff --git a/pkNX.Structures/Personal/EXPGroup.cs b/pkNX.Structures/Personal/EXPGroup.cs index a6245f72..774aa0fd 100644 --- a/pkNX.Structures/Personal/EXPGroup.cs +++ b/pkNX.Structures/Personal/EXPGroup.cs @@ -1,12 +1,11 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum EXPGroup { - public enum EXPGroup - { - MediumFast, - Erratic, - Fluctuating, - MediumSlow, - Fast, - Slow, - } -} \ No newline at end of file + MediumFast, + Erratic, + Fluctuating, + MediumSlow, + Fast, + Slow, +} diff --git a/pkNX.Structures/Personal/EggGroup.cs b/pkNX.Structures/Personal/EggGroup.cs index 0ae5e628..5e2ff359 100644 --- a/pkNX.Structures/Personal/EggGroup.cs +++ b/pkNX.Structures/Personal/EggGroup.cs @@ -1,22 +1,21 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum EggGroup { - public enum EggGroup - { - None, - Monster, - Water1, - Bug, - Flying, - Field, - Fairy, - Grass, - HumanLike, - Water3, - Mineral, - Amorphous, - Water2, - Ditto, - Dragon, - Undiscovered, - } -} \ No newline at end of file + None, + Monster, + Water1, + Bug, + Flying, + Field, + Fairy, + Grass, + HumanLike, + Water3, + Mineral, + Amorphous, + Water2, + Ditto, + Dragon, + Undiscovered, +} diff --git a/pkNX.Structures/Personal/Interfaces/IMovesInfo.cs b/pkNX.Structures/Personal/Interfaces/IMovesInfo.cs index 760bd40b..5d25dd10 100644 --- a/pkNX.Structures/Personal/Interfaces/IMovesInfo.cs +++ b/pkNX.Structures/Personal/Interfaces/IMovesInfo.cs @@ -1,96 +1,91 @@ -using System; -using System.Collections.Generic; -using System.Text; +namespace pkNX.Structures; -namespace pkNX.Structures +public interface IMovesInfo { - public interface IMovesInfo - { - } +} - public interface IMovesInfo_1 : IMovesInfo - { - /// - /// TM/HM learn compatibility flags for individual moves. - /// - bool[] TMHM { get; set; } - - /// - /// Grass-Fire-Water-Etc typed learn compatibility flags for individual moves. - /// - bool[] TypeTutors { get; set; } - } +public interface IMovesInfo_1 : IMovesInfo +{ + /// + /// TM/HM learn compatibility flags for individual moves. + /// + bool[] TMHM { get; set; } /// - /// SpecialTutors added in BW2 + /// Grass-Fire-Water-Etc typed learn compatibility flags for individual moves. /// - public interface IMovesInfo_2 : IMovesInfo_1 - { - /// - /// Special tutor learn compatibility flags for individual moves. - /// - bool[][] SpecialTutors { get; set; } - } + bool[] TypeTutors { get; set; } +} + +/// +/// SpecialTutors added in BW2 +/// +public interface IMovesInfo_2 : IMovesInfo_1 +{ + /// + /// Special tutor learn compatibility flags for individual moves. + /// + bool[][] SpecialTutors { get; set; } +} + +/// +/// Moves layout seems to have changed completely from the old verion +/// +public interface IMovesInfo_3 : IMovesInfo +{ + uint TM_A { get; set; } + uint TM_B { get; set; } + uint TM_C { get; set; } + uint TM_D { get; set; } + uint TR_A { get; set; } + uint TR_B { get; set; } + uint TR_C { get; set; } + uint TR_D { get; set; } + uint TypeTutor { get; set; } + uint MoveShop1 { get; set; } // uint + uint MoveShop2 { get; set; } // uint /// - /// Moves layout seems to have changed completely from the old verion + /// Special tutor learn compatibility flags for individual moves. /// - public interface IMovesInfo_3 : IMovesInfo - { - uint TM_A { get; set; } - uint TM_B { get; set; } - uint TM_C { get; set; } - uint TM_D { get; set; } - uint TR_A { get; set; } - uint TR_B { get; set; } - uint TR_C { get; set; } - uint TR_D { get; set; } - uint TypeTutor { get; set; } - uint MoveShop1 { get; set; } // uint - uint MoveShop2 { get; set; } // uint + bool[][] SpecialTutors { get; set; } +} - /// - /// Special tutor learn compatibility flags for individual moves. - /// - bool[][] SpecialTutors { get; set; } - } - - public static class IPersonalMovesExtensions +public static class IPersonalMovesExtensions +{ + public static void SetIMovesInfo(this IMovesInfo self, IMovesInfo other) { - public static void SetIMovesInfo(this IMovesInfo self, IMovesInfo other) + if (self is IMovesInfo_1 self_1 && other is IMovesInfo_1 other_1) { - if (self is IMovesInfo_1 self_1 && other is IMovesInfo_1 other_1) - { - self_1.TMHM = other_1.TMHM; - self_1.TypeTutors = other_1.TypeTutors; - } + self_1.TMHM = other_1.TMHM; + self_1.TypeTutors = other_1.TypeTutors; + } - if (self is IMovesInfo_2 self_2 && other is IMovesInfo_2 other_2) - { - self_2.SpecialTutors = other_2.SpecialTutors; - } + if (self is IMovesInfo_2 self_2 && other is IMovesInfo_2 other_2) + { + self_2.SpecialTutors = other_2.SpecialTutors; + } - if (self is IMovesInfo_3 self_3) + if (self is IMovesInfo_3 self_3) + { + if (other is IMovesInfo_2 other_2b) { - if (other is IMovesInfo_2 other_2b) - { - self_3.SpecialTutors = other_2b.SpecialTutors; - } - else if (other is IMovesInfo_3 other_3) - { - self_3.TM_A = other_3.TM_A; - self_3.TM_B = other_3.TM_B; - self_3.TM_C = other_3.TM_C; - self_3.TM_D = other_3.TM_D; - self_3.TR_A = other_3.TR_A; - self_3.TR_B = other_3.TR_B; - self_3.TR_C = other_3.TR_C; - self_3.TR_D = other_3.TR_D; - self_3.TypeTutor = other_3.TypeTutor; - self_3.MoveShop1 = other_3.MoveShop1; - self_3.MoveShop2 = other_3.MoveShop2; - self_3.SpecialTutors = other_3.SpecialTutors; - } + self_3.SpecialTutors = other_2b.SpecialTutors; + } + else if (other is IMovesInfo_3 other_3) + { + self_3.TM_A = other_3.TM_A; + self_3.TM_B = other_3.TM_B; + self_3.TM_C = other_3.TM_C; + self_3.TM_D = other_3.TM_D; + self_3.TR_A = other_3.TR_A; + self_3.TR_B = other_3.TR_B; + self_3.TR_C = other_3.TR_C; + self_3.TR_D = other_3.TR_D; + self_3.TypeTutor = other_3.TypeTutor; + self_3.MoveShop1 = other_3.MoveShop1; + self_3.MoveShop2 = other_3.MoveShop2; + self_3.SpecialTutors = other_3.SpecialTutors; } } } diff --git a/pkNX.Structures/Personal/Interfaces/IPersonalFormInfo.cs b/pkNX.Structures/Personal/Interfaces/IPersonalFormInfo.cs index 34379c4f..4077a64a 100644 --- a/pkNX.Structures/Personal/Interfaces/IPersonalFormInfo.cs +++ b/pkNX.Structures/Personal/Interfaces/IPersonalFormInfo.cs @@ -1,5 +1,3 @@ -using System; - namespace pkNX.Structures; /// diff --git a/pkNX.Structures/Personal/Interfaces/IPersonalInfo.cs b/pkNX.Structures/Personal/Interfaces/IPersonalInfo.cs index 7305e608..112017e1 100644 --- a/pkNX.Structures/Personal/Interfaces/IPersonalInfo.cs +++ b/pkNX.Structures/Personal/Interfaces/IPersonalInfo.cs @@ -1,101 +1,99 @@ -using pkNX.Structures; using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Base interface that can be used for any version. This should not contain variables that are not present in every game +/// +public interface IPersonalInfo : IBaseStat, IEffortValueYield, IPersonalType, IPersonalEgg, IPersonalTraits, IPersonalAbility, IPersonalMisc, IPersonalItems, IPersonalFormInfo { } + +public interface IPersonalInfoBin { - /// - /// Base interface that can be used for any version. This should not contain variables that are not present in every game - /// - public interface IPersonalInfo : IBaseStat, IEffortValueYield, IPersonalType, IPersonalEgg, IPersonalTraits, IPersonalAbility, IPersonalMisc, IPersonalItems, IPersonalFormInfo { } + byte[] Write(); +} - public interface IPersonalInfoBin +public static class IPersonalInfoBinExt +{ + public static bool[] GetBits(ReadOnlySpan data) { - byte[] Write(); + bool[] result = new bool[data.Length << 3]; + for (int i = result.Length - 1; i >= 0; i--) + result[i] = ((data[i >> 3] >> (i & 7)) & 0x1) == 1; + return result; } - public static class IPersonalInfoBinExt + public static void SetBits(ReadOnlySpan bits, Span data) { - public static bool[] GetBits(ReadOnlySpan data) + for (int i = bits.Length - 1; i >= 0; i--) + data[i >> 3] |= (byte)(bits[i] ? 1 << (i & 0x7) : 0); + } +} + +/// +/// Version one +/// +public interface IPersonalInfo_1 : IPersonalInfoBin, IPersonalInfo, IPersonalEgg_1, IMovesInfo_1 { } + +/// +/// Version 2 adds `SpecialTutors` to moves +/// +public interface IPersonalInfo_2 : IPersonalInfoBin, IPersonalInfo, IPersonalEgg_1, IMovesInfo_2 { } + +// Game specific PersonalInfo interfaces + +public interface IPersonalInfoBW : IPersonalInfo_1 { } +public interface IPersonalInfoXY : IPersonalInfo_1 { } +public interface IPersonalInfoB2W2 : IPersonalInfo_2 { } +public interface IPersonalInfoORAS : IPersonalInfo_2 { } +public interface IPersonalInfoSM : IPersonalInfo_2 +{ + int SpecialZ_Item { get; set; } + int SpecialZ_BaseMove { get; set; } + int SpecialZ_ZMove { get; set; } + bool IsRegionalForm { get; set; } +} +public interface IPersonalInfoGG : IPersonalInfoSM +{ + int GoSpecies { get; set; } +} +public interface IPersonalInfoSWSH : IPersonalInfoBin, IPersonalInfo, IPersonalEgg_2, IMovesInfo_2, IPersonalMisc_1 +{ + bool SpriteForm { get; set; } + bool IsRegionalForm { get; set; } + ushort RegionalFlags { get; set; } + bool CanNotDynamax { get; set; } + ushort ArmorDexIndex { get; set; } + ushort CrownDexIndex { get; set; } +} +public interface IPersonalInfoPLA : IPersonalInfo, IPersonalEgg_3, IMovesInfo_3, IPersonalMisc_2 +{ + byte Field_18 { get; set; } // Always Default (0) + bool Field_45 { get; set; } // byte + ushort Field_46 { get; set; } // ushort + byte Field_47 { get; set; } // byte +} + +public static class IPersonalInfoExt +{ + public static void SetPersonalInfo(this IPersonalInfo self, IPersonalInfo other) + { + self.SetIBaseStats(other); + self.SetIEffortValueYield(other); + self.SetIPersonalAbility(other); + self.SetIPersonalItems(other); + self.SetIPersonalType(other); + self.SetIPersonalEgg(other); + self.SetIPersonalTraits(other); + self.SetIPersonalMisc(other); + + if (self is IPersonalInfo_1 self_1 && other is IPersonalInfo_1 other_1) { - bool[] result = new bool[data.Length << 3]; - for (int i = result.Length - 1; i >= 0; i--) - result[i] = ((data[i >> 3] >> (i & 7)) & 0x1) == 1; - return result; + self_1.SetIMovesInfo(other_1); } - public static void SetBits(ReadOnlySpan bits, Span data) + if (self is IPersonalInfo_2 self_2 && other is IPersonalInfo_2 other_2) { - for (int i = bits.Length - 1; i >= 0; i--) - data[i >> 3] |= (byte)(bits[i] ? 1 << (i & 0x7) : 0); - } - } - - /// - /// Version one - /// - public interface IPersonalInfo_1 : IPersonalInfoBin, IPersonalInfo, IPersonalEgg_1, IMovesInfo_1 { } - - /// - /// Version 2 adds `SpecialTutors` to moves - /// - public interface IPersonalInfo_2 : IPersonalInfoBin, IPersonalInfo, IPersonalEgg_1, IMovesInfo_2 { } - - // Game specific PersonalInfo interfaces - - public interface IPersonalInfoBW : IPersonalInfo_1 { } - public interface IPersonalInfoXY : IPersonalInfo_1 { } - public interface IPersonalInfoB2W2 : IPersonalInfo_2 { } - public interface IPersonalInfoORAS : IPersonalInfo_2 { } - public interface IPersonalInfoSM : IPersonalInfo_2 - { - int SpecialZ_Item { get; set; } - int SpecialZ_BaseMove { get; set; } - int SpecialZ_ZMove { get; set; } - bool IsRegionalForm { get; set; } - } - public interface IPersonalInfoGG : IPersonalInfoSM - { - int GoSpecies { get; set; } - } - public interface IPersonalInfoSWSH : IPersonalInfoBin, IPersonalInfo, IPersonalEgg_2, IMovesInfo_2, IPersonalMisc_1 - { - bool SpriteForm { get; set; } - bool IsRegionalForm { get; set; } - ushort RegionalFlags { get; set; } - bool CanNotDynamax { get; set; } - ushort ArmorDexIndex { get; set; } - ushort CrownDexIndex { get; set; } - } - public interface IPersonalInfoPLA : IPersonalInfo, IPersonalEgg_3, IMovesInfo_3, IPersonalMisc_2 - { - byte Field_18 { get; set; } // Always Default (0) - bool Field_45 { get; set; } // byte - ushort Field_46 { get; set; } // ushort - byte Field_47 { get; set; } // byte - } - - public static class IPersonalInfoExt - { - public static void SetPersonalInfo(this IPersonalInfo self, IPersonalInfo other) - { - self.SetIBaseStats(other); - self.SetIEffortValueYield(other); - self.SetIPersonalAbility(other); - self.SetIPersonalItems(other); - self.SetIPersonalType(other); - self.SetIPersonalEgg(other); - self.SetIPersonalTraits(other); - self.SetIPersonalMisc(other); - - if (self is IPersonalInfo_1 self_1 && other is IPersonalInfo_1 other_1) - { - self_1.SetIMovesInfo(other_1); - } - - if (self is IPersonalInfo_2 self_2 && other is IPersonalInfo_2 other_2) - { - self_2.SetIMovesInfo(other_2); - } + self_2.SetIMovesInfo(other_2); } } } diff --git a/pkNX.Structures/Personal/Interfaces/IPersonalItems.cs b/pkNX.Structures/Personal/Interfaces/IPersonalItems.cs index 4766cf07..7228d06a 100644 --- a/pkNX.Structures/Personal/Interfaces/IPersonalItems.cs +++ b/pkNX.Structures/Personal/Interfaces/IPersonalItems.cs @@ -1,4 +1,4 @@ -using System; +using System; namespace pkNX.Structures; diff --git a/pkNX.Structures/Personal/Interfaces/IPersonalMisc.cs b/pkNX.Structures/Personal/Interfaces/IPersonalMisc.cs index 7b05a1c0..3dcd7e63 100644 --- a/pkNX.Structures/Personal/Interfaces/IPersonalMisc.cs +++ b/pkNX.Structures/Personal/Interfaces/IPersonalMisc.cs @@ -46,4 +46,4 @@ public static void SetIPersonalMisc(this IPersonalMisc self, IPersonalMisc other self_1.Form = other_1.Form; } } -} \ No newline at end of file +} diff --git a/pkNX.Structures/Personal/Interfaces/IPersonalTable.cs b/pkNX.Structures/Personal/Interfaces/IPersonalTable.cs index f17086cd..545d7220 100644 --- a/pkNX.Structures/Personal/Interfaces/IPersonalTable.cs +++ b/pkNX.Structures/Personal/Interfaces/IPersonalTable.cs @@ -129,4 +129,4 @@ public static string[] GetPersonalEntryList(this IPersonalTable pt, string[][] A } return result; } -} \ No newline at end of file +} diff --git a/pkNX.Structures/Personal/Interfaces/IPersonalTraits.cs b/pkNX.Structures/Personal/Interfaces/IPersonalTraits.cs index ae95366a..46519c0f 100644 --- a/pkNX.Structures/Personal/Interfaces/IPersonalTraits.cs +++ b/pkNX.Structures/Personal/Interfaces/IPersonalTraits.cs @@ -36,7 +36,7 @@ public interface IPersonalTraits int EscapeRate { get; set; } /// - /// Main color ID of the entry. The majority of the Pokmon's color is of this color, usually. + /// Main color ID of the entry. The majority of the Pokémon's color is of this color, usually. /// int Color { get; set; } @@ -104,4 +104,4 @@ public static void SetIPersonalTraits(this IPersonalTraits self, IPersonalTraits self.Height = other.Height; self.Weight = other.Weight; } -} \ No newline at end of file +} diff --git a/pkNX.Structures/Personal/PokeColor.cs b/pkNX.Structures/Personal/PokeColor.cs index b4d22274..a757a9d9 100644 --- a/pkNX.Structures/Personal/PokeColor.cs +++ b/pkNX.Structures/Personal/PokeColor.cs @@ -1,16 +1,15 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum PokeColor { - public enum PokeColor - { - Red, - Blue, - Yellow, - Green, - Black, - Brown, - Purple, - Gray, - White, - Pink, - } + Red, + Blue, + Yellow, + Green, + Black, + Brown, + Purple, + Gray, + White, + Pink, } diff --git a/pkNX.Structures/Resources/BinLinkerAccessor.cs b/pkNX.Structures/Resources/BinLinkerAccessor.cs index f200f23d..d86b52b4 100644 --- a/pkNX.Structures/Resources/BinLinkerAccessor.cs +++ b/pkNX.Structures/Resources/BinLinkerAccessor.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Diagnostics; using static System.Buffers.Binary.BinaryPrimitives; diff --git a/pkNX.Structures/Resources/ResourcesUtil.cs b/pkNX.Structures/Resources/ResourcesUtil.cs index bba194ff..b899e361 100644 --- a/pkNX.Structures/Resources/ResourcesUtil.cs +++ b/pkNX.Structures/Resources/ResourcesUtil.cs @@ -1,77 +1,75 @@ -using System; +using System; using System.Collections.Generic; using System.Reflection; -using System.Text; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class ResourcesUtil { - public class ResourcesUtil + private static readonly Assembly thisAssembly = typeof(Util).GetTypeInfo().Assembly; + private static readonly Dictionary resourceNameMap = BuildLookup(thisAssembly.GetManifestResourceNames()); + + /// + /// Personal Table used in . + /// + public static readonly PersonalTable8SWSH SWSH = new(GetTableBinary("swsh")); + + /// + /// Personal Table used in . + /// + public static readonly PersonalTable7SM USUM = new(GetTableBinary("usum"), Legal.MaxSpeciesID_7_USUM); + + /// + /// Evolution Table used in . + /// + public static readonly IReadOnlyList SWSH_Evolutions = EvolutionSet8.GetArray(GetReader("ss")); + + /// + /// Evolution Table used in . + /// + public static readonly IReadOnlyList USUM_Evolutions = EvolutionSet7.GetArray(GetReader("uu")); + + static ResourcesUtil() { - private static readonly Assembly thisAssembly = typeof(Util).GetTypeInfo().Assembly; - private static readonly Dictionary resourceNameMap = BuildLookup(thisAssembly.GetManifestResourceNames()); + SWSH.FixMissingData(); + } - /// - /// Personal Table used in . - /// - public static readonly PersonalTable8SWSH SWSH = new(GetTableBinary("swsh")); + private static ReadOnlySpan GetTableBinary(string game) => GetBinaryResource($"personal_{game}"); + private static ReadOnlySpan GetEvolutionBinary(string game) => GetBinaryResource($"evos_{game}.pkl"); + private static BinLinkerAccessor GetReader(string resource) => BinLinkerAccessor.Get(GetEvolutionBinary(resource), resource); - /// - /// Personal Table used in . - /// - public static readonly PersonalTable7SM USUM = new(GetTableBinary("usum"), Legal.MaxSpeciesID_7_USUM); + private static string GetFileName(string resName) + { + var period = resName.LastIndexOf('.', resName.Length - 5); + var start = period + 1; + System.Diagnostics.Debug.Assert(start != 0); - /// - /// Evolution Table used in . - /// - public static readonly IReadOnlyList SWSH_Evolutions = EvolutionSet8.GetArray(GetReader("ss")); + // text file fetch excludes ".txt" (mixed case...); other extensions are used (all lowercase). + return resName.EndsWith(".txt", StringComparison.Ordinal) ? resName[start..^4].ToLowerInvariant() : resName[start..]; + } - /// - /// Evolution Table used in . - /// - public static readonly IReadOnlyList USUM_Evolutions = EvolutionSet7.GetArray(GetReader("uu")); - - static ResourcesUtil() + private static Dictionary BuildLookup(IReadOnlyCollection manifestNames) + { + var result = new Dictionary(manifestNames.Count); + foreach (var resName in manifestNames) { - SWSH.FixMissingData(); + var fileName = GetFileName(resName); + result.Add(fileName, resName); } + return result; + } - private static ReadOnlySpan GetTableBinary(string game) => GetBinaryResource($"personal_{game}"); - private static ReadOnlySpan GetEvolutionBinary(string game) => GetBinaryResource($"evos_{game}.pkl"); - private static BinLinkerAccessor GetReader(string resource) => BinLinkerAccessor.Get(GetEvolutionBinary(resource), resource); + public static byte[] GetBinaryResource(string name) + { + if (!resourceNameMap.TryGetValue(name, out var resName)) + return Array.Empty(); - private static string GetFileName(string resName) - { - var period = resName.LastIndexOf('.', resName.Length - 5); - var start = period + 1; - System.Diagnostics.Debug.Assert(start != 0); + using var resource = thisAssembly.GetManifestResourceStream(resName); + if (resource is null) + return Array.Empty(); - // text file fetch excludes ".txt" (mixed case...); other extensions are used (all lowercase). - return resName.EndsWith(".txt", StringComparison.Ordinal) ? resName[start..^4].ToLowerInvariant() : resName[start..]; - } - - private static Dictionary BuildLookup(IReadOnlyCollection manifestNames) - { - var result = new Dictionary(manifestNames.Count); - foreach (var resName in manifestNames) - { - var fileName = GetFileName(resName); - result.Add(fileName, resName); - } - return result; - } - - public static byte[] GetBinaryResource(string name) - { - if (!resourceNameMap.TryGetValue(name, out var resName)) - return Array.Empty(); - - using var resource = thisAssembly.GetManifestResourceStream(resName); - if (resource is null) - return Array.Empty(); - - var buffer = new byte[resource.Length]; - _ = resource.Read(buffer, 0, (int)resource.Length); - return buffer; - } + var buffer = new byte[resource.Length]; + _ = resource.Read(buffer, 0, (int)resource.Length); + return buffer; } } diff --git a/pkNX.Structures/Scripts/Amx.cs b/pkNX.Structures/Scripts/Amx.cs index 435723f6..08a7f563 100644 --- a/pkNX.Structures/Scripts/Amx.cs +++ b/pkNX.Structures/Scripts/Amx.cs @@ -1,389 +1,388 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Pawn Script (.amx) Script File +/// +/// https://github.com/compuphase/pawn +public class Amx { - /// - /// Pawn Script (.amx) Script File - /// - /// https://github.com/compuphase/pawn - public class Amx + private const int MAX_NAME_LENGTH = 31; + + public readonly byte[] Data; + public readonly AmxHeader Header; + public readonly int CellSize; + + public Amx(byte[] data) { - private const int MAX_NAME_LENGTH = 31; + Data = data; + Header = data.ToClass(); + CellSize = Header.CellSize; - public readonly byte[] Data; - public readonly AmxHeader Header; - public readonly int CellSize; + if (Header.Flags.HasFlagFast(AmxFlags.DEBUG)) + return; - public Amx(byte[] data) + if (Header.Flags.HasFlagFast(AmxFlags.OVERLAY)) + throw new ArgumentException("Multi-environment script!?"); + + Unpack(); + + Trace.Assert(Header != null); + Trace.Assert(Header.Magic != 0); + Trace.Assert(Header.Natives <= Header.Libraries); + } + + public byte[] Write() => Data; + public bool IsDebug => Header.Flags.HasFlagFast(AmxFlags.DEBUG); + + // Generated Attributes + public int CodeLength => Header.Data - Header.COD; + public int CompressedLength => Header.Size - Header.COD; + public byte[] CompressedBytes => Data.Skip(Header.COD).ToArray(); + public int DecompressedLength => Header.Heap - Header.COD; + public uint[] DecompressedInstructions => PawnUtil.QuickDecompress(CompressedBytes, DecompressedLength / sizeof(uint)); + + public uint[] ScriptCommands => DecompressedInstructions.Take(CodeLength / sizeof(uint)).ToArray(); // Code + public uint[] DataPayload => DecompressedInstructions.Skip(CodeLength / sizeof(uint)).ToArray(); // Data + public string[] ParseScript => PawnUtil.ParseScript(ScriptCommands); + public string[] DataChunk => PawnUtil.ParseMovement(DataPayload); + + public string Info => string.Join(Environment.NewLine, SummaryLines); + + public IEnumerable SummaryLines + { + get { - Data = data; - Header = data.ToClass(); - CellSize = Header.CellSize; - - if (Header.Flags.HasFlagFast(AmxFlags.DEBUG)) - return; - - if (Header.Flags.HasFlagFast(AmxFlags.OVERLAY)) - throw new ArgumentException("Multi-environment script!?"); - - Unpack(); - - Trace.Assert(Header != null); - Trace.Assert(Header.Magic != 0); - Trace.Assert(Header.Natives <= Header.Libraries); - } - - public byte[] Write() => Data; - public bool IsDebug => Header.Flags.HasFlagFast(AmxFlags.DEBUG); - - // Generated Attributes - public int CodeLength => Header.Data - Header.COD; - public int CompressedLength => Header.Size - Header.COD; - public byte[] CompressedBytes => Data.Skip(Header.COD).ToArray(); - public int DecompressedLength => Header.Heap - Header.COD; - public uint[] DecompressedInstructions => PawnUtil.QuickDecompress(CompressedBytes, DecompressedLength / sizeof(uint)); - - public uint[] ScriptCommands => DecompressedInstructions.Take(CodeLength / sizeof(uint)).ToArray(); // Code - public uint[] DataPayload => DecompressedInstructions.Skip(CodeLength / sizeof(uint)).ToArray(); // Data - public string[] ParseScript => PawnUtil.ParseScript(ScriptCommands); - public string[] DataChunk => PawnUtil.ParseMovement(DataPayload); - - public string Info => string.Join(Environment.NewLine, SummaryLines); - - public IEnumerable SummaryLines - { - get - { - yield return $"Code Start: 0x{Header.COD:X4}"; - yield return $"Data Start: 0x{Header.Data:X4}"; - yield return $"Total Used Size: 0x{Header.Heap:X4}"; - yield return $"Reserved Size: 0x{Header.StackTop:X4}"; - yield return $"Compressed Len: 0x{CompressedLength:X4}"; - yield return $"Decompressed Len: 0x{DecompressedLength:X4}"; - yield return $"Entry Point: 0x{Header.CurrentInstructionPointer:X4}"; - yield return $"Compression Ratio: {(DecompressedLength - CompressedLength) / (decimal)DecompressedLength:p1}"; - } - } - - public Function LookupFunction(uint pc) => Array.Find(Functions, f => f.Within(pc)); - public TableRecord LookupPublic(string name) => Array.Find(Publics, t => t.Name == name); - public TableRecord LookupPublic(uint addr) => Array.Find(Publics, t => t.Address == addr); - - public Function[] Functions { get; protected set; } - public TableRecord[] Publics { get; protected set; } - public TableRecord[] Natives { get; protected set; } - public TableRecord[] Libraries { get; protected set; } - public TableRecord[] PublicVars { get; protected set; } - public Variable[] Globals { get; protected set; } - - public static string ReadName(byte[] data, int offset) - { - var end = Array.FindIndex(data, offset, z => z == 0); - if (end < 0) - end = offset + MAX_NAME_LENGTH; - if (end >= data.Length) - return null; - return System.Text.Encoding.UTF8.GetString(data, offset, end - offset); - } - - public void Unpack() - { - if (Header.Publics > 0) - ReadPublics(); - if (Header.Natives > 0) - ReadNatives(); - if (Header.Libraries > 0) - ReadLibraries(); - if (Header.PublicVars > 0) - ReadPublicVars(); - - if (IsDebug) - { - // todo - } - } - - public class Cell - { - } - - protected void ReadPublics() - { - var count = (Header.Natives - Header.Publics) / Header.DefinitionSize; - - Publics = ReadTable(Header.Publics, count); - } - - protected void ReadNatives() - { - var count = (Header.Libraries - Header.Natives) / Header.DefinitionSize; - - Natives = ReadTable(Header.Natives, count); - } - - protected void ReadLibraries() - { - var count = (Header.PublicVars - Header.Libraries) / Header.DefinitionSize; - - Libraries = ReadTable(Header.Libraries, count); - } - - protected void ReadPublicVars() - { - var count = (Header.Tags - Header.PublicVars) / Header.DefinitionSize; - - PublicVars = ReadTable(Header.PublicVars, count); - } - - protected TableRecord[] ReadTable(int offset, int count) - { - using var stream = new MemoryStream(Data, offset, count * Header.DefinitionSize); - using var reader = new BinaryReader(stream); - var dest = new TableRecord[count]; - - for (int i = 0; i < dest.Length; i++) - { - var address = reader.ReadUInt32(); - var nameoffset = reader.ReadUInt32(); - var name = default(string); - - if (nameoffset < Data.Length) - name = ReadName(Data, (int)nameoffset); - - name ??= "Unknown"; - dest[i] = new TableRecord(name, address); - } - - return dest; - } - - private int sysreq_flg; - - public void ParseOp(AmxOpCode op, ref int cip, ref Cell tgt) - { - static void GETPARAM_P(Cell v, AmxOpCode o) { } // (v = ((Cell) (o) >> (int) (CellSize * 4)));} - switch (op) - { - case AmxOpCode.CONST: - case AmxOpCode.CONST_S: - cip += CellSize * 2; - break; - - /* Packed Instructions */ - case AmxOpCode.CONST_P_PRI: - case AmxOpCode.CONST_P_ALT: - case AmxOpCode.ADDR_P_PRI: - case AmxOpCode.ADDR_P_ALT: - case AmxOpCode.STRB_P_I: - case AmxOpCode.LIDX_P_B: - case AmxOpCode.IDXADDR_P_B: - case AmxOpCode.ALIGN_P_PRI: - case AmxOpCode.PUSH_P_C: - case AmxOpCode.PUSH_P: - case AmxOpCode.PUSH_P_S: - case AmxOpCode.STACK_P: - case AmxOpCode.HEAP_P: - case AmxOpCode.SHL_P_C_PRI: - case AmxOpCode.SHL_P_C_ALT: - case AmxOpCode.ADD_P_C: - case AmxOpCode.SMUL_P_C: - case AmxOpCode.ZERO_P: - case AmxOpCode.ZERO_P_S: - case AmxOpCode.EQ_P_C_PRI: - case AmxOpCode.EQ_P_C_ALT: - case AmxOpCode.MOVS_P: - case AmxOpCode.CMPS_P: - case AmxOpCode.FILL_P: - case AmxOpCode.HALT_P: - case AmxOpCode.BOUNDS_P: - case AmxOpCode.PUSH_P_ADR: - break; - - /* Packed Instructions referencing pointers */ - case AmxOpCode.LOAD_P_PRI: - case AmxOpCode.LOAD_P_ALT: - case AmxOpCode.INC_P: - case AmxOpCode.DEC_P: - GETPARAM_P(tgt, op); - break; - - /* Packed Instructions referencing stack */ - case AmxOpCode.LOAD_P_S_PRI: - case AmxOpCode.LOAD_P_S_ALT: - case AmxOpCode.LREF_P_S_PRI: - case AmxOpCode.LREF_P_S_ALT: - case AmxOpCode.INC_P_S: - case AmxOpCode.DEC_P_S: - GETPARAM_P(tgt, op); /* verify address */ - break; - - /* Single-Value Instructions */ - case AmxOpCode.LODB_I: - case AmxOpCode.CONST_PRI: - case AmxOpCode.CONST_ALT: - case AmxOpCode.ADDR_PRI: - case AmxOpCode.ADDR_ALT: - case AmxOpCode.STRB_I: - case AmxOpCode.LIDX_B: - case AmxOpCode.IDXADDR_B: - case AmxOpCode.ALIGN_PRI: - case AmxOpCode.LCTRL: - case AmxOpCode.SCTRL: - case AmxOpCode.PICK: - case AmxOpCode.PUSH_C: - case AmxOpCode.PUSH: - case AmxOpCode.PUSH_S: - case AmxOpCode.STACK: - case AmxOpCode.HEAP: - case AmxOpCode.SHL_C_PRI: - case AmxOpCode.SHL_C_ALT: - case AmxOpCode.ADD_C: - case AmxOpCode.SMUL_C: - case AmxOpCode.ZERO: - case AmxOpCode.ZERO_S: - case AmxOpCode.EQ_C_PRI: - case AmxOpCode.EQ_C_ALT: - case AmxOpCode.MOVS: - case AmxOpCode.CMPS: - case AmxOpCode.FILL: - case AmxOpCode.HALT: - case AmxOpCode.BOUNDS: - case AmxOpCode.PUSH_ADR: - cip += CellSize; - break; - - case AmxOpCode.LOAD_PRI: - case AmxOpCode.LOAD_ALT: - case AmxOpCode.INC: - case AmxOpCode.DEC: - //VerifyAddress(0, ); - cip += CellSize; - break; - - case AmxOpCode.LOAD_S_PRI: - case AmxOpCode.LOAD_S_ALT: - case AmxOpCode.LREF_S_PRI: - case AmxOpCode.LREF_S_ALT: - case AmxOpCode.INC_S: - case AmxOpCode.DEC_S: - cip += CellSize; - break; - - /* Parameterless Instructions */ - case AmxOpCode.LOAD_I: - case AmxOpCode.STOR_I: - case AmxOpCode.LIDX: - case AmxOpCode.IDXADDR: - case AmxOpCode.XCHG: - case AmxOpCode.PUSH_PRI: - case AmxOpCode.PUSH_ALT: - case AmxOpCode.PPRI: - case AmxOpCode.PALT: - case AmxOpCode.PROC: - case AmxOpCode.RET: - case AmxOpCode.RETN: - case AmxOpCode.SHL: - case AmxOpCode.SHR: - case AmxOpCode.SSHR: - case AmxOpCode.SMUL: - case AmxOpCode.SDIV: - case AmxOpCode.ADD: - case AmxOpCode.SUB: - case AmxOpCode.AND: - case AmxOpCode.OR: - case AmxOpCode.XOR: - case AmxOpCode.NOT: - case AmxOpCode.NEG: - case AmxOpCode.INVERT: - case AmxOpCode.ZERO_PRI: - case AmxOpCode.ZERO_ALT: - case AmxOpCode.EQ: - case AmxOpCode.NEQ: - case AmxOpCode.SLESS: - case AmxOpCode.SLEQ: - case AmxOpCode.SGRTR: - case AmxOpCode.SGEQ: - case AmxOpCode.INC_PRI: - case AmxOpCode.INC_ALT: - case AmxOpCode.INC_I: - case AmxOpCode.DEC_PRI: - case AmxOpCode.DEC_ALT: - case AmxOpCode.DEC_I: - case AmxOpCode.SWAP_PRI: - case AmxOpCode.SWAP_ALT: - case AmxOpCode.NOP: - case AmxOpCode.BREAK: - break; - - /* Jump w/ Relocation */ - case AmxOpCode.CALL: - case AmxOpCode.JUMP: - case AmxOpCode.JZER: - case AmxOpCode.JNZ: - case AmxOpCode.JEQ: - case AmxOpCode.JNEQ: - case AmxOpCode.JSLESS: - case AmxOpCode.JSLEQ: - case AmxOpCode.JSGRTR: - case AmxOpCode.JSGEQ: - case AmxOpCode.SWITCH: - /* if this file is an older version (absolute references instead of the - * current use of position-independent code), convert the parameter - * to position-independent code first - */ - cip += CellSize; - break; - - /* overlay opcodes (overlays must be enabled) */ - case AmxOpCode.ISWITCH: - Debug.Assert(Header.FileVersion >= 10); - /* drop through */ - goto case AmxOpCode.ICALL; - case AmxOpCode.ICALL: - cip += CellSize; - /* drop through */ - goto case AmxOpCode.IRETN; - case AmxOpCode.IRETN: - Debug.Assert(Header.Overlays != 0 && Header.Overlays != Header.NameTable); - //return AmxError.OVERLAY; /* no overlay callback */ - break; - case AmxOpCode.ICASETBL: - { - // Cell num; - //DBGPARAM(num); /* number of records follows the opcode */ - //cip += (2 * num + 1) * CellSize; - //if (Header.Overlays == 0) - // return AmxError.OVERLAY; /* no overlay callback */ - break; - } /* case */ - - case AmxOpCode.SYSREQ_C: - cip += CellSize; - sysreq_flg |= 0x01; /* mark SYSREQ found */ - break; - case AmxOpCode.SYSREQ_N: - cip += CellSize * 2; - sysreq_flg |= 0x02; /* mark SYSREQ.N found */ - break; - - case AmxOpCode.CASETBL: - { - DBGPARAM(out _); - //cip += (2 * num + 1) * CellSize; - break; - } - - default: - Header.Flags &= ~AmxFlags.VERIFY; - //return AmxError.INVINSTR; - break; - } - - static void DBGPARAM(out Cell v) => v = null; // v = (Cell)(amx->code + (int)cip), cip += CellSize) + yield return $"Code Start: 0x{Header.COD:X4}"; + yield return $"Data Start: 0x{Header.Data:X4}"; + yield return $"Total Used Size: 0x{Header.Heap:X4}"; + yield return $"Reserved Size: 0x{Header.StackTop:X4}"; + yield return $"Compressed Len: 0x{CompressedLength:X4}"; + yield return $"Decompressed Len: 0x{DecompressedLength:X4}"; + yield return $"Entry Point: 0x{Header.CurrentInstructionPointer:X4}"; + yield return $"Compression Ratio: {(DecompressedLength - CompressedLength) / (decimal)DecompressedLength:p1}"; } } + + public Function LookupFunction(uint pc) => Array.Find(Functions, f => f.Within(pc)); + public TableRecord LookupPublic(string name) => Array.Find(Publics, t => t.Name == name); + public TableRecord LookupPublic(uint addr) => Array.Find(Publics, t => t.Address == addr); + + public Function[] Functions { get; protected set; } + public TableRecord[] Publics { get; protected set; } + public TableRecord[] Natives { get; protected set; } + public TableRecord[] Libraries { get; protected set; } + public TableRecord[] PublicVars { get; protected set; } + public Variable[] Globals { get; protected set; } + + public static string ReadName(byte[] data, int offset) + { + var end = Array.FindIndex(data, offset, z => z == 0); + if (end < 0) + end = offset + MAX_NAME_LENGTH; + if (end >= data.Length) + return null; + return System.Text.Encoding.UTF8.GetString(data, offset, end - offset); + } + + public void Unpack() + { + if (Header.Publics > 0) + ReadPublics(); + if (Header.Natives > 0) + ReadNatives(); + if (Header.Libraries > 0) + ReadLibraries(); + if (Header.PublicVars > 0) + ReadPublicVars(); + + if (IsDebug) + { + // todo + } + } + + public class Cell + { + } + + protected void ReadPublics() + { + var count = (Header.Natives - Header.Publics) / Header.DefinitionSize; + + Publics = ReadTable(Header.Publics, count); + } + + protected void ReadNatives() + { + var count = (Header.Libraries - Header.Natives) / Header.DefinitionSize; + + Natives = ReadTable(Header.Natives, count); + } + + protected void ReadLibraries() + { + var count = (Header.PublicVars - Header.Libraries) / Header.DefinitionSize; + + Libraries = ReadTable(Header.Libraries, count); + } + + protected void ReadPublicVars() + { + var count = (Header.Tags - Header.PublicVars) / Header.DefinitionSize; + + PublicVars = ReadTable(Header.PublicVars, count); + } + + protected TableRecord[] ReadTable(int offset, int count) + { + using var stream = new MemoryStream(Data, offset, count * Header.DefinitionSize); + using var reader = new BinaryReader(stream); + var dest = new TableRecord[count]; + + for (int i = 0; i < dest.Length; i++) + { + var address = reader.ReadUInt32(); + var nameoffset = reader.ReadUInt32(); + var name = default(string); + + if (nameoffset < Data.Length) + name = ReadName(Data, (int)nameoffset); + + name ??= "Unknown"; + dest[i] = new TableRecord(name, address); + } + + return dest; + } + + private int sysreq_flg; + + public void ParseOp(AmxOpCode op, ref int cip, ref Cell tgt) + { + static void GETPARAM_P(Cell v, AmxOpCode o) { } // (v = ((Cell) (o) >> (int) (CellSize * 4)));} + switch (op) + { + case AmxOpCode.CONST: + case AmxOpCode.CONST_S: + cip += CellSize * 2; + break; + + /* Packed Instructions */ + case AmxOpCode.CONST_P_PRI: + case AmxOpCode.CONST_P_ALT: + case AmxOpCode.ADDR_P_PRI: + case AmxOpCode.ADDR_P_ALT: + case AmxOpCode.STRB_P_I: + case AmxOpCode.LIDX_P_B: + case AmxOpCode.IDXADDR_P_B: + case AmxOpCode.ALIGN_P_PRI: + case AmxOpCode.PUSH_P_C: + case AmxOpCode.PUSH_P: + case AmxOpCode.PUSH_P_S: + case AmxOpCode.STACK_P: + case AmxOpCode.HEAP_P: + case AmxOpCode.SHL_P_C_PRI: + case AmxOpCode.SHL_P_C_ALT: + case AmxOpCode.ADD_P_C: + case AmxOpCode.SMUL_P_C: + case AmxOpCode.ZERO_P: + case AmxOpCode.ZERO_P_S: + case AmxOpCode.EQ_P_C_PRI: + case AmxOpCode.EQ_P_C_ALT: + case AmxOpCode.MOVS_P: + case AmxOpCode.CMPS_P: + case AmxOpCode.FILL_P: + case AmxOpCode.HALT_P: + case AmxOpCode.BOUNDS_P: + case AmxOpCode.PUSH_P_ADR: + break; + + /* Packed Instructions referencing pointers */ + case AmxOpCode.LOAD_P_PRI: + case AmxOpCode.LOAD_P_ALT: + case AmxOpCode.INC_P: + case AmxOpCode.DEC_P: + GETPARAM_P(tgt, op); + break; + + /* Packed Instructions referencing stack */ + case AmxOpCode.LOAD_P_S_PRI: + case AmxOpCode.LOAD_P_S_ALT: + case AmxOpCode.LREF_P_S_PRI: + case AmxOpCode.LREF_P_S_ALT: + case AmxOpCode.INC_P_S: + case AmxOpCode.DEC_P_S: + GETPARAM_P(tgt, op); /* verify address */ + break; + + /* Single-Value Instructions */ + case AmxOpCode.LODB_I: + case AmxOpCode.CONST_PRI: + case AmxOpCode.CONST_ALT: + case AmxOpCode.ADDR_PRI: + case AmxOpCode.ADDR_ALT: + case AmxOpCode.STRB_I: + case AmxOpCode.LIDX_B: + case AmxOpCode.IDXADDR_B: + case AmxOpCode.ALIGN_PRI: + case AmxOpCode.LCTRL: + case AmxOpCode.SCTRL: + case AmxOpCode.PICK: + case AmxOpCode.PUSH_C: + case AmxOpCode.PUSH: + case AmxOpCode.PUSH_S: + case AmxOpCode.STACK: + case AmxOpCode.HEAP: + case AmxOpCode.SHL_C_PRI: + case AmxOpCode.SHL_C_ALT: + case AmxOpCode.ADD_C: + case AmxOpCode.SMUL_C: + case AmxOpCode.ZERO: + case AmxOpCode.ZERO_S: + case AmxOpCode.EQ_C_PRI: + case AmxOpCode.EQ_C_ALT: + case AmxOpCode.MOVS: + case AmxOpCode.CMPS: + case AmxOpCode.FILL: + case AmxOpCode.HALT: + case AmxOpCode.BOUNDS: + case AmxOpCode.PUSH_ADR: + cip += CellSize; + break; + + case AmxOpCode.LOAD_PRI: + case AmxOpCode.LOAD_ALT: + case AmxOpCode.INC: + case AmxOpCode.DEC: + //VerifyAddress(0, ); + cip += CellSize; + break; + + case AmxOpCode.LOAD_S_PRI: + case AmxOpCode.LOAD_S_ALT: + case AmxOpCode.LREF_S_PRI: + case AmxOpCode.LREF_S_ALT: + case AmxOpCode.INC_S: + case AmxOpCode.DEC_S: + cip += CellSize; + break; + + /* Parameterless Instructions */ + case AmxOpCode.LOAD_I: + case AmxOpCode.STOR_I: + case AmxOpCode.LIDX: + case AmxOpCode.IDXADDR: + case AmxOpCode.XCHG: + case AmxOpCode.PUSH_PRI: + case AmxOpCode.PUSH_ALT: + case AmxOpCode.PPRI: + case AmxOpCode.PALT: + case AmxOpCode.PROC: + case AmxOpCode.RET: + case AmxOpCode.RETN: + case AmxOpCode.SHL: + case AmxOpCode.SHR: + case AmxOpCode.SSHR: + case AmxOpCode.SMUL: + case AmxOpCode.SDIV: + case AmxOpCode.ADD: + case AmxOpCode.SUB: + case AmxOpCode.AND: + case AmxOpCode.OR: + case AmxOpCode.XOR: + case AmxOpCode.NOT: + case AmxOpCode.NEG: + case AmxOpCode.INVERT: + case AmxOpCode.ZERO_PRI: + case AmxOpCode.ZERO_ALT: + case AmxOpCode.EQ: + case AmxOpCode.NEQ: + case AmxOpCode.SLESS: + case AmxOpCode.SLEQ: + case AmxOpCode.SGRTR: + case AmxOpCode.SGEQ: + case AmxOpCode.INC_PRI: + case AmxOpCode.INC_ALT: + case AmxOpCode.INC_I: + case AmxOpCode.DEC_PRI: + case AmxOpCode.DEC_ALT: + case AmxOpCode.DEC_I: + case AmxOpCode.SWAP_PRI: + case AmxOpCode.SWAP_ALT: + case AmxOpCode.NOP: + case AmxOpCode.BREAK: + break; + + /* Jump w/ Relocation */ + case AmxOpCode.CALL: + case AmxOpCode.JUMP: + case AmxOpCode.JZER: + case AmxOpCode.JNZ: + case AmxOpCode.JEQ: + case AmxOpCode.JNEQ: + case AmxOpCode.JSLESS: + case AmxOpCode.JSLEQ: + case AmxOpCode.JSGRTR: + case AmxOpCode.JSGEQ: + case AmxOpCode.SWITCH: + /* if this file is an older version (absolute references instead of the + * current use of position-independent code), convert the parameter + * to position-independent code first + */ + cip += CellSize; + break; + + /* overlay opcodes (overlays must be enabled) */ + case AmxOpCode.ISWITCH: + Debug.Assert(Header.FileVersion >= 10); + /* drop through */ + goto case AmxOpCode.ICALL; + case AmxOpCode.ICALL: + cip += CellSize; + /* drop through */ + goto case AmxOpCode.IRETN; + case AmxOpCode.IRETN: + Debug.Assert(Header.Overlays != 0 && Header.Overlays != Header.NameTable); + //return AmxError.OVERLAY; /* no overlay callback */ + break; + case AmxOpCode.ICASETBL: + { + // Cell num; + //DBGPARAM(num); /* number of records follows the opcode */ + //cip += (2 * num + 1) * CellSize; + //if (Header.Overlays == 0) + // return AmxError.OVERLAY; /* no overlay callback */ + break; + } /* case */ + + case AmxOpCode.SYSREQ_C: + cip += CellSize; + sysreq_flg |= 0x01; /* mark SYSREQ found */ + break; + case AmxOpCode.SYSREQ_N: + cip += CellSize * 2; + sysreq_flg |= 0x02; /* mark SYSREQ.N found */ + break; + + case AmxOpCode.CASETBL: + { + DBGPARAM(out _); + //cip += (2 * num + 1) * CellSize; + break; + } + + default: + Header.Flags &= ~AmxFlags.VERIFY; + //return AmxError.INVINSTR; + break; + } + + static void DBGPARAM(out Cell v) => v = null; // v = (Cell)(amx->code + (int)cip), cip += CellSize) + } } diff --git a/pkNX.Structures/Scripts/AmxError.cs b/pkNX.Structures/Scripts/AmxError.cs index 78f92694..f70d6c29 100644 --- a/pkNX.Structures/Scripts/AmxError.cs +++ b/pkNX.Structures/Scripts/AmxError.cs @@ -1,37 +1,35 @@ -namespace pkNX.Structures -{ +namespace pkNX.Structures; #pragma warning disable CA1027 // Mark enums with FlagsAttribute - public enum AmxError +public enum AmxError #pragma warning restore CA1027 // Mark enums with FlagsAttribute - { - AMX_ERR_NONE, - /* reserve the first 15 error codes for exit codes of the abstract machine */ - EXIT, /* forced exit */ - ASSERT, /* assertion failed */ - STACKERR, /* stack/heap collision */ - BOUNDS, /* index out of bounds */ - MEMACCESS, /* invalid memory access */ - INVINSTR, /* invalid instruction */ - STACKLOW, /* stack underflow */ - HEAPLOW, /* heap underflow */ - CALLBACK, /* no callback, or invalid callback */ - NATIVE, /* native function failed */ - DIVIDE, /* divide by zero */ - SLEEP, /* go into sleepmode - code can be restarted */ - INVSTATE, /* no implementation for this state, no fall-back */ +{ + AMX_ERR_NONE, + /* reserve the first 15 error codes for exit codes of the abstract machine */ + EXIT, /* forced exit */ + ASSERT, /* assertion failed */ + STACKERR, /* stack/heap collision */ + BOUNDS, /* index out of bounds */ + MEMACCESS, /* invalid memory access */ + INVINSTR, /* invalid instruction */ + STACKLOW, /* stack underflow */ + HEAPLOW, /* heap underflow */ + CALLBACK, /* no callback, or invalid callback */ + NATIVE, /* native function failed */ + DIVIDE, /* divide by zero */ + SLEEP, /* go into sleepmode - code can be restarted */ + INVSTATE, /* no implementation for this state, no fall-back */ - MEMORY = 16, /* out of memory */ - FORMAT, /* invalid file format */ - VERSION, /* file is for a newer version of the AMX */ - NOTFOUND, /* function not found */ - INDEX, /* invalid index parameter (bad entry point) */ - DEBUG, /* debugger cannot run */ - INIT, /* AMX not initialized (or doubly initialized) */ - USERDATA, /* unable to set user data field (table full) */ - INIT_JIT, /* cannot initialize the JIT */ - PARAMS, /* parameter error */ - DOMAIN, /* domain error, expression result does not fit in range */ - GENERAL, /* general error (unknown or unspecific error) */ - OVERLAY, /* overlays are unsupported (JIT) or uninitialized */ - } -} \ No newline at end of file + MEMORY = 16, /* out of memory */ + FORMAT, /* invalid file format */ + VERSION, /* file is for a newer version of the AMX */ + NOTFOUND, /* function not found */ + INDEX, /* invalid index parameter (bad entry point) */ + DEBUG, /* debugger cannot run */ + INIT, /* AMX not initialized (or doubly initialized) */ + USERDATA, /* unable to set user data field (table full) */ + INIT_JIT, /* cannot initialize the JIT */ + PARAMS, /* parameter error */ + DOMAIN, /* domain error, expression result does not fit in range */ + GENERAL, /* general error (unknown or unspecific error) */ + OVERLAY, /* overlays are unsupported (JIT) or uninitialized */ +} diff --git a/pkNX.Structures/Scripts/AmxFlags.cs b/pkNX.Structures/Scripts/AmxFlags.cs index c6c359ae..de285ce1 100644 --- a/pkNX.Structures/Scripts/AmxFlags.cs +++ b/pkNX.Structures/Scripts/AmxFlags.cs @@ -1,57 +1,56 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Feature flags for the +/// +/// +/// Flag version listed here is for CUR_FILE_VERSION = 10, circa 2008 +/// +[Flags] +public enum AmxFlags : ushort { - /// - /// Feature flags for the - /// - /// - /// Flag version listed here is for CUR_FILE_VERSION = 10, circa 2008 - /// - [Flags] - public enum AmxFlags : ushort + NONE, + + /// All function calls use overlays + OVERLAY = 0x01, + + /// Symbolic info is available + DEBUG = 0x02, + + /// Compact encoding + COMPACT = 0x04, + + /// Script uses the sleep instruction (possible re-entry or power-down mode) + SLEEP = 0x08, + + /// No array bounds checking; no BREAK opcodes + NOCHECKS = 0x10, + + /// Data section is explicitly initialized + DSEG_INIT = 0x20, + + /// Script new (optimized) version of SYSREQ opcode + SYSREQN = 0x800, + + /// All native functions are registered + NTVREG = 0x1000, + + /// Abstract machine is JIT compiled + JITC = 0x2000, + + /// Busy verifying P-code + VERIFY = 0x4000, + + /// AMX has been initialized + INIT = 0x8000 +} + +public static class AmxFlagsExtensions +{ + public static bool HasFlagFast(this AmxFlags value, AmxFlags flag) { - NONE, - - /// All function calls use overlays - OVERLAY = 0x01, - - /// Symbolic info is available - DEBUG = 0x02, - - /// Compact encoding - COMPACT = 0x04, - - /// Script uses the sleep instruction (possible re-entry or power-down mode) - SLEEP = 0x08, - - /// No array bounds checking; no BREAK opcodes - NOCHECKS = 0x10, - - /// Data section is explicitly initialized - DSEG_INIT = 0x20, - - /// Script new (optimized) version of SYSREQ opcode - SYSREQN = 0x800, - - /// All native functions are registered - NTVREG = 0x1000, - - /// Abstract machine is JIT compiled - JITC = 0x2000, - - /// Busy verifying P-code - VERIFY = 0x4000, - - /// AMX has been initialized - INIT = 0x8000 + return (value & flag) != 0; } - - public static class AmxFlagsExtensions - { - public static bool HasFlagFast(this AmxFlags value, AmxFlags flag) - { - return (value & flag) != 0; - } - } -} \ No newline at end of file +} diff --git a/pkNX.Structures/Scripts/AmxHeader.cs b/pkNX.Structures/Scripts/AmxHeader.cs index 5a757a54..f376d9f5 100644 --- a/pkNX.Structures/Scripts/AmxHeader.cs +++ b/pkNX.Structures/Scripts/AmxHeader.cs @@ -1,272 +1,271 @@ -using System; +using System; using System.Collections.Generic; using System.Runtime.InteropServices; -namespace pkNX.Structures +namespace pkNX.Structures; + +[StructLayout(LayoutKind.Sequential)] +public class AmxHeader { - [StructLayout(LayoutKind.Sequential)] - public class AmxHeader + // Cell Size magic verification + public const ushort MAGIC_32 = 0xf1e0; + public const ushort MAGIC_64 = 0xf1e1; + public const ushort MAGIC_16 = 0xf1e2; + + /// Size of the "file" + public int Size; // 0x00 + + /// Signature + public ushort Magic; // 0x04 + + /// File format version + public byte FileVersion; // 0x06 + + /// Required version of the AMX + public byte AMXVersion; // 0x07 + + /// Feature flags + public AmxFlags Flags; // 0x08 + + /// Size of a definition record + public short DefinitionSize; // 0x0A + + /// Initial value of COD - code block + public int COD; // 0x0C + + /// initial value of DAT - data block + public int Data; // 0x10 + + /// Initial value of HEA - start of the heap + public int Heap; // 0x14 + + /// Initial value of STP - stack top + public int StackTop; // 0x18 + + /// Initial value of CIP - the instruction pointer + public int CurrentInstructionPointer; // 0x20 + + /// Offset to the "public functions" table + public int Publics; // 0x24 + + /// Offset to the "native functions" table + public int Natives; // 0x28 + + /// Offset to the table of libraries + public int Libraries; // 0x2C + + /// Offset to the "public variables" table + public int PublicVars; // 0x30 + + /// Offset to the "public tagnames" table + public int Tags; // 0x34 + + /// Offset to the name table + public int NameTable; // 0x38 + + /// Offset to the overlay table + public int Overlays; // 0x3C + + public int CellSize { - // Cell Size magic verification - public const ushort MAGIC_32 = 0xf1e0; - public const ushort MAGIC_64 = 0xf1e1; - public const ushort MAGIC_16 = 0xf1e2; - - /// Size of the "file" - public int Size; // 0x00 - - /// Signature - public ushort Magic; // 0x04 - - /// File format version - public byte FileVersion; // 0x06 - - /// Required version of the AMX - public byte AMXVersion; // 0x07 - - /// Feature flags - public AmxFlags Flags; // 0x08 - - /// Size of a definition record - public short DefinitionSize; // 0x0A - - /// Initial value of COD - code block - public int COD; // 0x0C - - /// initial value of DAT - data block - public int Data; // 0x10 - - /// Initial value of HEA - start of the heap - public int Heap; // 0x14 - - /// Initial value of STP - stack top - public int StackTop; // 0x18 - - /// Initial value of CIP - the instruction pointer - public int CurrentInstructionPointer; // 0x20 - - /// Offset to the "public functions" table - public int Publics; // 0x24 - - /// Offset to the "native functions" table - public int Natives; // 0x28 - - /// Offset to the table of libraries - public int Libraries; // 0x2C - - /// Offset to the "public variables" table - public int PublicVars; // 0x30 - - /// Offset to the "public tagnames" table - public int Tags; // 0x34 - - /// Offset to the name table - public int NameTable; // 0x38 - - /// Offset to the overlay table - public int Overlays; // 0x3C - - public int CellSize + get { - get + return Magic switch { - return Magic switch - { - MAGIC_16 => 16, - MAGIC_32 => 32, - MAGIC_64 => 64, - _ => throw new ArgumentException("Invalid Magic identifier.") - }; - } + MAGIC_16 => 16, + MAGIC_32 => 32, + MAGIC_64 => 64, + _ => throw new ArgumentException("Invalid Magic identifier.") + }; } } - - /* File format version - * 0 original version - * 1 opcodes JUMP.pri, SWITCH and CASETBL - * 2 compressed files - * 3 public variables - * 4 opcodes SWAP.pri/alt and PUSHADDR - * 5 tagnames table - * 6 reformatted header - * 7 name table, opcodes SYMTAG & SYSREQ.D - * 8 opcode BREAK, renewed debug interface - * 9 macro opcodes - * 10 position-independent code, overlays, packed instructions - * 11 relocating instructions for the native interface, reorganized instruction set - */ - - /// - /// Debug data at the end of an amx - /// - [StructLayout(LayoutKind.Sequential)] - public class AmxDebugHeader - { - public const ushort MAGIC_DEBUG = 0xf1ef; - - public int Size; - public ushort Magic; - public byte FileVersion; - public byte AMXVersion; - public AmxFlags Flags; - public short Files; - public short Lines; - public short Symbols; - public short Tags; - public short Automatons; - public short States; - - public const int SIZE = 36; - } - - public class TableRecord - { - public TableRecord(string name, uint address) - { - Name = name; - Address = address; - } - - public string Name { get; } - public uint Address { get; } - } - - public class Tag - { - public Tag(string name, uint tagID) - { - TagID = tagID; - Name = name; - } - - public uint TagID { get; } - public string Name { get; } - } - - public class Dimension - { - public Dimension(int tagID, Tag tag, int size) - { - TagID = tagID; - Tag = tag; - Size = size; - } - - public int TagID { get; } - public Tag Tag { get; } - public int Size { get; } - } - - public class Argument - { - public Argument(VariableType type, string name, int tagID, Tag tag, Dimension[] dims) - { - Type = type; - Name = name; - TagID = tagID; - Tag = tag; - Dimensions = dims; - } - - public int TagID { get; } - public VariableType Type { get; } - public string Name { get; } - public Tag Tag { get; } - public Dimension[] Dimensions { get; } - } - - public enum Register : uint - { - Pri, - Alt - } - - public enum Scope : uint - { - Global, - Local, - Static - } - - public class Variable - { - public Variable(int addr, int tagID, Tag tag, uint codeStart, - uint codeEnd, VariableType type, Scope scope, - string name, Dimension[] dims = null) - { - Address = addr; - TagID = (uint)tagID; - Tag = tag; - CodeStart = codeStart; - CodeEnd = codeEnd; - Type = type; - Scope = scope; - Name = name; - Dims = dims; - } - - public int Address { get; } - public uint CodeStart { get; } - public uint CodeEnd { get; } - public string Name { get; } - public VariableType Type { get; } - public Scope Scope { get; } - public Tag Tag { get; set; } - public uint TagID { get; } - public Dimension[] Dims { get; } - } - - public class Signature - { - public Signature(string name) => Name = name; - - public Tag ReturnType { get; set; } - public uint TagID { get; protected set; } - public string Name { get; } - - public Argument[] Args { get; protected set; } - } - - public class Native : Signature - { - public Native(string name, int index) : base(name) => Index = index; - - public int Index { get; } - - public void SetDebugInfo(int tagID, Tag tag, Argument[] args) - { - TagID = (uint)tagID; - ReturnType = tag; - Args = args; - } - } - - public class Function : Signature - { - public Function(uint addr, uint codeStart, uint codeEnd, string name, Tag tag) - : base(name) - { - Address = addr; - CodeStart = codeStart; - CodeEnd = codeEnd; - ReturnType = tag; - } - - public Function(uint addr, uint codeStart, uint codeEnd, string name, uint tagID) - : base(name) - { - Address = addr; - CodeStart = codeStart; - CodeEnd = codeEnd; - TagID = tagID; - } - - public void SetArguments(List from) => Args = from.ToArray(); - - public uint Address { get; } - public uint CodeStart { get; } - public uint CodeEnd { get; } - - public bool Within(uint pc) => pc >= CodeStart && pc < CodeEnd; - } +} + +/* File format version + * 0 original version + * 1 opcodes JUMP.pri, SWITCH and CASETBL + * 2 compressed files + * 3 public variables + * 4 opcodes SWAP.pri/alt and PUSHADDR + * 5 tagnames table + * 6 reformatted header + * 7 name table, opcodes SYMTAG & SYSREQ.D + * 8 opcode BREAK, renewed debug interface + * 9 macro opcodes + * 10 position-independent code, overlays, packed instructions + * 11 relocating instructions for the native interface, reorganized instruction set + */ + +/// +/// Debug data at the end of an amx +/// +[StructLayout(LayoutKind.Sequential)] +public class AmxDebugHeader +{ + public const ushort MAGIC_DEBUG = 0xf1ef; + + public int Size; + public ushort Magic; + public byte FileVersion; + public byte AMXVersion; + public AmxFlags Flags; + public short Files; + public short Lines; + public short Symbols; + public short Tags; + public short Automatons; + public short States; + + public const int SIZE = 36; +} + +public class TableRecord +{ + public TableRecord(string name, uint address) + { + Name = name; + Address = address; + } + + public string Name { get; } + public uint Address { get; } +} + +public class Tag +{ + public Tag(string name, uint tagID) + { + TagID = tagID; + Name = name; + } + + public uint TagID { get; } + public string Name { get; } +} + +public class Dimension +{ + public Dimension(int tagID, Tag tag, int size) + { + TagID = tagID; + Tag = tag; + Size = size; + } + + public int TagID { get; } + public Tag Tag { get; } + public int Size { get; } +} + +public class Argument +{ + public Argument(VariableType type, string name, int tagID, Tag tag, Dimension[] dims) + { + Type = type; + Name = name; + TagID = tagID; + Tag = tag; + Dimensions = dims; + } + + public int TagID { get; } + public VariableType Type { get; } + public string Name { get; } + public Tag Tag { get; } + public Dimension[] Dimensions { get; } +} + +public enum Register : uint +{ + Pri, + Alt +} + +public enum Scope : uint +{ + Global, + Local, + Static +} + +public class Variable +{ + public Variable(int addr, int tagID, Tag tag, uint codeStart, + uint codeEnd, VariableType type, Scope scope, + string name, Dimension[] dims = null) + { + Address = addr; + TagID = (uint)tagID; + Tag = tag; + CodeStart = codeStart; + CodeEnd = codeEnd; + Type = type; + Scope = scope; + Name = name; + Dims = dims; + } + + public int Address { get; } + public uint CodeStart { get; } + public uint CodeEnd { get; } + public string Name { get; } + public VariableType Type { get; } + public Scope Scope { get; } + public Tag Tag { get; set; } + public uint TagID { get; } + public Dimension[] Dims { get; } +} + +public class Signature +{ + public Signature(string name) => Name = name; + + public Tag ReturnType { get; set; } + public uint TagID { get; protected set; } + public string Name { get; } + + public Argument[] Args { get; protected set; } +} + +public class Native : Signature +{ + public Native(string name, int index) : base(name) => Index = index; + + public int Index { get; } + + public void SetDebugInfo(int tagID, Tag tag, Argument[] args) + { + TagID = (uint)tagID; + ReturnType = tag; + Args = args; + } +} + +public class Function : Signature +{ + public Function(uint addr, uint codeStart, uint codeEnd, string name, Tag tag) + : base(name) + { + Address = addr; + CodeStart = codeStart; + CodeEnd = codeEnd; + ReturnType = tag; + } + + public Function(uint addr, uint codeStart, uint codeEnd, string name, uint tagID) + : base(name) + { + Address = addr; + CodeStart = codeStart; + CodeEnd = codeEnd; + TagID = tagID; + } + + public void SetArguments(List from) => Args = from.ToArray(); + + public uint Address { get; } + public uint CodeStart { get; } + public uint CodeEnd { get; } + + public bool Within(uint pc) => pc >= CodeStart && pc < CodeEnd; } diff --git a/pkNX.Structures/Scripts/AmxOpCode.cs b/pkNX.Structures/Scripts/AmxOpCode.cs index 37cfafee..f42ede3e 100644 --- a/pkNX.Structures/Scripts/AmxOpCode.cs +++ b/pkNX.Structures/Scripts/AmxOpCode.cs @@ -1,253 +1,252 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +// https://github.com/gameswop/mtasa-resources/blob/d557a72fefef57ac34780a76edf16383d3dff0e8/%5Bgamemodes%5D/%5Bamx%5D/amx-deps/src/amx/amx.c#L143 +public enum AmxOpCode : uint { - // https://github.com/gameswop/mtasa-resources/blob/d557a72fefef57ac34780a76edf16383d3dff0e8/%5Bgamemodes%5D/%5Bamx%5D/amx-deps/src/amx/amx.c#L143 - public enum AmxOpCode : uint - { - NONE, - LOAD_PRI, - LOAD_ALT, - LOAD_S_PRI, - LOAD_S_ALT, - LREF_PRI, - LREF_ALT, - LREF_S_PRI, - LREF_S_ALT, - LOAD_I, - LODB_I, - CONST_PRI, - CONST_ALT, - ADDR_PRI, - ADDR_ALT, - STOR_PRI, - STOR_ALT, - STOR_S_PRI, - STOR_S_ALT, - SREF_PRI, - SREF_ALT, - SREF_S_PRI, - SREF_S_ALT, - STOR_I, - STRB_I, - LIDX, - LIDX_B, - IDXADDR, - IDXADDR_B, - ALIGN_PRI, - ALIGN_ALT, - LCTRL, - SCTRL, - MOVE_PRI, - MOVE_ALT, - XCHG, - PUSH_PRI, - PUSH_ALT, - PICK, - PUSH_C, - PUSH, - PUSH_S, - PPRI, - PALT, - STACK, - HEAP, - PROC, - RET, - RETN, - CALL, - CALL_PRI, - JUMP, - JREL, - JZER, - JNZ, - JEQ, - JNEQ, - JLESS, - JLEQ, - JGRTR, - JGEQ, - JSLESS, - JSLEQ, - JSGRTR, - JSGEQ, - SHL, - SHR, - SSHR, - SHL_C_PRI, - SHL_C_ALT, - SHR_C_PRI, - SHR_C_ALT, - SMUL, - SDIV, - SDIV_ALT, - UMUL, - UDIV, - UDIV_ALT, - ADD, - SUB, - SUB_ALT, - AND, - OR, - XOR, - NOT, - NEG, - INVERT, - ADD_C, - SMUL_C, - ZERO_PRI, - ZERO_ALT, - ZERO, - ZERO_S, - SIGN_PRI, - SIGN_ALT, - EQ, - NEQ, - LESS, - LEQ, - GRTR, - GEQ, - SLESS, - SLEQ, - SGRTR, - SGEQ, - EQ_C_PRI, - EQ_C_ALT, - INC_PRI, - INC_ALT, - INC, - INC_S, - INC_I, - DEC_PRI, - DEC_ALT, - DEC, - DEC_S, - DEC_I, - MOVS, - CMPS, - FILL, - HALT, - BOUNDS, - SYSREQ_PRI, - SYSREQ_C, - FILE, - LINE, - SYMBOL, - SRANGE, - JUMP_PRI, - SWITCH, - CASETBL, - SWAP_PRI, - SWAP_ALT, - PUSH_ADR, - NOP, - SYSREQ_N, - SYMTAG, - BREAK, - PUSH2_C, - PUSH2, - PUSH2_S, - PUSH2_ADR, - PUSH3_C, - PUSH3, - PUSH3_S, - PUSH3_ADR, - PUSH4_C, - PUSH4, - PUSH4_S, - PUSH4_ADR, - PUSH5_C, - PUSH5, - PUSH5_S, - PUSH5_ADR, - LOAD_BOTH, - LOAD_S_BOTH, - CONST, - CONST_S, - /* overlay instructions */ - ICALL, - IRETN, - ISWITCH, - ICASETBL, - /* packed instructions */ - LOAD_P_PRI, - LOAD_P_ALT, - LOAD_P_S_PRI, - LOAD_P_S_ALT, - LREF_P_PRI, - LREF_P_ALT, - LREF_P_S_PRI, - LREF_P_S_ALT, - LODB_P_I, - CONST_P_PRI, - CONST_P_ALT, - ADDR_P_PRI, - ADDR_P_ALT, - STOR_P_PRI, - STOR_P_ALT, - STOR_P_S_PRI, - STOR_P_S_ALT, - SREF_P_PRI, - SREF_P_ALT, - SREF_P_S_PRI, - SREF_P_S_ALT, - STRB_P_I, - LIDX_P_B, - IDXADDR_P_B, - ALIGN_P_PRI, - ALIGN_P_ALT, - PUSH_P_C, - PUSH_P, - PUSH_P_S, - STACK_P, - HEAP_P, - SHL_P_C_PRI, - SHL_P_C_ALT, - SHR_P_C_PRI, - SHR_P_C_ALT, - ADD_P_C, - SMUL_P_C, - ZERO_P, - ZERO_P_S, - EQ_P_C_PRI, - EQ_P_C_ALT, - INC_P, - INC_P_S, - DEC_P, - DEC_P_S, - MOVS_P, - CMPS_P, - FILL_P, - HALT_P, - BOUNDS_P, - PUSH_P_ADR, + NONE, + LOAD_PRI, + LOAD_ALT, + LOAD_S_PRI, + LOAD_S_ALT, + LREF_PRI, + LREF_ALT, + LREF_S_PRI, + LREF_S_ALT, + LOAD_I, + LODB_I, + CONST_PRI, + CONST_ALT, + ADDR_PRI, + ADDR_ALT, + STOR_PRI, + STOR_ALT, + STOR_S_PRI, + STOR_S_ALT, + SREF_PRI, + SREF_ALT, + SREF_S_PRI, + SREF_S_ALT, + STOR_I, + STRB_I, + LIDX, + LIDX_B, + IDXADDR, + IDXADDR_B, + ALIGN_PRI, + ALIGN_ALT, + LCTRL, + SCTRL, + MOVE_PRI, + MOVE_ALT, + XCHG, + PUSH_PRI, + PUSH_ALT, + PICK, + PUSH_C, + PUSH, + PUSH_S, + PPRI, + PALT, + STACK, + HEAP, + PROC, + RET, + RETN, + CALL, + CALL_PRI, + JUMP, + JREL, + JZER, + JNZ, + JEQ, + JNEQ, + JLESS, + JLEQ, + JGRTR, + JGEQ, + JSLESS, + JSLEQ, + JSGRTR, + JSGEQ, + SHL, + SHR, + SSHR, + SHL_C_PRI, + SHL_C_ALT, + SHR_C_PRI, + SHR_C_ALT, + SMUL, + SDIV, + SDIV_ALT, + UMUL, + UDIV, + UDIV_ALT, + ADD, + SUB, + SUB_ALT, + AND, + OR, + XOR, + NOT, + NEG, + INVERT, + ADD_C, + SMUL_C, + ZERO_PRI, + ZERO_ALT, + ZERO, + ZERO_S, + SIGN_PRI, + SIGN_ALT, + EQ, + NEQ, + LESS, + LEQ, + GRTR, + GEQ, + SLESS, + SLEQ, + SGRTR, + SGEQ, + EQ_C_PRI, + EQ_C_ALT, + INC_PRI, + INC_ALT, + INC, + INC_S, + INC_I, + DEC_PRI, + DEC_ALT, + DEC, + DEC_S, + DEC_I, + MOVS, + CMPS, + FILL, + HALT, + BOUNDS, + SYSREQ_PRI, + SYSREQ_C, + FILE, + LINE, + SYMBOL, + SRANGE, + JUMP_PRI, + SWITCH, + CASETBL, + SWAP_PRI, + SWAP_ALT, + PUSH_ADR, + NOP, + SYSREQ_N, + SYMTAG, + BREAK, + PUSH2_C, + PUSH2, + PUSH2_S, + PUSH2_ADR, + PUSH3_C, + PUSH3, + PUSH3_S, + PUSH3_ADR, + PUSH4_C, + PUSH4, + PUSH4_S, + PUSH4_ADR, + PUSH5_C, + PUSH5, + PUSH5_S, + PUSH5_ADR, + LOAD_BOTH, + LOAD_S_BOTH, + CONST, + CONST_S, + /* overlay instructions */ + ICALL, + IRETN, + ISWITCH, + ICASETBL, + /* packed instructions */ + LOAD_P_PRI, + LOAD_P_ALT, + LOAD_P_S_PRI, + LOAD_P_S_ALT, + LREF_P_PRI, + LREF_P_ALT, + LREF_P_S_PRI, + LREF_P_S_ALT, + LODB_P_I, + CONST_P_PRI, + CONST_P_ALT, + ADDR_P_PRI, + ADDR_P_ALT, + STOR_P_PRI, + STOR_P_ALT, + STOR_P_S_PRI, + STOR_P_S_ALT, + SREF_P_PRI, + SREF_P_ALT, + SREF_P_S_PRI, + SREF_P_S_ALT, + STRB_P_I, + LIDX_P_B, + IDXADDR_P_B, + ALIGN_P_PRI, + ALIGN_P_ALT, + PUSH_P_C, + PUSH_P, + PUSH_P_S, + STACK_P, + HEAP_P, + SHL_P_C_PRI, + SHL_P_C_ALT, + SHR_P_C_PRI, + SHR_P_C_ALT, + ADD_P_C, + SMUL_P_C, + ZERO_P, + ZERO_P_S, + EQ_P_C_PRI, + EQ_P_C_ALT, + INC_P, + INC_P_S, + DEC_P, + DEC_P_S, + MOVS_P, + CMPS_P, + FILL_P, + HALT_P, + BOUNDS_P, + PUSH_P_ADR, - SYSREQ_D, - SYSREQ_ND, - NUM_OPCODES, - } + SYSREQ_D, + SYSREQ_ND, + NUM_OPCODES, +} - public static class AmxOpCodeExtensions +public static class AmxOpCodeExtensions +{ + public static AmxOpCode Invert(this AmxOpCode spop) { - public static AmxOpCode Invert(this AmxOpCode spop) + return spop switch { - return spop switch - { - AmxOpCode.JSLEQ => AmxOpCode.JSGRTR, - AmxOpCode.JSLESS => AmxOpCode.JSGEQ, - AmxOpCode.JSGRTR => AmxOpCode.JSLEQ, - AmxOpCode.JSGEQ => AmxOpCode.JSLESS, - AmxOpCode.JEQ => AmxOpCode.JNEQ, - AmxOpCode.JNEQ => AmxOpCode.JEQ, - AmxOpCode.JNZ => AmxOpCode.JZER, - AmxOpCode.JZER => AmxOpCode.JNZ, - AmxOpCode.SLEQ => AmxOpCode.SGRTR, - AmxOpCode.SLESS => AmxOpCode.SGEQ, - AmxOpCode.SGRTR => AmxOpCode.SLEQ, - AmxOpCode.SGEQ => AmxOpCode.SLESS, - AmxOpCode.EQ => AmxOpCode.NEQ, - AmxOpCode.NEQ => AmxOpCode.EQ, - _ => throw new ArgumentException(nameof(spop)) - }; - } + AmxOpCode.JSLEQ => AmxOpCode.JSGRTR, + AmxOpCode.JSLESS => AmxOpCode.JSGEQ, + AmxOpCode.JSGRTR => AmxOpCode.JSLEQ, + AmxOpCode.JSGEQ => AmxOpCode.JSLESS, + AmxOpCode.JEQ => AmxOpCode.JNEQ, + AmxOpCode.JNEQ => AmxOpCode.JEQ, + AmxOpCode.JNZ => AmxOpCode.JZER, + AmxOpCode.JZER => AmxOpCode.JNZ, + AmxOpCode.SLEQ => AmxOpCode.SGRTR, + AmxOpCode.SLESS => AmxOpCode.SGEQ, + AmxOpCode.SGRTR => AmxOpCode.SLEQ, + AmxOpCode.SGEQ => AmxOpCode.SLESS, + AmxOpCode.EQ => AmxOpCode.NEQ, + AmxOpCode.NEQ => AmxOpCode.EQ, + _ => throw new ArgumentException(nameof(spop)) + }; } } diff --git a/pkNX.Structures/Scripts/AmxOpCodeType.cs b/pkNX.Structures/Scripts/AmxOpCodeType.cs index af7a5175..d9be24f3 100644 --- a/pkNX.Structures/Scripts/AmxOpCodeType.cs +++ b/pkNX.Structures/Scripts/AmxOpCodeType.cs @@ -1,16 +1,15 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum AmxOpCodeType { - public enum AmxOpCodeType - { - Unknown = -1, - NoParams, - OneParam, - TwoParams, - ThreeParams, - FourParams, - FiveParams, - Jump, - Packed, - CaseTable, - } -} \ No newline at end of file + Unknown = -1, + NoParams, + OneParam, + TwoParams, + ThreeParams, + FourParams, + FiveParams, + Jump, + Packed, + CaseTable, +} diff --git a/pkNX.Structures/Scripts/OpCodeTypeMappings.cs b/pkNX.Structures/Scripts/OpCodeTypeMappings.cs index d29591d5..954cecd3 100644 --- a/pkNX.Structures/Scripts/OpCodeTypeMappings.cs +++ b/pkNX.Structures/Scripts/OpCodeTypeMappings.cs @@ -1,229 +1,228 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static partial class PawnUtil { - public static partial class PawnUtil + public static readonly Dictionary OpCodeTypes = new() { - public static readonly Dictionary OpCodeTypes = new() - { - { AmxOpCode.NONE, AmxOpCodeType.NoParams }, - { AmxOpCode.LOAD_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.LOAD_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.LOAD_S_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.LOAD_S_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.LREF_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.LREF_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.LREF_S_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.LREF_S_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.LOAD_I, AmxOpCodeType.NoParams }, - { AmxOpCode.LODB_I, AmxOpCodeType.OneParam }, - { AmxOpCode.CONST_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.CONST_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.ADDR_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.ADDR_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.STOR_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.STOR_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.STOR_S_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.STOR_S_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.SREF_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.SREF_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.SREF_S_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.SREF_S_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.STOR_I, AmxOpCodeType.NoParams }, - { AmxOpCode.STRB_I, AmxOpCodeType.OneParam }, - { AmxOpCode.LIDX, AmxOpCodeType.NoParams }, - { AmxOpCode.LIDX_B, AmxOpCodeType.OneParam }, - { AmxOpCode.IDXADDR, AmxOpCodeType.NoParams }, - { AmxOpCode.IDXADDR_B, AmxOpCodeType.OneParam }, - { AmxOpCode.ALIGN_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.ALIGN_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.LCTRL, AmxOpCodeType.OneParam }, - { AmxOpCode.SCTRL, AmxOpCodeType.OneParam }, - { AmxOpCode.MOVE_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.MOVE_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.XCHG, AmxOpCodeType.NoParams }, - { AmxOpCode.PUSH_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.PUSH_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.PICK, AmxOpCodeType.OneParam }, - { AmxOpCode.PUSH_C, AmxOpCodeType.OneParam }, - { AmxOpCode.PUSH, AmxOpCodeType.OneParam }, - { AmxOpCode.PUSH_S, AmxOpCodeType.OneParam }, - { AmxOpCode.PPRI, AmxOpCodeType.NoParams }, - { AmxOpCode.PALT, AmxOpCodeType.NoParams }, - { AmxOpCode.STACK, AmxOpCodeType.OneParam }, - { AmxOpCode.HEAP, AmxOpCodeType.OneParam }, - { AmxOpCode.PROC, AmxOpCodeType.NoParams }, - { AmxOpCode.RET, AmxOpCodeType.NoParams }, - { AmxOpCode.RETN, AmxOpCodeType.NoParams }, - { AmxOpCode.CALL, AmxOpCodeType.Jump }, - { AmxOpCode.CALL_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.JUMP, AmxOpCodeType.Jump }, - { AmxOpCode.JREL, AmxOpCodeType.Jump }, - { AmxOpCode.JZER, AmxOpCodeType.Jump }, - { AmxOpCode.JNZ, AmxOpCodeType.Jump }, - { AmxOpCode.JEQ, AmxOpCodeType.Jump }, - { AmxOpCode.JNEQ, AmxOpCodeType.Jump }, - { AmxOpCode.JLESS, AmxOpCodeType.Jump }, - { AmxOpCode.JLEQ, AmxOpCodeType.Jump }, - { AmxOpCode.JGRTR, AmxOpCodeType.Jump }, - { AmxOpCode.JGEQ, AmxOpCodeType.Jump }, - { AmxOpCode.JSLESS, AmxOpCodeType.Jump }, - { AmxOpCode.JSLEQ, AmxOpCodeType.Jump }, - { AmxOpCode.JSGRTR, AmxOpCodeType.Jump }, - { AmxOpCode.JSGEQ, AmxOpCodeType.Jump }, - { AmxOpCode.SHL, AmxOpCodeType.NoParams }, - { AmxOpCode.SHR, AmxOpCodeType.NoParams }, - { AmxOpCode.SSHR, AmxOpCodeType.NoParams }, - { AmxOpCode.SHL_C_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.SHL_C_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.SHR_C_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.SHR_C_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.SMUL, AmxOpCodeType.NoParams }, - { AmxOpCode.SDIV, AmxOpCodeType.NoParams }, - { AmxOpCode.SDIV_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.UMUL, AmxOpCodeType.NoParams }, - { AmxOpCode.UDIV, AmxOpCodeType.NoParams }, - { AmxOpCode.UDIV_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.ADD, AmxOpCodeType.NoParams }, - { AmxOpCode.SUB, AmxOpCodeType.NoParams }, - { AmxOpCode.SUB_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.AND, AmxOpCodeType.NoParams }, - { AmxOpCode.OR, AmxOpCodeType.NoParams }, - { AmxOpCode.XOR, AmxOpCodeType.NoParams }, - { AmxOpCode.NOT, AmxOpCodeType.NoParams }, - { AmxOpCode.NEG, AmxOpCodeType.NoParams }, - { AmxOpCode.INVERT, AmxOpCodeType.NoParams }, - { AmxOpCode.ADD_C, AmxOpCodeType.OneParam }, - { AmxOpCode.SMUL_C, AmxOpCodeType.OneParam }, - { AmxOpCode.ZERO_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.ZERO_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.ZERO, AmxOpCodeType.OneParam }, - { AmxOpCode.ZERO_S, AmxOpCodeType.OneParam }, - { AmxOpCode.SIGN_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.SIGN_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.EQ, AmxOpCodeType.NoParams }, - { AmxOpCode.NEQ, AmxOpCodeType.NoParams }, - { AmxOpCode.LESS, AmxOpCodeType.NoParams }, - { AmxOpCode.LEQ, AmxOpCodeType.NoParams }, - { AmxOpCode.GRTR, AmxOpCodeType.NoParams }, - { AmxOpCode.GEQ, AmxOpCodeType.NoParams }, - { AmxOpCode.SLESS, AmxOpCodeType.NoParams }, - { AmxOpCode.SLEQ, AmxOpCodeType.NoParams }, - { AmxOpCode.SGRTR, AmxOpCodeType.NoParams }, - { AmxOpCode.SGEQ, AmxOpCodeType.NoParams }, - { AmxOpCode.EQ_C_PRI, AmxOpCodeType.OneParam }, - { AmxOpCode.EQ_C_ALT, AmxOpCodeType.OneParam }, - { AmxOpCode.INC_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.INC_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.INC, AmxOpCodeType.OneParam }, - { AmxOpCode.INC_S, AmxOpCodeType.OneParam }, - { AmxOpCode.INC_I, AmxOpCodeType.NoParams }, - { AmxOpCode.DEC_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.DEC_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.DEC, AmxOpCodeType.OneParam }, - { AmxOpCode.DEC_S, AmxOpCodeType.OneParam }, - { AmxOpCode.DEC_I, AmxOpCodeType.NoParams }, - { AmxOpCode.MOVS, AmxOpCodeType.OneParam }, - { AmxOpCode.CMPS, AmxOpCodeType.OneParam }, - { AmxOpCode.FILL, AmxOpCodeType.OneParam }, - { AmxOpCode.HALT, AmxOpCodeType.OneParam }, - { AmxOpCode.BOUNDS, AmxOpCodeType.OneParam }, - { AmxOpCode.SYSREQ_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.SYSREQ_C, AmxOpCodeType.OneParam }, - { AmxOpCode.FILE, AmxOpCodeType.ThreeParams }, - { AmxOpCode.LINE, AmxOpCodeType.TwoParams }, - { AmxOpCode.SYMBOL, AmxOpCodeType.FourParams }, - { AmxOpCode.SRANGE, AmxOpCodeType.TwoParams }, - { AmxOpCode.JUMP_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.SWITCH, AmxOpCodeType.Jump }, - { AmxOpCode.CASETBL, AmxOpCodeType.CaseTable }, - { AmxOpCode.SWAP_PRI, AmxOpCodeType.NoParams }, - { AmxOpCode.SWAP_ALT, AmxOpCodeType.NoParams }, - { AmxOpCode.PUSH_ADR, AmxOpCodeType.OneParam }, - { AmxOpCode.NOP, AmxOpCodeType.NoParams }, - { AmxOpCode.SYSREQ_N, AmxOpCodeType.TwoParams }, - { AmxOpCode.SYMTAG, AmxOpCodeType.OneParam }, - { AmxOpCode.BREAK, AmxOpCodeType.NoParams }, - { AmxOpCode.PUSH2_C, AmxOpCodeType.TwoParams }, - { AmxOpCode.PUSH2, AmxOpCodeType.TwoParams }, - { AmxOpCode.PUSH2_S, AmxOpCodeType.TwoParams }, - { AmxOpCode.PUSH2_ADR, AmxOpCodeType.TwoParams }, - { AmxOpCode.PUSH3_C, AmxOpCodeType.ThreeParams }, - { AmxOpCode.PUSH3, AmxOpCodeType.ThreeParams }, - { AmxOpCode.PUSH3_S, AmxOpCodeType.ThreeParams }, - { AmxOpCode.PUSH3_ADR, AmxOpCodeType.ThreeParams }, - { AmxOpCode.PUSH4_C, AmxOpCodeType.FourParams }, - { AmxOpCode.PUSH4, AmxOpCodeType.FourParams }, - { AmxOpCode.PUSH4_S, AmxOpCodeType.FourParams }, - { AmxOpCode.PUSH4_ADR, AmxOpCodeType.FourParams }, - { AmxOpCode.PUSH5_C, AmxOpCodeType.FiveParams }, - { AmxOpCode.PUSH5, AmxOpCodeType.FiveParams }, - { AmxOpCode.PUSH5_S, AmxOpCodeType.FiveParams }, - { AmxOpCode.PUSH5_ADR, AmxOpCodeType.FiveParams }, - { AmxOpCode.LOAD_BOTH, AmxOpCodeType.TwoParams }, - { AmxOpCode.LOAD_S_BOTH, AmxOpCodeType.TwoParams }, - { AmxOpCode.CONST, AmxOpCodeType.TwoParams }, - { AmxOpCode.CONST_S, AmxOpCodeType.TwoParams }, - /* overlay instructions */ - { AmxOpCode.ICALL, AmxOpCodeType.Jump }, - { AmxOpCode.IRETN, AmxOpCodeType.NoParams }, - { AmxOpCode.ISWITCH, AmxOpCodeType.Jump }, - { AmxOpCode.ICASETBL, AmxOpCodeType.CaseTable }, - /* packed instructions */ - { AmxOpCode.LOAD_P_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.LOAD_P_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.LOAD_P_S_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.LOAD_P_S_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.LREF_P_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.LREF_P_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.LREF_P_S_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.LREF_P_S_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.LODB_P_I, AmxOpCodeType.Packed }, - { AmxOpCode.CONST_P_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.CONST_P_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.ADDR_P_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.ADDR_P_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.STOR_P_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.STOR_P_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.STOR_P_S_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.STOR_P_S_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.SREF_P_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.SREF_P_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.SREF_P_S_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.SREF_P_S_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.STRB_P_I, AmxOpCodeType.Packed }, - { AmxOpCode.LIDX_P_B, AmxOpCodeType.Packed }, - { AmxOpCode.IDXADDR_P_B, AmxOpCodeType.Packed }, - { AmxOpCode.ALIGN_P_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.ALIGN_P_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.PUSH_P_C, AmxOpCodeType.Packed }, - { AmxOpCode.PUSH_P, AmxOpCodeType.Packed }, - { AmxOpCode.PUSH_P_S, AmxOpCodeType.Packed }, - { AmxOpCode.STACK_P, AmxOpCodeType.Packed }, - { AmxOpCode.HEAP_P, AmxOpCodeType.Packed }, - { AmxOpCode.SHL_P_C_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.SHL_P_C_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.SHR_P_C_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.SHR_P_C_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.ADD_P_C, AmxOpCodeType.Packed }, - { AmxOpCode.SMUL_P_C, AmxOpCodeType.Packed }, - { AmxOpCode.ZERO_P, AmxOpCodeType.Packed }, - { AmxOpCode.ZERO_P_S, AmxOpCodeType.Packed }, - { AmxOpCode.EQ_P_C_PRI, AmxOpCodeType.Packed }, - { AmxOpCode.EQ_P_C_ALT, AmxOpCodeType.Packed }, - { AmxOpCode.INC_P, AmxOpCodeType.Packed }, - { AmxOpCode.INC_P_S, AmxOpCodeType.Packed }, - { AmxOpCode.DEC_P, AmxOpCodeType.Packed }, - { AmxOpCode.DEC_P_S, AmxOpCodeType.Packed }, - { AmxOpCode.MOVS_P, AmxOpCodeType.Packed }, - { AmxOpCode.CMPS_P, AmxOpCodeType.Packed }, - { AmxOpCode.FILL_P, AmxOpCodeType.Packed }, - { AmxOpCode.HALT_P, AmxOpCodeType.Packed }, - { AmxOpCode.BOUNDS_P, AmxOpCodeType.Packed }, - { AmxOpCode.PUSH_P_ADR, AmxOpCodeType.Packed }, + { AmxOpCode.NONE, AmxOpCodeType.NoParams }, + { AmxOpCode.LOAD_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.LOAD_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.LOAD_S_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.LOAD_S_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.LREF_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.LREF_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.LREF_S_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.LREF_S_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.LOAD_I, AmxOpCodeType.NoParams }, + { AmxOpCode.LODB_I, AmxOpCodeType.OneParam }, + { AmxOpCode.CONST_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.CONST_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.ADDR_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.ADDR_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.STOR_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.STOR_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.STOR_S_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.STOR_S_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.SREF_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.SREF_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.SREF_S_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.SREF_S_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.STOR_I, AmxOpCodeType.NoParams }, + { AmxOpCode.STRB_I, AmxOpCodeType.OneParam }, + { AmxOpCode.LIDX, AmxOpCodeType.NoParams }, + { AmxOpCode.LIDX_B, AmxOpCodeType.OneParam }, + { AmxOpCode.IDXADDR, AmxOpCodeType.NoParams }, + { AmxOpCode.IDXADDR_B, AmxOpCodeType.OneParam }, + { AmxOpCode.ALIGN_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.ALIGN_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.LCTRL, AmxOpCodeType.OneParam }, + { AmxOpCode.SCTRL, AmxOpCodeType.OneParam }, + { AmxOpCode.MOVE_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.MOVE_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.XCHG, AmxOpCodeType.NoParams }, + { AmxOpCode.PUSH_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.PUSH_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.PICK, AmxOpCodeType.OneParam }, + { AmxOpCode.PUSH_C, AmxOpCodeType.OneParam }, + { AmxOpCode.PUSH, AmxOpCodeType.OneParam }, + { AmxOpCode.PUSH_S, AmxOpCodeType.OneParam }, + { AmxOpCode.PPRI, AmxOpCodeType.NoParams }, + { AmxOpCode.PALT, AmxOpCodeType.NoParams }, + { AmxOpCode.STACK, AmxOpCodeType.OneParam }, + { AmxOpCode.HEAP, AmxOpCodeType.OneParam }, + { AmxOpCode.PROC, AmxOpCodeType.NoParams }, + { AmxOpCode.RET, AmxOpCodeType.NoParams }, + { AmxOpCode.RETN, AmxOpCodeType.NoParams }, + { AmxOpCode.CALL, AmxOpCodeType.Jump }, + { AmxOpCode.CALL_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.JUMP, AmxOpCodeType.Jump }, + { AmxOpCode.JREL, AmxOpCodeType.Jump }, + { AmxOpCode.JZER, AmxOpCodeType.Jump }, + { AmxOpCode.JNZ, AmxOpCodeType.Jump }, + { AmxOpCode.JEQ, AmxOpCodeType.Jump }, + { AmxOpCode.JNEQ, AmxOpCodeType.Jump }, + { AmxOpCode.JLESS, AmxOpCodeType.Jump }, + { AmxOpCode.JLEQ, AmxOpCodeType.Jump }, + { AmxOpCode.JGRTR, AmxOpCodeType.Jump }, + { AmxOpCode.JGEQ, AmxOpCodeType.Jump }, + { AmxOpCode.JSLESS, AmxOpCodeType.Jump }, + { AmxOpCode.JSLEQ, AmxOpCodeType.Jump }, + { AmxOpCode.JSGRTR, AmxOpCodeType.Jump }, + { AmxOpCode.JSGEQ, AmxOpCodeType.Jump }, + { AmxOpCode.SHL, AmxOpCodeType.NoParams }, + { AmxOpCode.SHR, AmxOpCodeType.NoParams }, + { AmxOpCode.SSHR, AmxOpCodeType.NoParams }, + { AmxOpCode.SHL_C_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.SHL_C_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.SHR_C_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.SHR_C_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.SMUL, AmxOpCodeType.NoParams }, + { AmxOpCode.SDIV, AmxOpCodeType.NoParams }, + { AmxOpCode.SDIV_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.UMUL, AmxOpCodeType.NoParams }, + { AmxOpCode.UDIV, AmxOpCodeType.NoParams }, + { AmxOpCode.UDIV_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.ADD, AmxOpCodeType.NoParams }, + { AmxOpCode.SUB, AmxOpCodeType.NoParams }, + { AmxOpCode.SUB_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.AND, AmxOpCodeType.NoParams }, + { AmxOpCode.OR, AmxOpCodeType.NoParams }, + { AmxOpCode.XOR, AmxOpCodeType.NoParams }, + { AmxOpCode.NOT, AmxOpCodeType.NoParams }, + { AmxOpCode.NEG, AmxOpCodeType.NoParams }, + { AmxOpCode.INVERT, AmxOpCodeType.NoParams }, + { AmxOpCode.ADD_C, AmxOpCodeType.OneParam }, + { AmxOpCode.SMUL_C, AmxOpCodeType.OneParam }, + { AmxOpCode.ZERO_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.ZERO_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.ZERO, AmxOpCodeType.OneParam }, + { AmxOpCode.ZERO_S, AmxOpCodeType.OneParam }, + { AmxOpCode.SIGN_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.SIGN_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.EQ, AmxOpCodeType.NoParams }, + { AmxOpCode.NEQ, AmxOpCodeType.NoParams }, + { AmxOpCode.LESS, AmxOpCodeType.NoParams }, + { AmxOpCode.LEQ, AmxOpCodeType.NoParams }, + { AmxOpCode.GRTR, AmxOpCodeType.NoParams }, + { AmxOpCode.GEQ, AmxOpCodeType.NoParams }, + { AmxOpCode.SLESS, AmxOpCodeType.NoParams }, + { AmxOpCode.SLEQ, AmxOpCodeType.NoParams }, + { AmxOpCode.SGRTR, AmxOpCodeType.NoParams }, + { AmxOpCode.SGEQ, AmxOpCodeType.NoParams }, + { AmxOpCode.EQ_C_PRI, AmxOpCodeType.OneParam }, + { AmxOpCode.EQ_C_ALT, AmxOpCodeType.OneParam }, + { AmxOpCode.INC_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.INC_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.INC, AmxOpCodeType.OneParam }, + { AmxOpCode.INC_S, AmxOpCodeType.OneParam }, + { AmxOpCode.INC_I, AmxOpCodeType.NoParams }, + { AmxOpCode.DEC_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.DEC_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.DEC, AmxOpCodeType.OneParam }, + { AmxOpCode.DEC_S, AmxOpCodeType.OneParam }, + { AmxOpCode.DEC_I, AmxOpCodeType.NoParams }, + { AmxOpCode.MOVS, AmxOpCodeType.OneParam }, + { AmxOpCode.CMPS, AmxOpCodeType.OneParam }, + { AmxOpCode.FILL, AmxOpCodeType.OneParam }, + { AmxOpCode.HALT, AmxOpCodeType.OneParam }, + { AmxOpCode.BOUNDS, AmxOpCodeType.OneParam }, + { AmxOpCode.SYSREQ_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.SYSREQ_C, AmxOpCodeType.OneParam }, + { AmxOpCode.FILE, AmxOpCodeType.ThreeParams }, + { AmxOpCode.LINE, AmxOpCodeType.TwoParams }, + { AmxOpCode.SYMBOL, AmxOpCodeType.FourParams }, + { AmxOpCode.SRANGE, AmxOpCodeType.TwoParams }, + { AmxOpCode.JUMP_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.SWITCH, AmxOpCodeType.Jump }, + { AmxOpCode.CASETBL, AmxOpCodeType.CaseTable }, + { AmxOpCode.SWAP_PRI, AmxOpCodeType.NoParams }, + { AmxOpCode.SWAP_ALT, AmxOpCodeType.NoParams }, + { AmxOpCode.PUSH_ADR, AmxOpCodeType.OneParam }, + { AmxOpCode.NOP, AmxOpCodeType.NoParams }, + { AmxOpCode.SYSREQ_N, AmxOpCodeType.TwoParams }, + { AmxOpCode.SYMTAG, AmxOpCodeType.OneParam }, + { AmxOpCode.BREAK, AmxOpCodeType.NoParams }, + { AmxOpCode.PUSH2_C, AmxOpCodeType.TwoParams }, + { AmxOpCode.PUSH2, AmxOpCodeType.TwoParams }, + { AmxOpCode.PUSH2_S, AmxOpCodeType.TwoParams }, + { AmxOpCode.PUSH2_ADR, AmxOpCodeType.TwoParams }, + { AmxOpCode.PUSH3_C, AmxOpCodeType.ThreeParams }, + { AmxOpCode.PUSH3, AmxOpCodeType.ThreeParams }, + { AmxOpCode.PUSH3_S, AmxOpCodeType.ThreeParams }, + { AmxOpCode.PUSH3_ADR, AmxOpCodeType.ThreeParams }, + { AmxOpCode.PUSH4_C, AmxOpCodeType.FourParams }, + { AmxOpCode.PUSH4, AmxOpCodeType.FourParams }, + { AmxOpCode.PUSH4_S, AmxOpCodeType.FourParams }, + { AmxOpCode.PUSH4_ADR, AmxOpCodeType.FourParams }, + { AmxOpCode.PUSH5_C, AmxOpCodeType.FiveParams }, + { AmxOpCode.PUSH5, AmxOpCodeType.FiveParams }, + { AmxOpCode.PUSH5_S, AmxOpCodeType.FiveParams }, + { AmxOpCode.PUSH5_ADR, AmxOpCodeType.FiveParams }, + { AmxOpCode.LOAD_BOTH, AmxOpCodeType.TwoParams }, + { AmxOpCode.LOAD_S_BOTH, AmxOpCodeType.TwoParams }, + { AmxOpCode.CONST, AmxOpCodeType.TwoParams }, + { AmxOpCode.CONST_S, AmxOpCodeType.TwoParams }, + /* overlay instructions */ + { AmxOpCode.ICALL, AmxOpCodeType.Jump }, + { AmxOpCode.IRETN, AmxOpCodeType.NoParams }, + { AmxOpCode.ISWITCH, AmxOpCodeType.Jump }, + { AmxOpCode.ICASETBL, AmxOpCodeType.CaseTable }, + /* packed instructions */ + { AmxOpCode.LOAD_P_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.LOAD_P_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.LOAD_P_S_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.LOAD_P_S_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.LREF_P_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.LREF_P_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.LREF_P_S_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.LREF_P_S_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.LODB_P_I, AmxOpCodeType.Packed }, + { AmxOpCode.CONST_P_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.CONST_P_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.ADDR_P_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.ADDR_P_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.STOR_P_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.STOR_P_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.STOR_P_S_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.STOR_P_S_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.SREF_P_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.SREF_P_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.SREF_P_S_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.SREF_P_S_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.STRB_P_I, AmxOpCodeType.Packed }, + { AmxOpCode.LIDX_P_B, AmxOpCodeType.Packed }, + { AmxOpCode.IDXADDR_P_B, AmxOpCodeType.Packed }, + { AmxOpCode.ALIGN_P_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.ALIGN_P_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.PUSH_P_C, AmxOpCodeType.Packed }, + { AmxOpCode.PUSH_P, AmxOpCodeType.Packed }, + { AmxOpCode.PUSH_P_S, AmxOpCodeType.Packed }, + { AmxOpCode.STACK_P, AmxOpCodeType.Packed }, + { AmxOpCode.HEAP_P, AmxOpCodeType.Packed }, + { AmxOpCode.SHL_P_C_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.SHL_P_C_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.SHR_P_C_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.SHR_P_C_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.ADD_P_C, AmxOpCodeType.Packed }, + { AmxOpCode.SMUL_P_C, AmxOpCodeType.Packed }, + { AmxOpCode.ZERO_P, AmxOpCodeType.Packed }, + { AmxOpCode.ZERO_P_S, AmxOpCodeType.Packed }, + { AmxOpCode.EQ_P_C_PRI, AmxOpCodeType.Packed }, + { AmxOpCode.EQ_P_C_ALT, AmxOpCodeType.Packed }, + { AmxOpCode.INC_P, AmxOpCodeType.Packed }, + { AmxOpCode.INC_P_S, AmxOpCodeType.Packed }, + { AmxOpCode.DEC_P, AmxOpCodeType.Packed }, + { AmxOpCode.DEC_P_S, AmxOpCodeType.Packed }, + { AmxOpCode.MOVS_P, AmxOpCodeType.Packed }, + { AmxOpCode.CMPS_P, AmxOpCodeType.Packed }, + { AmxOpCode.FILL_P, AmxOpCodeType.Packed }, + { AmxOpCode.HALT_P, AmxOpCodeType.Packed }, + { AmxOpCode.BOUNDS_P, AmxOpCodeType.Packed }, + { AmxOpCode.PUSH_P_ADR, AmxOpCodeType.Packed }, - { AmxOpCode.SYSREQ_D, AmxOpCodeType.OneParam }, - { AmxOpCode.SYSREQ_ND, AmxOpCodeType.TwoParams }, - }; - } -} \ No newline at end of file + { AmxOpCode.SYSREQ_D, AmxOpCodeType.OneParam }, + { AmxOpCode.SYSREQ_ND, AmxOpCodeType.TwoParams }, + }; +} diff --git a/pkNX.Structures/Scripts/PawnUtil.cs b/pkNX.Structures/Scripts/PawnUtil.cs index 3162974d..37489a5a 100644 --- a/pkNX.Structures/Scripts/PawnUtil.cs +++ b/pkNX.Structures/Scripts/PawnUtil.cs @@ -2,342 +2,341 @@ using System.Collections.Generic; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static partial class PawnUtil { - public static partial class PawnUtil + // FireFly's (github.com/FireyFly) concise decompression (ported c->c#): + // https://github.com/FireyFly/poketools/blob/e74538a5b5e5dab1e78c1cd313c55d158f37534d/src/formats/script.c#L61 + public static uint[] QuickDecompress(byte[] data, int count) { - // FireFly's (github.com/FireyFly) concise decompression (ported c->c#): - // https://github.com/FireyFly/poketools/blob/e74538a5b5e5dab1e78c1cd313c55d158f37534d/src/formats/script.c#L61 - public static uint[] QuickDecompress(byte[] data, int count) + uint[] code = new uint[count]; + uint i = 0, j = 0, x = 0, f = 0; + while (i < code.Length) { - uint[] code = new uint[count]; - uint i = 0, j = 0, x = 0, f = 0; - while (i < code.Length) - { - int b = data[f++], - v = b & 0x7F, - c = b & 0x80; - if (++j == 1) // sign extension possible - x = (uint)((((v >> 6 == 0 ? 1 : 0) - 1) << 6) | v); // only for bit6 being set - else - x = (x << 7) | (byte)v; // shift data into place + int b = data[f++], + v = b & 0x7F, + c = b & 0x80; + if (++j == 1) // sign extension possible + x = (uint)((((v >> 6 == 0 ? 1 : 0) - 1) << 6) | v); // only for bit6 being set + else + x = (x << 7) | (byte)v; // shift data into place - if (c > 0) - continue; // more data to read + if (c > 0) + continue; // more data to read - code[i++] = x; - j = 0; // write finalized instruction - } - - return code; + code[i++] = x; + j = 0; // write finalized instruction } - // https://github.com/gameswop/mtasa-resources/blob/d557a72fefef57ac34780a76edf16383d3dff0e8/%5Bgamemodes%5D/%5Bamx%5D/amx-deps/src/amx/amx.c#L1119 - // Slightly more readable, but potentially slower - public static uint[] QuickDecompress2(byte[] data, int count) + return code; + } + + // https://github.com/gameswop/mtasa-resources/blob/d557a72fefef57ac34780a76edf16383d3dff0e8/%5Bgamemodes%5D/%5Bamx%5D/amx-deps/src/amx/amx.c#L1119 + // Slightly more readable, but potentially slower + public static uint[] QuickDecompress2(byte[] data, int count) + { + var memsize = count * sizeof(uint); + var instructions = new uint[count]; + int i = data.Length; + + while (i > 0) { - var memsize = count * sizeof(uint); - var instructions = new uint[count]; - int i = data.Length; - - while (i > 0) - { - uint cell = 0; - var shift = 0; - - do - { - i--; - cell |= (uint)(data[i] & 0x7f) << shift; - shift += 7; - } - while (i > 0 && (data[i - 1] & 0x80) != 0); - - if ((data[i] & 0x40) != 0) - { - while (shift < 8 * sizeof(uint)) - { - cell |= (uint)0xff << shift; - shift += 8; - } - } - - memsize -= sizeof(uint); - instructions[memsize / sizeof(uint)] = cell; - } - - return instructions; - } - - // Compression - /*public static byte[] CompressScript(byte[] data) - { - if (data == null || data.Length % 4 != 0) // Bad Input - return null; - using (MemoryStream mn = new MemoryStream()) - using (BinaryWriter bw = new BinaryWriter(mn)) - { - for ( var pos = 0; pos < data.Length; pos += 4 ) - { - byte[] db = data.Skip(pos).Take(4).ToArray(); - byte[] cb = CompressBytes(db); - bw.Write(cb); - } - return mn.ToArray(); - } - }*/ - - public static byte[] CompressScript(uint[] instructions) - => instructions.SelectMany(CompressInstruction).ToArray(); - - private static byte[] CompressInstruction(uint instruction) - { - var bytes = new List(); - var sign = (instruction & 0x80000000) > 0; - - // Signed (negative) values are handled opposite of unsigned (positive) values. - // Positive values are "done" when we've shifted the value down to zero, but - // we don't need to store the highest 1s in a signed value. We handle this by - // tracking the loop via a NOTed shadow copy of the instruction if it's signed. - var shadow = sign ? ~instruction : instruction; + uint cell = 0; + var shift = 0; do { - var least7 = instruction & 0b01111111; - var byteVal = (byte)least7; - - if (bytes.Count > 0) - { - // Continuation bit on all but the lowest byte - byteVal |= 0x80; - } - - bytes.Add(byteVal); - - instruction >>= 7; - shadow >>= 7; + i--; + cell |= (uint)(data[i] & 0x7f) << shift; + shift += 7; } - while (shadow != 0); + while (i > 0 && (data[i - 1] & 0x80) != 0); - if (bytes.Count < 5) + if ((data[i] & 0x40) != 0) { - // Ensure "sign bit" (bit just to the right of highest continuation bit) is - // correct. Add an extra empty continuation byte if we need to. Values can't - // be longer than 5 bytes, though. - - var signBit = sign ? 0x40 : 0x00; - - if ((bytes.Last() & 0x40) != signBit) - bytes.Add(sign ? (byte)0xFF : (byte)0x80); + while (shift < 8 * sizeof(uint)) + { + cell |= (uint)0xff << shift; + shift += 8; + } } - // Little endian to big endian - bytes.Reverse(); - - return bytes.ToArray(); + memsize -= sizeof(uint); + instructions[memsize / sizeof(uint)] = cell; } - // Interpreting - public static string[] ParseScript(uint[] cmd, int sanity = -1) - { - // sub_148CBC Moon v1.0 - List parse = new(); - const int sanityMode = 0; // todo - - string ErrorNear(int line, string error) - { - var start = Math.Max(line - 6, 0); - var end = Math.Min(line + 6, cmd.Length - 1); - var toPrint = cmd.Skip(start).Take(end - start); - var message = $"Error at line {line}:" + Environment.NewLine; - - message += string.Join(" ", toPrint.Select(b => $"{b:X2}")) + Environment.NewLine; - - for (var x = 0; x < line - start; x++) - message += " "; - - message += "^^" + Environment.NewLine; - message += error; - - return message; - } - - int i = 0; // Current Offset of decompressed instructions - while (i < cmd.Length) // read away - { - // Read a Command - - string instrLine; - var line = i; - var opcodeval = cmd[i++]; - var opcodesafe = opcodeval & 0xFFFF; - - if (!Enum.IsDefined(typeof(AmxOpCode), opcodesafe)) - throw new ArgumentException(ErrorNear(line, $"Invalid command ID: {opcodesafe:X4} ({opcodesafe})")); - - var opcode = (AmxOpCode)opcodesafe; - - if (!OpCodeTypes.TryGetValue(opcode, out var optype)) - throw new ArgumentException(ErrorNear(line, $"Unknown OpCode: {opcodesafe:X4} ({opcodesafe})")); - - switch (optype) - { - default: - throw new ArgumentException("Invalid Command Type"); - - case AmxOpCodeType.NoParams: - { - instrLine = EchoIntCommand(opcode); - break; - } - - case AmxOpCodeType.OneParam: - { - var param = (int)cmd[i++]; - - instrLine = EchoIntCommand(opcode, param); - break; - } - - case AmxOpCodeType.TwoParams: - { - var param1 = (int)cmd[i++]; - var param2 = (int)cmd[i++]; - - instrLine = EchoIntCommand(opcode, param1, param2); - break; - } - - case AmxOpCodeType.ThreeParams: - { - var param1 = (int)cmd[i++]; - var param2 = (int)cmd[i++]; - var param3 = (int)cmd[i++]; - - instrLine = EchoIntCommand(opcode, param1, param2, param3); - break; - } - - case AmxOpCodeType.FourParams: - { - var param1 = (int)cmd[i++]; - var param2 = (int)cmd[i++]; - var param3 = (int)cmd[i++]; - var param4 = (int)cmd[i++]; - - instrLine = EchoIntCommand(opcode, param1, param2, param3, param4); - break; - } - - case AmxOpCodeType.FiveParams: - { - var param1 = (int)cmd[i++]; - var param2 = (int)cmd[i++]; - var param3 = (int)cmd[i++]; - var param4 = (int)cmd[i++]; - var param5 = (int)cmd[i++]; - - instrLine = EchoIntCommand(opcode, param1, param2, param3, param4, param5); - break; - } - - case AmxOpCodeType.Jump: - { - var jumpOffset = (int)cmd[i++]; - var jumpDest = (line * 4) + jumpOffset; - - instrLine = $"{Commands[opcode].PadRight(MaxCommandLength, ' ')} => 0x{jumpDest:X4} ({jumpOffset})"; - break; - } - - case AmxOpCodeType.Packed: - { - var param = (short)(opcodeval >> 16); - - instrLine = EchoIntCommand(opcode, param); - break; - } - - case AmxOpCodeType.CaseTable: - { - //var jOffset = (i * 4) - 4; // this may be the correct jump start point... - var count = cmd[i++]; // switch case table - // sanity check - - // Populate Switch-Case Tree - var tree = new List(); - - // Cases - for (int j = 0; j < count; j++) - { - var jmp = (int)cmd[i++]; - var toOffset = ((i - 2) * 4) + jmp; - var ifValue = (int)cmd[i++]; - tree.Add($"\t{ifValue} => 0x{toOffset:X4} ({jmp})"); - } - - // Default - { - int jmp = (int)cmd[i++]; - var toOffset = ((i - 2) * 4) + jmp; - tree.Add($"\t* => 0x{toOffset:X4} ({jmp})"); - } - - instrLine = Commands[opcode] + Environment.NewLine + string.Join(Environment.NewLine, tree); - break; - } - } - - if (opcode is AmxOpCode.RET or AmxOpCode.RETN or AmxOpCode.IRETN) - { - // Newline after return - instrLine += Environment.NewLine; - } - - if (parse.Count == 0 && opcode == AmxOpCode.HALT_P) - { - // Newline after 0x0000 HALT.P - instrLine += Environment.NewLine; - } - - parse.Add($"0x{line * 4:X4}: [{opcodeval & 0x7FF:X2}] {instrLine}"); - } - - if (sanity >= 0 && sanity != sanityMode) - throw new ArgumentException(); - - return parse.ToArray(); - } - - internal static string[] ParseMovement(uint[] cmd) => Util.GetHexLines(cmd); - - internal static string EchoIntCommand(AmxOpCode c, params int[] arr) - { - static string FormatParameter(int param) - { - if (param is < -100 or > 100) - return $"0x{param:X4}"; - return param.ToString(); - } - - string commandLeft = Commands[c].PadRight(MaxCommandLength, ' '); - string parameters = arr.Length == 0 ? "" : string.Join(", ", arr.Select(FormatParameter)); - return $"{commandLeft} {parameters}"; - } - - private static readonly Func getFloat = val => BitConverter.ToSingle(BitConverter.GetBytes(val), 0); - - internal static string EchoFloatCommand(AmxOpCode c, params uint[] arr) - { - string commandLeft = Commands[c].PadRight(MaxCommandLength, ' '); - string parameters = arr.Length == 1 ? "" : string.Join(", ", arr.Select(getFloat)); - return $"{commandLeft} {parameters}"; - } - - private static readonly Dictionary Commands = Enum.GetValues(typeof(AmxOpCode)) - .Cast() - .ToDictionary(v => v, v => v.ToString().Replace('_', '.')); - - private static readonly int MaxCommandLength = Commands.Values.Max(cmd => cmd.Length); + return instructions; } -} \ No newline at end of file + + // Compression + /*public static byte[] CompressScript(byte[] data) + { + if (data == null || data.Length % 4 != 0) // Bad Input + return null; + using (MemoryStream mn = new MemoryStream()) + using (BinaryWriter bw = new BinaryWriter(mn)) + { + for ( var pos = 0; pos < data.Length; pos += 4 ) + { + byte[] db = data.Skip(pos).Take(4).ToArray(); + byte[] cb = CompressBytes(db); + bw.Write(cb); + } + return mn.ToArray(); + } + }*/ + + public static byte[] CompressScript(uint[] instructions) + => instructions.SelectMany(CompressInstruction).ToArray(); + + private static byte[] CompressInstruction(uint instruction) + { + var bytes = new List(); + var sign = (instruction & 0x80000000) > 0; + + // Signed (negative) values are handled opposite of unsigned (positive) values. + // Positive values are "done" when we've shifted the value down to zero, but + // we don't need to store the highest 1s in a signed value. We handle this by + // tracking the loop via a NOTed shadow copy of the instruction if it's signed. + var shadow = sign ? ~instruction : instruction; + + do + { + var least7 = instruction & 0b01111111; + var byteVal = (byte)least7; + + if (bytes.Count > 0) + { + // Continuation bit on all but the lowest byte + byteVal |= 0x80; + } + + bytes.Add(byteVal); + + instruction >>= 7; + shadow >>= 7; + } + while (shadow != 0); + + if (bytes.Count < 5) + { + // Ensure "sign bit" (bit just to the right of highest continuation bit) is + // correct. Add an extra empty continuation byte if we need to. Values can't + // be longer than 5 bytes, though. + + var signBit = sign ? 0x40 : 0x00; + + if ((bytes.Last() & 0x40) != signBit) + bytes.Add(sign ? (byte)0xFF : (byte)0x80); + } + + // Little endian to big endian + bytes.Reverse(); + + return bytes.ToArray(); + } + + // Interpreting + public static string[] ParseScript(uint[] cmd, int sanity = -1) + { + // sub_148CBC Moon v1.0 + List parse = new(); + const int sanityMode = 0; // todo + + string ErrorNear(int line, string error) + { + var start = Math.Max(line - 6, 0); + var end = Math.Min(line + 6, cmd.Length - 1); + var toPrint = cmd.Skip(start).Take(end - start); + var message = $"Error at line {line}:" + Environment.NewLine; + + message += string.Join(" ", toPrint.Select(b => $"{b:X2}")) + Environment.NewLine; + + for (var x = 0; x < line - start; x++) + message += " "; + + message += "^^" + Environment.NewLine; + message += error; + + return message; + } + + int i = 0; // Current Offset of decompressed instructions + while (i < cmd.Length) // read away + { + // Read a Command + + string instrLine; + var line = i; + var opcodeval = cmd[i++]; + var opcodesafe = opcodeval & 0xFFFF; + + if (!Enum.IsDefined(typeof(AmxOpCode), opcodesafe)) + throw new ArgumentException(ErrorNear(line, $"Invalid command ID: {opcodesafe:X4} ({opcodesafe})")); + + var opcode = (AmxOpCode)opcodesafe; + + if (!OpCodeTypes.TryGetValue(opcode, out var optype)) + throw new ArgumentException(ErrorNear(line, $"Unknown OpCode: {opcodesafe:X4} ({opcodesafe})")); + + switch (optype) + { + default: + throw new ArgumentException("Invalid Command Type"); + + case AmxOpCodeType.NoParams: + { + instrLine = EchoIntCommand(opcode); + break; + } + + case AmxOpCodeType.OneParam: + { + var param = (int)cmd[i++]; + + instrLine = EchoIntCommand(opcode, param); + break; + } + + case AmxOpCodeType.TwoParams: + { + var param1 = (int)cmd[i++]; + var param2 = (int)cmd[i++]; + + instrLine = EchoIntCommand(opcode, param1, param2); + break; + } + + case AmxOpCodeType.ThreeParams: + { + var param1 = (int)cmd[i++]; + var param2 = (int)cmd[i++]; + var param3 = (int)cmd[i++]; + + instrLine = EchoIntCommand(opcode, param1, param2, param3); + break; + } + + case AmxOpCodeType.FourParams: + { + var param1 = (int)cmd[i++]; + var param2 = (int)cmd[i++]; + var param3 = (int)cmd[i++]; + var param4 = (int)cmd[i++]; + + instrLine = EchoIntCommand(opcode, param1, param2, param3, param4); + break; + } + + case AmxOpCodeType.FiveParams: + { + var param1 = (int)cmd[i++]; + var param2 = (int)cmd[i++]; + var param3 = (int)cmd[i++]; + var param4 = (int)cmd[i++]; + var param5 = (int)cmd[i++]; + + instrLine = EchoIntCommand(opcode, param1, param2, param3, param4, param5); + break; + } + + case AmxOpCodeType.Jump: + { + var jumpOffset = (int)cmd[i++]; + var jumpDest = (line * 4) + jumpOffset; + + instrLine = $"{Commands[opcode].PadRight(MaxCommandLength, ' ')} => 0x{jumpDest:X4} ({jumpOffset})"; + break; + } + + case AmxOpCodeType.Packed: + { + var param = (short)(opcodeval >> 16); + + instrLine = EchoIntCommand(opcode, param); + break; + } + + case AmxOpCodeType.CaseTable: + { + //var jOffset = (i * 4) - 4; // this may be the correct jump start point... + var count = cmd[i++]; // switch case table + // sanity check + + // Populate Switch-Case Tree + var tree = new List(); + + // Cases + for (int j = 0; j < count; j++) + { + var jmp = (int)cmd[i++]; + var toOffset = ((i - 2) * 4) + jmp; + var ifValue = (int)cmd[i++]; + tree.Add($"\t{ifValue} => 0x{toOffset:X4} ({jmp})"); + } + + // Default + { + int jmp = (int)cmd[i++]; + var toOffset = ((i - 2) * 4) + jmp; + tree.Add($"\t* => 0x{toOffset:X4} ({jmp})"); + } + + instrLine = Commands[opcode] + Environment.NewLine + string.Join(Environment.NewLine, tree); + break; + } + } + + if (opcode is AmxOpCode.RET or AmxOpCode.RETN or AmxOpCode.IRETN) + { + // Newline after return + instrLine += Environment.NewLine; + } + + if (parse.Count == 0 && opcode == AmxOpCode.HALT_P) + { + // Newline after 0x0000 HALT.P + instrLine += Environment.NewLine; + } + + parse.Add($"0x{line * 4:X4}: [{opcodeval & 0x7FF:X2}] {instrLine}"); + } + + if (sanity >= 0 && sanity != sanityMode) + throw new ArgumentException(); + + return parse.ToArray(); + } + + internal static string[] ParseMovement(uint[] cmd) => Util.GetHexLines(cmd); + + internal static string EchoIntCommand(AmxOpCode c, params int[] arr) + { + static string FormatParameter(int param) + { + if (param is < -100 or > 100) + return $"0x{param:X4}"; + return param.ToString(); + } + + string commandLeft = Commands[c].PadRight(MaxCommandLength, ' '); + string parameters = arr.Length == 0 ? "" : string.Join(", ", arr.Select(FormatParameter)); + return $"{commandLeft} {parameters}"; + } + + private static readonly Func getFloat = val => BitConverter.ToSingle(BitConverter.GetBytes(val), 0); + + internal static string EchoFloatCommand(AmxOpCode c, params uint[] arr) + { + string commandLeft = Commands[c].PadRight(MaxCommandLength, ' '); + string parameters = arr.Length == 1 ? "" : string.Join(", ", arr.Select(getFloat)); + return $"{commandLeft} {parameters}"; + } + + private static readonly Dictionary Commands = Enum.GetValues(typeof(AmxOpCode)) + .Cast() + .ToDictionary(v => v, v => v.ToString().Replace('_', '.')); + + private static readonly int MaxCommandLength = Commands.Values.Max(cmd => cmd.Length); +} diff --git a/pkNX.Structures/Scripts/VariableType.cs b/pkNX.Structures/Scripts/VariableType.cs index f8f6085a..43e5793c 100644 --- a/pkNX.Structures/Scripts/VariableType.cs +++ b/pkNX.Structures/Scripts/VariableType.cs @@ -1,34 +1,33 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum VariableType : uint { - public enum VariableType : uint - { - Normal, - Reference, - Array, - ArrayReference, - Variadic - } + Normal, + Reference, + Array, + ArrayReference, + Variadic +} - public static class VariableTypeExtensions - { - private const byte IDENT_VARIABLE = 1; - private const byte IDENT_REFERENCE = 2; - private const byte IDENT_ARRAY = 3; - private const byte IDENT_REFARRAY = 4; - //private const byte IDENT_FUNCTION = 9; - private const byte IDENT_VARARGS = 11; +public static class VariableTypeExtensions +{ + private const byte IDENT_VARIABLE = 1; + private const byte IDENT_REFERENCE = 2; + private const byte IDENT_ARRAY = 3; + private const byte IDENT_REFARRAY = 4; + //private const byte IDENT_FUNCTION = 9; + private const byte IDENT_VARARGS = 11; - public static VariableType FromIdent(this byte ident) + public static VariableType FromIdent(this byte ident) + { + return ident switch { - return ident switch - { - IDENT_VARIABLE => VariableType.Normal, - IDENT_REFERENCE => VariableType.Reference, - IDENT_ARRAY => VariableType.Array, - IDENT_REFARRAY => VariableType.ArrayReference, - IDENT_VARARGS => VariableType.Variadic, - _ => VariableType.Normal - }; - } + IDENT_VARIABLE => VariableType.Normal, + IDENT_REFERENCE => VariableType.Reference, + IDENT_ARRAY => VariableType.Array, + IDENT_REFARRAY => VariableType.ArrayReference, + IDENT_VARARGS => VariableType.Variadic, + _ => VariableType.Normal + }; } -} \ No newline at end of file +} diff --git a/pkNX.Structures/StructConverter.cs b/pkNX.Structures/StructConverter.cs index c7eb70e5..eb2c047d 100644 --- a/pkNX.Structures/StructConverter.cs +++ b/pkNX.Structures/StructConverter.cs @@ -1,46 +1,45 @@ -using System; +using System; using System.Runtime.InteropServices; -namespace pkNX.Structures +namespace pkNX.Structures; + +internal static class StructConverter { - internal static class StructConverter + public static T ToStructure(this byte[] bytes) where T : struct { - public static T ToStructure(this byte[] bytes) where T : struct - { - var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } - finally { handle.Free(); } - } + var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } + finally { handle.Free(); } + } - public static T ToClass(this byte[] bytes) where T : class - { - var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); - try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } - finally { handle.Free(); } - } + public static T ToClass(this byte[] bytes) where T : class + { + var handle = GCHandle.Alloc(bytes, GCHandleType.Pinned); + try { return (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T)); } + finally { handle.Free(); } + } - public static byte[] ToBytesClass(this T obj) where T : class - { - int size = Marshal.SizeOf(obj); - byte[] arr = new byte[size]; + public static byte[] ToBytesClass(this T obj) where T : class + { + int size = Marshal.SizeOf(obj); + byte[] arr = new byte[size]; - IntPtr ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(obj, ptr, true); - Marshal.Copy(ptr, arr, 0, size); - Marshal.FreeHGlobal(ptr); - return arr; - } + IntPtr ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + Marshal.Copy(ptr, arr, 0, size); + Marshal.FreeHGlobal(ptr); + return arr; + } - public static byte[] ToBytes(this T obj) where T : struct - { - int size = Marshal.SizeOf(obj); - byte[] arr = new byte[size]; + public static byte[] ToBytes(this T obj) where T : struct + { + int size = Marshal.SizeOf(obj); + byte[] arr = new byte[size]; - IntPtr ptr = Marshal.AllocHGlobal(size); - Marshal.StructureToPtr(obj, ptr, true); - Marshal.Copy(ptr, arr, 0, size); - Marshal.FreeHGlobal(ptr); - return arr; - } + IntPtr ptr = Marshal.AllocHGlobal(size); + Marshal.StructureToPtr(obj, ptr, true); + Marshal.Copy(ptr, arr, 0, size); + Marshal.FreeHGlobal(ptr); + return arr; } } diff --git a/pkNX.Structures/TableUtil.cs b/pkNX.Structures/TableUtil.cs index 4759e873..a454b4d7 100644 --- a/pkNX.Structures/TableUtil.cs +++ b/pkNX.Structures/TableUtil.cs @@ -1,111 +1,110 @@ -using System; +using System; using System.Collections; using System.Collections.Generic; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static class TableUtil { - public static class TableUtil + /// + /// Converts an enumerable list of to a tab separated sheet. + /// + /// Object Type + /// Array of type T + /// 2 dimensional sheet of cells + public static string GetTable(IEnumerable arr) where T : class => string.Join(Environment.NewLine, GetTableRaw(arr)); + + private const string sep = "\t"; + private static IEnumerable GetTableRaw(IEnumerable arr) => Table(arr).Select(row => string.Join(sep, row)); + private static IEnumerable GetTableRaw(IEnumerable arr, Type t) => Table(arr, t).Select(row => string.Join(sep, row)); + + public static string GetNamedTable(IEnumerable arr, IList names, string name = null) { - /// - /// Converts an enumerable list of to a tab separated sheet. - /// - /// Object Type - /// Array of type T - /// 2 dimensional sheet of cells - public static string GetTable(IEnumerable arr) where T : class => string.Join(Environment.NewLine, GetTableRaw(arr)); + var list = GetTableRaw(arr).ToArray(); - private const string sep = "\t"; - private static IEnumerable GetTableRaw(IEnumerable arr) => Table(arr).Select(row => string.Join(sep, row)); - private static IEnumerable GetTableRaw(IEnumerable arr, Type t) => Table(arr, t).Select(row => string.Join(sep, row)); + // slap in name to column header + list[0] = $"Index{sep}{name ?? typeof(T).Name}{sep}{list[0]}"; - public static string GetNamedTable(IEnumerable arr, IList names, string name = null) - { - var list = GetTableRaw(arr).ToArray(); + // slap in row name to row + for (int i = 1; i < list.Length; i++) + list[i] = $"{i - 1}{sep}{names[i - 1]}{sep}{list[i]}"; - // slap in name to column header - list[0] = $"Index{sep}{name ?? typeof(T).Name}{sep}{list[0]}"; + return string.Join(Environment.NewLine, list); + } - // slap in row name to row - for (int i = 1; i < list.Length; i++) - list[i] = $"{i - 1}{sep}{names[i - 1]}{sep}{list[i]}"; + public static string GetNamedTypeTable(IList arr, IList names, string name = null) + { + var t = arr[0].GetType(); + if (t.Name.StartsWith("tableReader_")) // flatbuffer generated wrapper + t = t.BaseType; + var list = GetTableRaw(arr, t).ToArray(); - return string.Join(Environment.NewLine, list); - } + // slap in name to column header + list[0] = $"Index{sep}{name ?? t.Name}{sep}{list[0]}"; - public static string GetNamedTypeTable(IList arr, IList names, string name = null) - { - var t = arr[0].GetType(); - if (t.Name.StartsWith("tableReader_")) // flatbuffer generated wrapper - t = t.BaseType; - var list = GetTableRaw(arr, t).ToArray(); + // slap in row name to row + for (int i = 1; i < names.Count + 1; i++) + list[i] = $"{i - 1}{sep}{names[i - 1]}{sep}{list[i]}"; - // slap in name to column header - list[0] = $"Index{sep}{name ?? t.Name}{sep}{list[0]}"; + return string.Join(Environment.NewLine, list); + } - // slap in row name to row - for (int i = 1; i < names.Count + 1; i++) - list[i] = $"{i - 1}{sep}{names[i - 1]}{sep}{list[i]}"; + private static IEnumerable> Table(IEnumerable arr) + { + var type = typeof(T); + yield return GetNames(type); + foreach (var z in arr) + yield return GetValues(z, type); + } - return string.Join(Environment.NewLine, list); - } + private static IEnumerable> Table(IEnumerable arr, Type type) + { + yield return GetNames(type); + foreach (var z in arr) + yield return GetValues(z, type); + } - private static IEnumerable> Table(IEnumerable arr) - { - var type = typeof(T); - yield return GetNames(type); - foreach (var z in arr) - yield return GetValues(z, type); - } + private static IEnumerable GetNames(Type type) + { + foreach (var z in type.GetProperties()) + yield return z.Name; + foreach (var z in type.GetFields()) + yield return z.Name; + } - private static IEnumerable> Table(IEnumerable arr, Type type) - { - yield return GetNames(type); - foreach (var z in arr) - yield return GetValues(z, type); - } + private static IEnumerable GetValues(object obj, Type type) + { + foreach (var z in type.GetProperties()) + yield return GetFormattedString(z.GetValue(obj, null)); - private static IEnumerable GetNames(Type type) - { - foreach (var z in type.GetProperties()) - yield return z.Name; - foreach (var z in type.GetFields()) - yield return z.Name; - } + foreach (var z in type.GetFields()) + yield return GetFormattedString(z.GetValue(obj)); + } - private static IEnumerable GetValues(object obj, Type type) - { - foreach (var z in type.GetProperties()) - yield return GetFormattedString(z.GetValue(obj, null)); + private static string GetFormattedString(object obj) + { + if (obj == null) + return string.Empty; + if (obj is ulong u) + return u.ToString("X16"); + if (obj is IEnumerable x and not string) + return string.Join("|", JoinEnumerator(x.GetEnumerator()).Select(GetFormattedString)); - foreach (var z in type.GetFields()) - yield return GetFormattedString(z.GetValue(obj)); - } + var objType = obj.GetType(); + if (objType.IsEnum) + return obj.ToString(); + var mi = objType.GetMethods().First(z => z.Name == nameof(obj.ToString)); + if (mi.DeclaringType == objType) + return obj.ToString(); - private static string GetFormattedString(object obj) - { - if (obj == null) - return string.Empty; - if (obj is ulong u) - return u.ToString("X16"); - if (obj is IEnumerable x and not string) - return string.Join("|", JoinEnumerator(x.GetEnumerator()).Select(GetFormattedString)); + var props = objType.GetProperties(); + return string.Join("|", props.Select(z => GetFormattedString(z.GetValue(obj)))); + } - var objType = obj.GetType(); - if (objType.IsEnum) - return obj.ToString(); - var mi = objType.GetMethods().First(z => z.Name == nameof(obj.ToString)); - if (mi.DeclaringType == objType) - return obj.ToString(); - - var props = objType.GetProperties(); - return string.Join("|", props.Select(z => GetFormattedString(z.GetValue(obj)))); - } - - private static IEnumerable JoinEnumerator(IEnumerator x) - { - while (x.MoveNext()) - yield return x.Current; - } + private static IEnumerable JoinEnumerator(IEnumerator x) + { + while (x.MoveNext()) + yield return x.Current; } } diff --git a/pkNX.Structures/Text/TextConfig.cs b/pkNX.Structures/Text/TextConfig.cs index c440b417..ff550e69 100644 --- a/pkNX.Structures/Text/TextConfig.cs +++ b/pkNX.Structures/Text/TextConfig.cs @@ -1,47 +1,46 @@ -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +/// +/// Version specific text parsing configuration object to interact with text variable codes. +/// +public class TextConfig { + internal static readonly TextConfig Default = new(GameVersion.Any); + private static readonly char[] _trim_hex = { '0', 'x' }; + private readonly TextVariableCode[] Variables; + + public IEnumerable GetVariableList() => Variables.Select(z => $"{z.Code:X4}={z.Name}"); + public TextConfig(GameVersion game) => Variables = TextVariableCode.GetVariables(game); + + private TextVariableCode GetCode(string name) => Array.Find(Variables, v => v.Name == name); + private TextVariableCode GetName(int value) => Array.Find(Variables, v => v.Code == value); + /// - /// Version specific text parsing configuration object to interact with text variable codes. + /// Gets the machine-friendly variable instruction code to be written to the data. /// - public class TextConfig + /// Variable name + public ushort GetVariableNumber(string variable) { - internal static readonly TextConfig Default = new(GameVersion.Any); - private static readonly char[] _trim_hex = { '0', 'x' }; - private readonly TextVariableCode[] Variables; + var v = GetCode(variable); + if (v != null) + return (ushort)v.Code; + if (ushort.TryParse(variable.TrimStart(_trim_hex), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) + return result; + throw new ArgumentException($"Variable parse error: {variable}. Expected a hexadecimal value or standard variable code."); + } - public IEnumerable GetVariableList() => Variables.Select(z => $"{z.Code:X4}={z.Name}"); - public TextConfig(GameVersion game) => Variables = TextVariableCode.GetVariables(game); - - private TextVariableCode GetCode(string name) => Array.Find(Variables, v => v.Name == name); - private TextVariableCode GetName(int value) => Array.Find(Variables, v => v.Code == value); - - /// - /// Gets the machine-friendly variable instruction code to be written to the data. - /// - /// Variable name - public ushort GetVariableNumber(string variable) - { - var v = GetCode(variable); - if (v != null) - return (ushort)v.Code; - if (ushort.TryParse(variable.TrimStart(_trim_hex), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) - return result; - throw new ArgumentException($"Variable parse error: {variable}. Expected a hexadecimal value or standard variable code."); - } - - /// - /// Gets the human-friendly variable instruction name to be written to the output text line. - /// - /// Variable code - public string GetVariableString(ushort variable) - { - var v = GetName(variable); - return v?.Name ?? variable.ToString("X4"); - } + /// + /// Gets the human-friendly variable instruction name to be written to the output text line. + /// + /// Variable code + public string GetVariableString(ushort variable) + { + var v = GetName(variable); + return v?.Name ?? variable.ToString("X4"); } } diff --git a/pkNX.Structures/Text/TextFile.cs b/pkNX.Structures/Text/TextFile.cs index 891891ed..f45bd3ef 100644 --- a/pkNX.Structures/Text/TextFile.cs +++ b/pkNX.Structures/Text/TextFile.cs @@ -1,395 +1,394 @@ -using System; +using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class TextFile { - public class TextFile + public bool SETEMPTYTEXT { get; set; } = true; + + // Text Formatting Config + private const ushort KEY_BASE = 0x7C89; + private const ushort KEY_ADVANCE = 0x2983; + private const ushort KEY_VARIABLE = 0x0010; + private const ushort KEY_TERMINATOR = 0x0000; + private const ushort KEY_TEXTRETURN = 0xBE00; + private const ushort KEY_TEXTCLEAR = 0xBE01; + private const ushort KEY_TEXTWAIT = 0xBE02; + private const ushort KEY_TEXTNULL = 0xBDFF; + private static readonly byte[] emptyTextFile = { 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00 }; + + public TextFile(byte[] data = null, TextConfig config = null, bool remapChars = false) { - public bool SETEMPTYTEXT { get; set; } = true; + Data = (byte[])(data ?? emptyTextFile).Clone(); - // Text Formatting Config - private const ushort KEY_BASE = 0x7C89; - private const ushort KEY_ADVANCE = 0x2983; - private const ushort KEY_VARIABLE = 0x0010; - private const ushort KEY_TERMINATOR = 0x0000; - private const ushort KEY_TEXTRETURN = 0xBE00; - private const ushort KEY_TEXTCLEAR = 0xBE01; - private const ushort KEY_TEXTWAIT = 0xBE02; - private const ushort KEY_TEXTNULL = 0xBDFF; - private static readonly byte[] emptyTextFile = { 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00 }; + if (InitialKey != 0) + throw new Exception("Invalid initial key! Not 0?"); + if (SectionDataOffset + TotalLength != Data.Length || TextSections != 1) + throw new Exception("Invalid Text File"); + if (SectionLength != TotalLength) + throw new Exception("Section size and overall size do not match."); - public TextFile(byte[] data = null, TextConfig config = null, bool remapChars = false) + Config = config ?? TextConfig.Default; + RemapChars = remapChars; + } + + public byte[] Data; + private readonly TextConfig Config; + private readonly bool RemapChars; + + private ushort TextSections { get => BitConverter.ToUInt16(Data, 0x0); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0); } // Always 0x0001 + private ushort LineCount { get => BitConverter.ToUInt16(Data, 0x2); set => BitConverter.GetBytes(value).CopyTo(Data, 0x2); } + private uint TotalLength { get => BitConverter.ToUInt32(Data, 0x4); set => BitConverter.GetBytes(value).CopyTo(Data, 0x4); } + private uint InitialKey => BitConverter.ToUInt32(Data, 0x8); // Always 0x00000000 + private uint SectionDataOffset { get => BitConverter.ToUInt32(Data, 0xC); set => BitConverter.GetBytes(value).CopyTo(Data, 0xC); } // Always 0x0010 + private uint SectionLength { get => BitConverter.ToUInt32(Data, (int)SectionDataOffset); set => BitConverter.GetBytes(value).CopyTo(Data, SectionDataOffset); } + + private TextLine[] LineOffsets + { + get { - Data = (byte[])(data ?? emptyTextFile).Clone(); - - if (InitialKey != 0) - throw new Exception("Invalid initial key! Not 0?"); - if (SectionDataOffset + TotalLength != Data.Length || TextSections != 1) - throw new Exception("Invalid Text File"); - if (SectionLength != TotalLength) - throw new Exception("Section size and overall size do not match."); - - Config = config ?? TextConfig.Default; - RemapChars = remapChars; - } - - public byte[] Data; - private readonly TextConfig Config; - private readonly bool RemapChars; - - private ushort TextSections { get => BitConverter.ToUInt16(Data, 0x0); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0); } // Always 0x0001 - private ushort LineCount { get => BitConverter.ToUInt16(Data, 0x2); set => BitConverter.GetBytes(value).CopyTo(Data, 0x2); } - private uint TotalLength { get => BitConverter.ToUInt32(Data, 0x4); set => BitConverter.GetBytes(value).CopyTo(Data, 0x4); } - private uint InitialKey => BitConverter.ToUInt32(Data, 0x8); // Always 0x00000000 - private uint SectionDataOffset { get => BitConverter.ToUInt32(Data, 0xC); set => BitConverter.GetBytes(value).CopyTo(Data, 0xC); } // Always 0x0010 - private uint SectionLength { get => BitConverter.ToUInt32(Data, (int)SectionDataOffset); set => BitConverter.GetBytes(value).CopyTo(Data, SectionDataOffset); } - - private TextLine[] LineOffsets - { - get + TextLine[] result = new TextLine[LineCount]; + int sdo = (int)SectionDataOffset; + for (int i = 0; i < result.Length; i++) { - TextLine[] result = new TextLine[LineCount]; - int sdo = (int)SectionDataOffset; - for (int i = 0; i < result.Length; i++) + result[i] = new TextLine { - result[i] = new TextLine - { - Offset = BitConverter.ToInt32(Data, (i * 8) + sdo + 4) + sdo, - Length = BitConverter.ToInt16(Data, (i * 8) + sdo + 8) - }; - } - - return result; - } - set - { - if (value == null) - return; - int sdo = (int)SectionDataOffset; - for (int i = 0; i < value.Length; i++) - { - BitConverter.GetBytes(value[i].Offset).CopyTo(Data, (i * 8) + sdo + 4); - BitConverter.GetBytes(value[i].Length).CopyTo(Data, (i * 8) + sdo + 8); - } + Offset = BitConverter.ToInt32(Data, (i * 8) + sdo + 4) + sdo, + Length = BitConverter.ToInt16(Data, (i * 8) + sdo + 8) + }; } + + return result; } - - public byte[] GetEncryptedLine(int index) + set { - ushort key = GetLineKey(index); - var line = LineOffsets[index]; - byte[] EncryptedLineData = new byte[line.Length * 2]; - Array.Copy(Data, line.Offset, EncryptedLineData, 0, EncryptedLineData.Length); - - return CryptLineData(EncryptedLineData, key); - } - - private static ushort GetLineKey(int index) - { - ushort key = KEY_BASE; - for (int i = 0; i < index; i++) - key += KEY_ADVANCE; - return key; - } - - public byte[][] LineData - { - get - { - ushort key = KEY_BASE; - var result = new byte[LineCount][]; - var lines = LineOffsets; - for (int i = 0; i < lines.Length; i++) - { - byte[] EncryptedLineData = new byte[lines[i].Length * 2]; - Array.Copy(Data, lines[i].Offset, EncryptedLineData, 0, EncryptedLineData.Length); - - result[i] = CryptLineData(EncryptedLineData, key); - key += KEY_ADVANCE; - } - return result; - } - set - { - // rebuild LineInfo - var lines = new TextLine[value.Length]; - int bytesUsed = 0; - for (int i = 0; i < lines.Length; i++) - { - lines[i] = new TextLine { Offset = 4 + (8 * value.Length) + bytesUsed, Length = value[i].Length / 2 }; - bytesUsed += value[i].Length; - } - - // Apply Line Data - int sdo = (int)SectionDataOffset; - Array.Resize(ref Data, sdo + 4 + (8 * value.Length) + bytesUsed); - LineOffsets = lines; - value.SelectMany(i => i).ToArray().CopyTo(Data, Data.Length - bytesUsed); - TotalLength = SectionLength = (uint)(Data.Length - sdo); - LineCount = (ushort)value.Length; - } - } - - public string[] Lines - { - get => LineData.Select(GetLineString).ToArray(); - set => LineData = ConvertLinesToData(value); - } - - private byte[][] ConvertLinesToData(string[] value) - { - value ??= Array.Empty(); - - ushort key = KEY_BASE; - var lineData = new byte[value.Length][]; + if (value == null) + return; + int sdo = (int)SectionDataOffset; for (int i = 0; i < value.Length; i++) { - string text = value[i]?.Trim() ?? string.Empty; - if (text.Length == 0 && SETEMPTYTEXT) - text = $"[~ {i}]"; - byte[] DecryptedLineData = GetLineData(text); - lineData[i] = CryptLineData(DecryptedLineData, key); - if (lineData[i].Length % 4 == 2) - Array.Resize(ref lineData[i], lineData[i].Length + 2); - key += KEY_ADVANCE; + BitConverter.GetBytes(value[i].Offset).CopyTo(Data, (i * 8) + sdo + 4); + BitConverter.GetBytes(value[i].Length).CopyTo(Data, (i * 8) + sdo + 8); } - - return lineData; } + } - private static byte[] CryptLineData(byte[] data, ushort key) + public byte[] GetEncryptedLine(int index) + { + ushort key = GetLineKey(index); + var line = LineOffsets[index]; + byte[] EncryptedLineData = new byte[line.Length * 2]; + Array.Copy(Data, line.Offset, EncryptedLineData, 0, EncryptedLineData.Length); + + return CryptLineData(EncryptedLineData, key); + } + + private static ushort GetLineKey(int index) + { + ushort key = KEY_BASE; + for (int i = 0; i < index; i++) + key += KEY_ADVANCE; + return key; + } + + public byte[][] LineData + { + get { - byte[] result = (byte[])data.Clone(); - for (int i = 0; i < result.Length; i += 2) + ushort key = KEY_BASE; + var result = new byte[LineCount][]; + var lines = LineOffsets; + for (int i = 0; i < lines.Length; i++) { - result[i + 0] ^= (byte)key; - result[i + 1] ^= (byte)(key >> 8); - key = (ushort)(key << 3 | key >> 13); + byte[] EncryptedLineData = new byte[lines[i].Length * 2]; + Array.Copy(Data, lines[i].Offset, EncryptedLineData, 0, EncryptedLineData.Length); + + result[i] = CryptLineData(EncryptedLineData, key); + key += KEY_ADVANCE; } return result; } - - private byte[] GetLineData(string line) + set { - if (line == null) - return new byte[2]; - - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - int i = 0; - while (i < line.Length) + // rebuild LineInfo + var lines = new TextLine[value.Length]; + int bytesUsed = 0; + for (int i = 0; i < lines.Length; i++) { - ushort val = line[i++]; - val = TryRemapChar(val); - - switch (val) - { - case '[': - // grab the string - int bracket = line.IndexOf(']', i); - if (bracket < 0) - throw new ArgumentException("Variable text is not capped properly: " + line); - string varText = line[i..bracket]; - var varValues = GetVariableValues(varText); - foreach (ushort v in varValues) bw.Write(v); - i += 1 + varText.Length; - break; - case '\\': - var escapeValues = GetEscapeValues(line[i++]); - foreach (ushort v in escapeValues) - bw.Write(v); - break; - default: - bw.Write(val); - break; - } - } - bw.Write(KEY_TERMINATOR); // cap the line off - return ms.ToArray(); - } - - private ushort TryRemapChar(ushort val) - { - if (!RemapChars) - return val; - return val switch - { - 0x202F => 0xE07F // nbsp - , - 0x2026 => 0xE08D // … - , - 0x2642 => 0xE08E // ♂ - , - 0x2640 => 0xE08F // ♀ - , - _ => val - }; - } - - private ushort TryUnmapChar(ushort val) - { - if (!RemapChars) - return val; - return val switch - { - 0xE07F => 0x202F // nbsp - , - 0xE08D => 0x2026 // … - , - 0xE08E => 0x2642 // ♂ - , - 0xE08F => 0x2640 // ♀ - , - _ => val - }; - } - - private string GetLineString(byte[] data) - { - if (data == null) - return null; - - var s = new StringBuilder(); - int i = 0; - while (i < data.Length) - { - ushort val = BitConverter.ToUInt16(data, i); - if (val == KEY_TERMINATOR) - break; - i += 2; - - switch (val) - { - case KEY_VARIABLE: s.Append(GetVariableString(Config, data, ref i)); break; - case '\n': s.Append(@"\n"); break; - case '\\': s.Append(@"\\"); break; - case '[': s.Append(@"\["); break; - default: s.Append((char)TryUnmapChar(val)); break; - } - } - return s.ToString(); // Shouldn't get hit if the string is properly terminated. - } - - private static string GetVariableString(TextConfig config, byte[] data, ref int i) - { - var s = new StringBuilder(); - ushort count = BitConverter.ToUInt16(data, i); i += 2; - ushort variable = BitConverter.ToUInt16(data, i); i += 2; - - switch (variable) - { - case KEY_TEXTRETURN: // "Waitbutton then scroll text \r" - return "\\r"; - case KEY_TEXTCLEAR: // "Waitbutton then clear text \c" - return "\\c"; - case KEY_TEXTWAIT: // Dramatic pause for a text line. New! - ushort time = BitConverter.ToUInt16(data, i); i += 2; - return $"[WAIT {time}]"; - case KEY_TEXTNULL: // Empty Text line? Includes linenum so maybe for betatest finding used-unused lines? - ushort line = BitConverter.ToUInt16(data, i); i += 2; - return $"[~ {line}]"; + lines[i] = new TextLine { Offset = 4 + (8 * value.Length) + bytesUsed, Length = value[i].Length / 2 }; + bytesUsed += value[i].Length; } - string varName = config.GetVariableString(variable); - - s.Append("[VAR").Append(" ").Append(varName); - if (count > 1) - { - s.Append('('); - while (count > 1) - { - ushort arg = BitConverter.ToUInt16(data, i); i += 2; - s.Append(arg.ToString("X4")); - if (--count == 1) break; - s.Append(","); - } - s.Append(')'); - } - s.Append("]"); - return s.ToString(); - } - - private static IEnumerable GetEscapeValues(char esc) - { - var vals = new List(); - switch (esc) - { - case 'n': vals.Add('\n'); return vals; - case '\\': vals.Add('\\'); return vals; - case '[': vals.Add('['); return vals; - case 'r': vals.AddRange(new ushort[] { KEY_VARIABLE, 1, KEY_TEXTRETURN }); return vals; - case 'c': vals.AddRange(new ushort[] { KEY_VARIABLE, 1, KEY_TEXTCLEAR }); return vals; - default: throw new Exception("Invalid terminated line: \\" + esc); - } - } - - private IEnumerable GetVariableValues(string variable) - { - string[] split = variable.Split(' '); - if (split.Length < 2) - throw new ArgumentException("Incorrectly formatted variable text: " + variable); - - var vals = new List { KEY_VARIABLE }; - switch (split[0]) - { - case "~": // Blank Text Line Variable (No text set - debug/quality testing variable?) - vals.Add(1); - vals.Add(KEY_TEXTNULL); - vals.Add(Convert.ToUInt16(split[1])); - break; - case "WAIT": // Event pause Variable. - vals.Add(1); - vals.Add(KEY_TEXTWAIT); - vals.Add(Convert.ToUInt16(split[1])); - break; - case "VAR": // Text Variable - vals.AddRange(GetVariableParameters(split[1])); - break; - default: throw new Exception("Unknown variable method type: " + variable); - } - return vals; - } - - private IEnumerable GetVariableParameters(string text) - { - var vals = new List(); - int bracket = text.IndexOf('('); - bool noArgs = bracket < 0; - string variable = noArgs ? text : text[..bracket]; - ushort varVal = Config.GetVariableNumber(variable); - - if (!noArgs) - { - string[] args = text.Substring(bracket + 1, text.Length - bracket - 2).Split(','); - vals.Add((ushort)(1 + args.Length)); - vals.Add(varVal); - vals.AddRange(args.Select(t => Convert.ToUInt16(t, 16))); - } - else - { - vals.Add(1); - vals.Add(varVal); - } - return vals; - } - - // Exposed Methods - public static string[] GetStrings(byte[] data, TextConfig config = null, bool remapChars = false) - { - try - { - var t = new TextFile(data, config, remapChars); - return t.Lines; - } - catch { return null; } - } - - public static byte[] GetBytes(string[] lines, TextConfig config = null, bool remapChars = false) - { - return new TextFile(config: config, remapChars: remapChars) { Lines = lines }.Data; + // Apply Line Data + int sdo = (int)SectionDataOffset; + Array.Resize(ref Data, sdo + 4 + (8 * value.Length) + bytesUsed); + LineOffsets = lines; + value.SelectMany(i => i).ToArray().CopyTo(Data, Data.Length - bytesUsed); + TotalLength = SectionLength = (uint)(Data.Length - sdo); + LineCount = (ushort)value.Length; } } + + public string[] Lines + { + get => LineData.Select(GetLineString).ToArray(); + set => LineData = ConvertLinesToData(value); + } + + private byte[][] ConvertLinesToData(string[] value) + { + value ??= Array.Empty(); + + ushort key = KEY_BASE; + var lineData = new byte[value.Length][]; + for (int i = 0; i < value.Length; i++) + { + string text = value[i]?.Trim() ?? string.Empty; + if (text.Length == 0 && SETEMPTYTEXT) + text = $"[~ {i}]"; + byte[] DecryptedLineData = GetLineData(text); + lineData[i] = CryptLineData(DecryptedLineData, key); + if (lineData[i].Length % 4 == 2) + Array.Resize(ref lineData[i], lineData[i].Length + 2); + key += KEY_ADVANCE; + } + + return lineData; + } + + private static byte[] CryptLineData(byte[] data, ushort key) + { + byte[] result = (byte[])data.Clone(); + for (int i = 0; i < result.Length; i += 2) + { + result[i + 0] ^= (byte)key; + result[i + 1] ^= (byte)(key >> 8); + key = (ushort)(key << 3 | key >> 13); + } + return result; + } + + private byte[] GetLineData(string line) + { + if (line == null) + return new byte[2]; + + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + int i = 0; + while (i < line.Length) + { + ushort val = line[i++]; + val = TryRemapChar(val); + + switch (val) + { + case '[': + // grab the string + int bracket = line.IndexOf(']', i); + if (bracket < 0) + throw new ArgumentException("Variable text is not capped properly: " + line); + string varText = line[i..bracket]; + var varValues = GetVariableValues(varText); + foreach (ushort v in varValues) bw.Write(v); + i += 1 + varText.Length; + break; + case '\\': + var escapeValues = GetEscapeValues(line[i++]); + foreach (ushort v in escapeValues) + bw.Write(v); + break; + default: + bw.Write(val); + break; + } + } + bw.Write(KEY_TERMINATOR); // cap the line off + return ms.ToArray(); + } + + private ushort TryRemapChar(ushort val) + { + if (!RemapChars) + return val; + return val switch + { + 0x202F => 0xE07F // nbsp + , + 0x2026 => 0xE08D // … + , + 0x2642 => 0xE08E // ♂ + , + 0x2640 => 0xE08F // ♀ + , + _ => val + }; + } + + private ushort TryUnmapChar(ushort val) + { + if (!RemapChars) + return val; + return val switch + { + 0xE07F => 0x202F // nbsp + , + 0xE08D => 0x2026 // … + , + 0xE08E => 0x2642 // ♂ + , + 0xE08F => 0x2640 // ♀ + , + _ => val + }; + } + + private string GetLineString(byte[] data) + { + if (data == null) + return null; + + var s = new StringBuilder(); + int i = 0; + while (i < data.Length) + { + ushort val = BitConverter.ToUInt16(data, i); + if (val == KEY_TERMINATOR) + break; + i += 2; + + switch (val) + { + case KEY_VARIABLE: s.Append(GetVariableString(Config, data, ref i)); break; + case '\n': s.Append(@"\n"); break; + case '\\': s.Append(@"\\"); break; + case '[': s.Append(@"\["); break; + default: s.Append((char)TryUnmapChar(val)); break; + } + } + return s.ToString(); // Shouldn't get hit if the string is properly terminated. + } + + private static string GetVariableString(TextConfig config, byte[] data, ref int i) + { + var s = new StringBuilder(); + ushort count = BitConverter.ToUInt16(data, i); i += 2; + ushort variable = BitConverter.ToUInt16(data, i); i += 2; + + switch (variable) + { + case KEY_TEXTRETURN: // "Waitbutton then scroll text \r" + return "\\r"; + case KEY_TEXTCLEAR: // "Waitbutton then clear text \c" + return "\\c"; + case KEY_TEXTWAIT: // Dramatic pause for a text line. New! + ushort time = BitConverter.ToUInt16(data, i); i += 2; + return $"[WAIT {time}]"; + case KEY_TEXTNULL: // Empty Text line? Includes linenum so maybe for betatest finding used-unused lines? + ushort line = BitConverter.ToUInt16(data, i); i += 2; + return $"[~ {line}]"; + } + + string varName = config.GetVariableString(variable); + + s.Append("[VAR").Append(" ").Append(varName); + if (count > 1) + { + s.Append('('); + while (count > 1) + { + ushort arg = BitConverter.ToUInt16(data, i); i += 2; + s.Append(arg.ToString("X4")); + if (--count == 1) break; + s.Append(","); + } + s.Append(')'); + } + s.Append("]"); + return s.ToString(); + } + + private static IEnumerable GetEscapeValues(char esc) + { + var vals = new List(); + switch (esc) + { + case 'n': vals.Add('\n'); return vals; + case '\\': vals.Add('\\'); return vals; + case '[': vals.Add('['); return vals; + case 'r': vals.AddRange(new ushort[] { KEY_VARIABLE, 1, KEY_TEXTRETURN }); return vals; + case 'c': vals.AddRange(new ushort[] { KEY_VARIABLE, 1, KEY_TEXTCLEAR }); return vals; + default: throw new Exception("Invalid terminated line: \\" + esc); + } + } + + private IEnumerable GetVariableValues(string variable) + { + string[] split = variable.Split(' '); + if (split.Length < 2) + throw new ArgumentException("Incorrectly formatted variable text: " + variable); + + var vals = new List { KEY_VARIABLE }; + switch (split[0]) + { + case "~": // Blank Text Line Variable (No text set - debug/quality testing variable?) + vals.Add(1); + vals.Add(KEY_TEXTNULL); + vals.Add(Convert.ToUInt16(split[1])); + break; + case "WAIT": // Event pause Variable. + vals.Add(1); + vals.Add(KEY_TEXTWAIT); + vals.Add(Convert.ToUInt16(split[1])); + break; + case "VAR": // Text Variable + vals.AddRange(GetVariableParameters(split[1])); + break; + default: throw new Exception("Unknown variable method type: " + variable); + } + return vals; + } + + private IEnumerable GetVariableParameters(string text) + { + var vals = new List(); + int bracket = text.IndexOf('('); + bool noArgs = bracket < 0; + string variable = noArgs ? text : text[..bracket]; + ushort varVal = Config.GetVariableNumber(variable); + + if (!noArgs) + { + string[] args = text.Substring(bracket + 1, text.Length - bracket - 2).Split(','); + vals.Add((ushort)(1 + args.Length)); + vals.Add(varVal); + vals.AddRange(args.Select(t => Convert.ToUInt16(t, 16))); + } + else + { + vals.Add(1); + vals.Add(varVal); + } + return vals; + } + + // Exposed Methods + public static string[] GetStrings(byte[] data, TextConfig config = null, bool remapChars = false) + { + try + { + var t = new TextFile(data, config, remapChars); + return t.Lines; + } + catch { return null; } + } + + public static byte[] GetBytes(string[] lines, TextConfig config = null, bool remapChars = false) + { + return new TextFile(config: config, remapChars: remapChars) { Lines = lines }.Data; + } } diff --git a/pkNX.Structures/Text/TextLineInfo.cs b/pkNX.Structures/Text/TextLineInfo.cs index 3e11cf7c..24a2895d 100644 --- a/pkNX.Structures/Text/TextLineInfo.cs +++ b/pkNX.Structures/Text/TextLineInfo.cs @@ -1,8 +1,7 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +internal class TextLine { - internal class TextLine - { - public int Offset; - public int Length; - } + public int Offset; + public int Length; } diff --git a/pkNX.Structures/Text/TextVariableCode.cs b/pkNX.Structures/Text/TextVariableCode.cs index 3d322555..fedc04f8 100644 --- a/pkNX.Structures/Text/TextVariableCode.cs +++ b/pkNX.Structures/Text/TextVariableCode.cs @@ -1,241 +1,240 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class TextVariableCode { - public sealed class TextVariableCode + public readonly string Name; + public readonly int Code; + + private TextVariableCode(int code, string name) { - public readonly string Name; - public readonly int Code; - - private TextVariableCode(int code, string name) - { - Code = code; - Name = name; - } - - public static TextVariableCode[] GetVariables(GameVersion game) - { - if (game == GameVersion.Any) - return Array.Empty(); - - if (GameVersion.GG.Contains(game)) - return GG; - if (GameVersion.XY.Contains(game)) - return XY; - if (GameVersion.ORAS.Contains(game) || GameVersion.ORASDEMO == game) - return AO; - if (GameVersion.SM.Contains(game) || GameVersion.USUM.Contains(game)) - return SM; - - return Array.Empty(); - } - - private static readonly TextVariableCode[] XY = - { - new(0xFF00, "COLOR"), - new(0x0100, "TRNAME"), - new(0x0101, "PKNAME"), - new(0x0102, "PKNICK"), - new(0x0103, "TYPE"), - new(0x0105, "LOCATION"), - new(0x0106, "ABILITY"), - new(0x0107, "MOVE"), - new(0x0108, "ITEM1"), - new(0x0109, "ITEM2"), - new(0x010A, "sTRBAG"), - new(0x010B, "BOX"), - new(0x010D, "EVSTAT"), - new(0x0110, "OPOWER"), - new(0x0127, "RIBBON"), - new(0x0134, "MIINAME"), - new(0x013E, "WEATHER"), - new(0x0189, "TRNICK"), - new(0x018A, "1stchrTR"), - new(0x018B, "SHOUTOUT"), - new(0x018E, "BERRY"), - new(0x018F, "REMFEEL"), - new(0x0190, "REMQUAL"), - new(0x0191, "WEBSITE"), - new(0x019C, "CHOICECOS"), - new(0x01A1, "GSYNCID"), - new(0x0192, "PRVIDSAY"), - new(0x0193, "BTLTEST"), - new(0x0195, "GENLOC"), - new(0x0199, "CHOICEFOOD"), - new(0x019A, "HOTELITEM"), - new(0x019B, "TAXISTOP"), - new(0x019F, "MAISTITLE"), - new(0x1000, "ITEMPLUR0"), - new(0x1001, "ITEMPLUR1"), - new(0x1100, "GENDBR"), - new(0x1101, "NUMBRNCH"), - new(0x1302, "iCOLOR2"), - new(0x1303, "iCOLOR3"), - new(0x0200, "NUM1"), - new(0x0201, "NUM2"), - new(0x0202, "NUM3"), - new(0x0203, "NUM4"), - new(0x0204, "NUM5"), - new(0x0205, "NUM6"), - new(0x0206, "NUM7"), - new(0x0207, "NUM8"), - new(0x0208, "NUM9"), - }; - - private static readonly TextVariableCode[] AO = - { - new(0xFF00, "COLOR"), - new(0x0100, "TRNAME"), - new(0x0101, "PKNAME"), - new(0x0102, "PKNICK"), - new(0x0103, "TYPE"), - new(0x0105, "LOCATION"), - new(0x0106, "ABILITY"), - new(0x0107, "MOVE"), - new(0x0108, "ITEM1"), - new(0x0109, "ITEM2"), - new(0x010A, "sTRBAG"), - new(0x010B, "BOX"), - new(0x010D, "EVSTAT"), - new(0x0110, "OPOWER"), - new(0x0127, "RIBBON"), - new(0x0134, "MIINAME"), - new(0x013E, "WEATHER"), - new(0x0189, "TRNICK"), - new(0x018A, "1stchrTR"), - new(0x018B, "SHOUTOUT"), - new(0x018E, "BERRY"), - new(0x018F, "REMFEEL"), - new(0x0190, "REMQUAL"), - new(0x0191, "WEBSITE"), - new(0x019C, "CHOICECOS"), - new(0x01A1, "GSYNCID"), - new(0x0192, "PRVIDSAY"), - new(0x0193, "BTLTEST"), - new(0x0195, "GENLOC"), - new(0x0199, "CHOICEFOOD"), - new(0x019A, "HOTELITEM"), - new(0x019B, "TAXISTOP"), - new(0x019F, "MAISTITLE"), - new(0x1000, "ITEMPLUR0"), - new(0x1001, "ITEMPLUR1"), - new(0x1100, "GENDBR"), - new(0x1101, "NUMBRNCH"), - new(0x1302, "iCOLOR2"), - new(0x1303, "iCOLOR3"), - new(0x0200, "NUM1"), - new(0x0201, "NUM2"), - new(0x0202, "NUM3"), - new(0x0203, "NUM4"), - new(0x0204, "NUM5"), - new(0x0205, "NUM6"), - new(0x0206, "NUM7"), - new(0x0207, "NUM8"), - new(0x0208, "NUM9"), - }; - - private static readonly TextVariableCode[] SM = - { - new(0xFF00, "COLOR"), - new(0x0100, "TRNAME"), - new(0x0101, "PKNAME"), - new(0x0102, "PKNICK"), - new(0x0103, "TYPE"), - new(0x0105, "LOCATION"), - new(0x0106, "ABILITY"), - new(0x0107, "MOVE"), - new(0x0108, "ITEM1"), - new(0x0109, "ITEM2"), - new(0x010A, "sTRBAG"), - new(0x010B, "BOX"), - new(0x010D, "EVSTAT"), - new(0x0110, "OPOWER"), - new(0x0127, "RIBBON"), - new(0x0134, "MIINAME"), - new(0x013E, "WEATHER"), - new(0x0189, "TRNICK"), - new(0x018A, "1stchrTR"), - new(0x018B, "SHOUTOUT"), - new(0x018E, "BERRY"), - new(0x018F, "REMFEEL"), - new(0x0190, "REMQUAL"), - new(0x0191, "WEBSITE"), - new(0x019C, "CHOICECOS"), - new(0x01A1, "GSYNCID"), - new(0x0192, "PRVIDSAY"), - new(0x0193, "BTLTEST"), - new(0x0195, "GENLOC"), - new(0x0199, "CHOICEFOOD"), - new(0x019A, "HOTELITEM"), - new(0x019B, "TAXISTOP"), - new(0x019F, "MAISTITLE"), - new(0x1000, "ITEMPLUR0"), - new(0x1001, "ITEMPLUR1"), - new(0x1100, "GENDBR"), - new(0x1101, "NUMBRNCH"), - new(0x1302, "iCOLOR2"), - new(0x1303, "iCOLOR3"), - new(0x0200, "NUM1"), - new(0x0201, "NUM2"), - new(0x0202, "NUM3"), - new(0x0203, "NUM4"), - new(0x0204, "NUM5"), - new(0x0205, "NUM6"), - new(0x0206, "NUM7"), - new(0x0207, "NUM8"), - new(0x0208, "NUM9"), - }; - - private static readonly TextVariableCode[] GG = - { - new(0xFF00, "COLOR"), - new(0x0100, "TRNAME"), - new(0x0101, "PKNAME"), - new(0x0102, "PKNICK"), - new(0x0103, "TYPE"), - new(0x0105, "LOCATION"), - new(0x0106, "ABILITY"), - new(0x0107, "MOVE"), - new(0x0108, "ITEM1"), - new(0x0109, "ITEM2"), - new(0x010A, "sTRBAG"), - new(0x010B, "BOX"), - new(0x010D, "EVSTAT"), - new(0x0110, "OPOWER"), - new(0x0127, "RIBBON"), - new(0x0134, "MIINAME"), - new(0x013E, "WEATHER"), - new(0x0189, "TRNICK"), - new(0x018A, "1stchrTR"), - new(0x018B, "SHOUTOUT"), - new(0x018E, "BERRY"), - new(0x018F, "REMFEEL"), - new(0x0190, "REMQUAL"), - new(0x0191, "WEBSITE"), - new(0x019C, "CHOICECOS"), - new(0x01A1, "GSYNCID"), - new(0x0192, "PRVIDSAY"), - new(0x0193, "BTLTEST"), - new(0x0195, "GENLOC"), - new(0x0199, "CHOICEFOOD"), - new(0x019A, "HOTELITEM"), - new(0x019B, "TAXISTOP"), - new(0x019F, "MAISTITLE"), - new(0x1000, "ITEMPLUR0"), - new(0x1001, "ITEMPLUR1"), - new(0x1100, "GENDBR"), - new(0x1101, "NUMBRNCH"), - new(0x1302, "iCOLOR2"), - new(0x1303, "iCOLOR3"), - new(0x0200, "NUM1"), - new(0x0201, "NUM2"), - new(0x0202, "NUM3"), - new(0x0203, "NUM4"), - new(0x0204, "NUM5"), - new(0x0205, "NUM6"), - new(0x0206, "NUM7"), - new(0x0207, "NUM8"), - new(0x0208, "NUM9"), - }; + Code = code; + Name = name; } -} \ No newline at end of file + + public static TextVariableCode[] GetVariables(GameVersion game) + { + if (game == GameVersion.Any) + return Array.Empty(); + + if (GameVersion.GG.Contains(game)) + return GG; + if (GameVersion.XY.Contains(game)) + return XY; + if (GameVersion.ORAS.Contains(game) || GameVersion.ORASDEMO == game) + return AO; + if (GameVersion.SM.Contains(game) || GameVersion.USUM.Contains(game)) + return SM; + + return Array.Empty(); + } + + private static readonly TextVariableCode[] XY = + { + new(0xFF00, "COLOR"), + new(0x0100, "TRNAME"), + new(0x0101, "PKNAME"), + new(0x0102, "PKNICK"), + new(0x0103, "TYPE"), + new(0x0105, "LOCATION"), + new(0x0106, "ABILITY"), + new(0x0107, "MOVE"), + new(0x0108, "ITEM1"), + new(0x0109, "ITEM2"), + new(0x010A, "sTRBAG"), + new(0x010B, "BOX"), + new(0x010D, "EVSTAT"), + new(0x0110, "OPOWER"), + new(0x0127, "RIBBON"), + new(0x0134, "MIINAME"), + new(0x013E, "WEATHER"), + new(0x0189, "TRNICK"), + new(0x018A, "1stchrTR"), + new(0x018B, "SHOUTOUT"), + new(0x018E, "BERRY"), + new(0x018F, "REMFEEL"), + new(0x0190, "REMQUAL"), + new(0x0191, "WEBSITE"), + new(0x019C, "CHOICECOS"), + new(0x01A1, "GSYNCID"), + new(0x0192, "PRVIDSAY"), + new(0x0193, "BTLTEST"), + new(0x0195, "GENLOC"), + new(0x0199, "CHOICEFOOD"), + new(0x019A, "HOTELITEM"), + new(0x019B, "TAXISTOP"), + new(0x019F, "MAISTITLE"), + new(0x1000, "ITEMPLUR0"), + new(0x1001, "ITEMPLUR1"), + new(0x1100, "GENDBR"), + new(0x1101, "NUMBRNCH"), + new(0x1302, "iCOLOR2"), + new(0x1303, "iCOLOR3"), + new(0x0200, "NUM1"), + new(0x0201, "NUM2"), + new(0x0202, "NUM3"), + new(0x0203, "NUM4"), + new(0x0204, "NUM5"), + new(0x0205, "NUM6"), + new(0x0206, "NUM7"), + new(0x0207, "NUM8"), + new(0x0208, "NUM9"), + }; + + private static readonly TextVariableCode[] AO = + { + new(0xFF00, "COLOR"), + new(0x0100, "TRNAME"), + new(0x0101, "PKNAME"), + new(0x0102, "PKNICK"), + new(0x0103, "TYPE"), + new(0x0105, "LOCATION"), + new(0x0106, "ABILITY"), + new(0x0107, "MOVE"), + new(0x0108, "ITEM1"), + new(0x0109, "ITEM2"), + new(0x010A, "sTRBAG"), + new(0x010B, "BOX"), + new(0x010D, "EVSTAT"), + new(0x0110, "OPOWER"), + new(0x0127, "RIBBON"), + new(0x0134, "MIINAME"), + new(0x013E, "WEATHER"), + new(0x0189, "TRNICK"), + new(0x018A, "1stchrTR"), + new(0x018B, "SHOUTOUT"), + new(0x018E, "BERRY"), + new(0x018F, "REMFEEL"), + new(0x0190, "REMQUAL"), + new(0x0191, "WEBSITE"), + new(0x019C, "CHOICECOS"), + new(0x01A1, "GSYNCID"), + new(0x0192, "PRVIDSAY"), + new(0x0193, "BTLTEST"), + new(0x0195, "GENLOC"), + new(0x0199, "CHOICEFOOD"), + new(0x019A, "HOTELITEM"), + new(0x019B, "TAXISTOP"), + new(0x019F, "MAISTITLE"), + new(0x1000, "ITEMPLUR0"), + new(0x1001, "ITEMPLUR1"), + new(0x1100, "GENDBR"), + new(0x1101, "NUMBRNCH"), + new(0x1302, "iCOLOR2"), + new(0x1303, "iCOLOR3"), + new(0x0200, "NUM1"), + new(0x0201, "NUM2"), + new(0x0202, "NUM3"), + new(0x0203, "NUM4"), + new(0x0204, "NUM5"), + new(0x0205, "NUM6"), + new(0x0206, "NUM7"), + new(0x0207, "NUM8"), + new(0x0208, "NUM9"), + }; + + private static readonly TextVariableCode[] SM = + { + new(0xFF00, "COLOR"), + new(0x0100, "TRNAME"), + new(0x0101, "PKNAME"), + new(0x0102, "PKNICK"), + new(0x0103, "TYPE"), + new(0x0105, "LOCATION"), + new(0x0106, "ABILITY"), + new(0x0107, "MOVE"), + new(0x0108, "ITEM1"), + new(0x0109, "ITEM2"), + new(0x010A, "sTRBAG"), + new(0x010B, "BOX"), + new(0x010D, "EVSTAT"), + new(0x0110, "OPOWER"), + new(0x0127, "RIBBON"), + new(0x0134, "MIINAME"), + new(0x013E, "WEATHER"), + new(0x0189, "TRNICK"), + new(0x018A, "1stchrTR"), + new(0x018B, "SHOUTOUT"), + new(0x018E, "BERRY"), + new(0x018F, "REMFEEL"), + new(0x0190, "REMQUAL"), + new(0x0191, "WEBSITE"), + new(0x019C, "CHOICECOS"), + new(0x01A1, "GSYNCID"), + new(0x0192, "PRVIDSAY"), + new(0x0193, "BTLTEST"), + new(0x0195, "GENLOC"), + new(0x0199, "CHOICEFOOD"), + new(0x019A, "HOTELITEM"), + new(0x019B, "TAXISTOP"), + new(0x019F, "MAISTITLE"), + new(0x1000, "ITEMPLUR0"), + new(0x1001, "ITEMPLUR1"), + new(0x1100, "GENDBR"), + new(0x1101, "NUMBRNCH"), + new(0x1302, "iCOLOR2"), + new(0x1303, "iCOLOR3"), + new(0x0200, "NUM1"), + new(0x0201, "NUM2"), + new(0x0202, "NUM3"), + new(0x0203, "NUM4"), + new(0x0204, "NUM5"), + new(0x0205, "NUM6"), + new(0x0206, "NUM7"), + new(0x0207, "NUM8"), + new(0x0208, "NUM9"), + }; + + private static readonly TextVariableCode[] GG = + { + new(0xFF00, "COLOR"), + new(0x0100, "TRNAME"), + new(0x0101, "PKNAME"), + new(0x0102, "PKNICK"), + new(0x0103, "TYPE"), + new(0x0105, "LOCATION"), + new(0x0106, "ABILITY"), + new(0x0107, "MOVE"), + new(0x0108, "ITEM1"), + new(0x0109, "ITEM2"), + new(0x010A, "sTRBAG"), + new(0x010B, "BOX"), + new(0x010D, "EVSTAT"), + new(0x0110, "OPOWER"), + new(0x0127, "RIBBON"), + new(0x0134, "MIINAME"), + new(0x013E, "WEATHER"), + new(0x0189, "TRNICK"), + new(0x018A, "1stchrTR"), + new(0x018B, "SHOUTOUT"), + new(0x018E, "BERRY"), + new(0x018F, "REMFEEL"), + new(0x0190, "REMQUAL"), + new(0x0191, "WEBSITE"), + new(0x019C, "CHOICECOS"), + new(0x01A1, "GSYNCID"), + new(0x0192, "PRVIDSAY"), + new(0x0193, "BTLTEST"), + new(0x0195, "GENLOC"), + new(0x0199, "CHOICEFOOD"), + new(0x019A, "HOTELITEM"), + new(0x019B, "TAXISTOP"), + new(0x019F, "MAISTITLE"), + new(0x1000, "ITEMPLUR0"), + new(0x1001, "ITEMPLUR1"), + new(0x1100, "GENDBR"), + new(0x1101, "NUMBRNCH"), + new(0x1302, "iCOLOR2"), + new(0x1303, "iCOLOR3"), + new(0x0200, "NUM1"), + new(0x0201, "NUM2"), + new(0x0202, "NUM3"), + new(0x0203, "NUM4"), + new(0x0204, "NUM5"), + new(0x0205, "NUM6"), + new(0x0206, "NUM7"), + new(0x0207, "NUM8"), + new(0x0208, "NUM9"), + }; +} diff --git a/pkNX.Structures/Util.cs b/pkNX.Structures/Util.cs index 649e8aed..7f163fe7 100644 --- a/pkNX.Structures/Util.cs +++ b/pkNX.Structures/Util.cs @@ -1,109 +1,108 @@ -using System; +using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; -namespace pkNX.Structures +namespace pkNX.Structures; + +public static class Util { - public static class Util + public static Random Rand { get; set; } = new(); + internal static uint Rand32() => (uint)Rand.Next(1 << 30) << 2 | (uint)Rand.Next(1 << 2); + + private static T[] GetArray(IReadOnlyList entries, Func del) { - public static Random Rand { get; set; } = new(); - internal static uint Rand32() => (uint)Rand.Next(1 << 30) << 2 | (uint)Rand.Next(1 << 2); + var data = new T[entries.Count]; + for (int i = 0; i < data.Length; i++) + data[i] = del(entries[i]); + return data; + } - private static T[] GetArray(IReadOnlyList entries, Func del) + public static T[] GetArray(byte[][] entries, Func del, int size) + { + var data = new T[entries.Length / size]; + for (int i = 0; i < data.Length; i++) + data[i] = del(entries[i]); + return data; + } + + public static T[] GetArray(this byte[] entries, Func del, int size) + { + if (entries == null || entries.Length < size) + return Array.Empty(); + + var data = new T[entries.Length / size]; + for (int i = 0; i < entries.Length; i += size) + data[i / size] = del(entries, i); + return data; + } + + public static T[] GetArray(this byte[] entries, Func del, int size) + { + if (entries == null || entries.Length < size) + return Array.Empty(); + + var data = new T[entries.Length / size]; + for (int i = 0; i < entries.Length; i += size) { - var data = new T[entries.Count]; - for (int i = 0; i < data.Length; i++) - data[i] = del(entries[i]); - return data; + byte[] arr = new byte[size]; + Array.Copy(entries, i, arr, 0, size); + data[i / size] = del(arr); } + return data; + } - public static T[] GetArray(byte[][] entries, Func del, int size) + public delegate TResult FromBytesConstructor(ReadOnlySpan arg); + public static T[] GetArray(this ReadOnlySpan entries, FromBytesConstructor constructor, int size) + { + if (entries.Length < size) + return Array.Empty(); + + Debug.Assert(entries.Length % size == 0, "This data can't be split into equally sized entries with the provided slice size"); + + var array = new T[entries.Length / size]; + for (int i = 0; i < entries.Length; i += size) { - var data = new T[entries.Length / size]; - for (int i = 0; i < data.Length; i++) - data[i] = del(entries[i]); - return data; + var entry = entries.Slice(i, size); + array[i / size] = constructor(entry); } + return array; + } - public static T[] GetArray(this byte[] entries, Func del, int size) + public static T[] GetArray(this Task task, Func del) + { + return GetArray(task.Result, del); + } + + public static T[] GetArray(this Task task, Func del, int size) => GetArray(task.Result, del, size); + + public static string[] GetHexLines(byte[] data, int count = 4) + { + if (data == null) + return Array.Empty(); + + // Generates an x-byte wide space separated string array; leftovers included at the end. + string[] s = new string[(data.Length / count) + (data.Length % count > 0 ? 1 : 0)]; + for (int i = 0; i < s.Length; i++) + s[i] = BitConverter.ToString(data.Skip(i * count).Take(count).ToArray()).Replace('-', ' '); + return s; + } + + public static string[] GetHexLines(uint[] data) => GetHexLines(GetBytes(data)); + + public static byte[] GetBytes(uint[] data) + { + byte[] result = new byte[data.Length * 4]; + for (int i = 0; i < data.Length; i++) { - if (entries == null || entries.Length < size) - return Array.Empty(); - - var data = new T[entries.Length / size]; - for (int i = 0; i < entries.Length; i += size) - data[i / size] = del(entries, i); - return data; - } - - public static T[] GetArray(this byte[] entries, Func del, int size) - { - if (entries == null || entries.Length < size) - return Array.Empty(); - - var data = new T[entries.Length / size]; - for (int i = 0; i < entries.Length; i += size) - { - byte[] arr = new byte[size]; - Array.Copy(entries, i, arr, 0, size); - data[i / size] = del(arr); - } - return data; - } - - public delegate TResult FromBytesConstructor(ReadOnlySpan arg); - public static T[] GetArray(this ReadOnlySpan entries, FromBytesConstructor constructor, int size) - { - if (entries.Length < size) - return Array.Empty(); - - Debug.Assert(entries.Length % size == 0, "This data can't be split into equally sized entries with the provided slice size"); - - var array = new T[entries.Length / size]; - for (int i = 0; i < entries.Length; i += size) - { - var entry = entries.Slice(i, size); - array[i / size] = constructor(entry); - } - return array; - } - - public static T[] GetArray(this Task task, Func del) - { - return GetArray(task.Result, del); - } - - public static T[] GetArray(this Task task, Func del, int size) => GetArray(task.Result, del, size); - - public static string[] GetHexLines(byte[] data, int count = 4) - { - if (data == null) - return Array.Empty(); - - // Generates an x-byte wide space separated string array; leftovers included at the end. - string[] s = new string[(data.Length / count) + (data.Length % count > 0 ? 1 : 0)]; - for (int i = 0; i < s.Length; i++) - s[i] = BitConverter.ToString(data.Skip(i * count).Take(count).ToArray()).Replace('-', ' '); - return s; - } - - public static string[] GetHexLines(uint[] data) => GetHexLines(GetBytes(data)); - - public static byte[] GetBytes(uint[] data) - { - byte[] result = new byte[data.Length * 4]; - for (int i = 0; i < data.Length; i++) - { - int o = i * 4; - var val = data[i]; - result[o + 0] = (byte)(val >> 0); - result[o + 1] = (byte)(val >> 8); - result[o + 2] = (byte)(val >> 16); - result[o + 3] = (byte)(val >> 24); - } - return result; + int o = i * 4; + var val = data[i]; + result[o + 0] = (byte)(val >> 0); + result[o + 1] = (byte)(val >> 8); + result[o + 2] = (byte)(val >> 16); + result[o + 3] = (byte)(val >> 24); } + return result; } } diff --git a/pkNX.Structures/VsTrainer/3DS/TrData6.cs b/pkNX.Structures/VsTrainer/3DS/TrData6.cs index 4b10adfe..a825e532 100644 --- a/pkNX.Structures/VsTrainer/3DS/TrData6.cs +++ b/pkNX.Structures/VsTrainer/3DS/TrData6.cs @@ -1,45 +1,44 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class TrData6 : TrainerData { - public abstract class TrData6 : TrainerData + protected abstract int Format { get; set; } + public bool HasItem { get => (Format & 1) == 1; set => Format = (ushort)((Format & ~1) | (value ? 1 : 0)); } + public bool HasMoves { get => (Format & 2) == 2; set => Format = (ushort)((Format & ~2) | (value ? 2 : 0)); } + + public TrPoke6[] Team { get; set; } + + protected TrData6(byte[] trData) : base(trData) { } + public byte[] WriteTeam() => WriteTeam(Team, HasItem, HasMoves); + public TrPoke6[] GetTeam(byte[] trPoke) => GetTeam(trPoke, NumPokemon, HasItem, HasMoves); + + public static byte[] WriteTeam(TrPoke6[] team, bool HasItem, bool HasMoves) { - protected abstract int Format { get; set; } - public bool HasItem { get => (Format & 1) == 1; set => Format = (ushort)((Format & ~1) | (value ? 1 : 0)); } - public bool HasMoves { get => (Format & 2) == 2; set => Format = (ushort)((Format & ~2) | (value ? 2 : 0)); } - - public TrPoke6[] Team { get; set; } - - protected TrData6(byte[] trData) : base(trData) { } - public byte[] WriteTeam() => WriteTeam(Team, HasItem, HasMoves); - public TrPoke6[] GetTeam(byte[] trPoke) => GetTeam(trPoke, NumPokemon, HasItem, HasMoves); - - public static byte[] WriteTeam(TrPoke6[] team, bool HasItem, bool HasMoves) - { - if (team.Length == 0) - return Array.Empty(); - var first = team[0].Write(HasItem, HasMoves); - byte[] result = new byte[first.Length * team.Length]; - first.CopyTo(result, 0); - for (int i = 1; i < team.Length; i++) - team[i].Write(HasItem, HasMoves).CopyTo(result, first.Length * i); - return result; - } - - public static TrPoke6[] GetTeam(byte[] trPoke, int numPokemon, bool item, bool moves) - { - var team = new TrPoke6[numPokemon]; - byte[][] teamData = new byte[numPokemon][]; - int dataLen = trPoke.Length / numPokemon; - for (int i = 0; i < teamData.Length; i++) - { - var arr = teamData[i] = new byte[dataLen]; - Array.Copy(trPoke, i * dataLen, arr, 0, dataLen); - } - - for (int i = 0; i < numPokemon; i++) - team[i] = new TrPoke6(teamData[i], item, moves); - return team; - } + if (team.Length == 0) + return Array.Empty(); + var first = team[0].Write(HasItem, HasMoves); + byte[] result = new byte[first.Length * team.Length]; + first.CopyTo(result, 0); + for (int i = 1; i < team.Length; i++) + team[i].Write(HasItem, HasMoves).CopyTo(result, first.Length * i); + return result; } -} \ No newline at end of file + + public static TrPoke6[] GetTeam(byte[] trPoke, int numPokemon, bool item, bool moves) + { + var team = new TrPoke6[numPokemon]; + byte[][] teamData = new byte[numPokemon][]; + int dataLen = trPoke.Length / numPokemon; + for (int i = 0; i < teamData.Length; i++) + { + var arr = teamData[i] = new byte[dataLen]; + Array.Copy(trPoke, i * dataLen, arr, 0, dataLen); + } + + for (int i = 0; i < numPokemon; i++) + team[i] = new TrPoke6(teamData[i], item, moves); + return team; + } +} diff --git a/pkNX.Structures/VsTrainer/3DS/TrData6AO.cs b/pkNX.Structures/VsTrainer/3DS/TrData6AO.cs index 0913c8ad..3f06a8b4 100644 --- a/pkNX.Structures/VsTrainer/3DS/TrData6AO.cs +++ b/pkNX.Structures/VsTrainer/3DS/TrData6AO.cs @@ -1,24 +1,23 @@ using System; -namespace pkNX.Structures -{ - public sealed class TrData6AO : TrData6 - { - public override int SIZE => 0x18; - public TrData6AO(byte[] trData = null) : base(trData) { } +namespace pkNX.Structures; - protected override int Format { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } - public override int Class { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } - public ushort Unused { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes(value).CopyTo(Data, 0x04); } - public override BattleMode Mode { get => (BattleMode) Data[0x06]; set => Data[0x06] = (byte) value; } - public override int NumPokemon { get => Data[0x07]; set => Data[0x07] = (byte)value; } - public override int Item1 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } - public override int Item2 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } - public override int Item3 { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } - public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0E); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0E); } - public override uint AI { get => BitConverter.ToUInt32(Data, 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, 0x10); } - public override bool Heal { get => Data[0x14] == 1; set => Data[0x14] = value ? (byte)1 : (byte)0; } - public override int Money { get => Data[0x15]; set => Data[0x15] = (byte)value; } - public override int Gift { get => BitConverter.ToUInt16(Data, 0x16); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x16); } - } -} \ No newline at end of file +public sealed class TrData6AO : TrData6 +{ + public override int SIZE => 0x18; + public TrData6AO(byte[] trData = null) : base(trData) { } + + protected override int Format { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } + public override int Class { get => BitConverter.ToUInt16(Data, 0x02); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x02); } + public ushort Unused { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes(value).CopyTo(Data, 0x04); } + public override BattleMode Mode { get => (BattleMode) Data[0x06]; set => Data[0x06] = (byte) value; } + public override int NumPokemon { get => Data[0x07]; set => Data[0x07] = (byte)value; } + public override int Item1 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } + public override int Item2 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } + public override int Item3 { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } + public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0E); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0E); } + public override uint AI { get => BitConverter.ToUInt32(Data, 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, 0x10); } + public override bool Heal { get => Data[0x14] == 1; set => Data[0x14] = value ? (byte)1 : (byte)0; } + public override int Money { get => Data[0x15]; set => Data[0x15] = (byte)value; } + public override int Gift { get => BitConverter.ToUInt16(Data, 0x16); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x16); } +} diff --git a/pkNX.Structures/VsTrainer/3DS/TrData6XY.cs b/pkNX.Structures/VsTrainer/3DS/TrData6XY.cs index a7999ff4..448e7012 100644 --- a/pkNX.Structures/VsTrainer/3DS/TrData6XY.cs +++ b/pkNX.Structures/VsTrainer/3DS/TrData6XY.cs @@ -1,23 +1,22 @@ using System; -namespace pkNX.Structures -{ - public sealed class TrData6XY : TrData6 - { - public override int SIZE => 0x14; - public TrData6XY(byte[] trData = null) : base(trData) { } +namespace pkNX.Structures; - protected override int Format { get => Data[0x00]; set => Data[0x00] = (byte) value; } - public override int Class { get => Data[0x01]; set => Data[0x01] = (byte)value; } - public override BattleMode Mode { get => (BattleMode)Data[0x02]; set => Data[0x02] = (byte)value; } - public override int NumPokemon { get => Data[0x03]; set => Data[0x03] = (byte)value; } - public override int Item1 { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x04); } - public override int Item2 { get => BitConverter.ToUInt16(Data, 0x06); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x06); } - public override int Item3 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } - public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } - public override uint AI { get => BitConverter.ToUInt32(Data, 0x0C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0C); } - public override bool Heal { get => Data[0x10] == 1; set => Data[0x10] = value ? (byte)1 : (byte)0; } - public override int Money { get => Data[0x11]; set => Data[0x11] = (byte)value; } - public override int Gift { get => BitConverter.ToUInt16(Data, 0x12); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x12); } - } -} \ No newline at end of file +public sealed class TrData6XY : TrData6 +{ + public override int SIZE => 0x14; + public TrData6XY(byte[] trData = null) : base(trData) { } + + protected override int Format { get => Data[0x00]; set => Data[0x00] = (byte) value; } + public override int Class { get => Data[0x01]; set => Data[0x01] = (byte)value; } + public override BattleMode Mode { get => (BattleMode)Data[0x02]; set => Data[0x02] = (byte)value; } + public override int NumPokemon { get => Data[0x03]; set => Data[0x03] = (byte)value; } + public override int Item1 { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x04); } + public override int Item2 { get => BitConverter.ToUInt16(Data, 0x06); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x06); } + public override int Item3 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } + public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } + public override uint AI { get => BitConverter.ToUInt32(Data, 0x0C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0C); } + public override bool Heal { get => Data[0x10] == 1; set => Data[0x10] = value ? (byte)1 : (byte)0; } + public override int Money { get => Data[0x11]; set => Data[0x11] = (byte)value; } + public override int Gift { get => BitConverter.ToUInt16(Data, 0x12); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x12); } +} diff --git a/pkNX.Structures/VsTrainer/3DS/TrPoke6.cs b/pkNX.Structures/VsTrainer/3DS/TrPoke6.cs index f75d4661..8fde70db 100644 --- a/pkNX.Structures/VsTrainer/3DS/TrPoke6.cs +++ b/pkNX.Structures/VsTrainer/3DS/TrPoke6.cs @@ -1,64 +1,63 @@ -using System.IO; +using System.IO; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class TrPoke6 { - public class TrPoke6 + public byte IVs; + public byte PID; + public ushort Level; + public ushort Species; + public ushort Form; + public int Ability; + public int Gender; + public int uBit; + public ushort Item; + public ushort[] Moves = new ushort[4]; + + public TrPoke6(byte[] data, bool HasItem, bool HasMoves) { - public byte IVs; - public byte PID; - public ushort Level; - public ushort Species; - public ushort Form; - public int Ability; - public int Gender; - public int uBit; - public ushort Item; - public ushort[] Moves = new ushort[4]; + using var ms = new MemoryStream(data); + using var br = new BinaryReader(ms); + IVs = br.ReadByte(); + PID = br.ReadByte(); + Level = br.ReadUInt16(); + Species = br.ReadUInt16(); + Form = br.ReadUInt16(); - public TrPoke6(byte[] data, bool HasItem, bool HasMoves) - { - using var ms = new MemoryStream(data); - using var br = new BinaryReader(ms); - IVs = br.ReadByte(); - PID = br.ReadByte(); - Level = br.ReadUInt16(); - Species = br.ReadUInt16(); - Form = br.ReadUInt16(); + Ability = PID >> 4; + Gender = PID & 3; + uBit = (PID >> 3) & 1; - Ability = PID >> 4; - Gender = PID & 3; - uBit = (PID >> 3) & 1; + if (HasItem) + Item = br.ReadUInt16(); - if (HasItem) - Item = br.ReadUInt16(); + if (!HasMoves) + return; - if (!HasMoves) - return; - - for (int i = 0; i < 4; i++) - Moves[i] = br.ReadUInt16(); - } - - public byte[] Write(bool HasItem, bool HasMoves) - { - using var ms = new MemoryStream(); - using var bw = new BinaryWriter(ms); - bw.Write(IVs); - PID = (byte)(((Ability & 0xF) << 4) | ((uBit & 1) << 3) | (Gender & 0x7)); - bw.Write(PID); - bw.Write(Level); - bw.Write(Species); - bw.Write(Form); - - if (HasItem) - bw.Write(Item); - if (!HasMoves) - return ms.ToArray(); - - foreach (ushort Move in Moves) - bw.Write(Move); - - return ms.ToArray(); - } + for (int i = 0; i < 4; i++) + Moves[i] = br.ReadUInt16(); } -} \ No newline at end of file + + public byte[] Write(bool HasItem, bool HasMoves) + { + using var ms = new MemoryStream(); + using var bw = new BinaryWriter(ms); + bw.Write(IVs); + PID = (byte)(((Ability & 0xF) << 4) | ((uBit & 1) << 3) | (Gender & 0x7)); + bw.Write(PID); + bw.Write(Level); + bw.Write(Species); + bw.Write(Form); + + if (HasItem) + bw.Write(Item); + if (!HasMoves) + return ms.ToArray(); + + foreach (ushort Move in Moves) + bw.Write(Move); + + return ms.ToArray(); + } +} diff --git a/pkNX.Structures/VsTrainer/3DS/TrainerClass6.cs b/pkNX.Structures/VsTrainer/3DS/TrainerClass6.cs index 44434b43..717a2766 100644 --- a/pkNX.Structures/VsTrainer/3DS/TrainerClass6.cs +++ b/pkNX.Structures/VsTrainer/3DS/TrainerClass6.cs @@ -1,7 +1,6 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public class TrainerClass6 { - public class TrainerClass6 - { - // todo - } + // todo } diff --git a/pkNX.Structures/VsTrainer/Base/IAwakened.cs b/pkNX.Structures/VsTrainer/Base/IAwakened.cs index 45740a32..b3a2adde 100644 --- a/pkNX.Structures/VsTrainer/Base/IAwakened.cs +++ b/pkNX.Structures/VsTrainer/Base/IAwakened.cs @@ -1,119 +1,118 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public interface IAwakened { - public interface IAwakened + int AV_HP { get; set; } + int AV_ATK { get; set; } + int AV_DEF { get; set; } + int AV_SPA { get; set; } + int AV_SPD { get; set; } + int AV_SPE { get; set; } +} + +public static partial class Extensions +{ + /// + /// Sums all values. + /// + /// Data to sum with + public static int AwakeningSum(this IAwakened pk) => pk.AV_HP + pk.AV_ATK + pk.AV_DEF + pk.AV_SPE + pk.AV_SPA + pk.AV_SPD; + + /// + /// Clears all values. + /// + /// Data to clear from + public static void AwakeningClear(this IAwakened pk) => pk.AV_HP = pk.AV_ATK = pk.AV_DEF = pk.AV_SPE = pk.AV_SPA = pk.AV_SPD = 0; + + /// + /// Sets all values to the maximum value. + /// + /// Data to clear from + public static void AwakeningMax(this IAwakened pk) => pk.AwakeningSetAllTo(Legal.AwakeningMax); + + /// + /// Sets all values to the specified value. + /// + /// Data to clear from + /// Value to set all to + public static void AwakeningSetAllTo(this IAwakened pk, int value) => pk.AV_HP = pk.AV_ATK = pk.AV_DEF = pk.AV_SPE = pk.AV_SPA = pk.AV_SPD = value; + + /// + /// Gets if all values are within legal limits. + /// + /// Data to check + public static bool AwakeningAllValid(this IAwakened pk) { - int AV_HP { get; set; } - int AV_ATK { get; set; } - int AV_DEF { get; set; } - int AV_SPA { get; set; } - int AV_SPD { get; set; } - int AV_SPE { get; set; } + if (pk.AV_HP > Legal.AwakeningMax) + return false; + if (pk.AV_ATK > Legal.AwakeningMax) + return false; + if (pk.AV_DEF > Legal.AwakeningMax) + return false; + if (pk.AV_SPE > Legal.AwakeningMax) + return false; + if (pk.AV_SPA > Legal.AwakeningMax) + return false; + if (pk.AV_SPD > Legal.AwakeningMax) + return false; + return true; } - public static partial class Extensions + /// + /// Sets one of the values based on its index within the array. + /// + /// Pokémon to modify. + /// Index to set to + /// Value to set + public static void SetAV(this IAwakened pk, int index, int value) { - /// - /// Sums all values. - /// - /// Data to sum with - public static int AwakeningSum(this IAwakened pk) => pk.AV_HP + pk.AV_ATK + pk.AV_DEF + pk.AV_SPE + pk.AV_SPA + pk.AV_SPD; - - /// - /// Clears all values. - /// - /// Data to clear from - public static void AwakeningClear(this IAwakened pk) => pk.AV_HP = pk.AV_ATK = pk.AV_DEF = pk.AV_SPE = pk.AV_SPA = pk.AV_SPD = 0; - - /// - /// Sets all values to the maximum value. - /// - /// Data to clear from - public static void AwakeningMax(this IAwakened pk) => pk.AwakeningSetAllTo(Legal.AwakeningMax); - - /// - /// Sets all values to the specified value. - /// - /// Data to clear from - /// Value to set all to - public static void AwakeningSetAllTo(this IAwakened pk, int value) => pk.AV_HP = pk.AV_ATK = pk.AV_DEF = pk.AV_SPE = pk.AV_SPA = pk.AV_SPD = value; - - /// - /// Gets if all values are within legal limits. - /// - /// Data to check - public static bool AwakeningAllValid(this IAwakened pk) + switch (index) { - if (pk.AV_HP > Legal.AwakeningMax) - return false; - if (pk.AV_ATK > Legal.AwakeningMax) - return false; - if (pk.AV_DEF > Legal.AwakeningMax) - return false; - if (pk.AV_SPE > Legal.AwakeningMax) - return false; - if (pk.AV_SPA > Legal.AwakeningMax) - return false; - if (pk.AV_SPD > Legal.AwakeningMax) - return false; - return true; + case 0: pk.AV_HP = value; break; + case 1: pk.AV_ATK = value; break; + case 2: pk.AV_DEF = value; break; + case 3: pk.AV_SPE = value; break; + case 4: pk.AV_SPA = value; break; + case 5: pk.AV_SPD = value; break; + default: + throw new ArgumentOutOfRangeException(nameof(index)); } - - /// - /// Sets one of the values based on its index within the array. - /// - /// Pokémon to modify. - /// Index to set to - /// Value to set - public static void SetAV(this IAwakened pk, int index, int value) - { - switch (index) - { - case 0: pk.AV_HP = value; break; - case 1: pk.AV_ATK = value; break; - case 2: pk.AV_DEF = value; break; - case 3: pk.AV_SPE = value; break; - case 4: pk.AV_SPA = value; break; - case 5: pk.AV_SPD = value; break; - default: - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - - /// - /// Sets one of the values based on its index within the array. - /// - /// Pokémon to check. - /// Index to get - public static int GetAV(this IAwakened pk, int index) - { - return index switch - { - 0 => pk.AV_HP, - 1 => pk.AV_ATK, - 2 => pk.AV_DEF, - 3 => pk.AV_SPE, - 4 => pk.AV_SPA, - 5 => pk.AV_SPD, - _ => throw new ArgumentOutOfRangeException(nameof(index)) - }; - } - - /// - /// Sets the values based on the current IVs. - /// - /// Accessor for setting the values - /// Retriever for IVs - public static void SetSuggestedAwakenedValues(this IAwakened a, StatPKM pk) - { - for (int i = 0; i < 6; i++) - { - if (pk.GetIV(i) > 2) - a.SetAV(i, 200); - } - } - - public static int[] AVs(this IAwakened a) => new[] {a.AV_HP, a.AV_ATK, a.AV_DEF, a.AV_SPA, a.AV_SPD, a.AV_SPE}; } -} \ No newline at end of file + + /// + /// Sets one of the values based on its index within the array. + /// + /// Pokémon to check. + /// Index to get + public static int GetAV(this IAwakened pk, int index) + { + return index switch + { + 0 => pk.AV_HP, + 1 => pk.AV_ATK, + 2 => pk.AV_DEF, + 3 => pk.AV_SPE, + 4 => pk.AV_SPA, + 5 => pk.AV_SPD, + _ => throw new ArgumentOutOfRangeException(nameof(index)) + }; + } + + /// + /// Sets the values based on the current IVs. + /// + /// Accessor for setting the values + /// Retriever for IVs + public static void SetSuggestedAwakenedValues(this IAwakened a, StatPKM pk) + { + for (int i = 0; i < 6; i++) + { + if (pk.GetIV(i) > 2) + a.SetAV(i, 200); + } + } + + public static int[] AVs(this IAwakened a) => new[] {a.AV_HP, a.AV_ATK, a.AV_DEF, a.AV_SPA, a.AV_SPD, a.AV_SPE}; +} diff --git a/pkNX.Structures/VsTrainer/Base/IMoveset.cs b/pkNX.Structures/VsTrainer/Base/IMoveset.cs index 68c268f2..12620af4 100644 --- a/pkNX.Structures/VsTrainer/Base/IMoveset.cs +++ b/pkNX.Structures/VsTrainer/Base/IMoveset.cs @@ -1,10 +1,9 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public interface IMoveset { - public interface IMoveset - { - int Move1 { get; set; } - int Move2 { get; set; } - int Move3 { get; set; } - int Move4 { get; set; } - } -} \ No newline at end of file + int Move1 { get; set; } + int Move2 { get; set; } + int Move3 { get; set; } + int Move4 { get; set; } +} diff --git a/pkNX.Structures/VsTrainer/Base/ITrainerPoke.cs b/pkNX.Structures/VsTrainer/Base/ITrainerPoke.cs index 77238736..c83b6317 100644 --- a/pkNX.Structures/VsTrainer/Base/ITrainerPoke.cs +++ b/pkNX.Structures/VsTrainer/Base/ITrainerPoke.cs @@ -1,27 +1,26 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public interface IPokeData { - public interface IPokeData - { - int Species { get; set; } - int Level { get; set; } - int Nature { get; set; } - int Form { get; set; } - int HeldItem { get; set; } - int Gender { get; set; } - int Ability { get; set; } + int Species { get; set; } + int Level { get; set; } + int Nature { get; set; } + int Form { get; set; } + int HeldItem { get; set; } + int Gender { get; set; } + int Ability { get; set; } - int IV_HP { get; set; } - int IV_ATK { get; set; } - int IV_DEF { get; set; } - int IV_SPA { get; set; } - int IV_SPD { get; set; } - int IV_SPE { get; set; } + int IV_HP { get; set; } + int IV_ATK { get; set; } + int IV_DEF { get; set; } + int IV_SPA { get; set; } + int IV_SPD { get; set; } + int IV_SPE { get; set; } - int EV_HP { get; set; } - int EV_ATK { get; set; } - int EV_DEF { get; set; } - int EV_SPA { get; set; } - int EV_SPD { get; set; } - int EV_SPE { get; set; } - } -} \ No newline at end of file + int EV_HP { get; set; } + int EV_ATK { get; set; } + int EV_DEF { get; set; } + int EV_SPA { get; set; } + int EV_SPD { get; set; } + int EV_SPE { get; set; } +} diff --git a/pkNX.Structures/VsTrainer/Base/StatPKM.cs b/pkNX.Structures/VsTrainer/Base/StatPKM.cs index 6e55e7d2..ddabf76a 100644 --- a/pkNX.Structures/VsTrainer/Base/StatPKM.cs +++ b/pkNX.Structures/VsTrainer/Base/StatPKM.cs @@ -1,144 +1,143 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class StatPKM : IPokeData { - public abstract class StatPKM : IPokeData + public abstract int Species { get; set; } + public abstract int Form { get; set; } + public abstract int Level { get; set; } + public abstract int Nature { get; set; } + + public abstract int HeldItem { get; set; } + public abstract int Gender { get; set; } + public abstract int Ability { get; set; } + + public abstract int IV_HP { get; set; } + public abstract int IV_ATK { get; set; } + public abstract int IV_DEF { get; set; } + public abstract int IV_SPA { get; set; } + public abstract int IV_SPD { get; set; } + public abstract int IV_SPE { get; set; } + + public abstract int EV_HP { get; set; } + public abstract int EV_ATK { get; set; } + public abstract int EV_DEF { get; set; } + public abstract int EV_SPA { get; set; } + public abstract int EV_SPD { get; set; } + public abstract int EV_SPE { get; set; } + + public virtual ushort[] GetStats(IPersonalInfo p) { - public abstract int Species { get; set; } - public abstract int Form { get; set; } - public abstract int Level { get; set; } - public abstract int Nature { get; set; } + ushort[] Stats = new ushort[6]; + Stats[0] = (ushort)(((IV_HP + (2 * p.HP) + (EV_HP / 4) + 100) * Level / 100) + 10); + Stats[1] = (ushort)(((IV_ATK + (2 * p.ATK) + (EV_ATK / 4)) * Level / 100) + 5); + Stats[2] = (ushort)(((IV_DEF + (2 * p.DEF) + (EV_DEF / 4)) * Level / 100) + 5); + Stats[4] = (ushort)(((IV_SPA + (2 * p.SPA) + (EV_SPA / 4)) * Level / 100) + 5); + Stats[5] = (ushort)(((IV_SPD + (2 * p.SPD) + (EV_SPD / 4)) * Level / 100) + 5); + Stats[3] = (ushort)(((IV_SPE + (2 * p.SPE) + (EV_SPE / 4)) * Level / 100) + 5); + if (p.HP == 1) + Stats[0] = 1; - public abstract int HeldItem { get; set; } - public abstract int Gender { get; set; } - public abstract int Ability { get; set; } - - public abstract int IV_HP { get; set; } - public abstract int IV_ATK { get; set; } - public abstract int IV_DEF { get; set; } - public abstract int IV_SPA { get; set; } - public abstract int IV_SPD { get; set; } - public abstract int IV_SPE { get; set; } - - public abstract int EV_HP { get; set; } - public abstract int EV_ATK { get; set; } - public abstract int EV_DEF { get; set; } - public abstract int EV_SPA { get; set; } - public abstract int EV_SPD { get; set; } - public abstract int EV_SPE { get; set; } - - public virtual ushort[] GetStats(IPersonalInfo p) + // Account for nature + int incr = (Nature / 5) + 1; + int decr = (Nature % 5) + 1; + if (incr != decr) { - ushort[] Stats = new ushort[6]; - Stats[0] = (ushort)(((IV_HP + (2 * p.HP) + (EV_HP / 4) + 100) * Level / 100) + 10); - Stats[1] = (ushort)(((IV_ATK + (2 * p.ATK) + (EV_ATK / 4)) * Level / 100) + 5); - Stats[2] = (ushort)(((IV_DEF + (2 * p.DEF) + (EV_DEF / 4)) * Level / 100) + 5); - Stats[4] = (ushort)(((IV_SPA + (2 * p.SPA) + (EV_SPA / 4)) * Level / 100) + 5); - Stats[5] = (ushort)(((IV_SPD + (2 * p.SPD) + (EV_SPD / 4)) * Level / 100) + 5); - Stats[3] = (ushort)(((IV_SPE + (2 * p.SPE) + (EV_SPE / 4)) * Level / 100) + 5); - if (p.HP == 1) - Stats[0] = 1; - - // Account for nature - int incr = (Nature / 5) + 1; - int decr = (Nature % 5) + 1; - if (incr != decr) - { - Stats[incr] *= 11; - Stats[incr] /= 10; - Stats[decr] *= 9; - Stats[decr] /= 10; - } - - return Stats; + Stats[incr] *= 11; + Stats[incr] /= 10; + Stats[decr] *= 9; + Stats[decr] /= 10; } - public int HiddenPowerType => 15 * ((IV_HP & 1) + (2 * (IV_ATK & 1)) + (4 * (IV_DEF & 1)) + (8 * (IV_SPE & 1)) + (16 * (IV_SPA & 1)) + (32 * (IV_SPD & 1))) / 63; + return Stats; + } - public int GetIV(int index) + public int HiddenPowerType => 15 * ((IV_HP & 1) + (2 * (IV_ATK & 1)) + (4 * (IV_DEF & 1)) + (8 * (IV_SPE & 1)) + (16 * (IV_SPA & 1)) + (32 * (IV_SPD & 1))) / 63; + + public int GetIV(int index) + { + return index switch { - return index switch - { - 0 => IV_HP, - 1 => IV_ATK, - 2 => IV_DEF, - 3 => IV_SPE, - 4 => IV_SPA, - 5 => IV_SPD, - _ => throw new ArgumentOutOfRangeException(nameof(index)) - }; - } - - public void SetIV(int index, int value) - { - switch (index) - { - case 0: IV_HP = value; break; - case 1: IV_ATK = value; break; - case 2: IV_DEF = value; break; - case 3: IV_SPE = value; break; - case 4: IV_SPA = value; break; - case 5: IV_SPD = value; break; - default: - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - - public int GetEV(int index) - { - return index switch - { - 0 => EV_HP, - 1 => EV_ATK, - 2 => EV_DEF, - 3 => EV_SPE, - 4 => EV_SPA, - 5 => EV_SPD, - _ => throw new ArgumentOutOfRangeException(nameof(index)) - }; - } - - public void SetEV(int index, int value) - { - switch (index) - { - case 0: EV_HP = value; break; - case 1: EV_ATK = value; break; - case 2: EV_DEF = value; break; - case 3: EV_SPE = value; break; - case 4: EV_SPA = value; break; - case 5: EV_SPD = value; break; - default: - throw new ArgumentOutOfRangeException(nameof(index)); - } - } - - public void SetHPIVs(int type) - { - for (int i = 0; i < 6; i++) - { - var val = (GetIV(i) & 0x1E) + hpivs[type, i]; - SetIV(i, val); - } - } - - private static readonly int[,] hpivs = { - { 1, 1, 0, 0, 0, 0 }, // Fighting - { 0, 0, 0, 0, 0, 1 }, // Flying - { 1, 1, 0, 0, 0, 1 }, // Poison - { 1, 1, 1, 0, 0, 1 }, // Ground - { 1, 1, 0, 1, 0, 0 }, // Rock - { 1, 0, 0, 1, 0, 1 }, // Bug - { 1, 0, 1, 1, 0, 1 }, // Ghost - { 1, 1, 1, 1, 0, 1 }, // Steel - { 1, 0, 1, 0, 1, 0 }, // Fire - { 1, 0, 0, 0, 1, 1 }, // Water - { 1, 0, 1, 0, 1, 1 }, // Grass - { 1, 1, 1, 0, 1, 1 }, // Electric - { 1, 0, 1, 1, 1, 0 }, // Psychic - { 1, 0, 0, 1, 1, 1 }, // Ice - { 1, 0, 1, 1, 1, 1 }, // Dragon - { 1, 1, 1, 1, 1, 1 }, // Dark + 0 => IV_HP, + 1 => IV_ATK, + 2 => IV_DEF, + 3 => IV_SPE, + 4 => IV_SPA, + 5 => IV_SPD, + _ => throw new ArgumentOutOfRangeException(nameof(index)) }; } -} \ No newline at end of file + + public void SetIV(int index, int value) + { + switch (index) + { + case 0: IV_HP = value; break; + case 1: IV_ATK = value; break; + case 2: IV_DEF = value; break; + case 3: IV_SPE = value; break; + case 4: IV_SPA = value; break; + case 5: IV_SPD = value; break; + default: + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + + public int GetEV(int index) + { + return index switch + { + 0 => EV_HP, + 1 => EV_ATK, + 2 => EV_DEF, + 3 => EV_SPE, + 4 => EV_SPA, + 5 => EV_SPD, + _ => throw new ArgumentOutOfRangeException(nameof(index)) + }; + } + + public void SetEV(int index, int value) + { + switch (index) + { + case 0: EV_HP = value; break; + case 1: EV_ATK = value; break; + case 2: EV_DEF = value; break; + case 3: EV_SPE = value; break; + case 4: EV_SPA = value; break; + case 5: EV_SPD = value; break; + default: + throw new ArgumentOutOfRangeException(nameof(index)); + } + } + + public void SetHPIVs(int type) + { + for (int i = 0; i < 6; i++) + { + var val = (GetIV(i) & 0x1E) + hpivs[type, i]; + SetIV(i, val); + } + } + + private static readonly int[,] hpivs = { + { 1, 1, 0, 0, 0, 0 }, // Fighting + { 0, 0, 0, 0, 0, 1 }, // Flying + { 1, 1, 0, 0, 0, 1 }, // Poison + { 1, 1, 1, 0, 0, 1 }, // Ground + { 1, 1, 0, 1, 0, 0 }, // Rock + { 1, 0, 0, 1, 0, 1 }, // Bug + { 1, 0, 1, 1, 0, 1 }, // Ghost + { 1, 1, 1, 1, 0, 1 }, // Steel + { 1, 0, 1, 0, 1, 0 }, // Fire + { 1, 0, 0, 0, 1, 1 }, // Water + { 1, 0, 1, 0, 1, 1 }, // Grass + { 1, 1, 1, 0, 1, 1 }, // Electric + { 1, 0, 1, 1, 1, 0 }, // Psychic + { 1, 0, 0, 1, 1, 1 }, // Ice + { 1, 0, 1, 1, 1, 1 }, // Dragon + { 1, 1, 1, 1, 1, 1 }, // Dark + }; +} diff --git a/pkNX.Structures/VsTrainer/Base/TrainerClass.cs b/pkNX.Structures/VsTrainer/Base/TrainerClass.cs index 181e791b..7e49f07d 100644 --- a/pkNX.Structures/VsTrainer/Base/TrainerClass.cs +++ b/pkNX.Structures/VsTrainer/Base/TrainerClass.cs @@ -1,18 +1,17 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class TrainerClass { - public abstract class TrainerClass - { - public abstract int SIZE { get; } - protected byte[] Data; + public abstract int SIZE { get; } + protected byte[] Data; - public virtual int Gender { get; set; } = 0; - public virtual int Multi { get; set; } = 0; - public virtual int Group { get; set; } = 0; - public virtual int BallID { get; set; } = 4; - public virtual int BattleBackground { get; set; } = 0; - public virtual int EyeCatchBGM { get; set; } = 0; + public virtual int Gender { get; set; } + public virtual int Multi { get; set; } + public virtual int Group { get; set; } + public virtual int BallID { get; set; } = 4; + public virtual int BattleBackground { get; set; } + public virtual int EyeCatchBGM { get; set; } - public virtual bool IsBoss => false; - public virtual int MegaItemID => 773; - } + public virtual bool IsBoss => false; + public virtual int MegaItemID => 773; } diff --git a/pkNX.Structures/VsTrainer/Base/TrainerData.cs b/pkNX.Structures/VsTrainer/Base/TrainerData.cs index 7d645a14..9c7391c6 100644 --- a/pkNX.Structures/VsTrainer/Base/TrainerData.cs +++ b/pkNX.Structures/VsTrainer/Base/TrainerData.cs @@ -1,27 +1,26 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class TrainerData { - public abstract class TrainerData - { - public abstract int SIZE { get; } - protected byte[] Data; + public abstract int SIZE { get; } + protected byte[] Data; - public abstract int Class { get; set; } - public abstract BattleMode Mode { get; set; } - public abstract int NumPokemon { get; set; } - public abstract int Item1 { get; set; } - public abstract int Item2 { get; set; } - public abstract int Item3 { get; set; } - public abstract int Item4 { get; set; } + public abstract int Class { get; set; } + public abstract BattleMode Mode { get; set; } + public abstract int NumPokemon { get; set; } + public abstract int Item1 { get; set; } + public abstract int Item2 { get; set; } + public abstract int Item3 { get; set; } + public abstract int Item4 { get; set; } - public abstract uint AI { get; set; } - public abstract bool Heal { get; set; } - public abstract int Money { get; set; } - public abstract int Gift { get; set; } + public abstract uint AI { get; set; } + public abstract bool Heal { get; set; } + public abstract int Money { get; set; } + public abstract int Gift { get; set; } - // derived - public bool HasAllyTrainer => (AI & 8) != 0; + // derived + public bool HasAllyTrainer => (AI & 8) != 0; - public byte[] Write() => Data; - protected TrainerData(byte[] trData) => Data = trData ?? new byte[SIZE]; - } + public byte[] Write() => Data; + protected TrainerData(byte[] trData) => Data = trData ?? new byte[SIZE]; } diff --git a/pkNX.Structures/VsTrainer/Base/TrainerPoke.cs b/pkNX.Structures/VsTrainer/Base/TrainerPoke.cs index 3afe0939..6386e50d 100644 --- a/pkNX.Structures/VsTrainer/Base/TrainerPoke.cs +++ b/pkNX.Structures/VsTrainer/Base/TrainerPoke.cs @@ -1,57 +1,56 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public abstract class TrainerPoke : StatPKM, IMoveset { - public abstract class TrainerPoke : StatPKM, IMoveset + protected byte[] Data; + + public abstract int Friendship { get; set; } + + public abstract bool Shiny { get; set; } + public abstract bool CanMegaEvolve { get; set; } + public abstract bool CanDynamax { get; set; } + + public abstract int Move1 { get; set; } + public abstract int Move2 { get; set; } + public abstract int Move3 { get; set; } + public abstract int Move4 { get; set; } + + public abstract uint IV32 { get; set; } + + public abstract int Rank { get; set; } + + public byte[] Write() => (byte[])Data.Clone(); + public abstract TrainerPoke Clone(); + + #region Derived + + public int[] Moves { - protected byte[] Data; - - public abstract int Friendship { get; set; } - - public abstract bool Shiny { get; set; } - public abstract bool CanMegaEvolve { get; set; } - public abstract bool CanDynamax { get; set; } - - public abstract int Move1 { get; set; } - public abstract int Move2 { get; set; } - public abstract int Move3 { get; set; } - public abstract int Move4 { get; set; } - - public abstract uint IV32 { get; set; } - - public abstract int Rank { get; set; } - - public byte[] Write() => (byte[])Data.Clone(); - public abstract TrainerPoke Clone(); - - #region Derived - - public int[] Moves - { - get => new[] { Move1, Move2, Move3, Move4 }; - set { if (value?.Length != 4) return; Move1 = value[0]; Move2 = value[1]; Move3 = value[2]; Move4 = value[3]; } - } - - public int[] IVs - { - get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; - set - { - if (value?.Length != 6) return; - IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; - IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; - } - } - - public int[] EVs - { - get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; - set - { - if (value?.Length != 6) return; - EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; - EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; - } - } - - #endregion + get => new[] { Move1, Move2, Move3, Move4 }; + set { if (value?.Length != 4) return; Move1 = value[0]; Move2 = value[1]; Move3 = value[2]; Move4 = value[3]; } } + + public int[] IVs + { + get => new[] { IV_HP, IV_ATK, IV_DEF, IV_SPE, IV_SPA, IV_SPD }; + set + { + if (value?.Length != 6) return; + IV_HP = value[0]; IV_ATK = value[1]; IV_DEF = value[2]; + IV_SPE = value[3]; IV_SPA = value[4]; IV_SPD = value[5]; + } + } + + public int[] EVs + { + get => new[] { EV_HP, EV_ATK, EV_DEF, EV_SPE, EV_SPA, EV_SPD }; + set + { + if (value?.Length != 6) return; + EV_HP = value[0]; EV_ATK = value[1]; EV_DEF = value[2]; + EV_SPE = value[3]; EV_SPA = value[4]; EV_SPD = value[5]; + } + } + + #endregion } diff --git a/pkNX.Structures/VsTrainer/Enums/AIType.cs b/pkNX.Structures/VsTrainer/Enums/AIType.cs index 91e21330..3b3bc761 100644 --- a/pkNX.Structures/VsTrainer/Enums/AIType.cs +++ b/pkNX.Structures/VsTrainer/Enums/AIType.cs @@ -1,18 +1,17 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum AIType : ushort { - [Flags] - public enum AIType : ushort - { - None = 0, - Basic = 1 << 0, - Strong = 1 << 1, - Expert = 1 << 2, + None = 0, + Basic = 1 << 0, + Strong = 1 << 1, + Expert = 1 << 2, - Double = 1 << 7, - // Allowance, - // UseItem, - // Switch, - } -} \ No newline at end of file + Double = 1 << 7, + // Allowance, + // UseItem, + // Switch, +} diff --git a/pkNX.Structures/VsTrainer/Enums/BattleMode.cs b/pkNX.Structures/VsTrainer/Enums/BattleMode.cs index 8e35567e..e58b282a 100644 --- a/pkNX.Structures/VsTrainer/Enums/BattleMode.cs +++ b/pkNX.Structures/VsTrainer/Enums/BattleMode.cs @@ -1,9 +1,8 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public enum BattleMode : byte { - public enum BattleMode : byte - { - Singles, - Doubles, - Multi, - } -} \ No newline at end of file + Singles, + Doubles, + Multi, +} diff --git a/pkNX.Structures/VsTrainer/GG/Trainer7b.cs b/pkNX.Structures/VsTrainer/GG/Trainer7b.cs index febace91..570a43f4 100644 --- a/pkNX.Structures/VsTrainer/GG/Trainer7b.cs +++ b/pkNX.Structures/VsTrainer/GG/Trainer7b.cs @@ -1,20 +1,19 @@ -using System.Diagnostics; +using System.Diagnostics; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Trainer7b : VsTrainer { - public class Trainer7b : VsTrainer + public Trainer7b(byte[] tr = null, byte[] tp = null) { - public Trainer7b(byte[] tr = null, byte[] tp = null) - { - Self = new TrainerData7b(tr); - LoadTeam(tp); - } + Self = new TrainerData7b(tr); + LoadTeam(tp); + } - private void LoadTeam(byte[] tp) - { - var pokes = TrainerPoke7b.ReadTeam(tp, Self); - Debug.Assert(pokes.Length == Self.NumPokemon); - Team.AddRange(pokes); - } + private void LoadTeam(byte[] tp) + { + var pokes = TrainerPoke7b.ReadTeam(tp, Self); + Debug.Assert(pokes.Length == Self.NumPokemon); + Team.AddRange(pokes); } } diff --git a/pkNX.Structures/VsTrainer/GG/Trainer8.cs b/pkNX.Structures/VsTrainer/GG/Trainer8.cs index c7aa3371..0ca623fd 100644 --- a/pkNX.Structures/VsTrainer/GG/Trainer8.cs +++ b/pkNX.Structures/VsTrainer/GG/Trainer8.cs @@ -1,20 +1,19 @@ -using System.Diagnostics; +using System.Diagnostics; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class Trainer8 : VsTrainer { - public class Trainer8 : VsTrainer + public Trainer8(byte[] tr = null, byte[] tp = null) { - public Trainer8(byte[] tr = null, byte[] tp = null) - { - Self = new TrainerData8(tr); - LoadTeam(tp); - } - - private void LoadTeam(byte[] tp) - { - var pokes = TrainerPoke8.ReadTeam(tp, Self); - Debug.Assert(pokes.Length == Self.NumPokemon); - Team.AddRange(pokes); - } + Self = new TrainerData8(tr); + LoadTeam(tp); } -} \ No newline at end of file + + private void LoadTeam(byte[] tp) + { + var pokes = TrainerPoke8.ReadTeam(tp, Self); + Debug.Assert(pokes.Length == Self.NumPokemon); + Team.AddRange(pokes); + } +} diff --git a/pkNX.Structures/VsTrainer/GG/TrainerAI.cs b/pkNX.Structures/VsTrainer/GG/TrainerAI.cs index 504030f8..21d57940 100644 --- a/pkNX.Structures/VsTrainer/GG/TrainerAI.cs +++ b/pkNX.Structures/VsTrainer/GG/TrainerAI.cs @@ -1,20 +1,19 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +[Flags] +public enum TrainerAI : byte { - [Flags] - public enum TrainerAI : byte - { - None = 0, + None = 0, - Basic = 1 << 0, - Strong = 1 << 1, - Expert = 1 << 2, + Basic = 1 << 0, + Strong = 1 << 1, + Expert = 1 << 2, - Doubles = 1 << 3, - Allowance = 1 << 4, - UseItem = 1 << 5, - PokeChange = 1 << 6, - Unused = 1 << 7, - } -} \ No newline at end of file + Doubles = 1 << 3, + Allowance = 1 << 4, + UseItem = 1 << 5, + PokeChange = 1 << 6, + Unused = 1 << 7, +} diff --git a/pkNX.Structures/VsTrainer/GG/TrainerClass7b.cs b/pkNX.Structures/VsTrainer/GG/TrainerClass7b.cs index e3832101..cc851e46 100644 --- a/pkNX.Structures/VsTrainer/GG/TrainerClass7b.cs +++ b/pkNX.Structures/VsTrainer/GG/TrainerClass7b.cs @@ -1,17 +1,16 @@ -namespace pkNX.Structures +namespace pkNX.Structures; + +public class TrainerClass7b : TrainerClass { - public class TrainerClass7b : TrainerClass - { - public sealed override int SIZE => 0x24; - public TrainerClass7b(byte[] data = null) => Data = data ?? new byte[SIZE]; + public sealed override int SIZE => 0x24; + public TrainerClass7b(byte[] data = null) => Data = data ?? new byte[SIZE]; - public byte Unk_0x00 { get => Data[0]; set => Data[0] = value; } - public override int Group { get => Data[1]; set => Data[1] = (byte)value; } - public override int BallID { get => Data[2]; set => Data[2] = (byte)value; } - public byte Unk_0x03 { get => Data[3]; set => Data[3] = value; } + public byte Unk_0x00 { get => Data[0]; set => Data[0] = value; } + public override int Group { get => Data[1]; set => Data[1] = (byte)value; } + public override int BallID { get => Data[2]; set => Data[2] = (byte)value; } + public byte Unk_0x03 { get => Data[3]; set => Data[3] = value; } - // model hash at end (name, form, variation)? + // model hash at end (name, form, variation)? - public override int MegaItemID => 773; - } -} \ No newline at end of file + public override int MegaItemID => 773; +} diff --git a/pkNX.Structures/VsTrainer/GG/TrainerClass8.cs b/pkNX.Structures/VsTrainer/GG/TrainerClass8.cs index 08e3b00d..3eb7e5df 100644 --- a/pkNX.Structures/VsTrainer/GG/TrainerClass8.cs +++ b/pkNX.Structures/VsTrainer/GG/TrainerClass8.cs @@ -1,30 +1,29 @@ using System.Text; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class TrainerClass8 : TrainerClass { - public class TrainerClass8 : TrainerClass - { - // 4 bytes used - // 4 bytes unused (align?) - // 10 bytes hash (model?) - // 0x80 bytes string1 file reference (eyecatch & bgm) - // 0x80 bytes string2 file reference (battle sequence) + // 4 bytes used + // 4 bytes unused (align?) + // 10 bytes hash (model?) + // 0x80 bytes string1 file reference (eyecatch & bgm) + // 0x80 bytes string2 file reference (battle sequence) - public sealed override int SIZE => 280; - public TrainerClass8(byte[] data = null) => Data = data ?? new byte[SIZE]; + public sealed override int SIZE => 280; + public TrainerClass8(byte[] data = null) => Data = data ?? new byte[SIZE]; - public byte Unk_0x00 { get => Data[0]; set => Data[0] = value; } // bool? - public override int Group { get => Data[1]; set => Data[1] = (byte)value; } - public override int BallID { get => Data[2]; set => Data[2] = (byte)value; } - public byte Unk_0x03 { get => Data[3]; set => Data[3] = value; } // bool? + public byte Unk_0x00 { get => Data[0]; set => Data[0] = value; } // bool? + public override int Group { get => Data[1]; set => Data[1] = (byte)value; } + public override int BallID { get => Data[2]; set => Data[2] = (byte)value; } + public byte Unk_0x03 { get => Data[3]; set => Data[3] = value; } // bool? - // model hash (name, form, variation)? - public byte[] Hash => Data.Slice(0x8, 0x10); + // model hash (name, form, variation)? + public byte[] Hash => Data.Slice(0x8, 0x10); - // music? - public string S1 => Encoding.ASCII.GetString(Data, 0x18, 0x80).TrimEnd('\0'); + // music? + public string S1 => Encoding.ASCII.GetString(Data, 0x18, 0x80).TrimEnd('\0'); - // sequence? - public string S2 => Encoding.ASCII.GetString(Data, 0x88, 0x80).TrimEnd('\0'); - } + // sequence? + public string S2 => Encoding.ASCII.GetString(Data, 0x88, 0x80).TrimEnd('\0'); } \ No newline at end of file diff --git a/pkNX.Structures/VsTrainer/GG/TrainerData7b.cs b/pkNX.Structures/VsTrainer/GG/TrainerData7b.cs index 7a22b108..3ff7c255 100644 --- a/pkNX.Structures/VsTrainer/GG/TrainerData7b.cs +++ b/pkNX.Structures/VsTrainer/GG/TrainerData7b.cs @@ -1,27 +1,26 @@ using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class TrainerData7b : TrainerData { - public sealed class TrainerData7b : TrainerData - { - public override int SIZE => 0x17; - public TrainerData7b(byte[] data = null) : base(data) { } + public override int SIZE => 0x17; + public TrainerData7b(byte[] data = null) : base(data) { } - public override int Class { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } - public override BattleMode Mode { get => (BattleMode)Data[2]; set => Data[2] = (byte)value; } // Not sure - public override int NumPokemon { get => Data[3]; set => Data[3] = (byte)(value % 7); } - public override int Item1 { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x04); } - public override int Item2 { get => BitConverter.ToUInt16(Data, 0x06); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x06); } - public override int Item3 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } - public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } + public override int Class { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } + public override BattleMode Mode { get => (BattleMode)Data[2]; set => Data[2] = (byte)value; } // Not sure + public override int NumPokemon { get => Data[3]; set => Data[3] = (byte)(value % 7); } + public override int Item1 { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x04); } + public override int Item2 { get => BitConverter.ToUInt16(Data, 0x06); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x06); } + public override int Item3 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } + public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } - public override uint AI { get => BitConverter.ToUInt32(Data, 0x0C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0C); } - public override bool Heal { get => Data[0x10] == 1; set => Data[0x10] = value ? (byte)1 : (byte)0; } // unused? - public override int Money { get => Data[0x11]; set => Data[0x11] = (byte)value; } + public override uint AI { get => BitConverter.ToUInt32(Data, 0x0C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0C); } + public override bool Heal { get => Data[0x10] == 1; set => Data[0x10] = value ? (byte)1 : (byte)0; } // unused? + public override int Money { get => Data[0x11]; set => Data[0x11] = (byte)value; } - // 12 unused + // 12 unused - public override int Gift { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } - public int GiftQuantity { get => Data[0x16]; set => Data[0x16] = (byte)value; } - } + public override int Gift { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } + public int GiftQuantity { get => Data[0x16]; set => Data[0x16] = (byte)value; } } \ No newline at end of file diff --git a/pkNX.Structures/VsTrainer/GG/TrainerData8.cs b/pkNX.Structures/VsTrainer/GG/TrainerData8.cs index 6bccff7c..bdc6c23f 100644 --- a/pkNX.Structures/VsTrainer/GG/TrainerData8.cs +++ b/pkNX.Structures/VsTrainer/GG/TrainerData8.cs @@ -1,24 +1,23 @@ -using System; +using System; -namespace pkNX.Structures +namespace pkNX.Structures; + +public sealed class TrainerData8 : TrainerData { - public sealed class TrainerData8 : TrainerData - { - public override int SIZE => 0x14; - public TrainerData8(byte[] data = null) : base(data) { } + public override int SIZE => 0x14; + public TrainerData8(byte[] data = null) : base(data) { } - public override int Class { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } - public override BattleMode Mode { get => (BattleMode)Data[2]; set => Data[2] = (byte)value; } // Not sure - public override int NumPokemon { get => Data[3]; set => Data[3] = (byte)(value % 7); } - public override int Item1 { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x04); } - public override int Item2 { get => BitConverter.ToUInt16(Data, 0x06); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x06); } - public override int Item3 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } - public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } + public override int Class { get => BitConverter.ToUInt16(Data, 0x00); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x00); } + public override BattleMode Mode { get => (BattleMode)Data[2]; set => Data[2] = (byte)value; } // Not sure + public override int NumPokemon { get => Data[3]; set => Data[3] = (byte)(value % 7); } + public override int Item1 { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x04); } + public override int Item2 { get => BitConverter.ToUInt16(Data, 0x06); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x06); } + public override int Item3 { get => BitConverter.ToUInt16(Data, 0x08); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x08); } + public override int Item4 { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } - public override uint AI { get => BitConverter.ToUInt32(Data, 0x0C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0C); } - public override bool Heal { get => Data[0x10] == 1; set => Data[0x10] = value ? (byte)1 : (byte)0; } // unused? - public override int Money { get => Data[0x11]; set => Data[0x11] = (byte)value; } + public override uint AI { get => BitConverter.ToUInt32(Data, 0x0C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x0C); } + public override bool Heal { get => Data[0x10] == 1; set => Data[0x10] = value ? (byte)1 : (byte)0; } // unused? + public override int Money { get => Data[0x11]; set => Data[0x11] = (byte)value; } - public override int Gift { get => BitConverter.ToUInt16(Data, 0x12); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x12); } // unused? - } -} \ No newline at end of file + public override int Gift { get => BitConverter.ToUInt16(Data, 0x12); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x12); } // unused? +} diff --git a/pkNX.Structures/VsTrainer/GG/TrainerPoke7b.cs b/pkNX.Structures/VsTrainer/GG/TrainerPoke7b.cs index 3629fb66..383a1c09 100644 --- a/pkNX.Structures/VsTrainer/GG/TrainerPoke7b.cs +++ b/pkNX.Structures/VsTrainer/GG/TrainerPoke7b.cs @@ -1,174 +1,173 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class TrainerPoke7b : TrainerPoke, IAwakened { - public class TrainerPoke7b : TrainerPoke, IAwakened + public const int SIZE = 0x28; + public override TrainerPoke Clone() => new TrainerPoke7b((byte[])Write().Clone()); + public TrainerPoke7b(byte[] data = null) => Data = data ?? new byte[SIZE]; + + public static TrainerPoke7b[] ReadTeam(byte[] data, TrainerData _) => data.GetArray((x, offset) => new TrainerPoke7b(offset, x), SIZE); + public static byte[] WriteTeam(IList team, TrainerData _) => team.SelectMany(z => z.Write()).ToArray(); + + public TrainerPoke7b(int offset, byte[] data = null) { - public const int SIZE = 0x28; - public override TrainerPoke Clone() => new TrainerPoke7b((byte[])Write().Clone()); - public TrainerPoke7b(byte[] data = null) => Data = data ?? new byte[SIZE]; + Data = new byte[SIZE]; + if (data == null || offset + SIZE > data.Length) + return; + Array.Copy(data, offset, Data, 0, SIZE); + } - public static TrainerPoke7b[] ReadTeam(byte[] data, TrainerData _) => data.GetArray((x, offset) => new TrainerPoke7b(offset, x), SIZE); - public static byte[] WriteTeam(IList team, TrainerData _) => team.SelectMany(z => z.Write()).ToArray(); + public override int Gender + { + get => Data[0] & 0x3; + set => Data[0] = (byte)((Data[0] & 0xFC) | (value & 0x3)); + } - public TrainerPoke7b(int offset, byte[] data = null) + public override int Ability + { + get => (Data[0] >> 4) & 0x3; + set => Data[0] = (byte)((Data[0] & 0xCF) | ((value & 0x3) << 4)); + } + + public override int Nature { get => Data[0x01]; set => Data[0x01] = (byte)value; } + + public override int EV_HP { get => Data[0x02]; set => Data[0x02] = (byte)value; } + public override int EV_ATK { get => Data[0x03]; set => Data[0x03] = (byte)value; } + public override int EV_DEF { get => Data[0x04]; set => Data[0x04] = (byte)value; } + public override int EV_SPA { get => Data[0x05]; set => Data[0x05] = (byte)value; } + public override int EV_SPD { get => Data[0x06]; set => Data[0x06] = (byte)value; } + public override int EV_SPE { get => Data[0x07]; set => Data[0x07] = (byte)value; } + + public int AV_HP { get => Data[0x08]; set => Data[0x08] = (byte)value; } + public int AV_ATK { get => Data[0x09]; set => Data[0x09] = (byte)value; } + public int AV_DEF { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } + public int AV_SPA { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } + public int AV_SPD { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } + public int AV_SPE { get => Data[0x0D]; set => Data[0x0D] = (byte)value; } + + public override int Friendship { get => Data[0x0E]; set => Data[0x0E] = (byte)value; } + public override int Rank { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } + public override bool CanDynamax { get => false; set { } } + + public override uint IV32 { get => BitConverter.ToUInt32(Data, 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, 0x10); } + public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); } + public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); } + public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); } + public override int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); } + public override int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); } + public override int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); } + public override bool Shiny { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (IV32 & ~0x40000000u) | (value ? 0x40000000u : 0); } + + public override bool CanMegaEvolve + { + get => ((IV32 >> 31) & 1) == 1; + set => IV32 = (IV32 & ~(1 << 31)) | (uint)((value ? 1 : 0) << 31); + } + + public int MegaFormChoice { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } + public override int Level { get => BitConverter.ToUInt16(Data, 0x16); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x16); } + public override int Species { get => BitConverter.ToUInt16(Data, 0x18); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x18); } + public override int Form { get => BitConverter.ToUInt16(Data, 0x1A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1A); } + public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x1C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1C); } + + // 1E-1F unused + + public override int Move1 { get => BitConverter.ToUInt16(Data, 0x20); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x20); } + public override int Move2 { get => BitConverter.ToUInt16(Data, 0x22); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x22); } + public override int Move3 { get => BitConverter.ToUInt16(Data, 0x24); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x24); } + public override int Move4 { get => BitConverter.ToUInt16(Data, 0x26); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x26); } + + public override ushort[] GetStats(IPersonalInfo p) + { + return CalculateStatsBeluga(p); + } + + public ushort[] CalculateStatsBeluga(IPersonalInfo p) + { + int level = Level; + int nature = Nature; + int friend = Friendship; // stats +10% depending on friendship! + int scalar = (int)(((friend / 255.0f / 10.0f) + 1.0f) * 100.0f); + ushort[] Stats = { - Data = new byte[SIZE]; - if (data == null || offset + SIZE > data.Length) - return; - Array.Copy(data, offset, Data, 0, SIZE); - } + (ushort)(AV_HP + GetStat(p.HP, IV_HP, level) + 10 + level), + (ushort)(AV_ATK + (scalar * GetStat(p.ATK, IV_ATK, level, nature, 0) / 100)), + (ushort)(AV_DEF + (scalar * GetStat(p.DEF, IV_DEF, level, nature, 1) / 100)), + (ushort)(AV_SPE + (scalar * GetStat(p.SPE, IV_SPE, level, nature, 4) / 100)), + (ushort)(AV_SPA + (scalar * GetStat(p.SPA, IV_SPA, level, nature, 2) / 100)), + (ushort)(AV_SPD + (scalar * GetStat(p.SPD, IV_SPD, level, nature, 3) / 100)), + }; + if (Species == 292) + Stats[0] = 1; + return Stats; + } - public override int Gender + /// + /// Gets the initial stat value based on the base stat value, IV, and current level. + /// + /// stat. + /// Current IV, already accounted for Hyper Training + /// Current Level + /// Initial Stat + private static int GetStat(int baseStat, int iv, int level) => (iv + (2 * baseStat)) * level / 100; + + /// + /// Gets the initial stat value with nature amplification applied. Used for all stats except HP. + /// + /// stat. + /// Current IV, already accounted for Hyper Training + /// Current Level + /// Current Nature + /// Stat amp index in the nature amp table + /// Initial Stat with nature amplification applied. + private static int GetStat(int baseStat, int iv, int level, int nature, int statIndex) + { + int initial = GetStat(baseStat, iv, level) + 5; + return AmplifyStat(nature, statIndex, initial); + } + + private static int AmplifyStat(int nature, int index, int initial) + { + return AbilityAmpTable[(5 * nature) + index] switch { - get => Data[0] & 0x3; - set => Data[0] = (byte)((Data[0] & 0xFC) | (value & 0x3)); - } - - public override int Ability - { - get => (Data[0] >> 4) & 0x3; - set => Data[0] = (byte)((Data[0] & 0xCF) | ((value & 0x3) << 4)); - } - - public override int Nature { get => Data[0x01]; set => Data[0x01] = (byte)value; } - - public override int EV_HP { get => Data[0x02]; set => Data[0x02] = (byte)value; } - public override int EV_ATK { get => Data[0x03]; set => Data[0x03] = (byte)value; } - public override int EV_DEF { get => Data[0x04]; set => Data[0x04] = (byte)value; } - public override int EV_SPA { get => Data[0x05]; set => Data[0x05] = (byte)value; } - public override int EV_SPD { get => Data[0x06]; set => Data[0x06] = (byte)value; } - public override int EV_SPE { get => Data[0x07]; set => Data[0x07] = (byte)value; } - - public int AV_HP { get => Data[0x08]; set => Data[0x08] = (byte)value; } - public int AV_ATK { get => Data[0x09]; set => Data[0x09] = (byte)value; } - public int AV_DEF { get => Data[0x0A]; set => Data[0x0A] = (byte)value; } - public int AV_SPA { get => Data[0x0B]; set => Data[0x0B] = (byte)value; } - public int AV_SPD { get => Data[0x0C]; set => Data[0x0C] = (byte)value; } - public int AV_SPE { get => Data[0x0D]; set => Data[0x0D] = (byte)value; } - - public override int Friendship { get => Data[0x0E]; set => Data[0x0E] = (byte)value; } - public override int Rank { get => Data[0x0F]; set => Data[0x0F] = (byte)value; } - public override bool CanDynamax { get => false; set { } } - - public override uint IV32 { get => BitConverter.ToUInt32(Data, 0x10); set => BitConverter.GetBytes(value).CopyTo(Data, 0x10); } - public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); } - public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); } - public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); } - public override int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); } - public override int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); } - public override int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); } - public override bool Shiny { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (IV32 & ~0x40000000u) | (value ? 0x40000000u : 0); } - - public override bool CanMegaEvolve - { - get => ((IV32 >> 31) & 1) == 1; - set => IV32 = (IV32 & ~(1 << 31)) | (uint)((value ? 1 : 0) << 31); - } - - public int MegaFormChoice { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } - public override int Level { get => BitConverter.ToUInt16(Data, 0x16); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x16); } - public override int Species { get => BitConverter.ToUInt16(Data, 0x18); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x18); } - public override int Form { get => BitConverter.ToUInt16(Data, 0x1A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1A); } - public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x1C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x1C); } - - // 1E-1F unused - - public override int Move1 { get => BitConverter.ToUInt16(Data, 0x20); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x20); } - public override int Move2 { get => BitConverter.ToUInt16(Data, 0x22); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x22); } - public override int Move3 { get => BitConverter.ToUInt16(Data, 0x24); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x24); } - public override int Move4 { get => BitConverter.ToUInt16(Data, 0x26); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x26); } - - public override ushort[] GetStats(IPersonalInfo p) - { - return CalculateStatsBeluga(p); - } - - public ushort[] CalculateStatsBeluga(IPersonalInfo p) - { - int level = Level; - int nature = Nature; - int friend = Friendship; // stats +10% depending on friendship! - int scalar = (int)(((friend / 255.0f / 10.0f) + 1.0f) * 100.0f); - ushort[] Stats = - { - (ushort)(AV_HP + GetStat(p.HP, IV_HP, level) + 10 + level), - (ushort)(AV_ATK + (scalar * GetStat(p.ATK, IV_ATK, level, nature, 0) / 100)), - (ushort)(AV_DEF + (scalar * GetStat(p.DEF, IV_DEF, level, nature, 1) / 100)), - (ushort)(AV_SPE + (scalar * GetStat(p.SPE, IV_SPE, level, nature, 4) / 100)), - (ushort)(AV_SPA + (scalar * GetStat(p.SPA, IV_SPA, level, nature, 2) / 100)), - (ushort)(AV_SPD + (scalar * GetStat(p.SPD, IV_SPD, level, nature, 3) / 100)), - }; - if (Species == 292) - Stats[0] = 1; - return Stats; - } - - /// - /// Gets the initial stat value based on the base stat value, IV, and current level. - /// - /// stat. - /// Current IV, already accounted for Hyper Training - /// Current Level - /// Initial Stat - private static int GetStat(int baseStat, int iv, int level) => (iv + (2 * baseStat)) * level / 100; - - /// - /// Gets the initial stat value with nature amplification applied. Used for all stats except HP. - /// - /// stat. - /// Current IV, already accounted for Hyper Training - /// Current Level - /// Current Nature - /// Stat amp index in the nature amp table - /// Initial Stat with nature amplification applied. - private static int GetStat(int baseStat, int iv, int level, int nature, int statIndex) - { - int initial = GetStat(baseStat, iv, level) + 5; - return AmplifyStat(nature, statIndex, initial); - } - - private static int AmplifyStat(int nature, int index, int initial) - { - return AbilityAmpTable[(5 * nature) + index] switch - { - 1 => (110 * initial / 100) // 110% - , - -1 => (90 * initial / 100) // 90% - , - _ => initial - }; - } - - private static readonly sbyte[] AbilityAmpTable = - { - 0, 0, 0, 0, 0, // Hardy - 1,-1, 0, 0, 0, // Lonely - 1, 0, 0, 0,-1, // Brave - 1, 0,-1, 0, 0, // Adamant - 1, 0, 0,-1, 0, // Naughty - -1, 1, 0, 0, 0, // Bold - 0, 0, 0, 0, 0, // Docile - 0, 1, 0, 0,-1, // Relaxed - 0, 1,-1, 0, 0, // Impish - 0, 1, 0,-1, 0, // Lax - -1, 0, 0, 0, 1, // Timid - 0,-1, 0, 0, 1, // Hasty - 0, 0, 0, 0, 0, // Serious - 0, 0,-1, 0, 1, // Jolly - 0, 0, 0,-1, 1, // Naive - -1, 0, 1, 0, 0, // Modest - 0,-1, 1, 0, 0, // Mild - 0, 0, 1, 0,-1, // Quiet - 0, 0, 0, 0, 0, // Bashful - 0, 0, 1,-1, 0, // Rash - -1, 0, 0, 1, 0, // Calm - 0,-1, 0, 1, 0, // Gentle - 0, 0, 0, 1,-1, // Sassy - 0, 0,-1, 1, 0, // Careful - 0, 0, 0, 0, 0, // Quirky + 1 => (110 * initial / 100) // 110% + , + -1 => (90 * initial / 100) // 90% + , + _ => initial }; } -} \ No newline at end of file + + private static readonly sbyte[] AbilityAmpTable = + { + 0, 0, 0, 0, 0, // Hardy + 1,-1, 0, 0, 0, // Lonely + 1, 0, 0, 0,-1, // Brave + 1, 0,-1, 0, 0, // Adamant + 1, 0, 0,-1, 0, // Naughty + -1, 1, 0, 0, 0, // Bold + 0, 0, 0, 0, 0, // Docile + 0, 1, 0, 0,-1, // Relaxed + 0, 1,-1, 0, 0, // Impish + 0, 1, 0,-1, 0, // Lax + -1, 0, 0, 0, 1, // Timid + 0,-1, 0, 0, 1, // Hasty + 0, 0, 0, 0, 0, // Serious + 0, 0,-1, 0, 1, // Jolly + 0, 0, 0,-1, 1, // Naive + -1, 0, 1, 0, 0, // Modest + 0,-1, 1, 0, 0, // Mild + 0, 0, 1, 0,-1, // Quiet + 0, 0, 0, 0, 0, // Bashful + 0, 0, 1,-1, 0, // Rash + -1, 0, 0, 1, 0, // Calm + 0,-1, 0, 1, 0, // Gentle + 0, 0, 0, 1,-1, // Sassy + 0, 0,-1, 1, 0, // Careful + 0, 0, 0, 0, 0, // Quirky + }; +} diff --git a/pkNX.Structures/VsTrainer/GG/TrainerPoke8.cs b/pkNX.Structures/VsTrainer/GG/TrainerPoke8.cs index 5332d35b..c558cc37 100644 --- a/pkNX.Structures/VsTrainer/GG/TrainerPoke8.cs +++ b/pkNX.Structures/VsTrainer/GG/TrainerPoke8.cs @@ -1,86 +1,85 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class TrainerPoke8 : TrainerPoke { - public class TrainerPoke8 : TrainerPoke + //sub_7101452DB0 + public const int SIZE = 0x20; + public override TrainerPoke Clone() => new TrainerPoke8((byte[])Write().Clone()); + public TrainerPoke8(byte[] data = null) => Data = data ?? new byte[SIZE]; + + public static TrainerPoke8[] ReadTeam(byte[] data, TrainerData _) => data.GetArray((x, offset) => new TrainerPoke8(offset, x), SIZE); + public static byte[] WriteTeam(IList team, TrainerData _) => team.SelectMany(z => z.Write()).ToArray(); + + public TrainerPoke8(int offset, byte[] data = null) { - //sub_7101452DB0 - public const int SIZE = 0x20; - public override TrainerPoke Clone() => new TrainerPoke8((byte[])Write().Clone()); - public TrainerPoke8(byte[] data = null) => Data = data ?? new byte[SIZE]; - - public static TrainerPoke8[] ReadTeam(byte[] data, TrainerData _) => data.GetArray((x, offset) => new TrainerPoke8(offset, x), SIZE); - public static byte[] WriteTeam(IList team, TrainerData _) => team.SelectMany(z => z.Write()).ToArray(); - - public TrainerPoke8(int offset, byte[] data = null) - { - Data = new byte[SIZE]; - if (data == null || offset + SIZE > data.Length) - return; - Array.Copy(data, offset, Data, 0, SIZE); - } - - public override int Gender - { - get => Data[0] & 0x3; - set => Data[0] = (byte)((Data[0] & 0xFC) | (value & 0x3)); - } - - public bool Flag - { - get => ((Data[0] >> 4) & 1) == 1; - set => Data[0] = (byte)((Data[0] & 0xF7) | ((value ? 1 : 0) << 4)); - } - - public override int Ability - { - get => (Data[0] >> 4) & 0x3; - set => Data[0] = (byte)((Data[0] & 0xCF) | ((value & 0x3) << 4)); - } - - public override int Nature { get => Data[0x01]; set => Data[0x01] = (byte)value; } - - public override int EV_HP { get => Data[0x02]; set => Data[0x02] = (byte)value; } - public override int EV_ATK { get => Data[0x03]; set => Data[0x03] = (byte)value; } - public override int EV_DEF { get => Data[0x04]; set => Data[0x04] = (byte)value; } - public override int EV_SPA { get => Data[0x05]; set => Data[0x05] = (byte)value; } - public override int EV_SPD { get => Data[0x06]; set => Data[0x06] = (byte)value; } - public override int EV_SPE { get => Data[0x07]; set => Data[0x07] = (byte)value; } - - public byte DynamaxLevel { get => Data[0x08]; set => Data[0x08] = Math.Min((byte)10, value); } - public bool CanGigantamax { get => Data[0x09] != 0; set => Data[0x09] = Convert.ToByte(value); } - - public override int Friendship { get => 0; set { } } - public override int Rank { get => 0; set { } } - public override bool CanMegaEvolve { get => false; set { } } - - public override int Level { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } - public override int Species { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } - public override int Form { get => BitConverter.ToUInt16(Data, 0x0E); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0E); } - public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x10); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); } - - public override int Move1 { get => BitConverter.ToUInt16(Data, 0x12); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x12); } - public override int Move2 { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } - public override int Move3 { get => BitConverter.ToUInt16(Data, 0x16); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x16); } - public override int Move4 { get => BitConverter.ToUInt16(Data, 0x18); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x18); } - - // 1A-1B unused padding - - public override uint IV32 { get => BitConverter.ToUInt32(Data, 0x1C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1C); } - public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); } - public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); } - public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); } - public override int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); } - public override int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); } - public override int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); } - public override bool Shiny { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (IV32 & ~0x40000000u) | (value ? 0x40000000u : 0); } - - public override bool CanDynamax - { - get => ((IV32 >> 31) & 1) == 1; - set => IV32 = (IV32 & ~(1 << 31)) | (uint)((value ? 1 : 0) << 31); - } + Data = new byte[SIZE]; + if (data == null || offset + SIZE > data.Length) + return; + Array.Copy(data, offset, Data, 0, SIZE); } -} \ No newline at end of file + + public override int Gender + { + get => Data[0] & 0x3; + set => Data[0] = (byte)((Data[0] & 0xFC) | (value & 0x3)); + } + + public bool Flag + { + get => ((Data[0] >> 4) & 1) == 1; + set => Data[0] = (byte)((Data[0] & 0xF7) | ((value ? 1 : 0) << 4)); + } + + public override int Ability + { + get => (Data[0] >> 4) & 0x3; + set => Data[0] = (byte)((Data[0] & 0xCF) | ((value & 0x3) << 4)); + } + + public override int Nature { get => Data[0x01]; set => Data[0x01] = (byte)value; } + + public override int EV_HP { get => Data[0x02]; set => Data[0x02] = (byte)value; } + public override int EV_ATK { get => Data[0x03]; set => Data[0x03] = (byte)value; } + public override int EV_DEF { get => Data[0x04]; set => Data[0x04] = (byte)value; } + public override int EV_SPA { get => Data[0x05]; set => Data[0x05] = (byte)value; } + public override int EV_SPD { get => Data[0x06]; set => Data[0x06] = (byte)value; } + public override int EV_SPE { get => Data[0x07]; set => Data[0x07] = (byte)value; } + + public byte DynamaxLevel { get => Data[0x08]; set => Data[0x08] = Math.Min((byte)10, value); } + public bool CanGigantamax { get => Data[0x09] != 0; set => Data[0x09] = Convert.ToByte(value); } + + public override int Friendship { get => 0; set { } } + public override int Rank { get => 0; set { } } + public override bool CanMegaEvolve { get => false; set { } } + + public override int Level { get => BitConverter.ToUInt16(Data, 0x0A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0A); } + public override int Species { get => BitConverter.ToUInt16(Data, 0x0C); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0C); } + public override int Form { get => BitConverter.ToUInt16(Data, 0x0E); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x0E); } + public override int HeldItem { get => BitConverter.ToUInt16(Data, 0x10); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x10); } + + public override int Move1 { get => BitConverter.ToUInt16(Data, 0x12); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x12); } + public override int Move2 { get => BitConverter.ToUInt16(Data, 0x14); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x14); } + public override int Move3 { get => BitConverter.ToUInt16(Data, 0x16); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x16); } + public override int Move4 { get => BitConverter.ToUInt16(Data, 0x18); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x18); } + + // 1A-1B unused padding + + public override uint IV32 { get => BitConverter.ToUInt32(Data, 0x1C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1C); } + public override int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 00)) | (uint)((value > 31 ? 31 : value) << 00)); } + public override int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 05)) | (uint)((value > 31 ? 31 : value) << 05)); } + public override int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 10)) | (uint)((value > 31 ? 31 : value) << 10)); } + public override int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); } + public override int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); } + public override int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); } + public override bool Shiny { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (IV32 & ~0x40000000u) | (value ? 0x40000000u : 0); } + + public override bool CanDynamax + { + get => ((IV32 >> 31) & 1) == 1; + set => IV32 = (IV32 & ~(1 << 31)) | (uint)((value ? 1 : 0) << 31); + } +} diff --git a/pkNX.Structures/VsTrainer/VsTrainer.cs b/pkNX.Structures/VsTrainer/VsTrainer.cs index 7c1e044b..e8ac3ccd 100644 --- a/pkNX.Structures/VsTrainer/VsTrainer.cs +++ b/pkNX.Structures/VsTrainer/VsTrainer.cs @@ -1,14 +1,13 @@ -using System.Collections.Generic; +using System.Collections.Generic; -namespace pkNX.Structures +namespace pkNX.Structures; + +public class VsTrainer { - public class VsTrainer - { - public int ID { get; set; } - public string Name { get; set; } - public TrainerData Self { get; set; } - public readonly List Team = new(6); + public int ID { get; set; } + public string Name { get; set; } + public TrainerData Self { get; set; } + public readonly List Team = new(6); - public TrainerClass GetClass(IList list) => list[Self.Class]; - } + public TrainerClass GetClass(IList list) => list[Self.Class]; } diff --git a/pkNX.Structures/pkNX.Structures.csproj b/pkNX.Structures/pkNX.Structures.csproj index 89792b93..aadaa61a 100644 --- a/pkNX.Structures/pkNX.Structures.csproj +++ b/pkNX.Structures/pkNX.Structures.csproj @@ -1,7 +1,7 @@ - + - netstandard2.0;net461 + net6.0 Data Structures 10 @@ -20,11 +20,6 @@ - - - - - diff --git a/pkNX.Tests/UnitTest1.cs b/pkNX.Tests/UnitTest1.cs index 4e891716..b0740327 100644 --- a/pkNX.Tests/UnitTest1.cs +++ b/pkNX.Tests/UnitTest1.cs @@ -1,14 +1,13 @@ using FluentAssertions; using Xunit; -namespace pkNX.Tests +namespace pkNX.Tests; + +public class UnitTest1 { - public class UnitTest1 + [Fact] + public void TestMethod1() { - [Fact] - public void TestMethod1() - { - true.Should().BeTrue(); - } + true.Should().BeTrue(); } } diff --git a/pkNX.WinForms/Main.cs b/pkNX.WinForms/Main.cs index f36f42bb..79294aa3 100644 --- a/pkNX.WinForms/Main.cs +++ b/pkNX.WinForms/Main.cs @@ -1,9 +1,7 @@ using System; using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; -using System.Threading; using System.Windows.Forms; using pkNX.Sprites; using pkNX.Structures; @@ -28,10 +26,6 @@ public Main() { InitializeComponent(); - // Fix number values displaying incorrectly for certain cultures. - Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; - Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; - Settings = SettingsSerializer.GetSettings(ProgramSettingsPath).Result; CB_Lang.SelectedIndex = Settings.Language; if (!string.IsNullOrWhiteSpace(Settings.GamePath)) diff --git a/pkNX.WinForms/Program.cs b/pkNX.WinForms/Program.cs index 0b23ce5b..95020dbd 100644 --- a/pkNX.WinForms/Program.cs +++ b/pkNX.WinForms/Program.cs @@ -1,4 +1,6 @@ using System; +using System.Globalization; +using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; @@ -16,6 +18,10 @@ private static void Main() // Opening a FlatBuffer editor later won't be hit with a >5s delay assuming the user opens the editor no earlier than 10 seconds after program startup. _ = Task.Run(() => _ = Structures.FlatBuffers.FlatBufferConverter.SerializeFrom(new Structures.FlatBuffers.Waza8())); + // Fix number values displaying incorrectly for certain cultures. + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; + Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture; + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Main());