From 5bdc6b9ef8ea5dac9de14329338c47a9cc9bba3e Mon Sep 17 00:00:00 2001 From: Kurt Date: Thu, 20 Apr 2023 21:23:15 -0700 Subject: [PATCH] Privatize some static fields, more robust legal helper classes. (#3865) * Uses LearnSource more throughout the codebase when appropriate, rather than loosely coupled pivot methods. * Hides Learnset/EggMove data inside the LearnSource classes. * Extracts functionality from the large Legal class & partial Table*.cs files into better performing helper classes. * Cleans up some code from prior LearnSource commits. --- .../Applicators/MoveShopRecordApplicator.cs | 16 +- PKHeX.Core/Editing/Bulk/BatchMods.cs | 2 +- PKHeX.Core/Editing/Pokerus.cs | 4 +- .../Editing/Showdown/ShowdownParsing.cs | 6 +- .../GameStrings/FilteredGameDataSource.cs | 2 +- PKHeX.Core/Items/ItemStorage7GG.cs | 9 +- PKHeX.Core/Items/ItemStorage8SWSH.cs | 10 +- PKHeX.Core/Legality/Breeding.cs | 2 - PKHeX.Core/Legality/Core.cs | 168 ++++++++---- .../Encounters/EncounterMisc/EncounterEgg.cs | 7 +- .../Encounters/EncounterSlot/EncounterSlot.cs | 3 +- .../EncounterSlot/EncounterSlot8a.cs | 12 +- .../EncounterSlot/EncounterSlot8b.cs | 6 +- .../EncounterSlot/GO/EncounterSlot7GO.cs | 3 +- .../EncounterSlot/GO/EncounterSlot8GO.cs | 6 +- .../EncounterStatic/EncounterStatic.cs | 3 +- .../EncounterStatic/EncounterStatic7.cs | 2 +- .../EncounterStatic/EncounterStatic8a.cs | 9 +- .../EncounterTrade/EncounterTrade.cs | 3 +- .../Encounters/Generator/EncounterFinder.cs | 2 +- .../Moveset/EncounterMovesetGenerator.cs | 6 +- .../Information/EncounterSuggestion.cs | 2 +- .../Encounters/Verifiers/EggHatchLocation3.cs | 67 +++++ .../Encounters/Verifiers/EggHatchLocation4.cs | 61 +++++ .../Encounters/Verifiers/EggHatchLocation5.cs | 58 +++++ .../Encounters/Verifiers/EggHatchLocation6.cs | 30 +++ .../Encounters/Verifiers/EggHatchLocation7.cs | 59 +++++ .../Encounters/Verifiers/EggHatchLocation8.cs | 36 +++ .../Verifiers/EggHatchLocation8b.cs | 87 +++++++ .../Encounters/Verifiers/EggHatchLocation9.cs | 39 +++ .../Encounters/Verifiers/EncounterVerifier.cs | 243 ++++++++++-------- .../Legality/LearnSource/Group/LearnGroup1.cs | 8 +- .../LearnSource/Sources/LearnSource1RB.cs | 5 +- .../LearnSource/Sources/LearnSource1YW.cs | 5 +- .../LearnSource/Sources/LearnSource2C.cs | 4 +- .../LearnSource/Sources/LearnSource2GS.cs | 4 +- .../LearnSource/Sources/LearnSource3E.cs | 6 +- .../LearnSource/Sources/LearnSource3FR.cs | 6 +- .../LearnSource/Sources/LearnSource3LG.cs | 6 +- .../LearnSource/Sources/LearnSource3RS.cs | 6 +- .../LearnSource/Sources/LearnSource4DP.cs | 6 +- .../LearnSource/Sources/LearnSource4HGSS.cs | 4 +- .../LearnSource/Sources/LearnSource4Pt.cs | 6 +- .../LearnSource/Sources/LearnSource5B2W2.cs | 6 +- .../LearnSource/Sources/LearnSource5BW.cs | 6 +- .../LearnSource/Sources/LearnSource6AO.cs | 4 +- .../LearnSource/Sources/LearnSource6XY.cs | 4 +- .../LearnSource/Sources/LearnSource7GG.cs | 2 +- .../LearnSource/Sources/LearnSource7SM.cs | 10 +- .../LearnSource/Sources/LearnSource7USUM.cs | 10 +- .../LearnSource/Sources/LearnSource8BDSP.cs | 4 +- .../LearnSource/Sources/LearnSource8PLA.cs | 9 +- .../LearnSource/Sources/LearnSource8SWSH.cs | 10 +- .../LearnSource/Sources/LearnSource9SV.cs | 6 +- .../Sources/Shared/ILearnSource.cs | 9 + .../Sources/Shared/LearnSource3.cs | 4 +- .../Sources/Shared/LearnSource4.cs | 4 +- .../Sources/Shared/LearnSource5.cs | 4 +- .../LearnSource/Verify/LearnVerifierEgg.cs | 4 +- PKHeX.Core/Legality/Learnset/EggMoves.cs | 24 ++ PKHeX.Core/Legality/MoveList.cs | 84 ------ PKHeX.Core/Legality/MoveListSuggest.cs | 11 +- .../Legality/Moves/Breeding/MoveBreed.cs | 6 +- .../Legality/Moves/Breeding/MoveBreed2.cs | 15 +- .../Legality/Moves/Breeding/MoveBreed3.cs | 21 +- .../Legality/Moves/Breeding/MoveBreed4.cs | 10 +- .../Legality/Moves/Breeding/MoveBreed5.cs | 6 +- .../Legality/Moves/Breeding/MoveBreed6.cs | 8 +- PKHeX.Core/Legality/Moves/GameData.cs | 79 +++--- PKHeX.Core/Legality/Moves/MoveEgg.cs | 81 ------ PKHeX.Core/Legality/Moves/MoveLevelUp.cs | 43 ---- .../Legality/Restrictions/ItemRestrictions.cs | 37 +++ .../Memories/MemoryPermissions.cs | 3 +- .../Structures/IMasteryInitialMoveShop8.cs | 2 +- PKHeX.Core/Legality/Tables/FormInfo.cs | 39 ++- PKHeX.Core/Legality/Tables/SpeciesCategory.cs | 89 +++++++ PKHeX.Core/Legality/Tables/Tables.cs | 136 ---------- PKHeX.Core/Legality/Tables/Tables1.cs | 9 - PKHeX.Core/Legality/Tables/Tables2.cs | 13 - PKHeX.Core/Legality/Tables/Tables3.cs | 67 ----- PKHeX.Core/Legality/Tables/Tables4.cs | 93 ------- PKHeX.Core/Legality/Tables/Tables5.cs | 55 ---- PKHeX.Core/Legality/Tables/Tables6.cs | 64 ----- PKHeX.Core/Legality/Tables/Tables7.cs | 174 ------------- PKHeX.Core/Legality/Tables/Tables7b.cs | 50 ---- PKHeX.Core/Legality/Tables/Tables8.cs | 100 ------- PKHeX.Core/Legality/Tables/Tables8a.cs | 15 -- PKHeX.Core/Legality/Tables/Tables8bs.cs | 75 ------ PKHeX.Core/Legality/Tables/Tables9.cs | 50 ---- PKHeX.Core/Legality/Verifiers/FormVerifier.cs | 29 --- .../Legality/Verifiers/GenderVerifier.cs | 5 +- .../Verifiers/LegendsArceusVerifier.cs | 16 +- .../Legality/Verifiers/Ribbons/RibbonRules.cs | 28 +- PKHeX.Core/Moves/MoveInfo7b.cs | 31 +++ PKHeX.Core/MysteryGifts/PGF.cs | 3 +- PKHeX.Core/MysteryGifts/WC3.cs | 12 +- PKHeX.Core/PKM/Interfaces/IAwakened.cs | 33 ++- PKHeX.Core/PKM/Interfaces/IBattleVersion.cs | 3 +- PKHeX.Core/PKM/PA8.cs | 6 +- PKHeX.Core/PKM/PB8.cs | 6 +- PKHeX.Core/PKM/PK1.cs | 12 +- PKHeX.Core/PKM/PK2.cs | 12 +- PKHeX.Core/PKM/PK4.cs | 2 +- PKHeX.Core/PKM/PK5.cs | 18 ++ PKHeX.Core/PKM/PK8.cs | 6 +- PKHeX.Core/PKM/PK9.cs | 6 +- PKHeX.Core/PKM/PKM.cs | 8 +- PKHeX.Core/PKM/Shared/GBPKML.cs | 22 +- PKHeX.Core/PKM/Shared/PokeListGB.cs | 4 +- .../PKM/Util/Conversion/FormConverter.cs | 40 ++- PKHeX.Core/Saves/SAV1Stadium.cs | 8 +- PKHeX.Core/Saves/SAV1StadiumJ.cs | 8 +- PKHeX.Core/Saves/SAV2.cs | 4 +- .../Saves/Substructures/Gen7/LGPE/GP1.cs | 3 +- .../Saves/Substructures/Gen8/BS/MyItem8b.cs | 3 - .../Controls/PKM Editor/StatEditor.cs | 6 +- PKHeX.WinForms/Subforms/KChart.cs | 21 +- 117 files changed, 1281 insertions(+), 1658 deletions(-) create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation3.cs create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation4.cs create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation5.cs create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation6.cs create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation7.cs create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8.cs create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8b.cs create mode 100644 PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation9.cs delete mode 100644 PKHeX.Core/Legality/MoveList.cs delete mode 100644 PKHeX.Core/Legality/Moves/MoveEgg.cs delete mode 100644 PKHeX.Core/Legality/Moves/MoveLevelUp.cs create mode 100644 PKHeX.Core/Legality/Tables/SpeciesCategory.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables1.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables2.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables3.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables4.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables5.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables6.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables7.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables7b.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables8.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables8a.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables8bs.cs delete mode 100644 PKHeX.Core/Legality/Tables/Tables9.cs diff --git a/PKHeX.Core/Editing/Applicators/MoveShopRecordApplicator.cs b/PKHeX.Core/Editing/Applicators/MoveShopRecordApplicator.cs index 241af5eb5..66ca9f521 100644 --- a/PKHeX.Core/Editing/Applicators/MoveShopRecordApplicator.cs +++ b/PKHeX.Core/Editing/Applicators/MoveShopRecordApplicator.cs @@ -46,12 +46,8 @@ public static void SetMoveShopFlags(this IMoveShop8Mastery shop, PKM pk) /// public static void SetMoveShopFlags(this IMoveShop8Mastery shop, ReadOnlySpan moves, PKM pk) { - var index = PersonalTable.LA.GetFormIndex(pk.Species, pk.Form); - var learn = Legal.LevelUpLA[index]; - var mastery = Legal.MasteryLA[index]; - var level = pk.CurrentLevel; - - shop.SetMoveShopFlags(moves, learn, mastery, level); + var (learn, mastery) = LearnSource8LA.GetLearnsetAndMastery(pk.Species, pk.Form); + shop.SetMoveShopFlags(moves, learn, mastery, pk.CurrentLevel); } /// @@ -59,12 +55,8 @@ public static void SetMoveShopFlags(this IMoveShop8Mastery shop, ReadOnlySpan public static void SetMoveShopFlagsAll(this IMoveShop8Mastery shop, PKM pk) { - var index = PersonalTable.LA.GetFormIndex(pk.Species, pk.Form); - var learn = Legal.LevelUpLA[index]; - var mastery = Legal.MasteryLA[index]; - var level = pk.CurrentLevel; - - shop.SetMoveShopFlagsAll(learn, mastery, level); + var (learn, mastery) = LearnSource8LA.GetLearnsetAndMastery(pk.Species, pk.Form); + shop.SetMoveShopFlagsAll(learn, mastery, pk.CurrentLevel); } /// diff --git a/PKHeX.Core/Editing/Bulk/BatchMods.cs b/PKHeX.Core/Editing/Bulk/BatchMods.cs index fba4db400..a42fe5218 100644 --- a/PKHeX.Core/Editing/Bulk/BatchMods.cs +++ b/PKHeX.Core/Editing/Bulk/BatchMods.cs @@ -20,7 +20,7 @@ public static class BatchMods new TypeSuggestion(nameof(Extensions.ClearGeoLocationData), p => p.ClearGeoLocationData()), new TypeSuggestion(nameof(AwakeningUtil.AwakeningClear), p => p.AwakeningClear()), new TypeSuggestion(nameof(AwakeningUtil.AwakeningMinimum), p => p.AwakeningMinimum()), - new TypeSuggestion(nameof(AwakeningUtil.AwakeningMax), p => p.AwakeningMax()), + new TypeSuggestion(nameof(AwakeningUtil.AwakeningMaximize), p => p.AwakeningMaximize()), new TypeSuggestion(nameof(GanbaruExtensions.ClearGanbaruValues), p => p.ClearGanbaruValues()), new TypeSuggestion(nameof(GanbaruExtensions.SetSuggestedGanbaruValues), p => p.SetSuggestedGanbaruValues((PKM)p)), diff --git a/PKHeX.Core/Editing/Pokerus.cs b/PKHeX.Core/Editing/Pokerus.cs index 7aff49a57..6b07e8776 100644 --- a/PKHeX.Core/Editing/Pokerus.cs +++ b/PKHeX.Core/Editing/Pokerus.cs @@ -50,8 +50,8 @@ public static bool IsStrainValid(PKM pk, int strain, int days) if (!IsObtainable(pk)) return IsSusceptible(strain, days); if (pk.Format <= 2) - return IsStrainValid2(strain); - return IsStrainValid(strain); + return IsStrainValid2(strain, days); + return IsStrainValid(strain, days); } /// diff --git a/PKHeX.Core/Editing/Showdown/ShowdownParsing.cs b/PKHeX.Core/Editing/Showdown/ShowdownParsing.cs index ffd0bbf81..c865d8753 100644 --- a/PKHeX.Core/Editing/Showdown/ShowdownParsing.cs +++ b/PKHeX.Core/Editing/Showdown/ShowdownParsing.cs @@ -106,8 +106,8 @@ public static string GetShowdownFormName(ushort species, string form) (int)Greninja or (int)Rockruff or (int)Koraidon or (int)Miraidon => string.Empty, - _ => Legal.Totem_USUM.Contains(species) && form == "Large" - ? Legal.Totem_Alolan.Contains(species) && species != (int)Mimikyu ? "Alola-Totem" : "Totem" + _ => FormInfo.HasTotemForm(species) && form == "Large" + ? species is (int)Raticate or (int)Marowak ? "Alola-Totem" : "Totem" : form.Replace(' ', '-'), }; } @@ -139,7 +139,7 @@ public static string SetShowdownFormName(ushort species, string form, int abilit (int)Maushold when form == "Four" => "Family of Four", (int)Urshifu or (int)Pikachu or (int)Alcremie => form.Replace('-', ' '), // Strike and Cosplay - _ => Legal.Totem_USUM.Contains(species) && form.EndsWith("Totem", StringComparison.OrdinalIgnoreCase) ? "Large" : form, + _ => FormInfo.HasTotemForm(species) && form.EndsWith("Totem", StringComparison.OrdinalIgnoreCase) ? "Large" : form, }; } diff --git a/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs b/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs index fbf77183e..2bf349f89 100644 --- a/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs +++ b/PKHeX.Core/Game/GameStrings/FilteredGameDataSource.cs @@ -82,7 +82,7 @@ private static IEnumerable GetFilteredMoves(IGameValueLimit sav, Game var legal = source.LegalMoveDataSource; return sav switch { - SAV7b => legal.Where(s => Legal.IsAllowedMoveGG((ushort)s.Value)), // LGPE: Not all moves are available + SAV7b => legal.Where(s => MoveInfo7b.IsAllowedMoveGG((ushort)s.Value)), // LGPE: Not all moves are available _ => legal.Where(m => m.Value <= sav.MaxMoveID), }; } diff --git a/PKHeX.Core/Items/ItemStorage7GG.cs b/PKHeX.Core/Items/ItemStorage7GG.cs index e4ad9994d..7efbcee35 100644 --- a/PKHeX.Core/Items/ItemStorage7GG.cs +++ b/PKHeX.Core/Items/ItemStorage7GG.cs @@ -6,16 +6,14 @@ public sealed class ItemStorage7GG : IItemStorage { public static readonly ItemStorage7GG Instance = new(); - private static ReadOnlySpan Pouch_Candy_GG_Regular => new ushort[] + private static ReadOnlySpan Pouch_Candy_GG => new ushort[] { 050, // Rare Candy 960, 961, 962, 963, 964, 965, // S 966, 967, 968, 969, 970, 971, // L 972, 973, 974, 975, 976, 977, // XL - }; - private static ReadOnlySpan Pouch_Candy_GG_Species => new ushort[] - { + // Species 978, 979, 980, 981, 982, 983, 984, 985, 986, 987, 988, 989, 990, 991, 992, 993, 994, 995, 996, 997, 998, 999, @@ -28,8 +26,6 @@ public sealed class ItemStorage7GG : IItemStorage 1057, }; - private static readonly ushort[] Pouch_Candy_GG = ArrayUtil.ConcatAll(Pouch_Candy_GG_Regular, Pouch_Candy_GG_Species); - private static ReadOnlySpan Pouch_Medicine_GG => new ushort[] { 017, 018, 019, 020, 021, 022, 023, 024, 025, 026, 027, 028, 029, 030, 031, 032, 038, 039, 040, 041, 709, 903, @@ -117,7 +113,6 @@ public sealed class ItemStorage7GG : IItemStorage public ReadOnlySpan GetItems(InventoryType type) => type switch { - InventoryType.Medicine => Pouch_Medicine_GG, InventoryType.TMHMs => Pouch_TM_GG, InventoryType.Balls => Pouch_Catching_GG, diff --git a/PKHeX.Core/Items/ItemStorage8SWSH.cs b/PKHeX.Core/Items/ItemStorage8SWSH.cs index 45db0d00f..592d5fc22 100644 --- a/PKHeX.Core/Items/ItemStorage8SWSH.cs +++ b/PKHeX.Core/Items/ItemStorage8SWSH.cs @@ -468,10 +468,16 @@ public sealed class ItemStorage8SWSH : IItemStorage 1578, // ★Aql7235 }; + private const int DMAX_START = 1279; + private const int DMAX_END = 1578; + private const int DMAX_LEGAL_END = 1290; // ★Sgr7194 (Eevee) + public static bool IsDynamaxCrystal(ushort item) => item is >= DMAX_START and <= DMAX_END; + public static bool IsDynamaxCrystalAvailable(ushort item) => item is >= DMAX_START and <= DMAX_LEGAL_END; + public static bool IsItemLegal(ushort item) { - if (Legal.IsDynamaxCrystal(item)) - return Legal.IsDynamaxCrystalAvailable(item); + if (IsDynamaxCrystal(item)) + return IsDynamaxCrystalAvailable(item); return Unreleased.BinarySearch(item) < 0; } diff --git a/PKHeX.Core/Legality/Breeding.cs b/PKHeX.Core/Legality/Breeding.cs index d43f1e8c5..3d13c7f12 100644 --- a/PKHeX.Core/Legality/Breeding.cs +++ b/PKHeX.Core/Legality/Breeding.cs @@ -50,8 +50,6 @@ public static class Breeding /// True if can inherit moves, false if cannot. internal static bool GetCanInheritMoves(ushort species) { - if (Legal.FixedGenderFromBiGender.Contains(species)) // Nincada -> Shedinja loses gender causing 'false', edge case - return true; var pi = PKX.Personal[species]; if (pi is { Genderless: false, OnlyMale: false }) return true; diff --git a/PKHeX.Core/Legality/Core.cs b/PKHeX.Core/Legality/Core.cs index eac3c1288..aa08869ae 100644 --- a/PKHeX.Core/Legality/Core.cs +++ b/PKHeX.Core/Legality/Core.cs @@ -1,5 +1,4 @@ using System; -using static PKHeX.Core.BinLinkerAccessor; namespace PKHeX.Core; @@ -8,60 +7,135 @@ namespace PKHeX.Core; /// public static partial class Legal { - // Gen 1 - internal static readonly Learnset[] LevelUpRB = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_rb.pkl"), MaxSpeciesID_1); - internal static readonly Learnset[] LevelUpY = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_y.pkl"), MaxSpeciesID_1); + internal const int MaxSpeciesID_1 = 151; + internal const int MaxMoveID_1 = 165; + internal const int MaxItemID_1 = 255; + internal const int MaxAbilityID_1 = 0; - // Gen 2 - internal static readonly EggMoves2[] EggMovesGS = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_gs.pkl"), MaxSpeciesID_2); - internal static readonly Learnset[] LevelUpGS = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_gs.pkl"), MaxSpeciesID_2); - internal static readonly EggMoves2[] EggMovesC = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_c.pkl"), MaxSpeciesID_2); - internal static readonly Learnset[] LevelUpC = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), MaxSpeciesID_2); + internal const int MaxSpeciesID_2 = 251; + internal const int MaxMoveID_2 = 251; + internal const int MaxItemID_2 = 255; + internal const int MaxAbilityID_2 = 0; - // Gen 3 - internal static readonly Learnset[] LevelUpE = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_e.pkl"), "em")); - internal static readonly Learnset[] LevelUpRS = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs")); - internal static readonly Learnset[] LevelUpFR = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr")); - internal static readonly Learnset[] LevelUpLG = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg")); - internal static readonly EggMoves6[] EggMovesRS = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_rs.pkl"), "rs")); + internal const int MaxSpeciesIndex_3 = 412; + internal const int MaxSpeciesID_3 = 386; + internal const int MaxMoveID_3 = 354; + internal const int MaxItemID_3 = 374; + internal const int MaxItemID_3_COLO = 547; + internal const int MaxItemID_3_XD = 593; + internal const int MaxAbilityID_3 = 77; + internal const int MaxBallID_3 = 0xC; + internal const int MaxGameID_3 = 15; // CXD - // Gen 4 - internal static readonly Learnset[] LevelUpDP = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp")); - internal static readonly Learnset[] LevelUpPt = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt")); - internal static readonly Learnset[] LevelUpHGSS = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs")); - internal static readonly EggMoves6[] EggMovesDPPt = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp")); - internal static readonly EggMoves6[] EggMovesHGSS = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs")); + internal const int MaxSpeciesID_4 = 493; + internal const int MaxMoveID_4 = 467; + internal const int MaxItemID_4_DP = 464; + internal const int MaxItemID_4_Pt = 467; + internal const int MaxItemID_4_HGSS = 536; + internal const int MaxAbilityID_4 = 123; + internal const int MaxBallID_4 = 0x18; + internal const int MaxGameID_4 = 15; // CXD - // Gen 5 - internal static readonly Learnset[] LevelUpBW = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_bw.pkl"), "51")); - internal static readonly Learnset[] LevelUpB2W2 = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52")); - internal static readonly EggMoves6[] EggMovesBW = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_bw.pkl"), "bw")); + internal const int MaxSpeciesID_5 = 649; + internal const int MaxMoveID_5 = 559; + internal const int MaxItemID_5_BW = 632; + internal const int MaxItemID_5_B2W2 = 638; + internal const int MaxAbilityID_5 = 164; + internal const int MaxBallID_5 = 0x19; + internal const int MaxGameID_5 = 23; // B2 - // Gen 6 - internal static readonly EggMoves6[] EggMovesXY = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_xy.pkl"), "xy")); - internal static readonly Learnset[] LevelUpXY = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy")); - internal static readonly EggMoves6[] EggMovesAO = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_ao.pkl"), "ao")); - internal static readonly Learnset[] LevelUpAO = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao")); + internal const int MaxSpeciesID_6 = 721; + internal const int MaxMoveID_6_XY = 617; + internal const int MaxMoveID_6_AO = 621; + internal const int MaxItemID_6_XY = 717; + internal const int MaxItemID_6_AO = 775; + internal const int MaxAbilityID_6_XY = 188; + internal const int MaxAbilityID_6_AO = 191; + internal const int MaxBallID_6 = 0x19; + internal const int MaxGameID_6 = 27; // OR - // Gen 7 - internal static readonly EggMoves7[] EggMovesSM = EggMoves7.GetArray(Get(Util.GetBinaryResource("eggmove_sm.pkl"), "sm")); - internal static readonly Learnset[] LevelUpSM = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm")); - internal static readonly EggMoves7[] EggMovesUSUM = EggMoves7.GetArray(Get(Util.GetBinaryResource("eggmove_uu.pkl"), "uu")); - internal static readonly Learnset[] LevelUpUSUM = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu")); - internal static readonly Learnset[] LevelUpGG = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg")); + internal const int MaxSpeciesID_7 = 802; + internal const int MaxMoveID_7 = 719; + internal const int MaxItemID_7 = 920; + internal const int MaxAbilityID_7 = 232; + internal const int MaxBallID_7 = 0x1A; // 26 + internal const int MaxGameID_7 = 41; // Crystal (VC?) - // Gen 8 - internal static readonly EggMoves7[] EggMovesSWSH = EggMoves7.GetArray(Get(Util.GetBinaryResource("eggmove_swsh.pkl"), "ss")); - internal static readonly Learnset[] LevelUpSWSH = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_swsh.pkl"), "ss")); - internal static readonly EggMoves6[] EggMovesBDSP = EggMoves6.GetArray(Get(Util.GetBinaryResource("eggmove_bdsp.pkl"), "bs")); - internal static readonly Learnset[] LevelUpBDSP = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_bdsp.pkl"), "bs")); - internal static readonly Learnset[] LevelUpLA = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_la.pkl"), "la")); - internal static readonly Learnset[] MasteryLA = LearnsetReader.GetArray(Get(Util.GetBinaryResource("mastery_la.pkl"), "la")); + internal const int MaxSpeciesID_7_USUM = 807; + internal const int MaxMoveID_7_USUM = 728; + internal const int MaxItemID_7_USUM = 959; + internal const int MaxAbilityID_7_USUM = 233; - // Gen 9 - internal static readonly ushort[][] EggMovesSV = EggMoves9.GetArray(Get(Util.GetBinaryResource("eggmove_sv.pkl"), "sv")); - internal static readonly ushort[][] ReminderSV = EggMoves9.GetArray(Get(Util.GetBinaryResource("reminder_sv.pkl"), "sv")); - internal static readonly Learnset[] LevelUpSV = LearnsetReader.GetArray(Get(Util.GetBinaryResource("lvlmove_sv.pkl"), "sv")); + internal const int MaxSpeciesID_7b = 809; // Melmetal + internal const int MaxMoveID_7b = 742; // Double Iron Bash + internal const int MaxItemID_7b = 1057; // Magmar Candy + internal const int MaxBallID_7b = (int)Ball.Beast; + internal const int MaxGameID_7b = (int)GameVersion.GE; + internal const int MaxAbilityID_7b = MaxAbilityID_7_USUM; + + // Current Binaries + internal const int MaxSpeciesID_8 = MaxSpeciesID_8_R2; + internal const int MaxMoveID_8 = MaxMoveID_8_R2; + internal const int MaxItemID_8 = MaxItemID_8_R2; + internal const int MaxAbilityID_8 = MaxAbilityID_8_R2; + + // Orion (No DLC) + internal const int MaxSpeciesID_8_O0 = 890; // Eternatus + internal const int MaxMoveID_8_O0 = 796; // Steel Beam + internal const int MaxItemID_8_O0 = 1278; // Rotom Catalog, ignore all catalog parts + internal const int MaxAbilityID_8_O0 = 258; // Hunger Switch + + // Rigel 1 (DLC 1: Isle of Armor) + internal const int MaxSpeciesID_8_R1 = 893; // Zarude + internal const int MaxMoveID_8_R1 = 818; // Surging Strikes + internal const int MaxItemID_8_R1 = 1589; // Mark Charm + internal const int MaxAbilityID_8_R1 = 260; // Unseen Fist + + // Rigel 2 (DLC 2: Crown Tundra) + internal const int MaxSpeciesID_8_R2 = 898; // Calyrex + internal const int MaxMoveID_8_R2 = 826; // Eerie Spell + internal const int MaxItemID_8_R2 = 1607; // Reins of Unity + internal const int MaxAbilityID_8_R2 = 267; // As One (Glastrier) + + internal const int MaxBallID_8 = 0x1A; // 26 Beast + internal const int MaxGameID_8 = 45; // Shield + + internal const int MaxSpeciesID_8a = (int)Species.Enamorus; + internal const int MaxMoveID_8a = (int)Move.TakeHeart; + internal const int MaxItemID_8a = 1828; // Legend Plate + internal const int MaxBallID_8a = (int)Ball.LAOrigin; + internal const int MaxGameID_8a = (int)GameVersion.SP; + internal const int MaxAbilityID_8a = MaxAbilityID_8_R2; + + internal const int MaxSpeciesID_8b = MaxSpeciesID_4; // Arceus-493 + internal const int MaxMoveID_8b = MaxMoveID_8_R2; + internal const int MaxItemID_8b = 1822; // DS Sounds + internal const int MaxBallID_8b = (int)Ball.LAOrigin; + internal const int MaxGameID_8b = (int)GameVersion.SP; + internal const int MaxAbilityID_8b = MaxAbilityID_8_R2; + + internal const int MaxSpeciesID_9 = (int)Species.IronLeaves; + internal const int MaxMoveID_9 = (int)Move.MagicalTorque; + internal const int MaxItemID_9 = 2400; // Yellow Dish + internal const int MaxAbilityID_9 = (int)Ability.MyceliumMight; + + internal const int MaxBallID_9 = (int)Ball.LAOrigin; + internal const int MaxGameID_9 = (int)GameVersion.VL; + + internal static readonly ushort[] HeldItems_GSC = ItemStorage2.GetAllHeld(); + internal static readonly ushort[] HeldItems_RS = ItemStorage3RS.GetAllHeld(); + internal static readonly ushort[] HeldItems_DP = ItemStorage4DP.GetAllHeld(); + internal static readonly ushort[] HeldItems_Pt = ItemStorage4Pt.GetAllHeld(); // Griseous Orb Added + internal static readonly ushort[] HeldItems_HGSS = HeldItems_Pt; + internal static readonly ushort[] HeldItems_BW = ItemStorage5.GetAllHeld(); + internal static readonly ushort[] HeldItem_AO = ItemStorage6XY.GetAllHeld(); + internal static readonly ushort[] HeldItems_SM = ItemStorage7SM.GetAllHeld(); + internal static readonly ushort[] HeldItems_USUM = ItemStorage7USUM.GetAllHeld(); + internal static readonly ushort[] HeldItems_GG = Array.Empty(); + internal static readonly ushort[] HeldItems_SWSH = ItemStorage8SWSH.GetAllHeld(); + internal static readonly ushort[] HeldItems_BS = ItemStorage8BDSP.GetAll(); + internal static readonly ushort[] HeldItems_LA = Array.Empty(); + internal static readonly ushort[] HeldItems_SV = ItemStorage9SV.GetAllHeld(); internal static int GetMaxSpeciesOrigin(int generation) => generation switch { diff --git a/PKHeX.Core/Legality/Encounters/EncounterMisc/EncounterEgg.cs b/PKHeX.Core/Legality/Encounters/EncounterMisc/EncounterEgg.cs index 4815a1dea..7931bd92b 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterMisc/EncounterEgg.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterMisc/EncounterEgg.cs @@ -153,8 +153,9 @@ private void SetMetData(PKM pk) private void SetEncounterMoves(PKM pk, GameVersion version) { - var learnset = GameData.GetLearnset(version, Species, Form); - var baseMoves = learnset.GetBaseEggMoves(Level); - pk.SetMoves(baseMoves); + var ls = GameData.GetLearnSource(version); + var learn = ls.GetLearnset(Species, Form); + var initial = learn.GetBaseEggMoves(LevelMin); + pk.SetMoves(initial); } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot.cs index e95b59b80..4d47a26ce 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot.cs @@ -125,7 +125,8 @@ protected virtual void ApplyDetailsBall(PKM pk) protected virtual void SetEncounterMoves(PKM pk, GameVersion version, int level) { Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, pk, level, version); + var source = GameData.GetLearnSource(version); + source.SetEncounterMoves(Species, Form, level, moves); pk.SetMoves(moves); pk.SetMaximumPPCurrent(moves); } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8a.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8a.cs index b4bce7700..789868933 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8a.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8a.cs @@ -84,13 +84,7 @@ public void LoadInitialMoveset(PA8 pa8, Span moves, Learnset learn, int } } - public (Learnset Learn, Learnset Mastery) GetLevelUpInfo() - { - var index = PersonalTable.LA.GetFormIndex(Species, Form); - var learn = Legal.LevelUpLA[index]; - var mastery = Legal.MasteryLA[index]; - return (learn, mastery); - } + public (Learnset Learn, Learnset Mastery) GetLevelUpInfo() => LearnSource8LA.GetLearnsetAndMastery(Species, Form); protected override void SetFormatSpecificData(PKM pk) { @@ -174,14 +168,12 @@ public bool IsForcedMasteryCorrect(PKM pk) bool allowAlphaPurchaseBug = Area.Type is not SlotType.OverworldMMO; // Everything else Alpha is pre-1.1 var level = pk.Met_Level; - var index = PersonalTable.LA.GetFormIndex(Species, Form); - var learn = Legal.LevelUpLA[index]; + var (learn, mastery) = GetLevelUpInfo(); ushort alpha = pk is PA8 pa ? pa.AlphaMove : (ushort)0; if (!p.IsValidPurchasedEncounter(learn, level, alpha, allowAlphaPurchaseBug)) return false; Span moves = stackalloc ushort[4]; - var mastery = Legal.MasteryLA[index]; if (pk is PA8 { AlphaMove: not 0 } pa8) { moves[0] = pa8.AlphaMove; diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8b.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8b.cs index d0533b93d..890a823fc 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8b.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot/EncounterSlot8b.cs @@ -41,10 +41,10 @@ public bool CanBeUndergroundMove(ushort move) var et = PersonalTable.BDSP; var sf = et.GetFormEntry(Species, Form); var species = sf.HatchSpecies; - var baseEgg = Legal.EggMovesBDSP[species].Moves; + var baseEgg = LearnSource8BDSP.Instance.GetEggMoves(species, 0); if (baseEgg.Length == 0) return move == 0; - return Array.IndexOf(baseEgg, move) >= 0; + return baseEgg.Contains(move); } public bool GetBaseEggMove(out ushort move) @@ -52,7 +52,7 @@ public bool GetBaseEggMove(out ushort move) var et = PersonalTable.BDSP; var sf = et.GetFormEntry(Species, Form); var species = sf.HatchSpecies; - var baseEgg = Legal.EggMovesBDSP[species].Moves; + var baseEgg = LearnSource8BDSP.Instance.GetEggMoves(species, 0); if (baseEgg.Length == 0) { move = 0; diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot7GO.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot7GO.cs index e4d3b0528..df375f1b2 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot7GO.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot7GO.cs @@ -50,7 +50,8 @@ protected override void SetPINGA(PKM pk, EncounterCriteria criteria) protected override void SetEncounterMoves(PKM pk, GameVersion version, int level) { Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, pk, level, GameVersion.GG); + var source = GameData.GetLearnSource(GameVersion.GG); + source.SetEncounterMoves(Species, Form, level, moves); pk.SetMoves(moves); pk.SetMaximumPPCurrent(moves); } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot8GO.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot8GO.cs index 744388407..a4b18d5d9 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot8GO.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot/GO/EncounterSlot8GO.cs @@ -139,7 +139,11 @@ protected override void SetEncounterMoves(PKM pk, GameVersion version, int level pk.SetMaximumPPCurrent(moves); } - public void GetInitialMoves(int level, Span moves) => MoveLevelUp.GetEncounterMoves(moves, Species, Form, level, OriginGroup); + public void GetInitialMoves(int level, Span moves) + { + var source = GameData.GetLearnSource(OriginGroup); + source.SetEncounterMoves(Species, Form, level, moves); + } public override EncounterMatchRating GetMatchRating(PKM pk) { diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs index 79f1d68b9..d5af4a6de 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs @@ -161,7 +161,8 @@ protected virtual void SetEncounterMoves(PKM pk, GameVersion version, int level) else { Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, pk, level, version); + var source = GameData.GetLearnSource(version); + source.SetEncounterMoves(Species, Form, level, moves); pk.SetMoves(moves); pk.SetMaximumPPCurrent(moves); } diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs index 882af64f3..706aaa49e 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs @@ -11,7 +11,7 @@ public sealed record EncounterStatic7(GameVersion Version) : EncounterStatic(Ver public Moveset Relearn { get; init; } public bool IsTotem => FormInfo.IsTotemForm(Species, Form); - public bool IsTotemNoTransfer => Legal.Totem_NoTransfer.Contains(Species); + public bool IsTotemNoTransfer => Species is (int)Core.Species.Marowak or (int)Core.Species.Araquanid or (int)Core.Species.Togedemaru or (int)Core.Species.Ribombee; public int GetTotemBaseForm() => FormInfo.GetTotemBaseForm(Species, Form); public bool IsRandomUnspecificForm => Form >= FormDynamic; diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8a.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8a.cs index 00f6e3356..8fc8d6bbc 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8a.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic8a.cs @@ -135,13 +135,11 @@ public bool IsForcedMasteryCorrect(PKM pk) const bool allowAlphaPurchaseBug = true; // Everything else Alpha is pre-1.1 var level = pk.Met_Level; - var index = PersonalTable.LA.GetFormIndex(Species, Form); - var learn = Legal.LevelUpLA[index]; + var (learn, mastery) = GetLevelUpInfo(); if (!p.IsValidPurchasedEncounter(learn, level, alpha, allowAlphaPurchaseBug)) return false; Span moves = stackalloc ushort[4]; - var mastery = Legal.MasteryLA[index]; if (Moves.HasMoves) Moves.CopyTo(moves); else @@ -165,10 +163,7 @@ protected override void SetEncounterMoves(PKM pk, GameVersion version, int level public (Learnset Learn, Learnset Mastery) GetLevelUpInfo() { - var index = PersonalTable.LA.GetFormIndex(Species, Form); - var learn = Legal.LevelUpLA[index]; - var mastery = Legal.MasteryLA[index]; - return (learn, mastery); + return LearnSource8LA.GetLearnsetAndMastery(Species, Form); } public void LoadInitialMoveset(PA8 pa8, Span moves, Learnset learn, int level) diff --git a/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs b/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs index b0613a7e5..13542ada4 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs @@ -166,7 +166,8 @@ private void SetMoves(PKM pk, GameVersion version, int level) else { Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, pk, level, version); + var source = GameData.GetLearnSource(version); + source.SetEncounterMoves(Species, Form, level, moves); pk.SetMoves(moves); pk.SetMaximumPPCurrent(moves); } diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs index 0534ef3af..b697588f5 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterFinder.cs @@ -174,7 +174,7 @@ private static string GetHintWhyNotFound(PKM pk, int gen) private static bool WasGiftEgg(PKM pk, int gen, ushort loc) => !pk.FatefulEncounter && gen switch { 3 => pk.IsEgg && (byte)pk.Met_Location == 253, // Gift Egg, indistinguishable from normal eggs after hatch - 4 => Legal.GiftEggLocation4.Contains(loc) || (pk.Format != 4 && (loc == Locations.Faraway4 && pk.HGSS)), + 4 => (uint)(loc - 2009) <= (2014 - 2009) || (pk.Format != 4 && (loc == Locations.Faraway4 && pk.HGSS)), 5 => loc is Locations.Breeder5, _ => loc is Locations.Breeder6, }; diff --git a/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs index f9d93a5cb..84e0c7cc4 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/Moveset/EncounterMovesetGenerator.cs @@ -302,7 +302,8 @@ private static IEnumerable GetEggs(PKM pk, ushort[] needs, EvoCr continue; } - var eggMoves = MoveEgg.GetEggMoves(egg.Species, egg.Form, egg.Version, egg.Generation); + var source = GameData.GetLearnSource(egg.Version); + var eggMoves = source.GetEggMoves(egg.Species, egg.Form); int flags = Moveset.BitOverlap(eggMoves, needs); var vt = Array.IndexOf(needs, (ushort)Move.VoltTackle); if (vt != -1 && egg is EncounterEgg { CanHaveVoltTackle: true }) @@ -463,7 +464,8 @@ private static int GetMoveMaskConsiderGen2(ReadOnlySpan needs, IEncounte private static int GetMoveMaskGen2(ReadOnlySpan needs, IEncounterTemplate enc) { Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, enc.Species, 0, enc.LevelMin, enc.Version); + var source = GameData.GetLearnSource(enc.Version); + source.SetEncounterMoves(enc.Species, 0, enc.LevelMin, moves); return Moveset.BitOverlap(moves, needs); } diff --git a/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs b/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs index 764a5a0e6..20f9de9d3 100644 --- a/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs +++ b/PKHeX.Core/Legality/Encounters/Information/EncounterSuggestion.cs @@ -107,7 +107,7 @@ public static int GetSuggestedTransferLocation(PKM pk) if (pk.Format == 4) // Pal Park return Locations.Transfer3; if (pk.Format >= 5) // Transporter - return Legal.GetTransfer45MetLocation(pk); + return PK5.GetTransferMetLocation4(pk); return -1; } diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation3.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation3.cs new file mode 100644 index 000000000..56e8183b8 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation3.cs @@ -0,0 +1,67 @@ +using System; +using static PKHeX.Core.GameVersion; + +namespace PKHeX.Core; + +public static class EggHatchLocation3 +{ + private const byte MaskRS = 1 << 0; // 1 + private const byte MaskE = 1 << 1; // 2 + private const byte MaskFRLG = 1 << 2; // 4 + private const byte MaskAll = MaskRS | MaskE | MaskFRLG; // 7 + + public static bool IsValidMet3(int location, GameVersion game) => game switch + { + R or S => IsValidMet3RS(location), + E => IsValidMet3E(location), + FR or LG => IsValidMet3FRLG(location), + _ => false, + }; + + public static bool IsValidMet3RS(int location) => HasLocationFlag(LocationPermitted3, MaskRS, location); + public static bool IsValidMet3E(int location) => HasLocationFlag(LocationPermitted3, MaskE, location); + public static bool IsValidMet3FRLG(int location) => HasLocationFlag(LocationPermitted3, MaskFRLG, location); + public static bool IsValidMet3Any(int location) => HasLocationFlag(LocationPermitted3, MaskAll, location); + + private static bool HasLocationFlag(ReadOnlySpan arr, byte mask, int location) + { + if ((uint)location >= arr.Length) + return false; + var flags = arr[location]; + return (flags & mask) != 0; + } + + // 064 is an unused location for Meteor Falls + // 084 is Inside of a truck, no possible pokemon can be hatched there + // 071 is Mirage island, cannot be obtained as the player is technically still on Route 130's map. + // 075 is an unused location for Fiery Path + // 077 is an unused location for Jagged Pass + + // 155 - 158 Sevii Isle 6-9 Unused + // 171 - 173 Sevii Isle 22-24 Unused + private static ReadOnlySpan LocationPermitted3 => new byte[] + { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, + 3, 0, 3, 3, 3, 0, 3, 0, 3, 3, + 3, 3, 3, 3, 0, 3, 3, 7, 4, 4, // 87 = all + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 0, 0, 0, 0, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 0, 0, 0, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 6, 2, 2, 2, // 196 = fr/lg & e + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation4.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation4.cs new file mode 100644 index 000000000..e011e537c --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation4.cs @@ -0,0 +1,61 @@ +using System; +using static PKHeX.Core.GameVersion; + +namespace PKHeX.Core; + +public static class EggHatchLocation4 +{ + private const byte MaskDP = 1 << 0; // 1 + private const byte MaskPt = 1 << 1; // 2 + private const byte MaskHGSS = 1 << 2; // 4 + private const byte MaskAll4 = MaskDP | MaskPt | MaskHGSS; // 7 + + public static bool IsValidMet4(int location, GameVersion game) => game switch + { + D or P => IsValidMet4DP(location), + Pt => IsValidMet4Pt(location), + HG or SS => IsValidMet4HGSS(location), + _ => false, + }; + + public static bool IsValidMet4DP(int location) => HasLocationFlag(LocationPermitted4, MaskDP, location); + public static bool IsValidMet4Pt(int location) => HasLocationFlag(LocationPermitted4, MaskPt, location); + public static bool IsValidMet4HGSS(int location) => HasLocationFlag(LocationPermitted4, MaskHGSS, location); + public static bool IsValidMet4Any(int location) => HasLocationFlag(LocationPermitted4, MaskAll4, location); + + private static bool HasLocationFlag(ReadOnlySpan arr, byte mask, int location) + { + if ((uint)location >= arr.Length) + return false; + var flags = arr[location]; + return (flags & mask) != 0; + } + + private static ReadOnlySpan LocationPermitted4 => new byte[] + { + 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, + 7, 3, 3, 3, 3, 2, 0, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 6, 6, 6, 6, 6, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 0, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 0, 4, + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation5.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation5.cs new file mode 100644 index 000000000..67abd666c --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation5.cs @@ -0,0 +1,58 @@ +using System; +using static PKHeX.Core.GameVersion; + +namespace PKHeX.Core; + +public static class EggHatchLocation5 +{ + private const byte MaskWhite = 1 << 0; // 1 + private const byte MaskBlack = 1 << 1; // 2 + private const byte MaskWhite2 = 1 << 2; // 4 + private const byte MaskBlack2 = 1 << 3; // 8 + + public static bool IsValidMet5(int location, GameVersion game) + { + var shift = (uint)((int)game - (int)W); + if (shift >= 4) + return false; + + var mask = (byte)(1 << (int)shift); + return HasLocationFlag(LocationPermitted5, mask, location); + } + + public static bool IsValidMet5W(int location) => HasLocationFlag(LocationPermitted5, MaskWhite, location); + public static bool IsValidMet5B(int location) => HasLocationFlag(LocationPermitted5, MaskBlack, location); + public static bool IsValidMet5W2(int location) => HasLocationFlag(LocationPermitted5, MaskWhite2, location); + public static bool IsValidMet5B2(int location) => HasLocationFlag(LocationPermitted5, MaskBlack2, location); + + private static bool HasLocationFlag(ReadOnlySpan arr, byte mask, int location) + { + if ((uint)location >= arr.Length) + return false; + var flags = arr[location]; + return (flags & mask) != 0; + } + + // Two game-specific locations we need to double check for. + // White / White2 cannot access Black Gate (112) + // Black / Black2 cannot access White Gate (113) + private static ReadOnlySpan LocationPermitted5 => new byte[] + { + 00, 00, 00, 00, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 03, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 03, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 03, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 03, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 15, 15, 10, 05, 15, 15, 15, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 00, 12, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation6.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation6.cs new file mode 100644 index 000000000..6d64c08b9 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation6.cs @@ -0,0 +1,30 @@ +namespace PKHeX.Core; + +public static class EggHatchLocation6 +{ + public static bool IsValidMet6XY(int location) + { + const int min = 6; + const int max = 168; + var delta = location - min; + if ((uint)delta >= max - min) + return false; + + if (location % 2 != 0) + return false; // All locations are even + return location != 80; // unused + } + + public static bool IsValidMet6AO(int location) + { + const int min = 170; + const int max = 354; + var delta = location - min; + if ((uint)delta >= max - min) + return false; + + if (location % 2 != 0) + return false; // All locations are even + return location != 348; // unused + } +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation7.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation7.cs new file mode 100644 index 000000000..cfeea48b5 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation7.cs @@ -0,0 +1,59 @@ +using System; + +namespace PKHeX.Core; + +public static class EggHatchLocation7 +{ + private const byte MaskSM = 1 << 0; // 1 + private const byte MaskUSUM = 1 << 1; // 2 + + public static bool IsValidMet7SM(int location) + { + if (HasLocationFlag(LocationPermitted7, MaskSM, location)) + return true; + return location == Locations.Pelago7; // 30016 + } + + public static bool IsValidMet7USUM(int location) + { + if (HasLocationFlag(LocationPermitted7, MaskUSUM, location)) + return true; + return location == Locations.Pelago7; // 30016 + } + + private static bool HasLocationFlag(ReadOnlySpan arr, byte mask, int location) + { + if ((uint)location >= arr.Length) + return false; + var flags = arr[location]; + return (flags & mask) != 0; + } + + private static ReadOnlySpan LocationPermitted7 => new byte[] + { + 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, // 000 + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 0, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 0, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, // 100 + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 0, 0, 0, 0, 2, 0, + 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, // 200 + 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, + 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, + 2, 0, 2, + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8.cs new file mode 100644 index 000000000..980505372 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8.cs @@ -0,0 +1,36 @@ +using System; + +namespace PKHeX.Core; + +public static class EggHatchLocation8 +{ + public static bool IsValidMet8SWSH(int location) + { + if (location % 2 != 0) + return false; + + var index = location >> 1; + var arr = LocationPermitted8; + if ((uint)index >= arr.Length) + return false; + return arr[index] != 0; + } + + // Odd indexes ignored. + private static ReadOnlySpan LocationPermitted8 => new byte[] + { + 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, + 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, + 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8b.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8b.cs new file mode 100644 index 000000000..00d163059 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation8b.cs @@ -0,0 +1,87 @@ +using System; + +namespace PKHeX.Core; + +public static class EggHatchLocation8b +{ + private const byte MaskBD = 1 << 0; // 1 + private const byte MaskSP = 1 << 1; // 2 + + public static bool IsValidMet8BD(int location) + { + if (HasLocationFlag(LocationPermitted8b, MaskBD, location)) + return true; + return location == Locations.Pelago7; // 30016 + } + + public static bool IsValidMet8SP(int location) + { + if (HasLocationFlag(LocationPermitted8b, MaskSP, location)) + return true; + return location == Locations.Pelago7; // 30016 + } + + private static bool HasLocationFlag(ReadOnlySpan arr, byte mask, int location) + { + if ((uint)location >= arr.Length) + return false; + var flags = arr[location]; + return (flags & mask) != 0; + } + + // BD Exclusive + // 216, // Spear Pillar + // 218, // Hall of Origin + // 498, // Ramanas Park (Johto Room) + // 503, // Ramanas Park (Rainbow Room) + // 650, // Ramanas Park (Johto Room) + // 655, // Ramanas Park (Rainbow Room) + + // SP Exclusive + // 217, // Spear Pillar + // 497, // Ramanas Park (Kanto Room) + // 504, // Ramanas Park (Squall Room) + // 618, // Hall of Origin + // 649, // Ramanas Park (Kanto Room) + // 656, // Ramanas Park (Squall Room) + + // Unobtainable + // 094, 103, 107, // Hearthome City + // 154, 155, 158, // Sunyshore City + // 181, 182, 183, // Pokémon League + // 329, // Lake Acuity + // 337, 338, // Battle Park + // 339, 340, 341, 342, 343, 344, // Battle Tower + // 345, 353, 421, // Mystery Zone + // 474, // Resort Area + // 483, 484, // Mystery Zone + // 491, 492, 493, // Mystery Zone + // 495, // Ramanas Park + // 620, 621, 622, 623, // Grand Underground (Secret Base) + // 625, // Sea (sailing animation) + // 627, 628, 629, 630, 631, 632, // Grand Underground (Secret Base) + // 633, 634, 635, 636, 637, 638, // Grand Underground (Secret Base) + // 639, 640, 641, 642, 643, 644, // Grand Underground (Secret Base) + // 645, 646, 647, // Grand Underground (Secret Base) + + private static ReadOnlySpan LocationPermitted8b => new byte[] + { + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 0, 1, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 3, 3, 0, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 3, 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 1, 3, 1, 3, 0, 3, 3, 3, 3, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 0, 3, 3, 3, 3, 3, + 3, 3, 3, 0, 0, 3, 3, 3, 3, 3, 3, 0, 0, 0, 3, 0, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 3, 0, 0, 0, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 3, 2, 3, 3, 3, 3, 3, 3, 2, 3, + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation9.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation9.cs new file mode 100644 index 000000000..6a51d3356 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EggHatchLocation9.cs @@ -0,0 +1,39 @@ +using System; + +namespace PKHeX.Core; + +public static class EggHatchLocation9 +{ + private const byte MaskScarlet = 1 << 0; // 1 + private const byte MaskViolet = 1 << 1; // 2 + public static bool IsValidMet9SL(int location) => HasLocationFlag(LocationPermitted9, MaskScarlet, location); + public static bool IsValidMet9VL(int location) => HasLocationFlag(LocationPermitted9, MaskViolet, location); + + private static bool HasLocationFlag(ReadOnlySpan arr, byte mask, int location) + { + if ((uint)location >= arr.Length) + return false; + var flags = arr[location]; + return (flags & mask) != 0; + } + + // 130 Naranja Academy does not exist in Violet + // 131 Uva Academy does not exist in Scarlet + private static ReadOnlySpan LocationPermitted9 => new byte[] + { + 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 0, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 0, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 0, 3, 0, 3, + 3, 0, 3, 0, 0, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 3, 0, 0, 3, + 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, + 0, 3, 0, 3, 0, 3, 0, 3, 3, 0, + 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, + 1, 2, + }; +} diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs index f059c9353..51e8be4b1 100644 --- a/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using static PKHeX.Core.LegalityCheckStrings; namespace PKHeX.Core; @@ -27,21 +26,21 @@ public static class EncounterVerifier EncounterSlot w => VerifyEncounterWild(w), EncounterStatic s => VerifyEncounterStatic(pk, s), MysteryGift g => VerifyEncounterEvent(pk, g), - _ => new CheckResult(Severity.Invalid, LEncInvalid, CheckIdentifier.Encounter), + _ => GetInvalid(LEncInvalid), }; private static CheckResult VerifyEncounterG12(PKM pk, IEncounterTemplate enc) { if (enc.EggEncounter) - return VerifyEncounterEgg(pk, enc.Generation); + return VerifyEncounterEgg(pk, 2); return enc switch { - EncounterSlot1 => new CheckResult(Severity.Valid, LEncCondition, CheckIdentifier.Encounter), + EncounterSlot1 => GetValid(LEncCondition), EncounterSlot2 s2 => VerifyWildEncounterGen2(pk, s2), EncounterStatic s => VerifyEncounterStatic(pk, s), EncounterTrade t => VerifyEncounterTrade(pk, t), - _ => new CheckResult(Severity.Invalid, LEncInvalid, CheckIdentifier.Encounter), + _ => GetInvalid(LEncInvalid), }; } @@ -57,21 +56,21 @@ private static CheckResult VerifyWildEncounterGen2(PKM pk, EncounterSlot2 encoun switch (encounter.Location) { case 19: // National Park - return new CheckResult(Severity.Invalid, LG2InvalidTilePark, CheckIdentifier.Encounter); + return GetInvalid(LG2InvalidTilePark); case 76: // Route 14 - return new CheckResult(Severity.Invalid, LG2InvalidTileR14, CheckIdentifier.Encounter); + return GetInvalid(LG2InvalidTileR14); } break; } - return new CheckResult(Severity.Valid, LEncCondition, CheckIdentifier.Encounter); + return GetValid(LEncCondition); } private static CheckResult VerifyWildEncounterCrystalHeadbutt(ITrainerID32 tr, EncounterSlot2 s2) { return s2.IsTreeAvailable(tr.TID16) - ? new CheckResult(Severity.Valid, LG2TreeID, CheckIdentifier.Encounter) - : new CheckResult(Severity.Invalid, LG2InvalidTileTreeNotFound, CheckIdentifier.Encounter); + ? GetValid(LG2TreeID) + : GetInvalid(LG2InvalidTileTreeNotFound); } // Eggs @@ -86,20 +85,20 @@ private static CheckResult VerifyWildEncounterCrystalHeadbutt(ITrainerID32 tr, E 8 when GameVersion.BDSP.Contains((GameVersion)pk.Version) => pk.IsEgg ? VerifyUnhatchedEgg(pk, Locations.LinkTrade6NPC, Locations.Default8bNone) : VerifyEncounterEgg8BDSP(pk), 8 => pk.IsEgg ? VerifyUnhatchedEgg(pk, Locations.LinkTrade6) : VerifyEncounterEgg8(pk), 9 => pk.IsEgg ? VerifyUnhatchedEgg(pk, Locations.LinkTrade6) : VerifyEncounterEgg9(pk), - _ => new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter), + _ => GetInvalid(LEggLocationInvalid), }; private static CheckResult VerifyUnhatchedEgg3(PKM pk) { if (pk.Met_Level != 0) - return new CheckResult(Severity.Invalid, string.Format(LEggFMetLevel_0, 0), CheckIdentifier.Encounter); + return GetInvalid(string.Format(LEggFMetLevel_0, 0)); // Only EncounterEgg should reach here. var loc = pk.FRLG ? Locations.HatchLocationFRLG : Locations.HatchLocationRSE; if (pk.Met_Location != loc) - return new CheckResult(Severity.Invalid, LEggMetLocationFail, CheckIdentifier.Encounter); + return GetInvalid(LEggMetLocationFail); - return new CheckResult(Severity.Valid, LEggLocation, CheckIdentifier.Encounter); + return GetValid(LEggLocation); } private static CheckResult VerifyEncounterEgg3(PKM pk) @@ -108,172 +107,192 @@ private static CheckResult VerifyEncounterEgg3(PKM pk) return VerifyEncounterEgg3Transfer(pk); if (pk.Met_Level != 0) - return new CheckResult(Severity.Invalid, string.Format(LEggFMetLevel_0, 0), CheckIdentifier.Encounter); + return GetInvalid(string.Format(LEggFMetLevel_0, 0)); // Check the origin game list. var met = (byte)pk.Met_Location; - var locs = pk.FRLG ? Legal.ValidMet_FRLG : pk.E ? Legal.ValidMet_E : Legal.ValidMet_RS; - if (locs.Contains(met)) - return new CheckResult(Severity.Valid, LEggLocation, CheckIdentifier.Encounter); + bool valid = EggHatchLocation3.IsValidMet3(met, (GameVersion)pk.Version); + if (valid) + return GetValid(LEggLocation); // Version isn't updated when hatching on a different game. Check any game. - if (Legal.ValidMet_FRLG.Contains(met) || Legal.ValidMet_E.Contains(met) || Legal.ValidMet_RS.Contains(met)) - return new CheckResult(Severity.Valid, LEggLocationTrade, CheckIdentifier.Encounter); - return new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter); + if (EggHatchLocation3.IsValidMet3Any(met)) + return GetValid(LEggLocationTrade); + return GetInvalid(LEggLocationInvalid); } + private static CheckResult GetInvalid(string message, CheckIdentifier ident = CheckIdentifier.Encounter) => new(Severity.Invalid, message, ident); + private static CheckResult GetValid(string message) => new(Severity.Valid, message, CheckIdentifier.Encounter); + private static CheckResult VerifyEncounterEgg3Transfer(PKM pk) { if (pk.IsEgg) - return new CheckResult(Severity.Invalid, LTransferEgg, CheckIdentifier.Encounter); + return GetInvalid(LTransferEgg); if (pk.Met_Level < 5) - return new CheckResult(Severity.Invalid, LTransferEggMetLevel, CheckIdentifier.Encounter); + return GetInvalid(LTransferEggMetLevel); var expectEgg = pk is PB8 ? Locations.Default8bNone : 0; if (pk.Egg_Location != expectEgg) - return new CheckResult(Severity.Invalid, LEggLocationNone, CheckIdentifier.Encounter); + return GetInvalid(LEggLocationNone); if (pk.Format != 4) { if (pk.Met_Location != Locations.Transfer4) - return new CheckResult(Severity.Invalid, LTransferEggLocationTransporter, CheckIdentifier.Encounter); + return GetInvalid(LTransferEggLocationTransporter); } else { if (pk.Met_Location != Locations.Transfer3) - return new CheckResult(Severity.Invalid, LEggLocationPalPark, CheckIdentifier.Encounter); + return GetInvalid(LEggLocationPalPark); } - return new CheckResult(Severity.Valid, LEggLocation, CheckIdentifier.Encounter); + return GetValid(LEggLocation); } private static CheckResult VerifyEncounterEgg4(PKM pk) { - if (pk.Format == 4) + if (pk.Format != 4) // transferred { - // Traded eggs don't update Version, like in future games. - var locations = pk.WasTradedEgg ? Legal.ValidMet_4 : - pk.HGSS ? Legal.ValidMet_HGSS : - pk.Pt ? Legal.ValidMet_Pt : - Legal.ValidMet_DP; - return VerifyEncounterEggLevelLoc(pk, 0, locations); + if (pk.IsEgg) + return GetInvalid(LTransferEgg); + if (pk.Met_Level < 1) + return GetInvalid(LTransferEggMetLevel); + if (pk.Met_Location != Locations.Transfer4) + return GetInvalid(LTransferEggLocationTransporter); + return GetValid(LEggLocation); } - if (pk.IsEgg) - return new CheckResult(Severity.Invalid, LTransferEgg, CheckIdentifier.Encounter); - // transferred - if (pk.Met_Level < 1) - return new CheckResult(Severity.Invalid, LTransferEggMetLevel, CheckIdentifier.Encounter); - if (pk.Met_Location != Locations.Transfer4) - return new CheckResult(Severity.Invalid, LTransferEggLocationTransporter, CheckIdentifier.Encounter); - return new CheckResult(Severity.Valid, LEggLocation, CheckIdentifier.Encounter); + // Native + const byte level = 0; + if (pk.Met_Level != level) + return GetInvalid(string.Format(LEggFMetLevel_0, level)); + + var met = (ushort)pk.Met_Location; + bool valid = EggHatchLocation4.IsValidMet4(met, (GameVersion)pk.Version); + if (valid) + return GetValid(LEggLocation); + + // Version isn't updated when hatching on a different game. Check any game. + if (EggHatchLocation4.IsValidMet4Any(met)) + return GetValid(LEggLocationTrade); + return GetInvalid(LEggLocationInvalid); } private static CheckResult VerifyEncounterEgg5(PKM pk) { - // Two game-specific locations we need to double check for. - // White / White2 cannot access Black Gate (112) - // Black / Black2 cannot access White Gate (113) - var met = pk.Met_Location; - var delta = (uint)(met - 112); - if (delta <= 1) - { - var ver = pk.Version & 1; // W*=0, B*=1 - if (ver == delta) - return new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter); - } - return VerifyEncounterEggLevelLoc(pk, 1, pk.B2W2 ? Legal.ValidMet_B2W2 : Legal.ValidMet_BW); + const byte level = 1; + if (pk.Met_Level != level) + return GetInvalid(string.Format(LEggFMetLevel_0, level)); + + var met = (ushort)pk.Met_Location; + bool valid = EggHatchLocation5.IsValidMet5(met, (GameVersion)pk.Version); + + if (valid) + return GetValid(LEggLocation); + return GetInvalid(LEggLocationInvalid); } private static CheckResult VerifyEncounterEgg6(PKM pk) { - if (pk.AO) - return VerifyEncounterEggLevelLoc(pk, 1, Legal.ValidMet_AO); + const byte level = 1; + if (pk.Met_Level != level) + return GetInvalid(string.Format(LEggFMetLevel_0, level)); - if (pk.Egg_Location == Locations.HatchLocation6AO) // Battle Resort Daycare is only OR/AS. - return new CheckResult(Severity.Invalid, LEggMetLocationFail, CheckIdentifier.Encounter); + var met = (ushort)pk.Met_Location; + bool valid = pk.XY + ? EggHatchLocation6.IsValidMet6XY(met) + : EggHatchLocation6.IsValidMet6AO(met); - return VerifyEncounterEggLevelLoc(pk, 1, Legal.ValidMet_XY); + if (valid) + return GetValid(LEggLocation); + return GetInvalid(LEggLocationInvalid); } private static CheckResult VerifyEncounterEgg7(PKM pk) { - if (pk.SM) - return VerifyEncounterEggLevelLoc(pk, 1, Legal.ValidMet_SM); - if (pk.USUM) - return VerifyEncounterEggLevelLoc(pk, 1, Legal.ValidMet_USUM); + const byte level = 1; + if (pk.Met_Level != level) + return GetInvalid(string.Format(LEggFMetLevel_0, level)); - // no other games - return new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter); + var met = (ushort)pk.Met_Location; + bool valid = pk.SM + ? EggHatchLocation7.IsValidMet7SM(met) + : EggHatchLocation7.IsValidMet7USUM(met); + + if (valid) + return GetValid(LEggLocation); + return GetInvalid(LEggLocationInvalid); } private static CheckResult VerifyEncounterEgg8(PKM pk) { - if (pk.SWSH) - { - if (pk.BDSP) - return VerifyEncounterEggLevelLoc(pk, 1, (location, game) => location == (game == GameVersion.SW ? Locations.HOME_SWBD : Locations.HOME_SHSP)); - return VerifyEncounterEggLevelLoc(pk, 1, Legal.ValidMet_SWSH); - } + const byte level = 1; + if (pk.Met_Level != level) + return GetInvalid(string.Format(LEggFMetLevel_0, level)); - // no other games - return new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter); - } + var met = (ushort)pk.Met_Location; + bool valid = pk.BDSP // Transferred from BD/SP, now acting like a SW/SH egg. + ? Locations.IsValidMetBDSP(met, pk.Version) + : EggHatchLocation8.IsValidMet8SWSH(met); - private static CheckResult VerifyEncounterEgg9(PKM pk) - { - if (pk.SV) - return VerifyEncounterEggLevelLoc(pk, 1, Legal.IsValidEggHatchLocation9); - - // no other games - return new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter); + if (valid) + return GetValid(LEggLocation); + return GetInvalid(LEggLocationInvalid); } private static CheckResult VerifyEncounterEgg8BDSP(PKM pk) { - if (pk.BDSP) - return VerifyEncounterEggLevelLoc(pk, 1, Legal.IsValidEggHatchLocation8b); + const byte level = 1; + if (pk.Met_Level != level) + return GetInvalid(string.Format(LEggFMetLevel_0, level)); - // no other games - return new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter); + var met = (ushort)pk.Met_Location; + bool valid = pk.Version == (int)GameVersion.BD + ? EggHatchLocation8b.IsValidMet8BD(met) + : EggHatchLocation8b.IsValidMet8SP(met); + + if (valid) + return GetValid(LEggLocation); + return GetInvalid(LEggLocationInvalid); } - private static CheckResult VerifyEncounterEggLevelLoc(PKM pk, int eggLevel, IReadOnlySet MetLocations) + private static CheckResult VerifyEncounterEgg9(PKM pk) { - return VerifyEncounterEggLevelLoc(pk, eggLevel, (location, _) => MetLocations.Contains(location)); - } + const byte level = 1; + if (pk.Met_Level != level) + return GetInvalid(string.Format(LEggFMetLevel_0, level)); - // (hatch location, hatch version, bool result) - private static CheckResult VerifyEncounterEggLevelLoc(PKM pk, int eggLevel, Func isValid) - { - if (pk.Met_Level != eggLevel) - return new CheckResult(Severity.Invalid, string.Format(LEggFMetLevel_0, eggLevel), CheckIdentifier.Encounter); - return isValid((ushort)pk.Met_Location, (GameVersion)pk.Version) - ? new CheckResult(Severity.Valid, LEggLocation, CheckIdentifier.Encounter) - : new CheckResult(Severity.Invalid, LEggLocationInvalid, CheckIdentifier.Encounter); + var met = (ushort)pk.Met_Location; + bool valid = pk.Version == (int)GameVersion.SL + ? EggHatchLocation9.IsValidMet9SL(met) + : EggHatchLocation9.IsValidMet9VL(met); + + if (valid) + return GetValid(LEggLocation); + return GetInvalid(LEggLocationInvalid); } private static CheckResult VerifyUnhatchedEgg(PKM pk, int tradeLoc, int noneLoc = 0) { var eggLevel = pk.Format < 5 ? 0 : 1; if (pk.Met_Level != eggLevel) - return new CheckResult(Severity.Invalid, string.Format(LEggFMetLevel_0, eggLevel), CheckIdentifier.Encounter); + return GetInvalid(string.Format(LEggFMetLevel_0, eggLevel)); if (pk.Egg_Location == tradeLoc) - return new CheckResult(Severity.Invalid, LEggLocationTradeFail, CheckIdentifier.Encounter); + return GetInvalid(LEggLocationTradeFail); var met = pk.Met_Location; if (met == tradeLoc) - return new CheckResult(Severity.Valid, LEggLocationTrade, CheckIdentifier.Encounter); + return GetValid(LEggLocationTrade); return met == noneLoc - ? new CheckResult(Severity.Valid, LEggUnhatched, CheckIdentifier.Encounter) - : new CheckResult(Severity.Invalid, LEggLocationNone, CheckIdentifier.Encounter); + ? GetValid(LEggUnhatched) + : GetInvalid(LEggLocationNone); } // Other private static CheckResult VerifyEncounterWild(EncounterSlot slot) { var summary = slot.GetConditionString(out bool valid); - return new CheckResult(valid ? Severity.Valid : Severity.Invalid, summary, CheckIdentifier.Encounter); + return valid ? GetValid(summary) : GetInvalid(summary); } private static CheckResult VerifyEncounterStatic(PKM pk, EncounterStatic s) @@ -283,24 +302,24 @@ private static CheckResult VerifyEncounterStatic(PKM pk, EncounterStatic s) { case 3: if (s is EncounterStaticShadow {EReader: true} && pk.Language != (int)LanguageID.Japanese) // Non-JP E-reader Pokemon - return new CheckResult(Severity.Invalid, LG3EReader, CheckIdentifier.Encounter); + return GetInvalid(LG3EReader); switch (s.Species) { case (int)Species.Mew when s.Location == 201 && pk.Language != (int)LanguageID.Japanese: // Non-JP Mew (Old Sea Map) - return new CheckResult(Severity.Invalid, LEncUnreleasedEMewJP, CheckIdentifier.Encounter); + return GetInvalid(LEncUnreleasedEMewJP); case (int)Species.Deoxys when s.Location == 200 && pk.Language == (int)LanguageID.Japanese: // JP Deoxys (Birth Island) - return new CheckResult(Severity.Invalid, LEncUnreleased, CheckIdentifier.Encounter); + return GetInvalid(LEncUnreleased); } break; case 4: if (s is EncounterStatic4 {Roaming: true} && pk.Met_Location == 193 && pk is IGroundTile {GroundTile:GroundTileType.Water}) // Roaming pokemon surfing in Johto Route 45 - return new CheckResult(Severity.Invalid, LG4InvalidTileR45Surf, CheckIdentifier.Encounter); + return GetInvalid(LG4InvalidTileR45Surf); break; case 7: if (s.EggLocation == Locations.Daycare5 && pk.RelearnMove1 != 0) // Eevee gift egg - return new CheckResult(Severity.Invalid, LEncStaticRelearn, CheckIdentifier.RelearnMove); // not gift egg + return GetInvalid(LEncStaticRelearn, CheckIdentifier.RelearnMove); // not gift egg break; } if (s.EggEncounter && !pk.IsEgg) // hatched @@ -310,7 +329,7 @@ private static CheckResult VerifyEncounterStatic(PKM pk, EncounterStatic s) return hatchCheck; } - return new CheckResult(Severity.Valid, LEncStaticMatch, CheckIdentifier.Encounter); + return GetValid(LEncStaticMatch); } private static CheckResult VerifyEncounterTrade(ISpeciesForm pk, EncounterTrade trade) @@ -323,9 +342,9 @@ private static CheckResult VerifyEncounterTrade(ISpeciesForm pk, EncounterTrade var names = ParseSettings.SpeciesStrings; var evolved = names[species + 1]; var unevolved = names[species]; - return new CheckResult(Severity.Invalid, string.Format(LEvoTradeReq, unevolved, evolved), CheckIdentifier.Encounter); + return GetInvalid(string.Format(LEvoTradeReq, unevolved, evolved)); } - return new CheckResult(Severity.Valid, LEncTradeMatch, CheckIdentifier.Encounter); + return GetValid(LEncTradeMatch); } private static CheckResult VerifyEncounterEvent(PKM pk, MysteryGift gift) @@ -334,7 +353,7 @@ private static CheckResult VerifyEncounterEvent(PKM pk, MysteryGift gift) { case PCD pcd: if (!pcd.CanBeReceivedByVersion(pk.Version) && pcd.Gift.PK.Version == 0) - return new CheckResult(Severity.Invalid, string.Format(L_XMatches0_1, gift.CardHeader, $"-- {LEncGiftVersionNotDistributed}"), CheckIdentifier.Encounter); + return GetInvalid(string.Format(L_XMatches0_1, gift.CardHeader, $"-- {LEncGiftVersionNotDistributed}")); break; } if (!pk.IsEgg && gift.IsEgg) // hatched @@ -345,6 +364,6 @@ private static CheckResult VerifyEncounterEvent(PKM pk, MysteryGift gift) } // Strict matching already performed by EncounterGenerator. May be worth moving some checks here to better flag invalid gifts. - return new CheckResult(Severity.Valid, string.Format(L_XMatches0_1, gift.CardHeader, string.Empty), CheckIdentifier.Encounter); + return GetValid(string.Format(L_XMatches0_1, gift.CardHeader, string.Empty)); } } diff --git a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs index a64277584..56dd26170 100644 --- a/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs +++ b/PKHeX.Core/Legality/LearnSource/Group/LearnGroup1.cs @@ -153,10 +153,10 @@ private static bool HasDefinitelyVisitedGen2(PK1 pk1) private static void GetEncounterMoves(IEncounterTemplate enc, Span moves) { - if (enc.Version is GameVersion.YW or GameVersion.RBY) - LearnSource1YW.Instance.GetEncounterMoves(enc, enc.LevelMin, moves); - else - LearnSource1RB.Instance.GetEncounterMoves(enc, enc.LevelMin, moves); + ILearnSource ls = enc.Version is GameVersion.YW or GameVersion.RBY + ? LearnSource1YW.Instance + : LearnSource1RB.Instance; + ls.SetEncounterMoves(enc.Species, 0, enc.LevelMin, moves); } private static void Check(Span result, ReadOnlySpan current, PKM pk, EvoCriteria evo, int stage, LearnOption option = LearnOption.Current, MoveSourceType types = MoveSourceType.All) diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1RB.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1RB.cs index 8a9e9733f..a104353ed 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1RB.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1RB.cs @@ -13,7 +13,7 @@ public sealed class LearnSource1RB : ILearnSource { public static readonly LearnSource1RB Instance = new(); private static readonly PersonalTable1 Personal = PersonalTable.RB; - private static readonly Learnset[] Learnsets = Legal.LevelUpRB; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_rb.pkl"), Legal.MaxSpeciesID_1); private const LearnEnvironment Game = RB; private const int MaxSpecies = Legal.MaxSpeciesID_1; @@ -100,9 +100,8 @@ public void GetAllMoves(Span result, PKM pk, EvoCriteria evo, MoveSourceTy } } - public void GetEncounterMoves(ISpeciesForm enc, int level, Span init) + public void SetEncounterMoves(ushort species, byte form, int level, Span init) { - var species = enc.Species; if (!TryGetPersonal(species, 0, out var personal)) return; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1YW.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1YW.cs index 088b35690..149fc4020 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1YW.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource1YW.cs @@ -13,7 +13,7 @@ public sealed class LearnSource1YW : ILearnSource { public static readonly LearnSource1YW Instance = new(); private static readonly PersonalTable1 Personal = PersonalTable.Y; - private static readonly Learnset[] Learnsets = Legal.LevelUpY; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_y.pkl"), Legal.MaxSpeciesID_1); private const LearnEnvironment Game = YW; private const int MaxSpecies = Legal.MaxSpeciesID_1; @@ -100,9 +100,8 @@ public void GetAllMoves(Span result, PKM pk, EvoCriteria evo, MoveSourceTy } } - public void GetEncounterMoves(ISpeciesForm enc, int level, Span init) + public void SetEncounterMoves(ushort species, byte form, int level, Span init) { - var species = enc.Species; if (!TryGetPersonal(species, 0, out var personal)) return; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2C.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2C.cs index 187b63262..d6bdc61aa 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2C.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2C.cs @@ -13,8 +13,8 @@ public sealed class LearnSource2C : ILearnSource, IEggSource { public static readonly LearnSource2C Instance = new(); private static readonly PersonalTable2 Personal = PersonalTable.C; - private static readonly EggMoves2[] EggMoves = Legal.EggMovesC; - private static readonly Learnset[] Learnsets = Legal.LevelUpC; + private static readonly EggMoves2[] EggMoves = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_c.pkl"), Legal.MaxSpeciesID_2); + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_c.pkl"), Legal.MaxSpeciesID_2); private const int MaxSpecies = Legal.MaxSpeciesID_2; private const LearnEnvironment Game = C; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2GS.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2GS.cs index ddb634d2f..0e67064f2 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2GS.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource2GS.cs @@ -13,8 +13,8 @@ public sealed class LearnSource2GS : ILearnSource, IEggSource { public static readonly LearnSource2GS Instance = new(); private static readonly PersonalTable2 Personal = PersonalTable.GS; - private static readonly EggMoves2[] EggMoves = Legal.EggMovesGS; - private static readonly Learnset[] Learnsets = Legal.LevelUpGS; + private static readonly EggMoves2[] EggMoves = EggMoves2.GetArray(Util.GetBinaryResource("eggmove_gs.pkl"), Legal.MaxSpeciesID_2); + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(Util.GetBinaryResource("lvlmove_gs.pkl"), Legal.MaxSpeciesID_2); private const int MaxSpecies = Legal.MaxSpeciesID_2; private const LearnEnvironment Game = GS; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3E.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3E.cs index 46a739936..2408619a2 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3E.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3E.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource3; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource3E : ILearnSource, IEggSource +public sealed class LearnSource3E : LearnSource3, ILearnSource, IEggSource { public static readonly LearnSource3E Instance = new(); private static readonly PersonalTable3 Personal = PersonalTable.E; - private static readonly Learnset[] Learnsets = Legal.LevelUpE; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesRS; // same for all Gen3 games + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_e.pkl"), "em")); private const int MaxSpecies = Legal.MaxSpeciesID_3; private const LearnEnvironment Game = E; private const int Generation = 3; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3FR.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3FR.cs index 56d6ff0e1..bcb0d10c5 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3FR.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3FR.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource3; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource3FR : ILearnSource, IEggSource +public sealed class LearnSource3FR : LearnSource3, ILearnSource, IEggSource { public static readonly LearnSource3FR Instance = new(); private static readonly PersonalTable3 Personal = PersonalTable.FR; - private static readonly Learnset[] Learnsets = Legal.LevelUpFR; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesRS; // same for all Gen3 games + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_fr.pkl"), "fr")); private const int MaxSpecies = Legal.MaxSpeciesID_3; private const LearnEnvironment Game = FR; private const int Generation = 3; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3LG.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3LG.cs index af832a8fa..e67c4a125 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3LG.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3LG.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource3; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource3LG : ILearnSource, IEggSource +public sealed class LearnSource3LG : LearnSource3, ILearnSource, IEggSource { public static readonly LearnSource3LG Instance = new(); private static readonly PersonalTable3 Personal = PersonalTable.LG; - private static readonly Learnset[] Learnsets = Legal.LevelUpLG; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesRS; // same for all Gen3 games + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_lg.pkl"), "lg")); private const int MaxSpecies = Legal.MaxSpeciesID_3; private const LearnEnvironment Game = LG; private const int Generation = 3; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3RS.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3RS.cs index 1356156bc..318ef50fa 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3RS.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource3RS.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource3; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource3RS : ILearnSource, IEggSource +public sealed class LearnSource3RS : LearnSource3, ILearnSource, IEggSource { public static readonly LearnSource3RS Instance = new(); private static readonly PersonalTable3 Personal = PersonalTable.RS; - private static readonly Learnset[] Learnsets = Legal.LevelUpRS; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesRS; // same for all Gen3 games + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_rs.pkl"), "rs")); private const int MaxSpecies = Legal.MaxSpeciesID_3; private const LearnEnvironment Game = RS; private const int Generation = 3; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4DP.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4DP.cs index ca225a5b4..49b6bf834 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4DP.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4DP.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource4; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource4DP : ILearnSource, IEggSource +public sealed class LearnSource4DP : LearnSource4, ILearnSource, IEggSource { public static readonly LearnSource4DP Instance = new(); private static readonly PersonalTable4 Personal = PersonalTable.DP; - private static readonly Learnset[] Learnsets = Legal.LevelUpDP; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesDPPt; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_dp.pkl"), "dp")); private const int MaxSpecies = Legal.MaxSpeciesID_4; private const LearnEnvironment Game = DP; private const int Generation = 4; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4HGSS.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4HGSS.cs index 26cd4ab6b..9228a0819 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4HGSS.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4HGSS.cs @@ -13,8 +13,8 @@ public sealed class LearnSource4HGSS : ILearnSource, IEggSource { public static readonly LearnSource4HGSS Instance = new(); private static readonly PersonalTable4 Personal = PersonalTable.HGSS; - private static readonly Learnset[] Learnsets = Legal.LevelUpHGSS; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesHGSS; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_hgss.pkl"), "hs")); + private static readonly EggMoves6[] EggMoves = EggMoves6.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_hgss.pkl"), "hs")); private const int MaxSpecies = Legal.MaxSpeciesID_4; private const LearnEnvironment Game = HGSS; private const int Generation = 4; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4Pt.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4Pt.cs index 958ea6718..69898a179 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4Pt.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource4Pt.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource4; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource4Pt : ILearnSource, IEggSource +public sealed class LearnSource4Pt : LearnSource4, ILearnSource, IEggSource { public static readonly LearnSource4Pt Instance = new(); private static readonly PersonalTable4 Personal = PersonalTable.Pt; - private static readonly Learnset[] Learnsets = Legal.LevelUpPt; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesDPPt; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_pt.pkl"), "pt")); private const int MaxSpecies = Legal.MaxSpeciesID_4; private const LearnEnvironment Game = Pt; private const int Generation = 4; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5B2W2.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5B2W2.cs index d1549583d..bef2f8dff 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5B2W2.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5B2W2.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource5; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource5B2W2 : ILearnSource, IEggSource +public sealed class LearnSource5B2W2 : LearnSource5, ILearnSource, IEggSource { public static readonly LearnSource5B2W2 Instance = new(); private static readonly PersonalTable5B2W2 Personal = PersonalTable.B2W2; - private static readonly Learnset[] Learnsets = Legal.LevelUpB2W2; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesBW; // same + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_b2w2.pkl"), "52")); private const int MaxSpecies = Legal.MaxSpeciesID_5; private const LearnEnvironment Game = B2W2; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5BW.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5BW.cs index 96a613ab3..b4a26243b 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5BW.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource5BW.cs @@ -2,19 +2,17 @@ using System.Diagnostics.CodeAnalysis; using static PKHeX.Core.LearnMethod; using static PKHeX.Core.LearnEnvironment; -using static PKHeX.Core.LearnSource5; namespace PKHeX.Core; /// /// Exposes information about how moves are learned in . /// -public sealed class LearnSource5BW : ILearnSource, IEggSource +public sealed class LearnSource5BW : LearnSource5, ILearnSource, IEggSource { public static readonly LearnSource5BW Instance = new(); private static readonly PersonalTable5BW Personal = PersonalTable.BW; - private static readonly Learnset[] Learnsets = Legal.LevelUpBW; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesBW; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_bw.pkl"), "51")); private const int MaxSpecies = Legal.MaxSpeciesID_5; private const LearnEnvironment Game = BW; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6AO.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6AO.cs index 713ac769d..7f1a638f7 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6AO.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6AO.cs @@ -12,8 +12,8 @@ public sealed class LearnSource6AO : ILearnSource, IEggSource { public static readonly LearnSource6AO Instance = new(); private static readonly PersonalTable6AO Personal = PersonalTable.AO; - private static readonly Learnset[] Learnsets = Legal.LevelUpAO; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesAO; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_ao.pkl"), "ao")); + private static readonly EggMoves6[] EggMoves = EggMoves6.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_ao.pkl"), "ao")); private const int MaxSpecies = Legal.MaxSpeciesID_6; private const LearnEnvironment Game = ORAS; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6XY.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6XY.cs index c0fb9157a..29f495341 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6XY.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource6XY.cs @@ -12,8 +12,8 @@ public sealed class LearnSource6XY : ILearnSource, IEggSource { public static readonly LearnSource6XY Instance = new(); private static readonly PersonalTable6XY Personal = PersonalTable.XY; - private static readonly Learnset[] Learnsets = Legal.LevelUpXY; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesXY; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_xy.pkl"), "xy")); + private static readonly EggMoves6[] EggMoves = EggMoves6.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_xy.pkl"), "xy")); private const int MaxSpecies = Legal.MaxSpeciesID_6; private const LearnEnvironment Game = XY; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7GG.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7GG.cs index 0e93b3855..349c9ccfd 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7GG.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7GG.cs @@ -12,7 +12,7 @@ public sealed class LearnSource7GG : ILearnSource { public static readonly LearnSource7GG Instance = new(); private static readonly PersonalTable7GG Personal = PersonalTable.GG; - private static readonly Learnset[] Learnsets = Legal.LevelUpGG; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_gg.pkl"), "gg")); private const int MaxSpecies = Legal.MaxSpeciesID_7b; private const LearnEnvironment Game = GG; private const int ReminderBonus = 100; // Move reminder allows re-learning ALL level up moves regardless of level. diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7SM.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7SM.cs index 92dff4f9b..0c04915ed 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7SM.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7SM.cs @@ -13,8 +13,8 @@ public sealed class LearnSource7SM : ILearnSource, IEggSource { public static readonly LearnSource7SM Instance = new(); private static readonly PersonalTable7 Personal = PersonalTable.SM; - private static readonly Learnset[] Learnsets = Legal.LevelUpSM; - private static readonly EggMoves7[] EggMoves = Legal.EggMovesSM; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_sm.pkl"), "sm")); + private static readonly EggMoves7[] EggMoves = EggMoves7.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_sm.pkl"), "sm")); private const int MaxSpecies = Legal.MaxSpeciesID_7; private const LearnEnvironment Game = SM; private const int ReminderBonus = 100; // Move reminder allows re-learning ALL level up moves regardless of level. @@ -34,15 +34,15 @@ public bool GetIsEggMove(ushort species, byte form, ushort move) { if (species > MaxSpecies) return false; - var moves = MoveEgg.GetFormEggMoves(species, form, EggMoves).AsSpan(); - return moves.IndexOf(move) != -1; + var moves = EggMoves.GetFormEggMoves(species, form); + return moves.Contains(move); } public ReadOnlySpan GetEggMoves(ushort species, byte form) { if (species > MaxSpecies) return ReadOnlySpan.Empty; - return MoveEgg.GetFormEggMoves(species, form, EggMoves); + return EggMoves.GetFormEggMoves(species, form); } public MoveLearnInfo GetCanLearn(PKM pk, PersonalInfo7 pi, EvoCriteria evo, ushort move, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7USUM.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7USUM.cs index 36b168b8e..161b2f249 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7USUM.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource7USUM.cs @@ -13,8 +13,8 @@ public sealed class LearnSource7USUM : ILearnSource, IEggSource { public static readonly LearnSource7USUM Instance = new(); private static readonly PersonalTable7 Personal = PersonalTable.USUM; - private static readonly Learnset[] Learnsets = Legal.LevelUpUSUM; - private static readonly EggMoves7[] EggMoves = Legal.EggMovesUSUM; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_uu.pkl"), "uu")); + private static readonly EggMoves7[] EggMoves = EggMoves7.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_uu.pkl"), "uu")); private const int MaxSpecies = Legal.MaxSpeciesID_7_USUM; private const LearnEnvironment Game = USUM; private const int ReminderBonus = 100; // Move reminder allows re-learning ALL level up moves regardless of level. @@ -34,15 +34,15 @@ public bool GetIsEggMove(ushort species, byte form, ushort move) { if (species > MaxSpecies) return false; - var moves = MoveEgg.GetFormEggMoves(species, form, EggMoves).AsSpan(); - return moves.IndexOf(move) != -1; + var moves = EggMoves.GetFormEggMoves(species, form); + return moves.Contains(move); } public ReadOnlySpan GetEggMoves(ushort species, byte form) { if (species > MaxSpecies) return ReadOnlySpan.Empty; - return MoveEgg.GetFormEggMoves(species, form, EggMoves); + return EggMoves.GetFormEggMoves(species, form); } public MoveLearnInfo GetCanLearn(PKM pk, PersonalInfo7 pi, EvoCriteria evo, ushort move, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8BDSP.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8BDSP.cs index e38f04ff0..f0d2a65a8 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8BDSP.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8BDSP.cs @@ -12,8 +12,8 @@ public sealed class LearnSource8BDSP : ILearnSource, IEggSour { public static readonly LearnSource8BDSP Instance = new(); private static readonly PersonalTable8BDSP Personal = PersonalTable.BDSP; - private static readonly Learnset[] Learnsets = Legal.LevelUpBDSP; - private static readonly EggMoves6[] EggMoves = Legal.EggMovesBDSP; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_bdsp.pkl"), "bs")); + private static readonly EggMoves6[] EggMoves = EggMoves6.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_bdsp.pkl"), "bs")); private const int MaxSpecies = Legal.MaxSpeciesID_8b; private const LearnEnvironment Game = BDSP; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8PLA.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8PLA.cs index cfb46294a..89160954c 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8PLA.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8PLA.cs @@ -12,12 +12,19 @@ public sealed class LearnSource8LA : ILearnSource { public static readonly LearnSource8LA Instance = new(); private static readonly PersonalTable8LA Personal = PersonalTable.LA; - private static readonly Learnset[] Learnsets = Legal.LevelUpLA; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_la.pkl"), "la")); + private static readonly Learnset[] Mastery = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("mastery_la.pkl"), "la")); private const int MaxSpecies = Legal.MaxSpeciesID_8a; private const LearnEnvironment Game = PLA; public Learnset GetLearnset(ushort species, byte form) => Learnsets[Personal.GetFormIndex(species, form)]; + public static (Learnset Learn, Learnset Mastery) GetLearnsetAndMastery(ushort species, byte form) + { + var index = Personal.GetFormIndex(species, form); + return (Learnsets[index], Mastery[index]); + } + public bool TryGetPersonal(ushort species, byte form, [NotNullWhen(true)] out PersonalInfo8LA? pi) { pi = null; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8SWSH.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8SWSH.cs index 7cc59f8b6..b560e009b 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8SWSH.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource8SWSH.cs @@ -12,8 +12,8 @@ public sealed class LearnSource8SWSH : ILearnSource, IEggSour { public static readonly LearnSource8SWSH Instance = new(); private static readonly PersonalTable8SWSH Personal = PersonalTable.SWSH; - private static readonly Learnset[] Learnsets = Legal.LevelUpSWSH; - private static readonly EggMoves7[] EggMoves = Legal.EggMovesSWSH; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_swsh.pkl"), "ss")); + private static readonly EggMoves7[] EggMoves = EggMoves7.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_swsh.pkl"), "ss")); private const int MaxSpecies = Legal.MaxSpeciesID_8_R2; private const LearnEnvironment Game = SWSH; @@ -32,15 +32,15 @@ public bool GetIsEggMove(ushort species, byte form, ushort move) { if (species > MaxSpecies) return false; - var moves = MoveEgg.GetFormEggMoves(species, form, EggMoves).AsSpan(); - return moves.IndexOf(move) != -1; + var moves = EggMoves.GetFormEggMoves(species, form); + return moves.Contains(move); } public ReadOnlySpan GetEggMoves(ushort species, byte form) { if (species > MaxSpecies) return ReadOnlySpan.Empty; - return MoveEgg.GetFormEggMoves(species, form, EggMoves); + return EggMoves.GetFormEggMoves(species, form); } public MoveLearnInfo GetCanLearn(PKM pk, PersonalInfo8SWSH pi, EvoCriteria evo, ushort move, MoveSourceType types = MoveSourceType.All, LearnOption option = LearnOption.Current) diff --git a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource9SV.cs b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource9SV.cs index c6ca3d862..c544fccb6 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/LearnSource9SV.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/LearnSource9SV.cs @@ -12,9 +12,9 @@ public sealed class LearnSource9SV : ILearnSource, IEggSource, { public static readonly LearnSource9SV Instance = new(); private static readonly PersonalTable9SV Personal = PersonalTable.SV; - private static readonly Learnset[] Learnsets = Legal.LevelUpSV; - private static readonly ushort[][] EggMoves = Legal.EggMovesSV; - private static readonly ushort[][] Reminder = Legal.ReminderSV; + private static readonly Learnset[] Learnsets = LearnsetReader.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("lvlmove_sv.pkl"), "sv")); + private static readonly ushort[][] EggMoves = EggMoves9.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_sv.pkl"), "sv")); + private static readonly ushort[][] Reminder = EggMoves9.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("reminder_sv.pkl"), "sv")); private const int MaxSpecies = Legal.MaxSpeciesID_9; private const LearnEnvironment Game = SV; diff --git a/PKHeX.Core/Legality/LearnSource/Sources/Shared/ILearnSource.cs b/PKHeX.Core/Legality/LearnSource/Sources/Shared/ILearnSource.cs index 49a0e82a2..ff1b46d37 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/Shared/ILearnSource.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/Shared/ILearnSource.cs @@ -23,6 +23,15 @@ public interface ILearnSource /// Entity species /// Entity form public Learnset GetLearnset(ushort species, byte form); + + public void SetEncounterMoves(ushort species, byte form, int level, Span init) + { + var start = (init.LastIndexOfAnyExcept(0) + 1) & 3; + var learn = GetLearnset(species, form); + learn.SetEncounterMoves(level, init, start); + } + + public ReadOnlySpan GetEggMoves(ushort species, byte form) => ReadOnlySpan.Empty; } /// diff --git a/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource3.cs b/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource3.cs index dd5c8236b..51b36591a 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource3.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource3.cs @@ -2,8 +2,10 @@ namespace PKHeX.Core; -internal static class LearnSource3 +public abstract class LearnSource3 { + private protected readonly EggMoves6[] EggMoves = EggMoves6.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_rs.pkl"), "rs")); // same for all Gen3 games + internal static ReadOnlySpan TM_3 => new ushort[] { 264, 337, 352, 347, 046, 092, 258, 339, 331, 237, diff --git a/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource4.cs b/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource4.cs index fe9aae33d..131ee2bb6 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource4.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource4.cs @@ -2,8 +2,10 @@ namespace PKHeX.Core; -internal static class LearnSource4 +public abstract class LearnSource4 { + private protected static readonly EggMoves6[] EggMoves = EggMoves6.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_dppt.pkl"), "dp")); + /// /// Gets the preferred list of HM moves to disallow on transfer from to . /// diff --git a/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource5.cs b/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource5.cs index 0587f4c1c..e68f8f4df 100644 --- a/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource5.cs +++ b/PKHeX.Core/Legality/LearnSource/Sources/Shared/LearnSource5.cs @@ -2,8 +2,10 @@ namespace PKHeX.Core; -internal static class LearnSource5 +public abstract class LearnSource5 { + private protected readonly EggMoves6[] EggMoves = EggMoves6.GetArray(BinLinkerAccessor.Get(Util.GetBinaryResource("eggmove_bw.pkl"), "bw")); + internal static ReadOnlySpan TMHM_BW => new ushort[] { 468, 337, 473, 347, 046, 092, 258, 339, 474, 237, diff --git a/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifierEgg.cs b/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifierEgg.cs index 326979645..982b47f06 100644 --- a/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifierEgg.cs +++ b/PKHeX.Core/Legality/LearnSource/Verify/LearnVerifierEgg.cs @@ -31,7 +31,9 @@ private static void VerifyFromEncounter(Span result, ReadOnlySpan initial = GameData.GetLearnset(enc.Version, enc.Species, enc.Form).GetBaseEggMoves(enc.LevelMin); + var ls = GameData.GetLearnSource(enc.Version); + var learn = ls.GetLearnset(enc.Species, enc.Form); + var initial = learn.GetBaseEggMoves(enc.LevelMin); VerifyMovesInitial(result, current, initial); } } diff --git a/PKHeX.Core/Legality/Learnset/EggMoves.cs b/PKHeX.Core/Legality/Learnset/EggMoves.cs index 6b784e339..0472cbd2d 100644 --- a/PKHeX.Core/Legality/Learnset/EggMoves.cs +++ b/PKHeX.Core/Legality/Learnset/EggMoves.cs @@ -125,6 +125,30 @@ public static EggMoves7[] GetArray(BinLinkerAccessor entries) } } +internal static class EggMovesExtensions +{ + public static ReadOnlySpan GetFormEggMoves(this EggMoves7[] table, ushort species, byte form) + { + if (species >= table.Length) + return ReadOnlySpan.Empty; + + var entry = table[species]; + if (form == 0 || species >= entry.FormTableIndex) + return entry.Moves; + + // Sanity check form in the event it is out of range. + var baseIndex = entry.FormTableIndex; + var index = baseIndex + form - 1; + if ((uint)index >= table.Length) + return ReadOnlySpan.Empty; + entry = table[index]; + if (entry.FormTableIndex != baseIndex) + return ReadOnlySpan.Empty; + + return entry.Moves; + } +} + /// /// Raw Egg Move storage /// diff --git a/PKHeX.Core/Legality/MoveList.cs b/PKHeX.Core/Legality/MoveList.cs deleted file mode 100644 index 74ccb4ae1..000000000 --- a/PKHeX.Core/Legality/MoveList.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System; -using static PKHeX.Core.Legal; -using static PKHeX.Core.GameVersion; - -namespace PKHeX.Core; - -/// -/// Logic for obtaining a list of moves. -/// -internal static class MoveList -{ - internal static void GetCurrentMoves(PKM pk, ushort species, byte form, GameVersion gameSource, int lvl, Span moves) => _ = gameSource switch - { - GSC or GS => Get(moves, LevelUpGS, species, lvl, pk.Format), - C => Get(moves, LevelUpC, species, lvl, pk.Format), - - R or S or RS => Get(moves, LevelUpRS, species, lvl), - E => Get(moves, LevelUpE, species, lvl), - FR or LG or FRLG => Get(moves, LevelUpFR, species, lvl), - - D or P or DP => Get(moves, LevelUpDP, species, lvl), - Pt => Get(moves, LevelUpPt, species, lvl), - HG or SS or HGSS => Get(moves, LevelUpHGSS, species, lvl), - - B or W or BW => Get(moves, LevelUpBW, species, lvl), - B2 or W2 or B2W2 => Get(moves, LevelUpB2W2, species, lvl), - - X or Y or XY => Get(moves, LevelUpXY, species, lvl), - AS or OR or ORAS => Get(moves, LevelUpAO, species, lvl), - - SN or MN or SM => Get(moves, LevelUpSM, PersonalTable.SM, species, form, lvl), - US or UM or USUM => Get(moves, LevelUpUSUM, PersonalTable.USUM, species, form, lvl), - SW or SH or SWSH => Get(moves, LevelUpSWSH, PersonalTable.SWSH, species, form, lvl), - BD or SP or BDSP => Get(moves, LevelUpBDSP, PersonalTable.BDSP, species, form, lvl), - PLA => Get(moves, LevelUpLA, PersonalTable.LA, species, form, lvl), - - SL or VL or SV => Get(moves, LevelUpSV, PersonalTable.SV, species, form, lvl), - - _ => moves, - }; - - private static Span Get(Span moves, Learnset[] source, ushort species, int lvl) - { - if (species >= source.Length) - return moves; - source[species].SetLevelUpMoves(1, lvl, moves); - return moves; - } - - private static Span Get(Span moves, Learnset[] source, T pt, ushort species, byte form, int lvl) where T : IPersonalTable - { - if (!pt.IsPresentInGame(species, form)) - return moves; - - int index = pt.GetFormIndex(species, form); - source[index].SetLevelUpMoves(1, lvl, moves); - return moves; - } - - private static Span Get(Span moves, Learnset[] source, ushort species, int lvl, int format) - { - if (species > MaxSpeciesID_2) - return moves; - - source[species].SetLevelUpMoves(1, lvl, moves); - if (format != 1) - return moves; - - // If checking back-transfer specimen (GSC->RBY), remove moves that must be deleted prior to transfer - // Remove all values greater than MaxMoveID_1, and shift the remaining indexes down. - for (int i = 0; i < moves.Length; i++) - { - if (moves[i] <= MaxMoveID_1) - continue; - // Shift remaining indexes down, set last index to 0 - for (int j = i; j < moves.Length - 1; j++) - moves[j] = moves[j + 1]; - - moves[^1] = 0; - } - - return moves; - } -} diff --git a/PKHeX.Core/Legality/MoveListSuggest.cs b/PKHeX.Core/Legality/MoveListSuggest.cs index 120c3b820..0d3200ad6 100644 --- a/PKHeX.Core/Legality/MoveListSuggest.cs +++ b/PKHeX.Core/Legality/MoveListSuggest.cs @@ -12,7 +12,8 @@ private static void GetSuggestedMoves(PKM pk, EvolutionHistory evoChains, MoveSo { if (pk is { IsEgg: true, Format: <= 5 }) // pre relearn { - MoveList.GetCurrentMoves(pk, pk.Species, 0, (GameVersion)pk.Version, pk.CurrentLevel, moves); + var source = GameData.GetLearnSource(enc.Version); + source.SetEncounterMoves(enc.Species, 0, enc.LevelMin, moves); return; } @@ -26,14 +27,16 @@ private static void GetSuggestedMoves(PKM pk, EvolutionHistory evoChains, MoveSo if (enc.Generation <= 2) { var lvl = pk.Format >= 7 ? pk.Met_Level : pk.CurrentLevel; - var ver = enc.Version; - MoveLevelUp.GetEncounterMoves(moves, enc.Species, 0, lvl, ver); + var source = GameData.GetLearnSource(enc.Version); + source.SetEncounterMoves(enc.Species, 0, lvl, moves); return; } if (pk.Species == enc.Species) { - MoveLevelUp.GetEncounterMoves(moves, pk.Species, pk.Form, pk.CurrentLevel, (GameVersion)pk.Version); + var game = (GameVersion)pk.Version; // account for SW/SH foreign mutated versions + var source = GameData.GetLearnSource(game); + source.SetEncounterMoves(pk.Species, pk.Form, pk.CurrentLevel, moves); return; } diff --git a/PKHeX.Core/Legality/Moves/Breeding/MoveBreed.cs b/PKHeX.Core/Legality/Moves/Breeding/MoveBreed.cs index 0301f2d70..ca6dff86c 100644 --- a/PKHeX.Core/Legality/Moves/Breeding/MoveBreed.cs +++ b/PKHeX.Core/Legality/Moves/Breeding/MoveBreed.cs @@ -73,10 +73,8 @@ public static bool GetExpectedMoves(int generation, ushort species, byte form, G // Well, that didn't work; probably because one or more moves aren't valid. // Let's remove all present base moves, and get a fresh set of base moves. - var learn = GameData.GetLearnsets(version); - var table = GameData.GetPersonal(version); - var index = table.GetFormIndex(species, form); - var learnset = learn[index]; + var learn = GameData.GetLearnSource(version); + var learnset = learn.GetLearnset(species, form); var eggLevel = EggStateLegality.GetEggLevel(generation); var baseMoves = learnset.GetBaseEggMoves(eggLevel); diff --git a/PKHeX.Core/Legality/Moves/Breeding/MoveBreed2.cs b/PKHeX.Core/Legality/Moves/Breeding/MoveBreed2.cs index 33c08d6b3..b94abe29f 100644 --- a/PKHeX.Core/Legality/Moves/Breeding/MoveBreed2.cs +++ b/PKHeX.Core/Legality/Moves/Breeding/MoveBreed2.cs @@ -23,22 +23,21 @@ public static bool Validate(ushort species, GameVersion version, ReadOnlySpan ls = version == GameVersion.C ? LearnSource2C.Instance : LearnSource2GS.Instance; + if (!ls.TryGetPersonal(species, 0, out var pi)) return false; - var learnset = learn[species]; - var pi = table[species]; - var egg = (version == GameVersion.C ? Legal.EggMovesC : Legal.EggMovesGS)[species].Moves; + var learnset = ls.GetLearnset(species, 0); + var eggMoves = version == GameVersion.C + ? LearnSource2C.Instance.GetEggMoves(species, 0) + : LearnSource2GS.Instance.GetEggMoves(species, 0); var actual = MemoryMarshal.Cast(origins); Span possible = stackalloc byte[count]; var value = new BreedInfo(actual, possible, learnset, moves, level); bool inherit = Breeding.GetCanInheritMoves(species); - MarkMovesForOrigin(value, egg, count, inherit, pi, version); + MarkMovesForOrigin(value, eggMoves, count, inherit, pi, version); var valid = RecurseMovesForOrigin(value, count - 1); if (!valid) CleanResult(actual, possible); diff --git a/PKHeX.Core/Legality/Moves/Breeding/MoveBreed3.cs b/PKHeX.Core/Legality/Moves/Breeding/MoveBreed3.cs index 6dc74dd6d..352eecaa2 100644 --- a/PKHeX.Core/Legality/Moves/Breeding/MoveBreed3.cs +++ b/PKHeX.Core/Legality/Moves/Breeding/MoveBreed3.cs @@ -24,20 +24,19 @@ public static bool Validate(ushort species, GameVersion version, ReadOnlySpan ls = version switch { - R or S => (Legal.LevelUpRS, PersonalTable.RS), - E => (Legal.LevelUpE, PersonalTable.E ), - FR => (Legal.LevelUpFR, PersonalTable.FR), - LG => (Legal.LevelUpLG, PersonalTable.LG), - _ => throw new ArgumentException($"Invalid version: {version}"), + R => LearnSource3RS.Instance, + S => LearnSource3RS.Instance, + E => LearnSource3E.Instance, + FR => LearnSource3FR.Instance, + LG => LearnSource3LG.Instance, + _ => throw new ArgumentOutOfRangeException(nameof(version), version, $"Invalid version: {version}"), }; - if (!table.IsSpeciesInGame(species)) + if (!ls.TryGetPersonal(species, 0, out var pi)) return false; - var learnset = learn[species]; - var pi = table[species]; - + var learnset = ls.GetLearnset(species, 0); var actual = MemoryMarshal.Cast(origins); Span possible = stackalloc byte[count]; var value = new BreedInfo(actual, possible, learnset, moves, level); @@ -51,7 +50,7 @@ public static bool Validate(ushort species, GameVersion version, ReadOnlySpan PersonalTable.HGSS, @@ -48,8 +48,10 @@ public static bool Validate(ushort species, GameVersion version, ReadOnlySpan PersonalTable.BW[species], @@ -44,7 +44,7 @@ public static bool Validate(ushort species, GameVersion version, ReadOnlySpan(origins); Span possible = stackalloc byte[count]; @@ -40,7 +38,7 @@ public static bool Validate(int generation, ushort species, byte form, GameVersi } else { - var egg = MoveEgg.GetEggMoves(generation, species, form, version); + var egg = learn.GetEggMoves(species, form); bool inherit = Breeding.GetCanInheritMoves(species); MarkMovesForOrigin(value, egg, count, inherit); valid = RecurseMovesForOrigin(value, count - 1); diff --git a/PKHeX.Core/Legality/Moves/GameData.cs b/PKHeX.Core/Legality/Moves/GameData.cs index e1ddd32b0..b4081d2c8 100644 --- a/PKHeX.Core/Legality/Moves/GameData.cs +++ b/PKHeX.Core/Legality/Moves/GameData.cs @@ -5,62 +5,53 @@ namespace PKHeX.Core; public static class GameData { - public static Learnset[] GetLearnsets(GameVersion game) => Learnsets(game); public static IPersonalTable GetPersonal(GameVersion game) => Personal(game); - public static Learnset GetLearnset(GameVersion game, ushort species, byte form) + public static ILearnSource GetLearnSource(GameVersion game) => game switch { - var pt = Personal(game); - var index = pt.GetFormIndex(species, form); - var sets = Learnsets(game); - return sets[index]; - } + RD or GN or BU or RB => LearnSource1RB.Instance, + YW or RBY => LearnSource1YW.Instance, + GD or SI or GS => LearnSource2GS.Instance, + C or GSC => LearnSource2C.Instance, - private static Learnset[] Learnsets(GameVersion game) => game switch - { - RD or GN or BU or RB => Legal.LevelUpRB, - YW or RBY => Legal.LevelUpY, - GD or SI or GS => Legal.LevelUpGS, - C or GSC => Legal.LevelUpC, + R or S or RS or RSE => LearnSource3RS.Instance, + E or COLO or XD or FRLG or CXD => LearnSource3E.Instance, + FR => LearnSource3FR.Instance, + LG => LearnSource3LG.Instance, - R or S or RS or RSE => Legal.LevelUpRS, - E or COLO or XD or FRLG or CXD => Legal.LevelUpE, - FR => Legal.LevelUpFR, - LG => Legal.LevelUpLG, + D or P or DP => LearnSource4DP.Instance, + Pt or DPPt => LearnSource4Pt.Instance, + HG or SS or HGSS => LearnSource4HGSS.Instance, - D or P or DP => Legal.LevelUpDP, - Pt or DPPt => Legal.LevelUpPt, - HG or SS or HGSS => Legal.LevelUpHGSS, + B or W or BW => LearnSource5BW.Instance, + B2 or W2 or B2W2 => LearnSource5B2W2.Instance, - B or W or BW => Legal.LevelUpBW, - B2 or W2 or B2W2 => Legal.LevelUpB2W2, + X or Y or XY => LearnSource6XY.Instance, + AS or OR or ORAS => LearnSource6AO.Instance, - X or Y or XY => Legal.LevelUpXY, - AS or OR or ORAS => Legal.LevelUpAO, + SN or MN or SM => LearnSource7SM.Instance, + US or UM or USUM => LearnSource7USUM.Instance, + GO or GP or GE or GG => LearnSource7GG.Instance, - SN or MN or SM => Legal.LevelUpSM, - US or UM or USUM => Legal.LevelUpUSUM, - GO or GP or GE or GG => Legal.LevelUpGG, + SW or SH or SWSH => LearnSource8SWSH.Instance, + BD or SP or BDSP => LearnSource8BDSP.Instance, + PLA => LearnSource8LA.Instance, - SW or SH or SWSH => Legal.LevelUpSWSH, - BD or SP or BDSP => Legal.LevelUpBDSP, - PLA => Legal.LevelUpLA, + SL or VL or SV => LearnSource9SV.Instance, - SL or VL or SV => Legal.LevelUpSV, + Gen1 => LearnSource1YW.Instance, + Gen2 => LearnSource2C.Instance, + Gen3 => LearnSource3E.Instance, + Gen4 => LearnSource4HGSS.Instance, + Gen5 => LearnSource5B2W2.Instance, + Gen6 => LearnSource6AO.Instance, + Gen7 => LearnSource7USUM.Instance, + Gen7b => LearnSource7GG.Instance, + Gen8 => LearnSource8BDSP.Instance, + Gen9 => LearnSource9SV.Instance, - Gen1 => Legal.LevelUpY, - Gen2 => Legal.LevelUpC, - Gen3 => Legal.LevelUpE, - Gen4 => Legal.LevelUpHGSS, - Gen5 => Legal.LevelUpB2W2, - Gen6 => Legal.LevelUpAO, - Gen7 => Legal.LevelUpSM, - Gen7b => Legal.LevelUpGG, - Gen8 => Legal.LevelUpSWSH, - Gen9 => Legal.LevelUpSV, - - Stadium => Legal.LevelUpY, - Stadium2 => Legal.LevelUpGS, + Stadium => LearnSource1YW.Instance, + Stadium2 => LearnSource2GS.Instance, _ => throw new ArgumentOutOfRangeException(nameof(game), $"{game} is not a valid entry in the expression."), }; diff --git a/PKHeX.Core/Legality/Moves/MoveEgg.cs b/PKHeX.Core/Legality/Moves/MoveEgg.cs deleted file mode 100644 index 2ea8b7b30..000000000 --- a/PKHeX.Core/Legality/Moves/MoveEgg.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using static PKHeX.Core.Legal; -using static PKHeX.Core.GameVersion; - -namespace PKHeX.Core; - -/// -/// Shared logic for interacting with data sources. -/// -public static class MoveEgg -{ - /// - /// Gets the data for the and . - /// - public static ReadOnlySpan GetEggMoves(ushort species, byte form, GameVersion version, int generation) - { - if (!Breeding.CanGameGenerateEggs(version)) - return Array.Empty(); - - return GetEggMoves(generation, species, form, version); - } - - /// - /// Gets the data for the and . - /// - /// Only use this if you're sure the game can generate eggs. - public static ReadOnlySpan GetEggMoves(int generation, ushort species, byte form, GameVersion version) => generation switch - { - 1 or 2 => GetMovesSafe(version == C ? EggMovesC : EggMovesGS, species), - 3 => GetMovesSafe(EggMovesRS, species), - 4 when version is D or P or Pt => GetMovesSafe(EggMovesDPPt, species), - 4 when version is HG or SS => GetMovesSafe(EggMovesHGSS, species), - 5 => GetMovesSafe(EggMovesBW, species), - - 6 when version is X or Y => GetMovesSafe(EggMovesXY, species), - 6 when version is OR or AS => GetMovesSafe(EggMovesAO, species), - - 7 when version is SN or MN => GetFormEggMoves(species, form, EggMovesSM), - 7 when version is US or UM => GetFormEggMoves(species, form, EggMovesUSUM), - 8 when version is SW or SH => GetFormEggMoves(species, form, EggMovesSWSH), - 8 when version is BD or SP => GetMovesSafe(EggMovesBDSP, species), - 9 when version is SL or VL => GetFormEggMoves(EggMovesSV, PersonalTable.SV.GetFormIndex(species, form)), - _ => Array.Empty(), - }; - - private static ushort[] GetMovesSafe(IReadOnlyList moves, ushort species) where T : EggMoves - { - if (species >= moves.Count) - return Array.Empty(); - return moves[species].Moves; - } - - public static ushort[] GetFormEggMoves(IReadOnlyList moves, int index) - { - if ((ushort)index >= moves.Count) - return Array.Empty(); - return moves[index]; - } - - public static ushort[] GetFormEggMoves(ushort species, byte form, IReadOnlyList table) - { - if (species >= table.Count) - return Array.Empty(); - - var entry = table[species]; - if (form == 0 || species >= entry.FormTableIndex) - return entry.Moves; - - // Sanity check form in the event it is out of range. - var baseIndex = entry.FormTableIndex; - var index = baseIndex + form - 1; - if ((uint)index >= table.Count) - return Array.Empty(); - entry = table[index]; - if (entry.FormTableIndex != baseIndex) - return Array.Empty(); - - return entry.Moves; - } -} diff --git a/PKHeX.Core/Legality/Moves/MoveLevelUp.cs b/PKHeX.Core/Legality/Moves/MoveLevelUp.cs deleted file mode 100644 index a4bcc1e7a..000000000 --- a/PKHeX.Core/Legality/Moves/MoveLevelUp.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System; - -using static PKHeX.Core.GameVersion; - -namespace PKHeX.Core; - -public static class MoveLevelUp -{ - public static void GetEncounterMoves(Span moves, PKM pk, int level, GameVersion version) - { - if (version <= 0) - version = (GameVersion)pk.Version; - GetEncounterMoves(moves, pk.Species, pk.Form, level, version); - } - - private static void GetEncounterMoves1(Span result, ushort species, int level, GameVersion version) - { - var learn = GameData.GetLearnsets(version); - var table = version is YW or RBY ? PersonalTable.Y : PersonalTable.RB; - var index = table.GetFormIndex(species, 0); - - // The initial moves are seeded from Personal rather than learn. - table[index].GetMoves(result); - int start = Math.Max(0, result.IndexOf(0)); - - learn[index].SetEncounterMoves(level, result, start); - } - - public static void GetEncounterMoves(Span result, ushort species, byte form, int level, GameVersion version) - { - if (RBY.Contains(version)) - { - GetEncounterMoves1(result, species, level, version); - } - else - { - var learn = GameData.GetLearnsets(version); - var table = GameData.GetPersonal(version); - var index = table.GetFormIndex(species, form); - learn[index].SetEncounterMoves(level, result); - } - } -} diff --git a/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs b/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs index 68cc7baf8..3b5b1077d 100644 --- a/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs +++ b/PKHeX.Core/Legality/Restrictions/ItemRestrictions.cs @@ -47,4 +47,41 @@ public static bool IsHeldItemAllowed(int item, EntityContext context) EntityContext.Gen8b => ReleasedHeldItems_8b, _ => Array.Empty(), // lgp/e, pla, etc }; + + private static readonly bool[] ReleasedHeldItems_2 = GetPermitList(MaxItemID_2, HeldItems_GSC); + private static readonly bool[] ReleasedHeldItems_3 = GetPermitList(MaxItemID_3, HeldItems_RS, ItemStorage3RS.Unreleased); // Safari Ball + private static readonly bool[] ReleasedHeldItems_4 = GetPermitList(MaxItemID_4_HGSS, HeldItems_HGSS, ItemStorage4.Unreleased); + private static readonly bool[] ReleasedHeldItems_5 = GetPermitList(MaxItemID_5_B2W2, HeldItems_BW, ItemStorage5.Unreleased); + private static readonly bool[] ReleasedHeldItems_6 = GetPermitList(MaxItemID_6_AO, HeldItem_AO, ItemStorage6XY.Unreleased); + private static readonly bool[] ReleasedHeldItems_7 = GetPermitList(MaxItemID_7_USUM, HeldItems_USUM, ItemStorage7SM.Unreleased); + private static readonly bool[] ReleasedHeldItems_8 = GetPermitList(MaxItemID_8, HeldItems_SWSH, ItemStorage8SWSH.Unreleased); + private static readonly bool[] ReleasedHeldItems_8b = GetPermitList(MaxItemID_8b, HeldItems_BS, ItemStorage8BDSP.Unreleased); + private static readonly bool[] ReleasedHeldItems_9 = GetPermitList(MaxItemID_9, HeldItems_SV, ItemStorage9SV.Unreleased); + + /// + /// Gets a permit list with the permitted indexes, then un-flags the indexes that are not permitted. + /// + /// Maximum index expected to allow + /// Allowed indexes + private static bool[] GetPermitList(int max, ReadOnlySpan allowed) + { + var result = new bool[max + 1]; + foreach (var index in allowed) + result[index] = true; + return result; + } + + /// + /// Gets a permit list with the permitted indexes, then un-flags the indexes that are not permitted. + /// + /// Maximum index expected to allow + /// Allowed indexes (may have some disallowed) + /// Disallowed indexes + private static bool[] GetPermitList(int max, ReadOnlySpan allowed, ReadOnlySpan disallow) + { + var result = GetPermitList(max, allowed); + foreach (var index in disallow) + result[index] = false; + return result; + } } diff --git a/PKHeX.Core/Legality/Restrictions/Memories/MemoryPermissions.cs b/PKHeX.Core/Legality/Restrictions/Memories/MemoryPermissions.cs index 8be9af0b6..78b0858e1 100644 --- a/PKHeX.Core/Legality/Restrictions/Memories/MemoryPermissions.cs +++ b/PKHeX.Core/Legality/Restrictions/Memories/MemoryPermissions.cs @@ -91,7 +91,8 @@ public static bool CanKnowMove(PKM pk, MemoryVariableSet memory, EntityContext g // Relearns can be wiped via Battle Version. Check for eggs too. if (IsSpecialEncounterMoveEggDeleted(pk, enc)) { - var em = MoveEgg.GetEggMoves(enc.Generation, enc.Species, enc.Form, enc.Version); + var learn = GameData.GetLearnSource(enc.Version); + var em = learn.GetEggMoves(enc.Species, enc.Form); if (em.Contains(move)) return true; } diff --git a/PKHeX.Core/Legality/Structures/IMasteryInitialMoveShop8.cs b/PKHeX.Core/Legality/Structures/IMasteryInitialMoveShop8.cs index ae5cc92bf..3e1a943b0 100644 --- a/PKHeX.Core/Legality/Structures/IMasteryInitialMoveShop8.cs +++ b/PKHeX.Core/Legality/Structures/IMasteryInitialMoveShop8.cs @@ -16,7 +16,7 @@ void SetInitialMastery(PKM pk) { Span moves = stackalloc ushort[4]; var level = pa8.Met_Level; - var (learn, mastery) = GetLevelUpInfo(); + var (learn, mastery) = LearnSource8LA.GetLearnsetAndMastery(pk.Species, pk.Form); LoadInitialMoveset(pa8, moves, learn, level); pa8.SetEncounterMasteryFlags(moves, mastery, level); } diff --git a/PKHeX.Core/Legality/Tables/FormInfo.cs b/PKHeX.Core/Legality/Tables/FormInfo.cs index 90d5200c2..89249b515 100644 --- a/PKHeX.Core/Legality/Tables/FormInfo.cs +++ b/PKHeX.Core/Legality/Tables/FormInfo.cs @@ -120,7 +120,7 @@ public static bool IsFormChangeable(ushort species, byte oldForm, byte newForm, return false; } - public static bool IsFormChangeEgg(ushort species) => FormChangeEgg.IndexOf(species) != -1; + public static bool IsFormChangeEgg(ushort species) => FormChangeEgg.Contains(species); private static ReadOnlySpan FormChangeEgg => new ushort[] { @@ -237,6 +237,28 @@ private static HashSet GetBattleFormSet() return hs; } + /// + /// Species has a Totem form in Gen7 (S/M & US/UM) that can be captured and owned. + /// + /// + /// True if the species exists as a Totem. + /// Excludes because it cannot be captured. + public static bool HasTotemForm(ushort species) => species switch + { + (ushort)Raticate => true, + (ushort)Marowak => true, + (ushort)Gumshoos => true, + (ushort)Vikavolt => true, + (ushort)Ribombee => true, + (ushort)Araquanid => true, + (ushort)Lurantis => true, + (ushort)Salazzle => true, + (ushort)Mimikyu => true, + (ushort)Kommoo => true, + (ushort)Togedemaru => true, + _ => false, + }; + /// /// Checks if the for the is a Totem form. /// @@ -255,11 +277,11 @@ public static bool IsTotemForm(ushort species, byte form) { if (form == 0) return false; - if (!Legal.Totem_USUM.Contains(species)) + if (!HasTotemForm(species)) return false; if (species == (int)Mimikyu) return form is 2 or 3; - if (Legal.Totem_Alolan.Contains(species)) + if (species is (int)Raticate or (int)Marowak) return form == 2; return form == 1; } @@ -323,7 +345,7 @@ public static bool HasFormSelection(IPersonalFormInfo pi, ushort species, int fo if (format <= 3 && species != (int)Unown) return false; - if (HasFormValuesNotIndicatedByPersonal.Contains(species)) + if (HasFormValuesNotIndicatedByPersonal(species)) return true; int count = pi.FormCount; @@ -333,10 +355,11 @@ public static bool HasFormSelection(IPersonalFormInfo pi, ushort species, int fo /// /// /// - private static readonly HashSet HasFormValuesNotIndicatedByPersonal = new() + private static bool HasFormValuesNotIndicatedByPersonal(ushort species) => species switch { - (int)Unown, - (int)Mothim, // (Burmy form is not cleared on evolution) - (int)Scatterbug, (int)Spewpa, // Vivillon pre-evos + (int)Unown => true, + (int)Mothim => true, // (Burmy form is not cleared on evolution) + (int)Scatterbug or (int)Spewpa => true, // Vivillon pre-evos + _ => false, }; } diff --git a/PKHeX.Core/Legality/Tables/SpeciesCategory.cs b/PKHeX.Core/Legality/Tables/SpeciesCategory.cs new file mode 100644 index 000000000..446937115 --- /dev/null +++ b/PKHeX.Core/Legality/Tables/SpeciesCategory.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using static PKHeX.Core.Species; + +namespace PKHeX.Core; + +/// +/// Categorizes into groups, or specific edge-case qualities. +/// +public static class SpeciesCategory +{ + /// + /// Checks if a Species is classified as a Mythical Distributions (disallowed species for competitive rulesets) + /// + public static bool IsMythical(ushort species) => Mythicals.Contains(species); + + /// + /// Checks if a Species is classified as "Legend" by the game code. + /// + /// Previous games may have included Mythicals in this species list, but that list should be considered separately. + public static bool IsLegendary(ushort species) => Legends.Contains(species); + + /// + /// Checks if a Species is classified as "SubLegend" by the game code. + /// + public static bool IsSubLegendary(ushort species) => SubLegends.Contains(species); + + private static readonly HashSet Mythicals = new() + { + (int)Mew, + (int)Celebi, + (int)Jirachi, (int)Deoxys, + (int)Phione, (int)Manaphy, (int)Darkrai, (int)Shaymin, (int)Arceus, + (int)Victini, (int)Keldeo, (int)Meloetta, (int)Genesect, + (int)Diancie, (int)Hoopa, (int)Volcanion, + (int)Magearna, (int)Marshadow, + (int)Zeraora, (int)Meltan, (int)Melmetal, + (int)Zarude, + }; + + private static readonly HashSet Legends = new() + { + (int)Mewtwo, + (int)Lugia, (int)HoOh, + (int)Kyogre, (int)Groudon, (int)Rayquaza, + (int)Dialga, (int)Palkia, (int)Giratina, + (int)Reshiram, (int)Zekrom, (int)Kyurem, + (int)Xerneas, (int)Yveltal, (int)Zygarde, + (int)Cosmog, (int)Cosmoem, (int)Solgaleo, (int)Lunala, (int)Necrozma, + (int)Zacian, (int)Zamazenta, (int)Eternatus, (int)Calyrex, + (int)Koraidon, (int)Miraidon, + }; + + private static readonly HashSet SubLegends = new() + { + (int)Articuno, (int)Zapdos, (int)Moltres, + (int)Raikou, (int)Entei, (int)Suicune, + (int)Regirock, (int)Regice, (int)Registeel, (int)Latias, (int)Latios, + (int)Uxie, (int)Mesprit, (int)Azelf, (int)Heatran, (int)Regigigas, (int)Cresselia, + (int)Cobalion, (int)Terrakion, (int)Virizion, (int)Tornadus, (int)Thundurus, (int)Landorus, + (int)TypeNull, (int)Silvally, (int)TapuKoko, (int)TapuLele, (int)TapuBulu, (int)TapuFini, + (int)Kubfu, (int)Urshifu, (int)Regieleki, (int)Regidrago, (int)Glastrier, (int)Spectrier, (int)Enamorus, + (int)WoChien, (int)ChienPao, (int)TingLu, (int)ChiYu, + }; + + /// + /// Checks if the is an Ultra Beast Pokémon. + /// + public static bool IsUltraBeast(ushort species) => species is (>= (int)Nihilego and <= (int)Guzzlord) or (>= (int)Poipole and <= (int)Blacephalon); + + /// + /// Checks if the is a Paradox Pokémon. + /// + public static bool IsParadox(ushort species) => species is (>= (int)GreatTusk and <= (int)IronThorns) or (int)RoaringMoon or (int)IronValiant; + + public static bool IsFixedGenderFromDual(ushort currentSpecies) => currentSpecies switch + { + (int)Shedinja => true, // Genderless + + (int)Wormadam => true, //(F) + (int)Mothim => true, // (M) + + (int)Gallade => true, // (M) + (int)Froslass => true, // (F) + (int)Meowstic => true, // (M/F) form specific + (int)Oinkologne => true, // (M/F) form specific + + _ => false, + }; +} diff --git a/PKHeX.Core/Legality/Tables/Tables.cs b/PKHeX.Core/Legality/Tables/Tables.cs deleted file mode 100644 index d5b296593..000000000 --- a/PKHeX.Core/Legality/Tables/Tables.cs +++ /dev/null @@ -1,136 +0,0 @@ -using System; -using System.Collections.Generic; -using static PKHeX.Core.Species; - -namespace PKHeX.Core; - -public static partial class Legal -{ - /// - /// Generation 3 & 4 Battle Frontier Species banlist. When referencing this in context to generation 4, be sure to disallow with Form 1 (Spiky). - /// - public static readonly HashSet BattleFrontierBanlist = new() - { - (int)Mewtwo, (int)Mew, - (int)Lugia, (int)HoOh, (int)Celebi, - (int)Kyogre, (int)Groudon, (int)Rayquaza, (int)Jirachi, (int)Deoxys, - (int)Dialga, (int)Palkia, (int)Giratina, (int)Phione, (int)Manaphy, (int)Darkrai, (int)Shaymin, (int)Arceus, - (int)Victini, (int)Reshiram, (int)Zekrom, (int)Kyurem, (int)Keldeo, (int)Meloetta, (int)Genesect, - (int)Xerneas, (int)Yveltal, (int)Zygarde, (int)Diancie, (int)Hoopa, (int)Volcanion, - (int)Cosmog, (int)Cosmoem, (int)Solgaleo, (int)Lunala, (int)Necrozma, (int)Magearna, (int)Marshadow, (int)Zeraora, - (int)Meltan, (int)Melmetal, - (int)Koraidon, (int)Miraidon, - }; - - /// - /// Species that are from Mythical Distributions (disallowed species for competitive rulesets) - /// - public static readonly HashSet Mythicals = new() - { - (int)Mew, - (int)Celebi, - (int)Jirachi, (int)Deoxys, - (int)Phione, (int)Manaphy, (int)Darkrai, (int)Shaymin, (int)Arceus, - (int)Victini, (int)Keldeo, (int)Meloetta, (int)Genesect, - (int)Diancie, (int)Hoopa, (int)Volcanion, - (int)Magearna, (int)Marshadow, - (int)Zeraora, (int)Meltan, (int)Melmetal, - (int)Zarude, - }; - - /// - /// Species classified as "Legend" by the game code. - /// - /// Previous games may have included Mythicals in this species list, but that list should be considered separately. - public static readonly HashSet Legends = new() - { - (int)Mewtwo, - (int)Lugia, (int)HoOh, - (int)Kyogre, (int)Groudon, (int)Rayquaza, - (int)Dialga, (int)Palkia, (int)Giratina, - (int)Reshiram, (int)Zekrom, (int)Kyurem, - (int)Xerneas, (int)Yveltal, (int)Zygarde, - (int)Cosmog, (int)Cosmoem, (int)Solgaleo, (int)Lunala, (int)Necrozma, - (int)Zacian, (int)Zamazenta, (int)Eternatus, (int)Calyrex, - (int)Koraidon, (int)Miraidon, - }; - - /// - /// Species classified as "SubLegend" by the game code. - /// - public static readonly HashSet SubLegends = new() - { - (int)Articuno, (int)Zapdos, (int)Moltres, - (int)Raikou, (int)Entei, (int)Suicune, - (int)Regirock, (int)Regice, (int)Registeel, (int)Latias, (int)Latios, - (int)Uxie, (int)Mesprit, (int)Azelf, (int)Heatran, (int)Regigigas, (int)Cresselia, - (int)Cobalion, (int)Terrakion, (int)Virizion, (int)Tornadus, (int)Thundurus, (int)Landorus, - (int)TypeNull, (int)Silvally, (int)TapuKoko, (int)TapuLele, (int)TapuBulu, (int)TapuFini, - (int)Kubfu, (int)Urshifu, (int)Regieleki, (int)Regidrago, (int)Glastrier, (int)Spectrier, (int)Enamorus, - (int)WoChien, (int)ChienPao, (int)TingLu, (int)ChiYu, - }; - - /// - /// Checks if the is an Ultra Beast Pokémon. - /// - public static bool IsUltraBeast(ushort species) => species is - (int)Nihilego or (int)Buzzwole or (int)Pheromosa or (int)Xurkitree or (int)Celesteela or (int)Kartana or (int)Guzzlord or - (int)Poipole or (int)Naganadel or (int)Stakataka or (int)Blacephalon; - - /// - /// Checks if the is a Paradox Pokémon. - /// - public static bool IsParadox(ushort species) => species is (>= (int)GreatTusk and <= (int)IronThorns) or (int)RoaringMoon or (int)IronValiant; - - /// - /// Species that evolve from a Bi-Gendered species into a Single-Gender. - /// - public static readonly HashSet FixedGenderFromBiGender = new() - { - (int)Nincada, - (int)Shedinja, // (G) - - (int)Burmy, - (int)Wormadam, //(F) - (int)Mothim, // (M) - - (int)Ralts, - (int)Gallade, // (M) - - (int)Snorunt, - (int)Froslass, // (F) - - (int)Espurr, - (int)Meowstic, // (M/F) form specific - - (int)Lechonk, - (int)Oinkologne, // (M/F) form specific - }; - - /// - /// Gets a permit list with the permitted indexes, then un-flags the indexes that are not permitted. - /// - /// Maximum index expected to allow - /// Allowed indexes - private static bool[] GetPermitList(int max, ReadOnlySpan allowed) - { - var result = new bool[max + 1]; - foreach (var index in allowed) - result[index] = true; - return result; - } - - /// - /// Gets a permit list with the permitted indexes, then un-flags the indexes that are not permitted. - /// - /// Maximum index expected to allow - /// Allowed indexes (may have some disallowed) - /// Disallowed indexes - private static bool[] GetPermitList(int max, ReadOnlySpan allowed, ReadOnlySpan disallow) - { - var result = GetPermitList(max, allowed); - foreach (var index in disallow) - result[index] = false; - return result; - } -} diff --git a/PKHeX.Core/Legality/Tables/Tables1.cs b/PKHeX.Core/Legality/Tables/Tables1.cs deleted file mode 100644 index c197a9349..000000000 --- a/PKHeX.Core/Legality/Tables/Tables1.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_1 = 151; - internal const int MaxMoveID_1 = 165; - internal const int MaxItemID_1 = 255; - internal const int MaxAbilityID_1 = 0; -} diff --git a/PKHeX.Core/Legality/Tables/Tables2.cs b/PKHeX.Core/Legality/Tables/Tables2.cs deleted file mode 100644 index 13d7d06bd..000000000 --- a/PKHeX.Core/Legality/Tables/Tables2.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_2 = 251; - internal const int MaxMoveID_2 = 251; - internal const int MaxItemID_2 = 255; - internal const int MaxAbilityID_2 = 0; - - internal static readonly ushort[] HeldItems_GSC = ItemStorage2.GetAllHeld(); - - internal static readonly bool[] ReleasedHeldItems_2 = GetPermitList(MaxItemID_2, HeldItems_GSC); -} diff --git a/PKHeX.Core/Legality/Tables/Tables3.cs b/PKHeX.Core/Legality/Tables/Tables3.cs deleted file mode 100644 index c852a9bac..000000000 --- a/PKHeX.Core/Legality/Tables/Tables3.cs +++ /dev/null @@ -1,67 +0,0 @@ -using System.Collections.Generic; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesIndex_3 = 412; - internal const int MaxSpeciesID_3 = 386; - internal const int MaxMoveID_3 = 354; - internal const int MaxItemID_3 = 374; - internal const int MaxItemID_3_COLO = 547; - internal const int MaxItemID_3_XD = 593; - internal const int MaxAbilityID_3 = 77; - internal const int MaxBallID_3 = 0xC; - internal const int MaxGameID_3 = 15; // CXD - - #region RS - - internal static readonly ushort[] HeldItems_RS = ItemStorage3RS.GetAllHeld(); - #endregion - - - internal static readonly bool[] ReleasedHeldItems_3 = GetPermitList(MaxItemID_3, HeldItems_RS, ItemStorage3RS.Unreleased); // Safari Ball - - // 064 is an unused location for Meteor Falls - // 084 is Inside of a truck, no possible pokemon can be hatched there - // 071 is Mirage island, cannot be obtained as the player is technically still on Route 130's map. - // 075 is an unused location for Fiery Path - // 077 is an unused location for Jagged Pass - internal static readonly HashSet ValidMet_RS = new() - { - 000, 001, 002, 003, 004, 005, 006, 007, 008, 009, - 010, 011, 012, 013, 014, 015, 016, 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, 065, 066, 067, 068, 069, - 070, 072, 073, 074, 076, 078, 079, - 080, 081, 082, 083, 085, 086, 087, - }; - - // 155 - 158 Sevii Isle 6-9 Unused - // 171 - 173 Sevii Isle 22-24 Unused - internal static readonly HashSet ValidMet_FRLG = new() - { - 087, 088, 089, - 090, 091, 092, 093, 094, 095, 096, 097, 098, 099, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, - }; - - internal static readonly HashSet ValidMet_E = new(ValidMet_RS) - { - 196, 197, 198, 199, - 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, - 210, 211, 212, - }; -} diff --git a/PKHeX.Core/Legality/Tables/Tables4.cs b/PKHeX.Core/Legality/Tables/Tables4.cs deleted file mode 100644 index be3a06e53..000000000 --- a/PKHeX.Core/Legality/Tables/Tables4.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System.Collections.Generic; -using System.Linq; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_4 = 493; - internal const int MaxMoveID_4 = 467; - internal const int MaxItemID_4_DP = 464; - internal const int MaxItemID_4_Pt = 467; - internal const int MaxItemID_4_HGSS = 536; - internal const int MaxAbilityID_4 = 123; - internal const int MaxBallID_4 = 0x18; - internal const int MaxGameID_4 = 15; // CXD - - internal static readonly ushort[] HeldItems_DP = ItemStorage4DP.GetAllHeld(); - internal static readonly ushort[] HeldItems_Pt = ItemStorage4Pt.GetAllHeld(); // Griseous Orb Added - internal static readonly ushort[] HeldItems_HGSS = HeldItems_Pt; - - internal static readonly bool[] ReleasedHeldItems_4 = GetPermitList(MaxItemID_4_HGSS, HeldItems_HGSS, ItemStorage4.Unreleased); - - internal static readonly HashSet ValidMet_DP = new() - { - // 063: Flower Paradise unreleased DP event - // 079: Newmoon Island unreleased DP event - // 085: Seabreak Path unreleased DP event - // 086: Hall of Origin unreleased event - 001, 002, 003, 004, 005, 006, 007, 008, 009, - 010, 011, 012, 013, 014, 015, 016, 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, 064, 065, 066, 067, 068, 069, - 070, 071, 072, 073, 074, 075, 076, 077, 078, - 080, 081, 082, 083, 084, 087, 088, 089, - 090, 091, 092, 093, 094, 095, 096, 097, 098, 099, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, - }; - - internal static readonly HashSet ValidMet_Pt = new(ValidMet_DP) - { - // 086: Hall of Origin unreleased event - 63, 79, 85, - 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, - }; - - internal static readonly HashSet ValidMet_HGSS = new() - { - 080, - 112, 113, 114, 115, 116, - 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, - 170, 172, 173, 174, 175, 176, 177, 178, 179, //171: Route 23 no longer exists - 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, 216, 217, 218, 219, - 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, - 230, 231, 232, 234, //233: Pokéwalker - }; - - internal static readonly HashSet ValidMet_4 = new(ValidMet_Pt.Concat(ValidMet_HGSS)); - - internal static readonly HashSet GiftEggLocation4 = new() - { - 2009, 2010, 2011, 2013, 2014, - }; - - internal static int GetTransfer45MetLocation(PKM pk) - { - // Everything except for crown beasts and Celebi get the default transfer location. - // Crown beasts and Celebi are 100% identifiable by the species ID and fateful encounter, originating from Gen4. - if (!pk.Gen4 || !pk.FatefulEncounter) - return Locations.Transfer4; // Pokétransfer - - return pk.Species switch - { - // Crown Beast - (int)Species.Raikou or (int)Species.Entei or (int)Species.Suicune => Locations.Transfer4_CrownUnused, - // Celebi - (int)Species.Celebi => Locations.Transfer4_CelebiUnused, - // Default - _ => Locations.Transfer4, - }; - } -} diff --git a/PKHeX.Core/Legality/Tables/Tables5.cs b/PKHeX.Core/Legality/Tables/Tables5.cs deleted file mode 100644 index 78408d100..000000000 --- a/PKHeX.Core/Legality/Tables/Tables5.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System.Collections.Generic; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_5 = 649; - internal const int MaxMoveID_5 = 559; - internal const int MaxItemID_5_BW = 632; - internal const int MaxItemID_5_B2W2 = 638; - internal const int MaxAbilityID_5 = 164; - internal const int MaxBallID_5 = 0x19; - internal const int MaxGameID_5 = 23; // B2 - - internal static readonly ushort[] HeldItems_BW = ItemStorage5.GetAllHeld(); - - internal static readonly bool[] ReleasedHeldItems_5 = GetPermitList(MaxItemID_5_B2W2, HeldItems_BW, ItemStorage5.Unreleased); - - internal static readonly HashSet ValidMet_BW = new() - { - 004, 005, 006, 007, 008, 009, - 010, 011, 012, 013, 014, 015, 016, 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, 095, 096, 097, 098, 099, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, - }; - - internal static readonly HashSet ValidMet_B2W2 = new() - { - 004, 005, 006, 007, 008, 009, - 010, 011, 012, 013, 014, 015, 016, 017, 018, 019, - 020, 021, 022, 024, 025, 026, 027, 028, 029, // 023 Route 10 - 030, 031, 032, 033, 034, 035, 036, 037, 038, 039, - 041, 042, 043, 044, 045, 046, 047, 048, 049, // 040->134 Victory Road - 050, 051, 052, 053, 054, 055, 056, 057, 058, // 059 Challenger's cave - 060, 061, 062, 063, 064, 065, 066, 067, 068, 069, - 070, 071, 072, 074, 075, 076, 077, 078, 079, // 073 Trial Chamber - 080, 081, 082, 083, 084, 085, 086, 087, 088, 089, - 090, 091, 092, 093, 094, 095, 096, 097, 098, 099, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, - 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 139, // 138 --- - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, - }; -} diff --git a/PKHeX.Core/Legality/Tables/Tables6.cs b/PKHeX.Core/Legality/Tables/Tables6.cs deleted file mode 100644 index ad303263c..000000000 --- a/PKHeX.Core/Legality/Tables/Tables6.cs +++ /dev/null @@ -1,64 +0,0 @@ -using System.Collections.Generic; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_6 = 721; - internal const int MaxMoveID_6_XY = 617; - internal const int MaxMoveID_6_AO = 621; - internal const int MaxItemID_6_XY = 717; - internal const int MaxItemID_6_AO = 775; - internal const int MaxAbilityID_6_XY = 188; - internal const int MaxAbilityID_6_AO = 191; - internal const int MaxBallID_6 = 0x19; - internal const int MaxGameID_6 = 27; // OR - - internal static readonly ushort[] HeldItem_AO = ItemStorage6XY.GetAllHeld(); - - internal static readonly HashSet ValidMet_XY = new() - { - 006, 008, - 010, 012, 014, 016, 018, - 020, 022, 024, 026, 028, - 030, 032, 034, 036, 038, - 040, 042, 044, 046, 048, - 050, 052, 054, 056, 058, - 060, 062, 064, 066, 068, - 070, 072, 074, 076, 078, - 082, 084, 086, 088, - 090, 092, 094, 096, 098, - 100, 102, 104, 106, 108, - 110, 112, 114, 116, 118, - 120, 122, 124, 126, 128, - 130, 132, 134, 136, 138, - 140, 142, 144, 146, 148, - 150, 152, 154, 156, 158, - 160, 162, 164, 166, 168, - }; - - internal static readonly HashSet ValidMet_AO = new() - { - 170, 172, 174, 176, 178, - 180, 182, 184, 186, 188, - 190, 192, 194, 196, 198, - 200, 202, 204, 206, 208, - 210, 212, 214, 216, 218, - 220, 222, 224, 226, 228, - 230, 232, 234, 236, 238, - 240, 242, 244, 246, 248, - 250, 252, 254, 256, 258, - 260, 262, 264, 266, 268, - 270, 272, 274, 276, 278, - 280, 282, 284, 286, 288, - 290, 292, 294, 296, 298, - 300, 302, 304, 306, 308, - 310, 312, 314, 316, 318, - 320, 322, 324, 326, 328, - 330, 332, 334, 336, 338, - 340, 342, 344, 346, - 350, 352, 354, - }; - - internal static readonly bool[] ReleasedHeldItems_6 = GetPermitList(MaxItemID_6_AO, HeldItem_AO, ItemStorage6XY.Unreleased); -} diff --git a/PKHeX.Core/Legality/Tables/Tables7.cs b/PKHeX.Core/Legality/Tables/Tables7.cs deleted file mode 100644 index a0ef58f53..000000000 --- a/PKHeX.Core/Legality/Tables/Tables7.cs +++ /dev/null @@ -1,174 +0,0 @@ -using System.Collections.Generic; -using static PKHeX.Core.Species; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_7 = 802; - internal const int MaxMoveID_7 = 719; - internal const int MaxItemID_7 = 920; - internal const int MaxAbilityID_7 = 232; - internal const int MaxBallID_7 = 0x1A; // 26 - internal const int MaxGameID_7 = 41; // Crystal (VC?) - - internal const int MaxSpeciesID_7_USUM = 807; - internal const int MaxMoveID_7_USUM = 728; - internal const int MaxItemID_7_USUM = 959; - internal const int MaxAbilityID_7_USUM = 233; - - private static Dictionary GetDictionary(IReadOnlyList key, IReadOnlyList held) - { - var result = new Dictionary(held.Count); - for (int i = 0; i < key.Count; i++) - result.Add(key[i], held[i]); - return result; - } - - internal static readonly ushort[] HeldItems_SM = ItemStorage7SM.GetAllHeld(); - internal static readonly ushort[] HeldItems_USUM = ItemStorage7USUM.GetAllHeld(); - - internal static readonly HashSet AlolanOriginForms = new() - { - (int)Rattata, - (int)Raticate, - (int)Sandshrew, - (int)Sandslash, - (int)Vulpix, - (int)Ninetales, - (int)Diglett, - (int)Dugtrio, - (int)Meowth, - (int)Persian, - (int)Geodude, - (int)Graveler, - (int)Golem, - (int)Grimer, - (int)Muk, - }; - - internal static readonly HashSet AlolanVariantEvolutions12 = new() - { - (int)Raichu, - (int)Exeggutor, - (int)Marowak, - }; - - public static readonly HashSet PastGenAlolanNatives = new() - { - 010, 011, 012, 019, 020, 021, 022, 025, 026, 027, 028, 035, 036, 037, 038, 039, 040, 041, 042, 046, 047, 050, - 051, 052, 053, 054, 055, 056, 057, 058, 059, 060, 061, 062, 063, 064, 065, 066, 067, 068, 072, 073, 074, 075, - 076, 079, 080, 081, 082, 088, 089, 090, 091, 092, 093, 094, 096, 097, 102, 103, 104, 105, 113, 115, 118, 119, - 120, 121, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 142, 143, 147, 148, 149, 165, - 166, 167, 168, 169, 170, 171, 172, 173, 174, 185, 186, 196, 197, 198, 199, 200, 209, 210, 212, 215, 222, 225, - 227, 233, 235, 239, 240, 241, 242, 278, 279, 283, 284, 296, 297, 299, 302, 318, 319, 320, 321, 324, 327, 328, - 329, 330, 339, 340, 349, 350, 351, 359, 361, 362, 369, 370, 371, 372, 373, 374, 375, 376, 408, 409, 410, 411, - 422, 423, 425, 426, 429, 430, 438, 440, 443, 444, 445, 446, 447, 448, 456, 457, 461, 462, 466, 467, 470, 471, - 474, 476, 478, 506, 507, 508, 524, 525, 526, 546, 547, 548, 549, 551, 552, 553, 564, 565, 566, 567, 568, 569, - 582, 583, 584, 587, 594, 627, 628, 629, 630, 661, 662, 663, 674, 675, 700, 703, 704, 705, 706, 707, 708, 709, - 718, - - // Regular - 023, 086, 108, 122, 138, 140, 163, 177, 179, 190, 204, - 206, 214, 223, 228, 238, 246, 303, 309, 341, 343, - 345, 347, 352, 353, 357, 366, 427, 439, 458, 550, - 559, 570, 572, 592, 605, 619, 621, 622, 624, 636, - 667, 669, 676, 686, 690, 692, 696, 698, 701, 702, - 714, - - // Wormhole - 333, 334, // Altaria - 193, 469, // Yanmega - 561, // Sigilyph - 580, 581, // Swanna - 276, 277, // Swellow - 451, 452, // Drapion - 531, // Audino - 694, 695, // Heliolisk - 273, 274, 275, // Nuzleaf - 325, 326, // Gumpig - 459, 460, // Abomasnow - 307, 308, // Medicham - 449, 450, // Hippowdon - 557, 558, // Crustle - 218, 219, // Magcargo - 688, 689, // Barbaracle - 270, 271, 272, // Lombre - 618, // Stunfisk - 418, 419, // Floatzel - 194, 195, // Quagsire - - 100, 101, // Voltorb & Electrode - }; - - internal static readonly HashSet Totem_Alolan = new() - { - (int)Raticate, // (Normal, Alolan, Totem) - (int)Marowak, // (Normal, Alolan, Totem) - (int)Mimikyu, // (Normal, Busted, Totem, Totem_Busted) - }; - - internal static readonly HashSet Totem_NoTransfer = new() - { - (int)Marowak, - (int)Araquanid, - (int)Togedemaru, - (int)Ribombee, - }; - - internal static readonly HashSet Totem_USUM = new() - { - (int)Raticate, - (int)Gumshoos, - //(int)Wishiwashi, - (int)Salazzle, - (int)Lurantis, - (int)Vikavolt, - (int)Mimikyu, - (int)Kommoo, - (int)Marowak, - (int)Araquanid, - (int)Togedemaru, - (int)Ribombee, - }; - - internal static readonly HashSet ValidMet_SM = new() - { - 006, 008, - 010, 012, 014, 016, 018, - 020, 022, 024, 026, 028, - 030, 032, 034, 036, 038, - 040, 042, 044, 046, 048, - 050, 052, 054, 056, 058, - 060, 062, 064, 068, - 070, 072, 074, 076, 078, - 082, 084, 086, 088, - 090, 092, 094, - 100, 102, 104, 106, 108, - 110, 112, 114, 116, 118, - 120, 122, 124, 126, 128, - 130, 132, 134, 136, 138, - 140, 142, 144, 146, 148, - 150, 152, 154, 156, 158, - 160, 162, 164, 166, 168, - 170, 172, 174, 176, 178, - 180, 182, 184, 186, 188, - 190, 192, - - Locations.Pelago7, // 30016 - }; - - internal static readonly HashSet ValidMet_USUM = new(ValidMet_SM) - { - // 194, 195, 196, 197, // Unobtainable new Locations - 198, - 200, 202, 204, 206, 208, - 210, 212, 214, 216, 218, - 220, 222, 224, 226, 228, - 230, 232, - }; - - #region Unreleased Items - internal static readonly bool[] ReleasedHeldItems_7 = GetPermitList(MaxItemID_7_USUM, HeldItems_USUM, ItemStorage7SM.Unreleased); - #endregion -} diff --git a/PKHeX.Core/Legality/Tables/Tables7b.cs b/PKHeX.Core/Legality/Tables/Tables7b.cs deleted file mode 100644 index d9f68bc7c..000000000 --- a/PKHeX.Core/Legality/Tables/Tables7b.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_7b = 809; // Melmetal - internal const int MaxMoveID_7b = 742; // Double Iron Bash - internal const int MaxItemID_7b = 1057; // Magmar Candy - internal const int MaxBallID_7b = (int)Ball.Beast; - internal const int MaxGameID_7b = (int)GameVersion.GE; - internal const int MaxAbilityID_7b = MaxAbilityID_7_USUM; - internal static readonly ushort[] HeldItems_GG = Array.Empty(); - public const byte AwakeningMax = 200; - - #region Moves - - public static bool IsAllowedMoveGG(ushort move) => AllowedMovesGG.BinarySearch(move) >= 0; - - private static ReadOnlySpan AllowedMovesGG => new ushort[] - { - 000, 001, 002, 003, 004, 005, 006, 007, 008, 009, - 010, 011, 012, 013, 014, 015, 016, 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, 095, 096, 097, 098, 099, - 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, - 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, - 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, - 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, - 160, 161, 162, 163, 164, - - 182, 188, 200, 224, 227, 231, 242, 243, 247, 252, - 257, 261, 263, 269, 270, 276, 280, 281, 339, 347, - 355, 364, 369, 389, 394, 398, 399, 403, 404, 405, - 406, 417, 420, 430, 438, 446, 453, 483, 492, 499, - 503, 504, 525, 529, 583, 585, 603, 605, 606, 607, - 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, - 740, 742, - }; - - #endregion -} diff --git a/PKHeX.Core/Legality/Tables/Tables8.cs b/PKHeX.Core/Legality/Tables/Tables8.cs deleted file mode 100644 index 87b300f40..000000000 --- a/PKHeX.Core/Legality/Tables/Tables8.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.Collections.Generic; - -namespace PKHeX.Core; - -public static partial class Legal -{ - // Current Binaries - internal const int MaxSpeciesID_8 = MaxSpeciesID_8_R2; - internal const int MaxMoveID_8 = MaxMoveID_8_R2; - internal const int MaxItemID_8 = MaxItemID_8_R2; - internal const int MaxAbilityID_8 = MaxAbilityID_8_R2; - - // Orion (No DLC) - internal const int MaxSpeciesID_8_O0 = 890; // Eternatus - internal const int MaxMoveID_8_O0 = 796; // Steel Beam - internal const int MaxItemID_8_O0 = 1278; // Rotom Catalog, ignore all catalog parts - internal const int MaxAbilityID_8_O0 = 258; // Hunger Switch - - // Rigel 1 (DLC 1: Isle of Armor) - internal const int MaxSpeciesID_8_R1 = 893; // Zarude - internal const int MaxMoveID_8_R1 = 818; // Surging Strikes - internal const int MaxItemID_8_R1 = 1589; // Mark Charm - internal const int MaxAbilityID_8_R1 = 260; // Unseen Fist - - // Rigel 2 (DLC 2: Crown Tundra) - internal const int MaxSpeciesID_8_R2 = 898; // Calyrex - internal const int MaxMoveID_8_R2 = 826; // Eerie Spell - internal const int MaxItemID_8_R2 = 1607; // Reins of Unity - internal const int MaxAbilityID_8_R2 = 267; // As One (Glastrier) - - internal const int MaxBallID_8 = 0x1A; // 26 Beast - internal const int MaxGameID_8 = 45; // Shield - - internal static readonly ushort[] HeldItems_SWSH = ItemStorage8SWSH.GetAllHeld(); - - internal static readonly HashSet GalarOriginForms = new() - { - (int)Species.Meowth, - (int)Species.Ponyta, - (int)Species.Rapidash, - (int)Species.Slowpoke, - (int)Species.Farfetchd, - (int)Species.MrMime, - (int)Species.Corsola, - (int)Species.Zigzagoon, - (int)Species.Linoone, - (int)Species.Yamask, - (int)Species.Darumaka, - (int)Species.Darmanitan, - (int)Species.Stunfisk, - }; - - internal static readonly HashSet GalarVariantFormEvolutions = new() - { - (int)Species.MrMime, - (int)Species.Weezing, - }; - - internal static readonly HashSet ValidMet_SWSH = new() - { - 006, 008, - 012, 014, 016, 018, - 020, 022, 024, 028, - 030, 032, 034, 036, - 040, 044, 046, 048, - 052, 054, 056, 058, - 060, 064, 066, 068, - 070, 072, 076, 078, - 080, 084, 086, 088, - 090, 092, 094, 096, 098, - 102, 104, 106, 108, - 110, 112, 114, 116, 118, - 120, 122, 124, 126, 128, - 130, 132, 134, 136, 138, - 140, 142, 144, 146, 148, - 150, 152, 154, 156, 158, - 160, 164, 166, 168, - 170, 172, 174, 176, 178, - 180, 182, 184, 186, 188, - 190, 192, 194, 196, 198, - 200, - - 202, 204, 206, 208, 210, - 212, 214, 216, 218, 220, - 222, 224, 226, 228, 230, - 232, 234, 236, 238, 240, - 242, 244, 246, - }; - - #region Unreleased Items - - private const int DMAX_START = 1279; - private const int DMAX_END = 1578; - private const int DMAX_LEGAL_END = 1290; // ★Sgr7194 (Eevee) - public static bool IsDynamaxCrystal(ushort item) => item is >= DMAX_START and <= DMAX_END; - public static bool IsDynamaxCrystalAvailable(ushort item) => item is >= DMAX_START and <= DMAX_LEGAL_END; - - internal static readonly bool[] ReleasedHeldItems_8 = GetPermitList(MaxItemID_8, HeldItems_SWSH, ItemStorage8SWSH.Unreleased); - #endregion -} diff --git a/PKHeX.Core/Legality/Tables/Tables8a.cs b/PKHeX.Core/Legality/Tables/Tables8a.cs deleted file mode 100644 index 0fabb4257..000000000 --- a/PKHeX.Core/Legality/Tables/Tables8a.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_8a = (int)Species.Enamorus; - internal const int MaxMoveID_8a = (int)Move.TakeHeart; - internal const int MaxItemID_8a = 1828; // Legend Plate - internal const int MaxBallID_8a = (int)Ball.LAOrigin; - internal const int MaxGameID_8a = (int)GameVersion.SP; - internal const int MaxAbilityID_8a = MaxAbilityID_8_R2; - - internal static readonly ushort[] HeldItems_LA = Array.Empty(); -} diff --git a/PKHeX.Core/Legality/Tables/Tables8bs.cs b/PKHeX.Core/Legality/Tables/Tables8bs.cs deleted file mode 100644 index 2e896d0e4..000000000 --- a/PKHeX.Core/Legality/Tables/Tables8bs.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System.Collections.Generic; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_8b = MaxSpeciesID_4; // Arceus-493 - internal const int MaxMoveID_8b = MaxMoveID_8_R2; - internal const int MaxItemID_8b = 1822; // DS Sounds - internal const int MaxBallID_8b = (int)Ball.LAOrigin; - internal const int MaxGameID_8b = (int)GameVersion.SP; - internal const int MaxAbilityID_8b = MaxAbilityID_8_R2; - - internal static readonly ushort[] HeldItems_BS = ItemStorage8BDSP.GetAll(); - - #region Unreleased Items - internal static readonly bool[] ReleasedHeldItems_8b = GetPermitList(MaxItemID_8b, HeldItems_BS, ItemStorage8BDSP.Unreleased); - #endregion - - private const int MaxValidHatchLocation8b = 657; - - public static bool IsValidEggHatchLocation8b(ushort location, GameVersion version) - { - if ((uint)location > MaxValidHatchLocation8b) - return false; - var loc16 = location; - if (LocationsNoHatchBDSP.Contains(loc16)) - return false; - - // Check if the location isn't an exclusive location that is only accessible in the other game. - var table = version == GameVersion.BD ? LocationsExclusiveSP : LocationsExclusiveBD; - return !table.Contains(loc16); - } - - private static readonly HashSet LocationsExclusiveBD = new() - { - 216, // Spear Pillar - 218, // Hall of Origin - 498, // Ramanas Park (Johto Room) - 503, // Ramanas Park (Rainbow Room) - 650, // Ramanas Park (Johto Room) - 655, // Ramanas Park (Rainbow Room) - }; - - private static readonly HashSet LocationsExclusiveSP = new() - { - 217, // Spear Pillar - 497, // Ramanas Park (Kanto Room) - 504, // Ramanas Park (Squall Room) - 618, // Hall of Origin - 649, // Ramanas Park (Kanto Room) - 656, // Ramanas Park (Squall Room) - }; - - private static readonly HashSet LocationsNoHatchBDSP = new() - { - 094, 103, 107, // Hearthome City - 154, 155, 158, // Sunyshore City - 181, 182, 183, // Pokémon League - 329, // Lake Acuity - 337, 338, // Battle Park - 339, 340, 341, 342, 343, 344, // Battle Tower - 345, 353, 421, // Mystery Zone - 474, // Resort Area - 483, 484, // Mystery Zone - 491, 492, 493, // Mystery Zone - 495, // Ramanas Park - 620, 621, 622, 623, // Grand Underground (Secret Base) - 625, // Sea (sailing animation) - 627, 628, 629, 630, 631, 632, // Grand Underground (Secret Base) - 633, 634, 635, 636, 637, 638, // Grand Underground (Secret Base) - 639, 640, 641, 642, 643, 644, // Grand Underground (Secret Base) - 645, 646, 647, // Grand Underground (Secret Base) - }; -} diff --git a/PKHeX.Core/Legality/Tables/Tables9.cs b/PKHeX.Core/Legality/Tables/Tables9.cs deleted file mode 100644 index 9d9aa1b95..000000000 --- a/PKHeX.Core/Legality/Tables/Tables9.cs +++ /dev/null @@ -1,50 +0,0 @@ -using System.Collections.Generic; - -namespace PKHeX.Core; - -public static partial class Legal -{ - internal const int MaxSpeciesID_9 = (int)Species.IronLeaves; - internal const int MaxMoveID_9 = (int)Move.MagicalTorque; - internal const int MaxItemID_9 = 2400; // Yellow Dish - internal const int MaxAbilityID_9 = (int)Ability.MyceliumMight; - - internal const int MaxBallID_9 = (int)Ball.LAOrigin; - internal const int MaxGameID_9 = (int)GameVersion.VL; - - internal static readonly ushort[] HeldItems_SV = ItemStorage9SV.GetAllHeld(); - - internal static readonly HashSet ValidMet_SV = new() - { - 006, - 010, 012, 014, 016, 018, - 020, 022, 024, 026, 028, - 030, 032, 034, 036, 038, - 040, 044, 046, 048, - 050, 052, 056, 058, - 060, 062, 064, - - 067, 069, 070, 072, 076, - 078, 080, 082, 084, 086, - 088, 090, 092, 094, 096, - - 099, 101, 103, 105, 107, - 109, 111, 113, 115, 117, - 118, 124, 130, - 131, - }; - - public static bool IsValidEggHatchLocation9(ushort location, GameVersion version) - { - if (version == GameVersion.SL && location == 131) // Uva Academy does not exist in Scarlet - return false; - if (version == GameVersion.VL && location == 130) // Naranja Academy does not exist in Violet - return false; - return ValidMet_SV.Contains(location); - } - - #region Unreleased Items - - internal static readonly bool[] ReleasedHeldItems_9 = GetPermitList(MaxItemID_9, HeldItems_SV, ItemStorage9SV.Unreleased); - #endregion -} diff --git a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs index d37908096..856e0e92f 100644 --- a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs @@ -179,35 +179,6 @@ private CheckResult VerifyForm(LegalityAnalysis data) if (FormInfo.IsBattleOnlyForm(species, form, format)) return GetInvalid(LFormBattle); - if (form == 0) - return VALID; - - // everything below here is not Form 0, so it has a form. - if (format >= 7 && Info.Generation < 7) - { - if (species == 25 || Legal.AlolanOriginForms.Contains(species) || Legal.AlolanVariantEvolutions12.Contains(enc.Species)) - return GetInvalid(LFormInvalidGame); - } - if (format >= 8 && Info.Generation < 8) - { - var orig = enc.Species; - if (Legal.GalarOriginForms.Contains(species) || Legal.GalarVariantFormEvolutions.Contains(orig)) - { - if (species == (int)Meowth && enc.Form != 2) - { - // We're okay here. There's also Alolan Meowth... - } - else if (((Species)orig is MrMime or MimeJr) && pk.CurrentLevel > enc.LevelMin && Info.Generation >= 4) - { - // We're okay with a Mime Jr. that has evolved via level up. - } - else if (enc.Version != GameVersion.GO) - { - return GetInvalid(LFormInvalidGame); - } - } - } - return VALID; } diff --git a/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs b/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs index cd7b62f4f..a0d001131 100644 --- a/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/GenderVerifier.cs @@ -57,9 +57,8 @@ private static bool IsValidGenderPID(LegalityAnalysis data) return IsValidGenderMismatch(pk); // check for mixed->fixed gender incompatibility by checking the gender of the original species - var original = data.EncounterMatch.Species; - if (Legal.FixedGenderFromBiGender.Contains(original)) - return IsValidFixedGenderFromBiGender(pk, original); + if (SpeciesCategory.IsFixedGenderFromDual(pk.Species)) + return IsValidFixedGenderFromBiGender(pk, data.EncounterMatch.Species); return true; } diff --git a/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs b/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs index 632711e02..c47d789ea 100644 --- a/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/LegendsArceusVerifier.cs @@ -82,10 +82,8 @@ private static void CheckLearnset(LegalityAnalysis data, PA8 pa) private static int LoadBareMinimumMoveset(ISpeciesForm enc, EvolutionHistory h, PA8 pa, Span moves) { // Get any encounter moves - var pt = PersonalTable.LA; - var index = pt.GetFormIndex(enc.Species, enc.Form); - var learn = Legal.LevelUpLA; - var moveset = learn[index]; + var ls = LearnSource8LA.Instance; + var moveset = ls.GetLearnset(enc.Species, enc.Form); if (enc is IMasteryInitialMoveShop8 ms) ms.LoadInitialMoveset(pa, moves, moveset, pa.Met_Level); else @@ -114,8 +112,7 @@ private static int LoadBareMinimumMoveset(ISpeciesForm enc, EvolutionHistory h, for (int i = 0; i < evos.Length - 1; i++) { var evo = evos[i]; - var x = pt.GetFormIndex(evo.Species, evo.Form); - var m = learn[x]; + var m = ls.GetLearnset(evo.Species, evo.Form); m.SetEvolutionMoves(moves, purchased, count); count = moves.IndexOf((ushort)0); if ((uint)count >= 4) @@ -123,8 +120,7 @@ private static int LoadBareMinimumMoveset(ISpeciesForm enc, EvolutionHistory h, } // Any tutored moves we don't know about?? - var currentIndex = pt.GetFormIndex(evos[0].Species, evos[0].Form); - var currentLearn = learn[currentIndex]; + var currentLearn = ls.GetLearnset(evos[0].Species, evos[0].Form); return AddMasteredMissing(pa, moves, count, moveset, currentLearn, level); } @@ -230,9 +226,7 @@ private static bool CanLearnMoveByLevelUp(LegalityAnalysis data, PA8 pa, int i, int level = 101; foreach (var evo in data.Info.EvoChainsAllGens.Gen8a) { - var pt = PersonalTable.LA; - var index = pt.GetFormIndex(evo.Species, evo.Form); - var moveset = Legal.LevelUpLA[index]; + var moveset = LearnSource8LA.Instance.GetLearnset(evo.Species, evo.Form); var lvl = moveset.GetLevelLearnMove(moves[i]); if (lvl == -1) continue; // cannot learn via level up diff --git a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonRules.cs b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonRules.cs index 90767fb8a..ad5717670 100644 --- a/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonRules.cs +++ b/PKHeX.Core/Legality/Verifiers/Ribbons/RibbonRules.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using static PKHeX.Core.Species; namespace PKHeX.Core; @@ -101,7 +103,7 @@ private static bool IsRibbonValidMasterRankSWSH(PKM pk, IEncounterTemplate enc) { // Ranked is still ongoing, but the use of Mythicals was restricted to Series 13 only. var met = pk.MetDate; - if (Legal.Mythicals.Contains(pk.Species) && met > new DateOnly(2022, 11, 1)) + if (SpeciesCategory.IsMythical(pk.Species) && met > new DateOnly(2022, 11, 1)) return false; } @@ -113,9 +115,9 @@ private static bool IsRibbonValidMasterRankSWSH(PKM pk, IEncounterTemplate enc) private static bool IsRibbonValidMasterRankSV(ISpeciesForm pk) { var species = pk.Species; - if (Legal.Mythicals.Contains(species)) + if (SpeciesCategory.IsMythical(species)) return false; - if (Legal.Legends.Contains(species)) + if (SpeciesCategory.IsLegendary(species)) return false; var pt = PersonalTable.SV; @@ -146,7 +148,7 @@ public static bool IsRibbonValidTowerMaster(EvolutionHistory evos) if (!evos.HasVisitedBDSP) return false; // Mythicals cannot be used in BD/SP's Battle Tower - return !Legal.Mythicals.Contains(evos.Gen8b[0].Species); + return !SpeciesCategory.IsMythical(evos.Gen8b[0].Species); } /// @@ -360,7 +362,7 @@ public static bool IsAllowedContest4(EvolutionHistory evos) /// /// Checks if the input species could have participated in any Battle Frontier trial. /// - public static bool IsAllowedBattleFrontier(ushort species) => !Legal.BattleFrontierBanlist.Contains(species); + public static bool IsAllowedBattleFrontier(ushort species) => !BattleFrontierBanlist.Contains(species); /// /// Checks if the input species could have participated in Generation 4's Battle Frontier. @@ -382,4 +384,20 @@ public static bool IsAllowedBattleFrontier(ushort species, byte form, EntityCont return false; return IsAllowedBattleFrontier(species); } + + /// + /// Generation 3 & 4 Battle Frontier Species banlist. When referencing this in context to generation 4, be sure to disallow with Form 1 (Spiky). + /// + public static readonly HashSet BattleFrontierBanlist = new() + { + (int)Mewtwo, (int)Mew, + (int)Lugia, (int)HoOh, (int)Celebi, + (int)Kyogre, (int)Groudon, (int)Rayquaza, (int)Jirachi, (int)Deoxys, + (int)Dialga, (int)Palkia, (int)Giratina, (int)Phione, (int)Manaphy, (int)Darkrai, (int)Shaymin, (int)Arceus, + (int)Victini, (int)Reshiram, (int)Zekrom, (int)Kyurem, (int)Keldeo, (int)Meloetta, (int)Genesect, + (int)Xerneas, (int)Yveltal, (int)Zygarde, (int)Diancie, (int)Hoopa, (int)Volcanion, + (int)Cosmog, (int)Cosmoem, (int)Solgaleo, (int)Lunala, (int)Necrozma, (int)Magearna, (int)Marshadow, (int)Zeraora, + (int)Meltan, (int)Melmetal, + (int)Koraidon, (int)Miraidon, + }; } diff --git a/PKHeX.Core/Moves/MoveInfo7b.cs b/PKHeX.Core/Moves/MoveInfo7b.cs index aa495f35c..b55b3da02 100644 --- a/PKHeX.Core/Moves/MoveInfo7b.cs +++ b/PKHeX.Core/Moves/MoveInfo7b.cs @@ -51,4 +51,35 @@ internal static class MoveInfo7b 05, 15, 05, 01, 01, 01, 01, 01, 01, 15, 15, 15, 20, 15, 15, 15, 15, 15, 15, 15, 15, 20, 05, }; + + public static bool IsAllowedMoveGG(ushort move) => AllowedMovesGG.BinarySearch(move) >= 0; + + private static ReadOnlySpan AllowedMovesGG => new ushort[] + { + 000, 001, 002, 003, 004, 005, 006, 007, 008, 009, + 010, 011, 012, 013, 014, 015, 016, 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, 095, 096, 097, 098, 099, + 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, + 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, + 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, + 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, + 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, + 160, 161, 162, 163, 164, + + 182, 188, 200, 224, 227, 231, 242, 243, 247, 252, + 257, 261, 263, 269, 270, 276, 280, 281, 339, 347, + 355, 364, 369, 389, 394, 398, 399, 403, 404, 405, + 406, 417, 420, 430, 438, 446, 453, 483, 492, 499, + 503, 504, 525, 529, 583, 585, 603, 605, 606, 607, + 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, + 740, 742, + }; } diff --git a/PKHeX.Core/MysteryGifts/PGF.cs b/PKHeX.Core/MysteryGifts/PGF.cs index b1932155d..125bf0130 100644 --- a/PKHeX.Core/MysteryGifts/PGF.cs +++ b/PKHeX.Core/MysteryGifts/PGF.cs @@ -247,7 +247,8 @@ public override PK5 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) if (Move1 == 0) // No moves defined { Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, Species, Form, Level, (GameVersion)pk.Version); + var source = GameData.GetLearnSource((GameVersion)pk.Version); + source.SetEncounterMoves(Species, Form, Level, moves); pk.SetMoves(moves); } diff --git a/PKHeX.Core/MysteryGifts/WC3.cs b/PKHeX.Core/MysteryGifts/WC3.cs index b7f81e934..0e6d84c78 100644 --- a/PKHeX.Core/MysteryGifts/WC3.cs +++ b/PKHeX.Core/MysteryGifts/WC3.cs @@ -165,8 +165,18 @@ private void SetMoves(PK3 pk) { if (!Moves.HasMoves) // not completely defined { + var ver = (GameVersion)pk.Version; + ILearnSource ls = ver switch + { + GameVersion.R or GameVersion.S => LearnSource3RS.Instance, + GameVersion.FR => LearnSource3FR.Instance, + GameVersion.LG => LearnSource3LG.Instance, + _ => LearnSource3E.Instance, + }; + + var learn = ls.GetLearnset(Species, Form); Span moves = stackalloc ushort[4]; - MoveList.GetCurrentMoves(pk, Species, Form, (GameVersion)pk.Version, Level, moves); + learn.SetEncounterMoves(Level, moves); Moves = new(moves[0], moves[1], moves[2], moves[3]); } diff --git a/PKHeX.Core/PKM/Interfaces/IAwakened.cs b/PKHeX.Core/PKM/Interfaces/IAwakened.cs index 2b226d0cb..287f75816 100644 --- a/PKHeX.Core/PKM/Interfaces/IAwakened.cs +++ b/PKHeX.Core/PKM/Interfaces/IAwakened.cs @@ -16,8 +16,13 @@ public interface IAwakened byte AV_SPD { get; set; } } +/// +/// Logic for interacting with LGP/E Awakening values. +/// public static class AwakeningUtil { + public const byte AwakeningMax = 200; + /// /// Sums all values. /// @@ -34,7 +39,7 @@ public static class AwakeningUtil /// Sets all values to the maximum value. /// /// Data to set values for - public static void AwakeningMax(this IAwakened pk) => pk.AwakeningSetAllTo(Legal.AwakeningMax); + public static void AwakeningMaximize(this IAwakened pk) => pk.AwakeningSetAllTo(AwakeningMax); /// /// Sets all values to the specified value. @@ -63,7 +68,7 @@ public static void AwakeningMinimum(this IAwakened pk) /// Data to set values for /// Minimum value to set /// Maximum value to set - public static void AwakeningSetRandom(this IAwakened pk, byte min = 0, int max = Legal.AwakeningMax) + public static void AwakeningSetRandom(this IAwakened pk, byte min = 0, int max = AwakeningMax) { if (pk is not PB7 pb7) return; @@ -117,17 +122,17 @@ public static void AwakeningSetVisual(IAwakened pk, ReadOnlySpan value) /// Data to check public static bool AwakeningAllValid(this IAwakened pk) { - if (pk.AV_HP > Legal.AwakeningMax) + if (pk.AV_HP > AwakeningMax) return false; - if (pk.AV_ATK > Legal.AwakeningMax) + if (pk.AV_ATK > AwakeningMax) return false; - if (pk.AV_DEF > Legal.AwakeningMax) + if (pk.AV_DEF > AwakeningMax) return false; - if (pk.AV_SPE > Legal.AwakeningMax) + if (pk.AV_SPE > AwakeningMax) return false; - if (pk.AV_SPA > Legal.AwakeningMax) + if (pk.AV_SPA > AwakeningMax) return false; - if (pk.AV_SPD > Legal.AwakeningMax) + if (pk.AV_SPD > AwakeningMax) return false; return true; } @@ -189,12 +194,12 @@ public static void SetSuggestedAwakenedValues(this IAwakened a, PKM pk) { Span result = stackalloc byte[6]; SetExpectedMinimumAVs(result, (PB7)a); - a.AV_HP = Legal.AwakeningMax; - a.AV_ATK = pk.IV_ATK == 0 ? result[1] : Legal.AwakeningMax; - a.AV_DEF = Legal.AwakeningMax; - a.AV_SPA = Legal.AwakeningMax; - a.AV_SPD = Legal.AwakeningMax; - a.AV_SPE = pk.IV_SPE == 0 ? result[5] : Legal.AwakeningMax; + a.AV_HP = AwakeningMax; + a.AV_ATK = pk.IV_ATK == 0 ? result[1] : AwakeningMax; + a.AV_DEF = AwakeningMax; + a.AV_SPA = AwakeningMax; + a.AV_SPD = AwakeningMax; + a.AV_SPE = pk.IV_SPE == 0 ? result[5] : AwakeningMax; } public static bool IsAwakeningBelow(this IAwakened current, IAwakened initial) => !current.IsAwakeningAboveOrEqual(initial); diff --git a/PKHeX.Core/PKM/Interfaces/IBattleVersion.cs b/PKHeX.Core/PKM/Interfaces/IBattleVersion.cs index 16219cfc9..8a98cbdbf 100644 --- a/PKHeX.Core/PKM/Interfaces/IBattleVersion.cs +++ b/PKHeX.Core/PKM/Interfaces/IBattleVersion.cs @@ -38,7 +38,8 @@ public static void AdaptToBattleVersion(this IBattleVersion v, PKM pk, GameVersi pk.SetRelearnMoves(empty); Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, pk, pk.CurrentLevel, version); + var source = GameData.GetLearnSource(version); + source.SetEncounterMoves(pk.Species, pk.Form, pk.CurrentLevel, moves); pk.SetMoves(moves); pk.FixMoves(); v.BattleVersion = (byte)version; diff --git a/PKHeX.Core/PKM/PA8.cs b/PKHeX.Core/PKM/PA8.cs index 1cd4fffa4..dfebbad27 100644 --- a/PKHeX.Core/PKM/PA8.cs +++ b/PKHeX.Core/PKM/PA8.cs @@ -1055,11 +1055,7 @@ public void SanitizeImport() public void ResetMoves() { - var learnsets = Legal.LevelUpLA; - var table = PersonalTable.LA; - - var index = table.GetFormIndex(Species, Form); - var learn = learnsets[index]; + var learn = LearnSource8LA.Instance.GetLearnset(Species, Form); Span moves = stackalloc ushort[4]; learn.SetEncounterMoves(CurrentLevel, moves); SetMoves(moves); diff --git a/PKHeX.Core/PKM/PB8.cs b/PKHeX.Core/PKM/PB8.cs index 0d9477a60..93fdfb7f5 100644 --- a/PKHeX.Core/PKM/PB8.cs +++ b/PKHeX.Core/PKM/PB8.cs @@ -147,11 +147,7 @@ public override PA8 ConvertToPA8() public override void ResetMoves() { - var learnsets = Legal.LevelUpBDSP; - var table = PersonalTable.BDSP; - - var index = table.GetFormIndex(Species, Form); - var learn = learnsets[index]; + var learn = LearnSource8BDSP.Instance.GetLearnset(Species, Form); Span moves = stackalloc ushort[4]; learn.SetEncounterMoves(CurrentLevel, moves); SetMoves(moves); diff --git a/PKHeX.Core/PKM/PK1.cs b/PKHeX.Core/PKM/PK1.cs index 21b07b871..d85f830cd 100644 --- a/PKHeX.Core/PKM/PK1.cs +++ b/PKHeX.Core/PKM/PK1.cs @@ -147,9 +147,9 @@ private static bool IsValidCatchRateAnyPreEvo(byte species, byte rate) public PK2 ConvertToPK2() { PK2 pk2 = new(Japanese) {Species = Species}; - Array.Copy(Data, 0x7, pk2.Data, 0x1, 0x1A); - RawOT.CopyTo(pk2.RawOT, 0); - RawNickname.CopyTo(pk2.RawNickname, 0); + Data.AsSpan(7, 0x1A).CopyTo(pk2.Data.AsSpan(1)); + OT_Trash.CopyTo(pk2.OT_Trash); + Nickname_Trash.CopyTo(pk2.Nickname_Trash); pk2.HeldItem = Gen2Item; pk2.CurrentFriendship = pk2.PersonalInfo.BaseFriendship; @@ -184,7 +184,6 @@ public PK7 ConvertToPK7() Move4_PPUps = Move4_PPUps, Met_Location = Locations.Transfer1, // "Kanto region", hardcoded. Gender = Gender, - OT_Name = StringConverter12Transporter.GetString(RawOT, Japanese), IsNicknamed = false, CurrentHandler = 1, @@ -197,8 +196,7 @@ public PK7 ConvertToPK7() var lang = TransferLanguage(RecentTrainerCache.Language); pk7.Language = lang; pk7.Nickname = SpeciesName.GetSpeciesNameGeneration(pk7.Species, lang, pk7.Format); - if (RawOT[0] == StringConverter12.G1TradeOTCode) // In-game Trade - pk7.OT_Name = StringConverter12.G1TradeOTName[lang]; + pk7.OT_Name = OT_Trash[0] != StringConverter12.G1TradeOTCode ? StringConverter12Transporter.GetString(OT_Trash, Japanese) : StringConverter12.G1TradeOTName[lang]; // In-game Trade pk7.OT_Friendship = pk7.HT_Friendship = PersonalTable.SM[Species].BaseFriendship; // IVs @@ -232,7 +230,7 @@ public PK7 ConvertToPK7() else if (IsNicknamedBank) { pk7.IsNicknamed = true; - pk7.Nickname = StringConverter12Transporter.GetString(RawNickname, Japanese); + pk7.Nickname = StringConverter12Transporter.GetString(Nickname_Trash, Japanese); } pk7.SetTradeMemoryHT6(bank:true); // oh no, memories on gen7 pk diff --git a/PKHeX.Core/PKM/PK2.cs b/PKHeX.Core/PKM/PK2.cs index 709b1136c..8acaa638f 100644 --- a/PKHeX.Core/PKM/PK2.cs +++ b/PKHeX.Core/PKM/PK2.cs @@ -13,7 +13,7 @@ public sealed class PK2 : GBPKML, ICaughtData2 public override int SIZE_PARTY => PokeCrypto.SIZE_2PARTY; public override int SIZE_STORED => PokeCrypto.SIZE_2STORED; - public override bool Korean => !Japanese && RawOT[0] <= 0xB; + public override bool Korean => !Japanese && OT_Trash[0] <= 0xB; public override EntityContext Context => EntityContext.Gen2; @@ -200,12 +200,16 @@ public PK7 ConvertToPK7() else if (IsNicknamedBank) { pk7.IsNicknamed = true; - pk7.Nickname = Korean ? Nickname : StringConverter12Transporter.GetString(RawNickname, Japanese); + pk7.Nickname = Korean ? Nickname : StringConverter12Transporter.GetString(Nickname_Trash, Japanese); } - if (RawOT[0] == StringConverter12.G1TradeOTCode) // In-game Trade + + if (OT_Trash[0] == StringConverter12.G1TradeOTCode) // In-game Trade pk7.OT_Name = StringConverter12.G1TradeOTName[lang]; + else if (Korean) + pk7.OT_Name = OT_Name; else - pk7.OT_Name = Korean ? OT_Name : StringConverter12Transporter.GetString(RawOT, Japanese); + pk7.OT_Name = StringConverter12Transporter.GetString(OT_Trash, Japanese); + pk7.OT_Gender = OT_Gender; // Crystal pk7.OT_Friendship = pk7.HT_Friendship = PersonalTable.SM[Species].BaseFriendship; diff --git a/PKHeX.Core/PKM/PK4.cs b/PKHeX.Core/PKM/PK4.cs index 548f8acbb..d9e97f87c 100644 --- a/PKHeX.Core/PKM/PK4.cs +++ b/PKHeX.Core/PKM/PK4.cs @@ -346,7 +346,7 @@ public PK5 ConvertToPK5() WriteUInt32LittleEndian(pk5.Data.AsSpan(0x44), 0); // Met / Crown Data Detection - pk5.Met_Location = Legal.GetTransfer45MetLocation(pk5); + pk5.Met_Location = PK5.GetTransferMetLocation4(pk5); // Egg Location is not modified; when clearing Pt/HGSS egg data, the location will revert to Faraway Place // pk5.Egg_Location = Egg_Location; diff --git a/PKHeX.Core/PKM/PK5.cs b/PKHeX.Core/PKM/PK5.cs index b44df1fa1..7706aeb9c 100644 --- a/PKHeX.Core/PKM/PK5.cs +++ b/PKHeX.Core/PKM/PK5.cs @@ -555,4 +555,22 @@ private int CalculateAbilityIndex() pid >>= 16; return (int)(pid & 1); } + + internal static int GetTransferMetLocation4(PKM pk) + { + // Everything except for crown beasts and Celebi get the default transfer location. + // Crown beasts and Celebi are 100% identifiable by the species ID and fateful encounter, originating from Gen4. + if (!pk.Gen4 || !pk.FatefulEncounter) + return Locations.Transfer4; // Pokétransfer + + return pk.Species switch + { + // Crown Beast + (int)Core.Species.Raikou or (int)Core.Species.Entei or (int)Core.Species.Suicune => Locations.Transfer4_CrownUnused, + // Celebi + (int)Core.Species.Celebi => Locations.Transfer4_CelebiUnused, + // Default + _ => Locations.Transfer4, + }; + } } diff --git a/PKHeX.Core/PKM/PK8.cs b/PKHeX.Core/PKM/PK8.cs index 322277db1..bfcf15a7d 100644 --- a/PKHeX.Core/PKM/PK8.cs +++ b/PKHeX.Core/PKM/PK8.cs @@ -143,11 +143,7 @@ private static void UnmapLocation(PKM pk) public override void ResetMoves() { - var learnsets = Legal.LevelUpSWSH; - var table = PersonalTable.SWSH; - - var index = table.GetFormIndex(Species, Form); - var learn = learnsets[index]; + var learn = LearnSource8SWSH.Instance.GetLearnset(Species, Form); Span moves = stackalloc ushort[4]; learn.SetEncounterMoves(CurrentLevel, moves); SetMoves(moves); diff --git a/PKHeX.Core/PKM/PK9.cs b/PKHeX.Core/PKM/PK9.cs index cadba9e1a..f8e477214 100644 --- a/PKHeX.Core/PKM/PK9.cs +++ b/PKHeX.Core/PKM/PK9.cs @@ -611,11 +611,7 @@ private void TradeHT(ITrainerInfo tr) public void ResetMoves() { - var learnsets = Legal.LevelUpSV; - var table = PersonalTable.SV; - - var index = table.GetFormIndex(Species, Form); - var learn = learnsets[index]; + var learn = LearnSource9SV.Instance.GetLearnset(Species, Form); Span moves = stackalloc ushort[4]; learn.SetEncounterMoves(CurrentLevel, moves); SetMoves(moves); diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index fed0967b5..21c337fd1 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -952,13 +952,13 @@ public int GetFlawlessIVCount() if (gen >= 6) { var species = Species; - if (Legal.Mythicals.Contains(species)) + if (SpeciesCategory.IsMythical(species)) return 3; - if (Legal.Legends.Contains(species)) + if (SpeciesCategory.IsLegendary(species)) return 3; - if (Legal.SubLegends.Contains(species)) + if (SpeciesCategory.IsSubLegendary(species)) return 3; - if (gen <= 7 && Legal.IsUltraBeast(species)) + if (gen <= 7 && SpeciesCategory.IsUltraBeast(species)) return 3; } if (XY) diff --git a/PKHeX.Core/PKM/Shared/GBPKML.cs b/PKHeX.Core/PKM/Shared/GBPKML.cs index 28f2a0c9b..9d10027c4 100644 --- a/PKHeX.Core/PKM/Shared/GBPKML.cs +++ b/PKHeX.Core/PKM/Shared/GBPKML.cs @@ -14,8 +14,8 @@ public abstract class GBPKML : GBPKM public sealed override int MaxStringLengthNickname => Japanese ? 5 : 10; public sealed override bool Japanese => RawOT.Length == StringLengthJapanese; - internal readonly byte[] RawOT; - internal readonly byte[] RawNickname; + private readonly byte[] RawOT; + private readonly byte[] RawNickname; // Trash Bytes public sealed override Span Nickname_Trash => RawNickname; @@ -28,8 +28,8 @@ protected GBPKML(int size, bool jp = false) : base(size) // initialize string buffers RawOT = new byte[strLen]; RawNickname = new byte[strLen]; - RawOT.AsSpan().Fill(StringConverter12.G1TerminatorCode); - RawNickname.AsSpan().Fill(StringConverter12.G1TerminatorCode); + OT_Trash.Fill(StringConverter12.G1TerminatorCode); + Nickname_Trash.Fill(StringConverter12.G1TerminatorCode); } protected GBPKML(byte[] data, bool jp = false) : base(data) @@ -39,8 +39,8 @@ protected GBPKML(byte[] data, bool jp = false) : base(data) // initialize string buffers RawOT = new byte[strLen]; RawNickname = new byte[strLen]; - RawOT.AsSpan().Fill(StringConverter12.G1TerminatorCode); - RawNickname.AsSpan().Fill(StringConverter12.G1TerminatorCode); + OT_Trash.Fill(StringConverter12.G1TerminatorCode); + Nickname_Trash.Fill(StringConverter12.G1TerminatorCode); } public override void SetNotNicknamed(int language) => GetNonNickname(language, RawNickname); @@ -76,31 +76,31 @@ private int SetString(ReadOnlySpan value, Span destBuffer, int maxLe public sealed override string Nickname { - get => GetString(RawNickname); + get => GetString(Nickname_Trash); set { if (!IsNicknamed && Nickname == value) return; - SetStringKeepTerminatorStyle(value, RawNickname); + SetStringKeepTerminatorStyle(value, Nickname_Trash); } } public sealed override string OT_Name { - get => GetString(RawOT); + get => GetString(OT_Trash); set { if (value == OT_Name) return; - SetStringKeepTerminatorStyle(value, RawOT); + SetStringKeepTerminatorStyle(value, OT_Trash); } } private void SetStringKeepTerminatorStyle(ReadOnlySpan value, Span exist) { // Reset the destination buffer based on the termination style of the existing string. - bool zeroed = exist.IndexOf((byte)0) != -1; + bool zeroed = exist.Contains(0); StringConverterOption converterOption = (zeroed) ? StringConverterOption.ClearZero : StringConverterOption.Clear50; SetString(value, exist, value.Length, converterOption); } diff --git a/PKHeX.Core/PKM/Shared/PokeListGB.cs b/PKHeX.Core/PKM/Shared/PokeListGB.cs index 16aed210d..772207eb8 100644 --- a/PKHeX.Core/PKM/Shared/PokeListGB.cs +++ b/PKHeX.Core/PKM/Shared/PokeListGB.cs @@ -155,7 +155,7 @@ private void SetEntry(int base_ofs, int index) var pk = Pokemon[index]; Array.Copy(pk.Data, 0, Data, pkOfs, Entry_Size); - pk.RawOT.CopyTo(Data, otOfs); - pk.RawNickname.CopyTo(Data, nkOfs); + pk.OT_Trash.CopyTo(Data.AsSpan(otOfs)); + pk.Nickname_Trash.CopyTo(Data.AsSpan(nkOfs)); } } diff --git a/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs b/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs index ef4a780b8..94a48b981 100644 --- a/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs +++ b/PKHeX.Core/PKM/Util/Conversion/FormConverter.cs @@ -25,7 +25,7 @@ public static string[] GetFormList(ushort species, IReadOnlyList types, if (context.IsMegaGeneration() && IsFormListSingleMega(species)) return GetMegaSingle(types, forms); - if (context is Gen7 && Legal.Totem_USUM.Contains(species)) + if (context is Gen7 && FormInfo.HasTotemForm(species)) return GetFormsTotem(species, types, forms); return species switch @@ -670,35 +670,27 @@ private static string[] GetFormsArceus(ushort species, int generation, IReadOnly }; } - private static string[] GetFormsTotem(ushort species, IReadOnlyList types, IReadOnlyList forms) + private static string[] GetFormsTotem(ushort species, IReadOnlyList types, IReadOnlyList forms) => species switch { - if ((Species)species == Mimikyu) // Mimikyu + (int)Mimikyu => new[] { - return new[] - { - forms[(int)Mimikyu], // Disguised - forms[1058], // Busted - forms[1007], // Large - "*" + forms[1058], // Busted - }; - } - - if (Legal.Totem_Alolan.Contains(species)) + forms[(int)Mimikyu], // Disguised + forms[1058], // Busted + forms[1007], // Large + "*" + forms[1058], // Busted + }, + (int)Raticate or (int)Marowak => new[] { - return new[] - { - types[0], // Normal - forms[810], // Alolan - forms[1007], // Large - }; - } - - return new[] + types[0], // Normal + forms[810], // Alolan + forms[1007], // Large + }, + _ => new[] { types[0], // Normal forms[1007], // Large - }; - } + }, + }; private static string[] GetFormsUnown(int generation) => generation switch { diff --git a/PKHeX.Core/Saves/SAV1Stadium.cs b/PKHeX.Core/Saves/SAV1Stadium.cs index d43bad3fd..9e7b85d19 100644 --- a/PKHeX.Core/Saves/SAV1Stadium.cs +++ b/PKHeX.Core/Saves/SAV1Stadium.cs @@ -114,8 +114,8 @@ protected override PK1 GetPKM(byte[] data) var ot = data.AsSpan(PokeCrypto.SIZE_1STORED + len, len); data = data.Slice(0, PokeCrypto.SIZE_1STORED); var pk1 = new PK1(data, Japanese); - nick.CopyTo(pk1.RawNickname); - ot.CopyTo(pk1.RawOT); + nick.CopyTo(pk1.Nickname_Trash); + ot.CopyTo(pk1.OT_Trash); return pk1; } @@ -127,8 +127,8 @@ public override byte[] GetDataForFormatStored(PKM pk) var data = pk.Data; int len = StringLength; data.CopyTo(result, 0); - gb.RawNickname.CopyTo(result, PokeCrypto.SIZE_1STORED); - gb.RawOT.CopyTo(result, PokeCrypto.SIZE_1STORED + len); + gb.Nickname_Trash.CopyTo(result.AsSpan(PokeCrypto.SIZE_1STORED)); + gb.OT_Trash.CopyTo(result.AsSpan(PokeCrypto.SIZE_1STORED + len)); return result; } diff --git a/PKHeX.Core/Saves/SAV1StadiumJ.cs b/PKHeX.Core/Saves/SAV1StadiumJ.cs index af157ae7b..f67faabb4 100644 --- a/PKHeX.Core/Saves/SAV1StadiumJ.cs +++ b/PKHeX.Core/Saves/SAV1StadiumJ.cs @@ -87,8 +87,8 @@ protected override PK1 GetPKM(byte[] data) var ot = data.AsSpan(0x21 + len, len); data = data.Slice(0, 0x21); var pk1 = new PK1(data, true); - nick.CopyTo(pk1.RawNickname); - ot.CopyTo(pk1.RawOT); + nick.CopyTo(pk1.Nickname_Trash); + ot.CopyTo(pk1.OT_Trash); return pk1; } @@ -100,8 +100,8 @@ public override byte[] GetDataForFormatStored(PKM pk) var data = pk.Data; const int len = StringLength; data.CopyTo(result, 0); - gb.RawNickname.CopyTo(result, PokeCrypto.SIZE_1STORED); - gb.RawOT.CopyTo(result, PokeCrypto.SIZE_1STORED + len); + gb.Nickname_Trash.CopyTo(result.AsSpan(PokeCrypto.SIZE_1STORED)); + gb.OT_Trash.CopyTo(result.AsSpan(PokeCrypto.SIZE_1STORED + len)); return result; } diff --git a/PKHeX.Core/Saves/SAV2.cs b/PKHeX.Core/Saves/SAV2.cs index 80c6756f7..57cb53ac9 100644 --- a/PKHeX.Core/Saves/SAV2.cs +++ b/PKHeX.Core/Saves/SAV2.cs @@ -155,8 +155,8 @@ private PK2 ReadPKMFromOffset(int offset) var nick = span[..stringLength]; var ot = span.Slice(stringLength, stringLength); - nick.CopyTo(pk.RawNickname); - ot.CopyTo(pk.RawOT); + nick.CopyTo(pk.Nickname_Trash); + ot.CopyTo(pk.OT_Trash); return pk; } diff --git a/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs b/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs index e9349f7dc..0d442c06c 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/LGPE/GP1.cs @@ -194,7 +194,8 @@ public PB7 ConvertToPB7(ITrainerInfo sav, EncounterCriteria criteria) } Span moves = stackalloc ushort[4]; - MoveLevelUp.GetEncounterMoves(moves, pk, pk.CurrentLevel, GameVersion.GO); + ILearnSource source = LearnSource7GG.Instance; + source.SetEncounterMoves(Species, Form, Level, moves); pk.SetMoves(moves); pk.SetMaximumPPCurrent(moves); pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; diff --git a/PKHeX.Core/Saves/Substructures/Gen8/BS/MyItem8b.cs b/PKHeX.Core/Saves/Substructures/Gen8/BS/MyItem8b.cs index 8931b8503..8cdd2a778 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/BS/MyItem8b.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/BS/MyItem8b.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; namespace PKHeX.Core; @@ -101,6 +100,4 @@ private InventoryPouch8b MakePouch(InventoryType type) var max = info.GetMax(type); return new InventoryPouch8b(type, info, max, Offset); } - - public static bool IsHeldItemLegal(ushort item) => !Legal.HeldItems_BS.Contains(item) || Legal.ReleasedHeldItems_8b[item]; } diff --git a/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs b/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs index f815db09c..0afdd365d 100644 --- a/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs +++ b/PKHeX.WinForms/Controls/PKM Editor/StatEditor.cs @@ -114,7 +114,7 @@ private void ClickAV(object sender, EventArgs e) if ((ModifierKeys & Keys.Control) != 0) // Max { - var max = Legal.AwakeningMax.ToString(); + var max = AwakeningUtil.AwakeningMax.ToString(); t.Text = t.Text == max ? 0.ToString() : max; } else if ((ModifierKeys & Keys.Alt) != 0) // Min @@ -218,9 +218,9 @@ private void UpdateAVs(object sender, EventArgs e) if (sender is MaskedTextBox m) { var value = (byte)Math.Min(byte.MaxValue, Util.ToInt32(m.Text)); - if (value > Legal.AwakeningMax) + if (value > AwakeningUtil.AwakeningMax) { - m.Text = Legal.AwakeningMax.ToString(); + m.Text = AwakeningUtil.AwakeningMax.ToString(); return; // recursive on text set } diff --git a/PKHeX.WinForms/Subforms/KChart.cs b/PKHeX.WinForms/Subforms/KChart.cs index 352205518..d01159289 100644 --- a/PKHeX.WinForms/Subforms/KChart.cs +++ b/PKHeX.WinForms/Subforms/KChart.cs @@ -87,11 +87,30 @@ private void PopEntry(ushort species, byte form, string name, IPersonalTable pt) private static bool GetIsNative(IPersonalInfo personalInfo, ushort s) => personalInfo switch { - PersonalInfo7 => s > 721 || Legal.PastGenAlolanNatives.Contains(s), + PersonalInfo7 => s > 721 || PastGenAlolanNatives.BinarySearch(s) >= 0, PersonalInfo8SWSH ss => ss.IsInDex, PersonalInfo8BDSP bs => bs.IsInDex, PersonalInfo8LA bs => bs.IsPresentInGame, PersonalInfo9SV sv => sv.IsInDex, _ => true, }; + + private static ReadOnlySpan PastGenAlolanNatives => new ushort[] + { + 010, 011, 012, 019, 020, 021, 022, 023, 025, 026, 027, 028, 035, 036, 037, 038, 039, 040, 041, 042, 046, 047, + 050, 051, 052, 053, 054, 055, 056, 057, 058, 059, 060, 061, 062, 063, 064, 065, 066, 067, 068, 072, 073, 074, + 075, 076, 079, 080, 081, 082, 086, 088, 089, 090, 091, 092, 093, 094, 096, 097, 100, 101, 102, 103, 104, 105, + 108, 113, 115, 118, 119, 120, 121, 122, 123, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, + 138, 140, 142, 143, 147, 148, 149, 163, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 177, 179, 185, 186, + 190, 193, 194, 195, 196, 197, 198, 199, 200, 204, 206, 209, 210, 212, 214, 215, 218, 219, 222, 223, 225, 227, + 228, 233, 235, 238, 239, 240, 241, 242, 246, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 283, 284, 296, + 297, 299, 302, 303, 307, 308, 309, 318, 319, 320, 321, 324, 325, 326, 327, 328, 329, 330, 333, 334, 339, 340, + 341, 343, 345, 347, 349, 350, 351, 352, 353, 357, 359, 361, 362, 366, 369, 370, 371, 372, 373, 374, 375, 376, + 408, 409, 410, 411, 418, 419, 422, 423, 425, 426, 427, 429, 430, 438, 439, 440, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 456, 457, 458, 459, 460, 461, 462, 466, 467, 469, 470, 471, 474, 476, 478, 506, 507, 508, + 524, 525, 526, 531, 546, 547, 548, 549, 550, 551, 552, 553, 557, 558, 559, 561, 564, 565, 566, 567, 568, 569, + 570, 572, 580, 581, 582, 583, 584, 587, 592, 594, 605, 618, 619, 621, 622, 624, 627, 628, 629, 630, 636, 661, + 662, 663, 667, 669, 674, 675, 676, 686, 688, 689, 690, 692, 694, 695, 696, 698, 700, 701, 702, 703, 704, 705, + 706, 707, 708, 709, 714, 718, + }; }