コード例 #1
0
ファイル: VerifyCurrentMoves.cs プロジェクト: ZeroX1ng/PKHeX
        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);
        }
コード例 #2
0
        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);
            }
        }
コード例 #3
0
        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();
        }
コード例 #4
0
        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);
        }
コード例 #5
0
        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;
                }
            }
        }
コード例 #6
0
        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));
        }
コード例 #7
0
        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));
        }
コード例 #8
0
ファイル: VerifyCurrentMoves.cs プロジェクト: Metryra/PKHeX
        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();
        }
コード例 #9
0
ファイル: MemoryVerifier.cs プロジェクト: Bappsack/PKHeX
        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)));
        }
コード例 #10
0
ファイル: VerifyCurrentMoves.cs プロジェクト: alnidu/PKHeX
        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);
        }
コード例 #11
0
        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));
        }
コード例 #12
0
 /// <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),
コード例 #13
0
 public static void AddValidMoves(LegalInfo info, List <string> lines, in int currentFormat)
コード例 #14
0
ファイル: EvolutionVerifier.cs プロジェクト: iiippppk/PKHeX
 /// <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));
 }
コード例 #15
0
 /// <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));
 }
コード例 #16
0
 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;
 }
コード例 #17
0
 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));
 }
コード例 #18
0
        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);
            }
        }
コード例 #19
0
        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);
        }
コード例 #20
0
        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));
        }
コード例 #21
0
        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);
        }
コード例 #22
0
 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;
     }
 }
コード例 #23
0
        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);
            }
        }
コード例 #24
0
        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);
        }
コード例 #25
0
        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]);
            }
        }
コード例 #26
0
        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;
                }
            }
        }
コード例 #27
0
        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));
        }
コード例 #28
0
        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);
            }
        }
コード例 #29
0
        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));
        }
コード例 #30
0
        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);
        }