Пример #1
0
        private static EvolutionMethod GetMethod(byte[] data, int offset)
        {
            var method  = data[offset]; // other byte unnecessary
            int arg     = BitConverter.ToUInt16(data, offset + 2);
            int species = BitConverter.ToUInt16(data, offset + 4);

            if (method == 0)
            {
                throw new ArgumentException(nameof(data));
            }

            // To have the same structure as gen 6
            // Gen 4 Method 6 is Gen 6 Method 7, G4 7 = G6 8, and so on
            if (method > 6)
            {
                method++;
            }

            var evo = new EvolutionMethod
            {
                Method   = method,
                Argument = arg,
                Species  = species,
                Level    = arg,
            };

            if (EvolutionSet6.EvosWithArg.Contains(method))
            {
                evo.Level = 0;
            }
            return(evo);
        }
Пример #2
0
        public static List <EvolutionSet> GetArray(byte[] data)
        {
            EvolutionSet[] evos = new EvolutionSet[Legal.MaxSpeciesID_3 + 1];
            evos[0] = new EvolutionSet3 {
                PossibleEvolutions = new EvolutionMethod[0]
            };
            for (int i = 0; i <= Legal.MaxSpeciesIndex_3; i++)
            {
                int g4species = SpeciesConverter.GetG4Species(i);
                if (g4species == 0)
                {
                    continue;
                }

                int offset = i * 40;
                var m_list = new List <EvolutionMethod>();
                for (int j = 0; j < 5; j++)
                {
                    EvolutionMethod m = GetMethod(data, offset);
                    if (m != null)
                    {
                        m_list.Add(m);
                    }
                    else
                    {
                        break;
                    }
                    offset += 8;
                }
                evos[g4species] = new EvolutionSet3 {
                    PossibleEvolutions = m_list.ToArray()
                };
            }
            return(evos.ToList());
        }
Пример #3
0
        public static List <EvolutionSet> getArray(byte[] data)
        {
            var evos = new List <EvolutionSet>();

            for (int i = 0; i <= Legal.MaxSpeciesIndex_4_HGSSPt; i++)
            {
                /* 44 bytes per species,
                 * for every species 7 evolutions with 6 bytes per evolution,
                 * last 2 bytes of every specie is padding*/
                int offset = i * 44;
                var m_list = new List <EvolutionMethod>();
                for (int j = 0; j < 7; j++)
                {
                    EvolutionMethod m = getMethod(data, offset);
                    if (m != null)
                    {
                        m_list.Add(m);
                    }
                    else
                    {
                        break;
                    }
                    offset += 6;
                }
                evos.Add(new EvolutionSet4 {
                    PossibleEvolutions = m_list.ToArray()
                });
            }
            return(evos.ToList());
        }
Пример #4
0
        private static EvolutionMethod GetMethod(byte[] data, int offset)
        {
            var method  = data[offset]; // other byte unnecessary
            int arg     = BitConverter.ToUInt16(data, offset + 2);
            int species = BitConverter.ToUInt16(data, offset + 4);

            if (method == 0)
            {
                throw new ArgumentException(nameof(data));
            }

            var evo = new EvolutionMethod
            {
                Method   = method,
                Argument = arg,
                Species  = species,
                Level    = arg,
            };

            if (EvolutionSet6.EvosWithArg.Contains(method))
            {
                evo.Level = 0;
            }
            return(evo);
        }
Пример #5
0
        public static List <EvolutionSet> GetArray(byte[] data)
        {
            var       evos    = new List <EvolutionSet>();
            const int bpe     = 6;  // bytes per evolution entry
            const int entries = 7;  // 7 * 6 = 42, + 2 alignment bytes
            const int size    = 44; // bytes per species entry

            int count = data.Length / size;

            for (int i = 0; i < count; i++)
            {
                int offset = i * size;
                var m_list = new List <EvolutionMethod>();
                for (int j = 0; j < entries; j++)
                {
                    EvolutionMethod m = GetMethod(data, offset);
                    if (m != null)
                    {
                        m_list.Add(m);
                    }
                    else
                    {
                        break;
                    }
                    offset += bpe;
                }
                evos.Add(new EvolutionSet4 {
                    PossibleEvolutions = m_list.ToArray()
                });
            }
            return(evos);
        }
