diff --git a/Legality/Tables3.cs b/Legality/Tables3.cs
new file mode 100644
index 000000000..fb828819e
--- /dev/null
+++ b/Legality/Tables3.cs
@@ -0,0 +1,36 @@
+using System.Linq;
+
+namespace PKHeX
+{
+ public static partial class Legal
+ {
+ // PKHeX Valid Array Storage
+ #region DP
+ internal static readonly ushort[] Pouch_Items_RS = {
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 80, 81, 83, 84, 85, 86, 93, 94, 95, 96, 97, 98, 103, 104, 106, 107, 108, 109, 110, 111, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 254, 255, 256, 257, 258
+ };
+ internal static readonly ushort[] Pouch_Key_RS = {
+ 259, 260, 261, 262, 263, 264, 265, 266, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288
+ };
+ internal static readonly ushort[] Pouch_TM_RS = {
+ 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338,
+ };
+ internal static readonly ushort[] Pouch_HM_RS = {
+ 339, 340, 341, 342, 343, 344, 345, 346
+ };
+ internal static readonly ushort[] Pouch_Berries_RS = {
+ 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175
+ };
+ internal static readonly ushort[] Pouch_Ball_RS = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+ };
+ internal static readonly ushort[] Pouch_Key_E = Pouch_Key_RS.Concat(new ushort[] { 375, 376 }).ToArray();
+ internal static readonly ushort[] Pouch_Key_FRLG = Pouch_Key_RS.Concat(new ushort[] { 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374 }).ToArray();
+
+ internal static readonly ushort[] Pouch_TMHM_RS = Pouch_TM_RS.Concat(Pouch_HM_RS).ToArray();
+ internal static readonly ushort[] HeldItems_RS = new ushort[1].Concat(Pouch_Items_RS).Concat(Pouch_Ball_RS).Concat(Pouch_Berries_RS).Concat(Pouch_TM_RS).ToArray();
+ #endregion
+
+
+ }
+}
diff --git a/PKHeX.csproj b/PKHeX.csproj
index bb15760cd..c3c813445 100644
--- a/PKHeX.csproj
+++ b/PKHeX.csproj
@@ -71,6 +71,7 @@
+
@@ -92,6 +93,7 @@
+
diff --git a/PKM/PK3.cs b/PKM/PK3.cs
index d2e9f9a29..7594f9127 100644
--- a/PKM/PK3.cs
+++ b/PKM/PK3.cs
@@ -5,6 +5,10 @@ namespace PKHeX
{
public class PK3 : PKM // 3rd Generation PKM File
{
+ internal static readonly byte[] ExtraBytes =
+ {
+ 0x2A, 0x2B
+ };
public override int SIZE_PARTY => PKX.SIZE_3PARTY;
public override int SIZE_STORED => PKX.SIZE_3STORED;
public override int Format => 3;
@@ -22,7 +26,8 @@ public PK3(byte[] decryptedData = null, string ident = null)
public override uint EncryptionConstant { get { return PID; } set { } }
public override int Nature { get { return (int)(PID % 25); } set { } }
public override int AltForm { get { return -1; } set { } }
- public override bool IsNicknamed { get { return Nickname != PKX.getSpeciesName(Species, Language); } set { } }
+
+ public override bool IsNicknamed { get { return PKX.getIsNicknamed(Species, Nickname); } set { } }
public override int Gender { get { return PKX.getGender(Species, PID); } set { } }
public override int Characteristic => -1;
public override int CurrentFriendship { get { return OT_Friendship; } set { OT_Friendship = value; } }
@@ -41,7 +46,7 @@ public PK3(byte[] decryptedData = null, string ident = null)
if (strdata.Length > 10)
Array.Resize(ref strdata, 10);
strdata.CopyTo(Data, 0x08); } }
- public override int Language { get { return BitConverter.ToUInt16(Data, 0x12); } set { BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x12); } }
+ public override int Language { get { return BitConverter.ToUInt16(Data, 0x12) & 0xFF; } set { BitConverter.GetBytes((ushort)(value | 0x200)).CopyTo(Data, 0x12); } }
public override string OT_Name {
get { return PKX.getG3Str(Data.Skip(0x14).Take(7).ToArray(), Japanese); }
set { byte[] strdata = PKX.setG3Str(value, Japanese);
@@ -55,7 +60,9 @@ public PK3(byte[] decryptedData = null, string ident = null)
#region Block A
public override int Species { get { return PKX.getG4Species(BitConverter.ToUInt16(Data, 0x20)); } set { BitConverter.GetBytes((ushort)PKX.getG3Species(value)).CopyTo(Data, 0x20); } }
- public override int HeldItem { get { return BitConverter.ToUInt16(Data, 0x22); } set { BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x22); } }
+ public override int HeldItem { get { return PKX.getG4Item((ushort)G3Item); } set { } }
+ public int G3Item { get { return PKX.getG4Item(BitConverter.ToUInt16(Data, 0x22)); } set { BitConverter.GetBytes((ushort) value).CopyTo(Data, 0x22); } }
+
public override uint EXP { get { return BitConverter.ToUInt32(Data, 0x24); } set { BitConverter.GetBytes(value).CopyTo(Data, 0x24); } }
private byte PPUps { get { return Data[0x28]; } set { Data[0x28] = value; } }
public override int Move1_PPUps { get { return (PPUps >> 0) & 3; } set { PPUps = (byte)((PPUps & ~(3 << 0)) | value); } }
@@ -154,7 +161,7 @@ public PK3(byte[] decryptedData = null, string ident = null)
public override byte[] Encrypt()
{
- throw new NotImplementedException();
+ return PKX.encryptArray3(Data);
}
public override bool getGenderIsValid()
{
@@ -277,7 +284,7 @@ public PK4 convertToPK4()
// Set Final Data
pk4.Met_Level = PKX.getLevel(pk4.Species, pk4.EXP);
pk4.Gender = PKX.getGender(pk4.Species, pk4.PID);
- pk4.IsNicknamed |= pk4.Nickname != PKX.getSpeciesName(pk4.Species, pk4.Language);
+ pk4.IsNicknamed = IsNicknamed;
// Unown Form
if (Species == 201)
diff --git a/PKM/PKM.cs b/PKM/PKM.cs
index c97495089..eabb37437 100644
--- a/PKM/PKM.cs
+++ b/PKM/PKM.cs
@@ -19,13 +19,20 @@ public abstract class PKM
public byte[] DecryptedPartyData => Write().Take(SIZE_PARTY).ToArray();
public byte[] DecryptedBoxData => Write().Take(SIZE_STORED).ToArray();
- public ushort CalculateChecksum()
+ protected ushort CalculateChecksum()
{
ushort chk = 0;
- for (int i = 8; i < SIZE_STORED; i += 2) // Loop through the entire PK5
- chk += BitConverter.ToUInt16(Data, i);
-
- return chk;
+ switch (Format)
+ {
+ case 3:
+ for (int i = 32; i < SIZE_STORED; i += 2)
+ chk += BitConverter.ToUInt16(Data, i);
+ return chk;
+ default: // 4+
+ for (int i = 8; i < SIZE_STORED; i += 2)
+ chk += BitConverter.ToUInt16(Data, i);
+ return chk;
+ }
}
public abstract byte[] Encrypt();
public abstract int Format { get; }
diff --git a/PKM/PKX.cs b/PKM/PKX.cs
index ce0a66a5b..1df311e9f 100644
--- a/PKM/PKX.cs
+++ b/PKM/PKX.cs
@@ -176,6 +176,11 @@ internal static string getSpeciesName(int species, int lang)
try { return SpeciesLang[lang][species]; }
catch { return ""; }
}
+ internal static bool getIsNicknamed(int species, string nick)
+ {
+ try { return SpeciesLang.All(list => list[species].ToUpper() != nick); }
+ catch { return false; }
+ }
internal static readonly PersonalInfo[] Personal = Legal.PersonalAO;
// Stat Fetching
@@ -1628,7 +1633,7 @@ internal static int getGender(int species, uint PID)
new byte[] {0x1a, 0x1a}, // 381
new byte[] {0x02, 0x02}, // 382
new byte[] {0x46, 0x46}, // 383
- new byte[] {0x4c, 0x4c}, // 384
+ new byte[] {0x4d, 0x4d}, // 384
new byte[] {0x20, 0x20}, // 385
new byte[] {0x2e, 0x2e}, // 386
};
@@ -2039,5 +2044,86 @@ internal static int getGender(int species, uint PID)
new byte[] { }, // Unused
new byte[] { 0x74, 0x20, 0x0D, 0x02, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA4, 0xA1, 0x0C, 0x02, 0xE0, 0xFF },
};
+
+ internal static byte[] decryptArray3(byte[] ekm)
+ {
+ if (ekm.Length != SIZE_3PARTY && ekm.Length != SIZE_3STORED)
+ return null;
+
+ uint PID = BitConverter.ToUInt32(ekm, 0);
+ uint OID = BitConverter.ToUInt32(ekm, 4);
+ uint seed = PID ^ OID;
+
+ byte[] xorkey = BitConverter.GetBytes(seed);
+ for (int i = 32; i < 80; i++)
+ ekm[i] ^= xorkey[i % 4];
+ return shuffleArray3(ekm, PID%24);
+ }
+ internal static byte[] shuffleArray3(byte[] data, uint sv)
+ {
+ byte[] sdata = new byte[data.Length];
+ Array.Copy(data, sdata, 32); // Copy unshuffled bytes
+
+ // Shuffle Away!
+ for (int block = 0; block < 4; block++)
+ Array.Copy(data, 32 + 12 * blockPosition[block][sv], sdata, 32 + 12 * block, 12);
+
+ // Fill the Battle Stats back
+ if (data.Length > SIZE_3STORED)
+ Array.Copy(data, SIZE_3STORED, sdata, SIZE_3STORED, data.Length - SIZE_3STORED);
+
+ return sdata;
+ }
+ internal static byte[] encryptArray3(byte[] pkm)
+ {
+ if (pkm.Length != SIZE_3PARTY && pkm.Length != SIZE_3STORED)
+ return null;
+
+ uint PID = BitConverter.ToUInt32(pkm, 0);
+ uint OID = BitConverter.ToUInt32(pkm, 4);
+ uint seed = PID ^ OID;
+
+ byte[] ekm = shuffleArray3(pkm, blockPositionInvert[PID%24]);
+ byte[] xorkey = BitConverter.GetBytes(seed);
+ for (int i = 32; i < 80; i++)
+ ekm[i] ^= xorkey[i % 4];
+ return ekm;
+ }
+
+ internal static ushort getG4Item(ushort g3val)
+ {
+ ushort[] arr =
+ {
+ 0,1,2,3,4,5,6,7,8,9,
+ 10,11,12,17,18,19,20,21,22,23,
+ 24,25,26,27,28,29,30,31,32,33,
+ 34,35,36,37,38,39,40,41,42,65,
+ 66,67,68,69,43,44,70,71,72,73,
+ 74,75,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,45,46,47,48,49,50,51,
+ 52,53,0xFFFF,55,56,57,58,59,60,0xFFFF,
+ 63,64,0xFFFF,76,77,78,79,0xFFFF,0xFFFF,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,80,81,82,83,84,85,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,86,87,0xFFFF,88,89,90,91,
+ 92,93,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,149,150,151,152,153,154,155,
+ 156,157,158,159,160,161,162,163,164,165,
+ 166,167,168,169,170,171,172,173,174,175,
+ 176,177,178,179,180,181,182,183,201,202,
+ 203,204,205,206,207,208,0xFFFF,0xFFFF,0xFFFF,213,
+ 214,215,216,217,218,219,220,221,222,223,
+ 224,225,226,227,228,229,230,231,232,233,
+ 234,235,236,237,238,239,240,241,242,243,
+ 244,245,246,247,248,249,250,251,252,253,
+ 254,255,256,257,258,259,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
+ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,260,261,262,263,264,
+ };
+ if (g3val > arr.Length)
+ return 0xFFFF;
+ return arr[g3val];
+ }
}
}
diff --git a/PKX/f1-Main.cs b/PKX/f1-Main.cs
index deb0812db..d51c5a9e5 100644
--- a/PKX/f1-Main.cs
+++ b/PKX/f1-Main.cs
@@ -724,48 +724,38 @@ private void openSAV(byte[] input, string path)
// Generational Interface
byte[] extraBytes = new byte[1];
Tip1.RemoveAll(); Tip2.RemoveAll(); Tip3.RemoveAll(); // TSV/PSV
+
+ CB_Country.Visible = CB_SubRegion.Visible = CB_3DSReg.Visible =
+ Label_Country.Visible = Label_SubRegion.Visible = Label_3DSRegion.Visible = SAV.Generation >= 6;
+ CB_Ability.Visible = TB_AbilityNumber.Visible = SAV.Generation >= 6;
+ Label_EncryptionConstant.Visible = BTN_RerollEC.Visible = TB_EC.Visible = SAV.Generation >= 6;
+ GB_nOT.Visible = GB_RelearnMoves.Visible = BTN_History.Visible = BTN_Ribbons.Visible = SAV.Generation >= 6;
+ PB_Legal.Visible = PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = SAV.Generation >= 6;
+
+ PB_MarkPentagon.Visible = SAV.Generation == 6;
+ PB_Legal.Visible = PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = SAV.Generation == 6;
+ TB_GameSync.Visible = TB_Secure1.Visible = TB_Secure2.Visible = L_GameSync.Visible = L_Secure1.Visible = L_Secure2.Visible = SAV.Generation == 6;
+
+ CB_Form.Visible = Label_Form.Visible = CHK_AsEgg.Visible = GB_EggConditions.Visible =
+ Label_MetDate.Visible = CAL_MetDate.Visible = PB_Mark5.Visible = PB_Mark6.Visible = SAV.Generation >= 4;
+
+ DEV_Ability.Enabled = DEV_Ability.Visible = SAV.Generation < 6 || HaX;
+ TB_AbilityNumber.Visible = SAV.Generation >= 6 && !HaX;
+ CB_Ability.Visible = SAV.Generation >= 6 && !HaX;
+
switch (SAV.Generation)
{
+ case 3:
+ extraBytes = PK3.ExtraBytes;
+ break;
case 4:
- TB_GameSync.Visible = TB_Secure1.Visible = TB_Secure2.Visible = false;
- L_GameSync.Visible = L_Secure1.Visible = L_Secure2.Visible = false;
- CB_Country.Visible = CB_SubRegion.Visible = CB_3DSReg.Visible = false;
- Label_Country.Visible = Label_SubRegion.Visible = Label_3DSRegion.Visible = false;
- CB_Ability.Visible = TB_AbilityNumber.Visible = false;
- GB_nOT.Visible = GB_RelearnMoves.Visible = BTN_History.Visible = BTN_Ribbons.Visible = false;
- Label_EncryptionConstant.Visible = BTN_RerollEC.Visible = TB_EC.Visible = false;
- PB_MarkPentagon.Visible = false;
- PB_Legal.Visible = PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = false;
-
- DEV_Ability.Enabled = DEV_Ability.Visible = true;
+
extraBytes = PK4.ExtraBytes;
break;
case 5:
- TB_GameSync.Visible = TB_Secure1.Visible = TB_Secure2.Visible = false;
- L_GameSync.Visible = L_Secure1.Visible = L_Secure2.Visible = false;
- CB_Country.Visible = CB_SubRegion.Visible = CB_3DSReg.Visible = false;
- Label_Country.Visible = Label_SubRegion.Visible = Label_3DSRegion.Visible = false;
- CB_Ability.Visible = TB_AbilityNumber.Visible = false;
- GB_nOT.Visible = GB_RelearnMoves.Visible = BTN_History.Visible = BTN_Ribbons.Visible = false;
- Label_EncryptionConstant.Visible = BTN_RerollEC.Visible = TB_EC.Visible = false;
- PB_MarkPentagon.Visible = false;
- PB_Legal.Visible = PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = false;
-
- DEV_Ability.Enabled = DEV_Ability.Visible = true;
extraBytes = PK5.ExtraBytes;
break;
case 6:
- TB_GameSync.Visible = TB_Secure1.Visible = TB_Secure2.Visible = true;
- L_GameSync.Visible = L_Secure1.Visible = L_Secure2.Visible = true;
- CB_Country.Visible = CB_SubRegion.Visible = CB_3DSReg.Visible = true;
- Label_Country.Visible = Label_SubRegion.Visible = Label_3DSRegion.Visible = true;
- DEV_Ability.Enabled = DEV_Ability.Visible = TB_AbilityNumber.Visible = HaX;
- GB_nOT.Visible = BTN_History.Visible = true;
- Label_EncryptionConstant.Visible = BTN_RerollEC.Visible = TB_EC.Visible = true;
- PB_MarkPentagon.Visible = true;
- PB_Legal.Visible = PB_WarnMove1.Visible = PB_WarnMove2.Visible = PB_WarnMove3.Visible = PB_WarnMove4.Visible = true;
-
- CB_Ability.Visible = !HaX;
extraBytes = PK6.ExtraBytes;
TB_GameSync.Enabled = (SAV as SAV6).GameSyncID != 0;
TB_GameSync.Text = (SAV as SAV6).GameSyncID.ToString("X16");
@@ -1017,7 +1007,7 @@ private void populateFilteredDataSources()
CB_Ball.DataSource = new BindingSource(BallDataSource.Where(b => b.Value <= SAV.MaxBallID), null);
CB_Species.DataSource = new BindingSource(SpeciesDataSource.Where(s => s.Value <= SAV.MaxSpeciesID), null);
DEV_Ability.DataSource = new BindingSource(AbilityDataSource.Where(a => a.Value <= SAV.MaxAbilityID), null);
- CB_GameOrigin.DataSource = new BindingSource(VersionDataSource.Where(g => g.Value <= SAV.MaxGameID), null);
+ CB_GameOrigin.DataSource = new BindingSource(VersionDataSource.Where(g => g.Value <= SAV.MaxGameID || SAV.Generation >= 3 && g.Value == 15), null);
// Set the Move ComboBoxes too..
foreach (ComboBox cb in new[] { CB_Move1, CB_Move2, CB_Move3, CB_Move4, CB_RelearnMove1, CB_RelearnMove2, CB_RelearnMove3, CB_RelearnMove4 })
@@ -1040,6 +1030,9 @@ public void populateFields(PKM pk, bool focus = true)
Util.Alert("PKX File has an invalid checksum.");
switch (pkm.Format)
{
+ case 3:
+ populateFieldsPK3(pkm as PK3);
+ break;
case 4:
populateFieldsPK4(pkm as PK4);
break;
@@ -1077,6 +1070,97 @@ public void populateFields(PKM pk, bool focus = true)
dragout.Image = pk.Sprite;
updateLegality();
}
+ private void populateFieldsPK3(PK3 pk3)
+ {
+ // Do first
+ pk3.Stat_Level = PKX.getLevel(pk3.Species, pk3.EXP);
+ if (pk3.Stat_Level == 100)
+ pk3.EXP = PKX.getEXP(pk3.Stat_Level, pk3.Species);
+
+ CB_Species.SelectedValue = pk3.Species;
+ TB_Level.Text = pk3.Stat_Level.ToString();
+ TB_EXP.Text = pk3.EXP.ToString();
+
+ // Load rest
+ CHK_Fateful.Checked = pk3.FatefulEncounter;
+ CHK_IsEgg.Checked = pk3.IsEgg;
+ CHK_Nicknamed.Checked = pk3.IsNicknamed;
+ Label_OTGender.Text = gendersymbols[pk3.OT_Gender];
+ Label_OTGender.ForeColor = pk3.OT_Gender == 1 ? Color.Red : Color.Blue;
+ TB_PID.Text = pk3.PID.ToString("X8");
+ CB_HeldItem.SelectedValue = pk3.HeldItem;
+ setAbilityList(TB_AbilityNumber, pk3.Species, CB_Ability, CB_Form);
+ DEV_Ability.SelectedValue = pk3.Ability;
+ CB_Nature.SelectedValue = pk3.Nature;
+ TB_TID.Text = pk3.TID.ToString("00000");
+ TB_SID.Text = pk3.SID.ToString("00000");
+ TB_Nickname.Text = pk3.Nickname;
+ TB_OT.Text = pk3.OT_Name;
+ TB_Friendship.Text = pk3.CurrentFriendship.ToString();
+ GB_OT.BackgroundImage = null;
+ CB_Language.SelectedValue = pk3.Language;
+ CB_GameOrigin.SelectedValue = pk3.Version;
+ CB_EncounterType.SelectedValue = pk3.Gen4 ? pk3.EncounterType : 0;
+ CB_Ball.SelectedValue = pk3.Ball;
+
+ CB_MetLocation.SelectedValue = pk3.Met_Location;
+
+ TB_MetLevel.Text = pk3.Met_Level.ToString();
+
+ // Reset Label and ComboBox visibility, as well as non-data checked status.
+ Label_PKRS.Visible = CB_PKRSStrain.Visible = CHK_Infected.Checked = pk3.PKRS_Strain != 0;
+ Label_PKRSdays.Visible = CB_PKRSDays.Visible = pk3.PKRS_Days != 0;
+
+ // Set SelectedIndexes for PKRS
+ CB_PKRSStrain.SelectedIndex = pk3.PKRS_Strain;
+ CHK_Cured.Checked = pk3.PKRS_Strain > 0 && pk3.PKRS_Days == 0;
+ CB_PKRSDays.SelectedIndex = Math.Min(CB_PKRSDays.Items.Count - 1, pk3.PKRS_Days); // to strip out bad hacked 'rus
+
+ TB_Cool.Text = pk3.CNT_Cool.ToString();
+ TB_Beauty.Text = pk3.CNT_Beauty.ToString();
+ TB_Cute.Text = pk3.CNT_Cute.ToString();
+ TB_Smart.Text = pk3.CNT_Smart.ToString();
+ TB_Tough.Text = pk3.CNT_Tough.ToString();
+ TB_Sheen.Text = pk3.CNT_Sheen.ToString();
+
+ TB_HPIV.Text = pk3.IV_HP.ToString();
+ TB_ATKIV.Text = pk3.IV_ATK.ToString();
+ TB_DEFIV.Text = pk3.IV_DEF.ToString();
+ TB_SPEIV.Text = pk3.IV_SPE.ToString();
+ TB_SPAIV.Text = pk3.IV_SPA.ToString();
+ TB_SPDIV.Text = pk3.IV_SPD.ToString();
+ CB_HPType.SelectedValue = pk3.HPType;
+
+ TB_HPEV.Text = pk3.EV_HP.ToString();
+ TB_ATKEV.Text = pk3.EV_ATK.ToString();
+ TB_DEFEV.Text = pk3.EV_DEF.ToString();
+ TB_SPEEV.Text = pk3.EV_SPE.ToString();
+ TB_SPAEV.Text = pk3.EV_SPA.ToString();
+ TB_SPDEV.Text = pk3.EV_SPD.ToString();
+
+ CB_Move1.SelectedValue = pk3.Move1;
+ CB_Move2.SelectedValue = pk3.Move2;
+ CB_Move3.SelectedValue = pk3.Move3;
+ CB_Move4.SelectedValue = pk3.Move4;
+ CB_PPu1.SelectedIndex = pk3.Move1_PPUps;
+ CB_PPu2.SelectedIndex = pk3.Move2_PPUps;
+ CB_PPu3.SelectedIndex = pk3.Move3_PPUps;
+ CB_PPu4.SelectedIndex = pk3.Move4_PPUps;
+ TB_PP1.Text = pk3.Move1_PP.ToString();
+ TB_PP2.Text = pk3.Move2_PP.ToString();
+ TB_PP3.Text = pk3.Move3_PP.ToString();
+ TB_PP4.Text = pk3.Move4_PP.ToString();
+
+ // Load Extrabyte Value
+ TB_ExtraByte.Text = pk3.Data[Convert.ToInt32(CB_ExtraBytes.Text, 16)].ToString();
+
+ updateStats();
+ setIsShiny();
+
+ TB_EXP.Text = pk3.EXP.ToString();
+ Label_Gender.Text = gendersymbols[pk3.Gender];
+ Label_Gender.ForeColor = pk3.Gender == 2 ? Label_Species.ForeColor : (pk3.Gender == 1 ? Color.Red : Color.Blue);
+ }
private void populateFieldsPK4(PK4 pk4)
{
// Do first
@@ -1493,6 +1577,27 @@ internal static void setAbilityList(MaskedTextBox tb_abil, int species, ComboBox
cb_abil.SelectedIndex = newabil < 3 ? newabil : 0;
}
+ private void setAbilityList3(MaskedTextBox tb_abil, int species, ComboBox cb_abil, ComboBox cb_forme)
+ {
+ if (!fieldsInitialized && string.IsNullOrWhiteSpace(tb_abil.Text))
+ return;
+ int newabil = Convert.ToInt16(tb_abil.Text) >> 1;
+
+ int form = cb_forme.SelectedIndex;
+ byte[] abils = PKX.Gen3Abilities[Util.getIndex(CB_Species)];
+ if (abils[0] == 76) abils[0] = 77; // Air Lock +1
+ if (abils[1] == 76) abils[1] = 77; // Air Lock +1
+
+ // Build Ability List
+ List ability_list = new List
+ {
+ abilitylist[abils[0]] + " (1)",
+ abilitylist[abils[1]] + " (2)",
+ };
+ cb_abil.DataSource = ability_list;
+
+ cb_abil.SelectedIndex = newabil < 3 ? newabil : 0;
+ }
// PKX Data Calculation Functions //
private void setIsShiny()
{
@@ -1789,7 +1894,10 @@ private void updateIVs(object sender, EventArgs e)
TB_IVTotal.Text = pkm.IVs.Sum().ToString();
- L_Characteristic.Text = characteristics[pkm.Characteristic];
+ int characteristic = pkm.Characteristic;
+ L_Characteristic.Visible = characteristic > -1;
+ if (characteristic > -1)
+ L_Characteristic.Text = characteristics[pkm.Characteristic];
updateStats();
}
private void updateEVs(object sender, EventArgs e)
@@ -2232,27 +2340,26 @@ private void updateNatureModification(object sender, EventArgs e)
private void updateNickname(object sender, EventArgs e)
{
if (fieldsInitialized && ModifierKeys == Keys.Control && sender != null) // Import Showdown
- {
- clickShowdownImportPK6(sender, e);
- return;
- }
+ { clickShowdownImportPK6(sender, e); return; }
if (fieldsInitialized && ModifierKeys == Keys.Alt && sender != null) // Export Showdown
- {
- clickShowdownExportPK6(sender, e);
- return;
- }
- if (!fieldsInitialized || CHK_Nicknamed.Checked) return;
+ { clickShowdownExportPK6(sender, e); return; }
+ if (!fieldsInitialized || CHK_Nicknamed.Checked)
+ return;
// Fetch Current Species and set it as Nickname Text
int species = Util.getIndex(CB_Species);
- if (species == 0 || species > 721)
+ if (species < 1 || species > SAV.MaxSpeciesID)
TB_Nickname.Text = "";
else
{
// get language
int lang = Util.getIndex(CB_Language);
if (CHK_IsEgg.Checked) species = 0; // Set species to 0 to get the egg name.
- TB_Nickname.Text = PKX.getSpeciesName(CHK_IsEgg.Checked ? 0 : species, lang);
+ string nick = PKX.getSpeciesName(CHK_IsEgg.Checked ? 0 : species, lang);
+
+ if (SAV.Generation < 5) // All caps GenIV and previous
+ nick = nick.ToUpper();
+ TB_Nickname.Text = nick;
}
}
private void updateNicknameClick(object sender, MouseEventArgs e)
@@ -2666,6 +2773,9 @@ public PKM preparePKM(bool click = true)
PKM pk = null;
switch (pkm.Format)
{
+ case 3:
+ pk = preparePK3();
+ break;
case 4:
pk = preparePK4();
break;
@@ -2678,6 +2788,95 @@ public PKM preparePKM(bool click = true)
}
return pk?.Clone();
}
+ private PK3 preparePK3()
+ {
+ PK3 pk3 = pkm as PK3;
+ if (pk3 == null)
+ return null;
+
+ pk3.Species = Util.getIndex(CB_Species);
+ pk3.G3Item = Util.getIndex(CB_HeldItem);
+ pk3.TID = Util.ToInt32(TB_TID.Text);
+ pk3.SID = Util.ToInt32(TB_SID.Text);
+ pk3.EXP = Util.ToUInt32(TB_EXP.Text);
+ pk3.PID = Util.getHEXval(TB_PID.Text);
+ pk3.Ability = (byte)Util.getIndex(DEV_Ability);
+ //pk4.Ability = (byte)Array.IndexOf(abilitylist, CB_Ability.Text.Remove(CB_Ability.Text.Length - 4));
+
+ pk3.FatefulEncounter = CHK_Fateful.Checked;
+ pk3.Gender = PKX.getGender(Label_Gender.Text);
+ pk3.EV_HP = Util.ToInt32(TB_HPEV.Text);
+ pk3.EV_ATK = Util.ToInt32(TB_ATKEV.Text);
+ pk3.EV_DEF = Util.ToInt32(TB_DEFEV.Text);
+ pk3.EV_SPE = Util.ToInt32(TB_SPEEV.Text);
+ pk3.EV_SPA = Util.ToInt32(TB_SPAEV.Text);
+ pk3.EV_SPD = Util.ToInt32(TB_SPDEV.Text);
+
+ pk3.CNT_Cool = Util.ToInt32(TB_Cool.Text);
+ pk3.CNT_Beauty = Util.ToInt32(TB_Beauty.Text);
+ pk3.CNT_Cute = Util.ToInt32(TB_Cute.Text);
+ pk3.CNT_Smart = Util.ToInt32(TB_Smart.Text);
+ pk3.CNT_Tough = Util.ToInt32(TB_Tough.Text);
+ pk3.CNT_Sheen = Util.ToInt32(TB_Sheen.Text);
+
+ pk3.PKRS_Days = CB_PKRSDays.SelectedIndex;
+ pk3.PKRS_Strain = CB_PKRSStrain.SelectedIndex;
+ pk3.Nickname = TB_Nickname.Text;
+ pk3.Move1 = Util.getIndex(CB_Move1);
+ pk3.Move2 = Util.getIndex(CB_Move2);
+ pk3.Move3 = Util.getIndex(CB_Move3);
+ pk3.Move4 = Util.getIndex(CB_Move4);
+ pk3.Move1_PP = Util.getIndex(CB_Move1) > 0 ? Util.ToInt32(TB_PP1.Text) : 0;
+ pk3.Move2_PP = Util.getIndex(CB_Move2) > 0 ? Util.ToInt32(TB_PP2.Text) : 0;
+ pk3.Move3_PP = Util.getIndex(CB_Move3) > 0 ? Util.ToInt32(TB_PP3.Text) : 0;
+ pk3.Move4_PP = Util.getIndex(CB_Move4) > 0 ? Util.ToInt32(TB_PP4.Text) : 0;
+ pk3.Move1_PPUps = Util.getIndex(CB_Move1) > 0 ? CB_PPu1.SelectedIndex : 0;
+ pk3.Move2_PPUps = Util.getIndex(CB_Move2) > 0 ? CB_PPu2.SelectedIndex : 0;
+ pk3.Move3_PPUps = Util.getIndex(CB_Move3) > 0 ? CB_PPu3.SelectedIndex : 0;
+ pk3.Move4_PPUps = Util.getIndex(CB_Move4) > 0 ? CB_PPu4.SelectedIndex : 0;
+
+ pk3.IV_HP = Util.ToInt32(TB_HPIV.Text);
+ pk3.IV_ATK = Util.ToInt32(TB_ATKIV.Text);
+ pk3.IV_DEF = Util.ToInt32(TB_DEFIV.Text);
+ pk3.IV_SPE = Util.ToInt32(TB_SPEIV.Text);
+ pk3.IV_SPA = Util.ToInt32(TB_SPAIV.Text);
+ pk3.IV_SPD = Util.ToInt32(TB_SPDIV.Text);
+ pk3.IsEgg = CHK_IsEgg.Checked;
+ pk3.IsNicknamed = CHK_Nicknamed.Checked;
+
+ pk3.OT_Name = TB_OT.Text;
+ pk3.CurrentFriendship = Util.ToInt32(TB_Friendship.Text);
+
+ pk3.Ball = Util.getIndex(CB_Ball);
+ pk3.Met_Level = Util.ToInt32(TB_MetLevel.Text);
+ pk3.OT_Gender = PKX.getGender(Label_OTGender.Text);
+ pk3.Version = Util.getIndex(CB_GameOrigin);
+ pk3.Language = Util.getIndex(CB_Language);
+
+ pk3.Met_Location = Util.getIndex(CB_MetLocation);
+
+ // Toss in Party Stats
+ Array.Resize(ref pk3.Data, pk3.SIZE_PARTY);
+ pk3.Stat_Level = Util.ToInt32(TB_Level.Text);
+ pk3.Stat_HPCurrent = Util.ToInt32(Stat_HP.Text);
+ pk3.Stat_HPMax = Util.ToInt32(Stat_HP.Text);
+ pk3.Stat_ATK = Util.ToInt32(Stat_ATK.Text);
+ pk3.Stat_DEF = Util.ToInt32(Stat_DEF.Text);
+ pk3.Stat_SPE = Util.ToInt32(Stat_SPE.Text);
+ pk3.Stat_SPA = Util.ToInt32(Stat_SPA.Text);
+ pk3.Stat_SPD = Util.ToInt32(Stat_SPD.Text);
+
+ if (HaX)
+ {
+ pk3.Stat_Level = (byte)Math.Min(Convert.ToInt32(MT_Level.Text), byte.MaxValue);
+ }
+
+ // Fix Moves if a slot is empty
+ pk3.FixMoves();
+
+ pk3.RefreshChecksum();
+ return pk3;
+ }
private PK4 preparePK4()
{
PK4 pk4 = pkm as PK4;
@@ -2692,8 +2891,7 @@ private PK4 preparePK4()
pk4.PID = Util.getHEXval(TB_PID.Text);
pk4.Ability = (byte)Util.getIndex(DEV_Ability);
//pk4.Ability = (byte)Array.IndexOf(abilitylist, CB_Ability.Text.Remove(CB_Ability.Text.Length - 4));
-
- pk4.Nature = (byte)Util.getIndex(CB_Nature);
+
pk4.FatefulEncounter = CHK_Fateful.Checked;
pk4.Gender = PKX.getGender(Label_Gender.Text);
pk4.AltForm = (MT_Form.Enabled ? Convert.ToInt32(MT_Form.Text) : CB_Form.SelectedIndex) & 0x1F;
diff --git a/SAV/SAV_SimpleTrainer.Designer.cs b/SAV/SAV_SimpleTrainer.Designer.cs
index e95c93130..5ccfc3300 100644
--- a/SAV/SAV_SimpleTrainer.Designer.cs
+++ b/SAV/SAV_SimpleTrainer.Designer.cs
@@ -28,11 +28,11 @@ protected override void Dispose(bool disposing)
///
private void InitializeComponent()
{
- this.groupBox2 = new System.Windows.Forms.GroupBox();
+ this.GB_Adventure = new System.Windows.Forms.GroupBox();
this.L_Started = new System.Windows.Forms.Label();
this.CAL_AdventureStartDate = new System.Windows.Forms.DateTimePicker();
this.CAL_HoFDate = new System.Windows.Forms.DateTimePicker();
- this.L_LastSaved = new System.Windows.Forms.Label();
+ this.L_Fame = new System.Windows.Forms.Label();
this.MT_Seconds = new System.Windows.Forms.MaskedTextBox();
this.MT_Hours = new System.Windows.Forms.MaskedTextBox();
this.L_Seconds = new System.Windows.Forms.Label();
@@ -62,8 +62,8 @@ private void InitializeComponent()
this.L_X = new System.Windows.Forms.Label();
this.B_Save = new System.Windows.Forms.Button();
this.B_Cancel = new System.Windows.Forms.Button();
- this.groupBox1 = new System.Windows.Forms.GroupBox();
- this.groupBox3 = new System.Windows.Forms.GroupBox();
+ this.GB_Trainer = new System.Windows.Forms.GroupBox();
+ this.GB_Badges = new System.Windows.Forms.GroupBox();
this.CHK_H8 = new System.Windows.Forms.CheckBox();
this.CHK_H7 = new System.Windows.Forms.CheckBox();
this.CHK_H6 = new System.Windows.Forms.CheckBox();
@@ -80,36 +80,36 @@ private void InitializeComponent()
this.CHK_3 = new System.Windows.Forms.CheckBox();
this.CHK_2 = new System.Windows.Forms.CheckBox();
this.CHK_1 = new System.Windows.Forms.CheckBox();
- this.groupBox2.SuspendLayout();
+ this.GB_Adventure.SuspendLayout();
this.GB_Map.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.NUD_Z)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_M)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_Y)).BeginInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_X)).BeginInit();
- this.groupBox1.SuspendLayout();
- this.groupBox3.SuspendLayout();
+ this.GB_Trainer.SuspendLayout();
+ this.GB_Badges.SuspendLayout();
this.SuspendLayout();
//
- // groupBox2
+ // GB_Adventure
//
- this.groupBox2.Controls.Add(this.L_Started);
- this.groupBox2.Controls.Add(this.CAL_AdventureStartDate);
- this.groupBox2.Controls.Add(this.CAL_HoFDate);
- this.groupBox2.Controls.Add(this.L_LastSaved);
- this.groupBox2.Controls.Add(this.MT_Seconds);
- this.groupBox2.Controls.Add(this.MT_Hours);
- this.groupBox2.Controls.Add(this.L_Seconds);
- this.groupBox2.Controls.Add(this.L_Hours);
- this.groupBox2.Controls.Add(this.MT_Minutes);
- this.groupBox2.Controls.Add(this.L_Minutes);
- this.groupBox2.Controls.Add(this.CAL_AdventureStartTime);
- this.groupBox2.Controls.Add(this.CAL_HoFTime);
- this.groupBox2.Location = new System.Drawing.Point(12, 98);
- this.groupBox2.Name = "groupBox2";
- this.groupBox2.Size = new System.Drawing.Size(200, 151);
- this.groupBox2.TabIndex = 70;
- this.groupBox2.TabStop = false;
- this.groupBox2.Text = "Adventure Info";
+ this.GB_Adventure.Controls.Add(this.L_Started);
+ this.GB_Adventure.Controls.Add(this.CAL_AdventureStartDate);
+ this.GB_Adventure.Controls.Add(this.CAL_HoFDate);
+ this.GB_Adventure.Controls.Add(this.L_Fame);
+ this.GB_Adventure.Controls.Add(this.MT_Seconds);
+ this.GB_Adventure.Controls.Add(this.MT_Hours);
+ this.GB_Adventure.Controls.Add(this.L_Seconds);
+ this.GB_Adventure.Controls.Add(this.L_Hours);
+ this.GB_Adventure.Controls.Add(this.MT_Minutes);
+ this.GB_Adventure.Controls.Add(this.L_Minutes);
+ this.GB_Adventure.Controls.Add(this.CAL_AdventureStartTime);
+ this.GB_Adventure.Controls.Add(this.CAL_HoFTime);
+ this.GB_Adventure.Location = new System.Drawing.Point(11, 98);
+ this.GB_Adventure.Name = "GB_Adventure";
+ this.GB_Adventure.Size = new System.Drawing.Size(200, 151);
+ this.GB_Adventure.TabIndex = 70;
+ this.GB_Adventure.TabStop = false;
+ this.GB_Adventure.Text = "Adventure Info";
//
// L_Started
//
@@ -141,14 +141,14 @@ private void InitializeComponent()
this.CAL_HoFDate.TabIndex = 31;
this.CAL_HoFDate.Value = new System.DateTime(2000, 1, 1, 0, 0, 0, 0);
//
- // L_LastSaved
+ // L_Fame
//
- this.L_LastSaved.Location = new System.Drawing.Point(4, 107);
- this.L_LastSaved.Name = "L_LastSaved";
- this.L_LastSaved.Size = new System.Drawing.Size(80, 20);
- this.L_LastSaved.TabIndex = 32;
- this.L_LastSaved.Text = "Hall of Fame:";
- this.L_LastSaved.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
+ this.L_Fame.Location = new System.Drawing.Point(4, 107);
+ this.L_Fame.Name = "L_Fame";
+ this.L_Fame.Size = new System.Drawing.Size(80, 20);
+ this.L_Fame.TabIndex = 32;
+ this.L_Fame.Text = "Hall of Fame:";
+ this.L_Fame.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
//
// MT_Seconds
//
@@ -340,7 +340,7 @@ private void InitializeComponent()
this.GB_Map.Controls.Add(this.L_CurrentMap);
this.GB_Map.Controls.Add(this.L_Z);
this.GB_Map.Controls.Add(this.L_X);
- this.GB_Map.Location = new System.Drawing.Point(218, 100);
+ this.GB_Map.Location = new System.Drawing.Point(217, 100);
this.GB_Map.Name = "GB_Map";
this.GB_Map.Size = new System.Drawing.Size(157, 125);
this.GB_Map.TabIndex = 71;
@@ -438,7 +438,7 @@ private void InitializeComponent()
//
// B_Save
//
- this.B_Save.Location = new System.Drawing.Point(300, 226);
+ this.B_Save.Location = new System.Drawing.Point(299, 226);
this.B_Save.Name = "B_Save";
this.B_Save.Size = new System.Drawing.Size(75, 23);
this.B_Save.TabIndex = 73;
@@ -448,7 +448,7 @@ private void InitializeComponent()
//
// B_Cancel
//
- this.B_Cancel.Location = new System.Drawing.Point(219, 226);
+ this.B_Cancel.Location = new System.Drawing.Point(218, 226);
this.B_Cancel.Name = "B_Cancel";
this.B_Cancel.Size = new System.Drawing.Size(75, 23);
this.B_Cancel.TabIndex = 72;
@@ -456,49 +456,49 @@ private void InitializeComponent()
this.B_Cancel.UseVisualStyleBackColor = true;
this.B_Cancel.Click += new System.EventHandler(this.B_Cancel_Click);
//
- // groupBox1
+ // GB_Trainer
//
- this.groupBox1.Controls.Add(this.TB_OTName);
- this.groupBox1.Controls.Add(this.B_MaxCash);
- this.groupBox1.Controls.Add(this.MT_SID);
- this.groupBox1.Controls.Add(this.MT_TID);
- this.groupBox1.Controls.Add(this.L_Money);
- this.groupBox1.Controls.Add(this.L_SID);
- this.groupBox1.Controls.Add(this.CB_Gender);
- this.groupBox1.Controls.Add(this.MT_Money);
- this.groupBox1.Controls.Add(this.L_TID);
- this.groupBox1.Controls.Add(this.L_TrainerName);
- this.groupBox1.Location = new System.Drawing.Point(12, 12);
- this.groupBox1.Name = "groupBox1";
- this.groupBox1.Size = new System.Drawing.Size(200, 82);
- this.groupBox1.TabIndex = 74;
- this.groupBox1.TabStop = false;
- this.groupBox1.Text = "Trainer";
+ this.GB_Trainer.Controls.Add(this.TB_OTName);
+ this.GB_Trainer.Controls.Add(this.B_MaxCash);
+ this.GB_Trainer.Controls.Add(this.MT_SID);
+ this.GB_Trainer.Controls.Add(this.MT_TID);
+ this.GB_Trainer.Controls.Add(this.L_Money);
+ this.GB_Trainer.Controls.Add(this.L_SID);
+ this.GB_Trainer.Controls.Add(this.CB_Gender);
+ this.GB_Trainer.Controls.Add(this.MT_Money);
+ this.GB_Trainer.Controls.Add(this.L_TID);
+ this.GB_Trainer.Controls.Add(this.L_TrainerName);
+ this.GB_Trainer.Location = new System.Drawing.Point(11, 12);
+ this.GB_Trainer.Name = "GB_Trainer";
+ this.GB_Trainer.Size = new System.Drawing.Size(200, 82);
+ this.GB_Trainer.TabIndex = 74;
+ this.GB_Trainer.TabStop = false;
+ this.GB_Trainer.Text = "Trainer";
//
- // groupBox3
+ // GB_Badges
//
- this.groupBox3.Controls.Add(this.CHK_H8);
- this.groupBox3.Controls.Add(this.CHK_H7);
- this.groupBox3.Controls.Add(this.CHK_H6);
- this.groupBox3.Controls.Add(this.CHK_H5);
- this.groupBox3.Controls.Add(this.CHK_H4);
- this.groupBox3.Controls.Add(this.CHK_H3);
- this.groupBox3.Controls.Add(this.CHK_H2);
- this.groupBox3.Controls.Add(this.CHK_H1);
- this.groupBox3.Controls.Add(this.CHK_8);
- this.groupBox3.Controls.Add(this.CHK_7);
- this.groupBox3.Controls.Add(this.CHK_6);
- this.groupBox3.Controls.Add(this.CHK_5);
- this.groupBox3.Controls.Add(this.CHK_4);
- this.groupBox3.Controls.Add(this.CHK_3);
- this.groupBox3.Controls.Add(this.CHK_2);
- this.groupBox3.Controls.Add(this.CHK_1);
- this.groupBox3.Location = new System.Drawing.Point(219, 12);
- this.groupBox3.Name = "groupBox3";
- this.groupBox3.Size = new System.Drawing.Size(157, 82);
- this.groupBox3.TabIndex = 75;
- this.groupBox3.TabStop = false;
- this.groupBox3.Text = "Badges";
+ this.GB_Badges.Controls.Add(this.CHK_H8);
+ this.GB_Badges.Controls.Add(this.CHK_H7);
+ this.GB_Badges.Controls.Add(this.CHK_H6);
+ this.GB_Badges.Controls.Add(this.CHK_H5);
+ this.GB_Badges.Controls.Add(this.CHK_H4);
+ this.GB_Badges.Controls.Add(this.CHK_H3);
+ this.GB_Badges.Controls.Add(this.CHK_H2);
+ this.GB_Badges.Controls.Add(this.CHK_H1);
+ this.GB_Badges.Controls.Add(this.CHK_8);
+ this.GB_Badges.Controls.Add(this.CHK_7);
+ this.GB_Badges.Controls.Add(this.CHK_6);
+ this.GB_Badges.Controls.Add(this.CHK_5);
+ this.GB_Badges.Controls.Add(this.CHK_4);
+ this.GB_Badges.Controls.Add(this.CHK_3);
+ this.GB_Badges.Controls.Add(this.CHK_2);
+ this.GB_Badges.Controls.Add(this.CHK_1);
+ this.GB_Badges.Location = new System.Drawing.Point(218, 12);
+ this.GB_Badges.Name = "GB_Badges";
+ this.GB_Badges.Size = new System.Drawing.Size(157, 82);
+ this.GB_Badges.TabIndex = 75;
+ this.GB_Badges.TabStop = false;
+ this.GB_Badges.Text = "Badges";
//
// CHK_H8
//
@@ -664,37 +664,38 @@ private void InitializeComponent()
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
- this.ClientSize = new System.Drawing.Size(386, 261);
- this.Controls.Add(this.groupBox3);
- this.Controls.Add(this.groupBox1);
+ this.ClientSize = new System.Drawing.Size(384, 261);
+ this.Controls.Add(this.GB_Badges);
+ this.Controls.Add(this.GB_Trainer);
this.Controls.Add(this.B_Save);
this.Controls.Add(this.B_Cancel);
this.Controls.Add(this.GB_Map);
- this.Controls.Add(this.groupBox2);
+ this.Controls.Add(this.GB_Adventure);
+ this.MinimumSize = new System.Drawing.Size(400, 300);
this.Name = "SAV_SimpleTrainer";
this.Text = "Trainer Data Editor";
- this.groupBox2.ResumeLayout(false);
- this.groupBox2.PerformLayout();
+ this.GB_Adventure.ResumeLayout(false);
+ this.GB_Adventure.PerformLayout();
this.GB_Map.ResumeLayout(false);
((System.ComponentModel.ISupportInitialize)(this.NUD_Z)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_M)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_Y)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.NUD_X)).EndInit();
- this.groupBox1.ResumeLayout(false);
- this.groupBox1.PerformLayout();
- this.groupBox3.ResumeLayout(false);
- this.groupBox3.PerformLayout();
+ this.GB_Trainer.ResumeLayout(false);
+ this.GB_Trainer.PerformLayout();
+ this.GB_Badges.ResumeLayout(false);
+ this.GB_Badges.PerformLayout();
this.ResumeLayout(false);
}
#endregion
- private System.Windows.Forms.GroupBox groupBox2;
+ private System.Windows.Forms.GroupBox GB_Adventure;
private System.Windows.Forms.Label L_Started;
private System.Windows.Forms.DateTimePicker CAL_AdventureStartDate;
private System.Windows.Forms.DateTimePicker CAL_HoFDate;
- private System.Windows.Forms.Label L_LastSaved;
+ private System.Windows.Forms.Label L_Fame;
private System.Windows.Forms.MaskedTextBox MT_Seconds;
private System.Windows.Forms.MaskedTextBox MT_Hours;
private System.Windows.Forms.Label L_Seconds;
@@ -724,8 +725,8 @@ private void InitializeComponent()
private System.Windows.Forms.Label L_X;
private System.Windows.Forms.Button B_Save;
private System.Windows.Forms.Button B_Cancel;
- private System.Windows.Forms.GroupBox groupBox1;
- private System.Windows.Forms.GroupBox groupBox3;
+ private System.Windows.Forms.GroupBox GB_Trainer;
+ private System.Windows.Forms.GroupBox GB_Badges;
private System.Windows.Forms.CheckBox CHK_8;
private System.Windows.Forms.CheckBox CHK_7;
private System.Windows.Forms.CheckBox CHK_6;
diff --git a/SAV/SAV_SimpleTrainer.cs b/SAV/SAV_SimpleTrainer.cs
index 4f19aa6c7..59fd633e6 100644
--- a/SAV/SAV_SimpleTrainer.cs
+++ b/SAV/SAV_SimpleTrainer.cs
@@ -20,6 +20,20 @@ public SAV_SimpleTrainer()
MT_TID.Text = SAV.TID.ToString("00000");
MT_SID.Text = SAV.SID.ToString("00000");
MT_Money.Text = SAV.Money.ToString();
+ MT_Hours.Text = SAV.PlayedHours.ToString();
+ MT_Minutes.Text = SAV.PlayedMinutes.ToString();
+ MT_Seconds.Text = SAV.PlayedSeconds.ToString();
+
+ if (SAV is SAV3)
+ {
+ GB_Map.Visible = false;
+ GB_Badges.Visible = false; // todo
+
+ L_Started.Visible = L_Fame.Visible = false;
+ CAL_AdventureStartDate.Visible = CAL_HoFDate.Visible = false;
+ CAL_AdventureStartTime.Visible = CAL_HoFTime.Visible = false;
+ return;
+ }
int badgeval = 0;
if (SAV is SAV4)
@@ -54,9 +68,6 @@ public SAV_SimpleTrainer()
cba[i].Checked = (badgeval & 1 << i) != 0;
}
- MT_Hours.Text = SAV.PlayedHours.ToString();
- MT_Minutes.Text = SAV.PlayedMinutes.ToString();
- MT_Seconds.Text = SAV.PlayedSeconds.ToString();
CAL_HoFDate.Value = new DateTime(2000, 1, 1).AddSeconds(SAV.SecondsToFame);
CAL_HoFTime.Value = new DateTime(2000, 1, 1).AddSeconds(SAV.SecondsToFame % 86400);
CAL_AdventureStartDate.Value = new DateTime(2000, 1, 1).AddSeconds(SAV.SecondsToStart);
@@ -81,6 +92,10 @@ private void B_Save_Click(object sender, EventArgs e)
SAV.SID = (ushort)Util.ToUInt32(MT_SID.Text);
SAV.Money = Util.ToUInt32(MT_Money.Text);
+ SAV.PlayedHours = ushort.Parse(MT_Hours.Text);
+ SAV.PlayedMinutes = ushort.Parse(MT_Minutes.Text) % 60;
+ SAV.PlayedSeconds = ushort.Parse(MT_Seconds.Text) % 60;
+
// Copy Badges
int badgeval = 0;
for (int i = 0; i < cba.Length; i++)
@@ -108,12 +123,7 @@ private void B_Save_Click(object sender, EventArgs e)
s.Y = (int)NUD_Y.Value;
s.Badges = badgeval & 0xFF;
}
-
- // Save PlayTime
- SAV.PlayedHours = ushort.Parse(MT_Hours.Text);
- SAV.PlayedMinutes = ushort.Parse(MT_Minutes.Text) % 60;
- SAV.PlayedSeconds = ushort.Parse(MT_Seconds.Text) % 60;
-
+
SAV.SecondsToStart = getSeconds(CAL_AdventureStartDate, CAL_AdventureStartTime);
SAV.SecondsToFame = getSeconds(CAL_HoFDate, CAL_HoFTime);
diff --git a/Saves/SAV3.cs b/Saves/SAV3.cs
new file mode 100644
index 000000000..4ddd69c0d
--- /dev/null
+++ b/Saves/SAV3.cs
@@ -0,0 +1,382 @@
+using System;
+using System.Linq;
+
+namespace PKHeX
+{
+ public sealed class SAV3 : SaveFile
+ {
+ public override string BAKName => $"{FileName} [{OT} ({Version})" +/* - {LastSavedTime}*/ "].bak";
+ public override string Filter => "Main SAV|*.*";
+ public override string Extension => "";
+
+ /* SAV3 Structure:
+ * 0xE000 per save file
+ * 14 blocks @ 0x1000 each.
+ * Blocks do not use all 0x1000 bytes allocated.
+ * Via: http://bulbapedia.bulbagarden.net/wiki/Save_data_structure_in_Generation_III
+ */
+ private readonly int[] chunkLength =
+ {
+ 0xf2c, // 0 | Trainer info
+ 0xf80, // 1 | Team / items
+ 0xf80, // 2 | Unknown
+ 0xf80, // 3 | Unknown
+ 0xf08, // 4 | Rival info
+ 0xf80, // 5 | PC Block 0
+ 0xf80, // 6 | PC Block 1
+ 0xf80, // 7 | PC Block 2
+ 0xf80, // 8 | PC Block 3
+ 0xf80, // 9 | PC Block 4
+ 0xf80, // A | PC Block 5
+ 0xf80, // B | PC Block 6
+ 0xf80, // C | PC Block 7
+ 0x7d0 // D | PC Block 8
+ };
+
+ public SAV3(byte[] data = null)
+ {
+ Data = data == null ? new byte[SaveUtil.SIZE_G3RAW] : (byte[])data.Clone();
+ BAK = (byte[])Data.Clone();
+ Exportable = !Data.SequenceEqual(new byte[Data.Length]);
+
+ BlockOrder = new int[14];
+ ActiveSAV = SaveUtil.SIZE_G3RAWHALF == data.Length || BitConverter.ToUInt32(Data, 0xFFC) > BitConverter.ToUInt32(Data, 0xEFFC) ? 0 : 1;
+ for (int i = 0; i < 14; i++)
+ BlockOrder[i] = BitConverter.ToInt16(Data, ABO + i*0x1000 + 0xFF4);
+
+ // Detect RS/E/FRLG
+ // Section 0 stores Game Code @ 0x00AC; 0 for RS, 1 for FRLG, else for Emerald
+ Trainer1 = Array.IndexOf(BlockOrder, 0)*0x1000 + ABO;
+ Party = Array.IndexOf(BlockOrder, 1)*0x1000 + ABO;
+ Block2 = Array.IndexOf(BlockOrder, 2)*0x1000 + ABO;
+ Block3 = Array.IndexOf(BlockOrder, 3)*0x1000 + ABO;
+
+ uint GameCode = BitConverter.ToUInt32(Data, ABO + Array.IndexOf(BlockOrder, 0)*0x1000);
+ SaveVersion = GameCode < 2 ? (int)GameCode : 2;
+
+ // Set up PC data buffer beyond end of save file.
+ Box = Data.Length;
+ Array.Resize(ref Data, Data.Length + 0x10000); // More than enough empty space.
+
+ // Copy chunk to the allocated location
+ for (int i = 5; i < 14; i++)
+ {
+ int blockIndex = Array.IndexOf(BlockOrder, i);
+ if (blockIndex == -1) // block empty
+ continue;
+ Array.Copy(Data, blockIndex * 0x1000 + ABO, Data, Box + (i - 5)*0xF80, chunkLength[i]);
+ }
+
+ HeldItems = Legal.HeldItems_RS;
+
+ if (!Exportable)
+ resetBoxes();
+ }
+
+ private readonly int SaveVersion;
+ private readonly int ActiveSAV;
+ private int ABO => ActiveSAV*0xE000;
+ private readonly int[] BlockOrder;
+
+ // Configuration
+ public override byte[] BAK { get; }
+ public override bool Exportable { get; }
+ public override SaveFile Clone() { return new SAV3(Data.Take(Box).ToArray()); }
+
+ public override int SIZE_STORED => PKX.SIZE_3STORED;
+ public override int SIZE_PARTY => PKX.SIZE_3PARTY;
+ public override PKM BlankPKM => new PK3();
+ protected override Type PKMType => typeof(PK3);
+
+ public override int MaxMoveID => 354;
+ public override int MaxSpeciesID => 386;
+ public override int MaxAbilityID => 77;
+ public override int MaxItemID => 374;
+ public override int MaxBallID => 0xC;
+ public override int MaxGameID => 5;
+
+ public override int BoxCount => 14;
+ public override int MaxEV => 252;
+ public override int Generation => 3;
+ protected override int GiftCountMax => 1;
+ public override int OTLength => 8;
+ public override int NickLength => 10;
+
+ private int Block2, Block3;
+
+ // Checksums
+ protected override void setChecksums()
+ {
+ for (int i = 0; i < 14; i++)
+ {
+ byte[] chunk = Data.Skip(ABO + i*0x1000).Take(chunkLength[BlockOrder[i]]).ToArray();
+ ushort chk = SaveUtil.check32(chunk);
+ BitConverter.GetBytes(chk).CopyTo(Data, ABO + i + 0xFF4);
+ }
+ }
+ public override bool ChecksumsValid
+ {
+ get
+ {
+ for (int i = 0; i < 14; i++)
+ {
+ byte[] chunk = Data.Skip(ABO + i * 0x1000).Take(chunkLength[BlockOrder[i]]).ToArray();
+ ushort chk = SaveUtil.check32(chunk);
+ if (chk != BitConverter.ToUInt16(Data, ABO + i*0xFF4))
+ return false;
+ }
+ return true;
+ }
+ }
+ public override string ChecksumInfo
+ {
+ get
+ {
+ string r = "";
+ for (int i = 0; i < 14; i++)
+ {
+ byte[] chunk = Data.Skip(ABO + i * 0x1000).Take(chunkLength[BlockOrder[i]]).ToArray();
+ ushort chk = SaveUtil.check32(chunk);
+ if (chk != BitConverter.ToUInt16(Data, ABO + i * 0xFF4))
+ r += $"Block {BlockOrder[i]} @ {i*0x1000} (len {chunkLength[BlockOrder[i]]}) invalid." + Environment.NewLine;
+ }
+ return r.Length == 0 ? "Checksums valid." : r.TrimEnd();
+ }
+ }
+
+ // Trainer Info
+ public override GameVersion Version
+ {
+ get
+ {
+ switch (SaveVersion)
+ {
+ case 0: return GameVersion.RS;
+ case 1: return GameVersion.FRLG;
+ case 2: return GameVersion.E;
+ }
+ return GameVersion.Unknown;
+ }
+ }
+
+ private bool Japanese;
+ private uint SecurityKey
+ {
+ get
+ {
+ switch (Version)
+ {
+ case GameVersion.E: return BitConverter.ToUInt32(Data, Trainer1 + 0xAC);
+ case GameVersion.FRLG: return BitConverter.ToUInt32(Data, Trainer1 + 0xAF8);
+ default: return 0;
+ }
+ }
+ }
+ public override string OT
+ {
+ get
+ {
+ return PKX.getG3Str(Data.Skip(Trainer1).Take(0x10).ToArray(), Japanese)
+ .Replace("\uE08F", "\u2640") // Nidoran ♂
+ .Replace("\uE08E", "\u2642") // Nidoran ♀
+ .Replace("\u2019", "\u0027"); // Farfetch'd
+ }
+ set
+ {
+ if (value.Length > 7)
+ value = value.Substring(0, 7); // Hard cap
+ string TempNick = value // Replace Special Characters and add Terminator
+ .Replace("\u2640", "\uE08F") // Nidoran ♂
+ .Replace("\u2642", "\uE08E") // Nidoran ♀
+ .Replace("\u0027", "\u2019"); // Farfetch'd
+ PKX.setG3Str(TempNick, Japanese).CopyTo(Data, Trainer1);
+ }
+ }
+ public override int Gender
+ {
+ get { return Data[Trainer1 + 8]; }
+ set { Data[Trainer1 + 8] = (byte)value; }
+ }
+ public override ushort TID
+ {
+ get { return BitConverter.ToUInt16(Data, Trainer1 + 0xA + 0); }
+ set { BitConverter.GetBytes(value).CopyTo(Data, Trainer1 + 0xA + 0); }
+ }
+ public override ushort SID
+ {
+ get { return BitConverter.ToUInt16(Data, Trainer1 + 0xC); }
+ set { BitConverter.GetBytes(value).CopyTo(Data, Trainer1 + 0xC); }
+ }
+ public override int PlayedHours
+ {
+ get { return BitConverter.ToUInt16(Data, Trainer1 + 0xE); }
+ set { BitConverter.GetBytes((ushort)value).CopyTo(Data, Trainer1 + 0xE); }
+ }
+ public override int PlayedMinutes
+ {
+ get { return Data[Trainer1 + 0x10]; }
+ set { Data[Trainer1 + 0x10] = (byte)value; }
+ }
+ public override int PlayedSeconds
+ {
+ get { return Data[Trainer1 + 0x11]; }
+ set { Data[Trainer1 + 0x11] = (byte)value; }
+ }
+ public int PlayedFrames
+ {
+ get { return Data[Trainer1 + 0x12]; }
+ set { Data[Trainer1 + 0x12] = (byte)value; }
+ }
+
+ public override uint Money
+ {
+ get
+ {
+ switch (Version)
+ {
+ case GameVersion.RS:
+ case GameVersion.E: return BitConverter.ToUInt32(Data, Party + 0x0490) ^ SecurityKey;
+ case GameVersion.FRLG: return BitConverter.ToUInt32(Data, Party + 0x0290) ^ SecurityKey;
+ default: return 0;
+ }
+ }
+ set
+ {
+ switch (Version)
+ {
+ case GameVersion.RS:
+ case GameVersion.E: BitConverter.GetBytes(value ^ SecurityKey).CopyTo(Data, Party + 0x0490); break;
+ case GameVersion.FRLG: BitConverter.GetBytes(value ^ SecurityKey).CopyTo(Data, Party + 0x0290); break;
+ }
+ }
+ }
+ public uint Coin
+ {
+ get
+ {
+ switch (Version)
+ {
+ case GameVersion.RS:
+ case GameVersion.E: return BitConverter.ToUInt32(Data, Party + 0x0494) ^ SecurityKey;
+ case GameVersion.FRLG: return BitConverter.ToUInt32(Data, Party + 0x0294) ^ SecurityKey;
+ default: return 0;
+ }
+ }
+ set
+ {
+ switch (Version)
+ {
+ case GameVersion.RS:
+ case GameVersion.E: BitConverter.GetBytes(value ^ SecurityKey).CopyTo(Data, Party + 0x0494); break;
+ case GameVersion.FRLG: BitConverter.GetBytes(value ^ SecurityKey).CopyTo(Data, Party + 0x0294); break;
+ }
+ }
+ }
+ public int BP
+ {
+ get { return Data[Trainer1 + 0xEB8]; }
+ set { Data[Trainer1 + 0xEB8] = (byte)value; }
+ }
+
+ public override InventoryPouch[] Inventory
+ {
+ get
+ {
+ return null;
+
+ }
+ set { }
+ }
+ public override int Language { get { return 0; } set { } }
+
+ public override int getDaycareSlotOffset(int loc, int slot)
+ {
+ return Daycare + slot * SIZE_PARTY;
+ }
+ public override ulong? getDaycareRNGSeed(int loc)
+ {
+ return null;
+ }
+ public override uint? getDaycareEXP(int loc, int slot)
+ {
+ int ofs = Daycare + (slot + 1) * SIZE_PARTY - 4;
+ return BitConverter.ToUInt32(Data, ofs);
+ }
+ public override bool? getDaycareOccupied(int loc, int slot)
+ {
+ return null;
+ }
+ public override void setDaycareEXP(int loc, int slot, uint EXP)
+ {
+ int ofs = Daycare + (slot + 1) * SIZE_PARTY - 4;
+ BitConverter.GetBytes(EXP).CopyTo(Data, ofs);
+ }
+ public override void setDaycareOccupied(int loc, int slot, bool occupied)
+ {
+
+ }
+
+ // Storage
+ public override int PartyCount
+ {
+ get
+ {
+ int ofs = 0x34;
+ if (GameVersion.FRLG != Version)
+ ofs += 0x200;
+ return Data[Party + ofs];
+
+ }
+ protected set
+ {
+ int ofs = 0x34;
+ if (GameVersion.FRLG != Version)
+ ofs += 0x200;
+ Data[Party + ofs] = (byte)value;
+ }
+ }
+ public override int getBoxOffset(int box)
+ {
+ return Box + 4 + SIZE_STORED * box * 30;
+ }
+ public override int getPartyOffset(int slot)
+ {
+ int ofs = 0x38;
+ if (GameVersion.FRLG != Version)
+ ofs += 0x200;
+ return Party + ofs + SIZE_PARTY * slot;
+ }
+ public override int CurrentBox
+ {
+ get { return Data[Box]; }
+ set { Data[Box] = (byte)value; }
+ }
+ public override int getBoxWallpaper(int box)
+ {
+ // Box Wallpaper is directly after the Box Names
+ int offset = getBoxOffset(BoxCount);
+ offset += BoxCount * 0x9;
+ return Data[offset];
+ }
+ public override string getBoxName(int box)
+ {
+ int offset = getBoxOffset(BoxCount);
+ return PKX.getG3Str(Data.Skip(offset + box * 9).Take(9).ToArray(), Japanese);
+ }
+ public override void setBoxName(int box, string value)
+ {
+ if (value.Length > 8)
+ value = value.Substring(0, 8); // Hard cap
+ int offset = getBoxOffset(BoxCount);
+ PKX.setG3Str(value, Japanese).CopyTo(Data, offset + box * 9);
+ }
+ public override PKM getPKM(byte[] data)
+ {
+ return new PK3(data);
+ }
+ public override byte[] decryptPKM(byte[] data)
+ {
+ return PKX.decryptArray3(data);
+ }
+ }
+}
diff --git a/Saves/SAV4.cs b/Saves/SAV4.cs
index 1e9fe9277..784898fb7 100644
--- a/Saves/SAV4.cs
+++ b/Saves/SAV4.cs
@@ -568,7 +568,6 @@ public override byte[] decryptPKM(byte[] data)
}
// Daycare
- public override int DaycareSeedSize => 8;
public override int getDaycareSlotOffset(int loc, int slot)
{
return Daycare + slot * SIZE_PARTY;
diff --git a/Saves/SaveFile.cs b/Saves/SaveFile.cs
index 1daf83b72..9cfc82206 100644
--- a/Saves/SaveFile.cs
+++ b/Saves/SaveFile.cs
@@ -84,7 +84,7 @@ public byte[] Write(bool DSV)
protected virtual int GiftFlagMax { get; } = 0x800;
protected virtual int EventFlagMax { get; } = int.MinValue;
protected virtual int EventConstMax { get; } = int.MinValue;
- public abstract int DaycareSeedSize { get; }
+ public virtual int DaycareSeedSize { get; } = 0;
public abstract int OTLength { get; }
public abstract int NickLength { get; }
@@ -249,8 +249,8 @@ public ushort[] EventConsts
protected int OFS_MailItems { get; set; } = int.MinValue;
// Mystery Gift
- protected abstract bool[] MysteryGiftReceivedFlags { get; set; }
- protected abstract MysteryGift[] MysteryGiftCards { get; set; }
+ protected virtual bool[] MysteryGiftReceivedFlags { get { return null; } set { } }
+ protected virtual MysteryGift[] MysteryGiftCards { get { return null; } set { } }
public virtual MysteryGiftAlbum GiftAlbum
{
get
@@ -285,8 +285,8 @@ public virtual MysteryGiftAlbum GiftAlbum
public abstract int PlayedHours { get; set; }
public abstract int PlayedMinutes { get; set; }
public abstract int PlayedSeconds { get; set; }
- public abstract int SecondsToStart { get; set; }
- public abstract int SecondsToFame { get; set; }
+ public virtual int SecondsToStart { get; set; }
+ public virtual int SecondsToFame { get; set; }
public abstract uint Money { get; set; }
public abstract int BoxCount { get; }
public abstract int PartyCount { get; protected set; }
diff --git a/Saves/SaveUtil.cs b/Saves/SaveUtil.cs
index af9a41b32..678af2428 100644
--- a/Saves/SaveUtil.cs
+++ b/Saves/SaveUtil.cs
@@ -14,6 +14,8 @@ public enum GameVersion
X = 24, Y = 25, AS = 26, OR = 27,
SN = 28, MN = 29,
+ RS = 200,
+ FRLG = 201,
DP = 100,
HGSS = 101,
}
@@ -28,11 +30,15 @@ internal static class SaveUtil
internal const int SIZE_G5BW = 0x24000;
internal const int SIZE_G5B2W2 = 0x26000;
internal const int SIZE_G4RAW = 0x80000;
+ internal const int SIZE_G3RAW = 0x20000;
+ internal const int SIZE_G3RAWHALF = 0x10000;
internal static readonly byte[] FOOTER_DSV = Encoding.ASCII.GetBytes("|-DESMUME SAVE-|");
internal static int getSAVGeneration(byte[] data)
{
+ if (getIsG3SAV(data) != -1)
+ return 3;
if (getIsG4SAV(data) != -1)
return 4;
if (getIsG5SAV(data) != -1)
@@ -41,6 +47,24 @@ internal static int getSAVGeneration(byte[] data)
return 6;
return -1;
}
+ internal static int getIsG3SAV(byte[] data)
+ {
+ if (data.Length != SIZE_G3RAW && data.Length != SIZE_G3RAWHALF)
+ return -1;
+
+ int[] BlockOrder = new int[14];
+ for (int i = 0; i < 14; i++)
+ BlockOrder[i] = BitConverter.ToInt16(data, i * 0x1000 + 0xFF4);
+
+ if (BlockOrder.Any(i => i > 0xD || i < 0))
+ return -1;
+
+ // Detect RS/E/FRLG
+ // Section 0 stores Game Code @ 0x00AC; 0 for RS, 1 for FRLG, else for Emerald
+
+ uint GameCode = BitConverter.ToUInt32(data, Array.IndexOf(BlockOrder, 0) * 0x1000);
+ return GameCode < 2 ? (int)GameCode : 2;
+ }
internal static int getIsG4SAV(byte[] data)
{
if (data.Length != SIZE_G4RAW)
@@ -103,6 +127,8 @@ internal static SaveFile getVariantSAV(byte[] data)
{
switch (getSAVGeneration(data))
{
+ case 3:
+ return new SAV3(data);
case 4:
return new SAV4(data);
case 5:
@@ -276,6 +302,16 @@ internal static void writeG6CHK(byte[] savefile)
BitConverter.GetBytes(ccitt16(array)).CopyTo(savefile, verificationOffset + 6 + i * 8);
}
}
+ /// Calculates the 32bit checksum over an input byte array. Used in GBA save files.
+ /// Input byte array
+ /// Checksum
+ internal static ushort check32(byte[] data)
+ {
+ uint val = 0;
+ for (int i = 0; i < data.Length; i += 4)
+ val += BitConverter.ToUInt32(data, i);
+ return (ushort)(val + val >> 16);
+ }
internal static int getDexFormIndexXY(int species, int formct)
{