mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 14:44:24 +00:00
Add gen5 trainer record edits
Refer to src (Record5) for indexes; documented a few. Closes #4245
This commit is contained in:
parent
9caab05aab
commit
2e62e41ab1
11 changed files with 234 additions and 4 deletions
|
@ -6,7 +6,7 @@
|
|||
リーフグリーン
|
||||
|
||||
ハートゴールド
|
||||
ソウルシルバー
|
||||
ソウルシルバー
|
||||
|
||||
ダイヤモンド
|
||||
パール
|
||||
|
|
|
@ -22,4 +22,5 @@ public interface ISaveBlock5BW
|
|||
GlobalLink5 GlobalLink { get; }
|
||||
GTS5 GTS { get; }
|
||||
AdventureInfo5 AdventureInfo { get; }
|
||||
Record5 Records { get; }
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ public sealed class SaveBlockAccessor5B2W2(SAV5B2W2 sav)
|
|||
public GlobalLink5 GlobalLink { get; } = new(sav, Block(sav, 35));
|
||||
public Chatter5 Chatter { get; } = new(sav, Block(sav, 36));
|
||||
public AdventureInfo5 AdventureInfo { get; } = new(sav, Block(sav, 37));
|
||||
public Record5 Records { get; } = new(sav, Block(sav, 38));
|
||||
public Musical5 Musical { get; } = new(sav, Block(sav, 42));
|
||||
public WhiteBlack5B2W2 Forest { get; } = new(sav, Block(sav, 43));
|
||||
public EventWork5B2W2 EventWork { get; } = new(sav, Block(sav, 45));
|
||||
|
|
|
@ -92,6 +92,7 @@ public sealed class SaveBlockAccessor5BW(SAV5BW sav) : ISaveBlockAccessor<BlockI
|
|||
public GlobalLink5 GlobalLink { get; } = new(sav, Block(sav, 35));
|
||||
public Chatter5 Chatter { get; } = new(sav, Block(sav, 36));
|
||||
public AdventureInfo5 AdventureInfo { get; } = new(sav, Block(sav, 37));
|
||||
public Record5 Records { get; } = new(sav, Block(sav, 38));
|
||||
public Musical5 Musical { get; } = new(sav, Block(sav, 42));
|
||||
public WhiteBlack5BW Forest { get; } = new(sav, Block(sav, 43));
|
||||
public EventWork5BW EventWork { get; } = new(sav, Block(sav, 45));
|
||||
|
|
|
@ -191,6 +191,7 @@ public abstract class SAV5 : SaveFile, ISaveBlock5BW, IEventFlagProvider37, IBox
|
|||
public abstract WhiteBlack5 Forest { get; }
|
||||
public abstract GTS5 GTS { get; }
|
||||
public abstract AdventureInfo5 AdventureInfo { get; }
|
||||
public abstract Record5 Records { get; }
|
||||
IEventFlag37 IEventFlagProvider37.EventWork => EventWork;
|
||||
|
||||
public abstract Memory<byte> BattleVideoNative { get; }
|
||||
|
|
|
@ -56,6 +56,7 @@ public sealed class SAV5B2W2 : SAV5, ISaveBlock5B2W2
|
|||
public override GTS5 GTS => Blocks.GTS;
|
||||
public override WhiteBlack5B2W2 Forest => Blocks.Forest;
|
||||
public override AdventureInfo5 AdventureInfo => Blocks.AdventureInfo;
|
||||
public override Record5 Records => Blocks.Records;
|
||||
|
||||
public FestaBlock5 Festa => Blocks.Festa;
|
||||
public PWTBlock5 PWT => Blocks.PWT;
|
||||
|
|
|
@ -56,6 +56,7 @@ public sealed class SAV5BW : SAV5
|
|||
public override GTS5 GTS => Blocks.GTS;
|
||||
public override WhiteBlack5BW Forest => Blocks.Forest;
|
||||
public override AdventureInfo5 AdventureInfo => Blocks.AdventureInfo;
|
||||
public override Record5 Records => Blocks.Records;
|
||||
|
||||
public override Memory<byte> BattleVideoNative => Data.AsMemory(0x4A000, BattleVideo5.SIZE_USED);
|
||||
public override Memory<byte> BattleVideoDownload1 => Data.AsMemory(0x4C000, BattleVideo5.SIZE_USED);
|
||||
|
|
|
@ -61,8 +61,8 @@ public sealed class FestaBlock5(SAV5B2W2 SAV, Memory<byte> raw) : SaveBlock<SAV5
|
|||
|
||||
public Funfest5Score GetMissionRecord(int mission)
|
||||
{
|
||||
var raw = ReadUInt32LittleEndian(Data[GetMissionRecordOffset(mission)..]);
|
||||
return new Funfest5Score(raw);
|
||||
var value = ReadUInt32LittleEndian(Data[GetMissionRecordOffset(mission)..]);
|
||||
return new Funfest5Score(value);
|
||||
}
|
||||
|
||||
public void SetMissionRecord(int mission, Funfest5Score score)
|
||||
|
|
105
PKHeX.Core/Saves/Substructures/Gen5/Record5.cs
Normal file
105
PKHeX.Core/Saves/Substructures/Gen5/Record5.cs
Normal file
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Buffers.Binary;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
public class Record5(SAV5 SAV, Memory<byte> raw) : SaveBlock<SAV5>(SAV, raw)
|
||||
{
|
||||
private Span<byte> DataRegion => Data[4..^4]; // 4..0x1DC
|
||||
|
||||
private uint CryptoSeed // 0x1DC
|
||||
{
|
||||
get => BinaryPrimitives.ReadUInt32LittleEndian(Data[^4..]);
|
||||
set => BinaryPrimitives.WriteUInt32LittleEndian(Data[^4..], value);
|
||||
}
|
||||
|
||||
private bool IsDecrypted;
|
||||
public void EndAccess() => EnsureDecrypted(false);
|
||||
private void EnsureDecrypted(bool state = true)
|
||||
{
|
||||
if (IsDecrypted == state)
|
||||
return;
|
||||
PokeCrypto.CryptArray(DataRegion, CryptoSeed);
|
||||
IsDecrypted = state;
|
||||
}
|
||||
|
||||
public uint Revision // 0x00
|
||||
{
|
||||
get => BinaryPrimitives.ReadUInt32LittleEndian(Data);
|
||||
set => BinaryPrimitives.WriteUInt32LittleEndian(Data, value);
|
||||
}
|
||||
|
||||
public const int Record32 = 68;
|
||||
public const int Record16 = 100;
|
||||
private const int Partition2 = Record32 * sizeof(uint);
|
||||
private Span<byte> Record32Data => DataRegion[..Partition2];
|
||||
private Span<byte> Record16Data => DataRegion[Partition2..];
|
||||
|
||||
private const uint Max32 = 999_999_999;
|
||||
private const ushort Max16 = 9999;
|
||||
|
||||
public uint GetRecord32(int index)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, Record32);
|
||||
EnsureDecrypted();
|
||||
return BinaryPrimitives.ReadUInt32LittleEndian(Record32Data[(index * 4)..]);
|
||||
}
|
||||
|
||||
public void SetRecord32(int index, uint value)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, Record32);
|
||||
EnsureDecrypted();
|
||||
BinaryPrimitives.WriteUInt32LittleEndian(Record32Data[(index * 4)..], value);
|
||||
}
|
||||
|
||||
public ushort GetRecord16(int index)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, Record16);
|
||||
EnsureDecrypted();
|
||||
return BinaryPrimitives.ReadUInt16LittleEndian(Record16Data[(index * 2)..]);
|
||||
}
|
||||
|
||||
public void SetRecord16(int index, ushort value)
|
||||
{
|
||||
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<uint>((uint)index, Record16);
|
||||
EnsureDecrypted();
|
||||
BinaryPrimitives.WriteUInt16LittleEndian(Record16Data[(index * 2)..], value);
|
||||
}
|
||||
|
||||
public enum Record5Index
|
||||
{
|
||||
TimesSaved = 0,
|
||||
StepsTaken = 1,
|
||||
UsedBicycle = 2,
|
||||
TotalBattles = 3,
|
||||
WildBattles = 4,
|
||||
TrainerBattles = 5,
|
||||
Captured = 6,
|
||||
CapturedFishing = 7,
|
||||
EggsHatched = 8,
|
||||
PokemonEvolved = 9,
|
||||
TimesHealedPokeCenter = 10,
|
||||
|
||||
// ???
|
||||
|
||||
LinkTrades = 21,
|
||||
LinkBattles = 22,
|
||||
LinkBattleWins = 23,
|
||||
LinkBattleLosses = 24,
|
||||
|
||||
// 00 - 0x110: start of u16 records
|
||||
// 46 - 0x16C: Feeling Checks
|
||||
// 47 - 0x16E: Musical
|
||||
// 56 - 0x180: Battle Tests Attempted
|
||||
// 57 - 0x182: Battle Test High Score
|
||||
// 60 - 0x188: Customers
|
||||
// 64 - 0x190: Movie Shoots
|
||||
FirstU16 = Record32 + 00,
|
||||
FeelingsChecked = Record32 + 46,
|
||||
Musical = Record32 + 47,
|
||||
BattleTestsAttempted = Record32 + 56,
|
||||
BattleTestHighScore = Record32 + 57,
|
||||
Customers = Record32 + 60,
|
||||
MovieShoots = Record32 + 64,
|
||||
}
|
||||
}
|
|
@ -33,6 +33,14 @@ namespace PKHeX.WinForms
|
|||
B_Save = new System.Windows.Forms.Button();
|
||||
TC_Misc = new System.Windows.Forms.TabControl();
|
||||
TAB_Main = new System.Windows.Forms.TabPage();
|
||||
L_Record32V = new System.Windows.Forms.Label();
|
||||
L_Record32 = new System.Windows.Forms.Label();
|
||||
L_Record16V = new System.Windows.Forms.Label();
|
||||
L_Record16 = new System.Windows.Forms.Label();
|
||||
NUD_Record32V = new System.Windows.Forms.NumericUpDown();
|
||||
NUD_Record32 = new System.Windows.Forms.NumericUpDown();
|
||||
NUD_Record16V = new System.Windows.Forms.NumericUpDown();
|
||||
NUD_Record16 = new System.Windows.Forms.NumericUpDown();
|
||||
GB_KeySystem = new System.Windows.Forms.GroupBox();
|
||||
B_AllKeys = new System.Windows.Forms.Button();
|
||||
CLB_KeySystem = new System.Windows.Forms.CheckedListBox();
|
||||
|
@ -170,6 +178,10 @@ namespace PKHeX.WinForms
|
|||
TipExpW = new System.Windows.Forms.ToolTip(components);
|
||||
TC_Misc.SuspendLayout();
|
||||
TAB_Main.SuspendLayout();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record32V).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record32).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record16V).BeginInit();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record16).BeginInit();
|
||||
GB_KeySystem.SuspendLayout();
|
||||
GB_Roamer.SuspendLayout();
|
||||
GB_FlyDest.SuspendLayout();
|
||||
|
@ -265,6 +277,14 @@ namespace PKHeX.WinForms
|
|||
//
|
||||
// TAB_Main
|
||||
//
|
||||
TAB_Main.Controls.Add(L_Record32V);
|
||||
TAB_Main.Controls.Add(L_Record32);
|
||||
TAB_Main.Controls.Add(L_Record16V);
|
||||
TAB_Main.Controls.Add(L_Record16);
|
||||
TAB_Main.Controls.Add(NUD_Record32V);
|
||||
TAB_Main.Controls.Add(NUD_Record32);
|
||||
TAB_Main.Controls.Add(NUD_Record16V);
|
||||
TAB_Main.Controls.Add(NUD_Record16);
|
||||
TAB_Main.Controls.Add(GB_KeySystem);
|
||||
TAB_Main.Controls.Add(CHK_LibertyPass);
|
||||
TAB_Main.Controls.Add(GB_Roamer);
|
||||
|
@ -278,6 +298,76 @@ namespace PKHeX.WinForms
|
|||
TAB_Main.Text = "Main";
|
||||
TAB_Main.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// L_Record32V
|
||||
//
|
||||
L_Record32V.Location = new System.Drawing.Point(178, 279);
|
||||
L_Record32V.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
L_Record32V.Name = "L_Record32V";
|
||||
L_Record32V.Size = new System.Drawing.Size(82, 23);
|
||||
L_Record32V.TabIndex = 11;
|
||||
L_Record32V.Text = "Value:";
|
||||
L_Record32V.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// L_Record32
|
||||
//
|
||||
L_Record32.Location = new System.Drawing.Point(178, 254);
|
||||
L_Record32.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
L_Record32.Name = "L_Record32";
|
||||
L_Record32.Size = new System.Drawing.Size(82, 23);
|
||||
L_Record32.TabIndex = 10;
|
||||
L_Record32.Text = "Record:";
|
||||
L_Record32.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// L_Record16V
|
||||
//
|
||||
L_Record16V.Location = new System.Drawing.Point(178, 225);
|
||||
L_Record16V.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
L_Record16V.Name = "L_Record16V";
|
||||
L_Record16V.Size = new System.Drawing.Size(82, 23);
|
||||
L_Record16V.TabIndex = 9;
|
||||
L_Record16V.Text = "Value:";
|
||||
L_Record16V.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// L_Record16
|
||||
//
|
||||
L_Record16.Location = new System.Drawing.Point(178, 200);
|
||||
L_Record16.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0);
|
||||
L_Record16.Name = "L_Record16";
|
||||
L_Record16.Size = new System.Drawing.Size(82, 23);
|
||||
L_Record16.TabIndex = 6;
|
||||
L_Record16.Text = "Record:";
|
||||
L_Record16.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// NUD_Record32V
|
||||
//
|
||||
NUD_Record32V.Location = new System.Drawing.Point(263, 279);
|
||||
NUD_Record32V.Maximum = new decimal(new int[] { -1, 0, 0, 0 });
|
||||
NUD_Record32V.Name = "NUD_Record32V";
|
||||
NUD_Record32V.Size = new System.Drawing.Size(120, 23);
|
||||
NUD_Record32V.TabIndex = 8;
|
||||
//
|
||||
// NUD_Record32
|
||||
//
|
||||
NUD_Record32.Location = new System.Drawing.Point(263, 254);
|
||||
NUD_Record32.Name = "NUD_Record32";
|
||||
NUD_Record32.Size = new System.Drawing.Size(120, 23);
|
||||
NUD_Record32.TabIndex = 7;
|
||||
//
|
||||
// NUD_Record16V
|
||||
//
|
||||
NUD_Record16V.Location = new System.Drawing.Point(263, 225);
|
||||
NUD_Record16V.Maximum = new decimal(new int[] { 65535, 0, 0, 0 });
|
||||
NUD_Record16V.Name = "NUD_Record16V";
|
||||
NUD_Record16V.Size = new System.Drawing.Size(120, 23);
|
||||
NUD_Record16V.TabIndex = 6;
|
||||
//
|
||||
// NUD_Record16
|
||||
//
|
||||
NUD_Record16.Location = new System.Drawing.Point(263, 200);
|
||||
NUD_Record16.Name = "NUD_Record16";
|
||||
NUD_Record16.Size = new System.Drawing.Size(120, 23);
|
||||
NUD_Record16.TabIndex = 5;
|
||||
//
|
||||
// GB_KeySystem
|
||||
//
|
||||
GB_KeySystem.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
|
@ -1855,6 +1945,10 @@ namespace PKHeX.WinForms
|
|||
TC_Misc.ResumeLayout(false);
|
||||
TAB_Main.ResumeLayout(false);
|
||||
TAB_Main.PerformLayout();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record32V).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record32).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record16V).EndInit();
|
||||
((System.ComponentModel.ISupportInitialize)NUD_Record16).EndInit();
|
||||
GB_KeySystem.ResumeLayout(false);
|
||||
GB_Roamer.ResumeLayout(false);
|
||||
GB_FlyDest.ResumeLayout(false);
|
||||
|
@ -2053,5 +2147,13 @@ namespace PKHeX.WinForms
|
|||
private System.Windows.Forms.ComboBox CB_Prop;
|
||||
private System.Windows.Forms.CheckBox CHK_PropObtained;
|
||||
private System.Windows.Forms.Button B_UnlockAllProps;
|
||||
private System.Windows.Forms.Label L_Record32V;
|
||||
private System.Windows.Forms.Label L_Record32;
|
||||
private System.Windows.Forms.Label L_Record16V;
|
||||
private System.Windows.Forms.Label L_Record16;
|
||||
private System.Windows.Forms.NumericUpDown NUD_Record32V;
|
||||
private System.Windows.Forms.NumericUpDown NUD_Record32;
|
||||
private System.Windows.Forms.NumericUpDown NUD_Record16V;
|
||||
private System.Windows.Forms.NumericUpDown NUD_Record16;
|
||||
}
|
||||
}
|
|
@ -39,6 +39,7 @@ public partial class SAV_Misc5 : Form
|
|||
ReadEntralink();
|
||||
ReadMedals();
|
||||
ReadMusical();
|
||||
ReadRecord();
|
||||
}
|
||||
|
||||
private void B_Cancel_Click(object sender, EventArgs e) => Close();
|
||||
|
@ -49,12 +50,28 @@ public partial class SAV_Misc5 : Form
|
|||
SaveForest();
|
||||
SaveSubway();
|
||||
SaveEntralink();
|
||||
SaveRecord();
|
||||
|
||||
Forest.EnsureDecrypted(false);
|
||||
Origin.CopyChangesFrom(SAV);
|
||||
Close();
|
||||
}
|
||||
|
||||
private void ReadRecord()
|
||||
{
|
||||
var record = SAV.Records;
|
||||
NUD_Record16.Maximum = Record5.Record16;
|
||||
NUD_Record32.Maximum = Record5.Record32;
|
||||
NUD_Record16V.Value = record.GetRecord16(0);
|
||||
NUD_Record32V.Value = record.GetRecord32(0);
|
||||
NUD_Record16V.ValueChanged += (_, _) => record.SetRecord16((int)NUD_Record16.Value, (ushort)NUD_Record16V.Value);
|
||||
NUD_Record32V.ValueChanged += (_, _) => record.SetRecord32((int)NUD_Record32.Value, (uint)NUD_Record32V.Value);
|
||||
NUD_Record16.ValueChanged += (_, _) => NUD_Record16V.Value = record.GetRecord16((int)NUD_Record16.Value);
|
||||
NUD_Record32.ValueChanged += (_, _) => NUD_Record32V.Value = record.GetRecord32((int)NUD_Record32.Value);
|
||||
}
|
||||
|
||||
private void SaveRecord() => SAV.Records.EndAccess();
|
||||
|
||||
private static ReadOnlySpan<uint> keyKS =>
|
||||
[
|
||||
// 0x34525, 0x11963, // Selected City
|
||||
|
|
Loading…
Reference in a new issue