From 024bd85cc34b378406adbefdaececbc15758da68 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 24 Mar 2024 20:12:33 -0500 Subject: [PATCH] Minor tweaks make PL6 use memory instead of byte[] make GP1 use memory instead of byte[] move IEncounterable properties higher to IEncounterTemplate --- PKHeX.Core/Editing/PKM/QR/QRPK7.cs | 30 ++-- .../Moveset/EncounterMovesetGenerator.cs | 5 + .../Templates/Gen1/EncounterTrade1.cs | 5 +- .../Interfaces/IEncounterTemplate.cs | 8 +- .../Templates/Interfaces/IEncounterable.cs | 4 +- PKHeX.Core/Legality/Tables/MystryMew.cs | 9 +- .../Verifiers/Ability/AbilityChangeRules.cs | 14 +- PKHeX.Core/MysteryGifts/PL6.cs | 122 +++++++++-------- PKHeX.Core/MysteryGifts/WC3.cs | 3 +- .../PKM/Util/Conversion/IEntityRejuvenator.cs | 4 +- .../Saves/Substructures/Gen6/LinkBlock6.cs | 16 +-- .../Saves/Substructures/Gen7/LGPE/GP1.cs | 51 +++---- PKHeX.Core/Saves/Util/BoxUtil.cs | 19 ++- PKHeX.Drawing.PokeSprite/Util/SpriteUtil.cs | 8 +- .../Controls/SAV Editor/BoxEditor.cs | 6 +- .../Controls/SAV Editor/SlotChangeManager.cs | 4 +- .../Subforms/Save Editors/Gen6/SAV_Link6.cs | 90 ++++++++---- .../Save Editors/Gen7/SAV_Trainer7GG.cs | 6 +- .../Gen8/SAV_PokedexResearchEditorLA.cs | 129 +++++++----------- 19 files changed, 270 insertions(+), 263 deletions(-) diff --git a/PKHeX.Core/Editing/PKM/QR/QRPK7.cs b/PKHeX.Core/Editing/PKM/QR/QRPK7.cs index 9e244fcbb..c58718055 100644 --- a/PKHeX.Core/Editing/PKM/QR/QRPK7.cs +++ b/PKHeX.Core/Editing/PKM/QR/QRPK7.cs @@ -6,9 +6,10 @@ namespace PKHeX.Core; /// /// Generation 7 PGL QR Code encoded entities. /// -public sealed class QRPK7(byte[] Data) : IEncounterInfo +public sealed class QRPK7(Memory Raw) : IEncounterInfo { - private readonly byte[] Data = (byte[])Data.Clone(); + public const int SIZE = 0x30; + private Span Data => Raw.Span; public bool EggEncounter => false; public byte LevelMin => Level; @@ -16,10 +17,13 @@ public sealed class QRPK7(byte[] Data) : IEncounterInfo public byte Generation => Version.GetGeneration(); public EntityContext Context => EntityContext.Gen7; public bool IsShiny => false; + public ushort Location => 0; + public ushort EggLocation => 0; + public AbilityPermission Ability => (AbilityPermission)AbilityIndex; + public Ball FixedBall => (Ball)Ball; + public Shiny Shiny => Shiny.Never; - public const int SIZE = 0x30; - - public uint EncryptionConstant => ReadUInt32LittleEndian(Data.AsSpan(0)); + public uint EncryptionConstant => ReadUInt32LittleEndian(Data[..]); public byte HyperTrainFlags => Data[4]; public byte Unk_5 => Data[5]; public byte Unk_6 => Data[6]; @@ -28,20 +32,20 @@ public sealed class QRPK7(byte[] Data) : IEncounterInfo public byte Move2_PPUps => Data[9]; public byte Move3_PPUps => Data[0xA]; public byte Move4_PPUps => Data[0xB]; - public uint IV32 { get => ReadUInt32LittleEndian(Data.AsSpan(0xC)); set => WriteUInt32LittleEndian(Data.AsSpan(0xC), value); } + public uint IV32 { get => ReadUInt32LittleEndian(Data.Slice(0xC)); set => WriteUInt32LittleEndian(Data.Slice(0xC), value); } public int IV_HP { get => (int)(IV32 >> 00) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 00)) | (uint)((value > 31 ? 31 : value) << 00); } public int IV_ATK { get => (int)(IV32 >> 05) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 05)) | (uint)((value > 31 ? 31 : value) << 05); } public int IV_DEF { get => (int)(IV32 >> 10) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 10)) | (uint)((value > 31 ? 31 : value) << 10); } public int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 15)) | (uint)((value > 31 ? 31 : value) << 15); } public int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 20)) | (uint)((value > 31 ? 31 : value) << 20); } public int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (IV32 & ~(0x1Fu << 25)) | (uint)((value > 31 ? 31 : value) << 25); } - public uint PID => ReadUInt32LittleEndian(Data.AsSpan(0x10)); - public ushort Species => ReadUInt16LittleEndian(Data.AsSpan(0x14)); - public ushort HeldItem => ReadUInt16LittleEndian(Data.AsSpan(0x16)); - public ushort Move1 => ReadUInt16LittleEndian(Data.AsSpan(0x18)); - public ushort Move2 => ReadUInt16LittleEndian(Data.AsSpan(0x1A)); - public ushort Move3 => ReadUInt16LittleEndian(Data.AsSpan(0x1C)); - public ushort Move4 => ReadUInt16LittleEndian(Data.AsSpan(0x1E)); + public uint PID => ReadUInt32LittleEndian(Data.Slice(0x10)); + public ushort Species => ReadUInt16LittleEndian(Data.Slice(0x14)); + public ushort HeldItem => ReadUInt16LittleEndian(Data.Slice(0x16)); + public ushort Move1 => ReadUInt16LittleEndian(Data.Slice(0x18)); + public ushort Move2 => ReadUInt16LittleEndian(Data.Slice(0x1A)); + public ushort Move3 => ReadUInt16LittleEndian(Data.Slice(0x1C)); + public ushort Move4 => ReadUInt16LittleEndian(Data.Slice(0x1E)); public byte Unk_20 => Data[0x20]; public byte AbilityIndex => Data[0x21]; public Nature Nature => (Nature)Data[0x22]; diff --git a/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs index 05fc79aa9..4057f07d6 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs @@ -203,6 +203,11 @@ public static class EncounterMovesetGenerator public ushort Species => 0; public byte Form => 0; public bool IsShiny => false; + public ushort Location => 0; + public ushort EggLocation => 0; + public AbilityPermission Ability => 0; + public Ball FixedBall => 0; + public Shiny Shiny => 0; } private static ushort[] GetNeededMoves(PKM pk, ReadOnlySpan moves, GameVersion version, byte generation, EntityContext context) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs index bb870c928..0b6c240f1 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen1/EncounterTrade1.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; namespace PKHeX.Core; @@ -81,9 +80,9 @@ public sealed record EncounterTrade1 : IEncounterable, IEncounterMatch, IFixedTr private int GetNicknameIndex(ReadOnlySpan nickname) => GetIndex(nickname, Nicknames); - private static int GetIndex(ReadOnlySpan name, IReadOnlyList arr) + private static int GetIndex(ReadOnlySpan name, ReadOnlySpan arr) { - for (int i = 0; i < arr.Count; i++) + for (int i = 0; i < arr.Length; i++) { if (name.SequenceEqual(arr[i])) return i; diff --git a/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterTemplate.cs b/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterTemplate.cs index 57ba41b2d..17c7d84f6 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterTemplate.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterTemplate.cs @@ -3,7 +3,7 @@ namespace PKHeX.Core; /// /// Represents all details that an entity may be encountered with. /// -public interface IEncounterTemplate : ISpeciesForm, IVersion, IGeneration, IShiny, ILevelRange +public interface IEncounterTemplate : ISpeciesForm, IVersion, IGeneration, IShiny, ILevelRange, ILocation, IFixedAbilityNumber, IFixedBall, IShinyPotential { /// /// Original Context @@ -27,6 +27,10 @@ public static partial class Extensions return level == encounter.LevelMin; if (encounter is MysteryGift g) return level == g.Level; - return level == pk.MetLevel; + + var met = pk.MetLevel; + if (met != 0) + return level == met; + return encounter.IsLevelWithinRange(level); } } diff --git a/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterable.cs b/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterable.cs index 253f1955e..b93979b88 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterable.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Interfaces/IEncounterable.cs @@ -1,10 +1,10 @@ -namespace PKHeX.Core; +namespace PKHeX.Core; /// /// Common Encounter Properties base interface. /// /// -public interface IEncounterable : IEncounterInfo, ILocation, IFixedAbilityNumber, IFixedBall, IShinyPotential +public interface IEncounterable : IEncounterInfo { /// /// Short name to describe the encounter data, usually just indicating which of the main component encounter types the data is. diff --git a/PKHeX.Core/Legality/Tables/MystryMew.cs b/PKHeX.Core/Legality/Tables/MystryMew.cs index eead42e8a..4ea4da3b7 100644 --- a/PKHeX.Core/Legality/Tables/MystryMew.cs +++ b/PKHeX.Core/Legality/Tables/MystryMew.cs @@ -33,7 +33,6 @@ public static class MystryMew 0xFE9D, ]; - //private const int FramesPerMew = 5; private const int MewPerRestrictedSeed = 5; /// @@ -70,9 +69,9 @@ public static class MystryMew var seeds = Seeds; if (seed <= ushort.MaxValue) return seeds.BinarySearch((ushort)seed); - for (int i = 0; i < 5; i++) + for (int i = 0; i < MewPerRestrictedSeed; i++) { - seed = LCRNG.Prev5(seed); + seed = LCRNG.Prev5(seed); // BACD{?} if (seed <= ushort.MaxValue) return seeds.BinarySearch((ushort)seed); } @@ -93,9 +92,9 @@ public static class MystryMew var index = seeds.BinarySearch((ushort)seed); return (index, -1); } - for (int i = 0; i < 5; i++) + for (int i = 0; i < MewPerRestrictedSeed; i++) { - seed = LCRNG.Prev5(seed); + seed = LCRNG.Prev5(seed); // BACD{?} if (seed <= ushort.MaxValue) { var index = seeds.BinarySearch((ushort)seed); diff --git a/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs b/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs index 11f5e7a99..ad9403516 100644 --- a/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs +++ b/PKHeX.Core/Legality/Verifiers/Ability/AbilityChangeRules.cs @@ -17,11 +17,8 @@ public static class AbilityChangeRules /// Current context /// Original context /// True if possible to obtain - public static bool IsAbilityStateValid(this IEncounterTemplate enc, EvolutionHistory evosAll, int abilityFlag, EntityContext current, EntityContext original) => (enc switch - { - IFixedAbilityNumber f => f.Ability, - _ => Any12, - }).IsAbilityStateValid(evosAll, abilityFlag, current, original); + public static bool IsAbilityStateValid(this IEncounterTemplate enc, EvolutionHistory evosAll, int abilityFlag, EntityContext current, EntityContext original) + => enc.Ability.IsAbilityStateValid(evosAll, abilityFlag, current, original); /// /// Checks if the current value is possible to obtain based on the original and game visiting. @@ -51,11 +48,8 @@ public static class AbilityChangeRules /// Current context /// Original context /// True if the ability can be changed - public static bool IsAbilityChangeAvailable(this IEncounterTemplate enc, EvolutionHistory evosAll, EntityContext current, EntityContext original) => (enc switch - { - IFixedAbilityNumber f => f.Ability, - _ => Any12, - }).IsAbilityChangeAvailable(evosAll, current, original); + public static bool IsAbilityChangeAvailable(this IEncounterTemplate enc, EvolutionHistory evosAll, EntityContext current, EntityContext original) + => enc.Ability.IsAbilityChangeAvailable(evosAll, current, original); /// /// Checks if the original value can be changed based on the games visited. diff --git a/PKHeX.Core/MysteryGifts/PL6.cs b/PKHeX.Core/MysteryGifts/PL6.cs index dd4f2b585..d9733a605 100644 --- a/PKHeX.Core/MysteryGifts/PL6.cs +++ b/PKHeX.Core/MysteryGifts/PL6.cs @@ -10,15 +10,14 @@ namespace PKHeX.Core; /// This Template object is very similar to the structure in that it stores more data than just the gift. /// This template object is only present in Generation 6 save files. /// -public sealed class PL6 +public sealed class PL6(Memory Raw) { public const int Size = 0xA47; public const string Filter = "Pokémon Link Data|*.pl6|All Files (*.*)|*.*"; - public readonly byte[] Data; + public PL6() : this(new byte[Size]) { } - public PL6() => Data = new byte[Size]; - public PL6(byte[] data) => Data = data; + public Span Data => Raw.Span; /// /// Pokémon Link Flag @@ -31,7 +30,7 @@ public sealed class PL6 public bool Enabled { get => (Flags & 0x80) != 0; set => Flags = value ? (byte)(1 << 7) : (byte)0; } - private Span Source => Data.AsSpan(0x01, 110); + private Span Source => Data.Slice(0x01, 110); /// /// Name of data source @@ -39,37 +38,37 @@ public sealed class PL6 public string Origin { get => StringConverter6.GetString(Source); set => StringConverter6.SetString(Source, value, 54, StringConverterOption.ClearZero); } // Pokemon transfer flags? - public uint Flags_1 { get => ReadUInt32LittleEndian(Data.AsSpan(0x099)); set => WriteUInt32LittleEndian(Data.AsSpan(0x099), value); } - public uint Flags_2 { get => ReadUInt32LittleEndian(Data.AsSpan(0x141)); set => WriteUInt32LittleEndian(Data.AsSpan(0x141), value); } - public uint Flags_3 { get => ReadUInt32LittleEndian(Data.AsSpan(0x1E9)); set => WriteUInt32LittleEndian(Data.AsSpan(0x1E9), value); } - public uint Flags_4 { get => ReadUInt32LittleEndian(Data.AsSpan(0x291)); set => WriteUInt32LittleEndian(Data.AsSpan(0x291), value); } - public uint Flags_5 { get => ReadUInt32LittleEndian(Data.AsSpan(0x339)); set => WriteUInt32LittleEndian(Data.AsSpan(0x339), value); } - public uint Flags_6 { get => ReadUInt32LittleEndian(Data.AsSpan(0x3E1)); set => WriteUInt32LittleEndian(Data.AsSpan(0x3E1), value); } + public uint Flags1 { get => ReadUInt32LittleEndian(Data[0x099..]); set => WriteUInt32LittleEndian(Data[0x099..], value); } + public uint Flags2 { get => ReadUInt32LittleEndian(Data[0x141..]); set => WriteUInt32LittleEndian(Data[0x141..], value); } + public uint Flags3 { get => ReadUInt32LittleEndian(Data[0x1E9..]); set => WriteUInt32LittleEndian(Data[0x1E9..], value); } + public uint Flags4 { get => ReadUInt32LittleEndian(Data[0x291..]); set => WriteUInt32LittleEndian(Data[0x291..], value); } + public uint Flags5 { get => ReadUInt32LittleEndian(Data[0x339..]); set => WriteUInt32LittleEndian(Data[0x339..], value); } + public uint Flags6 { get => ReadUInt32LittleEndian(Data[0x3E1..]); set => WriteUInt32LittleEndian(Data[0x3E1..], value); } // Pokémon - public PL6_PKM Poke_1 { get => new(Data.AsSpan(0x09D, PL6_PKM.Size).ToArray()); set => value.Data.CopyTo(Data, 0x09D); } - public PL6_PKM Poke_2 { get => new(Data.AsSpan(0x145, PL6_PKM.Size).ToArray()); set => value.Data.CopyTo(Data, 0x145); } - public PL6_PKM Poke_3 { get => new(Data.AsSpan(0x1ED, PL6_PKM.Size).ToArray()); set => value.Data.CopyTo(Data, 0x1ED); } - public PL6_PKM Poke_4 { get => new(Data.AsSpan(0x295, PL6_PKM.Size).ToArray()); set => value.Data.CopyTo(Data, 0x295); } - public PL6_PKM Poke_5 { get => new(Data.AsSpan(0x33D, PL6_PKM.Size).ToArray()); set => value.Data.CopyTo(Data, 0x33D); } - public PL6_PKM Poke_6 { get => new(Data.AsSpan(0x3E5, PL6_PKM.Size).ToArray()); set => value.Data.CopyTo(Data, 0x3E5); } + public LinkEntity6 Entity1 { get => new(Raw.Slice(0x09D, LinkEntity6.Size)); set => value.Data.CopyTo(Data[0x09D..]); } + public LinkEntity6 Entity2 { get => new(Raw.Slice(0x145, LinkEntity6.Size)); set => value.Data.CopyTo(Data[0x145..]); } + public LinkEntity6 Entity3 { get => new(Raw.Slice(0x1ED, LinkEntity6.Size)); set => value.Data.CopyTo(Data[0x1ED..]); } + public LinkEntity6 Entity4 { get => new(Raw.Slice(0x295, LinkEntity6.Size)); set => value.Data.CopyTo(Data[0x295..]); } + public LinkEntity6 Entity5 { get => new(Raw.Slice(0x33D, LinkEntity6.Size)); set => value.Data.CopyTo(Data[0x33D..]); } + public LinkEntity6 Entity6 { get => new(Raw.Slice(0x3E5, LinkEntity6.Size)); set => value.Data.CopyTo(Data[0x3E5..]); } // Item Properties - public int Item_1 { get => ReadUInt16LittleEndian(Data.AsSpan(0x489)); set => WriteUInt16LittleEndian(Data.AsSpan(0x489), (ushort)value); } - public int Quantity_1 { get => ReadUInt16LittleEndian(Data.AsSpan(0x48B)); set => WriteUInt16LittleEndian(Data.AsSpan(0x48B), (ushort)value); } - public int Item_2 { get => ReadUInt16LittleEndian(Data.AsSpan(0x48D)); set => WriteUInt16LittleEndian(Data.AsSpan(0x48D), (ushort)value); } - public int Quantity_2 { get => ReadUInt16LittleEndian(Data.AsSpan(0x48F)); set => WriteUInt16LittleEndian(Data.AsSpan(0x48F), (ushort)value); } - public int Item_3 { get => ReadUInt16LittleEndian(Data.AsSpan(0x491)); set => WriteUInt16LittleEndian(Data.AsSpan(0x491), (ushort)value); } - public int Quantity_3 { get => ReadUInt16LittleEndian(Data.AsSpan(0x493)); set => WriteUInt16LittleEndian(Data.AsSpan(0x493), (ushort)value); } - public int Item_4 { get => ReadUInt16LittleEndian(Data.AsSpan(0x495)); set => WriteUInt16LittleEndian(Data.AsSpan(0x495), (ushort)value); } - public int Quantity_4 { get => ReadUInt16LittleEndian(Data.AsSpan(0x497)); set => WriteUInt16LittleEndian(Data.AsSpan(0x497), (ushort)value); } - public int Item_5 { get => ReadUInt16LittleEndian(Data.AsSpan(0x499)); set => WriteUInt16LittleEndian(Data.AsSpan(0x499), (ushort)value); } - public int Quantity_5 { get => ReadUInt16LittleEndian(Data.AsSpan(0x49B)); set => WriteUInt16LittleEndian(Data.AsSpan(0x49B), (ushort)value); } - public int Item_6 { get => ReadUInt16LittleEndian(Data.AsSpan(0x49D)); set => WriteUInt16LittleEndian(Data.AsSpan(0x49D), (ushort)value); } - public int Quantity_6 { get => ReadUInt16LittleEndian(Data.AsSpan(0x49F)); set => WriteUInt16LittleEndian(Data.AsSpan(0x49F), (ushort)value); } + public ushort Item1 { get => ReadUInt16LittleEndian(Data[0x489..]); set => WriteUInt16LittleEndian(Data[0x489..], value); } + public ushort Quantity1 { get => ReadUInt16LittleEndian(Data[0x48B..]); set => WriteUInt16LittleEndian(Data[0x48B..], value); } + public ushort Item2 { get => ReadUInt16LittleEndian(Data[0x48D..]); set => WriteUInt16LittleEndian(Data[0x48D..], value); } + public ushort Quantity2 { get => ReadUInt16LittleEndian(Data[0x48F..]); set => WriteUInt16LittleEndian(Data[0x48F..], value); } + public ushort Item3 { get => ReadUInt16LittleEndian(Data[0x491..]); set => WriteUInt16LittleEndian(Data[0x491..], value); } + public ushort Quantity3 { get => ReadUInt16LittleEndian(Data[0x493..]); set => WriteUInt16LittleEndian(Data[0x493..], value); } + public ushort Item4 { get => ReadUInt16LittleEndian(Data[0x495..]); set => WriteUInt16LittleEndian(Data[0x495..], value); } + public ushort Quantity4 { get => ReadUInt16LittleEndian(Data[0x497..]); set => WriteUInt16LittleEndian(Data[0x497..], value); } + public ushort Item5 { get => ReadUInt16LittleEndian(Data[0x499..]); set => WriteUInt16LittleEndian(Data[0x499..], value); } + public ushort Quantity5 { get => ReadUInt16LittleEndian(Data[0x49B..]); set => WriteUInt16LittleEndian(Data[0x49B..], value); } + public ushort Item6 { get => ReadUInt16LittleEndian(Data[0x49D..]); set => WriteUInt16LittleEndian(Data[0x49D..], value); } + public ushort Quantity6 { get => ReadUInt16LittleEndian(Data[0x49F..]); set => WriteUInt16LittleEndian(Data[0x49F..], value); } - public int BattlePoints { get => ReadUInt16LittleEndian(Data.AsSpan(0x4A1)); set => WriteUInt16LittleEndian(Data.AsSpan(0x4A1), (ushort)value); } - public int Pokemiles { get => ReadUInt16LittleEndian(Data.AsSpan(0x4A3)); set => WriteUInt16LittleEndian(Data.AsSpan(0x4A3), (ushort)value); } + public ushort BattlePoints { get => ReadUInt16LittleEndian(Data[0x4A1..]); set => WriteUInt16LittleEndian(Data[0x4A1..], value); } + public ushort Pokemiles { get => ReadUInt16LittleEndian(Data[0x4A3..]); set => WriteUInt16LittleEndian(Data[0x4A3..], value); } } /// @@ -79,44 +78,46 @@ public sealed class PL6 /// This Template object is very similar to the structure and similar objects, in that the structure offsets are ordered the same. /// This template object is only present in Generation 6 save files. /// -public sealed class PL6_PKM(byte[] Data) : IRibbonSetEvent3, IRibbonSetEvent4, IEncounterInfo, IMoveset, IRelearn, - IContestStats, IMemoryOT, ITrainerID32, ILocation +public sealed class LinkEntity6(Memory Raw) : IRibbonSetEvent3, IRibbonSetEvent4, IEncounterInfo, IMoveset, IRelearn, + IContestStats, IMemoryOT, ITrainerID32 { internal const int Size = 0xA0; - public readonly byte[] Data = Data; + public Span Data => Raw.Span; - public PL6_PKM() : this(new byte[Size]) { } + public LinkEntity6() : this(new byte[Size]) { } public TrainerIDFormat TrainerIDDisplayFormat => TrainerIDFormat.SixteenBit; - public uint ID32 { get => ReadUInt32LittleEndian(Data.AsSpan(0x00)); set => WriteUInt32LittleEndian(Data.AsSpan(0x00), value); } - public ushort TID16 { get => ReadUInt16LittleEndian(Data.AsSpan(0x00)); set => WriteUInt16LittleEndian(Data.AsSpan(0x00), value); } - public ushort SID16 { get => ReadUInt16LittleEndian(Data.AsSpan(0x02)); set => WriteUInt16LittleEndian(Data.AsSpan(0x02), value); } + public uint ID32 { get => ReadUInt32LittleEndian(Data[..]); set => WriteUInt32LittleEndian(Data[..], value); } + public ushort TID16 { get => ReadUInt16LittleEndian(Data[..]); set => WriteUInt16LittleEndian(Data[..], value); } + public ushort SID16 { get => ReadUInt16LittleEndian(Data[0x02..]); set => WriteUInt16LittleEndian(Data[0x02..], value); } public byte OriginGame { get => Data[0x04]; set => Data[0x04] = value; } - public uint EncryptionConstant { get => ReadUInt32LittleEndian(Data.AsSpan(0x08)); set => WriteUInt32LittleEndian(Data.AsSpan(0x08), value); } + public uint EncryptionConstant { get => ReadUInt32LittleEndian(Data[0x08..]); set => WriteUInt32LittleEndian(Data[0x08..], value); } public byte Ball { get => Data[0xE]; set => Data[0xE] = value; } - public int HeldItem { get => ReadUInt16LittleEndian(Data.AsSpan(0x10)); set => WriteUInt16LittleEndian(Data.AsSpan(0x10), (ushort)value); } - public ushort Move1 { get => ReadUInt16LittleEndian(Data.AsSpan(0x12)); set => WriteUInt16LittleEndian(Data.AsSpan(0x12), value); } - public ushort Move2 { get => ReadUInt16LittleEndian(Data.AsSpan(0x14)); set => WriteUInt16LittleEndian(Data.AsSpan(0x14), value); } - public ushort Move3 { get => ReadUInt16LittleEndian(Data.AsSpan(0x16)); set => WriteUInt16LittleEndian(Data.AsSpan(0x16), value); } - public ushort Move4 { get => ReadUInt16LittleEndian(Data.AsSpan(0x18)); set => WriteUInt16LittleEndian(Data.AsSpan(0x18), value); } - public ushort Species { get => ReadUInt16LittleEndian(Data.AsSpan(0x1A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x1A), value); } + public int HeldItem { get => ReadUInt16LittleEndian(Data[0x10..]); set => WriteUInt16LittleEndian(Data[0x10..], (ushort)value); } + public ushort Move1 { get => ReadUInt16LittleEndian(Data[0x12..]); set => WriteUInt16LittleEndian(Data[0x12..], value); } + public ushort Move2 { get => ReadUInt16LittleEndian(Data[0x14..]); set => WriteUInt16LittleEndian(Data[0x14..], value); } + public ushort Move3 { get => ReadUInt16LittleEndian(Data[0x16..]); set => WriteUInt16LittleEndian(Data[0x16..], value); } + public ushort Move4 { get => ReadUInt16LittleEndian(Data[0x18..]); set => WriteUInt16LittleEndian(Data[0x18..], value); } + public ushort Species { get => ReadUInt16LittleEndian(Data[0x1A..]); set => WriteUInt16LittleEndian(Data[0x1A..], value); } public byte Form { get => Data[0x1C]; set => Data[0x1C] = value; } public int Language { get => Data[0x1D]; set => Data[0x1D] = (byte)value; } + public Span NicknameTrash => Data.Slice(0x1E, 0x1A); + public string Nickname { - get => StringConverter6.GetString(Data.AsSpan(0x1E, 0x1A)); - set => StringConverter6.SetString(Data.AsSpan(0x1E, 0x1A), value, 12, StringConverterOption.ClearZero); + get => StringConverter6.GetString(NicknameTrash); + set => StringConverter6.SetString(NicknameTrash, value, 12, StringConverterOption.ClearZero); } public Nature Nature { get => (Nature)Data[0x38]; set => Data[0x38] = (byte)value; } public byte Gender { get => Data[0x39]; set => Data[0x39] = value; } public int AbilityType { get => Data[0x3A]; set => Data[0x3A] = (byte)value; } public int PIDType { get => Data[0x3B]; set => Data[0x3B] = (byte)value; } - public ushort EggLocation { get => ReadUInt16LittleEndian(Data.AsSpan(0x3C)); set => WriteUInt16LittleEndian(Data.AsSpan(0x3C), value); } - public ushort Location { get => ReadUInt16LittleEndian(Data.AsSpan(0x3E)); set => WriteUInt16LittleEndian(Data.AsSpan(0x3E), value); } + public ushort EggLocation { get => ReadUInt16LittleEndian(Data[0x3C..]); set => WriteUInt16LittleEndian(Data[0x3C..], value); } + public ushort Location { get => ReadUInt16LittleEndian(Data[0x3E..]); set => WriteUInt16LittleEndian(Data[0x3E..], value); } public byte MetLevel { get => Data[0x40]; set => Data[0x40] = value; } public byte ContestCool { get => Data[0x41]; set => Data[0x41] = value; } @@ -135,22 +136,24 @@ public sealed class PL6_PKM(byte[] Data) : IRibbonSetEvent3, IRibbonSetEvent4, I public byte OTGender { get => Data[0x4D]; set => Data[0x4D] = value; } + public Span OriginalTrainerTrash => Data.Slice(0x4E, 0x1A); + public string OT { - get => StringConverter6.GetString(Data.AsSpan(0x4E, 0x1A)); - set => StringConverter6.SetString(Data.AsSpan(0x4E, 0x1A), value, 12, StringConverterOption.ClearZero); + get => StringConverter6.GetString(OriginalTrainerTrash); + set => StringConverter6.SetString(OriginalTrainerTrash, value, 12, StringConverterOption.ClearZero); } public int Level { get => Data[0x68]; set => Data[0x68] = (byte)value; } public bool IsEgg { get => Data[0x69] == 1; set => Data[0x69] = value ? (byte)1 : (byte)0; } - public uint PID { get => ReadUInt32LittleEndian(Data.AsSpan(0x6C)); set => WriteUInt32LittleEndian(Data.AsSpan(0x6C), value); } - public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data.AsSpan(0x70)); set => WriteUInt16LittleEndian(Data.AsSpan(0x70), value); } - public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data.AsSpan(0x72)); set => WriteUInt16LittleEndian(Data.AsSpan(0x72), value); } - public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data.AsSpan(0x74)); set => WriteUInt16LittleEndian(Data.AsSpan(0x74), value); } - public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data.AsSpan(0x76)); set => WriteUInt16LittleEndian(Data.AsSpan(0x76), value); } + public uint PID { get => ReadUInt32LittleEndian(Data[0x6C..]); set => WriteUInt32LittleEndian(Data[0x6C..], value); } + public ushort RelearnMove1 { get => ReadUInt16LittleEndian(Data[0x70..]); set => WriteUInt16LittleEndian(Data[0x70..], value); } + public ushort RelearnMove2 { get => ReadUInt16LittleEndian(Data[0x72..]); set => WriteUInt16LittleEndian(Data[0x72..], value); } + public ushort RelearnMove3 { get => ReadUInt16LittleEndian(Data[0x74..]); set => WriteUInt16LittleEndian(Data[0x74..], value); } + public ushort RelearnMove4 { get => ReadUInt16LittleEndian(Data[0x76..]); set => WriteUInt16LittleEndian(Data[0x76..], value); } public byte OriginalTrainerMemoryIntensity { get => Data[0x78]; set => Data[0x78] = value; } public byte OriginalTrainerMemory { get => Data[0x79]; set => Data[0x79] = value; } - public ushort OriginalTrainerMemoryVariable { get => ReadUInt16LittleEndian(Data.AsSpan(0x7A)); set => WriteUInt16LittleEndian(Data.AsSpan(0x7A), value); } + public ushort OriginalTrainerMemoryVariable { get => ReadUInt16LittleEndian(Data[0x7A..]); set => WriteUInt16LittleEndian(Data[0x7A..], value); } public byte OriginalTrainerMemoryFeeling { get => Data[0x7C]; set => Data[0x7C] = value; } private byte RIB0 { get => Data[0x0C]; set => Data[0x0C] = value; } @@ -205,13 +208,16 @@ public sealed class PL6_PKM(byte[] Data) : IRibbonSetEvent3, IRibbonSetEvent4, I public bool EggEncounter => false; public GameVersion Version => GameVersion.Gen6; public EntityContext Context => EntityContext.Gen6; + public AbilityPermission Ability => (AbilityPermission)AbilityType; + public Ball FixedBall => (Ball)Ball; + public Shiny Shiny => Shiny.Never; public PKM ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr, EncounterCriteria.Unrestricted); public PKM ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) { var wc6 = new WC6(); - Data.CopyTo(wc6.Data, 0x68); + Data.CopyTo(wc6.Data.AsSpan(0x68)); return wc6.ConvertToPKM(tr, criteria); } } diff --git a/PKHeX.Core/MysteryGifts/WC3.cs b/PKHeX.Core/MysteryGifts/WC3.cs index d7f69a785..fb727f731 100644 --- a/PKHeX.Core/MysteryGifts/WC3.cs +++ b/PKHeX.Core/MysteryGifts/WC3.cs @@ -160,8 +160,7 @@ public sealed class WC3(GameVersion Version, bool Fateful = false) } pk.OriginalTrainerGender = sav.Gender; - pk.TID16 = sav.TID16; - pk.SID16 = sav.SID16; + pk.ID32 = sav.ID32; pk.MetLocation = pk.FRLG ? Locations.HatchLocationFRLG : Locations.HatchLocationRSE; pk.FatefulEncounter &= pk.FRLG; // clear flag for RSE pk.MetLevel = 0; // hatched diff --git a/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs b/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs index bb11a3f4f..ea705076e 100644 --- a/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs +++ b/PKHeX.Core/PKM/Util/Conversion/IEntityRejuvenator.cs @@ -108,8 +108,8 @@ public sealed class LegalityRejuvenator : IEntityRejuvenator { if (result.Ball is >= (int)Ball.LAPoke and <= (int)Ball.LAOrigin) return; - if (enc is IFixedBall { FixedBall: not Ball.None } f) - result.Ball = (byte)f.FixedBall; + if (enc is { FixedBall: not Ball.None }) + result.Ball = (byte)enc.FixedBall; else result.Ball = result.Species == (int)Species.Unown ? (byte)Ball.LAJet : (byte)Ball.LAPoke; } diff --git a/PKHeX.Core/Saves/Substructures/Gen6/LinkBlock6.cs b/PKHeX.Core/Saves/Substructures/Gen6/LinkBlock6.cs index 88f482791..b6dfdfa72 100644 --- a/PKHeX.Core/Saves/Substructures/Gen6/LinkBlock6.cs +++ b/PKHeX.Core/Saves/Substructures/Gen6/LinkBlock6.cs @@ -8,21 +8,11 @@ public sealed class LinkBlock6 : SaveBlock public LinkBlock6(SAV6XY sav, Memory raw) : base(sav, raw) { } public LinkBlock6(SAV6AO sav, Memory raw) : base(sav, raw) { } - public Span InfoSpan() => Data.Slice(0x1FF, PL6.Size); + public Memory PL6 => Raw.Slice(0x1FF, Core.PL6.Size); - public PL6 GetLinkInfo() => new(InfoSpan().ToArray()); + public PL6 Gifts => new(PL6); - public void SetLinkInfoData(ReadOnlySpan data) - { - data.CopyTo(Data); - Checksum = GetCalculatedChecksum(); // [app,chk) - } - - public void SetLinkInfo(PL6 pl6) - { - pl6.Data.CopyTo(InfoSpan()); - Checksum = GetCalculatedChecksum(); // [app,chk) - } + public void RefreshChecksum() => Checksum = GetCalculatedChecksum(); // [app,chk) private ushort GetCalculatedChecksum() => Checksums.CRC16_CCITT(Data[0x200..^4]); // [app,chk) diff --git a/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs b/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs index db3b49c79..b2d674649 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs @@ -8,11 +8,11 @@ namespace PKHeX.Core; /// /// Go Park Entity transferred from to . /// -public sealed class GP1(byte[] Data) - : IEncounterInfo, IFixedAbilityNumber, IScaledSizeReadOnly, IEncounterConvertible +public sealed class GP1(Memory Raw) + : IEncounterInfo, IScaledSizeReadOnly, IEncounterConvertible { public const int SIZE = 0x1B0; - public readonly byte[] Data = Data; + public Span Data => Raw.Span; public GameVersion Version => GameVersion.GO; public bool EggEncounter => false; @@ -21,6 +21,10 @@ public sealed class GP1(byte[] Data) public byte Generation => 7; public EntityContext Context => EntityContext.Gen7b; public AbilityPermission Ability => AbilityPermission.Any12; + public ushort Location => Locations.GO7; + public ushort EggLocation => 0; + public Ball FixedBall => Ball.None; + public Shiny Shiny => Shiny.Random; public GP1() : this(new byte[SIZE]) => InitializeBlank(Data); public void WriteTo(Span data) => Data.CopyTo(data); @@ -55,17 +59,17 @@ public sealed class GP1(byte[] Data) private static string GetString(ReadOnlySpan buffer) => Encoding.ASCII.GetString(GetLength(buffer)); - public string Username1 => GetString(Data.AsSpan(0x00, 0x10)); - public string Username2 => GetString(Data.AsSpan(0x10, 0x10)); + public string Username1 => GetString(Data[..0x10]); + public string Username2 => GetString(Data.Slice(0x10, 0x10)); - public ushort Species => ReadUInt16LittleEndian(Data.AsSpan(0x28)); // s32, just read as u16 - public int CP => ReadInt32LittleEndian(Data.AsSpan(0x2C)); - public float LevelF => ReadSingleLittleEndian(Data.AsSpan(0x30)); + public ushort Species => ReadUInt16LittleEndian(Data[0x28..]); // s32, just read as u16 + public int CP => ReadInt32LittleEndian(Data[0x2C..]); + public float LevelF => ReadSingleLittleEndian(Data[0x30..]); public byte Level => Math.Max((byte)1, (byte)Math.Round(LevelF)); - public int Stat_HP => ReadInt32LittleEndian(Data.AsSpan(0x34)); + public int Stat_HP => ReadInt32LittleEndian(Data[0x34..]); // geolocation data 0x38-0x47? - public float HeightF => ReadSingleLittleEndian(Data.AsSpan(0x48)); - public float WeightF => ReadSingleLittleEndian(Data.AsSpan(0x4C)); + public float HeightF => ReadSingleLittleEndian(Data[0x48..]); + public float WeightF => ReadSingleLittleEndian(Data[0x4C..]); public byte HeightScalar { @@ -91,10 +95,10 @@ public sealed class GP1(byte[] Data) } } - public int IV_HP => ReadInt32LittleEndian(Data.AsSpan(0x50)); - public int IV_ATK => ReadInt32LittleEndian(Data.AsSpan(0x54)); - public int IV_DEF => ReadInt32LittleEndian(Data.AsSpan(0x58)); - public int Date => ReadInt32LittleEndian(Data.AsSpan(0x5C)); // ####.##.## YYYY.MM.DD + public int IV_HP => ReadInt32LittleEndian(Data[0x50..]); + public int IV_ATK => ReadInt32LittleEndian(Data[0x54..]); + public int IV_DEF => ReadInt32LittleEndian(Data[0x58..]); + public int Date => ReadInt32LittleEndian(Data[0x5C..]); // ####.##.## YYYY.MM.DD public int Year => Date / 1_00_00; public int Month => (Date / 1_00) % 1_00; public int Day => Date % 1_00; @@ -105,12 +109,12 @@ public sealed class GP1(byte[] Data) public bool IsShiny => Data[0x73] == 1; // https://bulbapedia.bulbagarden.net/wiki/List_of_moves_in_Pok%C3%A9mon_GO - public int Move1 => ReadInt32LittleEndian(Data.AsSpan(0x74)); // uses Go Indexes - public int Move2 => ReadInt32LittleEndian(Data.AsSpan(0x78)); // uses Go Indexes + public int Move1 => ReadInt32LittleEndian(Data[0x74..]); // uses Go Indexes + public int Move2 => ReadInt32LittleEndian(Data[0x78..]); // uses Go Indexes - public string GeoCityName => GetString(Data.AsSpan(0x7C, 0x60)); // dunno length + public string GeoCityName => GetString(Data.Slice(0x7C, 0x60)); // dunno length - public string Nickname => GetString(Data.AsSpan(0x12D, 0x20)); // dunno length + public string Nickname => GetString(Data.Slice(0x12D, 0x20)); // dunno length public static readonly IReadOnlyList Genders = GameInfo.GenderSymbolASCII; public string GenderString => (uint) Gender >= Genders.Count ? string.Empty : Genders[Gender]; @@ -152,14 +156,13 @@ public sealed class GP1(byte[] Data) Version = GameVersion.GO, Species = Species, Form = Form, - MetLocation = 50, // Go complex + MetLocation = Location, // Go complex MetYear = (byte)(Year - 2000), MetMonth = (byte)Month, MetDay = (byte)Day, CurrentLevel = Level, MetLevel = Level, - TID16 = sav.TID16, - SID16 = sav.SID16, + ID32 = sav.ID32, OriginalTrainerName = sav.OT, Ball = 4, Language = sav.Language, @@ -179,7 +182,7 @@ public sealed class GP1(byte[] Data) pk.IV_DEF = pk.IV_SPD = (IV_DEF * 2) + 1; pk.IV_ATK = pk.IV_SPA = (IV_ATK * 2) + 1; pk.IV_HP = (IV_HP * 2) + 1; - pk.IV_SPE = Util.Rand.Next(32); + pk.IV_SPE = rnd.Next(32); var pi = pk.PersonalInfo; pk.Gender = criteria.GetGender(Gender, pi); @@ -200,7 +203,7 @@ public sealed class GP1(byte[] Data) Span moves = stackalloc ushort[4]; ((ILearnSource)LearnSource7GG.Instance).SetEncounterMoves(Species, Form, Level, moves); pk.SetMoves(moves); - pk.OriginalTrainerFriendship = pk.PersonalInfo.BaseFriendship; + pk.OriginalTrainerFriendship = pi.BaseFriendship; pk.HeightScalar = HeightScalar; pk.WeightScalar = WeightScalar; diff --git a/PKHeX.Core/Saves/Util/BoxUtil.cs b/PKHeX.Core/Saves/Util/BoxUtil.cs index 436ba144e..ec8382919 100644 --- a/PKHeX.Core/Saves/Util/BoxUtil.cs +++ b/PKHeX.Core/Saves/Util/BoxUtil.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -224,21 +225,27 @@ public static class BoxUtil /// Returns default English box names in the event the save file does not have names (not exportable), or fails to return a box name. public static string[] GetBoxNames(SaveFile sav) { - int count = sav.BoxCount; + var count = sav.BoxCount; + if (count == 0) + return []; var result = new string[count]; + GetBoxNames(sav, result); + return result; + } + + private static void GetBoxNames(SaveFile sav, Span result) + { if (!sav.State.Exportable || sav is not IBoxDetailNameRead r) { - for (int i = 0; i < count; i++) + for (int i = 0; i < result.Length; i++) result[i] = BoxDetailNameExtensions.GetDefaultBoxName(i); - return result; + return; } - for (int i = 0; i < count; i++) + for (int i = 0; i < result.Length; i++) { try { result[i] = r.GetBoxName(i); } catch { result[i] = BoxDetailNameExtensions.GetDefaultBoxName(i); } } - - return result; } } diff --git a/PKHeX.Drawing.PokeSprite/Util/SpriteUtil.cs b/PKHeX.Drawing.PokeSprite/Util/SpriteUtil.cs index 18d5a8a71..6752bb90b 100644 --- a/PKHeX.Drawing.PokeSprite/Util/SpriteUtil.cs +++ b/PKHeX.Drawing.PokeSprite/Util/SpriteUtil.cs @@ -259,9 +259,9 @@ public static class SpriteUtil var gender = GetDisplayGender(enc); var shiny = enc.IsShiny ? Shiny.Always : Shiny.Never; var img = GetSprite(enc.Species, enc.Form, gender, 0, 0, enc.EggEncounter, shiny, enc.Context); - if (SpriteBuilder.ShowEncounterBall && enc is IFixedBall {FixedBall: not Ball.None} b) + if (SpriteBuilder.ShowEncounterBall && enc is {FixedBall: not Ball.None}) { - var ballSprite = GetBallSprite((byte)b.FixedBall); + var ballSprite = GetBallSprite((byte)enc.FixedBall); img = ImageUtil.LayerImage(img, ballSprite, 0, img.Height - ballSprite.Height); } if (enc is IGigantamaxReadOnly {CanGigantamax: true}) @@ -297,9 +297,9 @@ public static class SpriteUtil var gender = Math.Max((byte)0, gift.Gender); var img = GetSprite(gift.Species, gift.Form, gender, 0, gift.HeldItem, gift.IsEgg, gift.IsShiny ? Shiny.Always : Shiny.Never, gift.Context); - if (SpriteBuilder.ShowEncounterBall && gift is IFixedBall { FixedBall: not Ball.None } b) + if (SpriteBuilder.ShowEncounterBall && gift is { FixedBall: not Ball.None }) { - var ballSprite = GetBallSprite((byte)b.FixedBall); + var ballSprite = GetBallSprite((byte)gift.FixedBall); img = ImageUtil.LayerImage(img, ballSprite, 0, img.Height - ballSprite.Height); } diff --git a/PKHeX.WinForms/Controls/SAV Editor/BoxEditor.cs b/PKHeX.WinForms/Controls/SAV Editor/BoxEditor.cs index 0e01c0c6f..221d12903 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/BoxEditor.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/BoxEditor.cs @@ -180,11 +180,11 @@ public partial class BoxEditor : UserControl, ISlotViewer CurrentBox = box; } - private static bool GetIsSame(IReadOnlyList a, IList b) + private static bool GetIsSame(ReadOnlySpan a, IList b) { - if (a.Count != b.Count) + if (a.Length != b.Count) return false; - for (int i = 0; i < a.Count; i++) + for (int i = 0; i < a.Length; i++) { if (b[i] is not string s || s != a[i]) return false; diff --git a/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs b/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs index 09fb83ff0..c2662ae7c 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/SlotChangeManager.cs @@ -274,9 +274,9 @@ public sealed class SlotChangeManager(SAVEditor se) : IDisposable /// Args /// Destination slot disallows eggs/blanks /// True if loaded - private bool TryLoadFiles(IReadOnlyList files, DragEventArgs e, bool badDest) + private bool TryLoadFiles(ReadOnlySpan files, DragEventArgs e, bool badDest) { - if (files.Count == 0) + if (files.Length == 0) return false; var sav = Drag.Info.Destination!.View.SAV; diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs index 8edabb363..92d862e48 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Link6.cs @@ -1,6 +1,5 @@ using System; using System.IO; -using System.Linq; using System.Windows.Forms; using PKHeX.Core; @@ -11,7 +10,7 @@ public partial class SAV_Link6 : Form private readonly SaveFile Origin; private readonly ISaveBlock6Main SAV; - private PL6 LinkInfo; + private PL6 Gifts; public SAV_Link6(SaveFile sav) { @@ -19,18 +18,20 @@ public partial class SAV_Link6 : Form WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage); SAV = (ISaveBlock6Main)(Origin = sav).Clone(); var filtered = GameInfo.FilteredSources; - foreach (var cb in TAB_Items.Controls.OfType()) + + foreach (var cb in (ComboBox[])[CB_Item1, CB_Item2, CB_Item3, CB_Item4, CB_Item5, CB_Item6]) { cb.InitializeBinding(); cb.DataSource = new BindingSource(filtered.Items, null); } - LinkInfo = SAV.Link.GetLinkInfo(); + Gifts = SAV.Link.Gifts; LoadLinkData(); } private void B_Save_Click(object sender, EventArgs e) { - SAV.Link.SetLinkInfo(LinkInfo); + SaveLinkData(); + SAV.Link.RefreshChecksum(); Origin.CopyChangesFrom((SaveFile)SAV); Close(); } @@ -51,7 +52,7 @@ public partial class SAV_Link6 : Form { WinFormsUtil.Alert("Invalid file length"); return; } byte[] data = File.ReadAllBytes(ofd.FileName); - LinkInfo = new PL6(data); + Gifts = new PL6(data); LoadLinkData(); B_Export.Enabled = true; @@ -64,38 +65,69 @@ public partial class SAV_Link6 : Form if (sfd.ShowDialog() != DialogResult.OK) return; - File.WriteAllBytes(sfd.FileName, LinkInfo.Data); + File.WriteAllBytes(sfd.FileName, Gifts.Data.ToArray()); WinFormsUtil.Alert("Pokémon Link data saved to:" + Environment.NewLine + sfd.FileName); } private void LoadLinkData() { - RTB_LinkSource.Text = LinkInfo.Origin; - CHK_LinkAvailable.Checked = LinkInfo.Enabled; + RTB_LinkSource.Text = Gifts.Origin; + CHK_LinkAvailable.Checked = Gifts.Enabled; - NUD_BP.Value = LinkInfo.BattlePoints; - NUD_Pokemiles.Value = LinkInfo.Pokemiles; + NUD_BP.Value = Gifts.BattlePoints; + NUD_Pokemiles.Value = Gifts.Pokemiles; - CB_Item1.SelectedIndex = LinkInfo.Item_1; - CB_Item2.SelectedIndex = LinkInfo.Item_2; - CB_Item3.SelectedIndex = LinkInfo.Item_3; - CB_Item4.SelectedIndex = LinkInfo.Item_4; - CB_Item5.SelectedIndex = LinkInfo.Item_5; - CB_Item6.SelectedIndex = LinkInfo.Item_6; + CB_Item1.SelectedValue = (int)Gifts.Item1; + CB_Item2.SelectedValue = (int)Gifts.Item2; + CB_Item3.SelectedValue = (int)Gifts.Item3; + CB_Item4.SelectedValue = (int)Gifts.Item4; + CB_Item5.SelectedValue = (int)Gifts.Item5; + CB_Item6.SelectedValue = (int)Gifts.Item6; - NUD_Item1.Value = LinkInfo.Quantity_1; - NUD_Item2.Value = LinkInfo.Quantity_2; - NUD_Item3.Value = LinkInfo.Quantity_3; - NUD_Item4.Value = LinkInfo.Quantity_4; - NUD_Item5.Value = LinkInfo.Quantity_5; - NUD_Item6.Value = LinkInfo.Quantity_6; + NUD_Item1.Value = Gifts.Quantity1; + NUD_Item2.Value = Gifts.Quantity2; + NUD_Item3.Value = Gifts.Quantity3; + NUD_Item4.Value = Gifts.Quantity4; + NUD_Item5.Value = Gifts.Quantity5; + NUD_Item6.Value = Gifts.Quantity6; // Pokemon slots - TB_PKM1.Text = GameInfo.Strings.specieslist[LinkInfo.Poke_1.Species]; - TB_PKM2.Text = GameInfo.Strings.specieslist[LinkInfo.Poke_2.Species]; - TB_PKM3.Text = GameInfo.Strings.specieslist[LinkInfo.Poke_3.Species]; - TB_PKM4.Text = GameInfo.Strings.specieslist[LinkInfo.Poke_4.Species]; - TB_PKM5.Text = GameInfo.Strings.specieslist[LinkInfo.Poke_5.Species]; - TB_PKM6.Text = GameInfo.Strings.specieslist[LinkInfo.Poke_6.Species]; + TB_PKM1.Text = GetSpecies(Gifts.Entity1.Species); + TB_PKM2.Text = GetSpecies(Gifts.Entity2.Species); + TB_PKM3.Text = GetSpecies(Gifts.Entity3.Species); + TB_PKM4.Text = GetSpecies(Gifts.Entity4.Species); + TB_PKM5.Text = GetSpecies(Gifts.Entity5.Species); + TB_PKM6.Text = GetSpecies(Gifts.Entity6.Species); + } + + private static string GetSpecies(ushort species) + { + var arr = GameInfo.Strings.Species; + if (species < arr.Count) + return arr[species]; + return species.ToString(); + } + + private void SaveLinkData() + { + Gifts.Origin = RTB_LinkSource.Text; + Gifts.Enabled = CHK_LinkAvailable.Checked; + + Gifts.BattlePoints = (ushort)NUD_BP.Value; + Gifts.Pokemiles = (ushort)NUD_Pokemiles.Value; + + Gifts.Item1 = (ushort)WinFormsUtil.GetIndex(CB_Item1); + Gifts.Item2 = (ushort)WinFormsUtil.GetIndex(CB_Item2); + Gifts.Item3 = (ushort)WinFormsUtil.GetIndex(CB_Item3); + Gifts.Item4 = (ushort)WinFormsUtil.GetIndex(CB_Item4); + Gifts.Item5 = (ushort)WinFormsUtil.GetIndex(CB_Item5); + Gifts.Item6 = (ushort)WinFormsUtil.GetIndex(CB_Item6); + + Gifts.Quantity1 = (byte)NUD_Item1.Value; + Gifts.Quantity2 = (byte)NUD_Item2.Value; + Gifts.Quantity3 = (byte)NUD_Item3.Value; + Gifts.Quantity4 = (byte)NUD_Item4.Value; + Gifts.Quantity5 = (byte)NUD_Item5.Value; + Gifts.Quantity6 = (byte)NUD_Item6.Value; } } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs index a21948511..f8d1d9518 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7GG.cs @@ -207,7 +207,7 @@ public partial class SAV_Trainer7GG : Form var folder = fbd.SelectedPath; foreach (var gpk in gofiles) - File.WriteAllBytes(Path.Combine(folder, Util.CleanFileName(gpk.FileName)), gpk.Data); + File.WriteAllBytes(Path.Combine(folder, Util.CleanFileName(gpk.FileName)), gpk.Data.ToArray()); WinFormsUtil.Alert($"Dumped {gofiles.Length} files to {folder}"); } @@ -243,7 +243,7 @@ public partial class SAV_Trainer7GG : Form return; } var gp1 = new GP1(); - data.CopyTo(gp1.Data, 0); + data.CopyTo(gp1.Data); Park[index] = gp1; UpdateGoSummary((int)NUD_GoIndex.Value); } @@ -266,7 +266,7 @@ public partial class SAV_Trainer7GG : Form if (sfd.ShowDialog() != DialogResult.OK) return; - File.WriteAllBytes(sfd.FileName, data.Data); + File.WriteAllBytes(sfd.FileName, data.Data.ToArray()); } private void B_ImportGoFiles_Click(object sender, EventArgs e) diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexResearchEditorLA.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexResearchEditorLA.cs index 1e3d4d244..cd61b1d29 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexResearchEditorLA.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_PokedexResearchEditorLA.cs @@ -13,12 +13,55 @@ public partial class SAV_PokedexResearchEditorLA : Form private readonly PokedexSave8a Dex; private readonly ushort Species; - private readonly bool WasEmpty; private readonly NumericUpDown[] TaskNUPs; - private readonly PokedexResearchTaskType8a[] TaskTypes; - private readonly int[] TaskIndexes; + + private static ReadOnlySpan TaskTypes => + [ + Catch, + CatchAlpha, + CatchLarge, + CatchSmall, + CatchHeavy, + CatchLight, + CatchAtTime, + CatchSleeping, + CatchInAir, + CatchNotSpotted, + + UseMove, + UseMove, + UseMove, + UseMove, + DefeatWithMoveType, + DefeatWithMoveType, + DefeatWithMoveType, + Defeat, + UseStrongStyleMove, + UseAgileStyleMove, + + Evolve, + GiveFood, + StunWithItems, + ScareWithScatterBang, + LureWithPokeshiDoll, + + LeapFromTrees, + LeapFromLeaves, + LeapFromSnow, + LeapFromOre, + LeapFromTussocks, + ]; + + private static ReadOnlySpan TaskIndexes => + [ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 0, 1, 2, -1, -1, -1, + -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, + ]; + private readonly int[] TaskParameters; public SAV_PokedexResearchEditorLA(SAV8LA sav, ushort species, int dexIdx, IReadOnlyList tasks, IReadOnlyList timeTasks) @@ -107,80 +150,6 @@ public partial class SAV_PokedexResearchEditorLA : Form NUP_LeapTussocks, ]; - TaskTypes = - [ - Catch, - CatchAlpha, - CatchLarge, - CatchSmall, - CatchHeavy, - CatchLight, - CatchAtTime, - CatchSleeping, - CatchInAir, - CatchNotSpotted, - - UseMove, - UseMove, - UseMove, - UseMove, - DefeatWithMoveType, - DefeatWithMoveType, - DefeatWithMoveType, - Defeat, - UseStrongStyleMove, - UseAgileStyleMove, - - Evolve, - GiveFood, - StunWithItems, - ScareWithScatterBang, - LureWithPokeshiDoll, - - LeapFromTrees, - LeapFromLeaves, - LeapFromSnow, - LeapFromOre, - LeapFromTussocks, - ]; - - TaskIndexes = - [ - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - -1, - - 0, - 1, - 2, - 3, - 0, - 1, - 2, - -1, - -1, - -1, - - -1, - -1, - -1, - -1, - -1, - - -1, - -1, - -1, - -1, - -1, - ]; - TaskParameters = new int[TaskIndexes.Length]; InitializeTaskParameters(dexIdx); #endregion @@ -253,14 +222,10 @@ public partial class SAV_PokedexResearchEditorLA : Form if (nup.Value != 0) return false; } - return true; } - private void B_Cancel_Click(object sender, EventArgs e) - { - Close(); - } + private void B_Cancel_Click(object sender, EventArgs e) => Close(); private void B_Save_Click(object sender, EventArgs e) {