Пример #6
0
        private static EvolutionMethod GetMethod(byte[] data, int offset)
        {
            int[] argEvos = { 6, 8, 16, 17, 18, 19, 20, 21, 22 };
            int   method  = BitConverter.ToUInt16(data, offset + 0);
            int   arg     = BitConverter.ToUInt16(data, offset + 2);
            int   species = BitConverter.ToUInt16(data, offset + 4);

            if (method == 0)
            {
                return(null);
            }

            var evo = new EvolutionMethod
            {
                Method   = method,
                Argument = arg,
                Species  = species,
                Level    = arg,
            };

            if (argEvos.Contains(evo.Method))
            {
                evo.Level = 0;
            }
            return(evo);
        }
Пример #7
0
        public static IReadOnlyList <EvolutionMethod[]> GetArray(byte[] data, int maxSpecies)
        {
            var       evos = new EvolutionMethod[maxSpecies + 1][];
            int       ofs  = 0;
            const int bpe  = 3;

            for (int i = 0; i < evos.Length; i++)
            {
                int count = data[ofs];
                ofs++;
                if (count == 0)
                {
                    evos[i] = Array.Empty <EvolutionMethod>();
                    continue;
                }
                var m = new EvolutionMethod[count];
                for (int j = 0; j < m.Length; j++)
                {
                    m[j] = GetMethod(data, ofs);
                    ofs += bpe;
                }
                evos[i] = m;
            }
            return(evos);
        }
Пример #8
0
        public static List <EvolutionSet> GetArray(byte[] data)
        {
            var evos = new List <EvolutionSet>();

            for (int i = 0; i <= Legal.MaxSpeciesIndex_5_B2W2; i++)
            {
                /* 42 bytes per species,
                 * for every species 7 evolutions with 6 bytes per evolution*/
                int offset = i * 42;
                var m_list = new List <EvolutionMethod>();
                for (int j = 0; j < 7; j++)
                {
                    EvolutionMethod m = GetMethod(data, offset);
                    if (m != null)
                    {
                        m_list.Add(m);
                    }
                    else
                    {
                        break;
                    }
                    offset += 6;
                }
                evos.Add(new EvolutionSet5 {
                    PossibleEvolutions = m_list.ToArray()
                });
            }
            return(evos);
        }
Пример #9
0
        private static EvolutionMethod[] GetMethods(byte[] data)
        {
            var evos = new EvolutionMethod[data.Length / SIZE];

            for (int i = 0; i < data.Length; i += SIZE)
            {
                var evo = new EvolutionMethod
                {
                    Method   = BitConverter.ToUInt16(data, i + 0),
                    Argument = BitConverter.ToUInt16(data, i + 2),
                    Species  = BitConverter.ToUInt16(data, i + 4),

                    // Copy
                    Level = BitConverter.ToUInt16(data, i + 2),
                };

                // Argument is used by both Level argument and Item/Move/etc. Clear if appropriate.
                if (EvosWithArg.Contains(evo.Method))
                {
                    evo.Level = 0;
                }

                evos[i / SIZE] = evo;
            }
            return(evos);
        }
Пример #10
0
        public void Insert(EvolutionMethod entry)
        {
            int matchChain = -1;

            for (int i = 0; i < Chain.Count; i++)
            {
                if (Chain[i].StageEntryMethods.Any(e => e.Species == entry.Species))
                {
                    matchChain = i;
                }
            }

            if (matchChain != -1)
            {
                Chain[matchChain].StageEntryMethods.Add(entry);
            }
            else
            {
                Chain.Insert(0, new EvolutionStage {
                    StageEntryMethods = new List <EvolutionMethod> {
                        entry
                    }
                });
            }
        }
