Example #1
0
        public SAV3(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data)
        {
            LoadBlocks(out BlockOrder, out BlockOfs);
            Version   = versionOverride != GameVersion.Any ? versionOverride : GetVersion(Data, BlockOfs[0]);
            _personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS;

            // Japanese games are limited to 5 character OT names; any unused characters are 0xFF.
            // 5 for JP, 7 for INT. There's always 1 terminator, thus we can check 0x6-0x7 being 0xFFFF = INT
            // OT name is stored at the top of the first block.
            Japanese = BitConverter.ToInt16(Data, BlockOfs[0] + 0x6) == 0;

            LegalKeyItems = Version switch
            {
                GameVersion.RS => Legal.Pouch_Key_RS,
                GameVersion.E => Legal.Pouch_Key_E,
                _ => Legal.Pouch_Key_FRLG
            };

            PokeDex         = BlockOfs[0] + 0x18;
            SeenFlagOffsets = Version switch
            {
                GameVersion.RS => new[] { PokeDex + 0x44, BlockOfs[1] + 0x938, BlockOfs[4] + 0xC0C },
                GameVersion.E => new[] { PokeDex + 0x44, BlockOfs[1] + 0x988, BlockOfs[4] + 0xCA4 },
                _ => new[] { PokeDex + 0x44, BlockOfs[1] + 0x5F8, BlockOfs[4] + 0xB98 }
            };

            Initialize();
        }
Example #2
0
        /// <summary>
        /// Checks the input <see cref="PKM"/> data for legality.
        /// </summary>
        /// <param name="pk">Input data to check</param>
        /// <param name="table"><see cref="SaveFile"/> specific personal data</param>
        public LegalityAnalysis(PKM pk, PersonalTable table = null)
        {
            pkm = pk;
#if SUPPRESS
            try
#endif
            {
                PersonalInfo = table?.GetFormeEntry(pkm.Species, pkm.AltForm) ?? pkm.PersonalInfo;
                ParseLegality();

                if (Parse.Count <= 0)
                {
                    return;
                }

                Valid = Parse.All(chk => chk.Valid) &&
                        Info.Moves.All(m => m.Valid) &&
                        Info.Relearn.All(m => m.Valid);

                if (pkm.FatefulEncounter && Info.Relearn.Any(chk => !chk.Valid) && EncounterMatch is EncounterInvalid)
                {
                    AddLine(Severity.Indeterminate, LFatefulGiftMissing, CheckIdentifier.Fateful);
                }
            }
#if SUPPRESS
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
                Valid = false;
                AddLine(Severity.Invalid, L_AError, CheckIdentifier.Misc);
                Error = true;
            }
#endif
            Parsed = true;
        }
Example #3
0
File: SAV3.cs Project: nixhex/PKHeX
        public SAV3(GameVersion version = GameVersion.FRLG, bool japanese = false)
        {
            Version = version switch
            {
                GameVersion.FR or GameVersion.LG => GameVersion.FRLG,
                                              GameVersion.R or GameVersion.S => GameVersion.RS,
                                              _ => version
            };
            _personal = SaveUtil.GetG3Personal(Version);
            Japanese  = japanese;

            BlockOrder = Array.Empty <short>();

            LegalKeyItems = Version switch
            {
                GameVersion.RS => Legal.Pouch_Key_RS,
                GameVersion.E => Legal.Pouch_Key_E,
                _ => Legal.Pouch_Key_FRLG
            };
            PokeDex         = 0x18;
            SeenFlagOffsets = Array.Empty <int>();

            Initialize();
            ClearBoxes();
        }
Example #4
0
File: SAV3.cs Project: nixhex/PKHeX
        public SAV3(byte[] data, GameVersion versionOverride = GameVersion.Any) : base(data)
        {
            LoadBlocks(out BlockOrder);

            // Copy chunk to the allocated location
            LoadBlocks(Small, 0, 1);
            LoadBlocks(Large, 1, 5);
            LoadBlocks(Storage, 5, BLOCK_COUNT);

            Version   = versionOverride != GameVersion.Any ? versionOverride : GetVersion(Small);
            _personal = SaveUtil.GetG3Personal(Version);

            // Japanese games are limited to 5 character OT names; any unused characters are 0xFF.
            // 5 for JP, 7 for INT. There's always 1 terminator, thus we can check 0x6-0x7 being 0xFFFF = INT
            // OT name is stored at the top of the first block.
            Japanese = BitConverter.ToInt16(Small, 0x6) == 0;

            LegalKeyItems = Version switch
            {
                GameVersion.RS => Legal.Pouch_Key_RS,
                GameVersion.E => Legal.Pouch_Key_E,
                _ => Legal.Pouch_Key_FRLG
            };

            PokeDex         = 0x18;
            SeenFlagOffsets = Version switch
            {
                GameVersion.RS => new[] { 0x938, 0x3A8C },
                GameVersion.E => new[] { 0x988, 0x3B24 },
                _ => new[] { 0x5F8, 0x3A18 }
            };

            Initialize();
        }
