private static CheckMoveResult[] ParseMovesGenGB(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { var res = new CheckMoveResult[4]; var enc = info.EncounterMatch; var level = pkm.HasOriginalMetLocation ? pkm.Met_Level : enc.LevelMin; var InitialMoves = Array.Empty <int>(); var SpecialMoves = GetSpecialMoves(enc); var games = enc.Generation == 1 ? GBRestrictions.GetGen1Versions(enc) : GBRestrictions.GetGen2Versions(enc, pkm.Korean); foreach (var ver in games) { var VerInitialMoves = enc is IMoveset { Moves.Count : not 0 } x ? (int[])x.Moves : MoveLevelUp.GetEncounterMoves(enc.Species, 0, level, ver); if (VerInitialMoves.Intersect(InitialMoves).Count() == VerInitialMoves.Length) { return(res); } var source = new MoveParseSource { CurrentMoves = currentMoves, SpecialSource = SpecialMoves, Base = VerInitialMoves, }; res = ParseMoves(pkm, source, info); // Must have a minimum count of moves, depending on the tradeback state. if (pkm is PK1 pk1) { int count = GBRestrictions.GetRequiredMoveCount(pk1, source.CurrentMoves, info, source.Base); if (count == 1) { return(res); } // Reverse for loop and break instead of 0..count continue -- early-breaks for the vast majority of cases. // We already flag for empty interstitial moveslots. for (int m = count - 1; m >= 0; m--) { var move = source.CurrentMoves[m]; if (move != 0) { break; } // There are ways to skip level up moves by leveling up more than once. // https://bulbapedia.bulbagarden.net/wiki/List_of_glitches_(Generation_I)#Level-up_learnset_skipping // Evolution canceling also leads to incorrect assumptions in the above used method, so just indicate them as fishy in that case. // Not leveled up? Not possible to be missing the move slot. var severity = enc.LevelMin == pkm.CurrentLevel ? Invalid : Fishy; res[m] = new CheckMoveResult(None, pkm.Format, severity, LMoveSourceEmpty, CurrentMove); } } if (res.All(r => r.Valid)) { return(res); } InitialMoves = VerInitialMoves; } return(res); }
private static void ParseEvolutionLevelupMove(PKM pkm, IList <CheckMoveResult> res, IReadOnlyList <int> currentMoves, LegalInfo info) { // Ignore if there is an invalid move or an empty move, this validation is only for 4 non-empty moves that are all valid, but invalid as a 4 combination // Ignore Mr. Mime and Sudowodoo from generations 1 to 3, they cant be evolved from Bonsly or Munchlax // Ignore if encounter species is the evolution species, the pokemon was not evolved by the player if (info.EncounterMatch.Species == pkm.Species) { return; } if (!res.All(r => r?.Valid ?? false) || currentMoves.Any(m => m == 0) || (EvolutionRestrictions.BabyEvolutionWithMove.Contains(pkm.Species) && info.Generation <= 3)) { return; } var ValidMoves = MoveList.GetValidPostEvolutionMoves(pkm, pkm.Species, info.EvoChainsAllGens, GameVersion.Any); // Add the evolution moves to valid moves in case some of these moves could not be learned after evolving switch (pkm.Species) { case (int)Species.MrMime: // Mr. Mime (Mime Jr with Mimic) case (int)Species.Sudowoodo: // Sudowoodo (Bonsly with Mimic) ValidMoves.Add(102); break; case (int)Species.Ambipom: // Ambipom (Aipom with Double Hit) ValidMoves.Add(458); break; case (int)Species.Lickilicky: // Lickilicky (Lickitung with Rollout) ValidMoves.Add(205); break; case (int)Species.Tangrowth: // Tangrowth (Tangela with Ancient Power) case (int)Species.Yanmega: // Yanmega (Yanma with Ancient Power) case (int)Species.Mamoswine: // Mamoswine (Piloswine with Ancient Power) ValidMoves.Add(246); break; case (int)Species.Sylveon: // Sylveon (Eevee with Fairy Move) // Add every fairy moves without checking if Eevee learn it or not; pokemon moves are determined legal before this function ValidMoves.AddRange(EvolutionRestrictions.FairyMoves); break; case (int)Species.Tsareena: // Tsareena (Steenee with Stomp) ValidMoves.Add(023); break; } if (currentMoves.Any(m => ValidMoves.Contains(m))) { return; } for (int m = 0; m < 4; m++) { res[m] = new CheckMoveResult(res[m], Invalid, string.Format(LMoveEvoFCombination_0, SpeciesStrings[pkm.Species]), Move); } }
private static void UpdateGen2LevelUpMoves(PKM pkm, ValidEncounterMoves EncounterMoves, int defaultLvlG2, int generation, LegalInfo info) { if (generation >= 3) { return; } var lvlG2 = info.EncounterMatch.LevelMin + 1; if (lvlG2 == defaultLvlG2) { return; } EncounterMoves.LevelUpMoves[2] = MoveList.GetValidMoves(pkm, info.EvoChainsAllGens[2], generation: 2, minLvLG2: defaultLvlG2, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList(); }
private static CheckMoveResult[] ParseMoves(PKM pkm, MoveParseSource source, LegalInfo info) { var res = new CheckMoveResult[4]; bool AllParsed() => res.All(z => z != null); var required = !(pkm is PK1 pk1) ? 1 : GBRestrictions.GetRequiredMoveCount(pk1, source.CurrentMoves, info, source.Base); // Special considerations! int reset = 0; if (pkm is IBattleVersion v && v.BattleVersion != 0) { reset = ((GameVersion)v.BattleVersion).GetGeneration(); source.ResetSources(); } // Check empty moves and relearn moves before generation specific moves for (int m = 0; m < 4; m++) { if (source.CurrentMoves[m] == 0) { res[m] = new CheckMoveResult(None, pkm.Format, m < required ? Fishy : Valid, LMoveSourceEmpty, Move); } else if (reset == 0 && info.EncounterMoves.Relearn.Contains(source.CurrentMoves[m])) { res[m] = new CheckMoveResult(Relearn, info.Generation, Valid, LMoveSourceRelearn, Move); } } if (AllParsed()) { return(res); } // Encapsulate arguments to simplify method calls var moveInfo = new LearnInfo(pkm, source); // Check moves going backwards, marking the move valid in the most current generation when it can be learned int[] generations = GetGenMovesCheckOrder(pkm, info.EncounterOriginal.Generation); if (pkm.Format <= 2) { generations = generations.Where(z => z < info.EncounterMoves.LevelUpMoves.Length).ToArray(); } if (reset != 0) { generations = generations.Where(z => z >= reset).ToArray(); } int lastgen = generations.LastOrDefault(); foreach (var gen in generations) { ParseMovesByGeneration(pkm, res, gen, info, moveInfo, lastgen); if (AllParsed()) { return(res); } } if (pkm.Species == (int)Species.Shedinja && info.Generation <= 4) { ParseShedinjaEvolveMoves(pkm, res, source.CurrentMoves, info.EvoChainsAllGens); } for (int m = 0; m < 4; m++) { // ReSharper disable once ConditionIsAlwaysTrueOrFalse if (res[m] == null) { res[m] = new CheckMoveResult(Unknown, info.Generation, Invalid, LMoveSourceInvalid, Move); } } return(res); }
private static void ParseMovesByGeneration(PKM pkm, IList <CheckMoveResult> res, int gen, LegalInfo info, LearnInfo learnInfo) { var moves = learnInfo.Source.CurrentMoves; bool native = gen == pkm.Format; for (int m = 0; m < 4; m++) { if (IsCheckValid(res[m])) // already validated with another generation { continue; } int move = moves[m]; if (move == 0) { continue; } if (gen <= 2) { if (gen == 2 && !native && move > Legal.MaxMoveID_1 && pkm.VC1) { res[m] = new CheckMoveResult(Unknown, gen, Invalid, LMoveSourceInvalid, Move); continue; } if (gen == 2 && learnInfo.Source.EggMoveSource.Contains(move)) { res[m] = new CheckMoveResult(EggMove, gen, Valid, LMoveSourceEgg, Move); } else if (learnInfo.Source.Base.Contains(move)) { res[m] = new CheckMoveResult(Initial, gen, Valid, native ? LMoveSourceDefault : string.Format(LMoveFDefault_0, gen), Move); } } if (info.EncounterMoves.LevelUpMoves[gen].Contains(move)) { res[m] = new CheckMoveResult(LevelUp, gen, Valid, native ? LMoveSourceLevelUp : string.Format(LMoveFLevelUp_0, gen), Move); } else if (info.EncounterMoves.TMHMMoves[gen].Contains(move)) { res[m] = new CheckMoveResult(TMHM, gen, Valid, native ? LMoveSourceTMHM : string.Format(LMoveFTMHM_0, gen), Move); } else if (info.EncounterMoves.TutorMoves[gen].Contains(move)) { res[m] = new CheckMoveResult(Tutor, gen, Valid, native ? LMoveSourceTutor : string.Format(LMoveFTutor_0, gen), Move); } else if (gen == info.Generation && learnInfo.Source.SpecialSource.Contains(move)) { res[m] = new CheckMoveResult(Special, gen, Valid, LMoveSourceSpecial, Move); } else if (gen >= 8 && MoveEgg.GetIsSharedEggMove(pkm, gen, move)) { res[m] = new CheckMoveResult(Shared, gen, Valid, native ? LMoveSourceShared : string.Format(LMoveSourceSharedF, gen), Move); } if (gen >= 3 || !IsCheckValid(res[m])) { continue; } // Gen1/Gen2 only below if (gen == 2 && learnInfo.Source.NonTradeBackLevelUpMoves.Contains(m)) { learnInfo.Gen2PreevoMoves.Add(m); } else if (gen == 1) { learnInfo.Gen1Moves.Add(m); if (learnInfo.Gen2PreevoMoves.Count != 0) { learnInfo.MixedGen12NonTradeback = true; } } if (pkm.TradebackStatus == TradebackType.Any && info.Generation != gen) { pkm.TradebackStatus = TradebackType.WasTradeback; } } }
private static CheckMoveResult[] ParseMovesPre3DS(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { if (info.EncounterMatch is EncounterEgg e) { return(pkm.IsEgg ? ParseMovesIsEggPreRelearn(pkm, currentMoves, e) : ParseMovesWasEggPreRelearn(pkm, currentMoves, info, e)); } int gen = info.EncounterMatch.Generation; if (gen <= 2 && (gen == 1 || (gen == 2 && !ParseSettings.AllowGen2MoveReminder(pkm)))) // fixed encounter moves without relearning { return(ParseMovesGenGB(pkm, currentMoves, info)); } return(ParseMovesSpecialMoveset(pkm, currentMoves, info)); }
private static CheckMoveResult[] ParseMovesSpecialMoveset(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { var source = new MoveParseSource { CurrentMoves = currentMoves, SpecialSource = GetSpecialMoves(info.EncounterMatch), }; return(ParseMoves(pkm, source, info)); }
private static void UpdateGen1LevelUpMoves(PKM pkm, ValidEncounterMoves EncounterMoves, int defaultLvlG1, int generation, LegalInfo info) { if (generation >= 3) { return; } var lvlG1 = info.EncounterMatch?.LevelMin + 1 ?? 6; if (lvlG1 == defaultLvlG1) { return; } EncounterMoves.LevelUpMoves[1] = Legal.GetValidMoves(pkm, info.EvoChainsAllGens[1], generation: 1, minLvLG1: lvlG1, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList(); }
private CheckResult VerifyCommonMemory(PKM pkm, int handler, int gen, LegalInfo info) { var memory = MemoryVariableSet.Read((ITrainerMemories)pkm, handler); // Actionable HM moves int matchingMoveMemory = Array.IndexOf(Memories.MoveSpecificMemories[0], memory.MemoryID); if (matchingMoveMemory != -1) { // Gen8 has no HMs, so this memory can never exist. if (gen != 6 || (pkm.Species != (int)Species.Smeargle && !Legal.GetCanLearnMachineMove(pkm, Memories.MoveSpecificMemories[1][matchingMoveMemory], 6))) { return(GetInvalid(string.Format(LMemoryArgBadMove, memory.Handler))); } } switch (memory.MemoryID) { // {0} saw {2} carrying {1} on its back. {4} that {3}. case 21 when gen != 6 || !Legal.GetCanLearnMachineMove(new PK6 { Species = memory.Variable, EXP = Experience.GetEXP(100, PersonalTable.XY.GetFormIndex(memory.Variable, 0)) }, 19, 6): return(GetInvalid(string.Format(LMemoryArgBadMove, memory.Handler))); case 16 or 48 when !CanKnowMove(pkm, memory, gen, info, memory.MemoryID == 16): return(GetInvalid(string.Format(LMemoryArgBadMove, memory.Handler))); case 49 when memory.Variable == 0 || !Legal.GetCanRelearnMove(pkm, memory.Variable, gen, info.EvoChainsAllGens[gen]): return(GetInvalid(string.Format(LMemoryArgBadMove, memory.Handler))); // Dynamaxing // {0} battled at {1}’s side against {2} that Dynamaxed. {4} that {3}. case 71 when !GetCanBeCaptured(memory.Variable, 8, handler == 0 ? (GameVersion)pkm.Version : GameVersion.Any): // {0} battled {2} and Dynamaxed upon {1}’s instruction. {4} that {3}. case 72 when !((PersonalInfoSWSH)PersonalTable.SWSH[memory.Variable]).IsPresentInGame: return(GetInvalid(string.Format(LMemoryArgBadSpecies, handler == 0 ? L_XOT : L_XHT))); // Move // {0} studied about how to use {2} in a Box, thinking about {1}. {4} that {3}. // {0} practiced its cool pose for the move {2} in a Box, wishing to be praised by {1}. {4} that {3}. case 80 or 81 when !CanKnowMove(pkm, memory, gen, info): return(Get(string.Format(LMemoryArgBadMove, memory.Handler), gen == 8 ? Severity.Fishy : Severity.Invalid)); // Species // {0} had a great chat about {1} with the {2} that it was in a Box with. {4} that {3}. // {0} became good friends with the {2} in a Box, practiced moves with it, and talked about the day that {0} would be praised by {1}. {4} that {3}. // {0} got in a fight with the {2} that it was in a Box with about {1}. {4} that {3}. case 82 or 83 or 87 when !((PersonalInfoSWSH)PersonalTable.SWSH[memory.Variable]).IsPresentInGame: return(GetInvalid(string.Format(LMemoryArgBadSpecies, handler == 0 ? L_XOT : L_XHT))); // Item // {0} went to a Pokémon Center with {1} to buy {2}. {4} that {3}. case 5 when !CanBuyItem(gen, memory.Variable): // {1} used {2} when {0} was in trouble. {4} that {3}. case 15 when !CanUseItem(gen, memory.Variable, pkm.Species): // {0} saw {1} using {2}. {4} that {3}. case 26 when !CanUseItemGeneric(gen, memory.Variable): // {0} planted {2} with {1} and imagined a big harvest. {4} that {3}. case 34 when !CanPlantBerry(gen, memory.Variable): // {1} had {0} hold items like {2} to help it along. {4} that {3}. case 40 when !CanHoldItem(gen, memory.Variable): // {0} was excited when {1} won prizes like {2} through Loto-ID. {4} that {3}. case 51 when !CanWinRotoLoto(gen, memory.Variable): // {0} was worried if {1} was looking for the {2} that it was holding in a Box. {4} that {3}. // When {0} was in a Box, it thought about the reason why {1} had it hold the {2}. {4} that {3}. case 84 or 88 when !Legal.HeldItems_SWSH.Contains((ushort)memory.Variable) || pkm.IsEgg: return(GetInvalid(string.Format(LMemoryArgBadItem, memory.Handler))); } if (gen == 6 && !Memories.CanHaveIntensity(memory.MemoryID, memory.Intensity)) { if (pkm.Gen6 || (pkm.Gen7 && memory.MemoryID != 0)) // todo: memory intensity checks for gen8 { return(GetInvalid(string.Format(LMemoryIndexIntensityMin, memory.Handler, Memories.GetMinimumIntensity(memory.MemoryID)))); } } if (gen == 6 && memory.MemoryID != 4 && !Memories.CanHaveFeeling(memory.MemoryID, memory.Feeling)) { if (pkm.Gen6 || (pkm.Gen7 && memory.MemoryID != 0)) // todo: memory feeling checks for gen8 { return(GetInvalid(string.Format(LMemoryFeelInvalid, memory.Handler))); } } return(GetValid(string.Format(LMemoryF_0_Valid, memory.Handler))); }
private static CheckMoveResult[] ParseMoves(PKM pkm, MoveParseSource source, LegalInfo info) { var res = new CheckMoveResult[4]; bool AllParsed() => res.All(z => z != null); var required = pkm.Format != 1 ? 1 : GBRestrictions.GetRequiredMoveCount(pkm, source.CurrentMoves, info, source.Base); // Check empty moves and relearn moves before generation specific moves for (int m = 0; m < 4; m++) { if (source.CurrentMoves[m] == 0) { res[m] = new CheckMoveResult(None, pkm.Format, m < required ? Fishy : Valid, LMoveSourceEmpty, Move); } else if (info.EncounterMoves.Relearn.Contains(source.CurrentMoves[m])) { res[m] = new CheckMoveResult(Relearn, info.Generation, Valid, LMoveSourceRelearn, Move) { Flag = true } } ; } if (AllParsed()) { return(res); } // Encapsulate arguments to simplify method calls var moveInfo = new LearnInfo(pkm, source); // Check moves going backwards, marking the move valid in the most current generation when it can be learned int[] generations = GetGenMovesCheckOrder(pkm); if (pkm.Format <= 2) { generations = generations.Where(z => z < info.EncounterMoves.LevelUpMoves.Length).ToArray(); } int lastgen = generations.LastOrDefault(); foreach (var gen in generations) { ParseMovesByGeneration(pkm, res, gen, info, moveInfo, lastgen); if (AllParsed()) { return(res); } } if (pkm.Species == 292 && info.Generation <= 4) { ParseShedinjaEvolveMoves(pkm, res, source.CurrentMoves); } for (int m = 0; m < 4; m++) { if (res[m] == null) { res[m] = new CheckMoveResult(Unknown, info.Generation, Invalid, LMoveSourceInvalid, Move); } } return(res); }
private static CheckMoveResult[] ParseMovesPre3DS(PKM pkm, int[] currentMoves, LegalInfo info) { if (info.EncounterMatch is EncounterEgg e) { return(pkm.IsEgg ? VerifyPreRelearnEggBase(currentMoves, e) : ParseMovesWasEggPreRelearn(pkm, currentMoves, info, e)); } // Not all games have a re-learner. Initial moves may not fill out all 4 slots. int gen = info.EncounterMatch.Generation; if (gen == 1 || (gen == 2 && !AllowGen2MoveReminder(pkm))) { return(ParseMovesGenGB(pkm, currentMoves, info)); } return(ParseMovesSpecialMoveset(pkm, currentMoves, info)); }
/// <summary> /// Generates possible <see cref="IEncounterable"/> data according to the input PKM data and legality info. /// </summary> /// <param name="pkm">PKM data</param> /// <param name="info">Legality information</param> /// <returns>Possible encounters</returns> /// <remarks> /// The iterator lazily finds possible encounters. If no encounters are possible, the enumerable will be empty. /// </remarks> public static IEnumerable <IEncounterable> GetEncounters(PKM pkm, LegalInfo info) => info.Generation switch { 1 => EncounterGenerator12.GetEncounters12(pkm, info),
public static void AddValidMoves(LegalInfo info, List <string> lines, in int currentFormat)
/// <summary> /// Verifies Evolution scenarios of an <see cref="IEncounterable"/> for an input <see cref="PKM"/> and relevant <see cref="LegalInfo"/>. /// </summary> /// <param name="pkm">Source data to verify</param> /// <param name="info">Source supporting information to verify with</param> /// <returns></returns> public static CheckResult VerifyEvolution(PKM pkm, LegalInfo info) { return(IsValidEvolution(pkm, info) && info.EvoChainsAllGens[pkm.Format].Length >= 1 ? new CheckResult(CheckIdentifier.Evolution) : new CheckResult(Severity.Invalid, V86, CheckIdentifier.Evolution)); }
/// <summary> /// Verifies Evolution scenarios of an <see cref="IEncounterable"/> for an input <see cref="PKM"/> and relevant <see cref="LegalInfo"/>. /// </summary> /// <param name="pkm">Source data to verify</param> /// <param name="info">Source supporting information to verify with</param> /// <returns></returns> public static CheckResult VerifyEvolution(PKM pkm, LegalInfo info) { return(IsValidEvolution(pkm, info) ? new CheckResult(CheckIdentifier.Evolution) : new CheckResult(Severity.Invalid, LEvoInvalid, CheckIdentifier.Evolution)); }
public LevelUpRestriction(PKM pkm, LegalInfo info) { MinimumLevelGen1 = info.Generation <= 2 ? info.EncounterMatch.LevelMin + 1 : 0; MinimumLevelGen2 = ParseSettings.AllowGen2MoveReminder(pkm) ? 1 : info.EncounterMatch.LevelMin + 1; EvolutionChains = info.EvoChainsAllGens; }
private static CheckMoveResult[] ParseMoves3DS(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { info.EncounterMoves.Relearn = info.Generation >= 6 ? pkm.RelearnMoves : Array.Empty <int>(); return(info.EncounterMatch is IMoveset ? ParseMovesSpecialMoveset(pkm, currentMoves, info) : ParseMovesRelearn(pkm, currentMoves, info)); }
private static IEnumerable <IEncounterable> GetEncounters3(PKM pkm, LegalInfo info) { info.PIDIV = MethodFinder.Analyze(pkm); var deferred = new List <IEncounterable>(); foreach (var z in GenerateRawEncounters3(pkm, info)) { if (pkm.Version == (int)GameVersion.CXD) // C/XD { if (z is EncounterSlot w) { var seeds = MethodFinder.GetPokeSpotSeeds(pkm, w.SlotNumber).FirstOrDefault(); info.PIDIV = seeds ?? info.PIDIV; } else if (z is EncounterStaticShadow s) { bool valid = false; if (s.IVs == null) // not ereader { valid = LockFinder.IsAllShadowLockValid(s, info.PIDIV, pkm); } else { var possible = MethodFinder.GetColoEReaderMatches(pkm.EncryptionConstant); foreach (var poss in possible) { if (!LockFinder.IsAllShadowLockValid(s, poss, pkm)) { continue; } valid = true; info.PIDIV = poss; break; } } if (!valid) { deferred.Add(s); continue; } } } if (info.PIDIV.Type.IsCompatible3(z, pkm)) { yield return(z); } else { deferred.Add(z); } } if (deferred.Count == 0) { yield break; } info.PIDIVMatches = false; foreach (var z in deferred) { yield return(z); } }
private static CheckMoveResult[] ParseMovesGenGB(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { var res = new CheckMoveResult[4]; var G1Encounter = info.EncounterMatch; var InitialMoves = Array.Empty <int>(); var SpecialMoves = GetSpecialMoves(info.EncounterMatch); var games = info.EncounterMatch.Generation == 1 ? GBRestrictions.GetGen1Versions(info) : GBRestrictions.GetGen2Versions(info, pkm.Korean); foreach (var ver in games) { var VerInitialMoves = MoveLevelUp.GetEncounterMoves(G1Encounter.Species, 0, G1Encounter.LevelMin, ver); if (VerInitialMoves.Intersect(InitialMoves).Count() == VerInitialMoves.Length) { return(res); } var source = new MoveParseSource { CurrentMoves = currentMoves, SpecialSource = SpecialMoves, Base = VerInitialMoves, }; res = ParseMoves(pkm, source, info); if (res.All(r => r.Valid)) { return(res); } InitialMoves = VerInitialMoves; } return(res); }
private static CheckMoveResult[] ParseMovesWasEggPreRelearn(PKM pkm, int[] Moves, LegalInfo info, EncounterEgg e) { var EventEggMoves = GetSpecialMoves(info.EncounterMatch); // Level up moves could not be inherited if Ditto is parent, // that means genderless species and male only species except Nidoran and Volbeat (they breed with female nidoran and illumise) could not have level up moves as an egg var AllowLevelUp = pkm.PersonalInfo.Gender > 0 && pkm.PersonalInfo.Gender < 255 || Legal.MixedGenderBreeding.Contains(e.Species); int BaseLevel = AllowLevelUp ? 100 : e.LevelMin; var LevelUp = Legal.GetBaseEggMoves(pkm, e.Species, e.Game, BaseLevel); var TradebackPreevo = pkm.Format == 2 && info.EncounterMatch.Species > 151; var NonTradebackLvlMoves = new int[0]; if (TradebackPreevo) { NonTradebackLvlMoves = Legal.GetExclusivePreEvolutionMoves(pkm, info.EncounterMatch.Species, info.EvoChainsAllGens[2], 2, e.Game).Where(m => m > Legal.MaxMoveID_1).ToArray(); } var Egg = Legal.GetEggMoves(pkm, e.Species, pkm.AltForm); if (info.Generation < 3 && pkm.Format >= 7 && pkm.VC1) { Egg = Egg.Where(m => m <= Legal.MaxMoveID_1).ToArray(); } bool volt = (info.Generation > 3 || e.Game == GameVersion.E) && Legal.LightBall.Contains(pkm.Species); var Special = volt && EventEggMoves.Length == 0 ? new[] { 344 } : new int[0]; // Volt Tackle for bred Pichu line var source = new MoveParseSource { CurrentMoves = Moves, SpecialSource = Special, NonTradeBackLevelUpMoves = NonTradebackLvlMoves, EggLevelUpSource = LevelUp, EggMoveSource = Egg, EggEventSource = EventEggMoves, }; return(ParseMoves(pkm, source, info)); }
private static CheckMoveResult[] ParseMovesRelearn(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { var source = new MoveParseSource { CurrentMoves = currentMoves, SpecialSource = GetSpecialMoves(info.EncounterMatch), }; if (info.EncounterMatch is EncounterEgg e) { source.EggMoveSource = MoveEgg.GetEggMoves(pkm, e.Species, e.Form, e.Version); } var res = ParseMoves(pkm, source, info); var relearn = pkm.RelearnMoves; for (int i = 0; i < 4; i++) { if ((pkm.IsEgg || res[i].IsRelearn) && !relearn.Contains(currentMoves[i])) { res[i] = new CheckMoveResult(res[i], Invalid, string.Format(LMoveRelearnFMiss_0, res[i].Comment), res[i].Identifier); } } return(res); }
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.LevelUpMoves[2] = Legal.GetValidMoves(pkm, info.EvoChainsAllGens[2], generation: 2, minLvLG2: defaultLvlG2, LVL: true, Tutor: false, Machine: false, MoveReminder: false).ToList(); } break; } }
private static void ParseMovesByGeneration(PKM pkm, CheckMoveResult[] res, int gen, LegalInfo info, LearnInfo learnInfo, int last) { GetHMCompatibility(pkm, res, gen, learnInfo.Source.CurrentMoves, out bool[] HMLearned, out bool KnowDefogWhirlpool); ParseMovesByGeneration(pkm, res, gen, info, learnInfo); if (gen == last) { ParseMovesByGenerationLast(pkm, res, learnInfo, info.EncounterMatch); } switch (gen) { case 1: case 2: ParseMovesByGeneration12(pkm, res, learnInfo.Source.CurrentMoves, gen, info, learnInfo); break; case 3: case 4: if (pkm.Format > gen) { FlagIncompatibleTransferHMs45(res, learnInfo.Source.CurrentMoves, gen, HMLearned, KnowDefogWhirlpool); } break; } // Pokemon that evolved by leveling up while learning a specific move // This pokemon could only have 3 moves from preevolutions that are not the move used to evolved // including special and eggs moves before relearn generations if (EvolutionRestrictions.SpeciesEvolutionWithMove.Contains(pkm.Species)) { ParseEvolutionLevelupMove(pkm, res, learnInfo.Source.CurrentMoves, info); } }
private static CheckMoveResult[] ParseMoves(PKM pkm, MoveParseSource source, LegalInfo info) { CheckMoveResult[] res = new CheckMoveResult[4]; bool AllParsed() => res.All(r => r != null); var required = Legal.GetRequiredMoveCount(pkm, source.CurrentMoves, info, source.Base); // Check empty moves and relearn moves before generation specific moves for (int m = 0; m < 4; m++) { if (source.CurrentMoves[m] == 0) { res[m] = new CheckMoveResult(MoveSource.None, pkm.Format, m < required ? Severity.Fishy : Severity.Valid, V167, CheckIdentifier.Move); } else if (info.EncounterMoves.Relearn.Contains(source.CurrentMoves[m])) { res[m] = new CheckMoveResult(MoveSource.Relearn, info.Generation, Severity.Valid, V172, CheckIdentifier.Move) { Flag = true } } ; } if (AllParsed()) { return(res); } // Encapsulate arguments to simplify method calls var moveInfo = new LearnInfo(pkm) { Source = source }; // Check moves going backwards, marking the move valid in the most current generation when it can be learned int[] generations = GetGenMovesCheckOrder(pkm); if (pkm.Format <= 2) { generations = generations.Where(z => z < info.EncounterMoves.LevelUpMoves.Length).ToArray(); } int lastgen = generations.LastOrDefault(); foreach (var gen in generations) { ParseMovesByGeneration(pkm, res, gen, info, moveInfo, lastgen); if (AllParsed()) { return(res); } } if (pkm.Species == 292 && info.EncounterMatch.Species != 292) { // Ignore Shedinja if the Encounter was also a Shedinja, assume null Encounter as a Nincada egg // Check Shedinja evolved moves from Ninjask after egg moves // Those moves could also be inherited egg moves ParseShedinjaEvolveMoves(pkm, res, source.CurrentMoves); } for (int m = 0; m < 4; m++) { if (res[m] == null) { res[m] = new CheckMoveResult(MoveSource.Unknown, info.Generation, Severity.Invalid, V176, CheckIdentifier.Move); } } return(res); }
private static void ParseMovesByGeneration12(PKM pkm, CheckMoveResult[] res, IReadOnlyList <int> currentMoves, int gen, LegalInfo info, LearnInfo learnInfo) { // Mark the gen 1 exclusive moves as illegal because the pokemon also have Non tradeback egg moves. if (learnInfo.MixedGen12NonTradeback) { foreach (int m in learnInfo.Gen1Moves) { res[m] = new CheckMoveResult(res[m], Invalid, LG1MoveExclusive, Move); } foreach (int m in learnInfo.Gen2PreevoMoves) { res[m] = new CheckMoveResult(res[m], Invalid, LG1TradebackPreEvoMove, Move); } } if (gen == 1 && pkm.Format == 1 && pkm.Gen1_NotTradeback) { ParseRedYellowIncompatibleMoves(pkm, res, currentMoves); ParseEvolutionsIncompatibleMoves(pkm, res, currentMoves, info.EncounterMoves.TMHMMoves[1]); } }
private static void ParseMovesByGeneration(PKM pkm, CheckMoveResult[] res, int gen, LegalInfo info, LearnInfo learnInfo) { var moves = learnInfo.Source.CurrentMoves; bool native = gen == pkm.Format; for (int m = 0; m < 4; m++) { if (IsCheckValid(res[m])) // already validated with another generation { continue; } int move = moves[m]; if (move == 0) { continue; } if (gen <= 2 && learnInfo.Source.Base.Contains(move)) { res[m] = new CheckMoveResult(MoveSource.Initial, gen, Severity.Valid, native ? V361 : string.Format(V362, gen), CheckIdentifier.Move); } if (gen == 2 && !native && move > Legal.MaxMoveID_1 && pkm.VC1) { res[m] = new CheckMoveResult(MoveSource.Unknown, gen, Severity.Invalid, V176, CheckIdentifier.Move); } else if (info.EncounterMoves.LevelUpMoves[gen].Contains(move)) { res[m] = new CheckMoveResult(MoveSource.LevelUp, gen, Severity.Valid, native ? V177 : string.Format(V330, gen), CheckIdentifier.Move); } else if (info.EncounterMoves.TMHMMoves[gen].Contains(move)) { res[m] = new CheckMoveResult(MoveSource.TMHM, gen, Severity.Valid, native ? V173 : string.Format(V331, gen), CheckIdentifier.Move); } else if (info.EncounterMoves.TutorMoves[gen].Contains(move)) { res[m] = new CheckMoveResult(MoveSource.Tutor, gen, Severity.Valid, native ? V174 : string.Format(V332, gen), CheckIdentifier.Move); } else if (gen == info.Generation && learnInfo.Source.SpecialSource.Contains(move)) { res[m] = new CheckMoveResult(MoveSource.Special, gen, Severity.Valid, V175, CheckIdentifier.Move); } if (res[m] == null || gen >= 3) { continue; } if (res[m].Valid && gen == 2 && learnInfo.Source.NonTradeBackLevelUpMoves.Contains(m)) { learnInfo.Gen2PreevoMoves.Add(m); } if (res[m].Valid && gen == 1) { learnInfo.Gen1Moves.Add(m); if (learnInfo.Gen2PreevoMoves.Any()) { learnInfo.MixedGen12NonTradeback = true; } } if (res[m].Valid && gen <= 2 && pkm.TradebackStatus == TradebackType.Any && info.Generation != gen) { pkm.TradebackStatus = TradebackType.WasTradeback; } } }
private static CheckMoveResult[] ParseMovesForSmeargle(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info) { if (!pkm.IsEgg) { return(ParseMovesSketch(pkm, currentMoves)); } // can only know sketch as egg var levelup = new int[info.EvoChainsAllGens.Length][]; levelup[pkm.Format] = new[] { 166 }; info.EncounterMoves = new ValidEncounterMoves(levelup); var source = new MoveParseSource { CurrentMoves = currentMoves, }; return(ParseMoves(pkm, source, info)); }
private static void ParseEvolutionLevelupMove(PKM pkm, IList <CheckMoveResult> res, int[] moves, List <int> IncenseMovesLearned, LegalInfo info) { // Ignore if there is an invalid move or an empty move, this validation is only for 4 non-empty moves that are all valid, but invalid as a 4 combination // Ignore Mr. Mime and Sudowodoo from generations 1 to 3, they cant be evolved from Bonsly or Munchlax // Ignore if encounter species is the evolution species, the pokemon was not evolved by the player if (!res.All(r => r?.Valid ?? false) || moves.Any(m => m == 0) || (Legal.BabyEvolutionWithMove.Contains(pkm.Species) && pkm.GenNumber <= 3) || info.EncounterMatch.Species == pkm.Species) { return; } var ValidMoves = Legal.GetValidPostEvolutionMoves(pkm, pkm.Species, info.EvoChainsAllGens, GameVersion.Any); // Add the evolution moves to valid moves in case some of these moves could not be learned after evolving switch (pkm.Species) { case 122: // Mr. Mime (Mime Jr with Mimic) case 185: // Sudowoodo (Bonsly with Mimic) ValidMoves.Add(102); break; case 424: // Ambipom (Aipom with Double Hit) ValidMoves.Add(458); break; case 463: // Lickilicky (Lickitung with Rollout) ValidMoves.Add(205); break; case 465: // Tangrowth (Tangela with Ancient Power) case 469: // Yanmega (Yamma with Ancient Power) case 473: // Mamoswine (Piloswine with Ancient Power) ValidMoves.Add(246); break; case 700: // Sylveon (Eevee with Fairy Move) // Add every fairy moves without cheking if eevee learn it or not, pokemon moves are determined legal before this function ValidMoves.AddRange(Legal.FairyMoves); break; case 763: // Tsareena (Steenee with Stomp) ValidMoves.Add(023); break; } if (moves.Any(m => ValidMoves.Contains(m))) { return; } for (int m = 0; m < 4; m++) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, string.Format(V385, SpeciesStrings[pkm.Species]), CheckIdentifier.Move); } }
private static CheckMoveResult[] ParseMovesWasEggPreRelearn(PKM pkm, IReadOnlyList <int> currentMoves, LegalInfo info, EncounterEgg e) { var EventEggMoves = GetSpecialMoves(info.EncounterMatch); bool notEvent = EventEggMoves.Count == 0; // Level up moves could not be inherited if Ditto is parent, // that means genderless species and male only species (except Nidoran-M and Volbeat; they breed with Nidoran-F and Illumise) could not have level up moves as an egg var pi = pkm.PersonalInfo; var AllowLevelUp = notEvent && !pi.Genderless && !(pi.OnlyMale && Legal.MixedGenderBreeding.Contains(e.Species)); int BaseLevel = AllowLevelUp ? 100 : e.LevelMin; var LevelUp = MoveList.GetBaseEggMoves(pkm, e.Species, e.Form, e.Version, BaseLevel); var TradebackPreevo = pkm.Format == 2 && info.EncounterMatch.Species > 151; var NonTradebackLvlMoves = TradebackPreevo ? MoveList.GetExclusivePreEvolutionMoves(pkm, info.EncounterMatch.Species, info.EvoChainsAllGens[2], 2, e.Version).Where(m => m > Legal.MaxMoveID_1).ToArray() : Array.Empty <int>(); var Egg = MoveEgg.GetEggMoves(pkm, e.Species, e.Form, e.Version); if (info.Generation < 3 && pkm.Format >= 7 && pkm.VC1) { Egg = Egg.Where(m => m <= Legal.MaxMoveID_1).ToArray(); } bool volt = (info.Generation > 3 || e.Version == GameVersion.E) && Legal.LightBall.Contains(pkm.Species); var Special = volt && notEvent ? new[] { 344 } : Array.Empty <int>(); // Volt Tackle for bred Pichu line var source = new MoveParseSource { CurrentMoves = currentMoves, SpecialSource = Special, NonTradeBackLevelUpMoves = NonTradebackLvlMoves, EggLevelUpSource = LevelUp, EggMoveSource = Egg, EggEventSource = EventEggMoves, }; return(ParseMoves(pkm, source, info)); }
private static CheckMoveResult[] ParseMoves(PKM pkm, int[] moves, int[] special, int[] lvlupegg, int[] egg, int[] NonTradebackLvlMoves, int[] eventegg, int[] initialmoves, LegalInfo info) { CheckMoveResult[] res = new CheckMoveResult[4]; var required = Legal.GetRequiredMoveCount(pkm, moves, info, initialmoves); // Check none moves and relearn moves before generation moves for (int m = 0; m < 4; m++) { if (moves[m] == 0) { res[m] = new CheckMoveResult(MoveSource.None, pkm.Format, m < required ? Severity.Fishy : Severity.Valid, V167, CheckIdentifier.Move); } else if (info.EncounterMoves.Relearn.Contains(moves[m])) { res[m] = new CheckMoveResult(MoveSource.Relearn, pkm.GenNumber, Severity.Valid, V172, CheckIdentifier.Move) { Flag = true } } ; } if (res.All(r => r != null)) { return(res); } bool MixedGen1NonTradebackGen2 = false; var Gen1MovesLearned = new List <int>(); var Gen2PreevoMovesLearned = new List <int>(); var EggMovesLearned = new List <int>(); var LvlupEggMovesLearned = new List <int>(); var EventEggMovesLearned = new List <int>(); var IsGen2Pkm = pkm.Format == 2 || pkm.VC2; var IncenseMovesLearned = new List <int>(); // Check moves going backwards, marking the move valid in the most current generation when it can be learned int[] generations = GetGenMovesCheckOrder(pkm); if (pkm.Format <= 2) { generations = generations.Where(z => z < info.EncounterMoves.LevelUpMoves.Length).ToArray(); } foreach (var gen in generations) { var HMLearned = new int[0]; // Check if pokemon knows HM moves from generation 3 and 4 but are not valid yet, that means it cant learn the HMs in future generations bool KnowDefogWhirlpool = false; if (gen == 4 && pkm.Format > 4) { // Copy to array the hm found or else the list will be emptied when the legal status of moves changes in the current generation HMLearned = moves.Where((m, i) => !(res[i]?.Valid ?? false) && Legal.HM_4_RemovePokeTransfer.Any(l => l == m)).Select((m, i) => i).ToArray(); // Defog and Whirlpool at the same time, also both can't be learned in future generations or else they will be valid KnowDefogWhirlpool = moves.Where((m, i) => (m == 250 || m == 432) && !(res[i]?.Valid ?? false)).Count() == 2; } else if (gen == 3 && pkm.Format > 3) { HMLearned = moves.Select((m, i) => i).Where(i => !(res[i]?.Valid ?? false) && Legal.HM_3.Any(l => l == moves[i])).ToArray(); } bool native = gen == pkm.Format; for (int m = 0; m < 4; m++) { if (res[m]?.Valid ?? false) { continue; } if (moves[m] == 0) { continue; } if (gen == 1 && initialmoves.Contains(moves[m])) { res[m] = new CheckMoveResult(MoveSource.Initial, gen, Severity.Valid, native ? V361 : string.Format(V362, gen), CheckIdentifier.Move); } else if (info.EncounterMoves.LevelUpMoves[gen].Contains(moves[m])) { res[m] = new CheckMoveResult(MoveSource.LevelUp, gen, Severity.Valid, native ? V177 : string.Format(V330, gen), CheckIdentifier.Move); } else if (info.EncounterMoves.TMHMMoves[gen].Contains(moves[m])) { res[m] = new CheckMoveResult(MoveSource.TMHM, gen, Severity.Valid, native ? V173 : string.Format(V331, gen), CheckIdentifier.Move); } else if (info.EncounterMoves.TutorMoves[gen].Contains(moves[m])) { res[m] = new CheckMoveResult(MoveSource.Tutor, gen, Severity.Valid, native ? V174 : string.Format(V332, gen), CheckIdentifier.Move); } else if (gen == pkm.GenNumber && special.Contains(moves[m])) { res[m] = new CheckMoveResult(MoveSource.Special, gen, Severity.Valid, V175, CheckIdentifier.Move); } if (res[m] == null || gen >= 3) { continue; } if (res[m].Valid && gen == 2 && NonTradebackLvlMoves.Contains(m)) { Gen2PreevoMovesLearned.Add(m); } if (res[m].Valid && gen == 1) { Gen1MovesLearned.Add(m); if (Gen2PreevoMovesLearned.Any()) { MixedGen1NonTradebackGen2 = true; } } if (res[m].Valid && gen <= 2 && pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber != gen) { pkm.TradebackStatus = TradebackType.WasTradeback; } } if (gen == generations.Last()) { // Check higher-level moves after all the moves but just before egg moves to differentiate it from normal level up moves // Also check if the base egg moves is a non tradeback move for (int m = 0; m < 4; m++) { if (res[m]?.Valid ?? false) // Skip valid move { continue; } if (moves[m] == 0) { continue; } if (!lvlupegg.Contains(moves[m])) // Check if contains level-up egg moves from parents { continue; } if (IsGen2Pkm && Gen1MovesLearned.Any() && moves[m] > Legal.MaxMoveID_1) { res[m] = new CheckMoveResult(MoveSource.InheritLevelUp, gen, Severity.Invalid, V334, CheckIdentifier.Move); MixedGen1NonTradebackGen2 = true; } else { res[m] = new CheckMoveResult(MoveSource.InheritLevelUp, gen, Severity.Valid, V345, CheckIdentifier.Move); } LvlupEggMovesLearned.Add(m); if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1) { pkm.TradebackStatus = TradebackType.WasTradeback; } } // Check egg moves after all the generations and all the moves, every move that can't be learned in another source should have preference // the moves that can only be learned from egg moves should in the future check if the move combinations can be breed in gens 2 to 5 for (int m = 0; m < 4; m++) { if (res[m]?.Valid ?? false) { continue; } if (moves[m] == 0) { continue; } if (egg.Contains(moves[m])) { if (IsGen2Pkm && Gen1MovesLearned.Any() && moves[m] > Legal.MaxMoveID_1) { // To learn exclusive generation 1 moves the pokemon was tradeback, but it can't be trade to generation 1 // without removing moves above MaxMoveID_1, egg moves above MaxMoveID_1 and gen 1 moves are incompatible res[m] = new CheckMoveResult(MoveSource.EggMove, gen, Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true }; MixedGen1NonTradebackGen2 = true; } else { res[m] = new CheckMoveResult(MoveSource.EggMove, gen, Severity.Valid, V171, CheckIdentifier.Move) { Flag = true } }; EggMovesLearned.Add(m); if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1) { pkm.TradebackStatus = TradebackType.WasTradeback; } } if (!eventegg.Contains(moves[m])) { continue; } if (!egg.Contains(moves[m])) { if (IsGen2Pkm && Gen1MovesLearned.Any() && moves[m] > Legal.MaxMoveID_1) { res[m] = new CheckMoveResult(MoveSource.SpecialEgg, gen, Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true }; MixedGen1NonTradebackGen2 = true; } else { res[m] = new CheckMoveResult(MoveSource.SpecialEgg, gen, Severity.Valid, V333, CheckIdentifier.Move) { Flag = true } }; } if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1) { pkm.TradebackStatus = TradebackType.WasTradeback; } EventEggMovesLearned.Add(m); } // A pokemon could have normal egg moves and regular egg moves // Only if all regular egg moves are event egg moves or all event egg moves are regular egg moves var RegularEggMovesLearned = EggMovesLearned.Union(LvlupEggMovesLearned).ToList(); if (RegularEggMovesLearned.Any() && EventEggMovesLearned.Any()) { // Moves that are egg moves or event egg moves but not both var IncompatibleEggMoves = RegularEggMovesLearned.Except(EventEggMovesLearned).Union(EventEggMovesLearned.Except(RegularEggMovesLearned)).ToList(); if (IncompatibleEggMoves.Any()) { foreach (int m in IncompatibleEggMoves) { if (EventEggMovesLearned.Contains(m) && !EggMovesLearned.Contains(m)) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, V337, CheckIdentifier.Move); } else if (!EventEggMovesLearned.Contains(m) && EggMovesLearned.Contains(m)) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, V336, CheckIdentifier.Move); } else if (!EventEggMovesLearned.Contains(m) && LvlupEggMovesLearned.Contains(m)) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, V358, CheckIdentifier.Move); } } } } // If there is no incompatibility with event egg check that there is no inherited move in gift eggs and event eggs else if (RegularEggMovesLearned.Any() && (pkm.WasGiftEgg || pkm.WasEventEgg)) { foreach (int m in RegularEggMovesLearned) { if (EggMovesLearned.Contains(m)) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, pkm.WasGiftEgg ? V377 : V341, CheckIdentifier.Move); } else if (LvlupEggMovesLearned.Contains(m)) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, pkm.WasGiftEgg ? V378 : V347, CheckIdentifier.Move); } } } } if (3 <= gen && gen <= 4 && pkm.Format > gen) { // After all the moves from the generations 3 and 4, // including egg moves if is the origin generation because some hidden moves are also special egg moves in gen 3 // Check if the marked hidden moves that were invalid at the start are now marked as valid, that means // the hidden move was learned in gen 3 or 4 but was not removed when transfer to 4 or 5 if (KnowDefogWhirlpool) { int invalidCount = moves.Where((m, i) => (m == 250 || m == 432) && (res[i]?.Valid ?? false)).Count(); if (invalidCount == 2) // can't know both at the same time { for (int i = 0; i < 4; i++) // flag both moves { if (moves[i] == 250 || moves[i] == 432) { res[i] = new CheckMoveResult(res[i], Severity.Invalid, V338, CheckIdentifier.Move); } } } } for (int i = 0; i < HMLearned.Length; i++) { if (res[i]?.Valid ?? false) { res[i] = new CheckMoveResult(res[i], Severity.Invalid, string.Format(V339, gen, gen + 1), CheckIdentifier.Move); } } } // Mark the gen 1 exclusive moves as illegal because the pokemon also have Non tradeback egg moves. if (MixedGen1NonTradebackGen2) { foreach (int m in Gen1MovesLearned) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, V335, CheckIdentifier.Move); } foreach (int m in Gen2PreevoMovesLearned) { res[m] = new CheckMoveResult(res[m], Severity.Invalid, V412, CheckIdentifier.Move); } } if (gen == 1 && pkm.Format == 1 && pkm.Gen1_NotTradeback) { // Check moves learned at the same level in red/blue and yellow, illegal because there is no move reminder // Only two incompatibilites and only there are no illegal combination if generation 2 or 7 are included in the analysis ParseRedYellowIncompatibleMoves(pkm, res, moves); ParseEvolutionsIncompatibleMoves(pkm, res, moves, info.EncounterMoves.TMHMMoves[1]); } if (Legal.SpeciesEvolutionWithMove.Contains(pkm.Species)) { // Pokemon that evolved by leveling up while learning a specific move // This pokemon could only have 3 moves from preevolutions that are not the move used to evolved // including special and eggs moves before realearn generations ParseEvolutionLevelupMove(pkm, res, moves, IncenseMovesLearned, info); } if (res.All(r => r != null)) { return(res); } } if (pkm.Species == 292 && info.EncounterMatch.Species != 292) { // Ignore Shedinja if the Encounter was also a Shedinja, assume null Encounter as a Nincada egg // Check Shedinja evolved moves from Ninjask after egg moves // Those moves could also be inherited egg moves ParseShedinjaEvolveMoves(pkm, res, moves); } for (int m = 0; m < 4; m++) { if (res[m] == null) { res[m] = new CheckMoveResult(MoveSource.Unknown, pkm.GenNumber, Severity.Invalid, V176, CheckIdentifier.Move); } } return(res); }