diff --git a/PKHeX.Core/Saves/SAV1Stadium.cs b/PKHeX.Core/Saves/SAV1Stadium.cs index 535054221..3c6ba0369 100644 --- a/PKHeX.Core/Saves/SAV1Stadium.cs +++ b/PKHeX.Core/Saves/SAV1Stadium.cs @@ -164,24 +164,28 @@ private int GetTeamOffsetU(int team) 1 => 0x0D80, // Nintendo Cup '97 2 => 0x1B00, // Nintendo Cup '98 3 => 0x2880, // Nintendo Cup '99 + 4 => 0x4000, // Petit Cup 5 => 0x4D80, // Pika Cup 6 => 0x5B00, // Prime Cup 7 => 0x6880, // Gym Leader Castle + 8 => 0x8000, // Vs. Mewtwo _ => throw new ArgumentOutOfRangeException(nameof(team)), }; private static int GetTeamTypeOffsetU(int team) => team switch { - 0 => 0x0000, // Anything Goes - 1 => 0x0D80, // Unused - 2 => 0x1B00, // Unused - 3 => 0x2880, // Poke Cup + 0 => 0x0000, + 1 => 0x0DC0, // Unused + 2 => 0x1B80, // Unused + 3 => 0x2940, // Poke Cup + 4 => 0x4000, // Petit Cup - 5 => 0x4D80, // Pika Cup - 6 => 0x5B00, // Prime Cup - 7 => 0x6880, // Gym Leader Castle + 5 => 0x4DC0, // Pika Cup + 6 => 0x5B80, // Prime Cup + 7 => 0x6940, // Gym Leader Castle + 8 => 0x8000, // Vs. Mewtwo _ => throw new ArgumentOutOfRangeException(nameof(team)), }; @@ -217,15 +221,15 @@ private string GetTeamTypeName(int type) }; } - public BattleTeam[] GetRegisteredTeams() + public SlotGroup[] GetRegisteredTeams() { - var result = new BattleTeam[TeamCount]; + var result = new SlotGroup[TeamCount]; for (int i = 0; i < result.Length; i++) result[i] = GetTeam(i); return result; } - public BattleTeam GetTeam(int team) + public SlotGroup GetTeam(int team) { if ((uint)team >= TeamCount) throw new ArgumentOutOfRangeException(nameof(team)); @@ -235,10 +239,10 @@ public BattleTeam GetTeam(int team) var ofs = GetTeamOffset(team); for (int i = 0; i < 6; i++) { - var rel = ofs + (i * SIZE_STORED); + var rel = ofs + ListHeaderSize + (i * SIZE_STORED); members[i] = (PK1)GetStoredSlot(Data, rel); } - return new BattleTeam(name, members); + return new SlotGroup(name, members); } private int BoxSize => Japanese ? BoxSizeJ : BoxSizeU; @@ -293,16 +297,4 @@ public enum Stadium1TeamType GymLeaderCastle = 7, VsMewtwo = 8, } - - public class BattleTeam where T : PKM - { - public readonly string TeamName; - public readonly T[] Team; - - public BattleTeam(string name, T[] team) - { - TeamName = name; - Team = team; - } - } } diff --git a/PKHeX.Core/Saves/SAV1StadiumJ.cs b/PKHeX.Core/Saves/SAV1StadiumJ.cs index 4c97c2316..5be4e50ee 100644 --- a/PKHeX.Core/Saves/SAV1StadiumJ.cs +++ b/PKHeX.Core/Saves/SAV1StadiumJ.cs @@ -130,12 +130,20 @@ public SAV1StadiumJ() : base(SaveUtil.SIZE_G1STAD) private const int ListHeaderSize = 0x14; private const int ListFooterSize = 6; // POKE + 2byte checksum - private const int TeamCount = 86; // todo + private const int TeamCount = 32; // todo private const int TeamSizeJ = 0x14 + (SIZE_PK1J * 6) + ListFooterSize; // 0x128 public static int GetTeamOffset(int team) => 0 + ListHeaderSize + (team * TeamSizeJ); public static string GetTeamName(int team) => $"Team {team + 1}"; - public BattleTeam GetTeam(int team) + public SlotGroup[] GetRegisteredTeams() + { + var result = new SlotGroup[TeamCount]; + for (int i = 0; i < result.Length; i++) + result[i] = GetTeam(i); + return result; + } + + public SlotGroup GetTeam(int team) { if ((uint)team >= TeamCount) throw new ArgumentOutOfRangeException(nameof(team)); @@ -145,10 +153,10 @@ public BattleTeam GetTeam(int team) var ofs = GetTeamOffset(team); for (int i = 0; i < 6; i++) { - var rel = ofs + (i * SIZE_STORED); + var rel = ofs + ListHeaderSize + (i * SIZE_STORED); members[i] = (PK1)GetStoredSlot(Data, rel); } - return new BattleTeam(name, members); + return new SlotGroup(name, members); } private const int BoxSizeJ = 0x560; diff --git a/PKHeX.Core/Saves/SAV2Stadium.cs b/PKHeX.Core/Saves/SAV2Stadium.cs index 44cba6046..aaf424f51 100644 --- a/PKHeX.Core/Saves/SAV2Stadium.cs +++ b/PKHeX.Core/Saves/SAV2Stadium.cs @@ -145,15 +145,15 @@ public static int GetTeamOffset(int team) public static string GetTeamName(int team) => $"{(Stadium2TeamType)(team / TeamCountType)} {(team % 10) + 1}"; - public BattleTeam[] GetRegisteredTeams() + public SlotGroup[] GetRegisteredTeams() { - var result = new BattleTeam[TeamCount]; + var result = new SlotGroup[TeamCount]; for (int i = 0; i < result.Length; i++) result[i] = GetTeam(i); return result; } - public BattleTeam GetTeam(int team) + public SlotGroup GetTeam(int team) { if ((uint)team >= TeamCount) throw new ArgumentOutOfRangeException(nameof(team)); @@ -166,7 +166,7 @@ public BattleTeam GetTeam(int team) var rel = ofs + ListHeaderSizeTeam + (i * SIZE_STORED); members[i] = (SK2)GetStoredSlot(Data, rel); } - return new BattleTeam(name, members); + return new SlotGroup(name, members); } private int BoxSize => Japanese ? BoxSizeJ : BoxSizeU; diff --git a/PKHeX.Core/Saves/Substructures/Misc/SlotGroup.cs b/PKHeX.Core/Saves/Substructures/Misc/SlotGroup.cs new file mode 100644 index 000000000..24764c26c --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Misc/SlotGroup.cs @@ -0,0 +1,14 @@ +namespace PKHeX.Core +{ + public class SlotGroup + { + public readonly string GroupName; + public readonly PKM[] Slots; + + public SlotGroup(string name, PKM[] slots) + { + GroupName = name; + Slots = slots; + } + } +} diff --git a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs index 0152b519b..4bd9390d6 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.Designer.cs @@ -82,6 +82,7 @@ private void InitializeComponent() this.B_MailBox = new System.Windows.Forms.Button(); this.B_OpenApricorn = new System.Windows.Forms.Button(); this.B_Raids = new System.Windows.Forms.Button(); + this.B_RaidArmor = new System.Windows.Forms.Button(); this.B_Blocks = new System.Windows.Forms.Button(); this.L_SaveSlot = new System.Windows.Forms.Label(); this.L_Secure2 = new System.Windows.Forms.Label(); @@ -93,7 +94,7 @@ private void InitializeComponent() this.TB_GameSync = new System.Windows.Forms.TextBox(); this.B_SaveBoxBin = new System.Windows.Forms.Button(); this.B_VerifyCHK = new System.Windows.Forms.Button(); - this.B_RaidArmor = new System.Windows.Forms.Button(); + this.B_OtherSlots = new System.Windows.Forms.Button(); this.tabBoxMulti.SuspendLayout(); this.Tab_Box.SuspendLayout(); this.Tab_PartyBattle.SuspendLayout(); @@ -405,6 +406,7 @@ private void InitializeComponent() this.FLP_SAVtools.Controls.Add(this.B_Raids); this.FLP_SAVtools.Controls.Add(this.B_RaidArmor); this.FLP_SAVtools.Controls.Add(this.B_Blocks); + this.FLP_SAVtools.Controls.Add(this.B_OtherSlots); this.FLP_SAVtools.Dock = System.Windows.Forms.DockStyle.Fill; this.FLP_SAVtools.Location = new System.Drawing.Point(3, 16); this.FLP_SAVtools.Name = "FLP_SAVtools"; @@ -694,6 +696,16 @@ private void InitializeComponent() this.B_Raids.UseVisualStyleBackColor = true; this.B_Raids.Click += new System.EventHandler(this.B_OpenRaids_Click); // + // B_RaidArmor + // + this.B_RaidArmor.Location = new System.Drawing.Point(3, 206); + this.B_RaidArmor.Name = "B_RaidArmor"; + this.B_RaidArmor.Size = new System.Drawing.Size(87, 23); + this.B_RaidArmor.TabIndex = 2; + this.B_RaidArmor.Text = "Raids (DLC 1)"; + this.B_RaidArmor.UseVisualStyleBackColor = true; + this.B_RaidArmor.Click += new System.EventHandler(this.B_OpenRaids_Click); + // // B_Blocks // this.B_Blocks.Location = new System.Drawing.Point(96, 206); @@ -807,15 +819,15 @@ private void InitializeComponent() this.B_VerifyCHK.UseVisualStyleBackColor = true; this.B_VerifyCHK.Click += new System.EventHandler(this.ClickVerifyCHK); // - // B_RaidArmor + // B_OtherSlots // - this.B_RaidArmor.Location = new System.Drawing.Point(3, 206); - this.B_RaidArmor.Name = "B_RaidArmor"; - this.B_RaidArmor.Size = new System.Drawing.Size(87, 23); - this.B_RaidArmor.TabIndex = 2; - this.B_RaidArmor.Text = "Raids (DLC 1)"; - this.B_RaidArmor.UseVisualStyleBackColor = true; - this.B_RaidArmor.Click += new System.EventHandler(this.B_OpenRaids_Click); + this.B_OtherSlots.Location = new System.Drawing.Point(189, 206); + this.B_OtherSlots.Name = "B_OtherSlots"; + this.B_OtherSlots.Size = new System.Drawing.Size(87, 23); + this.B_OtherSlots.TabIndex = 3; + this.B_OtherSlots.Text = "Other Slots"; + this.B_OtherSlots.UseVisualStyleBackColor = true; + this.B_OtherSlots.Click += new System.EventHandler(this.B_OtherSlots_Click); // // SAVEditor // @@ -907,5 +919,6 @@ private void InitializeComponent() private System.Windows.Forms.Button B_Raids; private System.Windows.Forms.Button B_Blocks; private System.Windows.Forms.Button B_RaidArmor; + private System.Windows.Forms.Button B_OtherSlots; } } diff --git a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs index 859d67972..60fe3d40c 100644 --- a/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs +++ b/PKHeX.WinForms/Controls/SAV Editor/SAVEditor.cs @@ -619,6 +619,27 @@ private void B_OpenRaids_Click(object sender, EventArgs e) form.ShowDialog(); } + private void B_OtherSlots_Click(object sender, EventArgs e) + { + void TryOpen(SaveFile sav, IReadOnlyList g) + { + var form = WinFormsUtil.FirstFormOfType(); + if (form != null) + form.CenterToForm(ParentForm); + else + form = new SAV_GroupViewer(sav, M.Env.PKMEditor, g); + form.BringToFront(); + form.Show(); + } + + if (SAV is SAV1StadiumJ s0) + TryOpen(s0, s0.GetRegisteredTeams()); + else if (SAV is SAV1Stadium s1) + TryOpen(s1, s1.GetRegisteredTeams()); + else if (SAV is SAV2Stadium s2) + TryOpen(s2, s2.GetRegisteredTeams()); + } + private void B_Blocks_Click(object sender, EventArgs e) { var form = GetAccessorForm(SAV); @@ -1128,6 +1149,7 @@ private void ToggleViewSubEditors(SaveFile sav) B_CGearSkin.Enabled = sav.Generation == 5; B_OpenPokeBeans.Enabled = B_CellsStickers.Enabled = B_FestivalPlaza.Enabled = sav is SAV7; + B_OtherSlots.Enabled = sav is SAV1StadiumJ || sav is SAV1Stadium || sav is SAV2Stadium; B_OpenTrainerInfo.Enabled = B_OpenItemPouch.Enabled = (sav.HasParty && !(SAV is SAV4BR)) || SAV is SAV7b; // Box RS & Battle Revolution B_OpenMiscEditor.Enabled = sav is SAV3 || sav is SAV4 || sav is SAV5; B_Roamer.Enabled = sav is SAV3; diff --git a/PKHeX.WinForms/Subforms/Save Editors/SAV_GroupViewer.Designer.cs b/PKHeX.WinForms/Subforms/Save Editors/SAV_GroupViewer.Designer.cs new file mode 100644 index 000000000..319ae40e5 --- /dev/null +++ b/PKHeX.WinForms/Subforms/Save Editors/SAV_GroupViewer.Designer.cs @@ -0,0 +1,128 @@ +namespace PKHeX.WinForms +{ + sealed partial class SAV_GroupViewer + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.B_BoxRight = new System.Windows.Forms.Button(); + this.B_BoxLeft = new System.Windows.Forms.Button(); + this.CB_BoxSelect = new System.Windows.Forms.ComboBox(); + this.mnu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.mnuView = new System.Windows.Forms.ToolStripMenuItem(); + this.Box = new PKHeX.WinForms.Controls.PokeGrid(); + this.mnu.SuspendLayout(); + this.SuspendLayout(); + // + // B_BoxRight + // + this.B_BoxRight.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.B_BoxRight.Location = new System.Drawing.Point(194, 3); + this.B_BoxRight.Name = "B_BoxRight"; + this.B_BoxRight.Size = new System.Drawing.Size(27, 23); + this.B_BoxRight.TabIndex = 68; + this.B_BoxRight.Text = ">>"; + this.B_BoxRight.UseVisualStyleBackColor = true; + this.B_BoxRight.Click += new System.EventHandler(this.B_BoxRight_Click); + // + // B_BoxLeft + // + this.B_BoxLeft.FlatStyle = System.Windows.Forms.FlatStyle.System; + this.B_BoxLeft.Location = new System.Drawing.Point(28, 3); + this.B_BoxLeft.Name = "B_BoxLeft"; + this.B_BoxLeft.Size = new System.Drawing.Size(27, 23); + this.B_BoxLeft.TabIndex = 67; + this.B_BoxLeft.Text = "<<"; + this.B_BoxLeft.UseVisualStyleBackColor = true; + this.B_BoxLeft.Click += new System.EventHandler(this.B_BoxLeft_Click); + // + // CB_BoxSelect + // + this.CB_BoxSelect.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.CB_BoxSelect.FormattingEnabled = true; + this.CB_BoxSelect.Location = new System.Drawing.Point(61, 4); + this.CB_BoxSelect.Name = "CB_BoxSelect"; + this.CB_BoxSelect.Size = new System.Drawing.Size(127, 21); + this.CB_BoxSelect.TabIndex = 66; + this.CB_BoxSelect.SelectedIndexChanged += new System.EventHandler(this.CB_BoxSelect_SelectedIndexChanged); + // + // mnu + // + this.mnu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.mnuView}); + this.mnu.Name = "mnu"; + this.mnu.Size = new System.Drawing.Size(100, 26); + // + // mnuView + // + this.mnuView.Image = global::PKHeX.WinForms.Properties.Resources.other; + this.mnuView.Name = "mnuView"; + this.mnuView.Size = new System.Drawing.Size(99, 22); + this.mnuView.Text = "View"; + this.mnuView.Click += new System.EventHandler(this.ClickView); + // + // Box + // + this.Box.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch; + this.Box.Location = new System.Drawing.Point(0, 29); + this.Box.Margin = new System.Windows.Forms.Padding(0); + this.Box.Name = "Box"; + this.Box.Size = new System.Drawing.Size(249, 153); + this.Box.TabIndex = 0; + // + // SAV_GroupViewer + // + this.AllowDrop = true; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(250, 183); + this.Controls.Add(this.B_BoxRight); + this.Controls.Add(this.B_BoxLeft); + this.Controls.Add(this.CB_BoxSelect); + this.Controls.Add(this.Box); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + this.Icon = global::PKHeX.WinForms.Properties.Resources.Icon; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "SAV_GroupViewer"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Group Viewer"; + this.mnu.ResumeLayout(false); + this.ResumeLayout(false); + + } + + #endregion + + private Controls.PokeGrid Box; + public System.Windows.Forms.Button B_BoxRight; + public System.Windows.Forms.Button B_BoxLeft; + public System.Windows.Forms.ComboBox CB_BoxSelect; + private System.Windows.Forms.ContextMenuStrip mnu; + private System.Windows.Forms.ToolStripMenuItem mnuView; + } +} \ No newline at end of file diff --git a/PKHeX.WinForms/Subforms/Save Editors/SAV_GroupViewer.cs b/PKHeX.WinForms/Subforms/Save Editors/SAV_GroupViewer.cs new file mode 100644 index 000000000..b1ed2d0d5 --- /dev/null +++ b/PKHeX.WinForms/Subforms/Save Editors/SAV_GroupViewer.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using System.Windows.Forms; +using PKHeX.Core; +using PKHeX.Drawing; +using PKHeX.WinForms.Controls; + +namespace PKHeX.WinForms +{ + public sealed partial class SAV_GroupViewer : Form + { + private readonly SaveFile SAV; + private readonly IPKMView View; + private readonly IReadOnlyList Groups; + private readonly SummaryPreviewer Preview = new SummaryPreviewer(); + + public int CurrentGroup { get; set; } = -1; + + public SAV_GroupViewer(SaveFile sav, IPKMView view, IReadOnlyList groups) + { + SAV = sav; + View = view; + InitializeComponent(); + + Groups = groups; + int count = groups[0].Slots.Length; + Regenerate(count); + CenterToParent(); + + MouseWheel += (s, e) => CurrentGroup = e.Delta > 1 ? MoveLeft() : MoveRight(); + + var names = groups.Select(z => $"{z.GroupName}").ToArray(); + CB_BoxSelect.Items.AddRange(names); + CB_BoxSelect.SelectedIndex = GetFirstTeamWithContent(groups); + + foreach (PictureBox pb in Box.Entries) + { + pb.Click += OmniClick; + pb.MouseHover += HoverSlot; + pb.ContextMenuStrip = mnu; + } + } + + private void HoverSlot(object sender, EventArgs e) + { + var group = Groups[CurrentGroup]; + var pb = (PictureBox) sender; + var index = Box.Entries.IndexOf(pb); + var slot = group.Slots[index]; + Preview.Show(pb, slot); + } + + private void OmniClick(object sender, EventArgs e) + { + switch (ModifierKeys) + { + case Keys.Control: ClickView(sender, e); break; + default: + return; + } + } + + private static int GetFirstTeamWithContent(IReadOnlyList groups) + { + for (int i = 0; i < groups.Count; i++) + { + if (groups[i].Slots.Any(z => z.Species != 0)) + return i; + } + return 0; + } + + private void Regenerate(int count) + { + int deltaW = Width - Box.Width; + int deltaH = Height - Box.Height; + var height = count / 5; + var width = count / height; + bool changed = Box.InitializeGrid(width, height, SpriteUtil.Spriter); + if (!changed) + return; + + Width = Box.Width + deltaW + 2; + Height = Box.Height + deltaH + 2; + + RecenterControls(); + } + + private void RecenterControls() + { + if (Width < Box.Width) + Width = Box.Width; + Box.HorizontallyCenter(this); + Box.Location = new Point(Box.Location.X - 8, Box.Location.Y); // manual fudge + int p1 = CB_BoxSelect.Location.X; + CB_BoxSelect.HorizontallyCenter(this); + int p2 = CB_BoxSelect.Location.X; + if (p1 == p2) + return; + + B_BoxLeft.Location = new Point(B_BoxLeft.Location.X + p2 - p1, B_BoxLeft.Location.Y); + B_BoxRight.Location = new Point(B_BoxRight.Location.X + p2 - p1, B_BoxRight.Location.Y); + } + + private void LoadGroup(int index) + { + if (index == CurrentGroup) + return; + + var group = Groups[index]; + Regenerate(group.Slots.Length); + + var sav = SAV; + for (int i = 0; i < group.Slots.Length; i++) + Box.Entries[i].Image = group.Slots[i].Sprite(sav, -1, -1, true); + + if (groupSelected == index && slotSelected != -1 && (uint)slotSelected < Box.Entries.Count) + Box.Entries[slotSelected].BackgroundImage = null; + + CurrentGroup = index; + } + + public int MoveLeft(bool max = false) + { + int newBox = max ? 0 : (CurrentGroup + Groups.Count - 1) % Groups.Count; + LoadGroup(newBox); + return newBox; + } + + public int MoveRight(bool max = false) + { + int newBox = max ? Groups.Count - 1 : (CurrentGroup + 1) % Groups.Count; + LoadGroup(newBox); + return newBox; + } + + private int groupSelected = -1; + private int slotSelected = -1; + + private void ClickView(object sender, EventArgs e) + { + var pb = WinFormsUtil.GetUnderlyingControl(sender); + int index = Box.Entries.IndexOf(pb); + + var group = Groups[CurrentGroup]; + View.PopulateFields(group.Slots[index], false); + + if (slotSelected != index && (uint) slotSelected < Box.Entries.Count) + Box.Entries[slotSelected].BackgroundImage = null; + + groupSelected = CurrentGroup; + slotSelected = index; + Box.Entries[index].BackgroundImage = SpriteUtil.Spriter.View; + } + + private void B_BoxRight_Click(object sender, EventArgs e) => CB_BoxSelect.SelectedIndex = MoveRight((ModifierKeys & Keys.Control) != 0); + private void B_BoxLeft_Click(object sender, EventArgs e) => CB_BoxSelect.SelectedIndex = MoveLeft((ModifierKeys & Keys.Control) != 0); + private void CB_BoxSelect_SelectedIndexChanged(object sender, EventArgs e) => LoadGroup(CB_BoxSelect.SelectedIndex); + } +}