diff --git a/PKHeX.Core/Legality/Core.cs b/PKHeX.Core/Legality/Core.cs index 2a14829f7..ab64e71c6 100644 --- a/PKHeX.Core/Legality/Core.cs +++ b/PKHeX.Core/Legality/Core.cs @@ -139,11 +139,11 @@ internal static int[] GetMaxLevelLearnMoveG1(int species, List moves) } return r; } - internal static List[] GetExclusiveMoves(int species1, int species2, int Generation, IEnumerable tmhm, IEnumerable moves, bool korean) + internal static List[] GetExclusiveMovesG1(int species1, int species2, IEnumerable tmhm, IEnumerable moves) { // Return from two species the exclusive moves that only one could learn and also the current pokemon have it in its current moveset - var moves1 = GetLvlMoves(species1, 0, Generation, 1, 100, korean).Distinct().ToList(); - var moves2 = GetLvlMoves(species2, 0, Generation, 1, 100, korean).Distinct().ToList(); + var moves1 = MoveLevelUp.AddMovesLevelUp1(species1, 1, 100); + var moves2 = MoveLevelUp.AddMovesLevelUp1(species2, 1, 100); // Remove common moves and remove tmhm, remove not learned moves var common = new HashSet(moves1.Intersect(moves2).Concat(tmhm)); @@ -152,145 +152,6 @@ internal static List[] GetExclusiveMoves(int species1, int species2, int Ge moves2.RemoveAll(x => !hashMoves.Contains(x) || common.Contains(x)); return new[] { moves1, moves2 }; } - private static IEnumerable GetLvlMoves(int species, int form, int Generation, int minlvl, int lvl, bool korean = true, GameVersion Version = GameVersion.Any) - { - var r = new List(); - var ver = Version; - switch (Generation) - { - case 1: - { - int index = PersonalTable.RB.GetFormeIndex(species, 0); - if (index == 0) - return r; - - var pi_rb = (PersonalInfoG1)PersonalTable.RB[index]; - var pi_y = (PersonalInfoG1)PersonalTable.Y[index]; - if (minlvl == 1) - { - r.AddRange(pi_rb.Moves); - r.AddRange(pi_y.Moves); - } - r.AddRange(LevelUpRB[index].GetMoves(lvl, minlvl)); - r.AddRange(LevelUpY[index].GetMoves(lvl, minlvl)); - break; - } - case 2: - { - int index = PersonalTable.C.GetFormeIndex(species, 0); - if (index == 0) - return r; - r.AddRange(LevelUpGS[index].GetMoves(lvl)); - if (AllowGen2Crystal(korean)) - r.AddRange(LevelUpC[index].GetMoves(lvl)); - break; - } - case 3: - { - int index = PersonalTable.E.GetFormeIndex(species, 0); - if (index == 0) - return r; - if (index == 386) - { - switch (form) - { - case 0: r.AddRange(LevelUpRS[index].GetMoves(lvl)); break; - case 1: r.AddRange(LevelUpFR[index].GetMoves(lvl)); break; - case 2: r.AddRange(LevelUpLG[index].GetMoves(lvl)); break; - case 3: r.AddRange(LevelUpE[index].GetMoves(lvl)); break; - } - } - else - { - // Emerald level up table are equals to R/S level up tables - r.AddRange(LevelUpE[index].GetMoves(lvl)); - // fire red and leaf green are equals between each other but different than RSE - // Do not use FR Levelup table. It have 67 moves for charmander but Leaf Green moves table is correct - r.AddRange(LevelUpLG[index].GetMoves(lvl)); - } - break; - } - case 4: - { - int index = PersonalTable.HGSS.GetFormeIndex(species, 0); - if (index == 0) - return r; - r.AddRange(LevelUpDP[index].GetMoves(lvl)); - r.AddRange(LevelUpPt[index].GetMoves(lvl)); - r.AddRange(LevelUpHGSS[index].GetMoves(lvl)); - break; - } - case 5: - { - int index = PersonalTable.B2W2.GetFormeIndex(species, 0); - if (index == 0) - return r; - r.AddRange(LevelUpBW[index].GetMoves(lvl)); - r.AddRange(LevelUpB2W2[index].GetMoves(lvl)); - break; - } - case 6: - switch (ver) - { - case GameVersion.Any: // Start at the top, hit every table - case GameVersion.X: - case GameVersion.Y: - case GameVersion.XY: - { - int index = PersonalTable.XY.GetFormeIndex(species, form); - if (index == 0) - return r; - r.AddRange(LevelUpXY[index].GetMoves(lvl)); - if (ver == GameVersion.Any) // Fall Through - goto case GameVersion.ORAS; - break; - } - - case GameVersion.AS: - case GameVersion.OR: - case GameVersion.ORAS: - { - int index = PersonalTable.AO.GetFormeIndex(species, form); - if (index == 0) - return r; - r.AddRange(LevelUpAO[index].GetMoves(lvl)); - break; - } - } - break; - case 7: - switch (ver) - { - case GameVersion.SN: - case GameVersion.MN: - case GameVersion.SM: - { - if (species > MaxSpeciesID_7) - break; - int index = PersonalTable.SM.GetFormeIndex(species, form); - r.AddRange(LevelUpSM[index].GetMoves(lvl)); - break; - } - case GameVersion.Any: - case GameVersion.US: - case GameVersion.UM: - case GameVersion.USUM: - { - int index = PersonalTable.USUM.GetFormeIndex(species, form); - if (index == 0) - return r; - r.AddRange(LevelUpUSUM[index].GetMoves(lvl)); - if (ver == GameVersion.Any) // Fall Through - goto case GameVersion.SM; - break; - } - } - break; - default: - return r; - } - return r; - } internal static List[] GetValidMovesAllGens(PKM pkm, DexLevel[][] evoChains, int minLvLG1 = 1, int minLvLG2 = 1, bool LVL = true, bool Tutor = true, bool Machine = true, bool MoveReminder = true, bool RemoveTransferHM = true) { List[] Moves = new List[evoChains.Length]; @@ -321,7 +182,7 @@ internal static IEnumerable GetValidRelearn(PKM pkm, int species, bool inhe if (pkm.GenNumber < 6 || pkm.VC) return r; - r.AddRange(GetRelearnLVLMoves(pkm, species, 1, pkm.AltForm, version)); + r.AddRange(MoveEgg.GetRelearnLVLMoves(pkm, species, 1, pkm.AltForm, version)); int form = pkm.AltForm; if (pkm.Format == 6 && pkm.Species != 678) @@ -329,7 +190,7 @@ internal static IEnumerable GetValidRelearn(PKM pkm, int species, bool inhe r.AddRange(GetEggMoves(pkm, species, form, version)); if (inheritlvlmoves) - r.AddRange(GetRelearnLVLMoves(pkm, species, 100, pkm.AltForm, version)); + r.AddRange(MoveEgg.GetRelearnLVLMoves(pkm, species, 100, pkm.AltForm, version)); return r.Distinct(); } internal static IList GetShedinjaEvolveMoves(PKM pkm, int lvl = -1, int generation = 0) @@ -480,7 +341,7 @@ internal static List GetValidPostEvolutionMoves(PKM pkm, int Species, DexLe moves.AddRange(pkm.RelearnMoves.Where(m => m != 0)); return moves.Distinct().ToList(); } - private static IEnumerable GetValidPostEvolutionMoves(PKM pkm, int Species, DexLevel[] evoChain, int Generation, GameVersion Version) + private static List GetValidPostEvolutionMoves(PKM pkm, int Species, DexLevel[] evoChain, int Generation, GameVersion Version) { var evomoves = new List(); var index = Array.FindIndex(evoChain, e => e.Species == Species); @@ -505,7 +366,7 @@ internal static IEnumerable GetExclusivePreEvolutionMoves(PKM pkm, int Spec var list = i >= index ? preevomoves : evomoves; list.AddRange(moves); } - return preevomoves.Except(evomoves).Distinct().ToList(); + return preevomoves.Except(evomoves).Distinct(); } // Encounter @@ -743,9 +604,10 @@ private static List GetRequiredMoveCountLevel(PKM pk) maxlevel = 8; // Always learns a third move at level 8 } - return minlevel <= pk.CurrentLevel - ? GetLvlMoves(basespecies, 0, 1, minlevel, maxlevel, pk.Korean).Where(m => m != 0).Distinct().ToList() - : new List(); + if (minlevel > pk.CurrentLevel) + return new List(); + + return MoveLevelUp.AddMovesLevelUp1(basespecies, maxlevel, minlevel); } internal static bool GetWasEgg23(PKM pkm) @@ -1247,10 +1109,6 @@ internal static bool GetCanRelearnMove(PKM pkm, int move, int generation, GameVe { return GetValidMoves(pkm, version, GetValidPreEvolutions(pkm).ToArray(), generation, LVL: true, Relearn: true).Contains(move); } - internal static bool GetCanLearnMove(PKM pkm, int move, int generation, GameVersion version = GameVersion.Any) - { - return GetValidMoves(pkm, version, GetValidPreEvolutions(pkm).ToArray(), generation, Tutor: true, Machine: true).Contains(move); - } internal static bool GetCanKnowMove(PKM pkm, int move, int generation, GameVersion version = GameVersion.Any) { if (pkm.Species == 235 && !InvalidSketch.Contains(move)) @@ -1260,7 +1118,7 @@ internal static bool GetCanKnowMove(PKM pkm, int move, int generation, GameVersi internal static int GetBaseEggSpecies(PKM pkm, int skipOption = 0) { if (pkm.Format == 1) - return GetBaseSpecies(pkm, skipOption : skipOption, generation : 2); + return GetBaseSpecies(pkm, generation: 2); return GetBaseSpecies(pkm, skipOption); } internal static int GetBaseSpecies(PKM pkm, int skipOption = 0, int generation = -1) @@ -1319,10 +1177,6 @@ internal static int GetMinLevelEncounter(PKM pkm) return 1; return pkm.HasOriginalMetLocation ? pkm.Met_Level : GetMaxLevelGeneration(pkm); } - internal static int GetMinLevelGeneration(PKM pkm) - { - return GetMinLevelGeneration(pkm, pkm.GenNumber); - } private static int GetMinLevelGeneration(PKM pkm, int generation) { if (!pkm.InhabitedGeneration(generation)) @@ -1523,30 +1377,6 @@ private static DexLevel[] GetEvolutionChain(PKM pkm, IEncounterable Encounter, i d.Level = Math.Min(d.Level, maxlevel); return vs; } - private static IEnumerable GetRelearnLVLMoves(PKM pkm, int species, int lvl, int formnum, GameVersion version = GameVersion.Any) - { - if (version == GameVersion.Any) - version = (GameVersion)pkm.Version; - // A pkm can only have levelup relearn moves from the game it originated on - // eg Plusle/Minun have Charm/Fake Tears (respectively) only in OR/AS, not X/Y - switch (version) - { - case GameVersion.X: case GameVersion.Y: - return getMoves(LevelUpXY, PersonalTable.XY); - case GameVersion.AS: case GameVersion.OR: - return getMoves(LevelUpAO, PersonalTable.AO); - - case GameVersion.SN: case GameVersion.MN: - if (species > MaxSpeciesID_7) - break; - return getMoves(LevelUpSM, PersonalTable.SM); - case GameVersion.US: case GameVersion.UM: - return getMoves(LevelUpUSUM, PersonalTable.USUM); - } - return Enumerable.Empty(); - - int[] getMoves(Learnset[] moves, PersonalTable table) => moves[table.GetFormeIndex(species, formnum)].GetMoves(lvl); - } internal static IList GetValidPreEvolutions(PKM pkm, int maxspeciesorigin = -1, int lvl = -1, bool skipChecks = false) { if (lvl < 0) @@ -1623,7 +1453,6 @@ private static IEnumerable GetValidMoves(PKM pkm, GameVersion Version, ILis r.AddRange(pkm.RelearnMoves); return r.Distinct(); } - private static IEnumerable GetEvoMoves(PKM pkm, GameVersion Version, IList vs, int Generation, int minLvLG1, int minLvLG2, bool LVL, bool Tutor, bool Machine, bool MoveReminder, bool RemoveTransferHM, bool moveTutor, int i, DexLevel evo) { var minlvlevo1 = 1; @@ -1647,7 +1476,6 @@ private static IEnumerable GetEvoMoves(PKM pkm, GameVersion Version, IList< ++maxLevel; // allow lvlmoves from the level it evolved to the next species return GetMoves(pkm, evo.Species, minlvlevo1, minlvlevo2, maxLevel, pkm.AltForm, moveTutor, Version, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, Generation); } - private static IEnumerable GetMoves(PKM pkm, int species, int minlvlG1, int minlvlG2, int lvl, int form, bool moveTutor, GameVersion Version, bool LVL, bool specialTutors, bool Machine, bool MoveReminder, bool RemoveTransferHM, int Generation) { List r = new List(); @@ -1657,70 +1485,12 @@ private static IEnumerable GetMoves(PKM pkm, int species, int minlvlG1, int r.AddRange(MoveTechnicalMachine.GetTMHM(pkm, species, form, Generation, Version, RemoveTransferHM)); if (moveTutor) r.AddRange(MoveTutor.GetTutorMoves(pkm, species, form, specialTutors, Generation)); - return r; + return r.Distinct(); } - internal static int[] GetEggMoves(PKM pkm, int species, int formnum, GameVersion version) { - if (!pkm.InhabitedGeneration(pkm.GenNumber, species) || pkm.PersonalInfo.Gender == 255 && !FixedGenderFromBiGender.Contains(species)) - return new int[0]; - if (version == GameVersion.Any) - version = (GameVersion)pkm.Version; - return GetEggMoves(pkm.GenNumber, species, formnum, version); + return MoveEgg.GetEggMoves(pkm, species, formnum, version); } - private static int[] GetEggMoves(int gen, int species, int formnum, GameVersion version) - { - switch (gen) - { - case 1: - case 2: - return (version == GameVersion.C ? EggMovesC : EggMovesGS)[species].Moves; - case 3: - return EggMovesRS[species].Moves; - case 4: - switch (version) - { - case GameVersion.HG: - case GameVersion.SS: - return EggMovesHGSS[species].Moves; - default: - return EggMovesDPPt[species].Moves; - } - case 5: - return EggMovesBW[species].Moves; - case 6: // entries per species - switch (version) - { - case GameVersion.OR: - case GameVersion.AS: - return EggMovesAO[species].Moves; - default: - return EggMovesXY[species].Moves; - } - - case 7: // entries per form if required - EggMoves[] table; - switch (version) - { - case GameVersion.US: - case GameVersion.UM: - table = EggMovesUSUM; - break; - default: - table = EggMovesSM; - break; - } - - var entry = table[species]; - if (formnum > 0 && AlolanOriginForms.Contains(species)) - entry = table[entry.FormTableIndex + formnum - 1]; - return entry.Moves; - - default: - return new int[0]; - } - } - internal static IEnumerable GetTMHM(PKM pkm, int species, int form, int generation, GameVersion Version = GameVersion.Any, bool RemoveTransferHM = true) { return MoveTechnicalMachine.GetTMHM(pkm, species, form, generation, Version, RemoveTransferHM); @@ -1780,17 +1550,6 @@ internal static bool IsOutsider(PKM pkm) internal static bool HasVisitedORAS(this PKM pkm) => pkm.InhabitedGeneration(6) && (pkm.AO || !pkm.IsUntraded); internal static bool HasVisitedUSUM(this PKM pkm) => pkm.InhabitedGeneration(7) && (pkm.USUM || !pkm.IsUntraded); - internal static TreeEncounterAvailable GetGSCHeadbuttAvailability(EncounterSlot encounter, int TID) - { - var Area = Array.Find(HeadbuttTreesC, a => a.Location == encounter.Location); - if (Area == null) // Failsafe, every area with headbutt encounters has a tree area - return TreeEncounterAvailable.Impossible; - - var table = Area.GetTrees(encounter.Type); - var trainerpivot = TID % 10; - return table[trainerpivot]; - } - public static int[] GetEncounterMoves(PKM pk, int level, GameVersion version) { var learn = GameData.GetLearnsets(version); diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters2.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters2.cs index 665bb71e5..043edb83c 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters2.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters2.cs @@ -1,4 +1,5 @@ -using System.Linq; +using System; +using System.Linq; using static PKHeX.Core.EncounterUtil; namespace PKHeX.Core @@ -10,7 +11,7 @@ internal static class Encounters2 { internal static readonly EncounterArea[] SlotsGSC, SlotsGS, SlotsC; internal static readonly EncounterStatic[] StaticGSC, StaticGS, StaticC; - internal static readonly TreesArea[] HeadbuttTreesC = TreesArea.GetArray(Data.UnpackMini(Util.GetBinaryResource("trees_h_c.pkl"), "ch")); + private static readonly TreesArea[] HeadbuttTreesC = TreesArea.GetArray(Data.UnpackMini(Util.GetBinaryResource("trees_h_c.pkl"), "ch")); static Encounters2() { @@ -276,5 +277,16 @@ private static EncounterArea[] GetSlots_C(EncounterArea[] f) Util.GetStringList("tradegsc", "es"), // 7 Util.GetStringList("tradegsc", "ko"), // 8 }; + + internal static TreeEncounterAvailable GetGSCHeadbuttAvailability(EncounterSlot encounter, int TID) + { + var Area = Array.Find(HeadbuttTreesC, a => a.Location == encounter.Location); + if (Area == null) // Failsafe, every area with headbutt encounters has a tree area + return TreeEncounterAvailable.Impossible; + + var table = Area.GetTrees(encounter.Type); + var trainerpivot = TID % 10; + return table[trainerpivot]; + } } } diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs index 9cf58a35d..94c9a1e62 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterMovesetGenerator.cs @@ -316,7 +316,7 @@ private static bool IsUnobtainable(this EncounterSlot slot, PKM pk) return true; if ((slot.Type & SlotType.Headbutt) != 0) - if (Legal.GetGSCHeadbuttAvailability(slot, pk.TID) != TreeEncounterAvailable.ValidTree) // Unreachable Headbutt Trees. + if (Encounters2.GetGSCHeadbuttAvailability(slot, pk.TID) != TreeEncounterAvailable.ValidTree) // Unreachable Headbutt Trees. return true; break; case 4: diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs b/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs index c4069247f..5ce8da93a 100644 --- a/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs +++ b/PKHeX.Core/Legality/Encounters/Verifiers/EncounterVerifier.cs @@ -102,7 +102,7 @@ private static CheckResult VerifyWildEncounterCrystal(PKM pkm, EncounterSlot enc } private static CheckResult VerifyWildEncounterCrystalHeadbutt(ITrainerID tr, EncounterSlot encounter) { - var tree = Legal.GetGSCHeadbuttAvailability(encounter, tr.TID); + var tree = Encounters2.GetGSCHeadbuttAvailability(encounter, tr.TID); switch (tree) { case TreeEncounterAvailable.ValidTree: @@ -276,7 +276,7 @@ private static CheckResult VerifyEncounterStatic(PKM pkm, EncounterStatic s) switch (pkm.GenNumber) { case 3: - if (s is EncounterStaticShadow w && w.EReader && pkm.Language != (int)LanguageID.Japanese) // Non-JP E-reader Pokemon + if (s is EncounterStaticShadow w && w.EReader && pkm.Language != (int)LanguageID.Japanese) // Non-JP E-reader Pokemon return new CheckResult(Severity.Invalid, V406, CheckIdentifier.Encounter); if (pkm.Species == 151 && s.Location == 201 && pkm.Language != (int)LanguageID.Japanese) // Non-JP Mew (Old Sea Map) return new CheckResult(Severity.Invalid, V353, CheckIdentifier.Encounter); diff --git a/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs b/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs index 18cf913f1..13f17b611 100644 --- a/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs +++ b/PKHeX.Core/Legality/Encounters/Verifiers/VerifyCurrentMoves.cs @@ -520,7 +520,7 @@ private static void ParseEvolutionsIncompatibleMoves(PKM pkm, IList 0 && AlolanOriginForms.Contains(species)) + entry = table[entry.FormTableIndex + formnum - 1]; + return entry.Moves; + } + + internal static int[] GetRelearnLVLMoves(PKM pkm, int species, int lvl, int formnum, GameVersion version = GameVersion.Any) + { + if (version == GameVersion.Any) + version = (GameVersion)pkm.Version; + // A pkm can only have levelup relearn moves from the game it originated on + // eg Plusle/Minun have Charm/Fake Tears (respectively) only in OR/AS, not X/Y + switch (version) + { + case GameVersion.X: + case GameVersion.Y: + return getMoves(LevelUpXY, PersonalTable.XY); + case GameVersion.AS: + case GameVersion.OR: + return getMoves(LevelUpAO, PersonalTable.AO); + + case GameVersion.SN: + case GameVersion.MN: + if (species > MaxSpeciesID_7) + break; + return getMoves(LevelUpSM, PersonalTable.SM); + case GameVersion.US: + case GameVersion.UM: + return getMoves(LevelUpUSUM, PersonalTable.USUM); + } + return new int[0]; + + int[] getMoves(IReadOnlyList moves, PersonalTable table) => moves[table.GetFormeIndex(species, formnum)].GetMoves(lvl); + } + } +} diff --git a/PKHeX.Core/Legality/Moves/MoveLevelUp.cs b/PKHeX.Core/Legality/Moves/MoveLevelUp.cs index e894bd263..6b04af0a0 100644 --- a/PKHeX.Core/Legality/Moves/MoveLevelUp.cs +++ b/PKHeX.Core/Legality/Moves/MoveLevelUp.cs @@ -271,7 +271,7 @@ public static IEnumerable GetLevelUpMoves(PKM pkm, int species, int minlvlG return null; } - private static List AddMovesLevelUp1(int species, int max, int min) + internal static List AddMovesLevelUp1(int species, int max, int min) { List moves = new List(); int index = PersonalTable.RB.GetFormeIndex(species, 0);