Sync basic gen3 support

Still many things not yet working (item/inventory editing needs new
string resources)
This commit is contained in:
Kaphotics
2016-06-26 14:23:41 -07:00
parent ca139cf7e4
commit e6e3caabb2
12 changed files with 928 additions and 164 deletions

36
Legality/Tables3.cs Normal file
View File

@@ -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
}
}

View File

@@ -71,6 +71,7 @@
<Compile Include="Legality\Checks.cs" />
<Compile Include="Legality\Core.cs" />
<Compile Include="Legality\Data.cs" />
<Compile Include="Legality\Tables3.cs" />
<Compile Include="Legality\Tables5.cs" />
<Compile Include="Legality\Tables4.cs" />
<Compile Include="MysteryGifts\MysteryGift.cs" />
@@ -92,6 +93,7 @@
</Compile>
<Compile Include="Saves\BlockInfo.cs" />
<Compile Include="Saves\Inventory.cs" />
<Compile Include="Saves\SAV3.cs" />
<Compile Include="Saves\SAV4.cs" />
<Compile Include="Saves\SAV5.cs" />
<Compile Include="Saves\SAV6.cs" />

View File

@@ -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)

View File

@@ -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; }

View File

@@ -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];
}
}
}

View File

@@ -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<string> ability_list = new List<string>
{
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;

View File

@@ -28,11 +28,11 @@ protected override void Dispose(bool disposing)
/// </summary>
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;

View File

@@ -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);

382
Saves/SAV3.cs Normal file
View File

@@ -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);
}
}
}

View File

@@ -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;

View File

@@ -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; }

View File

@@ -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);
}
}
/// <summary>Calculates the 32bit checksum over an input byte array. Used in GBA save files.</summary>
/// <param name="data">Input byte array</param>
/// <returns>Checksum</returns>
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)
{