Пример #11
0
        public EvolutionSet6(byte[] data)
        {
            if (data.Length < SIZE || data.Length % SIZE != 0)
            {
                return;
            }
            int[] argEvos = { 6, 8, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34 };
            PossibleEvolutions = new EvolutionMethod[data.Length / SIZE];
            for (int i = 0; i < data.Length; i += SIZE)
            {
                var evo = new EvolutionMethod
                {
                    Method   = BitConverter.ToUInt16(data, i + 0),
                    Argument = BitConverter.ToUInt16(data, i + 2),
                    Species  = BitConverter.ToUInt16(data, i + 4),

                    // Copy
                    Level = BitConverter.ToUInt16(data, i + 2),
                };

                // Argument is used by both Level argument and Item/Move/etc. Clear if appropriate.
                if (argEvos.Contains(evo.Method))
                {
                    evo.Level = 0;
                }

                PossibleEvolutions[i / SIZE] = evo;
            }
        }
Пример #12
0
        private static EvolutionMethod GetMethod(byte[] data, int offset)
        {
            int[] argEvos = { 6, 8, 16, 17, 18, 19, 20, 21, 22 };
            int   method  = BitConverter.ToUInt16(data, offset + 0);
            int   arg     = BitConverter.ToUInt16(data, offset + 2);
            int   species = BitConverter.ToUInt16(data, offset + 4);

            if (method == 0)
            {
                return(null);
            }
            // To have the same estructure as gen 6
            // Gen 4 Method 6 is Gen 6 Method 7, G4 7 = G6 8, and so on
            if (method > 6)
            {
                method++;
            }

            var evo = new EvolutionMethod
            {
                Method   = method,
                Argument = arg,
                Species  = species,
                Level    = arg,
            };

            if (argEvos.Contains(evo.Method))
            {
                evo.Level = 0;
            }
            return(evo);
        }
Пример #13
0
        public static IReadOnlyList <EvolutionMethod[]> GetArray(IReadOnlyList <byte[]> data)
        {
            var evos = new EvolutionMethod[data.Count][];

            for (int i = 0; i < evos.Length; i++)
            {
                evos[i] = GetMethods(data[i]);
            }
            return(evos);
        }
Пример #14
0
        private static EvolutionMethod[] GetMethods(ReadOnlySpan <byte> data)
        {
            var evos = new EvolutionMethod[data.Length / SIZE];

            for (int i = 0; i < data.Length; i += SIZE)
            {
                var entry = data.Slice(i, SIZE);
                evos[i / SIZE] = ReadEvolution(entry);
            }
            return(evos);
        }
Пример #15
0
        public void Insert(EvolutionMethod entry)
        {
            int matchChain = -1;
            for (int i = 0; i < Chain.Count; i++)
            {
                if (Chain[i].Any(e => e.Species == entry.Species))
                    matchChain = i;
            }

            if (matchChain != -1)
                Chain[matchChain].Add(entry);
            else
                Chain.Insert(0, new List<EvolutionMethod> {entry});
        }
Пример #16
0
 public EvolutionSet7(byte[] data)
 {
     PossibleEvolutions = new EvolutionMethod[data.Length / SIZE];
     for (int i = 0; i < data.Length; i += SIZE)
     {
         PossibleEvolutions[i / SIZE] = new EvolutionMethod
         {
             Method   = BitConverter.ToUInt16(data, i + 0),
             Argument = BitConverter.ToUInt16(data, i + 2),
             Species  = BitConverter.ToUInt16(data, i + 4),
             Form     = (sbyte)data[i + 6],
             Level    = data[i + 7],
         };
     }
 }