Example #5
0
        public SAV3(GameVersion version = GameVersion.FRLG, bool japanese = false) : base(SaveUtil.SIZE_G3RAW)
        {
            if (version == GameVersion.FR || version == GameVersion.LG)
            {
                Version = GameVersion.FRLG;
            }
            else if (version == GameVersion.R || version == GameVersion.S)
            {
                Version = GameVersion.RS;
            }
            else
            {
                Version = version;
            }
            _personal = SaveUtil.GetG3Personal(Version) ?? PersonalTable.RS;
            Japanese  = japanese;

            LoadBlocks(out BlockOrder, out BlockOfs);
            // spoof block offsets
            BlockOfs = Enumerable.Range(0, BLOCK_COUNT).ToArray();

            LegalKeyItems = Version switch
            {
                GameVersion.RS => Legal.Pouch_Key_RS,
                GameVersion.E => Legal.Pouch_Key_E,
                _ => Legal.Pouch_Key_FRLG
            };
            PokeDex         = BlockOfs[0] + 0x18;
            SeenFlagOffsets = Array.Empty <int>();

            Initialize();
            ClearBoxes();
        }
Example #6
0
        public List<Zukan8EntryInfo> GetRawIndexes(PersonalTable pt, int dexRevision)
        {
            var result = new List<Zukan8EntryInfo>();
            for (int i = 1; i <= pt.MaxSpeciesID; i++)
            {
                var p = (PersonalInfoSWSH)pt[i];
                var index = p.PokeDexIndex;
                if (index != 0)
                    result.Add(new Zukan8EntryInfo(i, new Zukan8Index(Zukan8Type.Galar, index)));
            }
            if (dexRevision == 0)
                return result;

            for (int i = 1; i <= pt.MaxSpeciesID; i++)
            {
                var p = (PersonalInfoSWSH)pt[i];
                var index = p.ArmorDexIndex;
                if (index != 0)
                    result.Add(new Zukan8EntryInfo(i, new Zukan8Index(Zukan8Type.Armor, index)));
            }
            if (dexRevision == 1)
                return result;

            for (int i = 1; i <= pt.MaxSpeciesID; i++)
            {
                var p = (PersonalInfoSWSH)pt[i];
                var index = p.CrownDexIndex;
                if (index != 0)
                    result.Add(new Zukan8EntryInfo(i, new Zukan8Index(Zukan8Type.Crown, index)));
            }
            return result;
        }
Example #7
0
        private static Dictionary<int, Zukan8Index> GetDexLookup(PersonalTable pt, int dexRevision)
        {
            var lookup = new Dictionary<int, Zukan8Index>();
            for (int i = 1; i <= pt.MaxSpeciesID; i++)
            {
                var p = (PersonalInfoSWSH) pt[i];
                var index = p.PokeDexIndex;
                if (index != 0)
                {
                    lookup.Add(i, new Zukan8Index(Zukan8Type.Galar, index));
                    continue;
                }

                if (dexRevision == 0)
                    continue;

                var armor = p.ArmorDexIndex;
                if (armor != 0)
                {
                    lookup.Add(i, new Zukan8Index(Zukan8Type.Armor, armor));
                    continue;
                }

                if (dexRevision == 1)
                    continue;
                var crown = p.CrownDexIndex;
                if (crown != 0)
                {
                    lookup.Add(i, new Zukan8Index(Zukan8Type.Crown, armor));
                    // continue;
                }
            }
            return lookup;
        }
