Add Misc pkm array viewer for Stadium saves

Readonly slots

Things could be expanded on to use interfaces and wrappers for a "SlotReference" and properties for readonly.

But that's kinda unnecessary
This commit is contained in:
Kurt
2020-10-03 18:22:29 -07:00
parent bca8a80b39
commit 816f24e3db
8 changed files with 380 additions and 41 deletions

View File

@@ -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<PK1>[] GetRegisteredTeams()
public SlotGroup[] GetRegisteredTeams()
{
var result = new BattleTeam<PK1>[TeamCount];
var result = new SlotGroup[TeamCount];
for (int i = 0; i < result.Length; i++)
result[i] = GetTeam(i);
return result;
}
public BattleTeam<PK1> GetTeam(int team)
public SlotGroup GetTeam(int team)
{
if ((uint)team >= TeamCount)
throw new ArgumentOutOfRangeException(nameof(team));
@@ -235,10 +239,10 @@ public BattleTeam<PK1> 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<PK1>(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<T> where T : PKM
{
public readonly string TeamName;
public readonly T[] Team;
public BattleTeam(string name, T[] team)
{
TeamName = name;
Team = team;
}
}
}

View File

@@ -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<PK1> 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<PK1> 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<PK1>(name, members);
return new SlotGroup(name, members);
}
private const int BoxSizeJ = 0x560;

View File

@@ -145,15 +145,15 @@ public static int GetTeamOffset(int team)
public static string GetTeamName(int team) => $"{(Stadium2TeamType)(team / TeamCountType)} {(team % 10) + 1}";
public BattleTeam<SK2>[] GetRegisteredTeams()
public SlotGroup[] GetRegisteredTeams()
{
var result = new BattleTeam<SK2>[TeamCount];
var result = new SlotGroup[TeamCount];
for (int i = 0; i < result.Length; i++)
result[i] = GetTeam(i);
return result;
}
public BattleTeam<SK2> GetTeam(int team)
public SlotGroup GetTeam(int team)
{
if ((uint)team >= TeamCount)
throw new ArgumentOutOfRangeException(nameof(team));
@@ -166,7 +166,7 @@ public BattleTeam<SK2> GetTeam(int team)
var rel = ofs + ListHeaderSizeTeam + (i * SIZE_STORED);
members[i] = (SK2)GetStoredSlot(Data, rel);
}
return new BattleTeam<SK2>(name, members);
return new SlotGroup(name, members);
}
private int BoxSize => Japanese ? BoxSizeJ : BoxSizeU;

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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<SlotGroup> g)
{
var form = WinFormsUtil.FirstFormOfType<SAV_GroupViewer>();
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;

View File

@@ -0,0 +1,128 @@
namespace PKHeX.WinForms
{
sealed partial class SAV_GroupViewer
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
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;
}
}

View File

@@ -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<SlotGroup> Groups;
private readonly SummaryPreviewer Preview = new SummaryPreviewer();
public int CurrentGroup { get; set; } = -1;
public SAV_GroupViewer(SaveFile sav, IPKMView view, IReadOnlyList<SlotGroup> 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<SlotGroup> 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<PictureBox>(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);
}
}