diff --git a/PKHeX.Core/Saves/Access/SaveBlockAccessor7b.cs b/PKHeX.Core/Saves/Access/SaveBlockAccessor7b.cs index 4f766776b..cb0976c83 100644 --- a/PKHeX.Core/Saves/Access/SaveBlockAccessor7b.cs +++ b/PKHeX.Core/Saves/Access/SaveBlockAccessor7b.cs @@ -44,6 +44,7 @@ namespace PKHeX.Core Misc = new Misc7b(sav, GetBlockOffset(BelugaBlockIndex.Misc)); EventWork = new EventWork7b(sav, GetBlockOffset(BelugaBlockIndex.EventWork)); GiftRecords = new WB7Records(sav, GetBlockOffset(BelugaBlockIndex.WB7Record)); + Captured = new CaptureRecords(sav, GetBlockOffset(BelugaBlockIndex.CaptureRecord)); } public readonly MyItem Items; @@ -55,6 +56,7 @@ namespace PKHeX.Core public readonly EventWork7b EventWork; public readonly PokeListHeader Storage; public readonly WB7Records GiftRecords; + public readonly CaptureRecords Captured; public BlockInfo GetBlock(BelugaBlockIndex index) => BlockInfo[(int)index]; public int GetBlockOffset(BelugaBlockIndex index) => GetBlock(index).Offset; } diff --git a/PKHeX.Core/Saves/Substructures/Gen7/BelugaBlockIndex.cs b/PKHeX.Core/Saves/Substructures/Gen7/BelugaBlockIndex.cs index 29ce48017..c93117dca 100644 --- a/PKHeX.Core/Saves/Substructures/Gen7/BelugaBlockIndex.cs +++ b/PKHeX.Core/Saves/Substructures/Gen7/BelugaBlockIndex.cs @@ -14,7 +14,7 @@ /* 09 @ 0x05C00, len = 0x3F7A0 */ PokeListPokemon, /* 10 @ 0x45400, len = 0x00008 */ PlayTime, /* 11 @ 0x45600, len = 0x00E90 */ WB7Record, - /* 12 @ 0x46600, len = 0x010A4 */ _12, + /* 12 @ 0x46600, len = 0x010A4 */ CaptureRecord, /* 13 @ 0x47800, len = 0x000F0 */ _13, /* 14 @ 0x47A00, len = 0x06010 */ _14, /* 15 @ 0x4DC00, len = 0x00200 */ _15, // stuff containing data about recent captures? diff --git a/PKHeX.Core/Saves/Substructures/Gen7/CaptureRecords.cs b/PKHeX.Core/Saves/Substructures/Gen7/CaptureRecords.cs new file mode 100644 index 000000000..b462d48c6 --- /dev/null +++ b/PKHeX.Core/Saves/Substructures/Gen7/CaptureRecords.cs @@ -0,0 +1,130 @@ +using System; + +namespace PKHeX.Core +{ + public sealed class CaptureRecords : SaveBlock + { + public CaptureRecords(SAV7b sav, int offset) : base(sav) => Offset = offset; + + private const int ENTRY_COUNT = 153; + private const int MAX_COUNT_ENTRY = 9_999; + private const int MAX_COUNT_TOTAL = 999_999_999; + + // 0x468A8 to 0x46B0B contains 153 entries (u32) denoting how many of said Species you've caught (each cap out at 9,999). + private const int CapturedOffset = 0x2A8; + // 0x46B0C to 0x46D6F contains 153 entries (u32) denoting how many of said Species you've transferred to Professor Oak (each cap out at 999,999,999). + private const int TransferredOffset = CapturedOffset + (ENTRY_COUNT * sizeof(uint)); // 0x50C + + // 0x770 ?? + + // 0x46D94 is a u32 stores how many total Pokémon you've caught (caps out at 999,999,999). + private const int TotalCapturedOffset = 0x794; + + // 0x46DA8 is a u32 that stores how many Pokémon you've transferred to Professor Oak. + // This value is equal to the sum of all individual transferred Species, but caps out at 999,999,999 even if the sum of all individual Species exceeds this. + private const int TotalTransferredOffset = 0x7A8; + + // Calling into these directly, you should be sure that you're less than ENTRY_COUNT. + private int GetCapturedOffset(int index) => Offset + CapturedOffset + (index * 4); + private int GetTransferredOffset(int index) => Offset + TransferredOffset + (index * 4); + public uint GetCapturedCountIndex(int index) => BitConverter.ToUInt32(Data, GetCapturedOffset(index)); + public uint GetTransferredCountIndex(int index) => BitConverter.ToUInt32(Data, GetTransferredOffset(index)); + public void SetCapturedCountIndex(int index, uint value) => BitConverter.GetBytes(Math.Min(MAX_COUNT_ENTRY, value)).CopyTo(Data, Offset + GetCapturedOffset(index)); + public void SetTransferredCountIndex(int index, uint value) => BitConverter.GetBytes(Math.Min(MAX_COUNT_ENTRY, value)).CopyTo(Data, Offset + GetTransferredOffset(index)); + + private static int GetSpeciesIndex(int species) + { + if (species <= (int)Species.Mew) + return species - 1; + if (species == (int)Species.Meltan || species == (int)Species.Melmetal) + return species - 657; // 151, 152 + return -1; + } + + public uint GetCapturedCount(int species) + { + int index = GetSpeciesIndex(species); + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(species)); + return GetCapturedCountIndex(index); + } + + public void SetCapturedCount(int species, uint value) + { + int index = GetSpeciesIndex(species); + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(species)); + SetCapturedCountIndex(index, value); + } + + public uint GetTransferredCount(int species) + { + int index = GetSpeciesIndex(species); + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(species)); + return GetTransferredCountIndex(index); + } + + public void SetTransferredCount(int species, uint value) + { + int index = GetSpeciesIndex(species); + if (index < 0) + throw new ArgumentOutOfRangeException(nameof(species)); + SetTransferredCountIndex(index, value); + } + + public uint TotalCaptured + { + get => BitConverter.ToUInt32(Data, Offset + TotalCapturedOffset); + set => BitConverter.GetBytes(Math.Min(MAX_COUNT_TOTAL, value)).CopyTo(Data, Offset + TotalCapturedOffset); + } + + public uint TotalTransferred + { + get => BitConverter.ToUInt32(Data, Offset + TotalTransferredOffset); + set => BitConverter.GetBytes(Math.Min(MAX_COUNT_TOTAL, value)).CopyTo(Data, Offset + TotalTransferredOffset); + } + + public uint CalculateTotalCaptured() + { + uint total = 0; + for (int i = 0; i < ENTRY_COUNT; i++) + total += GetCapturedCountIndex(i); + return total; + } + + public uint CalculateTotalTransferred() + { + uint total = 0; + for (int i = 0; i < ENTRY_COUNT; i++) + total += GetTransferredCountIndex(i); + return total; + } + + public void SetAllCaptured(uint count = MAX_COUNT_ENTRY) + { + uint total = 0; + count = Math.Min(count, MAX_COUNT_ENTRY); + for (int i = 0; i < ENTRY_COUNT; i++) + { + SetCapturedCountIndex(i, count); + total += count; + } + if (total < TotalCaptured) + TotalCaptured = total; + } + + public void SetAllTransferred(uint count = MAX_COUNT_ENTRY) + { + uint total = 0; + count = Math.Min(count, MAX_COUNT_ENTRY); + for (int i = 0; i < ENTRY_COUNT; i++) + { + SetTransferredCountIndex(i, count); + total += count; + } + if (total < TotalTransferred) + TotalTransferred = total; + } + } +}