Example #8
0
 private EvolutionTree(IReadOnlyList <byte[]> data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
 {
     Game           = game;
     Personal       = personal;
     MaxSpeciesTree = maxSpeciesTree;
     Entries        = GetEntries(data);
     Lineage        = CreateTree();
 }
Example #9
0
 public bool ResetPersonal(GameVersion g)
 {
     if (g is not(GameVersion.FR or GameVersion.LG))
     {
         return(false);
     }
     _personal = g == GameVersion.FR ? PersonalTable.FR : PersonalTable.LG;
     return(true);
 }
Example #10
0
        public EvolutionTree(byte[][] data, GameVersion game, PersonalTable personal, int maxSpecies)
        {
            Game = game;
            Personal = personal;
            MaxSpecies = maxSpecies;
            switch (game)
            {
                case GameVersion.SM:
                    Entries.AddRange(data.Select(d => new EvolutionSet7(d)));
                    break;
                case GameVersion.ORAS:
                    Entries.AddRange(data.Select(d => new EvolutionSet6(d)));
                    break;
            }
            
            // Create Lineages
            Lineage = new EvolutionLineage[Entries.Count];
            for (int i = 0; i < Entries.Count; i++)
                Lineage[i] = new EvolutionLineage();
            if (Game == GameVersion.ORAS)
                Array.Resize(ref Lineage, maxSpecies + 1);

            // Populate Lineages
            for (int i = 1; i < Lineage.Length; i++)
            {
                // Iterate over all possible evolutions
                var s = Entries[i];
                foreach (EvolutionMethod evo in s.PossibleEvolutions)
                {
                    int index = getIndex(evo);
                    if (index < 0)
                        continue;

                    var sourceEvo = evo.Copy(i);

                    Lineage[index].Insert(sourceEvo);
                    // If current entries has a pre-evolution, propagate to evolution as well
                    if (Lineage[i].Chain.Count > 0)
                        Lineage[index].Insert(Lineage[i].Chain[0]);

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

                        Lineage[newIndex].Insert(sourceEvo);
                    }
                }
            }
            fixEvoTreeManually();
        }
Example #11
0
                        // Check if any pre-evolution could have it flipped.
                        static bool getWasDual(IEnumerable <EvoCriteria> evos, PersonalTable pt, PKM pk)
                        {
                            foreach (var evo in evos)
                            {
                                if (evo.Species == pk.Species)
                                {
                                    continue;
                                }

                                var pe    = pt.GetFormEntry(evo.Species, evo.Form);
                                var abils = pe.Abilities;
                                if (abils[0] != abils[1])
                                {
                                    return(true);
                                }
                            }
                            return(false);
                        }
Example #12
0
        private static bool GetWasDual(IReadOnlyList <EvoCriteria> evos, PersonalTable pt, ISpeciesForm pk)
        {
            foreach (var evo in evos)
            {
                if (evo.Species == pk.Species)
                {
                    continue;
                }

                var pe    = pt.GetFormEntry(evo.Species, evo.Form);
                var abils = pe.Abilities;
                if (CanAbilityCapsule(6, abils))
                {
                    return(true);
                }
            }

            return(false);
        }
Example #13
0
        private static void GetStaticMagnet(PersonalTable t, IEnumerable <EncounterSlot> grp, out List <EncounterSlot> s, out List <EncounterSlot> m)
        {
            const int steel    = (int)MoveType.Steel;
            const int electric = (int)MoveType.Electric + 1; // offset by 1 in gen3/4 for the ??? type

            s = new List <EncounterSlot>();
            m = new List <EncounterSlot>();
            foreach (EncounterSlot Slot in grp)
            {
                var p = t[Slot.Species];
                if (p.IsType(steel))
                {
                    m.Add(Slot);
                }
                if (p.IsType(electric))
                {
                    s.Add(Slot);
                }
            }
        }
Example #14
0
 /// <summary>
 /// Checks the input <see cref="PKM"/> data for legality. This is the best method for checking with context, as some games do not have all Alternate Form data available.
 /// </summary>
 /// <param name="pk">Input data to check</param>
 /// <param name="table"><see cref="SaveFile"/> specific personal data</param>
 public LegalityAnalysis(PKM pk, PersonalTable table) : this(pk, table.GetFormeEntry(pk.Species, pk.AltForm))
 {
 }
