diff --git a/PKHeX/Legality/Core.cs b/PKHeX/Legality/Core.cs index 29fcad10c..f29c885f9 100644 --- a/PKHeX/Legality/Core.cs +++ b/PKHeX/Legality/Core.cs @@ -525,7 +525,7 @@ private static IEnumerable getValidPreEvolutions(PK6 pk6, int lvl = -1 if (lvl >= pk6.Met_Level && lvl >= evo.Level) dl.Add(new DexLevel {Species = evo.Species, Level = lvl}); else break; - if (evo.Level > 1) // Level Up (from previous level) + if (evo.Level > 2) // Level Up (from previous level) lvl--; } return dl; diff --git a/PKHeX/MainWindow/Main.Designer.cs b/PKHeX/MainWindow/Main.Designer.cs index 14db5ba68..d051460a6 100644 --- a/PKHeX/MainWindow/Main.Designer.cs +++ b/PKHeX/MainWindow/Main.Designer.cs @@ -3008,6 +3008,7 @@ public void InitializeComponent() this.tabBoxMulti.Size = new System.Drawing.Size(310, 225); this.tabBoxMulti.TabIndex = 50; this.tabBoxMulti.Click += new System.EventHandler(this.clickBoxSort); + this.tabBoxMulti.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.clickBoxDouble); // // Tab_Box // diff --git a/PKHeX/MainWindow/Main.cs b/PKHeX/MainWindow/Main.cs index a2739c7b0..4c07e8e3c 100644 --- a/PKHeX/MainWindow/Main.cs +++ b/PKHeX/MainWindow/Main.cs @@ -151,6 +151,7 @@ public Main() public static string[] wallpapernames, puffs = { }; public static bool unicode; public static List MoveDataSource, ItemDataSource, SpeciesDataSource, BallDataSource, NatureDataSource, AbilityDataSource, VersionDataSource; + private static List metGen1, metGen2, metGen3, metGen4, metGen5, metGen6; public static volatile bool formInitialized, fieldsInitialized, fieldsLoaded; private static int colorizedbox = -1; @@ -172,7 +173,7 @@ public Main() "中文", // CHN "Português", // Portuguese }; - private static string origintrack; + private static GameVersion origintrack; private readonly PictureBox[] SlotPictureBoxes, movePB, relearnPB; private readonly ToolTip Tip1 = new ToolTip(), Tip2 = new ToolTip(), Tip3 = new ToolTip(), NatureTip = new ToolTip(); #endregion @@ -1122,7 +1123,7 @@ private void InitializeStrings() abilitylist[0] = itemlist[0] = movelist[0] = metXY_00000[0] = metBW2_00000[0] = metHGSS_00000[0] = "(" + itemlist[0] + ")"; // Force an update to the met locations - origintrack = ""; + origintrack = GameVersion.Unknown; // Update Legality Analysis strings LegalityAnalysis.movelist = movelist; @@ -1179,6 +1180,48 @@ private void InitializeLanguage() MoveDataSource = Util.getCBList(movelist, null); + #region Met Locations + // Gen 3 + { + var met_list = Util.getCBList(metRSEFRLG_00000, Enumerable.Range(0, 213).ToArray()); + met_list = Util.getOffsetCBList(met_list, metRSEFRLG_00000, 00000, new[] { 253, 254, 255 }); + metGen3 = met_list; + } + // Gen 4 + { + var met_list = Util.getCBList(metHGSS_00000, new[] { 0 }); + met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, new[] { 2000 }); + met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, new[] { 2002 }); + met_list = Util.getOffsetCBList(met_list, metHGSS_03000, 3000, new[] { 3001 }); + met_list = Util.getOffsetCBList(met_list, metHGSS_00000, 0000, Legal.Met_HGSS_0); + met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, Legal.Met_HGSS_2); + met_list = Util.getOffsetCBList(met_list, metHGSS_03000, 3000, Legal.Met_HGSS_3); + metGen4 = met_list; + } + // Gen 5 + { + var met_list = Util.getCBList(metBW2_00000, new[] { 0 }); + met_list = Util.getOffsetCBList(met_list, metBW2_60000, 60001, new[] { 60002 }); + met_list = Util.getOffsetCBList(met_list, metBW2_30000, 30001, new[] { 30003 }); + met_list = Util.getOffsetCBList(met_list, metBW2_00000, 00000, Legal.Met_BW2_0); + met_list = Util.getOffsetCBList(met_list, metBW2_30000, 30001, Legal.Met_BW2_3); + met_list = Util.getOffsetCBList(met_list, metBW2_40000, 40001, Legal.Met_BW2_4); + met_list = Util.getOffsetCBList(met_list, metBW2_60000, 60001, Legal.Met_BW2_6); + metGen5 = met_list; + } + // Gen 6 + { + var met_list = Util.getCBList(metXY_00000, new[] { 0 }); + met_list = Util.getOffsetCBList(met_list, metXY_60000, 60001, new[] { 60002 }); + met_list = Util.getOffsetCBList(met_list, metXY_30000, 30001, new[] { 30002 }); + met_list = Util.getOffsetCBList(met_list, metXY_00000, 00000, Legal.Met_XY_0); + met_list = Util.getOffsetCBList(met_list, metXY_30000, 30001, Legal.Met_XY_3); + met_list = Util.getOffsetCBList(met_list, metXY_40000, 40001, Legal.Met_XY_4); + met_list = Util.getOffsetCBList(met_list, metXY_60000, 60001, Legal.Met_XY_6); + metGen6 = met_list; + } + #endregion + CB_EncounterType.DataSource = Util.getCBList(encountertypelist, new[] { 0 }, Legal.Gen4EncounterTypes); CB_HPType.DataSource = Util.getCBList(types.Skip(1).Take(16).ToArray(), null); CB_Nature.DataSource = new BindingSource(NatureDataSource, null); @@ -1812,7 +1855,10 @@ private void updateForm(object sender, EventArgs e) if (Util.getIndex(CB_Species) == 201) { if (fieldsLoaded && SAV.Generation == 3) - updateRandomPID(sender, e); // Fix AltForm + { + pkm.setPIDUnown3(CB_Form.SelectedIndex); + TB_PID.Text = pkm.PID.ToString("X8"); + } } else if (PKX.getGender(CB_Form.Text) < 2) Label_Gender.Text = CB_Form.Text; @@ -1963,114 +2009,112 @@ private void updateSpecies(object sender, EventArgs e) updateLegality(); } + private IEnumerable getLocationList(GameVersion Version, int SaveFormat, bool egg) + { + if (egg) + { + if (Version < GameVersion.W && SaveFormat >= 5) + return metGen4; + } + + switch (Version) + { + case GameVersion.CXD: + if (SaveFormat == 3) + return metGen3; + break; + + case GameVersion.R: + case GameVersion.S: + if (SaveFormat == 3) + return metGen3.OrderByDescending(loc => loc.Value <= 87); // Ferry + break; + case GameVersion.E: + if (SaveFormat == 3) + return metGen3.OrderByDescending(loc => loc.Value <= 87 || (loc.Value >= 196 && loc.Value <= 212)); // Trainer Hill + break; + case GameVersion.FR: + case GameVersion.LG: + if (SaveFormat == 3) + return metGen3.OrderByDescending(loc => loc.Value > 87 && loc.Value < 197); // Celadon Dept. + break; + + case GameVersion.D: + case GameVersion.P: + if (SaveFormat == 4 || (SaveFormat >= 5 && egg)) + return metGen4.Take(4).Concat(metGen6.Skip(4).OrderByDescending(loc => loc.Value <= 111)); // Battle Park + break; + + case GameVersion.Pt: + if (SaveFormat == 4 || (SaveFormat >= 5 && egg)) + return metGen4.Take(4).Concat(metGen6.Skip(4).OrderByDescending(loc => loc.Value <= 125)); // Rock Peak Ruins + break; + + case GameVersion.HG: + case GameVersion.SS: + if (SaveFormat == 4 || (SaveFormat >= 5 && egg)) + return metGen4.Take(4).Concat(metGen6.Skip(4).OrderByDescending(loc => loc.Value > 125 && loc.Value < 234)); // Celadon Dept. + break; + + case GameVersion.B: + case GameVersion.W: + return metGen5; + + case GameVersion.B2: + case GameVersion.W2: + return metGen5.Take(3).Concat(metGen5.Skip(3).OrderByDescending(loc => loc.Value <= 116)); // Abyssal Ruins + + case GameVersion.X: + case GameVersion.Y: + return metGen6.Take(3).Concat(metGen6.Skip(3).OrderByDescending(loc => loc.Value <= 168)); // Unknown Dungeon + + case GameVersion.OR: + case GameVersion.AS: + return metGen6.Take(3).Concat(metGen6.Skip(3).OrderByDescending(loc => loc.Value > 168 && loc.Value <= 354)); // Secret Base + } + + // Currently on a future game, return corresponding list for generation + if (Version <= GameVersion.CXD && SaveFormat == 4) + return metGen4.Where(loc => loc.Value == 0x37) // Pal Park to front + .Concat(metGen4.Take(4)) + .Concat(metGen4.Skip(4).Where(loc => loc.Value != 0x37)); + + if (Version < GameVersion.X && SaveFormat >= 5) // PokéTransfer to front + return metGen5.Where(loc => loc.Value == 30001) + .Concat(metGen5.Take(3)) + .Concat(metGen5.Skip(3).Where(loc => loc.Value != 30001)); + + return metGen6; + } private void updateOriginGame(object sender, EventArgs e) { - int Version = Util.getIndex(CB_GameOrigin); - - if (SAV.Generation == 3 && origintrack != "Gen3") + GameVersion Version = (GameVersion)Util.getIndex(CB_GameOrigin); + + // check if differs + GameVersion newTrack = SaveUtil.getVersionGroup(Version); + if (newTrack != origintrack) { - var met_list = Util.getCBList(metRSEFRLG_00000, Enumerable.Range(0, 213).ToArray()); - met_list = Util.getOffsetCBList(met_list, metRSEFRLG_00000, 00000, new[] {253, 254, 255}); - origintrack = "Gen3"; + var met_list = getLocationList(Version, SAV.Generation, egg:false); CB_MetLocation.DisplayMember = "Text"; CB_MetLocation.ValueMember = "Value"; - CB_MetLocation.DataSource = met_list; - CB_MetLocation.SelectedValue = 0; - } - else if (SAV.Generation == 4 && origintrack != "Gen4") - { - var met_list = Util.getCBList(metHGSS_00000, new[] { 0 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, new[] { 2000 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, new[] { 2002 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_03000, 3000, new[] { 3001 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_00000, 0000, Legal.Met_HGSS_0); - met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, Legal.Met_HGSS_2); - met_list = Util.getOffsetCBList(met_list, metHGSS_03000, 3000, Legal.Met_HGSS_3); - CB_MetLocation.DisplayMember = "Text"; - CB_MetLocation.ValueMember = "Value"; - CB_MetLocation.DataSource = met_list; + CB_MetLocation.DataSource = new BindingSource(met_list, null); + CB_MetLocation.SelectedIndex = 0; // transporter or pal park for past gen pkm + + var egg_list = getLocationList(Version, SAV.Generation, egg:true); CB_EggLocation.DisplayMember = "Text"; CB_EggLocation.ValueMember = "Value"; - CB_EggLocation.DataSource = new BindingSource(met_list, null); - CB_EggLocation.SelectedValue = 0; - CB_MetLocation.SelectedValue = 0; - origintrack = "Gen4"; - } - else if (Version < 24 && origintrack != "Past" && SAV.Generation >= 5) - { - // Load Past Gen Locations - #region B2W2 Met Locations - { - // Build up our met list - var met_list = Util.getCBList(metBW2_00000, new[] { 0 }); - met_list = Util.getOffsetCBList(met_list, metBW2_60000, 60001, new[] { 60002 }); - met_list = Util.getOffsetCBList(met_list, metBW2_30000, 30001, new[] { 30003 }); - met_list = Util.getOffsetCBList(met_list, metBW2_00000, 00000, Legal.Met_BW2_0); - met_list = Util.getOffsetCBList(met_list, metBW2_30000, 30001, Legal.Met_BW2_3); - met_list = Util.getOffsetCBList(met_list, metBW2_40000, 40001, Legal.Met_BW2_4); - met_list = Util.getOffsetCBList(met_list, metBW2_60000, 60001, Legal.Met_BW2_6); - CB_MetLocation.DisplayMember = "Text"; - CB_MetLocation.ValueMember = "Value"; - CB_MetLocation.DataSource = met_list; - CB_EggLocation.DisplayMember = "Text"; - CB_EggLocation.ValueMember = "Value"; - CB_EggLocation.DataSource = new BindingSource(met_list, null); - CB_EggLocation.SelectedValue = 0; - CB_MetLocation.SelectedValue = Version < 20 ? 30001 : 60001; - origintrack = "Past"; - } - #endregion - } - else if (Version > 23 && origintrack != "XY") - { - // Load X/Y/OR/AS locations - #region ORAS Met Locations - { - // Build up our met list - var met_list = Util.getCBList(metXY_00000, new[] { 0 }); - met_list = Util.getOffsetCBList(met_list, metXY_60000, 60001, new[] { 60002 }); - met_list = Util.getOffsetCBList(met_list, metXY_30000, 30001, new[] { 30002 }); - met_list = Util.getOffsetCBList(met_list, metXY_00000, 00000, Legal.Met_XY_0); - met_list = Util.getOffsetCBList(met_list, metXY_30000, 30001, Legal.Met_XY_3); - met_list = Util.getOffsetCBList(met_list, metXY_40000, 40001, Legal.Met_XY_4); - met_list = Util.getOffsetCBList(met_list, metXY_60000, 60001, Legal.Met_XY_6); - CB_MetLocation.DisplayMember = "Text"; - CB_MetLocation.ValueMember = "Value"; - CB_MetLocation.DataSource = met_list; - CB_EggLocation.DisplayMember = "Text"; - CB_EggLocation.ValueMember = "Value"; - CB_EggLocation.DataSource = new BindingSource(met_list, null); - CB_EggLocation.SelectedValue = 0; - CB_MetLocation.SelectedValue = 0; - origintrack = "XY"; - } - #endregion - } + CB_EggLocation.DataSource = new BindingSource(egg_list, null); + CB_EggLocation.SelectedIndex = CHK_AsEgg.Checked ? 1 : 0; // daycare : none - if (SAV.Generation >= 4 && Version < 0x10 && origintrack != "Gen4") - { - // Load Gen 4 egg locations if Gen 4 Origin. - #region HGSS Met Locations - var met_list = Util.getCBList(metHGSS_00000, new[] { 0 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, new[] { 2000 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, new[] { 2002 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_03000, 3000, new[] { 3001 }); - met_list = Util.getOffsetCBList(met_list, metHGSS_00000, 0000, Legal.Met_HGSS_0); - met_list = Util.getOffsetCBList(met_list, metHGSS_02000, 2000, Legal.Met_HGSS_2); - met_list = Util.getOffsetCBList(met_list, metHGSS_03000, 3000, Legal.Met_HGSS_3); - - CB_EggLocation.DisplayMember = "Text"; - CB_EggLocation.ValueMember = "Value"; - CB_EggLocation.DataSource = met_list; - CB_EggLocation.SelectedValue = 0; - origintrack = "Gen4"; - #endregion + origintrack = newTrack; } // Visibility logic for Gen 4 encounter type; only show for Gen 4 Pokemon. if (SAV.Generation >= 4) { - bool g4 = Version >= 7 && Version <= 12 && Version != 9; + bool g4 = Version >= GameVersion.HG && Version <= GameVersion.Pt; + if ((int) Version == 9) // invalid + g4 = false; CB_EncounterType.Visible = Label_EncounterType.Visible = g4; if (!g4) CB_EncounterType.SelectedValue = 0; @@ -2079,7 +2123,7 @@ private void updateOriginGame(object sender, EventArgs e) setMarkings(); // Set/Remove KB marking if (!fieldsLoaded) return; - pkm.Version = Version; + pkm.Version = (int)Version; updateLegality(); } private void updateExtraByteValue(object sender, EventArgs e) @@ -2325,28 +2369,13 @@ private void validateMove(object sender, EventArgs e) if (new[] { CB_Move1, CB_Move2, CB_Move3, CB_Move4 }.Contains(sender)) // Move updatePP(sender, e); - // Refresh Relearn if... - if (new[] { CB_RelearnMove1, CB_RelearnMove2, CB_RelearnMove3, CB_RelearnMove4 }.Contains(sender)) - { - if (pkm.Format < 6) - return; - ((PK6) pkm).RelearnMoves = new[] { Util.getIndex(CB_RelearnMove1), Util.getIndex(CB_RelearnMove2), Util.getIndex(CB_RelearnMove3), Util.getIndex(CB_RelearnMove4) }; - Legality.updateRelearnLegality(); - for (int i = 0; i < 4; i++) - movePB[i].Visible = !Legality.vRelearn[i].Valid; - } - // else, Refresh Moves - { - pkm.Moves = new[] { Util.getIndex(CB_Move1), Util.getIndex(CB_Move2), Util.getIndex(CB_Move3), Util.getIndex(CB_Move4) }; - Legality.updateMoveLegality(); - for (int i = 0; i < 4; i++) - movePB[i].Visible = !Legality.vMoves[i].Valid; - } - if (relearnPB.Any(p => p.Visible) || movePB.Any(p => p.Visible)) - { - Legality.Valid = false; - PB_Legal.Image = Properties.Resources.warn; - } + if (pkm.Format < 6) + return; + + // Legality + pkm.Moves = new[] { Util.getIndex(CB_Move1), Util.getIndex(CB_Move2), Util.getIndex(CB_Move3), Util.getIndex(CB_Move4) }; + pkm.RelearnMoves = new[] { Util.getIndex(CB_RelearnMove1), Util.getIndex(CB_RelearnMove2), Util.getIndex(CB_RelearnMove3), Util.getIndex(CB_RelearnMove4) }; + updateLegality(); } private void validateLocation(object sender, EventArgs e) { @@ -2382,8 +2411,15 @@ private void updateLegality(LegalityAnalysis la = null) // Refresh Move Legality for (int i = 0; i < 4; i++) movePB[i].Visible = !Legality.vMoves[i].Valid && !HaX; + + int[] suggested = Legality.getSuggestedRelearn(); for (int i = 0; i < 4; i++) - relearnPB[i].Visible = !Legality.vRelearn[i].Valid && !HaX; + { + if (pkm.RelearnMoves[i] == 0 && suggested[i] != 0) + relearnPB[i].Visible = !HaX; + else + relearnPB[i].Visible = !Legality.vRelearn[i].Valid && !HaX; + } } private void updateStats() { @@ -2718,14 +2754,20 @@ private void clickBoxSort(object sender, EventArgs e) setPKXBoxes(); Util.Alert("Current Box sorted!"); } - else if (ModifierKeys == Keys.Shift) + } + private void clickBoxDouble(object sender, MouseEventArgs e) + { + if (tabBoxMulti.SelectedIndex != 0) + return; + if (!SAV.HasBox) + return; + if (ModifierKeys != Keys.Shift) { var z = Application.OpenForms.Cast
().FirstOrDefault(form => form.GetType() == typeof(SAV_BoxViewer)) as SAV_BoxViewer; if (z != null) { Util.CenterToForm(z, this); z.BringToFront(); return; } - - new SAV_BoxViewer(this).Show(); } + new SAV_BoxViewer(this).Show(); } public int swapBoxesViewer(int viewBox) { diff --git a/PKHeX/PKM/PK6.cs b/PKHeX/PKM/PK6.cs index b731d2b26..c30b9db71 100644 --- a/PKHeX/PKM/PK6.cs +++ b/PKHeX/PKM/PK6.cs @@ -411,18 +411,6 @@ public int OppositeFriendship public bool IsUntraded => string.IsNullOrWhiteSpace(HT_Name); public bool IsUntradedEvent6 => Geo1_Country == 0 && Geo1_Region == 0 && Met_Location / 10000 == 4 && Gen6; - public int[] RelearnMoves - { - get { return new[] { RelearnMove1, RelearnMove2, RelearnMove3, RelearnMove4 }; } - set - { - if (value.Length > 0) RelearnMove1 = value[0]; - if (value.Length > 1) RelearnMove2 = value[1]; - if (value.Length > 2) RelearnMove3 = value[2]; - if (value.Length > 3) RelearnMove4 = value[3]; - } - } - // Complex Generated Attributes public override int Characteristic diff --git a/PKHeX/PKM/PKM.cs b/PKHeX/PKM/PKM.cs index 84b89785f..273088a93 100644 --- a/PKHeX/PKM/PKM.cs +++ b/PKHeX/PKM/PKM.cs @@ -287,6 +287,17 @@ public int[] Moves get { return new[] { Move1, Move2, Move3, Move4 }; } set { if (value?.Length != 4) return; Move1 = value[0]; Move2 = value[1]; Move3 = value[2]; Move4 = value[3]; } } + public int[] RelearnMoves + { + get { return new[] { RelearnMove1, RelearnMove2, RelearnMove3, RelearnMove4 }; } + set + { + if (value.Length > 0) RelearnMove1 = value[0]; + if (value.Length > 1) RelearnMove2 = value[1]; + if (value.Length > 2) RelearnMove3 = value[2]; + if (value.Length > 3) RelearnMove4 = value[3]; + } + } public int PIDAbility { get @@ -465,5 +476,9 @@ public void setPIDNature(int nature) if (GenNumber < 6) EncryptionConstant = PID; } + public void setPIDUnown3(int form) + { + do PID = Util.rnd32(); while (PKX.getUnownForm(PID) != form); + } } } diff --git a/PKHeX/Resources/byte/personal_dp b/PKHeX/Resources/byte/personal_dp index 48373cc00..4962a7a18 100644 Binary files a/PKHeX/Resources/byte/personal_dp and b/PKHeX/Resources/byte/personal_dp differ diff --git a/PKHeX/Resources/byte/personal_hgss b/PKHeX/Resources/byte/personal_hgss index c0a9df7fa..9dbd2eaa1 100644 Binary files a/PKHeX/Resources/byte/personal_hgss and b/PKHeX/Resources/byte/personal_hgss differ diff --git a/PKHeX/Resources/byte/personal_pt b/PKHeX/Resources/byte/personal_pt index c16af449e..f627c2cf8 100644 Binary files a/PKHeX/Resources/byte/personal_pt and b/PKHeX/Resources/byte/personal_pt differ diff --git a/PKHeX/Saves/SAV4.cs b/PKHeX/Saves/SAV4.cs index dabfeb61c..7384563ca 100644 --- a/PKHeX/Saves/SAV4.cs +++ b/PKHeX/Saves/SAV4.cs @@ -687,12 +687,162 @@ protected override void setDex(PKM pkm) int bit = pkm.Species - 1; // Set the Species Owned Flag - Data[PokeDex + brSize * 0 + bit / 8 + 0x4] |= (byte)(1 << (bit % 8)); + Data[PokeDex + brSize*0 + bit/8 + 0x4] |= (byte) (1 << (bit%8)); // Set the Species Seen Flag - Data[PokeDex + brSize * 1 + bit / 8 + 0x4] |= (byte)(1 << (bit % 8)); + Data[PokeDex + brSize*1 + bit/8 + 0x4] |= (byte) (1 << (bit%8)); - // Formes : todo + int FormOffset1 = PokeDex + 0x108; + int PokeDexLanguageFlags = FormOffset1 + 0x20; + + // Formes : Castform & Cherrim do not have entries (Battle Only formes) + // Lowest sub-value of formevalue is displayed, else is order of formes displayed. + + // Deoxys forms 1-2 are stored in the last byte of the first bitRegion. + // Deoxys forms 3-4 are stored in the last byte of the second bitRegion. + if (pkm.Species == 386) + { + uint val = (uint)(Data[PokeDex + 0x4 + 1*brSize - 1] | Data[PokeDex + 0x4 + 2*brSize - 1] << 8); + int[] forms = getDexFormValues(val, 4, 4); + checkInsertForm(ref forms, pkm.AltForm); + uint newval = setDexFormValues(forms, 4, 4); + + Data[PokeDex + 0x4 + 1*brSize - 1] = (byte)(newval & 0xFF); + Data[PokeDex + 0x4 + 2*brSize - 1] = (byte)((newval>>8) & 0xFF); + } + + // After the BitRegions is 0x20 bytes for the rest of the formes. + // Standard Forme Bytes (DP) + // [Shellos-Gastrodon-Burmy-Wormadam],[Unown*0x1C] + if (pkm.Species == 422) // Shellos + { + int[] forms = getDexFormValues(Data[FormOffset1 + 0], 2, 2); + checkInsertForm(ref forms, pkm.AltForm); + uint newval = setDexFormValues(forms, 2, 2); + Data[FormOffset1 + 0] = (byte)newval; + } + if (pkm.Species == 423) // Gastrodon + { + int[] forms = getDexFormValues(Data[FormOffset1 + 1], 2, 2); + checkInsertForm(ref forms, pkm.AltForm); + uint newval = setDexFormValues(forms, 2, 2); + Data[FormOffset1 + 1] = (byte)newval; + } + if (pkm.Species == 412) // Burmy + { + int[] forms = getDexFormValues(Data[FormOffset1 + 2], 2, 3); + checkInsertForm(ref forms, pkm.AltForm); + uint newval = setDexFormValues(forms, 2, 3); + Data[FormOffset1 + 2] = (byte)newval; + } + if (pkm.Species == 413) // Wormadam + { + int[] forms = getDexFormValues(Data[FormOffset1 + 3], 2, 3); + checkInsertForm(ref forms, pkm.AltForm); + uint newval = setDexFormValues(forms, 2, 3); + Data[FormOffset1 + 3] = (byte)newval; + } + if (pkm.Species == 201) // Unown + { + for (int i = 0; i < 0x1C; i++) + { + byte val = Data[FormOffset1 + 4 + i]; + if (val == pkm.AltForm) + break; // already set + if (val != 0xFF) + continue; // keep searching + + Data[FormOffset1 + 4 + i] = (byte)pkm.AltForm; + break; // form now set + } + } + + // DP stops here. + if (DP) + return; + + // Set the Language + int lang = pkm.Language - 1; + if (lang > 5) lang = 0; // no KOR + if (lang < 0) lang = 1; + Data[PokeDexLanguageFlags + pkm.Species] |= (byte) (1 << lang); + + int FormOffset2 = PokeDexLanguageFlags + 0x210; + // PtHGSS added more forms. + // [Rotom*4-highest bits unused],[Shaymin],[Giratina],[Pichu-HGSS ONLY] + if (pkm.Species == 479) // Rotom + { + int[] forms = getDexFormValues(BitConverter.ToUInt32(Data, FormOffset2), 3, 6); + checkInsertForm(ref forms, pkm.AltForm); + uint newval = setDexFormValues(forms, 3, 6); + BitConverter.GetBytes(newval).CopyTo(Data, FormOffset2); + } + if (pkm.Species == 492) // Shaymin + { + int[] forms = getDexFormValues(Data[FormOffset2 + 4], 2, 2); + uint newval = setDexFormValues(forms, 2, 2); + Data[FormOffset1 + 3] = (byte)newval; + } + if (pkm.Species == 487) // Giratina + { + int[] forms = getDexFormValues(Data[FormOffset2 + 5], 2, 2); + uint newval = setDexFormValues(forms, 2, 2); + Data[FormOffset1 + 3] = (byte)newval; + } + if (pkm.Species == 172 && HGSS) // Pichu + { + int[] forms = getDexFormValues(Data[FormOffset2 + 6], 2, 3); + uint newval = setDexFormValues(forms, 2, 3); + Data[FormOffset1 + 3] = (byte)newval; + } + } + private int[] getDexFormValues(uint Value, int BitsPerForm, int readCt) + { + int[] Forms = new int[readCt]; + int n1 = 0xFF >> (8 - BitsPerForm); + for (int i = 0; i < Forms.Length; i++) + { + int val = (int)(Value >> (i*BitsPerForm))&n1; + if (n1 == val) + Forms[i] = -1; + else + Forms[i] = val; + } + return Forms; + } + private uint setDexFormValues(int[] Forms, int BitsPerForm, int readCt) + { + int n1 = 0xFF >> (8 - BitsPerForm); + uint Value = 0xFFFFFFFF << (Forms.Length*BitsPerForm); + for (int i = 0; i < Forms.Length; i++) + { + int val = Forms[i]; + if (val == -1) + val = n1; + + Value |= (uint)(val << (BitsPerForm*i)); + } + return Value; + } + private bool checkInsertForm(ref int[] Forms, int FormNum) + { + if (Forms.Any(num => num == FormNum)) + { + return false; // already in list + } + if (Forms.All(num => num == -1)) + { + Forms[0] = FormNum; + return true; // none in list, insert at top + } + + // insert at first empty + int n1 = Array.IndexOf(Forms, -1); + if (n1 < 0) + return false; + + Forms[n1] = FormNum; + return true; } } } diff --git a/PKHeX/Saves/SAV5.cs b/PKHeX/Saves/SAV5.cs index 068006099..5f7870931 100644 --- a/PKHeX/Saves/SAV5.cs +++ b/PKHeX/Saves/SAV5.cs @@ -622,25 +622,47 @@ protected override void setDex(PKM pkm) int shiftoff = shiny * brSize * 2 + gender * brSize + brSize; // Set the Species Owned Flag - Data[PokeDex + bit / 8 + 0x8] |= (byte)(1 << (bit % 8)); + Data[PokeDex + 0x8 + bit / 8] |= (byte)(1 << (bit % 8)); // Set the [Species/Gender/Shiny] Seen Flag - Data[PokeDex + shiftoff + bit / 8 + 0x8] |= (byte)(1 << (bit % 8)); + Data[PokeDex + 0x8 + shiftoff + bit / 8] |= (byte)(1 << (bit % 8)); // Set the Display flag if none are set bool Displayed = false; - Displayed |= (Data[PokeDex + brSize * 5 + bit / 8 + 0x8] & (byte)(1 << (bit % 8))) != 0; - Displayed |= (Data[PokeDex + brSize * 6 + bit / 8 + 0x8] & (byte)(1 << (bit % 8))) != 0; - Displayed |= (Data[PokeDex + brSize * 7 + bit / 8 + 0x8] & (byte)(1 << (bit % 8))) != 0; - Displayed |= (Data[PokeDex + brSize * 8 + bit / 8 + 0x8] & (byte)(1 << (bit % 8))) != 0; - if (!Displayed) // offset is already biased by 0x60, reuse shiftoff but for the display flags. - Data[PokeDex + shiftoff + brSize * 4 + bit / 8 + 0x8] |= (byte)(1 << (bit % 8)); + Displayed |= (Data[PokeDex + 0x8 + brSize*5 + bit/8] & (byte)(1 << (bit%8))) != 0; + Displayed |= (Data[PokeDex + 0x8 + brSize*6 + bit/8] & (byte)(1 << (bit%8))) != 0; + Displayed |= (Data[PokeDex + 0x8 + brSize*7 + bit/8] & (byte)(1 << (bit%8))) != 0; + Displayed |= (Data[PokeDex + 0x8 + brSize*8 + bit/8] & (byte)(1 << (bit%8))) != 0; + if (!Displayed) // offset is already biased by brSize, reuse shiftoff but for the display flags. + Data[PokeDex + 0x8 + shiftoff + brSize*4 + bit/8] |= (byte)(1 << (bit%8)); // Set the Language if (lang < 0) lang = 1; - Data[PokeDexLanguageFlags + (bit * 7 + lang) / 8] |= (byte)(1 << ((bit * 7 + lang) % 8)); + Data[PokeDexLanguageFlags + (bit*7 + lang) / 8] |= (byte)(1 << ((bit*7 + lang) % 8)); - // Formes : todo + // Formes + int fc = Personal[pkm.Species].FormeCount; + int f = B2W2 ? SaveUtil.getDexFormIndexB2W2(pkm.Species, fc) : SaveUtil.getDexFormIndexBW(pkm.Species, fc); + if (f < 0) return; + + int FormLen = B2W2 ? 0xB : 0x9; + int FormDex = PokeDex + 0x8 + brSize*9; + bit = f + pkm.AltForm; + + // Set Form Seen Flag + Data[FormDex + FormLen*shiny + bit/8] |= (byte)(1 << (bit%8)); + + // Set Displayed Flag if necessary, check all flags + for (int i = 0; i < fc; i++) + { + bit = f + i; + if ((Data[FormDex + FormLen*2 + bit/8] & (byte)(1 << (bit%8))) != 0) // Nonshiny + return; // already set + if ((Data[FormDex + FormLen*3 + bit/8] & (byte)(1 << (bit%8))) != 0) // Shiny + return; // already set + } + bit = f + pkm.AltForm; + Data[FormDex + FormLen * (2 + shiny) + bit / 8] |= (byte)(1 << (bit % 8)); } } } diff --git a/PKHeX/Saves/SAV6.cs b/PKHeX/Saves/SAV6.cs index e18a4319d..9063f81ec 100644 --- a/PKHeX/Saves/SAV6.cs +++ b/PKHeX/Saves/SAV6.cs @@ -730,35 +730,33 @@ protected override void setDex(PKM pkm) if (lang < 0) lang = 1; Data[PokeDexLanguageFlags + (bit * 7 + lang) / 8] |= (byte)(1 << ((bit * 7 + lang) % 8)); - // Set Form flags - int fc = Personal[pkm.Species].FormeCount; - int f = ORAS ? SaveUtil.getDexFormIndexORAS(pkm.Species, fc) : SaveUtil.getDexFormIndexXY(pkm.Species, fc); - if (f >= 0) - { - int FormLen = ORAS ? 0x26 : 0x18; - int FormDex = PokeDex + 0x368; - bit = f + pkm.AltForm; - // Set Seen Flag - Data[FormDex + FormLen * shiny + bit / 8] |= (byte)(1 << (bit % 8)); - - // Set Displayed Flag if necessary, check all flags - bool FormDisplayed = false; - for (int i = 0; i < fc; i++) - { - bit = f + i; - FormDisplayed |= (Data[FormDex + FormLen * 2 + bit / 8] & (byte)(1 << (bit % 8))) != 0; // Nonshiny - FormDisplayed |= (Data[FormDex + FormLen * 3 + bit / 8] & (byte)(1 << (bit % 8))) != 0; // Shiny - } - if (!FormDisplayed) - { - bit = f + pkm.AltForm; - Data[FormDex + FormLen * (2 + shiny) + bit / 8] |= (byte)(1 << (bit % 8)); - } - } - // Set DexNav count (only if not encountered previously) if (ORAS && getEncounterCount(pkm.Species - 1) == 0) setEncounterCount(pkm.Species - 1, 1); + + // Set Form flags + int fc = Personal[pkm.Species].FormeCount; + int f = ORAS ? SaveUtil.getDexFormIndexORAS(pkm.Species, fc) : SaveUtil.getDexFormIndexXY(pkm.Species, fc); + if (f < 0) return; + + int FormLen = ORAS ? 0x26 : 0x18; + int FormDex = PokeDex + 0x8 + brSize*9; + bit = f + pkm.AltForm; + + // Set Form Seen Flag + Data[FormDex + FormLen*shiny + bit/8] |= (byte)(1 << (bit%8)); + + // Set Displayed Flag if necessary, check all flags + for (int i = 0; i < fc; i++) + { + bit = f + i; + if ((Data[FormDex + FormLen*2 + bit/8] & (byte) (1 << (bit%8))) != 0) // Nonshiny + return; // already set + if ((Data[FormDex + FormLen*3 + bit/8] & (byte) (1 << (bit%8))) != 0) // Shiny + return; // already set + } + bit = f + pkm.AltForm; + Data[FormDex + FormLen * (2 + shiny) + bit / 8] |= (byte)(1 << (bit % 8)); } public override byte[] decryptPKM(byte[] data) { diff --git a/PKHeX/Saves/SaveUtil.cs b/PKHeX/Saves/SaveUtil.cs index 8c53069c5..f8d7db77e 100644 --- a/PKHeX/Saves/SaveUtil.cs +++ b/PKHeX/Saves/SaveUtil.cs @@ -205,6 +205,59 @@ public static GameVersion getIsG6SAV(byte[] data) return GameVersion.Invalid; } + /// Determines the Version Grouping of an input Version ID + /// Version of which to determine the group + /// Version Group Identifier or Invalid if type cannot be determined. + public static GameVersion getVersionGroup(GameVersion Version) + { + switch (Version) + { + case GameVersion.CXD: + return GameVersion.CXD; + + case GameVersion.R: + case GameVersion.S: + return GameVersion.RS; + + case GameVersion.E: + return GameVersion.E; + + case GameVersion.FR: + case GameVersion.LG: + return GameVersion.FR; + + case GameVersion.D: + case GameVersion.P: + return GameVersion.DP; + + case GameVersion.Pt: + return GameVersion.Pt; + + case GameVersion.HG: + case GameVersion.SS: + return GameVersion.HGSS; + + case GameVersion.B: + case GameVersion.W: + return GameVersion.BW; + + case GameVersion.B2: + case GameVersion.W2: + return GameVersion.B2W2; + + case GameVersion.X: + case GameVersion.Y: + return GameVersion.XY; + + case GameVersion.OR: + case GameVersion.AS: + return GameVersion.ORAS; + + default: + return GameVersion.Invalid; + } + } + /// Creates an instance of a SaveFile using the given save data. /// Save data from which to create a SaveFile. /// An appropriate type of save file for the given data, or null if the save data is invalid. @@ -335,7 +388,7 @@ internal static ushort check32(byte[] data) return (ushort)((val & 0xFFFF) + (val >> 16)); } - public static int getDexFormIndexXY(int species, int formct) + public static int getDexFormIndexBW(int species, int formct) { if (formct < 1 || species < 0) return -1; // invalid @@ -357,11 +410,29 @@ public static int getDexFormIndexXY(int species, int formct) case 648: return 066; // 2 Meloetta case 555: return 068; // 2 Darmanitan case 550: return 070; // 2 Basculin + default: return -1; + } + } + public static int getDexFormIndexB2W2(int species, int formct) + { + if (formct < 1 || species < 0) + return -1; // invalid + switch (species) + { case 646: return 072; // 3 Kyurem case 647: return 075; // 2 Keldeo case 642: return 077; // 2 Thundurus case 641: return 079; // 2 Tornadus case 645: return 081; // 2 Landorus + default: return getDexFormIndexBW(species, formct); + } + } + public static int getDexFormIndexXY(int species, int formct) + { + if (formct < 1 || species < 0) + return -1; // invalid + switch (species) + { case 666: return 083; // 20 Vivillion case 669: return 103; // 5 Flabébé case 670: return 108; // 6 Floette @@ -398,7 +469,7 @@ public static int getDexFormIndexXY(int species, int formct) case 445: return 183; // 2 Garchomp case 448: return 185; // 2 Lucario case 460: return 187; // 2 Abomasnow - default: return -1; + default: return getDexFormIndexB2W2(species, formct); } } public static int getDexFormIndexORAS(int species, int formct)