diff --git a/PKHeX.Core/PKM/PK1.cs b/PKHeX.Core/PKM/PK1.cs index 7fcd2266e..ffe69a7ac 100644 --- a/PKHeX.Core/PKM/PK1.cs +++ b/PKHeX.Core/PKM/PK1.cs @@ -11,8 +11,6 @@ namespace PKHeX.Core internal byte[] nick; public override PersonalInfo PersonalInfo => PersonalTable.Y[Species]; - public byte[] OT_Name_Raw => (byte[])otname.Clone(); - public byte[] Nickname_Raw => (byte[])nick.Clone(); public override bool Valid => Species <= 151 && (Data[0] == 0 || Species != 0); public override int SIZE_PARTY => PKX.SIZE_1PARTY; @@ -97,7 +95,7 @@ namespace PKHeX.Core } } - protected override byte[] Encrypt() => new PokemonList1(this).GetBytes(); + protected override byte[] Encrypt() => new PokeList1(this).Write(); public override byte[] EncryptedPartyData => Encrypt(); public override byte[] EncryptedBoxData => Encrypt(); public override byte[] DecryptedBoxData => Encrypt(); @@ -434,121 +432,4 @@ namespace PKHeX.Core return pk7; } } - - public class PokemonList1 - { - private const int CAPACITY_DAYCARE = 1; - private const int CAPACITY_PARTY = 6; - private const int CAPACITY_STORED = 20; - private const int CAPACITY_STORED_JP = 30; - - private readonly bool Japanese; - - private int StringLength => Japanese ? PK1.STRLEN_J : PK1.STRLEN_U; - - public enum CapacityType - { - Daycare = CAPACITY_DAYCARE, - Party = CAPACITY_PARTY, - Stored = CAPACITY_STORED, - StoredJP = CAPACITY_STORED_JP, - Single - } - - private static int GetEntrySize(CapacityType c) => c == CapacityType.Single || c == CapacityType.Party - ? PKX.SIZE_1PARTY - : PKX.SIZE_1STORED; - private static byte GetCapacity(CapacityType c) => c == CapacityType.Single ? (byte)1 : (byte)c; - - private static byte[] GetEmptyList(CapacityType c, bool is_JP = false) - { - int cap = GetCapacity(c); - return new[] { (byte)0 }.Concat(Enumerable.Repeat((byte)0xFF, cap + 1)).Concat(Enumerable.Repeat((byte)0, GetEntrySize(c) * cap)).Concat(Enumerable.Repeat((byte)0x50, (is_JP ? PK1.STRLEN_J : PK1.STRLEN_U) * 2 * cap)).ToArray(); - } - - public PokemonList1(byte[] d, CapacityType c = CapacityType.Single, bool jp = false) - { - Japanese = jp; - Data = d ?? GetEmptyList(c, Japanese); - Capacity = GetCapacity(c); - Entry_Size = GetEntrySize(c); - - if (Data.Length != DataSize) - Array.Resize(ref Data, DataSize); - - Pokemon = new PK1[Capacity]; - for (int i = 0; i < Capacity; i++) - { - int base_ofs = 2 + Capacity; - byte[] dat = new byte[Entry_Size]; - byte[] otname = new byte[StringLength]; - byte[] nick = new byte[StringLength]; - Buffer.BlockCopy(Data, base_ofs + Entry_Size * i, dat, 0, Entry_Size); - Buffer.BlockCopy(Data, base_ofs + Capacity * Entry_Size + StringLength * i, otname, 0, StringLength); - Buffer.BlockCopy(Data, base_ofs + Capacity * Entry_Size + StringLength * (i + Capacity), nick, 0, StringLength); - - Pokemon[i] = new PK1(dat, null, jp) {otname = otname, nick = nick}; - } - } - - public PokemonList1(CapacityType c = CapacityType.Single, bool jp = false) - : this(null, c, jp) => Count = 1; - - public PokemonList1(PK1 pk) - : this(CapacityType.Single, pk.Japanese) - { - this[0] = pk; - Count = 1; - } - - private readonly byte[] Data; - private readonly byte Capacity; - private readonly int Entry_Size; - - public byte Count - { - get => Data[0]; - set => Data[0] = value > Capacity ? Capacity : value; - } - - public readonly PK1[] Pokemon; - - public PK1 this[int i] - { - get - { - if (i > Capacity || i < 0) throw new ArgumentOutOfRangeException($"Invalid PokemonList Access: {i}"); - return Pokemon[i]; - } - set - { - if (value == null) return; - Pokemon[i] = (PK1)value.Clone(); - } - } - - private void Update() - { - int count = Array.FindIndex(Pokemon, pk => pk.Species == 0); - Count = count < 0 ? Capacity : (byte)count; - for (int i = 0; i < Count; i++) - { - int base_ofs = 2 + Capacity; - Data[1 + i] = (byte)SpeciesConverter.SetG1Species(Pokemon[i].Species); - Array.Copy(Pokemon[i].Data, 0, Data, base_ofs + Entry_Size * i, Entry_Size); - Array.Copy(Pokemon[i].OT_Name_Raw, 0, Data, base_ofs + Capacity * Entry_Size + StringLength * i, StringLength); - Array.Copy(Pokemon[i].Nickname_Raw, 0, Data, base_ofs + Capacity * Entry_Size + StringLength * (i + Capacity), StringLength); - } - Data[1 + Count] = byte.MaxValue; - } - - public byte[] GetBytes() - { - Update(); - return Data; - } - - private int DataSize => Capacity * (Entry_Size + 1 + 2 * StringLength) + 2; - public static int GetDataLength(CapacityType c, bool jp = false) => GetCapacity(c) * (GetEntrySize(c) + 1 + 2 * (jp ? PK1.STRLEN_J : PK1.STRLEN_U)) + 2; - } } diff --git a/PKHeX.Core/PKM/PK2.cs b/PKHeX.Core/PKM/PK2.cs index 1a11cc9d0..dad6312b7 100644 --- a/PKHeX.Core/PKM/PK2.cs +++ b/PKHeX.Core/PKM/PK2.cs @@ -11,8 +11,6 @@ namespace PKHeX.Core internal byte[] nick; public override PersonalInfo PersonalInfo => PersonalTable.C[Species]; - public byte[] OT_Name_Raw => (byte[])otname.Clone(); - public byte[] Nickname_Raw => (byte[])nick.Clone(); public override bool Valid => Species <= 252; public override int SIZE_PARTY => PKX.SIZE_2PARTY; @@ -119,7 +117,7 @@ namespace PKHeX.Core } } - protected override byte[] Encrypt() => new PokemonList2(this).GetBytes(); + protected override byte[] Encrypt() => new PokeList2(this).Write(); public override byte[] EncryptedPartyData => Encrypt(); public override byte[] EncryptedBoxData => Encrypt(); public override byte[] DecryptedBoxData => Encrypt(); @@ -361,7 +359,7 @@ namespace PKHeX.Core public PK1 ConvertToPK1() { - PK1 pk1 = new PK1(null, Identifier, Japanese) {TradebackStatus = TradebackType.WasTradeback}; + PK1 pk1 = new PK1(null, Identifier) {TradebackStatus = TradebackType.WasTradeback}; Array.Copy(Data, 0x1, pk1.Data, 0x7, 0x1A); pk1.Species = Species; // This will take care of Typing :) @@ -377,8 +375,8 @@ namespace PKHeX.Core pk1.Stat_Level = Stat_Level; } // Status = 0 - Array.Copy(otname, 0, pk1.otname, 0, otname.Length); - Array.Copy(nick, 0, pk1.nick, 0, nick.Length); + pk1.otname = (byte[])otname.Clone(); + pk1.nick = (byte[])nick.Clone(); pk1.ClearInvalidMoves(); @@ -479,122 +477,4 @@ namespace PKHeX.Core return pk7; } } - - public class PokemonList2 - { - private const int CAPACITY_DAYCARE = 1; - private const int CAPACITY_PARTY = 6; - private const int CAPACITY_STORED = 20; - private const int CAPACITY_STORED_JP = 30; - - private readonly bool Japanese; - - private int StringLength => Japanese ? PK2.STRLEN_J : PK2.STRLEN_U; - - public enum CapacityType - { - Daycare = CAPACITY_DAYCARE, - Party = CAPACITY_PARTY, - Stored = CAPACITY_STORED, - StoredJP = CAPACITY_STORED_JP, - Single - } - - private static int GetEntrySize(CapacityType c) => c == CapacityType.Single || c == CapacityType.Party - ? PKX.SIZE_2PARTY - : PKX.SIZE_2STORED; - - private static byte GetCapacity(CapacityType c) => c == CapacityType.Single ? (byte)1 : (byte)c; - - private static byte[] GetEmptyList(CapacityType c, bool is_JP = false) - { - int cap = GetCapacity(c); - return new[] { (byte)0 }.Concat(Enumerable.Repeat((byte)0xFF, cap + 1)).Concat(Enumerable.Repeat((byte)0, GetEntrySize(c) * cap)).Concat(Enumerable.Repeat((byte)0x50, (is_JP ? PK2.STRLEN_J : PK2.STRLEN_U) * 2 * cap)).ToArray(); - } - - public PokemonList2(byte[] d, CapacityType c = CapacityType.Single, bool jp = false) - { - Japanese = jp; - Data = d ?? GetEmptyList(c, Japanese); - Capacity = GetCapacity(c); - Entry_Size = GetEntrySize(c); - - if (Data.Length != DataSize) - { - Array.Resize(ref Data, DataSize); - } - - Pokemon = new PK2[Capacity]; - for (int i = 0; i < Capacity; i++) - { - int base_ofs = 2 + Capacity; - byte[] dat = new byte[Entry_Size]; - byte[] otname = new byte[StringLength]; - byte[] nick = new byte[StringLength]; - Buffer.BlockCopy(Data, base_ofs + Entry_Size * i, dat, 0, Entry_Size); - Buffer.BlockCopy(Data, base_ofs + Capacity * Entry_Size + StringLength * i, otname, 0, StringLength); - Buffer.BlockCopy(Data, base_ofs + Capacity * Entry_Size + StringLength * (i + Capacity), nick, 0, StringLength); - Pokemon[i] = new PK2(dat, null, jp) {IsEgg = Data[1 + i] == 0xFD, otname = otname, nick = nick}; - } - } - - public PokemonList2(CapacityType c = CapacityType.Single, bool jp = false) - : this(null, c, jp) => Count = 1; - - public PokemonList2(PK2 pk) - : this(CapacityType.Single, pk.Japanese) - { - this[0] = pk; - Count = 1; - } - - private readonly byte[] Data; - private readonly byte Capacity; - private readonly int Entry_Size; - - public byte Count - { - get => Data[0]; - set => Data[0] = value > Capacity ? Capacity : value; - } - - public readonly PK2[] Pokemon; - - public PK2 this[int i] - { - get - { - if (i > Capacity || i < 0) throw new ArgumentOutOfRangeException($"Invalid PokemonList Access: {i}"); - return Pokemon[i]; - } - set - { - if (value == null) return; - Pokemon[i] = (PK2)value.Clone(); - } - } - - private void Update() - { - int count = Array.FindIndex(Pokemon, pk => pk.Species == 0); - Count = count < 0 ? Capacity : (byte)count; - for (int i = 0; i < Count; i++) - { - Data[1 + i] = Pokemon[i].IsEgg ? (byte)0xFD : (byte)Pokemon[i].Species; - Array.Copy(Pokemon[i].Data, 0, Data, 2 + Capacity + Entry_Size * i, Entry_Size); - Array.Copy(Pokemon[i].OT_Name_Raw, 0, Data, 2 + Capacity + Capacity * Entry_Size + StringLength * i, StringLength); - Array.Copy(Pokemon[i].Nickname_Raw, 0, Data, 2 + Capacity + Capacity * Entry_Size + StringLength * Capacity + StringLength * i, StringLength); - } - Data[1 + Count] = byte.MaxValue; - } - - public byte[] GetBytes() - { - Update(); - return Data; - } - - private int DataSize => Capacity * (Entry_Size + 1 + 2 * StringLength) + 2; - public static int GetDataLength(CapacityType c, bool jp = false) => GetCapacity(c) * (GetEntrySize(c) + 1 + 2 * (jp ? PK2.STRLEN_J : PK2.STRLEN_U)) + 2; - } } diff --git a/PKHeX.Core/PKM/Shared/PokeList1.cs b/PKHeX.Core/PKM/Shared/PokeList1.cs new file mode 100644 index 000000000..cabc9c349 --- /dev/null +++ b/PKHeX.Core/PKM/Shared/PokeList1.cs @@ -0,0 +1,17 @@ +namespace PKHeX.Core +{ + public sealed class PokeList1 : PokeListGB + { + protected override byte GetSpeciesBoxIdentifier(PK1 pk) => (byte)SpeciesConverter.SetG1Species(pk.Species); + protected override PK1 GetEntry(byte[] dat, byte[] otname, byte[] nick, bool egg) => new PK1(dat) { otname = otname, nick = nick }; + protected override int GetEntrySize() => GetEntrySize(IsFormatParty); + + public PokeList1(byte[] d, PokeListType c = PokeListType.Single, bool jp = false) : base(d, c, jp) { } + public PokeList1(PokeListType c = PokeListType.Single, bool jp = false) : base(c, jp) { } + public PokeList1(byte[] d) : base(d, PokeListType.Single, d.Length == PKX.SIZE_1JLIST) { } + public PokeList1(PK1 pk) : base(pk) { } + + private static int GetEntrySize(bool party) => party ? PKX.SIZE_1PARTY : PKX.SIZE_1STORED; + public static int GetDataLength(PokeListType c, bool jp) => GetDataSize(c, jp, GetEntrySize(IsCapacityPartyFormat(c))); + } +} \ No newline at end of file diff --git a/PKHeX.Core/PKM/Shared/PokeList2.cs b/PKHeX.Core/PKM/Shared/PokeList2.cs new file mode 100644 index 000000000..2acd1072b --- /dev/null +++ b/PKHeX.Core/PKM/Shared/PokeList2.cs @@ -0,0 +1,17 @@ +namespace PKHeX.Core +{ + public sealed class PokeList2 : PokeListGB + { + protected override byte GetSpeciesBoxIdentifier(PK2 pk) => pk.IsEgg ? (byte)0xFD : (byte)pk.Species; + protected override PK2 GetEntry(byte[] dat, byte[] otname, byte[] nick, bool egg) => new PK2(dat) { IsEgg = egg, otname = otname, nick = nick }; + protected override int GetEntrySize() => GetEntrySize(IsFormatParty); + + public PokeList2(byte[] d, PokeListType c = PokeListType.Single, bool jp = false) : base(d, c, jp) { } + public PokeList2(PokeListType c = PokeListType.Single, bool jp = false) : base (c, jp) { } + public PokeList2(byte[] d) : base(d, PokeListType.Single, d.Length == PKX.SIZE_2JLIST) { } + public PokeList2(PK2 pk) : base(pk) { } + + private static int GetEntrySize(bool party) => party ? PKX.SIZE_2PARTY : PKX.SIZE_2STORED; + public static int GetDataLength(PokeListType c, bool jp) => GetDataSize(c, jp, GetEntrySize(IsCapacityPartyFormat(c))); + } +} \ No newline at end of file diff --git a/PKHeX.Core/PKM/Shared/PokeListGB.cs b/PKHeX.Core/PKM/Shared/PokeListGB.cs new file mode 100644 index 000000000..3a6393915 --- /dev/null +++ b/PKHeX.Core/PKM/Shared/PokeListGB.cs @@ -0,0 +1,129 @@ +using System; +using System.Linq; + +namespace PKHeX.Core +{ + public abstract class PokeListGB where T : PKM + { + private readonly int StringLength; + private readonly byte[] Data; + private readonly byte Capacity; + private readonly int Entry_Size; + + public readonly T[] Pokemon; + + public byte Count { get => Data[0]; private set => Data[0] = value > Capacity ? Capacity : value; } + + protected PokeListGB(byte[] d, PokeListType c = PokeListType.Single, bool jp = false) + { + Data = d ?? GetEmptyList(c, jp); + StringLength = GetStringLength(jp); + Capacity = (byte)c; + Entry_Size = GetEntrySize(); + var dataSize = 2 + (Capacity * (Entry_Size + 1 + (2 * StringLength))); + + if (Data.Length != dataSize) + Array.Resize(ref Data, dataSize); + + Pokemon = Read(); + } + + protected PokeListGB(PokeListType c = PokeListType.Single, bool jp = false) + : this(null, c, jp) => Count = 1; + + protected PokeListGB(T pk) + : this(PokeListType.Single, pk.Japanese) + { + this[0] = pk; + Count = 1; + } + + private byte[] GetEmptyList(PokeListType c, bool jp = false) + { + int capacity = (byte)c; + var intro = Enumerable.Repeat((byte) 0xFF, capacity + 1); + var pkm = Enumerable.Repeat((byte) 0, GetEntrySize() * capacity); + var strings = Enumerable.Repeat((byte) 0x50, GetStringLength(jp) * 2 * capacity); + return new[] { (byte)0 }.Concat(intro).Concat(pkm).Concat(strings).ToArray(); + } + + private int GetOffsetPKMData(int base_ofs, int i) => base_ofs + (Entry_Size * i); + private int GetOffsetPKMOT(int base_ofs, int i) => GetOffsetPKMData(base_ofs, Capacity) + (StringLength * i); + private int GetOffsetPKMNickname(int base_ofs, int i) => GetOffsetPKMOT(base_ofs, Capacity) + (StringLength * i); + + private static int GetStringLength(bool jp) => jp ? PK1.STRLEN_J : PK1.STRLEN_U; + protected bool IsFormatParty => IsCapacityPartyFormat((PokeListType)Capacity); + protected static bool IsCapacityPartyFormat(PokeListType Capacity) => Capacity == PokeListType.Single || Capacity == PokeListType.Party; + + protected static int GetDataSize(PokeListType c, bool jp, int entrySize) + { + var entryLength = 1 + entrySize + (2 * GetStringLength(jp)); + return 2 + ((byte)c * entryLength); + } + + protected abstract int GetEntrySize(); + protected abstract byte GetSpeciesBoxIdentifier(T pk); + protected abstract T GetEntry(byte[] dat, byte[] otname, byte[] nick, bool egg); + + public T this[int i] + { + get + { + if (i > Capacity || i < 0) throw new ArgumentOutOfRangeException($"Invalid {nameof(PokeListGB)} Access: {i}"); + return Pokemon[i]; + } + set + { + if (value == null) return; + Pokemon[i] = (T)value.Clone(); + } + } + + private T[] Read() + { + var arr = new T[Capacity]; + int base_ofs = 2 + Capacity; + for (int i = 0; i < Capacity; i++) + arr[i] = GetEntry(base_ofs, i); + return arr; + } + + public byte[] Write() + { + int count = Array.FindIndex(Pokemon, pk => pk.Species == 0); + Count = count < 0 ? Capacity : (byte)count; + int base_ofs = 2 + Capacity; + for (int i = 0; i < Count; i++) + { + Data[1 + i] = GetSpeciesBoxIdentifier(Pokemon[i]); + SetEntry(base_ofs, i); + } + Data[1 + Count] = byte.MaxValue; + return Data; + } + + private T GetEntry(int base_ofs, int i) + { + byte[] dat = new byte[Entry_Size]; + byte[] otname = new byte[StringLength]; + byte[] nick = new byte[StringLength]; + int pkOfs = GetOffsetPKMData(base_ofs, i); + int otOfs = GetOffsetPKMOT(base_ofs, i); + int nkOfs = GetOffsetPKMNickname(base_ofs, i); + Buffer.BlockCopy(Data, pkOfs, dat, 0, Entry_Size); + Buffer.BlockCopy(Data, otOfs, otname, 0, StringLength); + Buffer.BlockCopy(Data, nkOfs, nick, 0, StringLength); + return GetEntry(dat, otname, nick, Data[1 + i] == 0xFD); + } + + private void SetEntry(int base_ofs, int i) + { + int pkOfs = GetOffsetPKMData(base_ofs, i); + int otOfs = GetOffsetPKMOT(base_ofs, i); + int nkOfs = GetOffsetPKMNickname(base_ofs, i); + Array.Copy(Pokemon[i].Data, 0, Data, pkOfs, Entry_Size); + Array.Copy(Pokemon[i].OT_Trash, 0, Data, otOfs, StringLength); + Array.Copy(Pokemon[i].Nickname_Trash, 0, Data, nkOfs, StringLength); + } + } +} \ No newline at end of file diff --git a/PKHeX.Core/PKM/Shared/PokeListType.cs b/PKHeX.Core/PKM/Shared/PokeListType.cs new file mode 100644 index 000000000..08d187bb5 --- /dev/null +++ b/PKHeX.Core/PKM/Shared/PokeListType.cs @@ -0,0 +1,10 @@ +namespace PKHeX.Core +{ + public enum PokeListType : byte + { + Single = 1, + Party = 6, + Stored = 20, + StoredJP = 30, + } +} \ No newline at end of file diff --git a/PKHeX.Core/PKM/Util/PKMConverter.cs b/PKHeX.Core/PKM/Util/PKMConverter.cs index ffa4bd40e..6666c1458 100644 --- a/PKHeX.Core/PKM/Util/PKMConverter.cs +++ b/PKHeX.Core/PKM/Util/PKMConverter.cs @@ -86,12 +86,12 @@ namespace PKHeX.Core switch (format) { case 1: - var PL1 = new PokemonList1(data, PokemonList1.CapacityType.Single, data.Length == PKX.SIZE_1JLIST); + var PL1 = new PokeList1(data); if (ident != null) PL1[0].Identifier = ident; return PL1[0]; case 2: - var PL2 = new PokemonList2(data, PokemonList2.CapacityType.Single, data.Length == PKX.SIZE_2JLIST); + var PL2 = new PokeList2(data); if (ident != null) PL2[0].Identifier = ident; return PL2[0]; diff --git a/PKHeX.Core/Saves/SAV1.cs b/PKHeX.Core/Saves/SAV1.cs index 9b30bf8fd..f90cf5eaf 100644 --- a/PKHeX.Core/Saves/SAV1.cs +++ b/PKHeX.Core/Saves/SAV1.cs @@ -41,71 +41,56 @@ namespace PKHeX.Core Personal = PersonalTable.Y; // Stash boxes after the save file's end. - byte[] TempBox = new byte[SIZE_STOREDBOX]; + int stored = SIZE_STOREDBOX; + int baseDest = Data.Length - SIZE_RESERVED; + var capacity = Japanese ? PokeListType.StoredJP : PokeListType.Stored; for (int i = 0; i < BoxCount; i++) { - if (i < BoxCount / 2) - Array.Copy(Data, 0x4000 + i * TempBox.Length, TempBox, 0, TempBox.Length); - else - Array.Copy(Data, 0x6000 + (i - BoxCount / 2) * TempBox.Length, TempBox, 0, TempBox.Length); - PokemonList1 PL1 = new PokemonList1(TempBox, Japanese ? PokemonList1.CapacityType.StoredJP : PokemonList1.CapacityType.Stored, Japanese); - for (int j = 0; j < PL1.Pokemon.Length; j++) + int ofs = GetBoxRawDataOffset(i); + var box = GetData(ofs, stored); + var boxDest = baseDest + (i * SIZE_BOX); + var boxPL = new PokeList1(box, capacity, Japanese); + for (int j = 0; j < boxPL.Pokemon.Length; j++) { - if (j < PL1.Count) - { - byte[] pkDat = new PokemonList1(PL1[j]).GetBytes(); - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED); - } - else - { - byte[] pkDat = new byte[PokemonList1.GetDataLength(PokemonList1.CapacityType.Single, Japanese)]; - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED); - } + var dest = boxDest + (j * SIZE_STORED); + var pkDat = (j < boxPL.Count) + ? new PokeList1(boxPL[j]).Write() + : new byte[PokeList1.GetDataLength(PokeListType.Single, Japanese)]; + pkDat.CopyTo(Data, dest); } } - Array.Copy(Data, Japanese ? 0x302D : 0x30C0, TempBox, 0, TempBox.Length); - PokemonList1 curBoxPL = new PokemonList1(TempBox, Japanese ? PokemonList1.CapacityType.StoredJP : PokemonList1.CapacityType.Stored, Japanese); + var current = GetData(Japanese ? 0x302D : 0x30C0, SIZE_STOREDBOX); + var curBoxPL = new PokeList1(current, capacity, Japanese); for (int i = 0; i < curBoxPL.Pokemon.Length; i++) { - if (i < curBoxPL.Count) - { - byte[] pkDat = new PokemonList1(curBoxPL[i]).GetBytes(); - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED); - } - else - { - byte[] pkDat = new byte[PokemonList1.GetDataLength(PokemonList1.CapacityType.Single, Japanese)]; - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED); - } + var dest = Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED; + var pkDat = i < curBoxPL.Count + ? new PokeList1(curBoxPL[i]).Write() + : new byte[PokeList1.GetDataLength(PokeListType.Single, Japanese)]; + pkDat.CopyTo(Data, dest); } - byte[] TempParty = new byte[PokemonList1.GetDataLength(PokemonList1.CapacityType.Party, Japanese)]; - Array.Copy(Data, Japanese ? 0x2ED5 : 0x2F2C, TempParty, 0, TempParty.Length); - PokemonList1 partyList = new PokemonList1(TempParty, PokemonList1.CapacityType.Party, Japanese); - for (int i = 0; i < partyList.Pokemon.Length; i++) + var party = GetData(Japanese ? 0x2ED5 : 0x2F2C, SIZE_STOREDPARTY); + var partyPL = new PokeList1(party, PokeListType.Party, Japanese); + for (int i = 0; i < partyPL.Pokemon.Length; i++) { - if (i < partyList.Count) - { - byte[] pkDat = new PokemonList1(partyList[i]).GetBytes(); - pkDat.CopyTo(Data, GetPartyOffset(i)); - } - else - { - byte[] pkDat = new byte[PokemonList1.GetDataLength(PokemonList1.CapacityType.Single, Japanese)]; - pkDat.CopyTo(Data, GetPartyOffset(i)); - } + var dest = GetPartyOffset(i); + var pkDat = i < partyPL.Count + ? new PokeList1(partyPL[i]).Write() + : new byte[PokeList1.GetDataLength(PokeListType.Single, Japanese)]; + pkDat.CopyTo(Data, dest); } byte[] rawDC = new byte[0x38]; Array.Copy(Data, Japanese ? 0x2CA7 : 0x2CF4, rawDC, 0, rawDC.Length); - byte[] TempDaycare = new byte[PokemonList1.GetDataLength(PokemonList1.CapacityType.Single, Japanese)]; + byte[] TempDaycare = new byte[PokeList1.GetDataLength(PokeListType.Single, Japanese)]; TempDaycare[0] = rawDC[0]; Array.Copy(rawDC, 1, TempDaycare, 2 + 1 + PKX.SIZE_1PARTY + StringLength, StringLength); Array.Copy(rawDC, 1 + StringLength, TempDaycare, 2 + 1 + PKX.SIZE_1PARTY, StringLength); Array.Copy(rawDC, 1 + 2 * StringLength, TempDaycare, 2 + 1, PKX.SIZE_1STORED); - PokemonList1 daycareList = new PokemonList1(TempDaycare, PokemonList1.CapacityType.Single, Japanese); - daycareList.GetBytes().CopyTo(Data, GetPartyOffset(7)); + PokeList1 daycareList = new PokeList1(TempDaycare, PokeListType.Single, Japanese); + daycareList.Write().CopyTo(Data, GetPartyOffset(7)); Daycare = GetPartyOffset(7); EventFlag = Japanese ? 0x29E9 : 0x29F3; @@ -127,25 +112,29 @@ namespace PKHeX.Core protected override byte[] Write(bool DSV) { + var capacity = Japanese ? PokeListType.StoredJP : PokeListType.Stored; for (int i = 0; i < BoxCount; i++) { - PokemonList1 boxPL = new PokemonList1(Japanese ? PokemonList1.CapacityType.StoredJP : PokemonList1.CapacityType.Stored, Japanese); + var boxPL = new PokeList1(capacity, Japanese); int slot = 0; for (int j = 0; j < boxPL.Pokemon.Length; j++) { - PK1 boxPK = (PK1) GetPKM(GetData(GetBoxOffset(i) + j*SIZE_STORED, SIZE_STORED)); + PK1 boxPK = (PK1)GetPKM(GetData(GetBoxOffset(i) + (j * SIZE_STORED), SIZE_STORED)); if (boxPK.Species > 0) boxPL[slot++] = boxPK; } - if (i < BoxCount / 2) - boxPL.GetBytes().CopyTo(Data, 0x4000 + i * SIZE_STOREDBOX); - else - boxPL.GetBytes().CopyTo(Data, 0x6000 + (i - BoxCount / 2) * SIZE_STOREDBOX); + + // copy to box location + var boxdata = boxPL.Write(); + int ofs = GetBoxRawDataOffset(i); + SetData(boxdata, ofs); + + // copy to active loc if current box if (i == CurrentBox) - boxPL.GetBytes().CopyTo(Data, Japanese ? 0x302D : 0x30C0); + SetData(boxdata, Japanese ? 0x302D : 0x30C0); } - PokemonList1 partyPL = new PokemonList1(PokemonList1.CapacityType.Party, Japanese); + var partyPL = new PokeList1(PokeListType.Party, Japanese); int pSlot = 0; for (int i = 0; i < 6; i++) { @@ -153,7 +142,7 @@ namespace PKHeX.Core if (partyPK.Species > 0) partyPL[pSlot++] = partyPK; } - partyPL.GetBytes().CopyTo(Data, Japanese ? 0x2ED5 : 0x2F2C); + partyPL.Write().CopyTo(Data, Japanese ? 0x2ED5 : 0x2F2C); // Daycare is read-only, but in case it ever becomes editable, copy it back in. byte[] rawDC = GetData(GetDaycareSlotOffset(loc: 0, slot: 0), SIZE_STORED); @@ -170,13 +159,21 @@ namespace PKHeX.Core return outData; } + private int GetBoxRawDataOffset(int i) + { + if (i < BoxCount / 2) + return 0x4000 + (i * SIZE_STOREDBOX); + return 0x6000 + ((i - (BoxCount / 2)) * SIZE_STOREDBOX); + } + // Configuration public override SaveFile Clone() { return new SAV1(Write(DSV: false)); } public override int SIZE_STORED => Japanese ? PKX.SIZE_1JLIST : PKX.SIZE_1ULIST; protected override int SIZE_PARTY => Japanese ? PKX.SIZE_1JLIST : PKX.SIZE_1ULIST; private int SIZE_BOX => BoxSlotCount*SIZE_STORED; - private int SIZE_STOREDBOX => PokemonList1.GetDataLength(Japanese ? PokemonList1.CapacityType.StoredJP : PokemonList1.CapacityType.Stored, Japanese); + private int SIZE_STOREDBOX => PokeList1.GetDataLength(Japanese ? PokeListType.StoredJP : PokeListType.Stored, Japanese); + private int SIZE_STOREDPARTY => PokeList1.GetDataLength(PokeListType.Party, Japanese); public override PKM BlankPKM => new PK1(null, null, Japanese); public override Type PKMType => typeof(PK1); @@ -441,7 +438,7 @@ namespace PKHeX.Core public override PKM GetPKM(byte[] data) { if (data.Length == SIZE_STORED) - return new PokemonList1(data, PokemonList1.CapacityType.Single, Japanese)[0]; + return new PokeList1(data, PokeListType.Single, Japanese)[0]; return new PK1(data); } public override byte[] DecryptPKM(byte[] data) diff --git a/PKHeX.Core/Saves/SAV2.cs b/PKHeX.Core/Saves/SAV2.cs index 6ffa2f467..706ea6f4a 100644 --- a/PKHeX.Core/Saves/SAV2.cs +++ b/PKHeX.Core/Saves/SAV2.cs @@ -54,60 +54,47 @@ namespace PKHeX.Core HeldItems = Legal.HeldItems_GSC; // Stash boxes after the save file's end. - byte[] TempBox = new byte[SIZE_STOREDBOX]; + int splitAtIndex = (Japanese ? 6 : 7); + int stored = SIZE_STOREDBOX; + int baseDest = Data.Length - SIZE_RESERVED; + var capacity = Japanese ? PokeListType.StoredJP : PokeListType.Stored; for (int i = 0; i < BoxCount; i++) { - if (i < (Japanese ? 6 : 7)) - Array.Copy(Data, 0x4000 + i * (TempBox.Length + 2), TempBox, 0, TempBox.Length); - else - Array.Copy(Data, 0x6000 + (i - (Japanese ? 6 : 7)) * (TempBox.Length + 2), TempBox, 0, TempBox.Length); - PokemonList2 PL2 = new PokemonList2(TempBox, Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese); - for (int j = 0; j < PL2.Pokemon.Length; j++) + int ofs = GetBoxRawDataOffset(i, splitAtIndex); + var box = GetData(ofs, stored); + var boxDest = baseDest + (i * SIZE_BOX); + var boxPL = new PokeList2(box, capacity, Japanese); + for (int j = 0; j < boxPL.Pokemon.Length; j++) { - if (j < PL2.Count) - { - byte[] pkDat = new PokemonList2(PL2[j]).GetBytes(); - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED); - } - else - { - byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)]; - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + i * SIZE_BOX + j * SIZE_STORED); - } + var dest = boxDest + (j * SIZE_STORED); + var pkDat = (j < boxPL.Count) + ? new PokeList2(boxPL[j]).Write() + : new byte[PokeList2.GetDataLength(PokeListType.Single, Japanese)]; + pkDat.CopyTo(Data, dest); } } - Array.Copy(Data, Offsets.CurrentBox, TempBox, 0, TempBox.Length); - PokemonList2 curBoxPL = new PokemonList2(TempBox, Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese); + var current = GetData(Offsets.CurrentBox, stored); + var curBoxPL = new PokeList2(current, capacity, Japanese); + var curDest = baseDest + (CurrentBox * SIZE_BOX); for (int i = 0; i < curBoxPL.Pokemon.Length; i++) { - if (i < curBoxPL.Count) - { - byte[] pkDat = new PokemonList2(curBoxPL[i]).GetBytes(); - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED); - } - else - { - byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)]; - pkDat.CopyTo(Data, Data.Length - SIZE_RESERVED + CurrentBox * SIZE_BOX + i * SIZE_STORED); - } + var dest = curDest + (i * SIZE_STORED); + var pkDat = i < curBoxPL.Count + ? new PokeList2(curBoxPL[i]).Write() + : new byte[PokeList2.GetDataLength(PokeListType.Single, Japanese)]; + pkDat.CopyTo(Data, dest); } - byte[] TempParty = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Party, Japanese)]; - Array.Copy(Data, Offsets.Party, TempParty, 0, TempParty.Length); - PokemonList2 partyList = new PokemonList2(TempParty, PokemonList2.CapacityType.Party, Japanese); - for (int i = 0; i < partyList.Pokemon.Length; i++) + var party = GetData(Offsets.Party, SIZE_STOREDPARTY); + var partyPL = new PokeList2(party, PokeListType.Party, Japanese); + for (int i = 0; i < partyPL.Pokemon.Length; i++) { - if (i < partyList.Count) - { - byte[] pkDat = new PokemonList2(partyList[i]).GetBytes(); - pkDat.CopyTo(Data, GetPartyOffset(i)); - } - else - { - byte[] pkDat = new byte[PokemonList2.GetDataLength(PokemonList2.CapacityType.Single, Japanese)]; - pkDat.CopyTo(Data, GetPartyOffset(i)); - } + var dest = GetPartyOffset(i); + var pkDat = i < partyPL.Count + ? new PokeList2(partyPL[i]).Write() + : new byte[PokeList2.GetDataLength(PokeListType.Single, Japanese)]; + pkDat.CopyTo(Data, dest); } // Daycare currently undocumented for all Gen II games. @@ -117,21 +104,21 @@ namespace PKHeX.Core DaycareFlags[0] = Data[offset]; offset++; var pk1 = ReadPKMFromOffset(offset); // parent 1 - var daycare1 = new PokemonList2(pk1); + var daycare1 = new PokeList2(pk1); offset += StringLength * 2 + 0x20; // nick/ot/pkm DaycareFlags[1] = Data[offset]; offset++; byte steps = Data[offset]; offset++; byte BreedMotherOrNonDitto = Data[offset]; offset++; var pk2 = ReadPKMFromOffset(offset); // parent 2 - var daycare2 = new PokemonList2(pk2); + var daycare2 = new PokeList2(pk2); offset += StringLength * 2 + PKX.SIZE_2STORED; // nick/ot/pkm var pk3 = ReadPKMFromOffset(offset); // egg! pk3.IsEgg = true; - var daycare3 = new PokemonList2(pk3); + var daycare3 = new PokeList2(pk3); - daycare1.GetBytes().CopyTo(Data, GetPartyOffset(7 + (0 * 2))); - daycare2.GetBytes().CopyTo(Data, GetPartyOffset(7 + (1 * 2))); - daycare3.GetBytes().CopyTo(Data, GetPartyOffset(7 + (2 * 2))); + daycare1.Write().CopyTo(Data, GetPartyOffset(7 + (0 * 2))); + daycare2.Write().CopyTo(Data, GetPartyOffset(7 + (1 * 2))); + daycare3.Write().CopyTo(Data, GetPartyOffset(7 + (2 * 2))); Daycare = Offsets.Daycare; } @@ -160,11 +147,20 @@ namespace PKHeX.Core public bool Korean { get; } private readonly SAV2Offsets Offsets; + private int GetBoxRawDataOffset(int i, int splitAtIndex) + { + if (i < splitAtIndex) + return 0x4000 + (i * (SIZE_STOREDBOX + 2)); + return 0x6000 + ((i - splitAtIndex) * (SIZE_STOREDBOX + 2)); + } + protected override byte[] Write(bool DSV) { + int len = SIZE_STOREDBOX; + int splitAtIndex = (Japanese ? 6 : 7); for (int i = 0; i < BoxCount; i++) { - PokemonList2 boxPL = new PokemonList2(Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese); + var boxPL = new PokeList2(Japanese ? PokeListType.StoredJP : PokeListType.Stored, Japanese); int slot = 0; for (int j = 0; j < boxPL.Pokemon.Length; j++) { @@ -172,15 +168,14 @@ namespace PKHeX.Core if (boxPK.Species > 0) boxPL[slot++] = boxPK; } - if (i < (Japanese ? 6 : 7)) - boxPL.GetBytes().CopyTo(Data, 0x4000 + i * (SIZE_STOREDBOX + 2)); - else - boxPL.GetBytes().CopyTo(Data, 0x6000 + (i - (Japanese ? 6 : 7)) * (SIZE_STOREDBOX + 2)); + + int src = GetBoxRawDataOffset(i, splitAtIndex); + boxPL.Write().CopyTo(Data, src); if (i == CurrentBox) - boxPL.GetBytes().CopyTo(Data, Offsets.CurrentBox); + boxPL.Write().CopyTo(Data, Offsets.CurrentBox); } - PokemonList2 partyPL = new PokemonList2(PokemonList2.CapacityType.Party, Japanese); + var partyPL = new PokeList2(PokeListType.Party, Japanese); int pSlot = 0; for (int i = 0; i < 6; i++) { @@ -188,7 +183,7 @@ namespace PKHeX.Core if (partyPK.Species > 0) partyPL[pSlot++] = partyPK; } - partyPL.GetBytes().CopyTo(Data, Offsets.Party); + partyPL.Write().CopyTo(Data, Offsets.Party); SetChecksums(); if (Japanese) @@ -246,7 +241,8 @@ namespace PKHeX.Core public override Type PKMType => typeof(PK2); private int SIZE_BOX => BoxSlotCount*SIZE_STORED; - private int SIZE_STOREDBOX => PokemonList2.GetDataLength(Japanese ? PokemonList2.CapacityType.StoredJP : PokemonList2.CapacityType.Stored, Japanese); + private int SIZE_STOREDBOX => PokeList2.GetDataLength(Japanese ? PokeListType.StoredJP : PokeListType.Stored, Japanese); + private int SIZE_STOREDPARTY => PokeList2.GetDataLength(PokeListType.Party, Japanese); public override int MaxMoveID => Legal.MaxMoveID_2; public override int MaxSpeciesID => Legal.MaxSpeciesID_2; @@ -482,7 +478,7 @@ namespace PKHeX.Core public override PKM GetPKM(byte[] data) { if (data.Length == SIZE_STORED) - return new PokemonList2(data, PokemonList2.CapacityType.Single, Japanese)[0]; + return new PokeList2(data, PokeListType.Single, Japanese)[0]; return new PK2(data); } public override byte[] DecryptPKM(byte[] data)