Пример #17
0
        private static EvolutionMethod[] GetMethods(byte[] data)
        {
            var evos = new EvolutionMethod[data.Length / SIZE];

            for (int i = 0; i < data.Length; i += SIZE)
            {
                var method  = BitConverter.ToUInt16(data, i + 0);
                var arg     = BitConverter.ToUInt16(data, i + 2);
                var species = BitConverter.ToUInt16(data, i + 4);
                var form    = (sbyte)data[i + 6];
                var level   = data[i + 7];
                evos[i / SIZE] = new EvolutionMethod(method, species, argument: arg, level: level, form: form);
            }
            return(evos);
        }
        private static EvolutionMethod[] GetMethods(byte[] data)
        {
            var evos = new EvolutionMethod[data.Length / SIZE];

            for (int i = 0; i < data.Length; i += SIZE)
            {
                evos[i / SIZE] = new EvolutionMethod
                {
                    Method   = BitConverter.ToUInt16(data, i + 0),
                    Argument = BitConverter.ToUInt16(data, i + 2),
                    Species  = BitConverter.ToUInt16(data, i + 4),
                    Form     = (sbyte)data[i + 6],
                    Level    = data[i + 7],
                };
            }
            return(evos);
        }
Пример #19
0
        private static void UpdateMinValues(IReadOnlyList <EvoCriteria> dl, EvolutionMethod evo)
        {
            var last = dl[dl.Count - 1];

            if (!evo.RequiresLevelUp)
            {
                // Evolutions like elemental stones, trade, etc
                last.MinLevel = 1;
                return;
            }
            if (evo.Level == 0)
            {
                // Friendship based Evolutions, Pichu -> Pikachu, Eevee -> Umbreon, etc
                last.MinLevel = 2;

                var first = dl[0];
                if (dl.Count > 1 && !first.RequiresLvlUp)
                {
                    first.MinLevel = 2; // Raichu from Pikachu would have a minimum level of 1; accounting for Pichu (level up required) results in a minimum level of 2
                }
            }
            else // level up evolutions
            {
                last.MinLevel = evo.Level;

                var first = dl[0];
                if (dl.Count > 1)
                {
                    if (first.RequiresLvlUp)
                    {
                        if (first.MinLevel <= evo.Level)
                        {
                            first.MinLevel = evo.Level + 1; // Pokemon like Crobat, its minimum level is Golbat minimum level + 1
                        }
                    }
                    else
                    {
                        if (first.MinLevel < evo.Level)
                        {
                            first.MinLevel = evo.Level; // Pokemon like Nidoqueen who evolve with an evolution stone, minimum level is prior evolution minimum level
                        }
                    }
                }
            }
            last.RequiresLvlUp = evo.RequiresLevelUp;
        }
Пример #20
0
        private static EvolutionMethod[] GetMethods(byte[] data)
        {
            var evos = new EvolutionMethod[data.Length / SIZE];

            for (int i = 0; i < data.Length; i += SIZE)
            {
                var method = BitConverter.ToUInt16(data, i + 0);
                var arg    = BitConverter.ToUInt16(data, i + 2);
                var spec   = BitConverter.ToUInt16(data, i + 4);

                // Argument is used by both Level argument and Item/Move/etc. Clear if appropriate.
                var lvl = EvosWithArg.Contains(method) ? 0 : arg;

                evos[i / SIZE] = new EvolutionMethod(method, spec, argument: arg, level: lvl);
            }
            return(evos);
        }
Пример #21
0
        private static EvolutionMethod GetMethod(byte[] data, int offset)
        {
            int method  = data[offset];
            int species = data[offset + 1];
            int arg     = data[offset + 2];
            var obj     = new EvolutionMethod {
                Method = method, Species = species
            };

            if (method == 1)
            {
                obj.Level = arg;
            }
            else
            {
                obj.Argument = arg;
            }
            return(obj);
        }
Пример #22
0
        public static IReadOnlyList <EvolutionSet> GetArray(byte[] data)
        {
            var evos = new EvolutionSet[Legal.MaxSpeciesID_3 + 1];

            evos[0] = Blank;
            for (int i = 1; i <= Legal.MaxSpeciesIndex_3; i++)
            {
                int g4species = SpeciesConverter.GetG4Species(i);
                if (g4species == 0)
                {
                    continue;
                }

                const int maxCount = 5;
                const int size     = 8;

                int offset = i * (maxCount * size);
                int count  = 0;
                for (; count < maxCount; count++)
                {
                    if (data[offset + (count * size)] == 0)
                    {
                        break;
                    }
                }
                if (count == 0)
                {
                    evos[g4species] = Blank;
                    continue;
                }

                var set = new EvolutionMethod[count];
                for (int j = 0; j < set.Length; j++)
                {
                    set[j] = GetMethod(data, offset + (j * size));
                }
                evos[g4species] = new EvolutionSet3 {
                    PossibleEvolutions = set
                };
            }
            return(evos);
        }
