Add GUI For XY Roamer (#4056)

* Add GUI For XY Roamer

* Account For Roamer Not Set In XY
This commit is contained in:
Jonathan Herbert 2023-11-09 03:33:02 -04:00 committed by GitHub
parent 3df5478d11
commit 1f6d2de891
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 234 additions and 20 deletions

View file

@ -19,16 +19,16 @@ public sealed class Encount6 : SaveBlock<SAV6>
public PokeRadar6 Radar
{
get => new(Data.Slice(Offset + 0x04, PokeRadar6.SIZE));
set => value.Data.CopyTo(Data, Offset + 0x04);
get => new(Data.AsMemory(Offset + 0x04, PokeRadar6.SIZE));
set => value.Data.CopyTo(Data.AsMemory(Offset + 0x04));
}
// 0x1C
public Roamer6 Roamer
{
get => new(Data.Slice(Offset + 0x1C, Roamer6.SIZE));
set => value.Data.CopyTo(Data, Offset + 0x1C);
get => new(Data.AsMemory(Offset + 0x1C, Roamer6.SIZE));
set => value.Data.CopyTo(Data.AsMemory(Offset + 0x1C, Roamer6.SIZE));
}
// 0x44
@ -44,20 +44,21 @@ public sealed class PokeRadar6
private const int MaxCharge = 50;
private const int RecordCount = 5;
public readonly byte[] Data;
public readonly Memory<byte> Data;
private Span<byte> Span => Data.Span;
public PokeRadar6(byte[] data) => Data = data;
public PokeRadar6(Memory<byte> data) => Data = data;
public override string ToString() => ((Species)PokeRadarSpecies).ToString();
public ushort PokeRadarSpecies { get => ReadUInt16LittleEndian(Data.AsSpan(0x00)); set => WriteUInt16LittleEndian(Data.AsSpan(0x00), value); }
private ushort PokeRadarPacked { get => ReadUInt16LittleEndian(Data.AsSpan(0x02)); set => WriteUInt16LittleEndian(Data.AsSpan(0x02), value); }
public ushort PokeRadarSpecies { get => ReadUInt16LittleEndian(Span[0..2]); set => WriteUInt16LittleEndian(Span[0..2], value); }
private ushort PokeRadarPacked { get => ReadUInt16LittleEndian(Span[2..4]); set => WriteUInt16LittleEndian(Span[2..4], value); }
public int PokeRadarCharge { get => PokeRadarPacked & 0x3FFF; set => PokeRadarPacked = (ushort)((PokeRadarPacked & ~0x3FFF) | Math.Min(MaxCharge, value)); }
public bool PokeRadarFlag1 { get => PokeRadarPacked >> 14 != 0; set => PokeRadarPacked = (ushort)((PokeRadarPacked & ~(1 << 14)) | (value ? (1 << 14) : 0)); }
public bool PokeRadarFlag2 { get => PokeRadarPacked >> 15 != 0; set => PokeRadarPacked = (ushort)((PokeRadarPacked & ~(1 << 15)) | (value ? (1 << 15) : 0)); }
public PokeRadarRecord GetRecord(int index) => PokeRadarRecord.ReadRecord(Data.AsSpan(GetRecordOffset(index)));
public void SetRecord(PokeRadarRecord record, int index) => record.WriteRecord(Data.AsSpan(GetRecordOffset(index)));
public PokeRadarRecord GetRecord(int index) => PokeRadarRecord.ReadRecord(Span[GetRecordOffset(index)..]);
public void SetRecord(PokeRadarRecord record, int index) => record.WriteRecord(Span[GetRecordOffset(index)..]);
private static int GetRecordOffset(int index)
{
@ -108,21 +109,22 @@ public sealed class Roamer6
{
public const int SIZE = 0x28;
public readonly byte[] Data;
public readonly Memory<byte> Data;
private Span<byte> Span => Data.Span;
public Roamer6(byte[] data) => Data = data;
public Roamer6(Memory<byte> data) => Data = data;
public override string ToString() => ((Species)Species).ToString();
private ushort SpecForm { get => ReadUInt16LittleEndian(Data.AsSpan(0x00)); set => WriteUInt16LittleEndian(Data.AsSpan(0x00), value); }
private ushort SpecForm { get => ReadUInt16LittleEndian(Span[0..2]); set => WriteUInt16LittleEndian(Span[0..2], value); }
public ushort Species { get => (ushort)(SpecForm & 0x3FF); set => SpecForm = (ushort)((SpecForm & ~0x3FF) | (value & 0x3FF)); }
public bool Flag1 { get => SpecForm >> 14 != 0; set => SpecForm = (ushort)((SpecForm & 0xBFFF) | (value ? (1 << 14) : 0)); }
public bool Flag2 { get => SpecForm >> 15 != 0; set => SpecForm = (ushort)((SpecForm & 0x7FFF) | (value ? (1 << 15) : 0)); }
public int CurrentLevel { get => Data[0x04]; set => Data[0x04] = (byte)value; }
private int Status { get => Data[0x07]; set => Data[0x07] = (byte)value; }
public int CurrentLevel { get => Span[4]; set => Span[4] = (byte)value; }
private int Status { get => Span[7]; set => Span[7] = (byte)value; }
public Roamer6State RoamStatus { get => (Roamer6State)((Status >> 4) & 0xF); set => Status = (Status & 0x0F) | (((int)value << 4) & 0xF0); }
public uint TimesEncountered { get => ReadUInt32LittleEndian(Data.AsSpan(0x24)); set => WriteUInt32LittleEndian(Data.AsSpan(0x24), value); }
public uint TimesEncountered { get => ReadUInt32LittleEndian(Span[36..40]); set => WriteUInt32LittleEndian(Span[36..40], value); }
}
public enum Roamer6State

View file

@ -510,7 +510,6 @@ public partial class SAVEditor : UserControl, ISlotViewer<PictureBox>, ISaveFile
private void B_OpenSecretBase_Click(object sender, EventArgs e) => OpenDialog(new SAV_SecretBase(SAV));
private void B_CellsStickers_Click(object sender, EventArgs e) => OpenDialog(new SAV_ZygardeCell(SAV));
private void B_LinkInfo_Click(object sender, EventArgs e) => OpenDialog(new SAV_Link6(SAV));
private void B_Roamer_Click(object sender, EventArgs e) => OpenDialog(new SAV_Roamer3(SAV));
private void B_OpenApricorn_Click(object sender, EventArgs e) => OpenDialog(new SAV_Apricorn((SAV4HGSS)SAV));
private void B_CGearSkin_Click(object sender, EventArgs e) => OpenDialog(new SAV_CGearSkin(SAV));
private void B_OpenTrainerInfo_Click(object sender, EventArgs e) => OpenDialog(GetTrainerEditor(SAV));
@ -519,6 +518,14 @@ public partial class SAVEditor : UserControl, ISlotViewer<PictureBox>, ISaveFile
private void B_OpenGeonetEditor_Click(object sender, EventArgs e) => OpenDialog(new SAV_Geonet4((SAV4)SAV));
private void B_OpenUnityTowerEditor_Click(object sender, EventArgs e) => OpenDialog(new SAV_UnityTower((SAV5)SAV));
private void B_Roamer_Click(object sender, EventArgs e)
{
if (SAV is SAV3 s3)
OpenDialog(new SAV_Roamer3(s3));
else if (SAV is SAV6XY xy)
OpenDialog(new SAV_Roamer6(xy));
}
private void B_OpenEventFlags_Click(object sender, EventArgs e)
{
using var form = SAV switch
@ -1129,7 +1136,7 @@ public partial class SAVEditor : UserControl, ISlotViewer<PictureBox>, ISaveFile
B_OtherSlots.Visible = sav is SAV1StadiumJ or SAV1Stadium or SAV2Stadium;
B_OpenTrainerInfo.Visible = B_OpenItemPouch.Visible = (sav.HasParty && SAV is not SAV4BR) || SAV is SAV7b; // Box RS & Battle Revolution
B_OpenMiscEditor.Visible = sav is SAV3 or SAV4 or SAV5 or SAV8BS;
B_Roamer.Visible = sav is SAV3;
B_Roamer.Visible = sav is SAV3 or SAV6XY;
B_OpenHoneyTreeEditor.Visible = sav is SAV4Sinnoh;
B_OpenUGSEditor.Visible = sav is SAV4Sinnoh or SAV8BS;

View file

@ -8,11 +8,11 @@ public partial class SAV_Roamer3 : Form
{
private readonly Roamer3 Reader;
public SAV_Roamer3(SaveFile sav)
public SAV_Roamer3(SAV3 sav)
{
InitializeComponent();
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
Reader = new Roamer3((SAV3)sav);
Reader = new Roamer3(sav);
CB_Species.InitializeBinding();
CB_Species.DataSource = new BindingSource(GameInfo.FilteredSources.Species, null);

View file

@ -0,0 +1,151 @@
namespace PKHeX.WinForms
{
partial class SAV_Roamer6
{
/// <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()
{
L_Species = new System.Windows.Forms.Label();
CB_Species = new System.Windows.Forms.ComboBox();
L_TimesEncountered = new System.Windows.Forms.Label();
NUD_TimesEncountered = new System.Windows.Forms.NumericUpDown();
L_RoamState = new System.Windows.Forms.Label();
CB_RoamState = new System.Windows.Forms.ComboBox();
B_Cancel = new System.Windows.Forms.Button();
B_Save = new System.Windows.Forms.Button();
((System.ComponentModel.ISupportInitialize)NUD_TimesEncountered).BeginInit();
SuspendLayout();
//
// L_Species
//
L_Species.AutoSize = true;
L_Species.Location = new System.Drawing.Point(15, 10);
L_Species.Name = "L_Species";
L_Species.Size = new System.Drawing.Size(48, 15);
L_Species.TabIndex = 0;
L_Species.Text = "Roamer";
//
// CB_Species
//
CB_Species.FormattingEnabled = true;
CB_Species.Location = new System.Drawing.Point(15, 30);
CB_Species.Name = "CB_Species";
CB_Species.Size = new System.Drawing.Size(121, 23);
CB_Species.TabIndex = 1;
CB_Species.SelectedIndexChanged += CB_Species_SelectedIndexChanged;
//
// L_TimesEncountered
//
L_TimesEncountered.AutoSize = true;
L_TimesEncountered.Location = new System.Drawing.Point(150, 10);
L_TimesEncountered.Name = "L_TimesEncountered";
L_TimesEncountered.Size = new System.Drawing.Size(108, 15);
L_TimesEncountered.TabIndex = 2;
L_TimesEncountered.Text = "Times Encountered";
//
// NUD_TimesEncountered
//
NUD_TimesEncountered.Location = new System.Drawing.Point(150, 30);
NUD_TimesEncountered.Maximum = new decimal(new int[] { 11, 0, 0, 0 });
NUD_TimesEncountered.Name = "NUD_TimesEncountered";
NUD_TimesEncountered.Size = new System.Drawing.Size(120, 23);
NUD_TimesEncountered.TabIndex = 3;
NUD_TimesEncountered.ValueChanged += NUD_TimesEncountered_ValueChanged;
//
// L_RoamState
//
L_RoamState.AutoSize = true;
L_RoamState.Location = new System.Drawing.Point(280, 10);
L_RoamState.Name = "L_RoamState";
L_RoamState.Size = new System.Drawing.Size(67, 15);
L_RoamState.TabIndex = 4;
L_RoamState.Text = "Roam State";
//
// CB_RoamState
//
CB_RoamState.FormattingEnabled = true;
CB_RoamState.Location = new System.Drawing.Point(280, 30);
CB_RoamState.Name = "CB_RoamState";
CB_RoamState.Size = new System.Drawing.Size(121, 23);
CB_RoamState.TabIndex = 5;
CB_RoamState.SelectedIndexChanged += CB_RoamState_SelectedIndexChanged;
//
// B_Cancel
//
B_Cancel.Location = new System.Drawing.Point(245, 66);
B_Cancel.Name = "B_Cancel";
B_Cancel.Size = new System.Drawing.Size(75, 23);
B_Cancel.TabIndex = 6;
B_Cancel.Text = "Cancel";
B_Cancel.UseVisualStyleBackColor = true;
B_Cancel.Click += B_Cancel_Click;
//
// B_Save
//
B_Save.Location = new System.Drawing.Point(326, 66);
B_Save.Name = "B_Save";
B_Save.Size = new System.Drawing.Size(75, 23);
B_Save.TabIndex = 7;
B_Save.Text = "Save";
B_Save.UseVisualStyleBackColor = true;
B_Save.Click += B_Save_Click;
//
// SAV_Roamer6
//
AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
ClientSize = new System.Drawing.Size(414, 101);
Controls.Add(B_Save);
Controls.Add(B_Cancel);
Controls.Add(CB_RoamState);
Controls.Add(L_RoamState);
Controls.Add(NUD_TimesEncountered);
Controls.Add(L_TimesEncountered);
Controls.Add(CB_Species);
Controls.Add(L_Species);
Icon = Properties.Resources.Icon;
Margin = new System.Windows.Forms.Padding(4, 3, 4, 3);
MaximizeBox = false;
MinimizeBox = false;
Name = "SAV_Roamer6";
Text = "Roamer Editor";
((System.ComponentModel.ISupportInitialize)NUD_TimesEncountered).EndInit();
ResumeLayout(false);
PerformLayout();
}
#endregion
private System.Windows.Forms.Label L_Species;
private System.Windows.Forms.ComboBox CB_Species;
private System.Windows.Forms.Label L_TimesEncountered;
private System.Windows.Forms.NumericUpDown NUD_TimesEncountered;
private System.Windows.Forms.Label L_RoamState;
private System.Windows.Forms.ComboBox CB_RoamState;
private System.Windows.Forms.Button B_Cancel;
private System.Windows.Forms.Button B_Save;
}
}

View file

@ -0,0 +1,54 @@
using PKHeX.Core;
using System;
using System.Windows.Forms;
namespace PKHeX.WinForms;
public partial class SAV_Roamer6 : Form
{
private const int SpeciesOffset = 144;
private const int StarterChoiceIndex = 48;
private readonly SAV6XY Origin;
private readonly SAV6XY SAV;
private readonly Roamer6 roamer;
public SAV_Roamer6(SAV6XY sav)
{
InitializeComponent();
WinFormsUtil.TranslateInterface(this, Main.CurrentLanguage);
SAV = (SAV6XY)(Origin = sav).Clone();
roamer = SAV.Encount.Roamer;
var species = GameInfo.Strings.specieslist;
var entries = new[] { species[(int)Species.Articuno], species[(int)Species.Zapdos], species[(int)Species.Moltres] };
var states = new[] { "Inactive", "Roaming", "Stationary", "Defeated", "Captured" };
CB_Species.Items.AddRange(entries);
CB_RoamState.Items.AddRange(states);
CB_Species.SelectedIndex = GetInitialIndex(sav);
NUD_TimesEncountered.Value = roamer.TimesEncountered;
CB_RoamState.SelectedIndex = (int)roamer.RoamStatus;
}
private int GetInitialIndex(SAV6XY sav)
{
if (roamer.Species != 0)
return roamer.Species - SpeciesOffset;
// Roamer Species is not set if the player hasn't beaten the league so derive the species from the starter choice
return sav.GetWork(StarterChoiceIndex);
}
private void CB_Species_SelectedIndexChanged(object sender, EventArgs e) => roamer.Species = (ushort)(SpeciesOffset + CB_Species.SelectedIndex);
private void NUD_TimesEncountered_ValueChanged(object sender, EventArgs e) => roamer.TimesEncountered = (uint)NUD_TimesEncountered.Value;
private void CB_RoamState_SelectedIndexChanged(object sender, EventArgs e) => roamer.RoamStatus = (Roamer6State)CB_RoamState.SelectedIndex;
private void B_Cancel_Click(object sender, EventArgs e) => Close();
private void B_Save_Click(object sender, EventArgs e)
{
Origin.CopyChangesFrom(SAV);
Close();
}
}