Example #15
0
        public EvolutionTree(byte[][] data, GameVersion game, PersonalTable personal, int maxSpeciesTree)
        {
            Game           = game;
            Personal       = personal;
            MaxSpeciesTree = maxSpeciesTree;
            switch (game)
            {
            case GameVersion.RBY:
                Entries = EvolutionSet1.GetArray(data[0], maxSpeciesTree);
                break;

            case GameVersion.GSC:
                Entries = EvolutionSet2.GetArray(data[0], maxSpeciesTree);
                break;

            case GameVersion.RS:
                Entries = EvolutionSet3.GetArray(data[0]);
                break;

            case GameVersion.DP:
                Entries = EvolutionSet4.GetArray(data[0]);
                break;

            case GameVersion.BW:
                Entries = EvolutionSet5.GetArray(data[0]);
                break;

            case GameVersion.ORAS:
                Entries.AddRange(data.Select(d => new EvolutionSet6(d)));
                break;

            case GameVersion.SM:
                Entries.AddRange(data.Select(d => new EvolutionSet7(d)));
                break;
            }

            // Create Lineages
            Lineage = new EvolutionLineage[Entries.Count];
            for (int i = 0; i < Entries.Count; i++)
            {
                Lineage[i] = new EvolutionLineage();
            }
            if (Game == GameVersion.ORAS)
            {
                Array.Resize(ref Lineage, MaxSpeciesTree + 1);
            }

            // Populate Lineages
            for (int i = 1; i < Lineage.Length; i++)
            {
                // Iterate over all possible evolutions
                var s = Entries[i];
                foreach (EvolutionMethod evo in s.PossibleEvolutions)
                {
                    int index = GetIndex(evo);
                    if (index < 0)
                    {
                        continue;
                    }

                    var sourceEvo = evo.Copy(i);

                    Lineage[index].Insert(sourceEvo);
                    // If current entries has a pre-evolution, propagate to evolution as well
                    if (Lineage[i].Chain.Count > 0)
                    {
                        Lineage[index].Insert(Lineage[i].Chain[0]);
                    }

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

                        Lineage[newIndex].Insert(sourceEvo);
                    }
                }
            }
            FixEvoTreeManually();
        }
Example #16
0
 /// <summary>
 /// Marks Encounter Slots for party lead's ability slot influencing.
 /// </summary>
 /// <remarks>Magnet Pull attracts Steel type slots, and Static attracts Electric</remarks>
 /// <param name="Areas">Encounter Area array for game</param>
 /// <param name="t">Personal data for use with a given species' type</param>
 internal static void MarkEncountersStaticMagnetPull(IEnumerable <EncounterArea> Areas, PersonalTable t)
 {
     foreach (EncounterArea Area in Areas)
     {
         foreach (var grp in Area.Slots.GroupBy(z => z.Type))
         {
             MarkEncountersStaticMagnetPull(grp, t);
         }
     }
 }
Example #17
0
        internal static void MarkEncountersStaticMagnetPullPermutation(IEnumerable <EncounterSlot> grp, PersonalTable t, List <EncounterSlot> permuted)
        {
            GetStaticMagnet(t, grp, out List <EncounterSlot> s, out List <EncounterSlot> m);

            // Apply static/magnet values; if any permutation has a unique slot combination, add it to the slot list.
            for (int i = 0; i < s.Count; i++)
            {
                var slot = s[i];
                if (slot.Permissions.StaticIndex >= 0) // already has unique data
                {
                    if (slot.IsMatchStatic(i, s.Count))
                    {
                        continue; // same values, no permutation
                    }
                    if (permuted.Any(z => z.SlotNumber == slot.SlotNumber && z.IsMatchStatic(i, s.Count) && z.Species == slot.Species))
                    {
                        continue; // same values, previously permuted
                    }
                    s[i] = slot = slot.Clone();
                    permuted.Add(slot);
                }
                slot.Permissions.StaticIndex = i;
                slot.Permissions.StaticCount = s.Count;
            }
            for (int i = 0; i < m.Count; i++)
            {
                var slot = m[i];
                if (slot.Permissions.MagnetPullIndex >= 0) // already has unique data
                {
                    if (slot.IsMatchStatic(i, m.Count))
                    {
                        continue; // same values, no permutation
                    }
                    if (permuted.Any(z => z.SlotNumber == slot.SlotNumber && z.IsMatchMagnet(i, m.Count) && z.Species == slot.Species))
                    {
                        continue; // same values, previously permuted
                    }
                    m[i] = slot = slot.Clone();
                    permuted.Add(slot);
                }
                slot.Permissions.MagnetPullIndex = i;
                slot.Permissions.MagnetPullCount = m.Count;
            }
        }