Пример #23
0
        private static void UpdateMinValues(IReadOnlyCollection <DexLevel> dl, EvolutionMethod evo)
        {
            var last = dl.Last();

            if (evo.Level == 0) // Evolutions like elemental stones, trade, etc
            {
                if (!evo.RequiresLevelUp)
                {
                    last.MinLevel = 1;
                }
                else
                {
                    // Evolutions like frienship, pichu -> pikachu, eevee -> umbreon, etc
                    last.MinLevel = 2;

                    var first = dl.First();
                    if (dl.Count > 1 && !first.RequiresLvlUp)
                    {
                        first.MinLevel = 2; // Raichu from Pikachu would have minimum level 1, but with Pichu included Raichu minimum level is 2
                    }
                }
            }
            else // level up evolutions
            {
                last.MinLevel = evo.Level;

                var first = dl.First();
                if (dl.Count > 1)
                {
                    if (first.MinLevel < evo.Level && !first.RequiresLvlUp)
                    {
                        first.MinLevel = evo.Level; // Pokemon like Nidoqueen, its minimum level is Nidorina minimum level
                    }
                    if (first.MinLevel <= evo.Level && first.RequiresLvlUp)
                    {
                        first.MinLevel = evo.Level + 1; // Pokemon like Crobat, its minimum level is Golbat minimum level + 1
                    }
                }
            }
            last.RequiresLvlUp = evo.RequiresLevelUp;
        }
Пример #24
0
        private void CreateLeaf(IReadOnlyList <EvolutionLineage> lineage, int i, EvolutionMethod evo)
        {
            int index = GetIndex(evo);

            if (index < 0)
            {
                return;
            }

            var sourceEvo = evo.Copy(i);

            lineage[index].Insert(sourceEvo);
            // If current entries has a pre-evolution, propagate to evolution as well
            var current = lineage[i].Chain;

            if (current.Count > 0)
            {
                lineage[index].Insert(current[0]);
            }

            if (index >= i)
            {
                return;
            }

            // If destination species evolves into something (ie a 'baby' Pokemon like Cleffa)
            // Add it to the corresponding parent chains
            foreach (var method in Entries[index].PossibleEvolutions)
            {
                int newIndex = GetIndex(method);
                if (newIndex < 0)
                {
                    continue;
                }

                lineage[newIndex].Insert(sourceEvo);
            }
        }
Пример #25
0
        private int GetIndex(EvolutionMethod evo)
        {
            int evolvesToSpecies = evo.Species;

            if (evolvesToSpecies == 0)
            {
                return(-1);
            }

            if (Personal == null)
            {
                return(evolvesToSpecies);
            }

            int evolvesToForm = evo.Form;

            if (evolvesToForm < 0)
            {
                evolvesToForm = 0;
            }

            return(Personal.GetFormeIndex(evolvesToSpecies, evolvesToForm));
        }
Пример #26
0
        private static EvolutionMethod GetMethod(byte[] data, ref int offset)
        {
            switch (data[offset])
            {
            case 1:     // Level
                var m1 = new EvolutionMethod
                {
                    Method  = 1,    // Level Up
                    Level   = data[offset + 1],
                    Species = data[offset + 2]
                };
                offset += 3;
                return(m1);

            case 2:     // Use Item
                var m2 = new EvolutionMethod
                {
                    Method   = 8,   // Use Item
                    Argument = data[offset + 1],
                    // 1
                    Species = data[offset + 3],
                };
                offset += 4;
                return(m2);

            case 3:     // Trade
                var m3 = new EvolutionMethod
                {
                    Method = 5,     // Trade
                    // 1
                    Species = data[offset + 2]
                };
                offset += 3;
                return(m3);
            }
            return(null);
        }
