diff --git a/Misc/PKX.cs b/Misc/PKX.cs index 254c0956d..a798c9181 100644 --- a/Misc/PKX.cs +++ b/Misc/PKX.cs @@ -495,6 +495,7 @@ namespace PKHeX ekx = shuffleArray(ekx, sv); uint seed = pv; + // Encrypt Blocks with RNG Seed for (int i = 8; i < 232; i += 2) BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekx, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekx, i); @@ -572,6 +573,77 @@ namespace PKHeX return pid; } + // Past Gen Manipulation + internal static byte[] shuffleG4Array(byte[] data, uint sv) + { + byte[] sdata = new byte[PK4.SIZE_PARTY]; + Array.Copy(data, sdata, 8); // Copy unshuffled bytes + + // Shuffle Away! + for (int block = 0; block < 4; block++) + Array.Copy(data, 8 + 32 * blockPosition[block][sv], sdata, 8 + 32 * block, 32); + + // Fill the Battle Stats back + if (data.Length > 136) + Array.Copy(data, 136, sdata, 136, 100); + + return sdata; + } + internal static byte[] decryptG4Array(byte[] ekm, uint seed = 0x10000) + { + byte[] pkm = (byte[])ekm.Clone(); + + uint pv = BitConverter.ToUInt32(pkm, 0); + uint sv = (((pv & 0x3E000) >> 0xD) % 24); + + seed = seed > 0xFFFF ? pv : seed; + + // Decrypt Blocks with RNG Seed + for (int i = 8; i < 136; i += 2) + BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(pkm, i); + + // Deshuffle + pkm = shuffleG4Array(pkm, sv); + + // Decrypt the Party Stats + seed = pv; + if (pkm.Length <= 136) return pkm; + for (int i = 136; i < 236; i += 2) + BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(pkm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(pkm, i); + + return pkm; + } + internal static byte[] encryptG4Array(byte[] pkm, uint seed = 0x10000) + { + // Shuffle + uint pv = BitConverter.ToUInt32(pkm, 0); + uint sv = (((pv & 0x3E000) >> 0xD) % 24); + + byte[] ekm = (byte[])pkm.Clone(); + + // If I unshuffle 11 times, the 12th (decryption) will always decrypt to ABCD. + // 2 x 3 x 4 = 12 (possible unshuffle loops -> total iterations) + for (int i = 0; i < 11; i++) + ekm = shuffleArray(ekm, sv); + + seed = seed > 0xFFFF ? pv : seed; + + // Encrypt Blocks with RNG Seed + for (int i = 8; i < 136; i += 2) + BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekm, i); + + // If no party stats, return. + if (ekm.Length <= 136) return ekm; + + // Encrypt the Party Stats + seed = pv; + for (int i = 136; i < 236; i += 2) + BitConverter.GetBytes((ushort)(BitConverter.ToUInt16(ekm, i) ^ (LCRNG(ref seed) >> 16))).CopyTo(ekm, i); + + // Done + return ekm; + } + // SAV Manipulation /// Calculates the CRC16-CCITT checksum over an input byte array. /// Input byte array