Add BDSP trainer stat records

Continue crawling down the serialized savedata structure :)
This commit is contained in:
Kurt 2021-11-20 15:40:18 -08:00
parent 1d3d317665
commit 6980026ca2
7 changed files with 118 additions and 7 deletions

View file

@ -2,7 +2,7 @@
namespace PKHeX.Core
{
public abstract class RecordBlock : SaveBlock
public abstract class RecordBlock : SaveBlock, IRecordStatStorage
{
protected abstract IReadOnlyList<byte> RecordMax { get; }
public abstract int GetRecord(int recordID);

View file

@ -2,11 +2,9 @@
using System.Collections.Generic;
using System.Security.Cryptography;
#nullable disable
namespace PKHeX.Core
{
public class SAV8BS : SaveFile, ISaveFileRevision
public class SAV8BS : SaveFile, ISaveFileRevision, ITrainerStatRecord
{
// Save Data Attributes
protected internal override string ShortSummary => $"{OT} ({Version})";
@ -28,7 +26,11 @@ namespace PKHeX.Core
MyStatus = new MyStatus8b(this, 0x79BB4); // size: 0x50
Played = new PlayTime8b(this, 0x79C04); // size: 0x04
Contest = new Contest8b(this, 0x79C08); // size: 0x720
Zukan = new Zukan8b(this, 0x7A328);
Zukan = new Zukan8b(this, 0x7A328); // size: 0x30B8
// 0x7D3E0 - Trainer Battle Data (bool,bool)[707]
// 0x7E9F8 - Menu selections (TopMenuItemTypeInt32, bool IsNew)[8], TopMenuItemTypeInt32 LastSelected
// 0x7EA3C - _FIELDOBJ_SAVE Objects[1000] (sizeof (0x44, 17 int fields), total size 0x109A0
Records = new Record8b(this, 0x8F3DC);
Initialize();
}
@ -143,6 +145,7 @@ namespace PKHeX.Core
public Contest8b Contest { get; }
// public Misc8 Misc { get; }
public Zukan8b Zukan { get; }
public Record8b Records { get; }
#endregion
public override GameVersion Version => Game switch
@ -218,7 +221,13 @@ namespace PKHeX.Core
pk.Trade(this, Date.Day, Date.Month, Date.Year);
pkm.RefreshChecksum();
//AddCountAcquired(pkm);
AddCountAcquired(pkm);
}
private void AddCountAcquired(PKM pkm)
{
// There aren't many records, and they only track Capture/Fish/Hatch/Defeat.
Records.AddRecord(pkm.WasEgg ? 004 : 002); // egg, capture
}
protected override void SetDex(PKM pkm) => Zukan.SetDex(pkm);
@ -233,5 +242,23 @@ namespace PKHeX.Core
public override PKM GetDecryptedPKM(byte[] data) => GetPKM(DecryptPKM(data));
public override PKM GetBoxSlot(int offset) => GetDecryptedPKM(GetData(Data, offset, SIZE_PARTY)); // party format in boxes!
public enum TopMenuItemType
{
Zukan = 0,
Pokemon = 1,
Bag = 2,
Card = 3,
Map = 4,
Seal = 5,
Setting = 6,
Gift = 7,
}
public int RecordCount => Record8b.RecordCount;
public int GetRecord(int recordID) => Records.GetRecord(recordID);
public int GetRecordOffset(int recordID) => Records.GetRecordOffset(recordID);
public int GetRecordMax(int recordID) => Record8b.RecordMaxValue;
public void SetRecord(int recordID, int value) => Records.SetRecord(recordID, value);
}
}

View file