Пример #27
0
        public static IReadOnlyList <EvolutionMethod[]> GetArray(byte[] data)
        {
            const int bpe     = 6;             // bytes per evolution entry
            const int entries = 7;             // amount of entries per species
            const int size    = entries * bpe; // bytes per species entry

            var evos = new EvolutionMethod[data.Length / size][];

            for (int i = 0; i < evos.Length; i++)
            {
                int offset = i * size;
                int count  = 0;
                for (; count < entries; count++)
                {
                    var methodOffset = offset + (count * bpe);
                    var method       = data[methodOffset];
                    if (method == 0)
                    {
                        break;
                    }
                }
                if (count == 0)
                {
                    evos[i] = Array.Empty <EvolutionMethod>();
                    continue;
                }

                var set = new EvolutionMethod[count];
                for (int j = 0; j < set.Length; j++)
                {
                    set[j] = GetMethod(data, offset + (j * bpe));
                }
                evos[i] = set;
            }
            return(evos);
        }
Пример #28
0
        public EvolutionSet6(byte[] data)
        {
            PossibleEvolutions = new EvolutionMethod[data.Length / SIZE];
            for (int i = 0; i < data.Length; i += SIZE)
            {
                var evo = new EvolutionMethod
                {
                    Method   = BitConverter.ToUInt16(data, i + 0),
                    Argument = BitConverter.ToUInt16(data, i + 2),
                    Species  = BitConverter.ToUInt16(data, i + 4),

                    // Copy
                    Level = BitConverter.ToUInt16(data, i + 2),
                };

                // Argument is used by both Level argument and Item/Move/etc. Clear if appropriate.
                if (argEvos.Contains(evo.Method))
                {
                    evo.Level = 0;
                }

                PossibleEvolutions[i / SIZE] = evo;
            }
        }
Пример #29
0
        private int getIndex(EvolutionMethod evo)
        {
            int evolvesToSpecies = evo.Species;
            if (evolvesToSpecies == 0)
                return -1;

            if (Personal == null)
                return evolvesToSpecies;

            int evolvesToForm = evo.Form;
            if (evolvesToForm < 0)
                evolvesToForm = 0;

            return Personal.getFormeIndex(evolvesToSpecies, evolvesToForm);
        }
Пример #30
0
        public EvolutionSet6(byte[] data)
        {
            if (data.Length < SIZE || data.Length % SIZE != 0) return;
            int[] argEvos = {6, 8, 16, 17, 18, 19, 20, 21, 22, 29, 30, 31, 32, 33, 34};
            PossibleEvolutions = new EvolutionMethod[data.Length / SIZE];
            for (int i = 0; i < data.Length; i += SIZE)
            {
                PossibleEvolutions[i/SIZE] = new EvolutionMethod
                {
                    Method = BitConverter.ToUInt16(data, i + 0),
                    Argument = BitConverter.ToUInt16(data, i + 2),
                    Species = BitConverter.ToUInt16(data, i + 4),

                    // Copy
                    Level = BitConverter.ToUInt16(data, i + 2),
                };

                // Argument is used by both Level argument and Item/Move/etc. Clear if appropriate.
                if (argEvos.Contains(PossibleEvolutions[i/SIZE].Method))
                    PossibleEvolutions[i/SIZE].Level = 0;
            }
        }
Пример #31
0
 public EvolutionSet7(byte[] data)
 {
     if (data.Length < SIZE || data.Length % SIZE != 0) return;
     PossibleEvolutions = new EvolutionMethod[data.Length / SIZE];
     for (int i = 0; i < data.Length; i += SIZE)
     {
         PossibleEvolutions[i / SIZE] = new EvolutionMethod
         {
             Method = BitConverter.ToUInt16(data, i + 0),
             Argument = BitConverter.ToUInt16(data, i + 2),
             Species = BitConverter.ToUInt16(data, i + 4),
             Form = (sbyte)data[i + 6],
             Level = data[i + 7],
         };
     }
 }
