2016-06-20 04:22:43 +00:00
|
|
|
|
using System;
|
|
|
|
|
|
|
|
|
|
namespace PKHeX
|
|
|
|
|
{
|
|
|
|
|
internal static class PKMConverter
|
|
|
|
|
{
|
2016-07-04 23:11:03 +00:00
|
|
|
|
internal static int Country = 49;
|
2016-06-20 04:22:43 +00:00
|
|
|
|
internal static int Region = 7;
|
|
|
|
|
internal static int ConsoleRegion = 1;
|
|
|
|
|
internal static string OT_Name = "PKHeX";
|
|
|
|
|
internal static int OT_Gender;
|
|
|
|
|
|
|
|
|
|
internal static void updateConfig(int SUBREGION, int COUNTRY, int _3DSREGION, string TRAINERNAME, int TRAINERGENDER)
|
|
|
|
|
{
|
|
|
|
|
Region = SUBREGION;
|
|
|
|
|
Country = COUNTRY;
|
|
|
|
|
ConsoleRegion = _3DSREGION;
|
|
|
|
|
OT_Name = TRAINERNAME;
|
|
|
|
|
OT_Gender = TRAINERGENDER;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int getPKMDataFormat(byte[] data)
|
|
|
|
|
{
|
|
|
|
|
if (!PKX.getIsPKM(data.Length))
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
switch (data.Length)
|
|
|
|
|
{
|
|
|
|
|
case PKX.SIZE_3PARTY:
|
|
|
|
|
case PKX.SIZE_3STORED:
|
|
|
|
|
return 3;
|
|
|
|
|
case PKX.SIZE_4PARTY:
|
|
|
|
|
case PKX.SIZE_4STORED:
|
|
|
|
|
case PKX.SIZE_5PARTY:
|
|
|
|
|
if ((BitConverter.ToUInt16(data, 0x80) >= 0x3333 || data[0x5F] >= 0x10) && BitConverter.ToUInt16(data, 0x46) == 0) // PK5
|
|
|
|
|
return 5;
|
|
|
|
|
return 4;
|
|
|
|
|
case PKX.SIZE_6STORED:
|
|
|
|
|
return 6;
|
|
|
|
|
case PKX.SIZE_6PARTY: // collision with PGT, same size.
|
|
|
|
|
if (BitConverter.ToUInt16(data, 0x4) != 0) // Bad Sanity?
|
|
|
|
|
return -1;
|
2016-07-04 01:27:12 +00:00
|
|
|
|
if (BitConverter.ToUInt32(data, 0x06) == PKX.getCHK(data))
|
|
|
|
|
return 6;
|
2016-06-20 04:22:43 +00:00
|
|
|
|
if (BitConverter.ToUInt16(data, 0x58) != 0) // Encrypted?
|
|
|
|
|
{
|
|
|
|
|
for (int i = data.Length - 0x10; i < data.Length; i++) // 0x10 of 00's at the end != PK6
|
|
|
|
|
if (data[i] != 0)
|
2016-07-04 01:27:12 +00:00
|
|
|
|
return 6;
|
|
|
|
|
return -1;
|
2016-06-20 04:22:43 +00:00
|
|
|
|
}
|
2016-07-04 01:27:12 +00:00
|
|
|
|
return 6;
|
2016-06-20 04:22:43 +00:00
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
2016-06-28 05:20:31 +00:00
|
|
|
|
internal static PKM getPKMfromBytes(byte[] data, string ident = null)
|
2016-06-20 04:22:43 +00:00
|
|
|
|
{
|
|
|
|
|
checkEncrypted(ref data);
|
|
|
|
|
switch (getPKMDataFormat(data))
|
|
|
|
|
{
|
|
|
|
|
case 3:
|
2016-06-28 05:20:31 +00:00
|
|
|
|
return new PK3(data, ident);
|
2016-06-20 04:22:43 +00:00
|
|
|
|
case 4:
|
2016-06-28 05:20:31 +00:00
|
|
|
|
return new PK4(data, ident);
|
2016-06-20 04:22:43 +00:00
|
|
|
|
case 5:
|
2016-06-28 05:20:31 +00:00
|
|
|
|
return new PK5(data, ident);
|
2016-06-20 04:22:43 +00:00
|
|
|
|
case 6:
|
2016-06-28 05:20:31 +00:00
|
|
|
|
return new PK6(data, ident);
|
2016-06-20 04:22:43 +00:00
|
|
|
|
default:
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
internal static PKM convertToFormat(PKM pk, int Format, out string comment)
|
|
|
|
|
{
|
|
|
|
|
if (pk == null)
|
|
|
|
|
{
|
|
|
|
|
comment = "Null input. Aborting.";
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
if (pk.Format == Format)
|
|
|
|
|
{
|
|
|
|
|
comment = "No need to convert, current format matches requested format.";
|
|
|
|
|
return pk;
|
|
|
|
|
}
|
|
|
|
|
if (pk.Format > Format)
|
|
|
|
|
{
|
|
|
|
|
comment = "Cannot convert a PKM backwards." + Environment.NewLine
|
|
|
|
|
+ "Current Format: " + pk.Format + Environment.NewLine
|
|
|
|
|
+ "Desired Format: " + Format;
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
string currentFormat = pk.Format.ToString();
|
|
|
|
|
PKM pkm = pk.Clone();
|
|
|
|
|
if (pkm.IsEgg) // force hatch
|
|
|
|
|
{
|
|
|
|
|
pkm.IsEgg = false;
|
|
|
|
|
if (pkm.AO)
|
|
|
|
|
pkm.Met_Location = 318; // Battle Resort
|
|
|
|
|
else if (pkm.XY)
|
|
|
|
|
pkm.Met_Location = 38; // Route 7
|
|
|
|
|
else if (pkm.Gen5)
|
|
|
|
|
pkm.Met_Location = 16; // Route 16
|
|
|
|
|
else
|
|
|
|
|
pkm.Met_Location = 30001; // Pokétransfer
|
|
|
|
|
}
|
|
|
|
|
if (pkm.Format == 3 && Format > 3)
|
2016-07-18 18:51:26 +00:00
|
|
|
|
pkm = ((PK3) pkm).convertToPK4();
|
2016-06-20 04:22:43 +00:00
|
|
|
|
if (pkm.Format == 4 && Format > 4)
|
2016-07-18 18:51:26 +00:00
|
|
|
|
pkm = ((PK4) pkm).convertToPK5();
|
2016-06-20 04:22:43 +00:00
|
|
|
|
if (pkm.Format == 5 && Format > 5)
|
2016-07-18 18:51:26 +00:00
|
|
|
|
pkm = ((PK5) pkm).convertToPK6();
|
2016-06-20 04:22:43 +00:00
|
|
|
|
comment = $"Converted from pk{currentFormat} to pk{Format}";
|
|
|
|
|
return pkm;
|
|
|
|
|
}
|
|
|
|
|
internal static void checkEncrypted(ref byte[] pkm)
|
|
|
|
|
{
|
|
|
|
|
int format = getPKMDataFormat(pkm);
|
|
|
|
|
ushort chk = 0;
|
|
|
|
|
switch (format)
|
|
|
|
|
{
|
|
|
|
|
case 3: // TOneverDO, nobody exports encrypted pk3s
|
|
|
|
|
return;
|
|
|
|
|
case 4:
|
|
|
|
|
case 5:
|
|
|
|
|
for (int i = 8; i < PKX.SIZE_4STORED; i += 2)
|
|
|
|
|
chk += BitConverter.ToUInt16(pkm, i);
|
|
|
|
|
if (chk != BitConverter.ToUInt16(pkm, 0x06))
|
|
|
|
|
pkm = PKX.decryptArray45(pkm);
|
|
|
|
|
return;
|
|
|
|
|
case 6:
|
|
|
|
|
if (BitConverter.ToUInt16(pkm, 0xC8) != 0 && BitConverter.ToUInt16(pkm, 0x58) != 0)
|
|
|
|
|
pkm = PKX.decryptArray(pkm);
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
return; // bad!
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|