diff --git a/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs b/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs index 7adfac889..b1e72faa0 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/FashionBlock7.cs @@ -9,27 +9,53 @@ public sealed class FashionBlock7 : SaveBlock private const int FashionLength = 0x1A08; - public sealed class FashionItem + // Every fashion item is 2 bits, New Flag (high) & Owned Flag (low) + public sealed class FashionItem7 { public bool IsOwned { get; set; } public bool IsNew { get; set; } + + public FashionItem7(byte b) + { + IsOwned = (b & 1) != 0; + IsNew = (b & 2) != 0; + } + + public byte Value => (byte)((IsOwned ? 1 : 0) | (IsNew ? 2 : 0)); } - public FashionItem[] Wardrobe + public FashionItem7[] Wardrobe { get { var data = SAV.GetData(Offset, 0x5A8); - return data.Select(b => new FashionItem { IsOwned = (b & 1) != 0, IsNew = (b & 2) != 0 }).ToArray(); + return data.Select(b => new FashionItem7(b)).ToArray(); } set { if (value.Length != 0x5A8) throw new ArgumentOutOfRangeException($"Unexpected size: 0x{value.Length:X}"); - SAV.SetData(value.Select(t => (byte)((t.IsOwned ? 1 : 0) | (t.IsNew ? 2 : 0))).ToArray(), Offset); + SAV.SetData(value.Select(z => z.Value).ToArray(), Offset); } } public void Clear() => Array.Clear(Data, Offset, FashionLength); + + /// + /// Resets the fashion unlocks to default values. + /// + public void Reset() + { + var offsetList = SAV is SAV7USUM + ? (SAV.Gender == 0 + ? new[] { 0x03A, 0x109, 0x1DA, 0x305, 0x3D9, 0x4B1, 0x584 } // M + : new[] { 0x05E, 0x208, 0x264, 0x395, 0x3B4, 0x4F9, 0x5A8 }) // F + : (SAV.Gender == 0 + ? new[] { 0x000, 0x0FB, 0x124, 0x28F, 0x3B4, 0x452, 0x517 } // M + : new[] { 0x000, 0x100, 0x223, 0x288, 0x3B4, 0x452, 0x517 }); // F + + foreach (var ofs in offsetList) + SAV.Data[Offset + ofs] = 3; // owned | new + } } } \ No newline at end of file diff --git a/PKHeX.Core/Util/DateUtil.cs b/PKHeX.Core/Util/DateUtil.cs index fcf21e783..d94d98de9 100644 --- a/PKHeX.Core/Util/DateUtil.cs +++ b/PKHeX.Core/Util/DateUtil.cs @@ -27,5 +27,33 @@ public static bool IsDateValid(uint year, uint month, uint day) { return year < int.MaxValue && month < int.MaxValue && day < int.MaxValue && IsDateValid((int)year, (int)month, (int)day); } + + private static readonly DateTime Epoch2000 = new DateTime(2000, 1, 1); + private const int spd = 86400; // seconds per day + + public static int GetSecondsFrom2000(DateTime date, DateTime time) + { + int seconds = (int)(date - Epoch2000).TotalSeconds; + seconds -= seconds % spd; + seconds += (int)(time - Epoch2000).TotalSeconds; + return seconds; + } + + public static void GetDateTime2000(uint seconds, out DateTime date, out DateTime time) + { + date = Epoch2000.AddSeconds(seconds); + time = Epoch2000.AddSeconds(seconds % spd); + } + + public static string ConvertDateValueToString(int value, int secondsBias = -1) + { + string tip = string.Empty; + if (value >= spd) + tip += (value / spd) + "d "; + tip += new DateTime(0).AddSeconds(value).ToString("HH:mm:ss"); + if (secondsBias >= 0) + tip += Environment.NewLine + $"Date: {Epoch2000.AddSeconds(value + secondsBias)}"; + return tip; + } } } diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs index 681428503..65773043f 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen6/SAV_Trainer.cs @@ -53,10 +53,12 @@ public SAV_Trainer(SaveFile sav) L_Style.Visible = TB_Style.Visible = SAV is SAV6XY; if (!(SAV is SAV6XY)) TC_Editor.TabPages.Remove(Tab_Appearance); + if (SAV is SAV6AODemo) + { TC_Editor.TabPages.Remove(Tab_Multiplayer); - if (SAV is SAV6AODemo) TC_Editor.TabPages.Remove(Tab_Maison); + } GetComboBoxes(); GetTextBoxes(); @@ -68,7 +70,7 @@ public SAV_Trainer(SaveFile sav) CHK_MegaRayquazaUnlocked.Checked = status.IsMegaRayquazaUnlocked; } - private readonly bool editing = true; + private readonly bool editing; private readonly ToolTip Tip1 = new ToolTip(), Tip2 = new ToolTip(); private readonly MaskedTextBox[] MaisonRecords; private readonly CheckBox[] cba; @@ -217,11 +219,13 @@ private void GetTextBoxes() L_LastSaved.Visible = CAL_LastSavedDate.Visible = CAL_LastSavedTime.Visible = false; } - var epoch = new DateTime(2000, 1, 1); - CAL_AdventureStartDate.Value = epoch.AddSeconds(SAV.SecondsToStart); - CAL_AdventureStartTime.Value = epoch.AddSeconds(SAV.SecondsToStart % 86400); - CAL_HoFDate.Value = epoch.AddSeconds(SAV.SecondsToFame); - CAL_HoFTime.Value = epoch.AddSeconds(SAV.SecondsToFame % 86400); + Util.GetDateTime2000(SAV.SecondsToStart, out var date, out var time); + CAL_AdventureStartDate.Value = date; + CAL_AdventureStartTime.Value = time; + + Util.GetDateTime2000(SAV.SecondsToStart, out date, out time); + CAL_HoFDate.Value = date; + CAL_HoFTime.Value = time; } private void Save() @@ -295,15 +299,8 @@ private void Save() // Vivillon SAV.Vivillon = CB_Vivillon.SelectedIndex; - uint seconds = (uint)(CAL_AdventureStartDate.Value - new DateTime(2000, 1, 1)).TotalSeconds; - seconds -= seconds%86400; - seconds += (uint)(CAL_AdventureStartTime.Value - new DateTime(2000, 1, 1)).TotalSeconds; - SAV.SecondsToStart = seconds; - - uint fame = (uint)(CAL_HoFDate.Value - new DateTime(2000, 1, 1)).TotalSeconds; - fame -= fame % 86400; - fame += (uint)(CAL_HoFTime.Value - new DateTime(2000, 1, 1)).TotalSeconds; - SAV.SecondsToFame = fame; + SAV.SecondsToStart = (uint)Util.GetSecondsFrom2000(CAL_AdventureStartDate.Value, CAL_AdventureStartTime.Value); + SAV.SecondsToFame = (uint)Util.GetSecondsFrom2000(CAL_HoFDate.Value, CAL_HoFTime.Value); if (SAV.Played.LastSavedDate.HasValue) SAV.Played.LastSavedDate = new DateTime(CAL_LastSavedDate.Value.Year, CAL_LastSavedDate.Value.Month, CAL_LastSavedDate.Value.Day, CAL_LastSavedTime.Value.Hour, CAL_LastSavedTime.Value.Minute, 0); @@ -360,8 +357,10 @@ private void Change255(object sender, EventArgs e) private void ChangeFFFF(object sender, EventArgs e) { MaskedTextBox box = (MaskedTextBox)sender; - if (box.Text.Length == 0) box.Text = "0"; - if (Util.ToInt32(box.Text) > 65535) box.Text = "65535"; + if (box.Text.Length == 0) + box.Text = "0"; + else if (Util.ToInt32(box.Text) > 65535) + box.Text = "65535"; } private void GiveAllAccessories(object sender, EventArgs e) @@ -401,26 +400,11 @@ private string UpdateTip(int index) switch (index) { case 2: // Storyline Completed Time - var epoch = new DateTime(2000, 1, 1); - int seconds = (int)(CAL_AdventureStartDate.Value - epoch).TotalSeconds; - seconds -= seconds % 86400; - seconds += (int)(CAL_AdventureStartTime.Value - epoch).TotalSeconds; - return ConvertDateValueToString(SAV.GetRecord(index), seconds); + var seconds = Util.GetSecondsFrom2000(CAL_AdventureStartDate.Value, CAL_AdventureStartTime.Value); + return Util.ConvertDateValueToString(SAV.GetRecord(index), seconds); default: return null; } } - - private static string ConvertDateValueToString(int value, int secondsBias = -1) - { - const int spd = 86400; // seconds per day - string tip = string.Empty; - if (value >= spd) - tip += (value / spd) + "d "; - tip += new DateTime(0).AddSeconds(value).ToString("HH:mm:ss"); - if (secondsBias >= 0) - tip += Environment.NewLine + $"Date: {new DateTime(2000, 1, 1).AddSeconds(value + secondsBias)}"; - return tip; - } } } \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs index 7e9c6a885..f88ea8184 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen7/SAV_Trainer7.cs @@ -111,13 +111,13 @@ private void GetTextBoxes() CB_Region.SelectedValue = SAV.SubRegion; CB_3DSReg.SelectedValue = SAV.ConsoleRegion; CB_Language.SelectedValue = SAV.Language; - var time = SAV.GameTime.AlolaTime; - if (time == 0) - time = 24 * 60 * 60; // Patch up any bad times from previous program versions. - if (time == 9_999_999) + var timeA = SAV.GameTime.AlolaTime; + if (timeA == 0) + timeA = 24 * 60 * 60; // Patch up any bad times from previous program versions. + if (timeA == 9_999_999) CB_AlolaTime.Enabled = false; // alola time doesn't exist yet else - CB_AlolaTime.SelectedValue = (int)time; + CB_AlolaTime.SelectedValue = (int)timeA; if (CB_AlolaTime.SelectedValue == null) CB_AlolaTime.Enabled = false; @@ -147,11 +147,13 @@ private void GetTextBoxes() L_LastSaved.Visible = CAL_LastSavedDate.Visible = CAL_LastSavedTime.Visible = false; } - var epoch = new DateTime(2000, 1, 1); - CAL_AdventureStartDate.Value = epoch.AddSeconds(SAV.SecondsToStart); - CAL_AdventureStartTime.Value = epoch.AddSeconds(SAV.SecondsToStart % 86400); - CAL_HoFDate.Value = epoch.AddSeconds(SAV.SecondsToFame); - CAL_HoFTime.Value = epoch.AddSeconds(SAV.SecondsToFame % 86400); + Util.GetDateTime2000(SAV.SecondsToStart, out var date, out var time); + CAL_AdventureStartDate.Value = date; + CAL_AdventureStartTime.Value = time; + + Util.GetDateTime2000(SAV.SecondsToStart, out date, out time); + CAL_HoFDate.Value = date; + CAL_HoFTime.Value = time; NUD_BP.Value = Math.Min(NUD_BP.Maximum, SAV.MiscBlock.BP); NUD_FC.Value = Math.Min(NUD_FC.Maximum, SAV.Festa.FestaCoins); @@ -349,16 +351,8 @@ private void SaveTrainerInfo() SAV.PlayedMinutes = ushort.Parse(MT_Minutes.Text)%60; SAV.PlayedSeconds = ushort.Parse(MT_Seconds.Text)%60; - var epoch = new DateTime(2000, 1, 1); - uint seconds = (uint)(CAL_AdventureStartDate.Value - epoch).TotalSeconds; - seconds -= seconds%86400; - seconds += (uint)(CAL_AdventureStartTime.Value - epoch).TotalSeconds; - SAV.SecondsToStart = seconds; - - uint fame = (uint)(CAL_HoFDate.Value - epoch).TotalSeconds; - fame -= fame % 86400; - fame += (uint)(CAL_HoFTime.Value - epoch).TotalSeconds; - SAV.SecondsToFame = fame; + SAV.SecondsToStart = (uint)Util.GetSecondsFrom2000(CAL_AdventureStartDate.Value, CAL_AdventureStartTime.Value); + SAV.SecondsToFame = (uint)Util.GetSecondsFrom2000(CAL_HoFDate.Value, CAL_HoFTime.Value); if (SAV.Played.LastSavedDate.HasValue) SAV.Played.LastSavedDate = new DateTime(CAL_LastSavedDate.Value.Year, CAL_LastSavedDate.Value.Month, CAL_LastSavedDate.Value.Day, CAL_LastSavedTime.Value.Hour, CAL_LastSavedTime.Value.Minute, 0); @@ -505,13 +499,6 @@ private void Change255(object sender, EventArgs e) if (Util.ToInt32(box.Text) > 255) box.Text = "255"; } - private void ChangeFFFF(object sender, EventArgs e) - { - MaskedTextBox box = (MaskedTextBox)sender; - if (box.Text.Length == 0) box.Text = "0"; - if (Util.ToInt32(box.Text) > 65535) box.Text = "65535"; - } - private void ChangeMapValue(object sender, EventArgs e) { if (!Loading) @@ -535,35 +522,25 @@ private void B_Fashion_Click(object sender, EventArgs e) SAV.FashionBlock.Clear(); // Write Payload - // Every fashion item is 2 bits, New Flag (high) & Owned Flag (low) switch (CB_Fashion.SelectedIndex) { case 0: // Base Fashion { - var list = SAV is SAV7USUM - ? (SAV.Gender == 0 - ? new[] {0x03A, 0x109, 0x1DA, 0x305, 0x3D9, 0x4B1, 0x584} // M - : new[] {0x05E, 0x208, 0x264, 0x395, 0x3B4, 0x4F9, 0x5A8}) // F - : (SAV.Gender == 0 - ? new[] {0x000, 0x0FB, 0x124, 0x28F, 0x3B4, 0x452, 0x517} // M - : new[] {0x000, 0x100, 0x223, 0x288, 0x3B4, 0x452, 0x517}); // F - - foreach (var ofs in list) - SAV.Data[SAV.Fashion + ofs] = 3; + SAV.FashionBlock.Reset(); break; } case 1: // Full Legal byte[] data1 = SAV is SAV7USUM ? SAV.Gender == 0 ? Properties.Resources.fashion_m_uu : Properties.Resources.fashion_f_uu : SAV.Gender == 0 ? Properties.Resources.fashion_m_sm : Properties.Resources.fashion_f_sm; - data1.CopyTo(SAV.Data, SAV.Fashion); + SAV.SetData(data1, SAV.Fashion); break; case 2: // Everything byte[] data2 = SAV is SAV7USUM ? SAV.Gender == 0 ? Properties.Resources.fashion_m_uu_illegal : Properties.Resources.fashion_f_uu_illegal : SAV.Gender == 0 ? Properties.Resources.fashion_m_sm_illegal : Properties.Resources.fashion_f_sm_illegal; - data2.CopyTo(SAV.Data, SAV.Fashion); + SAV.SetData(data2, SAV.Fashion); break; default: return; @@ -576,27 +553,13 @@ private string UpdateTip(int index) switch (index) { case 2: // Storyline Completed Time - int seconds = (int)(CAL_AdventureStartDate.Value - new DateTime(2000, 1, 1)).TotalSeconds; - seconds -= seconds % 86400; - seconds += (int)(CAL_AdventureStartTime.Value - new DateTime(2000, 1, 1)).TotalSeconds; - return ConvertDateValueToString(SAV.GetRecord(index), seconds); + var seconds = Util.GetSecondsFrom2000(CAL_AdventureStartDate.Value, CAL_AdventureStartTime.Value); + return Util.ConvertDateValueToString(SAV.GetRecord(index), seconds); default: return null; } } - private static string ConvertDateValueToString(int value, int secondsBias = -1) - { - const int spd = 86400; // seconds per day - string tip = string.Empty; - if (value >= spd) - tip += (value / spd) + "d "; - tip += new DateTime(0).AddSeconds(value).ToString("HH:mm:ss"); - if (secondsBias >= 0) - tip += Environment.NewLine + $"Date: {new DateTime(2000, 1, 1).AddSeconds(value + secondsBias)}"; - return tip; - } - private void UpdateBattleStyle(object sender, EventArgs e) { if (CB_BallThrowTypeListMode.SelectedIndex == 0) diff --git a/PKHeX.WinForms/Subforms/Save Editors/SAV_SimpleTrainer.cs b/PKHeX.WinForms/Subforms/Save Editors/SAV_SimpleTrainer.cs index 64f83df8d..dd6d0fb35 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/SAV_SimpleTrainer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/SAV_SimpleTrainer.cs @@ -151,10 +151,13 @@ public SAV_SimpleTrainer(SaveFile sav) cba[i].Checked = (badgeval & 1 << i) != 0; } - CAL_HoFDate.Value = new DateTime(2000, 1, 1).AddSeconds(SAV.SecondsToFame); - CAL_HoFTime.Value = new DateTime(2000, 1, 1).AddSeconds(SAV.SecondsToFame % 86400); - CAL_AdventureStartDate.Value = new DateTime(2000, 1, 1).AddSeconds(SAV.SecondsToStart); - CAL_AdventureStartTime.Value = new DateTime(2000, 1, 1).AddSeconds(SAV.SecondsToStart % 86400); + Util.GetDateTime2000(SAV.SecondsToStart, out var date, out var time); + CAL_AdventureStartDate.Value = date; + CAL_AdventureStartTime.Value = time; + + Util.GetDateTime2000(SAV.SecondsToStart, out date, out time); + CAL_HoFDate.Value = date; + CAL_HoFTime.Value = time; Loading = false; } @@ -252,8 +255,8 @@ private void B_Save_Click(object sender, EventArgs e) s.BattleSubwayBlock.BP = (ushort)Math.Min(Util.ToUInt32(MT_Coins.Text), SAV.MaxCoins); } - SAV.SecondsToStart = GetSeconds(CAL_AdventureStartDate, CAL_AdventureStartTime); - SAV.SecondsToFame = GetSeconds(CAL_HoFDate, CAL_HoFTime); + SAV.SecondsToStart = (uint)Util.GetSecondsFrom2000(CAL_AdventureStartDate.Value, CAL_AdventureStartTime.Value); + SAV.SecondsToFame = (uint)Util.GetSecondsFrom2000(CAL_HoFDate.Value, CAL_HoFTime.Value); Origin.CopyChangesFrom(SAV); Close(); @@ -264,15 +267,6 @@ private void B_Cancel_Click(object sender, EventArgs e) Close(); } - private static uint GetSeconds(DateTimePicker date, DateTimePicker time) - { - var epoch = new DateTime(2000, 1, 1); - uint val = (uint)(date.Value - epoch).TotalSeconds; - val -= val % 86400; - val += (uint)(time.Value - epoch).TotalSeconds; - return val; - } - private void ChangeMapValue(object sender, EventArgs e) { if (!Loading)