@ -0,0 +1,33 @@
using System;
namespace PKHeX.Core
{
public sealed class Record8b : SaveBlock, IRecordStatStorage
{
public const int RecordCount = 30;
public const int RecordMaxValue = 999_999;
public Record8b(SAV8BS sav, int offset) : base(sav) => Offset = offset;
public int GetRecordOffset(int recordID)
{
if ((uint)recordID >= RecordCount)
throw new ArgumentOutOfRangeException(nameof(recordID));
return Offset + (sizeof(int) * recordID);
}
public int GetRecord(int recordID)
{
var value = BitConverter.ToInt32(Data, GetRecordOffset(recordID));
return Math.Min(RecordMaxValue, value);
}
public void SetRecord(int recordID, int value)
{
var toWrite = Math.Min(RecordMaxValue, value);
BitConverter.GetBytes(toWrite).CopyTo(Data, GetRecordOffset(recordID));
}
public void AddRecord(int recordID, int count = 1) => SetRecord(recordID, GetRecord(recordID) + count);
}
}

View file

@ -1,5 +1,8 @@
namespace PKHeX.Core
{
/// <summary>
/// Provides an API for fluent record editors.
/// </summary>
public interface ITrainerStatRecord
{
int GetRecord(int recordID);

View file

@ -0,0 +1,12 @@
namespace PKHeX.Core
{
/// <summary>
/// Provides a minimal API for mutating stat records.
/// </summary>
public interface IRecordStatStorage
{
int GetRecord(int recordID);
void SetRecord(int recordID, int value);
void AddRecord(int recordID, int count = 1);
}
}

View file

@ -591,5 +591,39 @@ namespace PKHeX.Core
public const int G8BattleTowerSingleWin = 47;
public const int G8BattleTowerDoubleWin = 48;
public static readonly Dictionary<int, string> RecordList_8b = new()
{
{ 00, "CLEAR_TIME" },
{ 01, "DENDOU_CNT" },
{ 02, "CAPTURE_POKE" },
{ 03, "FISHING_SUCCESS" },
{ 04, "TAMAGO_HATCHING" },
{ 05, "BEAT_DOWN_POKE" },
{ 06, "RENSHOU_SINGLE" },
{ 07, "RENSHOU_SINGLE_NOW" },
{ 08, "RENSHOU_DOUBLE" },
{ 09, "RENSHOU_DOUBLE_NOW" },
{ 10, "RENSHOU_MASTER_SINGLE" },
{ 11, "RENSHOU_MASTER_SINGLE_NOW" },
{ 12, "RENSHOU_MASTER_DOUBLE" },
{ 13, "RENSHOU_MASTER_DOUBLE_NOW" },
{ 14, "BTL_TOWER_AVERAGE" },
{ 15, "CONTEST_STYLE_RANK" },
{ 16, "CONTEST_BEATIFUL_RANK" },
{ 17, "CONTEST_CUTE_RANK" },
{ 18, "CONTEST_CLEVER_RANK" },
{ 19, "CONTEST_STRONG_RANK" },
{ 20, "CONTEST_PLAY_SINGLE" },
{ 21, "CONTEST_PLAY_LOCAL" },
{ 22, "CONTEST_PLAY_NETWORK" },
{ 23, "CONTEST_WIN_SINGLE" },
{ 24, "CONTEST_WIN_LOCAL" },
{ 25, "CONTEST_WIN_NETWORK" },
{ 26, "CONTEST_RATE_SINGLE" },
{ 27, "CONTEST_RATE_LOCAL" },
{ 28, "CONTEST_RATE_NETWORK" },
{ 29, "CONTEST_GET_RIBBON" },
};
}
}

View file

@ -32,6 +32,8 @@ namespace PKHeX.WinForms
GetComboBoxes();
GetTextBoxes();
TrainerStats.LoadRecords(SAV, Records.RecordList_8b);
Loading = false;
}
@ -47,7 +49,7 @@ namespace PKHeX.WinForms
CB_Game.SelectedIndex = Math.Max(0, Math.Min(1, SAV.Game - (int)GameVersion.BD));
CB_Gender.SelectedIndex = SAV.Gender;
GB_Stats.Visible = false;
L_BP.Visible = NUD_BP.Visible = false;
// Display Data
TB_OTName.Text = SAV.OT;