/// <summary>Creates an instance of a SaveFile using the given save data.</summary> /// <param name="data">Save data from which to create a SaveFile.</param> /// <returns>An appropriate type of save file for the given data, or null if the save data is invalid.</returns> public static SaveFile getVariantSAV(byte[] data) { // Pre-check for header/footer signatures SaveFile sav; byte[] header = new byte[0], footer = new byte[0]; CheckHeaderFooter(ref data, ref header, ref footer); switch (getSAVGeneration(data)) { // Main Games case GameVersion.Gen1: sav = new SAV1(data); break; case GameVersion.Gen2: sav = new SAV2(data); break; case GameVersion.Gen3: sav = new SAV3(data); break; case GameVersion.Gen4: sav = new SAV4(data); break; case GameVersion.Gen5: sav = new SAV5(data); break; case GameVersion.Gen6: sav = new SAV6(data); break; case GameVersion.Gen7: sav = new SAV7(data); break; // Side Games case GameVersion.COLO: sav = new SAV3Colosseum(data); break; case GameVersion.XD: sav = new SAV3XD(data); break; case GameVersion.RSBOX: sav = new SAV3RSBox(data); break; case GameVersion.BATREV: sav = new SAV4BR(data); break; // No pattern matched default: return(null); } sav.Header = header; sav.Footer = footer; return(sav); }
private void openSAV(SaveFile sav, string path) { if (sav == null || sav.Version == GameVersion.Invalid) { Util.Error("Invalid save file loaded. Aborting.", path); return; } // Finish setting up the save file. if (sav.IndeterminateGame && sav.Generation == 3) { // Hacky cheats invalidated the Game Code value. var drGame = Util.Prompt(MessageBoxButtons.YesNoCancel, "Unknown Gen3 Game Detected. Select Origins:", "Yes: Ruby / Sapphire" + Environment.NewLine + "No: Emerald" + Environment.NewLine + "Cancel: FireRed / LeafGreen"); switch (drGame) // Reset save file info { case DialogResult.Yes: sav = new SAV3(sav.BAK, GameVersion.RS); break; case DialogResult.No: sav = new SAV3(sav.BAK, GameVersion.E); break; case DialogResult.Cancel: sav = new SAV3(sav.BAK, GameVersion.FRLG); break; default: return; } } if (sav.IndeterminateLanguage) { // Japanese Save files are different. Get isJapanese var drJP = Util.Prompt(MessageBoxButtons.YesNoCancel, $"{sav.Version} Save File detected. Select language...", "Yes: International" + Environment.NewLine + "No: Japanese"); if (drJP == DialogResult.Cancel) return; sav.Japanese = drJP == DialogResult.No; } if (sav.IndeterminateSubVersion && sav.Version == GameVersion.FRLG) { var drFRLG = Util.Prompt(MessageBoxButtons.YesNoCancel, $"{sav.Version} detected. Select version...", "Yes: FireRed" + Environment.NewLine + "No: LeafGreen"); if (drFRLG == DialogResult.Cancel) return; sav.Personal = drFRLG == DialogResult.Yes ? PersonalTable.FR : PersonalTable.LG; } // clean fields PKM pk = preparePKM(); populateFields(SAV.BlankPKM); SAV = sav; if (path != null) // Actual save file { SAV.FilePath = Path.GetDirectoryName(path); SAV.FileName = Path.GetExtension(path) == ".bak" ? Path.GetFileName(path).Split(new[] { " [" }, StringSplitOptions.None)[0] : Path.GetFileName(path); Text = $"PKH{(HaX ? "a" : "e")}X - " + $"SAV{SAV.Generation}: {Path.GetFileNameWithoutExtension(Util.CleanFileName(SAV.BAKName))}"; // more descriptive // If backup folder exists, save a backup. string backupName = Path.Combine(BackupPath, Util.CleanFileName(SAV.BAKName)); if (SAV.Exportable && Directory.Exists(BackupPath) && !File.Exists(backupName)) File.WriteAllBytes(backupName, SAV.BAK); GB_SAVtools.Visible = true; } else // Blank save file { SAV.FilePath = null; SAV.FileName = "Blank Save File"; Text = $"PKH{(HaX ? "a" : "e")}X - " + $"SAV{SAV.Generation}: {SAV.FileName} [{SAV.OT} ({SAV.Version})]"; GB_SAVtools.Visible = false; } Menu_ExportSAV.Enabled = B_VerifyCHK.Enabled = SAV.Exportable; // Close subforms that are save dependent Type[] f = { typeof(SAV_BoxViewer), typeof(f2_Text) }; foreach (var form in Application.OpenForms.Cast<Form>().Where(form => f.Contains(form.GetType())).ToArray()) form.Close(); setBoxNames(); // Display the Box Names if (SAV.HasBox) { int startBox = path == null ? 0 : SAV.CurrentBox; // FF if BattleBox if (startBox > SAV.BoxCount - 1) { tabBoxMulti.SelectedIndex = 1; CB_BoxSelect.SelectedIndex = 0; } else { tabBoxMulti.SelectedIndex = 0; CB_BoxSelect.SelectedIndex = startBox; } } setPKXBoxes(); // Reload all of the PKX Windows bool WindowTranslationRequired = false; // Hide content if not present in game. GB_SUBE.Visible = SAV.HasSUBE; PB_Locked.Visible = SAV.HasBattleBox && SAV.BattleBoxLocked; if (!SAV.HasBox && tabBoxMulti.TabPages.Contains(Tab_Box)) tabBoxMulti.TabPages.Remove(Tab_Box); else if (SAV.HasBox && !tabBoxMulti.TabPages.Contains(Tab_Box)) { tabBoxMulti.TabPages.Insert(0, Tab_Box); WindowTranslationRequired = true; } Menu_LoadBoxes.Enabled = Menu_DumpBoxes.Enabled = Menu_Report.Enabled = Menu_Modify.Enabled = B_SaveBoxBin.Enabled = SAV.HasBox; int BoxTab = tabBoxMulti.TabPages.IndexOf(Tab_Box); int PartyTab = tabBoxMulti.TabPages.IndexOf(Tab_PartyBattle); if (!SAV.HasParty && tabBoxMulti.TabPages.Contains(Tab_PartyBattle)) tabBoxMulti.TabPages.Remove(Tab_PartyBattle); else if (SAV.HasParty && !tabBoxMulti.TabPages.Contains(Tab_PartyBattle)) { int index = BoxTab; if (index < 0) index = -1; tabBoxMulti.TabPages.Insert(index + 1, Tab_PartyBattle); WindowTranslationRequired = true; } if (!SAV.HasDaycare && tabBoxMulti.TabPages.Contains(Tab_Other)) tabBoxMulti.TabPages.Remove(Tab_Other); else if (SAV.HasDaycare && !tabBoxMulti.TabPages.Contains(Tab_Other)) { int index = PartyTab; if (index < 0) index = BoxTab; if (index < 0) index = -1; tabBoxMulti.TabPages.Insert(index + 1, Tab_Other); WindowTranslationRequired = true; } if (path != null) // Actual save file { PAN_BattleBox.Visible = L_BattleBox.Visible = L_ReadOnlyPBB.Visible = SAV.HasBattleBox; GB_Daycare.Visible = SAV.HasDaycare; GB_Fused.Visible = SAV.HasFused; GB_GTS.Visible = SAV.HasGTS; B_OpenSecretBase.Enabled = SAV.HasSecretBase; B_OpenPokepuffs.Enabled = SAV.HasPuff; B_OUTPasserby.Enabled = SAV.HasPSS; B_OpenBoxLayout.Enabled = SAV.HasBoxWallpapers; B_OpenWondercards.Enabled = SAV.HasWondercards; B_OpenSuperTraining.Enabled = SAV.HasSuperTrain; B_OpenHallofFame.Enabled = SAV.HasHoF; B_OpenOPowers.Enabled = SAV.HasOPower; B_OpenPokedex.Enabled = SAV.HasPokeDex; B_OpenBerryField.Enabled = SAV.HasBerryField && SAV.XY; B_OpenPokeblocks.Enabled = SAV.HasPokeBlock; B_JPEG.Enabled = SAV.HasJPEG; B_OpenEventFlags.Enabled = SAV.HasEvents; B_OpenLinkInfo.Enabled = SAV.HasLink; B_CGearSkin.Enabled = SAV.Generation == 5; B_OpenTrainerInfo.Visible = B_OpenItemPouch.Visible = SAV.HasParty; // Box RS } GB_SAVtools.Visible = FLP_SAVtools.Controls.Cast<Control>().Any(c => c.Enabled); foreach (Control c in FLP_SAVtools.Controls.Cast<Control>()) c.Visible = c.Enabled; // Generational Interface byte[] extraBytes = new byte[1]; Tip1.RemoveAll(); Tip2.RemoveAll(); Tip3.RemoveAll(); // TSV/PSV FLP_Country.Visible = FLP_SubRegion.Visible = FLP_3DSRegion.Visible = SAV.Generation >= 6; Label_EncryptionConstant.Visible = BTN_RerollEC.Visible = TB_EC.Visible = SAV.Generation >= 6; GB_nOT.Visible = GB_RelearnMoves.Visible = BTN_Medals.Visible = BTN_History.Visible = SAV.Generation >= 6; PB_Legal.Visible = PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = SAV.Generation >= 6; PB_MarkPentagon.Visible = SAV.Generation >= 6; PB_MarkAlola.Visible = SAV.Generation >= 7; TB_Secure1.Visible = TB_Secure2.Visible = L_GameSync.Visible = L_Secure1.Visible = L_Secure2.Visible = SAV.Exportable && SAV.Generation >= 6; TB_GameSync.Visible = SAV.Exportable && SAV.Generation == 6; FLP_NSparkle.Visible = L_NSparkle.Visible = CHK_NSparkle.Visible = SAV.Generation == 5; CB_Form.Visible = Label_Form.Visible = CHK_AsEgg.Visible = GB_EggConditions.Visible = PB_Mark5.Visible = PB_Mark6.Visible = SAV.Generation >= 4; DEV_Ability.Enabled = DEV_Ability.Visible = SAV.Generation > 3 && HaX; CB_Ability.Visible = !DEV_Ability.Enabled && SAV.Generation >= 3; FLP_Nature.Visible = SAV.Generation >= 3; FLP_Ability.Visible = SAV.Generation >= 3; FLP_Language.Visible = SAV.Generation >= 3; GB_ExtraBytes.Visible = GB_ExtraBytes.Enabled = SAV.Generation >= 3; GB_Markings.Visible = SAV.Generation >= 3; BTN_Ribbons.Visible = SAV.Generation >= 3; CB_HPType.Enabled = CB_Form.Enabled = SAV.Generation >= 3; BTN_RerollPID.Visible = Label_PID.Visible = TB_PID.Visible = Label_SID.Visible = TB_SID.Visible = SAV.Generation >= 3; FLP_FriendshipForm.Visible = SAV.Generation >= 2; FLP_HeldItem.Visible = SAV.Generation >= 2; CHK_IsEgg.Visible = Label_Gender.Visible = SAV.Generation >= 2; FLP_PKRS.Visible = FLP_EggPKRSRight.Visible = SAV.Generation >= 2; Label_OTGender.Visible = SAV.Generation >= 2; if (SAV.Generation == 1) Label_IsShiny.Visible = false; if (SAV.Version == GameVersion.BATREV) { L_SaveSlot.Visible = CB_SaveSlot.Visible = true; CB_SaveSlot.Items.Clear(); CB_SaveSlot.DisplayMember = "Text"; CB_SaveSlot.ValueMember = "Value"; CB_SaveSlot.DataSource = new BindingSource(((SAV4BR) SAV).SaveSlots.Select(i => new ComboItem { Text = ((SAV4BR) SAV).SaveNames[i], Value = i }).ToList(), null); CB_SaveSlot.SelectedValue = ((SAV4BR)SAV).CurrentSlot; } else L_SaveSlot.Visible = CB_SaveSlot.Visible = false; FLP_Purification.Visible = FLP_ShadowID.Visible = SAV.Version == GameVersion.COLO || SAV.Version == GameVersion.XD; NUD_ShadowID.Maximum = SAV.MaxShadowID; // HaX override, needs to be after DEV_Ability enabled assignment. TB_AbilityNumber.Visible = SAV.Generation >= 6 && DEV_Ability.Enabled; // Met Tab FLP_MetDate.Visible = SAV.Generation >= 4; FLP_Fateful.Visible = FLP_Ball.Visible = FLP_OriginGame.Visible = SAV.Generation >= 3; FLP_MetLocation.Visible = FLP_MetLevel.Visible = SAV.Generation >= 2; FLP_TimeOfDay.Visible = SAV.Generation == 2; // Stats FLP_StatsTotal.Visible = SAV.Generation >= 3; FLP_Characteristic.Visible = SAV.Generation >= 3; FLP_HPType.Visible = SAV.Generation >= 2; PAN_Contest.Visible = SAV.Generation >= 3; // Second daycare slot SlotPictureBoxes[43].Visible = SAV.Generation >= 2; if (sav.Generation == 1) { FLP_SpD.Visible = false; Label_SPA.Visible = false; Label_SPC.Visible = true; TB_HPIV.Enabled = false; MaskedTextBox[] evControls = { TB_SPAEV, TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPEEV, TB_SPDEV }; foreach (var ctrl in evControls) { ctrl.Mask = "00000"; ctrl.Size = Stat_HP.Size; } } else if (sav.Generation == 2) { FLP_SpD.Visible = true; Label_SPA.Visible = true; Label_SPC.Visible = false; TB_SPDEV.Enabled = TB_SPDIV.Enabled = false; TB_HPIV.Enabled = false; MaskedTextBox[] evControls = { TB_SPAEV, TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPEEV, TB_SPDEV }; foreach (var ctrl in evControls) { ctrl.Mask = "00000"; ctrl.Size = Stat_HP.Size; } } else { FLP_SpD.Visible = true; Label_SPA.Visible = true; Label_SPC.Visible = false; TB_SPDEV.Enabled = TB_SPDIV.Enabled = true; TB_HPIV.Enabled = true; MaskedTextBox[] evControls = { TB_SPAEV, TB_HPEV, TB_ATKEV, TB_DEFEV, TB_SPEEV, TB_SPDEV }; foreach (var ctrl in evControls) { ctrl.Mask = "000"; ctrl.Size = TB_ExtraByte.Size; } } // Recenter PKM SubEditors FLP_PKMEditors.Location = new Point((Tab_OTMisc.Width - FLP_PKMEditors.Width) / 2, FLP_PKMEditors.Location.Y); switch (SAV.Generation) { case 1: getFieldsfromPKM = populateFieldsPK1; getPKMfromFields = preparePK1; extraBytes = new byte[] {}; break; case 2: getFieldsfromPKM = populateFieldsPK2; getPKMfromFields = preparePK2; extraBytes = new byte[] { }; break; case 3: if (SAV.Version == GameVersion.COLO) { getFieldsfromPKM = populateFieldsCK3; getPKMfromFields = prepareCK3; extraBytes = CK3.ExtraBytes; break; } if (SAV.Version == GameVersion.XD) { getFieldsfromPKM = populateFieldsXK3; getPKMfromFields = prepareXK3; extraBytes = XK3.ExtraBytes; break; } getFieldsfromPKM = populateFieldsPK3; getPKMfromFields = preparePK3; extraBytes = PK3.ExtraBytes; break; case 4: if (SAV.Version == GameVersion.BATREV) { getFieldsfromPKM = populateFieldsBK4; getPKMfromFields = prepareBK4; } else { getFieldsfromPKM = populateFieldsPK4; getPKMfromFields = preparePK4; } extraBytes = PK4.ExtraBytes; break; case 5: getFieldsfromPKM = populateFieldsPK5; getPKMfromFields = preparePK5; extraBytes = PK5.ExtraBytes; break; case 6: getFieldsfromPKM = populateFieldsPK6; getPKMfromFields = preparePK6; extraBytes = PK6.ExtraBytes; TB_GameSync.Enabled = (SAV.GameSyncID ?? 0) != 0; TB_GameSync.Text = SAV.GameSyncID?.ToString("X16"); TB_Secure1.Text = SAV.Secure1?.ToString("X16"); TB_Secure2.Text = SAV.Secure2?.ToString("X16"); break; case 7: getFieldsfromPKM = populateFieldsPK7; getPKMfromFields = preparePK7; extraBytes = PK7.ExtraBytes; TB_GameSync.Enabled = (SAV.GameSyncID ?? 0) != 0; TB_GameSync.Text = SAV.GameSyncID?.ToString("X16"); TB_Secure1.Text = SAV.Secure1?.ToString("X16"); TB_Secure2.Text = SAV.Secure2?.ToString("X16"); break; } bool init = fieldsInitialized; fieldsInitialized = fieldsLoaded = false; pkm = pkm.GetType() != SAV.PKMType ? SAV.BlankPKM : pk; if (pkm.Format < 3) pkm = SAV.BlankPKM; populateFilteredDataSources(); populateFields(pkm); fieldsInitialized |= init; // SAV Specific Limits TB_OT.MaxLength = SAV.OTLength; TB_OTt2.MaxLength = SAV.OTLength; TB_Nickname.MaxLength = SAV.NickLength; // Hide Unused Tabs if (SAV.Generation == 1 && tabMain.TabPages.Contains(Tab_Met)) tabMain.TabPages.Remove(Tab_Met); else if (SAV.Generation != 1 && !tabMain.TabPages.Contains(Tab_Met)) { tabMain.TabPages.Insert(1, Tab_Met); WindowTranslationRequired = true; } // Common HaX Interface CHK_HackedStats.Enabled = CHK_HackedStats.Visible = MT_Level.Enabled = MT_Level.Visible = MT_Form.Enabled = MT_Form.Visible = HaX; TB_Level.Visible = !HaX; // Load Extra Byte List if (GB_ExtraBytes.Enabled) { CB_ExtraBytes.Items.Clear(); foreach (byte b in extraBytes) CB_ExtraBytes.Items.Add("0x" + b.ToString("X2")); CB_ExtraBytes.SelectedIndex = 0; } // pk2 save files do not have an Origin Game stored. Prompt the met location list to update. if (SAV.Generation == 2) updateOriginGame(null, null); // Refresh PK* conversion info PKMConverter.updateConfig(SAV.SubRegion, SAV.Country, SAV.ConsoleRegion, SAV.OT, SAV.Gender); if (WindowTranslationRequired) // force update -- re-added controls may be untranslated Util.TranslateInterface(this, curlanguage); // No changes made yet UndoStack.Clear(); Menu_Undo.Enabled = false; RedoStack.Clear(); Menu_Redo.Enabled = false; // Indicate audibly the save is loaded SystemSounds.Beep.Play(); }
/// <summary>Creates an instance of a SaveFile using the given save data.</summary> /// <param name="data">Save data from which to create a SaveFile.</param> /// <returns>An appropriate type of save file for the given data, or null if the save data is invalid.</returns> public static SaveFile getVariantSAV(byte[] data) { // Pre-check for header/footer signatures SaveFile sav; byte[] header = new byte[0], footer = new byte[0]; CheckHeaderFooter(ref data, ref header, ref footer); switch (getSAVGeneration(data)) { // Main Games case GameVersion.Gen1: sav = new SAV1(data); break; case GameVersion.Gen2: sav = new SAV2(data); break; case GameVersion.Gen3: sav = new SAV3(data); break; case GameVersion.Gen4: sav = new SAV4(data); break; case GameVersion.Gen5: sav = new SAV5(data); break; case GameVersion.Gen6: sav = new SAV6(data); break; case GameVersion.Gen7: sav = new SAV7(data); break; // Side Games case GameVersion.COLO: sav = new SAV3Colosseum(data); break; case GameVersion.XD: sav = new SAV3XD(data); break; case GameVersion.RSBOX: sav = new SAV3RSBox(data); break; case GameVersion.BATREV: sav = new SAV4BR(data); break; // No pattern matched default: return null; } sav.Header = header; sav.Footer = footer; return sav; }