diff --git a/PKHeX.Core/Saves/Access/ISaveBlock8Main.cs b/PKHeX.Core/Saves/Access/ISaveBlock8Main.cs index 129ae59d2..b1b779549 100644 --- a/PKHeX.Core/Saves/Access/ISaveBlock8Main.cs +++ b/PKHeX.Core/Saves/Access/ISaveBlock8Main.cs @@ -14,5 +14,7 @@ Daycare8 Daycare { get; } Record8 Records { get; } TrainerCard8 TrainerCard { get; } + RaidSpawnList8 Raid { get; } + TitleScreen8 TitleScreen { get; } } } \ No newline at end of file diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessorSWSH.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessorSWSH.cs index aca390f9c..c2dd56973 100644 --- a/PKHeX.Core/Saves/Access/SaveBlockAccessorSWSH.cs +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessorSWSH.cs @@ -19,6 +19,7 @@ namespace PKHeX.Core public TrainerCard8 TrainerCard{ get; } public FashionUnlock8 Fashion { get; } public RaidSpawnList8 Raid { get; } + public TitleScreen8 TitleScreen { get; } public SaveBlockAccessorSWSH(SAV8SWSH sav) { @@ -37,6 +38,7 @@ namespace PKHeX.Core Records = new Record8(sav, GetBlock(KRecord), Core.Records.MaxType_SWSH); Fashion = new FashionUnlock8(sav, GetBlock(KFashionUnlock)); Raid = new RaidSpawnList8(sav, GetBlock(KRaidSpawnList)); + TitleScreen = new TitleScreen8(sav, GetBlock(KTitleScreenTeam)); } /* To dump key list of current format, use the following in the immediate window, and update Meta8 @@ -60,6 +62,7 @@ namespace PKHeX.Core private const uint KRaidSpawnList = 0x9033eb7b; // Nest current values (hash, seed, meta) private const uint KFused = 0xc0de5c5f; // Fused PKM (*3) private const uint KFashionUnlock = 0xd224f9ac; // Fashion unlock bool array (owned for (each apparel type) * 0x80, then another array for "new") + private const uint KTitleScreenTeam = 0xE9BE28BF; // Title Screen Team details private const uint KMyStatus = 0xf25c070e; // Trainer Details // Values diff --git a/PKHeX.Core/Saves/SAV8.cs b/PKHeX.Core/Saves/SAV8.cs index 04f18d139..eba2dc4ab 100644 --- a/PKHeX.Core/Saves/SAV8.cs +++ b/PKHeX.Core/Saves/SAV8.cs @@ -52,6 +52,8 @@ namespace PKHeX.Core public abstract Daycare8 Daycare { get; } public abstract Record8 Records { get; } public abstract TrainerCard8 TrainerCard { get; } + public abstract RaidSpawnList8 Raid { get; } + public abstract TitleScreen8 TitleScreen { get; } #endregion public override GameVersion Version diff --git a/PKHeX.Core/Saves/SAV8SWSH.cs b/PKHeX.Core/Saves/SAV8SWSH.cs index 478788129..15f2050f1 100644 --- a/PKHeX.Core/Saves/SAV8SWSH.cs +++ b/PKHeX.Core/Saves/SAV8SWSH.cs @@ -63,6 +63,8 @@ namespace PKHeX.Core public override Daycare8 Daycare => Blocks.Daycare; public override Record8 Records => Blocks.Records; public override TrainerCard8 TrainerCard => Blocks.TrainerCard; + public override RaidSpawnList8 Raid => Blocks.Raid; + public override TitleScreen8 TitleScreen => Blocks.TitleScreen; public object GetValue(uint key) => Blocks.GetBlockValue(key); diff --git a/PKHeX.Core/Saves/Substructures/Gen8/TitleScreen8.cs b/PKHeX.Core/Saves/Substructures/Gen8/TitleScreen8.cs new file mode 100644 index 000000000..086627c1a --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen8/TitleScreen8.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; + +namespace PKHeX.Core +{ + /// + /// Pokémon Team that shows up at the title screen. + /// + public sealed class TitleScreen8 : SaveBlock + { + public TitleScreen8(SAV8SWSH sav, SCBlock block) : base(sav, block.Data) { } + + /// + /// Gets an object that exposes the data of the corresponding party . + /// + public TitleScreen8Poke ViewPoke(int index) + { + if ((uint)index >= 6) + throw new ArgumentOutOfRangeException(nameof(index)); + return new TitleScreen8Poke(Data, Offset + 0x00 + (index * TitleScreen8Poke.SIZE)); + } + + /// + /// Applies the current to the block. + /// + public void SetPartyData() => LoadTeamData(SAV.PartyData); + + public void LoadTeamData(IList party) + { + for (int i = 0; i < party.Count; i++) + ViewPoke(i).LoadFrom(party[i]); + } + } + + public class TitleScreen8Poke + { + public const int SIZE = 0x28; + private readonly byte[] Data; + private readonly int Offset; + + public TitleScreen8Poke(byte[] data, int offset) + { + Data = data; + Offset = offset; + } + + public int Species + { + get => BitConverter.ToInt32(Data, Offset + 0x00); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x00); + } + + public int AltForm + { + get => BitConverter.ToInt32(Data, Offset + 0x04); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x04); + } + + public int Gender + { + get => BitConverter.ToInt32(Data, Offset + 0x08); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); + } + + public bool IsShiny + { + get => Data[Offset + 0xC] != 0; + set => Data[Offset + 0xC] = (byte)(value ? 1 : 0); + } + + public uint EncryptionConstant + { + get => BitConverter.ToUInt32(Data, Offset + 0x10); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x10); + } + + public int FormArgument + { + get => BitConverter.ToInt32(Data, Offset + 0x14); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x14); + } + + public uint Unknown18 + { + get => BitConverter.ToUInt32(Data, Offset + 0x18); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x18); + } + + public uint Unknown1C + { + get => BitConverter.ToUInt32(Data, Offset + 0x1C); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x1C); + } + + public uint Unknown20 + { + get => BitConverter.ToUInt32(Data, Offset + 0x20); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x20); + } + + public uint Unknown24 + { + get => BitConverter.ToUInt32(Data, Offset + 0x24); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x24); + } + + public void LoadFrom(PKM pkm) + { + Species = pkm.Species; + AltForm = pkm.AltForm; + Gender = pkm.Gender; + IsShiny = pkm.IsShiny; + EncryptionConstant = pkm.EncryptionConstant; + FormArgument = pkm is IFormArgument f && pkm.Species == (int)Core.Species.Alcremie ? (int)f.FormArgument : -1; + } + + public void LoadFrom(TrainerCard8Poke pkm) + { + Species = pkm.Species; + AltForm = pkm.AltForm; + Gender = pkm.Gender; + IsShiny = pkm.IsShiny; + EncryptionConstant = pkm.EncryptionConstant; + FormArgument = pkm.FormArgument; + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs b/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs index e71b741e0..fdff8e874 100644 --- a/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs +++ b/PKHeX.Core/Saves/Substructures/Gen8/TrainerCard8.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text; namespace PKHeX.Core @@ -45,5 +46,109 @@ namespace PKHeX.Core SAV.Edited = true; } } + + // Trainer Card Pokemon + // 0xC8 - 0xE3 (0x1C) + // 0xE4 + // 0x100 + // 0x11C + // 0x138 + // 0x154 - 0x16F + + /// + /// Gets an object that exposes the data of the corresponding party . + /// + public TrainerCard8Poke ViewPoke(int index) + { + if ((uint) index >= 6) + throw new ArgumentOutOfRangeException(nameof(index)); + return new TrainerCard8Poke(Data, Offset + 0xC8 + (index * TrainerCard8Poke.SIZE)); + } + + /// + /// Applies the current to the block. + /// + public void SetPartyData() => LoadTeamData(SAV.PartyData); + + public void LoadTeamData(IList party) + { + for (int i = 0; i < party.Count; i++) + ViewPoke(i).LoadFrom(party[i]); + } + } + + public class TrainerCard8Poke + { + public const int SIZE = 0x1C; + private readonly byte[] Data; + private readonly int Offset; + + public TrainerCard8Poke(byte[] data, int offset) + { + Data = data; + Offset = offset; + } + + public int Species + { + get => BitConverter.ToInt32(Data, Offset + 0x00); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x00); + } + + public int AltForm + { + get => BitConverter.ToInt32(Data, Offset + 0x04); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x04); + } + + public int Gender + { + get => BitConverter.ToInt32(Data, Offset + 0x08); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x08); + } + + public bool IsShiny + { + get => Data[Offset + 0xC] != 0; + set => Data[Offset + 0xC] = (byte) (value ? 1 : 0); + } + + public uint EncryptionConstant + { + get => BitConverter.ToUInt32(Data, Offset + 0x10); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x10); + } + + public uint Unknown + { + get => BitConverter.ToUInt32(Data, Offset + 0x14); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x14); + } + + public int FormArgument + { + get => BitConverter.ToInt32(Data, Offset + 0x18); + set => BitConverter.GetBytes(value).CopyTo(Data, Offset + 0x18); + } + + public void LoadFrom(PKM pkm) + { + Species = pkm.Species; + AltForm = pkm.AltForm; + Gender = pkm.Gender; + IsShiny = pkm.IsShiny; + EncryptionConstant = pkm.EncryptionConstant; + FormArgument = pkm is IFormArgument f && pkm.Species == (int) Core.Species.Alcremie ? (int)f.FormArgument : -1; + } + + public void LoadFrom(TitleScreen8Poke pkm) + { + Species = pkm.Species; + AltForm = pkm.AltForm; + Gender = pkm.Gender; + IsShiny = pkm.IsShiny; + EncryptionConstant = pkm.EncryptionConstant; + FormArgument = pkm.FormArgument; + } } } \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.Designer.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.Designer.cs index c853cc229..e392e25a5 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.Designer.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.Designer.cs @@ -139,6 +139,15 @@ this.L_BattleTowerWins = new System.Windows.Forms.Label(); this.L_Singles = new System.Windows.Forms.Label(); this.MT_BattleTowerSinglesWin = new System.Windows.Forms.MaskedTextBox(); + this.Tab_Team = new System.Windows.Forms.TabPage(); + this.NUD_ShowTrainerCard = new System.Windows.Forms.NumericUpDown(); + this.L_ShowTrainerCard = new System.Windows.Forms.Label(); + this.PG_ShowTrainerCard = new System.Windows.Forms.PropertyGrid(); + this.NUD_ShowTitleScreen = new System.Windows.Forms.NumericUpDown(); + this.L_ShowTitleScreen = new System.Windows.Forms.Label(); + this.PG_ShowTitleScreen = new System.Windows.Forms.PropertyGrid(); + this.B_CopyFromPartyToTitleScreen = new System.Windows.Forms.Button(); + this.B_CopyFromPartyToTrainerCard = new System.Windows.Forms.Button(); this.TC_Editor.SuspendLayout(); this.Tab_Overview.SuspendLayout(); this.GB_Stats.SuspendLayout(); @@ -153,6 +162,9 @@ ((System.ComponentModel.ISupportInitialize)(this.NUD_X)).BeginInit(); this.Tab_MiscValues.SuspendLayout(); this.GB_BattleTower.SuspendLayout(); + this.Tab_Team.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.NUD_ShowTrainerCard)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.NUD_ShowTitleScreen)).BeginInit(); this.SuspendLayout(); // // B_Cancel @@ -660,6 +672,7 @@ this.TC_Editor.Controls.Add(this.Tab_Overview); this.TC_Editor.Controls.Add(this.Tab_BadgeMap); this.TC_Editor.Controls.Add(this.Tab_MiscValues); + this.TC_Editor.Controls.Add(this.Tab_Team); this.TC_Editor.Location = new System.Drawing.Point(12, 12); this.TC_Editor.Name = "TC_Editor"; this.TC_Editor.SelectedIndex = 0; @@ -1235,6 +1248,126 @@ this.MT_BattleTowerSinglesWin.TabIndex = 76; this.MT_BattleTowerSinglesWin.TextAlign = System.Windows.Forms.HorizontalAlignment.Center; // + // Tab_Team + // + this.Tab_Team.Controls.Add(this.B_CopyFromPartyToTrainerCard); + this.Tab_Team.Controls.Add(this.B_CopyFromPartyToTitleScreen); + this.Tab_Team.Controls.Add(this.NUD_ShowTrainerCard); + this.Tab_Team.Controls.Add(this.L_ShowTrainerCard); + this.Tab_Team.Controls.Add(this.PG_ShowTrainerCard); + this.Tab_Team.Controls.Add(this.NUD_ShowTitleScreen); + this.Tab_Team.Controls.Add(this.L_ShowTitleScreen); + this.Tab_Team.Controls.Add(this.PG_ShowTitleScreen); + this.Tab_Team.Location = new System.Drawing.Point(4, 22); + this.Tab_Team.Name = "Tab_Team"; + this.Tab_Team.Padding = new System.Windows.Forms.Padding(3); + this.Tab_Team.Size = new System.Drawing.Size(430, 287); + this.Tab_Team.TabIndex = 5; + this.Tab_Team.Text = "Team"; + this.Tab_Team.UseVisualStyleBackColor = true; + // + // NUD_ShowTrainerCard + // + this.NUD_ShowTrainerCard.Location = new System.Drawing.Point(138, 9); + this.NUD_ShowTrainerCard.Maximum = new decimal(new int[] { + 6, + 0, + 0, + 0}); + this.NUD_ShowTrainerCard.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.NUD_ShowTrainerCard.Name = "NUD_ShowTrainerCard"; + this.NUD_ShowTrainerCard.Size = new System.Drawing.Size(65, 20); + this.NUD_ShowTrainerCard.TabIndex = 2; + this.NUD_ShowTrainerCard.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.NUD_ShowTrainerCard.ValueChanged += new System.EventHandler(this.ChangeTrainerCardIndex); + // + // L_ShowTrainerCard + // + this.L_ShowTrainerCard.AutoSize = true; + this.L_ShowTrainerCard.Location = new System.Drawing.Point(3, 11); + this.L_ShowTrainerCard.Name = "L_ShowTrainerCard"; + this.L_ShowTrainerCard.Size = new System.Drawing.Size(119, 13); + this.L_ShowTrainerCard.TabIndex = 1; + this.L_ShowTrainerCard.Text = "Shown on Trainer Card:"; + // + // PG_ShowTrainerCard + // + this.PG_ShowTrainerCard.HelpVisible = false; + this.PG_ShowTrainerCard.Location = new System.Drawing.Point(3, 30); + this.PG_ShowTrainerCard.Name = "PG_ShowTrainerCard"; + this.PG_ShowTrainerCard.Size = new System.Drawing.Size(200, 222); + this.PG_ShowTrainerCard.TabIndex = 3; + this.PG_ShowTrainerCard.ToolbarVisible = false; + // + // NUD_ShowTitleScreen + // + this.NUD_ShowTitleScreen.Location = new System.Drawing.Point(359, 9); + this.NUD_ShowTitleScreen.Maximum = new decimal(new int[] { + 6, + 0, + 0, + 0}); + this.NUD_ShowTitleScreen.Minimum = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.NUD_ShowTitleScreen.Name = "NUD_ShowTitleScreen"; + this.NUD_ShowTitleScreen.Size = new System.Drawing.Size(65, 20); + this.NUD_ShowTitleScreen.TabIndex = 6; + this.NUD_ShowTitleScreen.Value = new decimal(new int[] { + 1, + 0, + 0, + 0}); + this.NUD_ShowTitleScreen.ValueChanged += new System.EventHandler(this.ChangeTitleScreenIndex); + // + // L_ShowTitleScreen + // + this.L_ShowTitleScreen.AutoSize = true; + this.L_ShowTitleScreen.Location = new System.Drawing.Point(221, 11); + this.L_ShowTitleScreen.Name = "L_ShowTitleScreen"; + this.L_ShowTitleScreen.Size = new System.Drawing.Size(118, 13); + this.L_ShowTitleScreen.TabIndex = 5; + this.L_ShowTitleScreen.Text = "Shown on Title Screen:"; + // + // PG_ShowTitleScreen + // + this.PG_ShowTitleScreen.HelpVisible = false; + this.PG_ShowTitleScreen.Location = new System.Drawing.Point(224, 30); + this.PG_ShowTitleScreen.Name = "PG_ShowTitleScreen"; + this.PG_ShowTitleScreen.Size = new System.Drawing.Size(200, 222); + this.PG_ShowTitleScreen.TabIndex = 7; + this.PG_ShowTitleScreen.ToolbarVisible = false; + // + // B_CopyFromPartyToTitleScreen + // + this.B_CopyFromPartyToTitleScreen.Location = new System.Drawing.Point(309, 258); + this.B_CopyFromPartyToTitleScreen.Name = "B_CopyFromPartyToTitleScreen"; + this.B_CopyFromPartyToTitleScreen.Size = new System.Drawing.Size(115, 23); + this.B_CopyFromPartyToTitleScreen.TabIndex = 8; + this.B_CopyFromPartyToTitleScreen.Text = "Copy From Party"; + this.B_CopyFromPartyToTitleScreen.UseVisualStyleBackColor = true; + this.B_CopyFromPartyToTitleScreen.Click += new System.EventHandler(this.B_CopyFromPartyToTitleScreen_Click); + // + // B_CopyFromPartyToTrainerCard + // + this.B_CopyFromPartyToTrainerCard.Location = new System.Drawing.Point(88, 258); + this.B_CopyFromPartyToTrainerCard.Name = "B_CopyFromPartyToTrainerCard"; + this.B_CopyFromPartyToTrainerCard.Size = new System.Drawing.Size(115, 23); + this.B_CopyFromPartyToTrainerCard.TabIndex = 4; + this.B_CopyFromPartyToTrainerCard.Text = "Copy From Party"; + this.B_CopyFromPartyToTrainerCard.UseVisualStyleBackColor = true; + this.B_CopyFromPartyToTrainerCard.Click += new System.EventHandler(this.B_CopyFromPartyToTrainerCard_Click); + // // SAV_Trainer8 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -1267,6 +1400,10 @@ this.Tab_MiscValues.ResumeLayout(false); this.GB_BattleTower.ResumeLayout(false); this.GB_BattleTower.PerformLayout(); + this.Tab_Team.ResumeLayout(false); + this.Tab_Team.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.NUD_ShowTrainerCard)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.NUD_ShowTitleScreen)).EndInit(); this.ResumeLayout(false); } @@ -1384,5 +1521,14 @@ private System.Windows.Forms.Label L_BattleTowerWins; private System.Windows.Forms.Label L_Singles; private System.Windows.Forms.MaskedTextBox MT_BattleTowerSinglesWin; + private System.Windows.Forms.TabPage Tab_Team; + private System.Windows.Forms.Label L_ShowTitleScreen; + private System.Windows.Forms.PropertyGrid PG_ShowTitleScreen; + private System.Windows.Forms.NumericUpDown NUD_ShowTrainerCard; + private System.Windows.Forms.Label L_ShowTrainerCard; + private System.Windows.Forms.PropertyGrid PG_ShowTrainerCard; + private System.Windows.Forms.NumericUpDown NUD_ShowTitleScreen; + private System.Windows.Forms.Button B_CopyFromPartyToTrainerCard; + private System.Windows.Forms.Button B_CopyFromPartyToTitleScreen; } } \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.cs b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.cs index eea3835cb..0e9264cbc 100644 --- a/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.cs +++ b/PKHeX.WinForms/Subforms/Save Editors/Gen8/SAV_Trainer8.cs @@ -36,6 +36,9 @@ namespace PKHeX.WinForms TC_Editor.TabPages.Remove(Tab_BadgeMap); // needs more work + ChangeTitleScreenIndex(null, EventArgs.Empty); + ChangeTrainerCardIndex(null, EventArgs.Empty); + //Loading = false; } @@ -209,6 +212,32 @@ namespace PKHeX.WinForms // MapUpdated = true; } + private void ChangeTrainerCardIndex(object sender, EventArgs e) + { + var index = (int)NUD_ShowTrainerCard.Value - 1; + PG_ShowTrainerCard.SelectedObject = SAV.Blocks.TrainerCard.ViewPoke(index); + } + + private void ChangeTitleScreenIndex(object sender, EventArgs e) + { + var index = (int)NUD_ShowTitleScreen.Value - 1; + PG_ShowTitleScreen.SelectedObject = SAV.Blocks.TitleScreen.ViewPoke(index); + } + + private void B_CopyFromPartyToTrainerCard_Click(object sender, EventArgs e) + { + SAV.Blocks.TrainerCard.SetPartyData(); + System.Media.SystemSounds.Asterisk.Play(); + ChangeTrainerCardIndex(null, EventArgs.Empty); + } + + private void B_CopyFromPartyToTitleScreen_Click(object sender, EventArgs e) + { + SAV.Blocks.TitleScreen.SetPartyData(); + System.Media.SystemSounds.Asterisk.Play(); + ChangeTitleScreenIndex(null, EventArgs.Empty); + } + //private string UpdateTip(int index) //{ // switch (index)