Пример #32
0
        public void Insert(EvolutionMethod entry)
        {
            int matchChain = -1;
            for (int i = 0; i < Chain.Count; i++)
                if (Chain[i].StageEntryMethods.Any(e => e.Species == entry.Species))
                    matchChain = i;

            if (matchChain != -1)
                Chain[matchChain].StageEntryMethods.Add(entry);
            else
                Chain.Insert(0, new EvolutionStage { StageEntryMethods = new List<EvolutionMethod> {entry}});
        }
Пример #33
0
        private CheckResult VerifyForm(LegalityAnalysis data)
        {
            var pkm          = data.pkm;
            var PersonalInfo = data.PersonalInfo;

            int count = PersonalInfo.FormCount;
            var form  = pkm.Form;

            if (count <= 1 && form == 0)
            {
                return(VALID); // no forms to check
            }
            var species = pkm.Species;
            var enc     = data.EncounterMatch;
            var Info    = data.Info;

            if (!PersonalInfo.IsFormWithinRange(form) && !FormInfo.IsValidOutOfBoundsForm(species, form, Info.Generation))
            {
                return(GetInvalid(string.Format(LFormInvalidRange, count - 1, form)));
            }

            switch (enc)
            {
            case EncounterSlot w when w.Area.Type == SlotType.FriendSafari:
                VerifyFormFriendSafari(data);
                break;

            case EncounterEgg e when FormInfo.IsTotemForm(species, form, e.Generation):
                return(GetInvalid(LFormInvalidGame));
            }

            switch ((Species)species)
            {
            case Pikachu when Info.Generation == 6:     // Cosplay
                bool isStatic     = enc is EncounterStatic;
                bool validCosplay = form == (isStatic ? enc.Form : 0);
                if (!validCosplay)
                {
                    return(GetInvalid(isStatic ? LFormPikachuCosplayInvalid : LFormPikachuCosplay));
                }
                break;

            case Pikachu when Info.Generation >= 7:     // Cap
                bool validCap = form == (enc is EncounterInvalid ? 0 : enc.Form);
                if (!validCap)
                {
                    bool gift = enc is MysteryGift g && g.Form != form;
                    var  msg  = gift ? LFormPikachuEventInvalid : LFormInvalidGame;
                    return(GetInvalid(msg));
                }
                break;

            case Unown when Info.Generation == 2 && form >= 26:
                return(GetInvalid(string.Format(LFormInvalidRange, "Z", form == 26 ? "!" : "?")));

            case Giratina when form == 1 ^ pkm.HeldItem == 112:     // Giratina, Origin form only with Griseous Orb
                return(GetInvalid(LFormItemInvalid));

            case Arceus:
            {
                int arceus = GetArceusFormFromHeldItem(pkm.HeldItem, pkm.Format);
                return(arceus != form?GetInvalid(LFormItemInvalid) : GetValid(LFormItem));
            }

            case Keldeo when pkm.Format < 8 && enc.Generation != 5:
                // can mismatch in gen5 via BW tutor and transfer up
                // can mismatch in gen8+ as the form activates in battle when knowing the move; outside of battle can be either state.
                bool hasSword = pkm.HasMove((int)Move.SecretSword);
                bool isSword  = pkm.Form == 1;
                if (isSword != hasSword)
                {
                    return(GetInvalid(LMoveKeldeoMismatch));
                }
                break;

            case Genesect:
            {
                int genesect = GetGenesectFormFromHeldItem(pkm.HeldItem);
                return(genesect != form?GetInvalid(LFormItemInvalid) : GetValid(LFormItem));
            }

            case Greninja:
                if (form > 1)     // Ash Battle Bond active
                {
                    return(GetInvalid(LFormBattle));
                }
                if (form != 0 && enc is not MysteryGift)     // Formes are not breedable, MysteryGift already checked
                {
                    return(GetInvalid(string.Format(LFormInvalidRange, 0, form)));
                }
                break;

            case Scatterbug or Spewpa:
                if (form > 17)     // Fancy & Pokéball
                {
                    return(GetInvalid(LFormVivillonEventPre));
                }
                if (pkm is not IRegionOrigin tr)
                {
                    break;
                }
                if (!Vivillon3DS.IsPatternValid(form, (byte)tr.Country, (byte)tr.Region))
                {
                    data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy));
                }
                break;

            case Vivillon:
                if (form > 17)     // Fancy & Pokéball
                {
                    if (enc is not MysteryGift)
                    {
                        return(GetInvalid(LFormVivillonInvalid));
                    }
                    return(GetValid(LFormVivillon));
                }
                if (pkm is not IRegionOrigin trv)
                {
                    break;
                }
                if (!Vivillon3DS.IsPatternValid(form, (byte)trv.Country, (byte)trv.Region))
                {
                    data.AddLine(Get(LFormVivillonInvalid, Severity.Fishy));
                }
                break;

            case Floette when form == 5:     // Floette Eternal Flower -- Never Released
                if (enc is not MysteryGift)
                {
                    return(GetInvalid(LFormEternalInvalid));
                }
                return(GetValid(LFormEternal));

            case Meowstic when form != pkm.Gender:
                return(GetInvalid(LGenderInvalidNone));

            case Silvally:
            {
                int silvally = GetSilvallyFormFromHeldItem(pkm.HeldItem);
                return(silvally != form?GetInvalid(LFormItemInvalid) : GetValid(LFormItem));
            }

            // Form doesn't exist in SM; cannot originate from that game.
            case Lillipup when enc.Generation == 7 && form == 1 && pkm.SM:
            case Lycanroc when enc.Generation == 7 && form == 2 && pkm.SM:
                return(GetInvalid(LFormInvalidGame));

            // Toxel encounters have already been checked for the nature-specific evolution criteria.
            case Toxtricity when enc.Species == (int)Toxtricity:
            {
                // The game enforces the Nature for Toxtricity encounters too!
                if (pkm.Form != EvolutionMethod.GetAmpLowKeyResult(pkm.Nature))
                {
                    return(GetInvalid(LFormInvalidNature));
                }
                break;
            }

            // Impossible Egg forms
            case Rotom when pkm.IsEgg && form != 0:
            case Furfrou when pkm.IsEgg && form != 0:
                return(GetInvalid(LEggSpecies));

            // Party Only Forms
            case Shaymin:
            case Furfrou:
            case Hoopa:
                if (form != 0 && pkm.Box > -1 && pkm.Format <= 6)     // has form but stored in box
                {
                    return(GetInvalid(LFormParty));
                }
                break;
            }

            var format = pkm.Format;

            if (FormInfo.IsBattleOnlyForm(species, form, format))
            {
                return(GetInvalid(LFormBattle));
            }

            if (form == 0)
            {
                return(VALID);
            }

            // everything below here is not Form 0, so it has a form.
            if (format >= 7 && Info.Generation < 7)
            {
                if (species == 25 || Legal.AlolanOriginForms.Contains(species) || Legal.AlolanVariantEvolutions12.Contains(enc.Species))
                {
                    return(GetInvalid(LFormInvalidGame));
                }
            }
            if (format >= 8 && Info.Generation < 8)
            {
                var orig = enc.Species;
                if (Legal.GalarOriginForms.Contains(species) || Legal.GalarVariantFormEvolutions.Contains(orig))
                {
                    if (species == (int)Meowth && enc.Form != 2)
                    {
                        // We're okay here. There's also Alolan Meowth...
                    }
                    else if (((Species)orig is MrMime or MimeJr) && pkm.CurrentLevel > enc.LevelMin && Info.Generation >= 4)
                    {
                        // We're okay with a Mime Jr. that has evolved via level up.
                    }
                    else if (enc.Version != GameVersion.GO)
                    {
                        return(GetInvalid(LFormInvalidGame));
                    }
                }
            }