Example #18
0
 internal static void MarkEncountersStaticMagnetPull(IEnumerable <EncounterSlot> grp, PersonalTable t)
 {
     GetStaticMagnet(t, grp, out List <EncounterSlot> s, out List <EncounterSlot> m);
     for (var i = 0; i < s.Count; i++)
     {
         var slot = s[i];
         slot.Permissions.StaticIndex = i;
         slot.Permissions.StaticCount = s.Count;
     }
     for (var i = 0; i < m.Count; i++)
     {
         var slot = m[i];
         slot.Permissions.MagnetPullIndex = i;
         slot.Permissions.MagnetPullCount = m.Count;
     }
 }
Example #19
0
        /// <summary>
        /// Checks the input <see cref="PKM"/> data for legality.
        /// </summary>
        /// <param name="pk">Input data to check</param>
        /// <param name="table"><see cref="SaveFile"/> specific personal data</param>
        public LegalityAnalysis(PKM pk, PersonalTable table = null)
        {
#if SUPPRESS
            try
#endif
            {
                PersonalInfo = table?.GetFormeEntry(pk.Species, pk.AltForm) ?? pk.PersonalInfo;
                switch (pk.Format) // prior to storing GameVersion
                {
                case 1: ParsePK1(pk); break;

                case 2: ParsePK1(pk); break;
                }

                if (!Parse.Any())
                {
                    switch (pk.GenNumber)
                    {
                    case 3: ParsePK3(pk); break;

                    case 4: ParsePK4(pk); break;

                    case 5: ParsePK5(pk); break;

                    case 6: ParsePK6(pk); break;

                    case 1:
                    case 2:
                    case 7: ParsePK7(pk); break;
                    }
                }

                if (Parse.Count > 0)
                {
                    if (Parse.Any(chk => !chk.Valid))
                    {
                        Valid = false;
                    }
                    else if (Info.Moves.Any(m => m.Valid != true))
                    {
                        Valid = false;
                    }
                    else if (Info.Relearn.Any(m => m.Valid != true))
                    {
                        Valid = false;
                    }
                    else
                    {
                        Valid = true;
                    }

                    if (pkm.FatefulEncounter && Info.Relearn.Any(chk => !chk.Valid) && EncounterMatch == null)
                    {
                        AddLine(Severity.Indeterminate, V188, CheckIdentifier.Fateful);
                    }
                }
            }
#if SUPPRESS
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
                Valid = false;
                AddLine(Severity.Invalid, V190, CheckIdentifier.Misc);
                pkm   = pk;
                Error = true;
            }
#endif
            Parsed = true;
        }
Example #20
0
        /// <summary>
        /// Marks Encounter Slots for party lead's ability slot influencing.
        /// </summary>
        /// <remarks>Magnet Pull attracts Steel type slots, and Static attracts Electric</remarks>
        /// <param name="Areas">Encounter Area array for game</param>
        /// <param name="t">Personal data for use with a given species' type</param>
        internal static void MarkEncountersStaticMagnetPull(ref EncounterArea[] Areas, PersonalTable t)
        {
            const int steel    = 8;
            const int electric = 12;

            foreach (EncounterArea Area in Areas)
            {
                var s = new List <EncounterSlot>(); // Static
                var m = new List <EncounterSlot>(); // Magnet Pull
                foreach (EncounterSlot Slot in Area.Slots)
                {
                    var types = t[Slot.Species].Types;
                    if (types[0] == steel || types[1] == steel)
                    {
                        m.Add(Slot);
                    }
                    if (types[0] == electric || types[1] == electric)
                    {
                        s.Add(Slot);
                    }
                }
                foreach (var slot in s)
                {
                    slot.Permissions.Static      = true;
                    slot.Permissions.StaticCount = s.Count;
                }
                foreach (var slot in m)
                {
                    slot.Permissions.MagnetPull      = true;
                    slot.Permissions.MagnetPullCount = s.Count;
                }
            }
        }
 public LearnLookup(PersonalTable table, Learnset[] learn, GameVersion version)
 {
     Version = version;
     Table   = table;
     Learn   = learn;
 }