diff --git a/PKHeX.Core/Legality/Core.cs b/PKHeX.Core/Legality/Core.cs index 3dc45df39..9bb50ab03 100644 --- a/PKHeX.Core/Legality/Core.cs +++ b/PKHeX.Core/Legality/Core.cs @@ -17,6 +17,7 @@ namespace PKHeX.Core public static bool AllowGen2VCTransfer => AllowGen1Tradeback; public static bool AllowGen2VCCrystal = false; public static bool AllowGen2Crystal => AllowGBCartEra || AllowGen2Crystal; + public static bool AllowGen2MoveReminder => AllowGBCartEra; /// Setting to specify if the e-berry index item is an eningma berry or a e-reader berry and the name of the e-reader berry public static bool EReaderBerryIsEnigma = true; @@ -1185,29 +1186,29 @@ namespace PKHeX.Core } return r; } - internal static List[] getValidMovesAllGens(PKM pkm, DexLevel[][] evoChains, int minLvLG1 = 1, bool LVL = true, bool Tutor = true, bool Machine = true, bool MoveReminder = true, bool RemoveTransferHM = true) + 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]; for (int i = 1; i < evoChains.Length; i++) if (evoChains[i].Any()) - Moves[i] = getValidMoves(pkm, evoChains[i], i, minLvLG1, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM).ToList(); + Moves[i] = getValidMoves(pkm, evoChains[i], i, minLvLG1, minLvLG2, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM).ToList(); else Moves[i] = new List(); return Moves; } - internal static IEnumerable getValidMoves(PKM pkm, DexLevel[][] evoChains, int minLvLG1 = 1, bool LVL = true, bool Tutor = true, bool Machine = true, bool MoveReminder = true, bool RemoveTransferHM = true) + internal static IEnumerable getValidMoves(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) { GameVersion version = (GameVersion)pkm.Version; if (!pkm.IsUntraded) version = GameVersion.Any; - return getValidMoves(pkm, version, evoChains, minLvLG1: minLvLG1, LVL: LVL, Relearn: false, Tutor: Tutor, Machine: Machine, MoveReminder: MoveReminder, RemoveTransferHM: RemoveTransferHM); + return getValidMoves(pkm, version, evoChains, minLvLG1: minLvLG1, minLvLG2: minLvLG2, LVL: LVL, Relearn: false, Tutor: Tutor, Machine: Machine, MoveReminder: MoveReminder, RemoveTransferHM: RemoveTransferHM); } - internal static IEnumerable getValidMoves(PKM pkm, DexLevel[] evoChain, int generation, int minLvLG1 = 1, bool LVL = true, bool Tutor = true, bool Machine = true, bool MoveReminder = true, bool RemoveTransferHM = true) + internal static IEnumerable getValidMoves(PKM pkm, DexLevel[] evoChain, int generation, int minLvLG1 = 1, int minLvLG2 = 1, bool LVL = true, bool Tutor = true, bool Machine = true, bool MoveReminder = true, bool RemoveTransferHM = true) { GameVersion version = (GameVersion)pkm.Version; if (!pkm.IsUntraded) version = GameVersion.Any; - return getValidMoves(pkm, version, evoChain, generation, minLvLG1: minLvLG1, LVL: LVL, Relearn: false, Tutor: Tutor, Machine: Machine, MoveReminder: MoveReminder, RemoveTransferHM: RemoveTransferHM); + return getValidMoves(pkm, version, evoChain, generation, minLvLG1: minLvLG1, minLvLG2: minLvLG2, LVL: LVL, Relearn: false, Tutor: Tutor, Machine: Machine, MoveReminder: MoveReminder, RemoveTransferHM: RemoveTransferHM); } internal static IEnumerable getValidRelearn(PKM pkm, int species, bool inheritlvlmoves) { @@ -1369,7 +1370,7 @@ namespace PKHeX.Core for (int i = 0; i <= index; i++) { var evo = evoChain[i]; - var moves = getMoves(pkm, evo.Species, 1, evo.Level, pkm.AltForm, moveTutor: true, Version: Version, LVL: true, specialTutors: true, Machine: true, MoveReminder: true, RemoveTransferHM: false, Generation: Generation); + var moves = getMoves(pkm, evo.Species, 1, 1, evo.Level, pkm.AltForm, moveTutor: true, Version: Version, LVL: true, specialTutors: true, Machine: true, MoveReminder: true, RemoveTransferHM: false, Generation: Generation); // Moves from Species or any species after in the evolution phase evomoves.AddRange(moves); } @@ -1394,7 +1395,7 @@ namespace PKHeX.Core for (int i = 0; i < evoChain.Length; i++) { var evo = evoChain[i]; - var moves = getMoves(pkm, evo.Species, 1, evo.Level, pkm.AltForm, moveTutor: true, Version: Version, LVL: true, specialTutors: true, Machine: true, MoveReminder: true, RemoveTransferHM: false, Generation: Generation); + var moves = getMoves(pkm, evo.Species, 1, 1, evo.Level, pkm.AltForm, moveTutor: true, Version: Version, LVL: true, specialTutors: true, Machine: true, MoveReminder: true, RemoveTransferHM: false, Generation: Generation); if (i >= index) // Moves from Species or any species bellow in the evolution phase preevomoves.AddRange(moves); @@ -1407,6 +1408,10 @@ namespace PKHeX.Core } // Encounter + internal static GameVersion[] getGen2GameEncounter(PKM pk) + { + return AllowGen2VCCrystal ? new[] { GameVersion.GS, GameVersion.C } : new[] { GameVersion.GS}; + } internal static GameVersion[] getGen1GameEncounter(PKM pk) { if (pk.Format != 1 || !pk.Gen1_NotTradeback) @@ -2034,7 +2039,7 @@ namespace PKHeX.Core if (info.EncounterMatch.EggEncounter && !pkm.WasGiftEgg && !pkm.WasEventEgg && allowegg) { if (getIsMoveInherited(pkm, info, moves)) - LearnLevel = Math.Min(LearnLevel, pkm.GenNumber < 4 ? 5 : 1); + LearnLevel = Math.Min(LearnLevel, pkm.GenNumber < 4 ? 6 : 2); } // If has original met location the minimum evolution level is one level after met level @@ -2042,10 +2047,11 @@ namespace PKHeX.Core // VC pokemon: minimum level is one level after transfer to generation 7 // Sylveon: always one level after met level, for gen 4 and 5 eevees in gen 6 games minimum for evolution is one level after transfer to generation 5 if (pkm.HasOriginalMetLocation || pkm.Format == 4 && pkm.Gen3 || pkm.VC || pkm.Species == 700) - LearnLevel = Math.Max(pkm.Met_Level, LearnLevel); + LearnLevel = Math.Max(pkm.Met_Level + 1, LearnLevel); - // Current level must be at least one level after the minimum learn level - return pkm.CurrentLevel > LearnLevel; + // Current level must be at least one the minimum learn level + // the level-up event that triggers the learning of the move also triggers evolution with no further level-up required + return pkm.CurrentLevel >= LearnLevel; } private static bool getIsMoveInherited(PKM pkm, LegalInfo info, int[] moves) { @@ -2405,7 +2411,7 @@ namespace PKHeX.Core var et = maxspeciesorigin == MaxSpeciesID_2 ? getEvolutionTable(2) : getEvolutionTable(pkm); return et.getValidPreEvolutions(pkm, lvl: lvl, maxSpeciesOrigin: maxspeciesorigin, skipChecks: skipChecks); } - private static IEnumerable getValidMoves(PKM pkm, GameVersion Version, IReadOnlyList vs, int minLvLG1 = 1, bool LVL = false, bool Relearn = false, bool Tutor = false, bool Machine = false, bool MoveReminder = true, bool RemoveTransferHM = true) + private static IEnumerable getValidMoves(PKM pkm, GameVersion Version, IReadOnlyList vs, int minLvLG1 = 1, int minLvLG2 = 1, bool LVL = false, bool Relearn = false, bool Tutor = false, bool Machine = false, bool MoveReminder = true, bool RemoveTransferHM = true) { List r = new List { 0 }; if (Relearn && pkm.Format >= 6) @@ -2413,11 +2419,11 @@ namespace PKHeX.Core for (int gen = pkm.GenNumber; gen <= pkm.Format; gen++) if (vs[gen].Any()) - r.AddRange(getValidMoves(pkm, Version, vs[gen], gen, minLvLG1:minLvLG1, LVL: LVL, Relearn: false, Tutor: Tutor, Machine: Machine, MoveReminder: MoveReminder, RemoveTransferHM: RemoveTransferHM)); + r.AddRange(getValidMoves(pkm, Version, vs[gen], gen, minLvLG1: minLvLG1, minLvLG2: minLvLG2, LVL: LVL, Relearn: false, Tutor: Tutor, Machine: Machine, MoveReminder: MoveReminder, RemoveTransferHM: RemoveTransferHM)); return r.Distinct().ToArray(); } - private static IEnumerable getValidMoves(PKM pkm, GameVersion Version, DexLevel[] vs, int Generation, int minLvLG1 = 1, bool LVL = false, bool Relearn = false, bool Tutor = false, bool Machine = false, bool MoveReminder = true, bool RemoveTransferHM = true) + private static IEnumerable getValidMoves(PKM pkm, GameVersion Version, DexLevel[] vs, int Generation, int minLvLG1 = 1, int minLvLG2 = 1, bool LVL = false, bool Relearn = false, bool Tutor = false, bool Machine = false, bool MoveReminder = true, bool RemoveTransferHM = true) { List r = new List { 0 }; if (!vs.Any()) @@ -2434,23 +2440,30 @@ namespace PKHeX.Core // In gen 3 deoxys has different forms depending on the current game, in personal info there is no alter form info formcount = 4; for (int i = 0; i < formcount; i++) - r.AddRange(getMoves(pkm, species, minLvLG1, vs.First().Level, i, moveTutor, Version, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, Generation)); + r.AddRange(getMoves(pkm, species, minLvLG1, minLvLG2, vs.First().Level, i, moveTutor, Version, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, Generation)); if (Relearn) r.AddRange(pkm.RelearnMoves); return r.Distinct(); } foreach (DexLevel evo in vs) { - var minlvlevo = 1; + var minlvlevo1 = 1; + var minlvlevo2 = 1; if (Generation == 1) { // Return moves from minLvLG1 if species if the species encounters // For evolutions return moves using evolution min level as min level - minlvlevo = minLvLG1; + minlvlevo1 = minLvLG1; if (evo.MinLevel > 1) - minlvlevo = Math.Min(pkm.CurrentLevel, evo.MinLevel); + minlvlevo1 = Math.Min(pkm.CurrentLevel, evo.MinLevel); } - r.AddRange(getMoves(pkm, evo.Species, minlvlevo, evo.Level, pkm.AltForm, moveTutor, Version, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, Generation)); + if (Generation == 2 && !AllowGen2MoveReminder) + { + minlvlevo2 = minLvLG2; + if (evo.MinLevel > 1) + minlvlevo2 = Math.Min(pkm.CurrentLevel, evo.MinLevel); + } + r.AddRange(getMoves(pkm, evo.Species, minlvlevo1, minlvlevo2, evo.Level, pkm.AltForm, moveTutor, Version, LVL, Tutor, Machine, MoveReminder, RemoveTransferHM, Generation)); } if (pkm.Format <= 3) @@ -2480,7 +2493,7 @@ namespace PKHeX.Core r.AddRange(pkm.RelearnMoves); return r.Distinct(); } - private static IEnumerable getMoves(PKM pkm, int species, int minlvlG1, int lvl, int form, bool moveTutor, GameVersion Version, bool LVL, bool specialTutors, bool Machine, bool MoveReminder, bool RemoveTransferHM, int 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(); @@ -2521,9 +2534,9 @@ namespace PKHeX.Core return r; if (LVL) { - r.AddRange(LevelUpGS[index].getMoves(lvl)); + r.AddRange(LevelUpGS[index].getMoves(lvl, minlvlG2)); if (AllowGen2Crystal) - r.AddRange(LevelUpC[index].getMoves(lvl)); + r.AddRange(LevelUpC[index].getMoves(lvl, minlvlG2)); } if (Machine) { diff --git a/PKHeX.Core/Legality/Encounters/VerifyCurrentMoves.cs b/PKHeX.Core/Legality/Encounters/VerifyCurrentMoves.cs index ee375b0ca..673c65fcc 100644 --- a/PKHeX.Core/Legality/Encounters/VerifyCurrentMoves.cs +++ b/PKHeX.Core/Legality/Encounters/VerifyCurrentMoves.cs @@ -38,10 +38,16 @@ namespace PKHeX.Core var EncounterMatchGen = info.EncounterMatch as IGeneration; var defaultG1LevelMoves = info.EncounterMoves.validLevelUpMoves[1]; + var defaultG2LevelMoves = pkm.InhabitedGeneration(2) ? info.EncounterMoves.validLevelUpMoves[2] : null; var defaultTradeback = pkm.TradebackStatus; if (EncounterMatchGen != null) + { // Generation 1 can have different minimum level in different encounter of the same species; update valid level moves UptateGen1LevelUpMoves(pkm, info.EncounterMoves, info.EncounterMoves.minLvlG1, EncounterMatchGen.Generation, info); + if(!Legal.AllowGen2MoveReminder && pkm.InhabitedGeneration(2)) + // The same for Generation 2 if move reminder from Stadium 2 is not allowed + UptateGen2LevelUpMoves(pkm, info.EncounterMoves, info.EncounterMoves.minLvlG2, EncounterMatchGen.Generation, info); + } var res = pre3DS ? parseMovesPre3DS(pkm, Moves, info) @@ -50,8 +56,12 @@ namespace PKHeX.Core if (res.All(x => x.Valid)) return res; - if (EncounterMatchGen?.Generation == 1) // not valid, restore generation 1 moves + if (EncounterMatchGen?.Generation == 1 || EncounterMatchGen?.Generation == 2) // not valid, restore generation 1 and 2 moves + { info.EncounterMoves.validLevelUpMoves[1] = defaultG1LevelMoves; + if (pkm.InhabitedGeneration(2)) + info.EncounterMoves.validLevelUpMoves[2] = defaultG2LevelMoves; + } pkm.TradebackStatus = defaultTradeback; return res; } @@ -142,16 +152,17 @@ namespace PKHeX.Core var allowinherited = SpecialMoves == null && !pkm.WasGiftEgg && pkm.Species != 489 && pkm.Species != 490; return parseMovesIsEggPreRelearn(pkm, Moves, SpecialMoves ?? new int[0], allowinherited, egg); } - if (pkm.GenNumber <= 2 && (info.EncounterMatch as IGeneration)?.Generation == 1) - return parseMovesGen1(pkm, Moves, info); + var NoMoveReminder = (info.EncounterMatch as IGeneration)?.Generation == 1 || (info.EncounterMatch as IGeneration)?.Generation == 2 && !Legal.AllowGen2MoveReminder; + if (pkm.GenNumber <= 2 && NoMoveReminder) + return parseMovesGenGB(pkm, Moves, info); if (info.EncounterMatch is EncounterEgg e) return parseMovesWasEggPreRelearn(pkm, Moves, info, e); return parseMovesSpecialMoveset(pkm, Moves, info); } - private static CheckMoveResult[] parseMovesGen1(PKM pkm, int[] Moves, LegalInfo info) + private static CheckMoveResult[] parseMovesGenGB(PKM pkm, int[] Moves, LegalInfo info) { - GameVersion[] games = Legal.getGen1GameEncounter(pkm); + GameVersion[] games = (info.EncounterMatch as IGeneration)?.Generation == 1 ? Legal.getGen1GameEncounter(pkm) : Legal.getGen2GameEncounter(pkm); CheckMoveResult[] res = new CheckMoveResult[4]; var G1Encounter = info.EncounterMatch; if (G1Encounter == null) @@ -709,7 +720,18 @@ namespace PKHeX.Core EncounterMoves.validLevelUpMoves[1] = Legal.getValidMoves(pkm, info.EvoChainsAllGens[1], generation: 1, minLvLG1: lvlG1, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList(); break; } - + } + private static void UptateGen2LevelUpMoves(PKM pkm, ValidEncounterMoves EncounterMoves, int defaultLvlG2, int generation, LegalInfo info) + { + switch (generation) + { + case 1: + case 2: + var lvlG2 = info.EncounterMatch?.LevelMin + 1 ?? 6; + if (lvlG2 != defaultLvlG2) + EncounterMoves.validLevelUpMoves[2] = Legal.getValidMoves(pkm, info.EvoChainsAllGens[2], generation: 2, minLvLG2: defaultLvlG2, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList(); + break; + } } private static int[] getGenMovesCheckOrder(PKM pkm) { @@ -730,10 +752,11 @@ namespace PKHeX.Core private static ValidEncounterMoves getEncounterValidMoves(PKM pkm, LegalInfo info) { var minLvLG1 = pkm.GenNumber <= 2 ? info.EncounterMatch.LevelMin + 1 : 0; + var minLvlG2 = Legal.AllowGen2MoveReminder ? 1 : info.EncounterMatch.LevelMin + 1; var encounterspecies = info.EncounterMatch.Species; var EvoChainsAllGens = info.EvoChainsAllGens; // If encounter species is the same species from the first match, the one in variable EncounterMatch, its evolution chains is already in EvoChainsAllGens - var LevelMoves = Legal.getValidMovesAllGens(pkm, EvoChainsAllGens, minLvLG1: minLvLG1, Tutor: false, Machine: false, RemoveTransferHM: false); + var LevelMoves = Legal.getValidMovesAllGens(pkm, EvoChainsAllGens, minLvLG1: minLvLG1, minLvLG2: minLvlG2, Tutor: false, Machine: false, RemoveTransferHM: false); var TMHMMoves = Legal.getValidMovesAllGens(pkm, EvoChainsAllGens, LVL: false, Tutor: false, MoveReminder: false, RemoveTransferHM: false); var TutorMoves = Legal.getValidMovesAllGens(pkm, EvoChainsAllGens, LVL: false, Machine: false, MoveReminder: false, RemoveTransferHM: false); return new ValidEncounterMoves @@ -743,7 +766,8 @@ namespace PKHeX.Core validTMHMMoves = TMHMMoves, validTutorMoves = TutorMoves, EvolutionChains = EvoChainsAllGens, - minLvlG1 = minLvLG1 + minLvlG1 = minLvLG1, + minLvlG2 = minLvlG2 }; } } diff --git a/PKHeX.Core/Legality/Structures/ValidEncounterMoves.cs b/PKHeX.Core/Legality/Structures/ValidEncounterMoves.cs index 3c1113668..602b2b793 100644 --- a/PKHeX.Core/Legality/Structures/ValidEncounterMoves.cs +++ b/PKHeX.Core/Legality/Structures/ValidEncounterMoves.cs @@ -12,6 +12,7 @@ namespace PKHeX.Core public List[] validTutorMoves { get; set; } = Empty; public int[] Relearn = new int[0]; public int minLvlG1 { get; set; } + public int minLvlG2 { get; set; } private const int EmptyCount = 7; public static readonly List[] Empty = new int[EmptyCount].Select(z => new List()).ToArray(); diff --git a/PKHeX.Core/Legality/Tables.cs b/PKHeX.Core/Legality/Tables.cs index 067539c18..d1a97cb6b 100644 --- a/PKHeX.Core/Legality/Tables.cs +++ b/PKHeX.Core/Legality/Tables.cs @@ -256,23 +256,23 @@ namespace PKHeX.Core internal static readonly int[][] MinLevelEvolutionWithMove = { // Mr. Mime (Mime Jr with Mimic) - new [] { 0, 0, 0, 0, 18, 15, 15, 15 }, + new [] { 0, 0, 0, 0, 18, 15, 15, 2 }, // Sudowoodo (Bonsly with Mimic) - new [] { 0, 0, 0, 0, 17, 17, 15, 15 }, + new [] { 0, 0, 0, 0, 17, 17, 15, 2 }, // Ambipom (Aipom with Double Hit) - new [] { 0, 0, 0, 0, 32, 32, 32, 32 }, + new [] { 0, 0, 0, 0, 32, 32, 32, 2 }, // Lickilicky (Lickitung with Rollout) - new [] { 0, 0, 1, 0, 1, 33, 33, 33 }, + new [] { 0, 0, 2, 0, 2, 33, 33, 2 }, // Tangrowth (Tangela with Ancient Power) - new [] { 0, 0, 0, 0, 1, 36, 38, 38 }, + new [] { 0, 0, 0, 0, 2, 36, 38, 2 }, // Yanmega (Yanma with Ancient Power) - new [] { 0, 0, 0, 0, 1, 33, 33, 33 }, + new [] { 0, 0, 0, 0, 2, 33, 33, 2 }, // Mamoswine (Piloswine with Ancient Power) - new [] { 0, 0, 0, 0, 1, 1, 1, 1 }, + new [] { 0, 0, 0, 0, 2, 2, 2, 2 }, // Sylveon (Eevee with Fairy Move) - new [] { 0, 0, 0, 0, 0, 29, 9, 9 }, + new [] { 0, 0, 0, 0, 0, 29, 9, 2 }, // Tsareena (Steenee with Stomp) - new [] { 0, 0, 0, 0, 0, 0, 0, 29 }, + new [] { 0, 0, 0, 0, 0, 0, 0, 2 }, }; // True -> the pokemon could hatch from an egg with the move for evolution as an egg move internal static readonly bool[][] EggMoveEvolutionWithMove =