Sync current Colo/XD implementation

Not working yet, need to pull in PBR support
This commit is contained in:
Kaphotics 2016-09-26 16:15:40 -07:00
parent 3114c658d9
commit 05000b7697
12 changed files with 1591 additions and 2 deletions

View file

@ -43,5 +43,37 @@ namespace PKHeX
20, 15, 10, 10, 15, 10, 05, 05, 10, 15, 10, 05, 20, 25, 05, 40, 10, 05, 40, 15, 20, 20, 05, 15, 20, 30, 15, 15, 05, 10, 30, 20, 30, 15, 05, 40, 15, 05, 20, 05, 15, 25, 40, 15, 20, 15, 20, 15, 20, 10,
20, 20, 05, 05,
};
internal static readonly ushort[] Pouch_Cologne_CXD = {543, 544, 545};
internal static readonly ushort[] Pouch_Items_COLO = Pouch_Items_RS.Concat(new ushort[] {537}).ToArray(); // Time Flute
internal static readonly ushort[] HeldItems_COLO = new ushort[1].Concat(Pouch_Items_COLO).Concat(Pouch_Ball_RS).Concat(Pouch_Berries_RS).Concat(Pouch_TM_RS).ToArray();
internal static readonly ushort[] Pouch_Key_COLO =
{
500, 501, 502, 503, 504, 505, 506, 507, 508, 509,
510, 511, 512, 513, 514, 515, 516, 517, 518, 519,
520, 521, 522, 523, 524, 525, 526, 527, 528, 529,
530, 531, 532, 533, 534, 535, 536, 538, 539,
540, 541, 542, 546, 547,
};
internal static readonly ushort[] Pouch_Items_XD = Pouch_Items_RS.Concat(new ushort[] {511}).ToArray(); // Poké Snack
internal static readonly ushort[] HeldItems_XD = new ushort[1].Concat(Pouch_Items_XD).Concat(Pouch_Ball_RS).Concat(Pouch_Berries_RS).Concat(Pouch_TM_RS).ToArray();
internal static readonly ushort[] Pouch_Key_XD =
{
500, 501, 502, 503, 504, 505, 506, 507, 508, 509,
510, 512, 516, 517, 518, 519,
523, 524, 525, 526, 527, 528, 529,
530, 531, 532, 533
};
internal static readonly ushort[] Pouch_Disc_XD =
{
534, 535, 536, 537, 538, 539,
540, 541, 542, 543, 544, 545, 546, 547, 548, 549,
550, 551, 552, 553, 554, 555, 556, 557, 558, 559,
560, 561, 562, 563, 564, 565, 566, 567, 568, 569,
570, 571, 572, 573, 574, 575, 576, 577, 578, 579,
580, 581, 582, 583, 584, 585, 586, 587, 588, 589,
590, 591, 592, 593
};
}
}

View file

@ -1031,6 +1031,20 @@ namespace PKHeX
extraBytes = new byte[] { };
break;
case 3:
if (SAV.Version == GameVersion.COLO)
{
getFieldsfromPKM = populateFieldsCK3;
getPKMfromFields = prepareCK3;
extraBytes = CK3.ExtraBytes;
break;
}
if (SAV.Version == GameVersion.XD)
{
getFieldsfromPKM = populateFieldsXK3;
getPKMfromFields = prepareXK3;
extraBytes = XK3.ExtraBytes;
break;
}
getFieldsfromPKM = populateFieldsPK3;
getPKMfromFields = preparePK3;
extraBytes = PK3.ExtraBytes;

197
PKHeX/MainWindow/MainCK3.cs Normal file
View file

@ -0,0 +1,197 @@
using System;
using System.Drawing;
namespace PKHeX
{
public partial class Main
{
private void populateFieldsCK3()
{
CK3 ck3 = pkm as CK3;
if (ck3 == null)
return;
// Do first
ck3.Stat_Level = PKX.getLevel(ck3.Species, ck3.EXP);
if (ck3.Stat_Level == 100)
ck3.EXP = PKX.getEXP(ck3.Stat_Level, ck3.Species);
CB_Species.SelectedValue = ck3.Species;
TB_Level.Text = ck3.Stat_Level.ToString();
TB_EXP.Text = ck3.EXP.ToString();
// Load rest
CHK_Fateful.Checked = ck3.FatefulEncounter;
CHK_IsEgg.Checked = ck3.IsEgg;
CHK_Nicknamed.Checked = ck3.IsNicknamed;
Label_OTGender.Text = gendersymbols[ck3.OT_Gender];
Label_OTGender.ForeColor = ck3.OT_Gender == 1 ? Color.Red : Color.Blue;
TB_PID.Text = ck3.PID.ToString("X8");
CB_HeldItem.SelectedValue = ck3.G3Item;
setAbilityList();
CB_Ability.SelectedIndex = ck3.AbilityNumber > CB_Ability.Items.Count ? 0 : ck3.AbilityNumber;
CB_Nature.SelectedValue = ck3.Nature;
TB_TID.Text = ck3.TID.ToString("00000");
TB_SID.Text = ck3.SID.ToString("00000");
TB_Nickname.Text = ck3.Nickname;
TB_OT.Text = ck3.OT_Name;
TB_Friendship.Text = ck3.CurrentFriendship.ToString();
GB_OT.BackgroundImage = null;
CB_Language.SelectedValue = ck3.Language;
CB_GameOrigin.SelectedValue = ck3.Version;
CB_EncounterType.SelectedValue = ck3.Gen4 ? ck3.EncounterType : 0;
CB_Ball.SelectedValue = ck3.Ball;
int cr = ck3.CurrentRegion;
int or = ck3.OriginalRegion;
int ver = ck3.Version;
CB_MetLocation.SelectedValue = ck3.Met_Location;
TB_MetLevel.Text = ck3.Met_Level.ToString();
// Reset Label and ComboBox visibility, as well as non-data checked status.
Label_PKRS.Visible = CB_PKRSStrain.Visible = CHK_Infected.Checked = ck3.PKRS_Strain != 0;
Label_PKRSdays.Visible = CB_PKRSDays.Visible = ck3.PKRS_Days != 0;
// Set SelectedIndexes for PKRS
CB_PKRSStrain.SelectedIndex = ck3.PKRS_Strain;
CHK_Cured.Checked = ck3.PKRS_Strain > 0 && ck3.PKRS_Days == 0;
CB_PKRSDays.SelectedIndex = Math.Min(CB_PKRSDays.Items.Count - 1, ck3.PKRS_Days); // to strip out bad hacked 'rus
TB_Cool.Text = ck3.CNT_Cool.ToString();
TB_Beauty.Text = ck3.CNT_Beauty.ToString();
TB_Cute.Text = ck3.CNT_Cute.ToString();
TB_Smart.Text = ck3.CNT_Smart.ToString();
TB_Tough.Text = ck3.CNT_Tough.ToString();
TB_Sheen.Text = ck3.CNT_Sheen.ToString();
TB_HPIV.Text = ck3.IV_HP.ToString();
TB_ATKIV.Text = ck3.IV_ATK.ToString();
TB_DEFIV.Text = ck3.IV_DEF.ToString();
TB_SPEIV.Text = ck3.IV_SPE.ToString();
TB_SPAIV.Text = ck3.IV_SPA.ToString();
TB_SPDIV.Text = ck3.IV_SPD.ToString();
CB_HPType.SelectedValue = ck3.HPType;
TB_HPEV.Text = ck3.EV_HP.ToString();
TB_ATKEV.Text = ck3.EV_ATK.ToString();
TB_DEFEV.Text = ck3.EV_DEF.ToString();
TB_SPEEV.Text = ck3.EV_SPE.ToString();
TB_SPAEV.Text = ck3.EV_SPA.ToString();
TB_SPDEV.Text = ck3.EV_SPD.ToString();
CB_Move1.SelectedValue = ck3.Move1;
CB_Move2.SelectedValue = ck3.Move2;
CB_Move3.SelectedValue = ck3.Move3;
CB_Move4.SelectedValue = ck3.Move4;
CB_PPu1.SelectedIndex = ck3.Move1_PPUps;
CB_PPu2.SelectedIndex = ck3.Move2_PPUps;
CB_PPu3.SelectedIndex = ck3.Move3_PPUps;
CB_PPu4.SelectedIndex = ck3.Move4_PPUps;
TB_PP1.Text = ck3.Move1_PP.ToString();
TB_PP2.Text = ck3.Move2_PP.ToString();
TB_PP3.Text = ck3.Move3_PP.ToString();
TB_PP4.Text = ck3.Move4_PP.ToString();
// Set Form if count is enough, else cap.
CB_Form.SelectedIndex = CB_Form.Items.Count > ck3.AltForm ? ck3.AltForm : CB_Form.Items.Count - 1;
// Load Extrabyte Value
TB_ExtraByte.Text = ck3.Data[Convert.ToInt32(CB_ExtraBytes.Text, 16)].ToString();
updateStats();
TB_EXP.Text = ck3.EXP.ToString();
Label_Gender.Text = gendersymbols[ck3.Gender];
Label_Gender.ForeColor = ck3.Gender == 2 ? Label_Species.ForeColor : (ck3.Gender == 1 ? Color.Red : Color.Blue);
}
private PKM prepareCK3()
{
CK3 ck3 = pkm as CK3;
if (ck3 == null)
return null;
ck3.Species = Util.getIndex(CB_Species);
ck3.G3Item = Util.getIndex(CB_HeldItem);
ck3.TID = Util.ToInt32(TB_TID.Text);
ck3.SID = Util.ToInt32(TB_SID.Text);
ck3.EXP = Util.ToUInt32(TB_EXP.Text);
ck3.PID = Util.getHEXval(TB_PID.Text);
ck3.AbilityNumber = CB_Ability.SelectedIndex;
ck3.FatefulEncounter = CHK_Fateful.Checked;
ck3.Gender = PKX.getGender(Label_Gender.Text);
ck3.EV_HP = Util.ToInt32(TB_HPEV.Text);
ck3.EV_ATK = Util.ToInt32(TB_ATKEV.Text);
ck3.EV_DEF = Util.ToInt32(TB_DEFEV.Text);
ck3.EV_SPE = Util.ToInt32(TB_SPEEV.Text);
ck3.EV_SPA = Util.ToInt32(TB_SPAEV.Text);
ck3.EV_SPD = Util.ToInt32(TB_SPDEV.Text);
ck3.CNT_Cool = Util.ToInt32(TB_Cool.Text);
ck3.CNT_Beauty = Util.ToInt32(TB_Beauty.Text);
ck3.CNT_Cute = Util.ToInt32(TB_Cute.Text);
ck3.CNT_Smart = Util.ToInt32(TB_Smart.Text);
ck3.CNT_Tough = Util.ToInt32(TB_Tough.Text);
ck3.CNT_Sheen = Util.ToInt32(TB_Sheen.Text);
ck3.PKRS_Days = CB_PKRSDays.SelectedIndex;
ck3.PKRS_Strain = CB_PKRSStrain.SelectedIndex;
ck3.Nickname = TB_Nickname.Text;
ck3.Move1 = Util.getIndex(CB_Move1);
ck3.Move2 = Util.getIndex(CB_Move2);
ck3.Move3 = Util.getIndex(CB_Move3);
ck3.Move4 = Util.getIndex(CB_Move4);
ck3.Move1_PP = Util.getIndex(CB_Move1) > 0 ? Util.ToInt32(TB_PP1.Text) : 0;
ck3.Move2_PP = Util.getIndex(CB_Move2) > 0 ? Util.ToInt32(TB_PP2.Text) : 0;
ck3.Move3_PP = Util.getIndex(CB_Move3) > 0 ? Util.ToInt32(TB_PP3.Text) : 0;
ck3.Move4_PP = Util.getIndex(CB_Move4) > 0 ? Util.ToInt32(TB_PP4.Text) : 0;
ck3.Move1_PPUps = Util.getIndex(CB_Move1) > 0 ? CB_PPu1.SelectedIndex : 0;
ck3.Move2_PPUps = Util.getIndex(CB_Move2) > 0 ? CB_PPu2.SelectedIndex : 0;
ck3.Move3_PPUps = Util.getIndex(CB_Move3) > 0 ? CB_PPu3.SelectedIndex : 0;
ck3.Move4_PPUps = Util.getIndex(CB_Move4) > 0 ? CB_PPu4.SelectedIndex : 0;
ck3.IV_HP = Util.ToInt32(TB_HPIV.Text);
ck3.IV_ATK = Util.ToInt32(TB_ATKIV.Text);
ck3.IV_DEF = Util.ToInt32(TB_DEFIV.Text);
ck3.IV_SPE = Util.ToInt32(TB_SPEIV.Text);
ck3.IV_SPA = Util.ToInt32(TB_SPAIV.Text);
ck3.IV_SPD = Util.ToInt32(TB_SPDIV.Text);
ck3.IsEgg = CHK_IsEgg.Checked;
ck3.IsNicknamed = CHK_Nicknamed.Checked;
ck3.OT_Name = TB_OT.Text;
ck3.CurrentFriendship = Util.ToInt32(TB_Friendship.Text);
ck3.Ball = Util.getIndex(CB_Ball);
ck3.Met_Level = Util.ToInt32(TB_MetLevel.Text);
ck3.OT_Gender = PKX.getGender(Label_OTGender.Text);
ck3.Version = Util.getIndex(CB_GameOrigin);
ck3.Language = Util.getIndex(CB_Language);
ck3.Met_Location = Util.getIndex(CB_MetLocation);
// Toss in Party Stats
Array.Resize(ref ck3.Data, ck3.SIZE_PARTY);
ck3.Stat_Level = Util.ToInt32(TB_Level.Text);
ck3.Stat_HPCurrent = Util.ToInt32(Stat_HP.Text);
ck3.Stat_HPMax = Util.ToInt32(Stat_HP.Text);
ck3.Stat_ATK = Util.ToInt32(Stat_ATK.Text);
ck3.Stat_DEF = Util.ToInt32(Stat_DEF.Text);
ck3.Stat_SPE = Util.ToInt32(Stat_SPE.Text);
ck3.Stat_SPA = Util.ToInt32(Stat_SPA.Text);
ck3.Stat_SPD = Util.ToInt32(Stat_SPD.Text);
if (HaX)
{
ck3.Stat_Level = (byte)Math.Min(Convert.ToInt32(MT_Level.Text), byte.MaxValue);
}
// Fix Moves if a slot is empty
ck3.FixMoves();
ck3.RefreshChecksum();
return ck3;
}
}
}

194
PKHeX/MainWindow/MainXK3.cs Normal file
View file

@ -0,0 +1,194 @@
using System;
using System.Drawing;
namespace PKHeX
{
public partial class Main
{
private void populateFieldsXK3()
{
XK3 xk3 = pkm as XK3;
if (xk3 == null)
return;
// Do first
xk3.Stat_Level = PKX.getLevel(xk3.Species, xk3.EXP);
if (xk3.Stat_Level == 100)
xk3.EXP = PKX.getEXP(xk3.Stat_Level, xk3.Species);
CB_Species.SelectedValue = xk3.Species;
TB_Level.Text = xk3.Stat_Level.ToString();
TB_EXP.Text = xk3.EXP.ToString();
// Load rest
CHK_Fateful.Checked = xk3.FatefulEncounter;
CHK_IsEgg.Checked = xk3.IsEgg;
CHK_Nicknamed.Checked = xk3.IsNicknamed;
Label_OTGender.Text = gendersymbols[xk3.OT_Gender];
Label_OTGender.ForeColor = xk3.OT_Gender == 1 ? Color.Red : Color.Blue;
TB_PID.Text = xk3.PID.ToString("X8");
CB_HeldItem.SelectedValue = xk3.G3Item;
setAbilityList();
CB_Ability.SelectedIndex = xk3.AbilityNumber > CB_Ability.Items.Count ? 0 : xk3.AbilityNumber;
CB_Nature.SelectedValue = xk3.Nature;
TB_TID.Text = xk3.TID.ToString("00000");
TB_SID.Text = xk3.SID.ToString("00000");
TB_Nickname.Text = xk3.Nickname;
TB_OT.Text = xk3.OT_Name;
TB_Friendship.Text = xk3.CurrentFriendship.ToString();
GB_OT.BackgroundImage = null;
CB_Language.SelectedValue = xk3.Language;
CB_GameOrigin.SelectedValue = xk3.Version;
CB_EncounterType.SelectedValue = xk3.Gen4 ? xk3.EncounterType : 0;
CB_Ball.SelectedValue = xk3.Ball;
CB_MetLocation.SelectedValue = xk3.Met_Location;
TB_MetLevel.Text = xk3.Met_Level.ToString();
// Reset Label and ComboBox visibility, as well as non-data checked status.
Label_PKRS.Visible = CB_PKRSStrain.Visible = CHK_Infected.Checked = xk3.PKRS_Strain != 0;
Label_PKRSdays.Visible = CB_PKRSDays.Visible = xk3.PKRS_Days != 0;
// Set SelectedIndexes for PKRS
CB_PKRSStrain.SelectedIndex = xk3.PKRS_Strain;
CHK_Cured.Checked = xk3.PKRS_Strain > 0 && xk3.PKRS_Days == 0;
CB_PKRSDays.SelectedIndex = Math.Min(CB_PKRSDays.Items.Count - 1, xk3.PKRS_Days); // to strip out bad hacked 'rus
TB_Cool.Text = xk3.CNT_Cool.ToString();
TB_Beauty.Text = xk3.CNT_Beauty.ToString();
TB_Cute.Text = xk3.CNT_Cute.ToString();
TB_Smart.Text = xk3.CNT_Smart.ToString();
TB_Tough.Text = xk3.CNT_Tough.ToString();
TB_Sheen.Text = xk3.CNT_Sheen.ToString();
TB_HPIV.Text = xk3.IV_HP.ToString();
TB_ATKIV.Text = xk3.IV_ATK.ToString();
TB_DEFIV.Text = xk3.IV_DEF.ToString();
TB_SPEIV.Text = xk3.IV_SPE.ToString();
TB_SPAIV.Text = xk3.IV_SPA.ToString();
TB_SPDIV.Text = xk3.IV_SPD.ToString();
CB_HPType.SelectedValue = xk3.HPType;
TB_HPEV.Text = xk3.EV_HP.ToString();
TB_ATKEV.Text = xk3.EV_ATK.ToString();
TB_DEFEV.Text = xk3.EV_DEF.ToString();
TB_SPEEV.Text = xk3.EV_SPE.ToString();
TB_SPAEV.Text = xk3.EV_SPA.ToString();
TB_SPDEV.Text = xk3.EV_SPD.ToString();
CB_Move1.SelectedValue = xk3.Move1;
CB_Move2.SelectedValue = xk3.Move2;
CB_Move3.SelectedValue = xk3.Move3;
CB_Move4.SelectedValue = xk3.Move4;
CB_PPu1.SelectedIndex = xk3.Move1_PPUps;
CB_PPu2.SelectedIndex = xk3.Move2_PPUps;
CB_PPu3.SelectedIndex = xk3.Move3_PPUps;
CB_PPu4.SelectedIndex = xk3.Move4_PPUps;
TB_PP1.Text = xk3.Move1_PP.ToString();
TB_PP2.Text = xk3.Move2_PP.ToString();
TB_PP3.Text = xk3.Move3_PP.ToString();
TB_PP4.Text = xk3.Move4_PP.ToString();
// Set Form if count is enough, else cap.
CB_Form.SelectedIndex = CB_Form.Items.Count > xk3.AltForm ? xk3.AltForm : CB_Form.Items.Count - 1;
// Load Extrabyte Value
TB_ExtraByte.Text = xk3.Data[Convert.ToInt32(CB_ExtraBytes.Text, 16)].ToString();
updateStats();
TB_EXP.Text = xk3.EXP.ToString();
Label_Gender.Text = gendersymbols[xk3.Gender];
Label_Gender.ForeColor = xk3.Gender == 2 ? Label_Species.ForeColor : (xk3.Gender == 1 ? Color.Red : Color.Blue);
}
private PKM prepareXK3()
{
XK3 xk3 = pkm as XK3;
if (xk3 == null)
return null;
xk3.Species = Util.getIndex(CB_Species);
xk3.G3Item = Util.getIndex(CB_HeldItem);
xk3.TID = Util.ToInt32(TB_TID.Text);
xk3.SID = Util.ToInt32(TB_SID.Text);
xk3.EXP = Util.ToUInt32(TB_EXP.Text);
xk3.PID = Util.getHEXval(TB_PID.Text);
xk3.AbilityNumber = CB_Ability.SelectedIndex; // 0/1 (stored in IVbits)
xk3.FatefulEncounter = CHK_Fateful.Checked;
xk3.Gender = PKX.getGender(Label_Gender.Text);
xk3.EV_HP = Util.ToInt32(TB_HPEV.Text);
xk3.EV_ATK = Util.ToInt32(TB_ATKEV.Text);
xk3.EV_DEF = Util.ToInt32(TB_DEFEV.Text);
xk3.EV_SPE = Util.ToInt32(TB_SPEEV.Text);
xk3.EV_SPA = Util.ToInt32(TB_SPAEV.Text);
xk3.EV_SPD = Util.ToInt32(TB_SPDEV.Text);
xk3.CNT_Cool = Util.ToInt32(TB_Cool.Text);
xk3.CNT_Beauty = Util.ToInt32(TB_Beauty.Text);
xk3.CNT_Cute = Util.ToInt32(TB_Cute.Text);
xk3.CNT_Smart = Util.ToInt32(TB_Smart.Text);
xk3.CNT_Tough = Util.ToInt32(TB_Tough.Text);
xk3.CNT_Sheen = Util.ToInt32(TB_Sheen.Text);
xk3.PKRS_Days = CB_PKRSDays.SelectedIndex;
xk3.PKRS_Strain = CB_PKRSStrain.SelectedIndex;
xk3.Nickname = TB_Nickname.Text;
xk3.Move1 = Util.getIndex(CB_Move1);
xk3.Move2 = Util.getIndex(CB_Move2);
xk3.Move3 = Util.getIndex(CB_Move3);
xk3.Move4 = Util.getIndex(CB_Move4);
xk3.Move1_PP = Util.getIndex(CB_Move1) > 0 ? Util.ToInt32(TB_PP1.Text) : 0;
xk3.Move2_PP = Util.getIndex(CB_Move2) > 0 ? Util.ToInt32(TB_PP2.Text) : 0;
xk3.Move3_PP = Util.getIndex(CB_Move3) > 0 ? Util.ToInt32(TB_PP3.Text) : 0;
xk3.Move4_PP = Util.getIndex(CB_Move4) > 0 ? Util.ToInt32(TB_PP4.Text) : 0;
xk3.Move1_PPUps = Util.getIndex(CB_Move1) > 0 ? CB_PPu1.SelectedIndex : 0;
xk3.Move2_PPUps = Util.getIndex(CB_Move2) > 0 ? CB_PPu2.SelectedIndex : 0;
xk3.Move3_PPUps = Util.getIndex(CB_Move3) > 0 ? CB_PPu3.SelectedIndex : 0;
xk3.Move4_PPUps = Util.getIndex(CB_Move4) > 0 ? CB_PPu4.SelectedIndex : 0;
xk3.IV_HP = Util.ToInt32(TB_HPIV.Text);
xk3.IV_ATK = Util.ToInt32(TB_ATKIV.Text);
xk3.IV_DEF = Util.ToInt32(TB_DEFIV.Text);
xk3.IV_SPE = Util.ToInt32(TB_SPEIV.Text);
xk3.IV_SPA = Util.ToInt32(TB_SPAIV.Text);
xk3.IV_SPD = Util.ToInt32(TB_SPDIV.Text);
xk3.IsEgg = CHK_IsEgg.Checked;
xk3.IsNicknamed = CHK_Nicknamed.Checked;
xk3.OT_Name = TB_OT.Text;
xk3.CurrentFriendship = Util.ToInt32(TB_Friendship.Text);
xk3.Ball = Util.getIndex(CB_Ball);
xk3.Met_Level = Util.ToInt32(TB_MetLevel.Text);
xk3.OT_Gender = PKX.getGender(Label_OTGender.Text);
xk3.Version = Util.getIndex(CB_GameOrigin);
xk3.Language = Util.getIndex(CB_Language);
xk3.Met_Location = Util.getIndex(CB_MetLocation);
// Toss in Party Stats
Array.Resize(ref xk3.Data, xk3.SIZE_PARTY);
xk3.Stat_Level = Util.ToInt32(TB_Level.Text);
xk3.Stat_HPCurrent = Util.ToInt32(Stat_HP.Text);
xk3.Stat_HPMax = Util.ToInt32(Stat_HP.Text);
xk3.Stat_ATK = Util.ToInt32(Stat_ATK.Text);
xk3.Stat_DEF = Util.ToInt32(Stat_DEF.Text);
xk3.Stat_SPE = Util.ToInt32(Stat_SPE.Text);
xk3.Stat_SPA = Util.ToInt32(Stat_SPA.Text);
xk3.Stat_SPD = Util.ToInt32(Stat_SPD.Text);
if (HaX)
{
xk3.Stat_Level = (byte)Math.Min(Convert.ToInt32(MT_Level.Text), byte.MaxValue);
}
// Fix Moves if a slot is empty
xk3.FixMoves();
xk3.RefreshChecksum();
return xk3;
}
}
}

View file

@ -105,12 +105,18 @@
<Compile Include="Legality\Tables3.cs" />
<Compile Include="Legality\Tables5.cs" />
<Compile Include="Legality\Tables4.cs" />
<Compile Include="MainWindow\MainXK3.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainWindow\MainPK2.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainWindow\MainPK1.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainWindow\MainCK3.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainWindow\MainPK6.cs">
<SubType>Form</SubType>
</Compile>
@ -141,6 +147,8 @@
<Compile Include="PersonalInfo\PersonalInfoORAS.cs" />
<Compile Include="PersonalInfo\PersonalInfoXY.cs" />
<Compile Include="PersonalInfo\PersonalTable.cs" />
<Compile Include="PKM\CK3.cs" />
<Compile Include="PKM\XK3.cs" />
<Compile Include="PKM\PK1.cs" />
<Compile Include="PKM\PK2.cs" />
<Compile Include="PKM\PKM.cs" />
@ -164,6 +172,8 @@
<Compile Include="Saves\Inventory.cs" />
<Compile Include="Saves\SAV2.cs" />
<Compile Include="Saves\SAV1.cs" />
<Compile Include="Saves\SAV3XD.cs" />
<Compile Include="Saves\SAV3Colosseum.cs" />
<Compile Include="Saves\SAV3RSBox.cs" />
<Compile Include="Saves\SAV3.cs" />
<Compile Include="Saves\SAV4.cs" />

211
PKHeX/PKM/CK3.cs Normal file
View file

@ -0,0 +1,211 @@
using System;
using System.Linq;
namespace PKHeX
{
public class CK3 : PKM // 3rd Generation PKM File
{
internal static readonly byte[] ExtraBytes =
{
0x11, 0x12, 0x13,
0x61, 0x62, 0x63, 0x64,
0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xDA, 0xDB,
0xE4, 0xE5, 0xE6, 0xE7, 0xCE,
// 0xFC onwards unused?
};
public sealed override int SIZE_PARTY => PKX.SIZE_3CSTORED;
public override int SIZE_STORED => PKX.SIZE_3CSTORED;
public override int Format => 3;
public CK3(byte[] decryptedData = null, string ident = null)
{
Data = (byte[])(decryptedData ?? new byte[SIZE_PARTY]).Clone();
PKMConverter.checkEncrypted(ref Data);
Identifier = ident;
if (Data.Length != SIZE_PARTY)
Array.Resize(ref Data, SIZE_PARTY);
}
public override PKM Clone() { return new CK3(Data); }
// Future Attributes
public override uint EncryptionConstant { get { return PID; } set { } }
public override int Nature { get { return (int)(PID % 25); } set { } }
public override int AltForm { get { return Species == 201 ? PKX.getUnownForm(PID) : 0; } 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; } }
public override int Ability { get { int[] abils = PersonalTable.RS.getAbilities(Species, 0); return abils[abils[1] == 0 ? 0 : AbilityNumber]; } set { } }
public override int CurrentHandler { get { return 0; } set { } }
public override int Egg_Location { get { return 0; } set { } }
// Silly Attributes
public override ushort Sanity { get { return 0; } set { } } // valid flag set in pkm structure.
public override ushort Checksum { get { return PKX.getCHK(Data); } set { } } // totally false, just a way to get a 'random' ident for the pkm.
public override int Species { get { return PKX.getG4Species(BigEndian.ToUInt16(Data, 0x00)); } set { BigEndian.GetBytes((ushort)PKX.getG3Species(value)).CopyTo(Data, 0x00); } }
// 02-04 unused
public override uint PID { get { return BigEndian.ToUInt32(Data, 0x04); } set { BigEndian.GetBytes(value).CopyTo(Data, 0x04); } }
public override int Version { get { return SaveUtil.getG3VersionID(Data[0x08]); } set { Data[0x08] = (byte)SaveUtil.getCXDVersionID(value); } }
public int CurrentRegion { get { return Data[0x09]; } set { Data[0x09] = (byte)value; } }
public int OriginalRegion { get { return Data[0x0A]; } set { Data[0x0A] = (byte)value; } }
public override int Language { get { return Data[0x0B]; } set { Data[0x0B] = (byte)value; } }
public override int Met_Location { get { return BigEndian.ToUInt16(Data, 0x0C); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x0C);} }
public override int Met_Level { get { return Data[0x0E]; } set { Data[0x0E] = (byte)value; } }
public override int Ball { get { return Data[0x0F]; } set { Data[0x0F] = (byte)value; } }
public override int OT_Gender { get { return Data[0x10]; } set { Data[0x10] = (byte)value; } }
public override int SID { get { return BigEndian.ToUInt16(Data, 0x14); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x14); } }
public override int TID { get { return BigEndian.ToUInt16(Data, 0x16); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x16); } }
public override string OT_Name { get { return PKX.getColoStr(Data, 0x18, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x18); } } // +2 terminator
public override string Nickname { get { return PKX.getColoStr(Data, 0x2E, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x2E); Nickname2 = value; } } // +2 terminator
private string Nickname2 { get { return PKX.getColoStr(Data, 0x44, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x44); } } // +2 terminator
public override uint EXP { get { return BigEndian.ToUInt32(Data, 0x5C); } set { BigEndian.GetBytes(value).CopyTo(Data, 0x5C);} }
public override int Stat_Level { get { return Data[0x60]; } set { Data[0x60] = (byte)value; } }
// 0x64-0x77 are battle/status related
// Not that the program cares
// Moves
public override int Move1 { get { return BigEndian.ToUInt16(Data, 0x78); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x78); } }
public override int Move1_PP { get { return Data[0x7A]; } set { Data[0x7A] = (byte)value; } }
public override int Move1_PPUps { get { return Data[0x7B]; } set { Data[0x7B] = (byte)value; } }
public override int Move2 { get { return BigEndian.ToUInt16(Data, 0x7C); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x7C); } }
public override int Move2_PP { get { return Data[0x7E]; } set { Data[0x7E] = (byte)value; } }
public override int Move2_PPUps { get { return Data[0x7F]; } set { Data[0x7F] = (byte)value; } }
public override int Move3 { get { return BigEndian.ToUInt16(Data, 0x80); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x80); } }
public override int Move3_PP { get { return Data[0x82]; } set { Data[0x82] = (byte)value; } }
public override int Move3_PPUps { get { return Data[0x83]; } set { Data[0x83] = (byte)value; } }
public override int Move4 { get { return BigEndian.ToUInt16(Data, 0x84); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x84); } }
public override int Move4_PP { get { return Data[0x86]; } set { Data[0x86] = (byte)value; } }
public override int Move4_PPUps { get { return Data[0x87]; } set { Data[0x87] = (byte)value; } }
public override int HeldItem { get { return PKX.getG4Item((ushort)G3Item); } set { } }
public int G3Item { get { return BigEndian.ToUInt16(Data, 0x88); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x88); } }
// More party stats
public override int Stat_HPCurrent { get { return BigEndian.ToUInt16(Data, 0x8A); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x8A); } }
public override int Stat_HPMax { get { return BigEndian.ToUInt16(Data, 0x8C); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x8C); } }
public override int Stat_ATK { get { return BigEndian.ToUInt16(Data, 0x8E); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x8E); } }
public override int Stat_DEF { get { return BigEndian.ToUInt16(Data, 0x90); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x90); } }
public override int Stat_SPE { get { return BigEndian.ToUInt16(Data, 0x92); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x92); } }
public override int Stat_SPA { get { return BigEndian.ToUInt16(Data, 0x94); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x94); } }
public override int Stat_SPD { get { return BigEndian.ToUInt16(Data, 0x96); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x96); } }
// EVs
public override int EV_HP {
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0x98)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0x98); } }
public override int EV_ATK {
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0x9A)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0x9A); } }
public override int EV_DEF {
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0x9C)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0x9C); } }
public override int EV_SPA {
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0x9E)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0x9E); } }
public override int EV_SPD {
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0xA0)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0xA0); } }
public override int EV_SPE {
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0xA2)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0xA2); } }
// IVs
public override int IV_HP {
get { return Math.Min((ushort)31, BigEndian.ToUInt16(Data, 0xA4)); }
set { BigEndian.GetBytes((ushort)(value & 0x1F)).CopyTo(Data, 0xA4); } }
public override int IV_ATK {
get { return Math.Min((ushort)31, BigEndian.ToUInt16(Data, 0xA6)); }
set { BigEndian.GetBytes((ushort)(value & 0x1F)).CopyTo(Data, 0xA6); } }
public override int IV_DEF {
get { return Math.Min((ushort)31, BigEndian.ToUInt16(Data, 0xA8)); }
set { BigEndian.GetBytes((ushort)(value & 0x1F)).CopyTo(Data, 0xA8); } }
public override int IV_SPA {
get { return Math.Min((ushort)31, BigEndian.ToUInt16(Data, 0xAA)); }
set { BigEndian.GetBytes((ushort)(value & 0x1F)).CopyTo(Data, 0xAA); } }
public override int IV_SPD {
get { return Math.Min((ushort)31, BigEndian.ToUInt16(Data, 0xAC)); }
set { BigEndian.GetBytes((ushort)(value & 0x1F)).CopyTo(Data, 0xAC); } }
public override int IV_SPE {
get { return Math.Min((ushort)31, BigEndian.ToUInt16(Data, 0xAE)); }
set { BigEndian.GetBytes((ushort)(value & 0x1F)).CopyTo(Data, 0xAE); } }
public override int OT_Friendship { get { return Data[0xB0]; } set { Data[0xB0] = (byte)value; } }
// Contest
public override int CNT_Cool { get { return Data[0xB2]; } set { Data[0xB2] = (byte)value; } }
public override int CNT_Beauty { get { return Data[0xB3]; } set { Data[0xB3] = (byte)value; } }
public override int CNT_Cute { get { return Data[0xB4]; } set { Data[0xB4] = (byte)value; } }
public override int CNT_Smart { get { return Data[0xB5]; } set { Data[0xB5] = (byte)value; } }
public override int CNT_Tough { get { return Data[0xB6]; } set { Data[0xB6] = (byte)value; } }
public int RibbonCountG3Cool { get { return Data[0xB7]; } set { Data[0xB7] = (byte)value; } }
public int RibbonCountG3Beauty { get { return Data[0xB8]; } set { Data[0xB8] = (byte)value; } }
public int RibbonCountG3Cute { get { return Data[0xB9]; } set { Data[0xB9] = (byte)value; } }
public int RibbonCountG3Smart { get { return Data[0xBA]; } set { Data[0xBA] = (byte)value; } }
public int RibbonCountG3Tough { get { return Data[0xBB]; } set { Data[0xBB] = (byte)value; } }
public override int CNT_Sheen { get { return Data[0xBC]; } set { Data[0xBC] = (byte)value; } }
// Ribbons
public bool RibbonChampionG3Hoenn { get { return Data[0xBD] == 1; } set { Data[0xBD] = (byte)(value ? 1 : 0); } }
public bool RibbonWinning { get { return Data[0xBE] == 1; } set { Data[0xBE] = (byte)(value ? 1 : 0); } }
public bool RibbonVictory { get { return Data[0xBF] == 1; } set { Data[0xBF] = (byte)(value ? 1 : 0); } }
public bool RibbonArtist { get { return Data[0xC0] == 1; } set { Data[0xC0] = (byte)(value ? 1 : 0); } }
public bool RibbonEffort { get { return Data[0xC1] == 1; } set { Data[0xC1] = (byte)(value ? 1 : 0); } }
public bool RibbonChampionBattle { get { return Data[0xC2] == 1; } set { Data[0xC2] = (byte)(value ? 1 : 0); } }
public bool RibbonChampionRegional { get { return Data[0xC3] == 1; } set { Data[0xC3] = (byte)(value ? 1 : 0); } }
public bool RibbonChampionNational { get { return Data[0xC4] == 1; } set { Data[0xC4] = (byte)(value ? 1 : 0); } }
public bool RibbonCountry { get { return Data[0xC5] == 1; } set { Data[0xC5] = (byte)(value ? 1 : 0); } }
public bool RibbonNational { get { return Data[0xC6] == 1; } set { Data[0xC6] = (byte)(value ? 1 : 0); } }
public bool RibbonEarth { get { return Data[0xC7] == 1; } set { Data[0xC7] = (byte)(value ? 1 : 0); } }
public bool RibbonWorld { get { return Data[0xC8] == 1; } set { Data[0xC8] = (byte)(value ? 1 : 0); } }
public bool Unused1 { get { return ((Data[0xC9]>>0) & 1) == 1; } set { Data[0xC9] = (byte)(Data[0xC9] & ~1 | (value ? 1 : 0)); } }
public bool Unused2 { get { return ((Data[0xC9]>>1) & 1) == 1; } set { Data[0xC9] = (byte)(Data[0xC9] & ~2 | (value ? 2 : 0)); } }
public bool Unused3 { get { return ((Data[0xC9]>>2) & 1) == 1; } set { Data[0xC9] = (byte)(Data[0xC9] & ~4 | (value ? 4 : 0)); } }
public bool Unused4 { get { return ((Data[0xC9]>>3) & 1) == 1; } set { Data[0xC9] = (byte)(Data[0xC9] & ~8 | (value ? 8 : 0)); } }
public override int PKRS_Strain { get { return Data[0xCA] & 0xF; } set { Data[0xCA] = (byte)(value & 0xF); } }
public override bool IsEgg { get { return Data[0xCB] == 1; } set { Data[0xCB] = (byte)(value ? 1 : 0); } }
public int AbilityNumber { get { return Data[0xCC]; } set { Data[0xCC] = (byte)(value & 1); } }
public override bool Valid => Data[0xCD] == 0;
// 0xCE unknown
public override byte MarkByte { get { return Data[0xCF]; } protected set { Data[0xCF] = value; } }
public override int PKRS_Days { get { return Data[0xD0] & 0xF; } set { Data[0xD0] = (byte)(value & 0xF); } }
public ushort ShadowID { get { return BigEndian.ToUInt16(Data, 0xD8); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xD8); } }
public int Purification { get { return BigEndian.ToInt32(Data, 0xDC); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xDC); } }
public uint EXP_Shadow { get { return BigEndian.ToUInt32(Data, 0xC0); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xC0); } }
public override bool FatefulEncounter { get { return Data[0x11C] == 1; } set { Data[0x11C] = (byte)(value ? 1 : 0); } }
public new int EncounterType { get { return Data[0xFB]; } set { Data[0xFB] = (byte)value; } }
// Generated Attributes
public override int PSV => (int)((PID >> 16 ^ PID & 0xFFFF) >> 3);
public override int TSV => (TID ^ SID) >> 3;
public bool Japanese => Language == 1;
public override byte[] Encrypt()
{
return (byte[])Data.Clone();
}
public override bool getGenderIsValid()
{
int gv = PersonalTable.RS[Species].Gender;
if (gv == 255)
return Gender == 2;
if (gv == 254)
return Gender == 0;
if (gv == 0)
return Gender == 1;
if (gv <= (PID & 0xFF))
return Gender == 0;
if ((PID & 0xFF) < gv)
return Gender == 1;
return false;
}
public override bool CanHoldItem(ushort[] ValidArray)
{
return ValidArray.Contains((ushort)G3Item);
}
}
}

View file

@ -4,6 +4,7 @@ using System.Drawing;
using System.Drawing.Text;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using PKHeX.Properties;
namespace PKHeX
@ -20,6 +21,8 @@ namespace PKHeX
internal const int SIZE_2PARTY = 48;
internal const int SIZE_2STORED = 32;
internal const int SIZE_3CSTORED = 312;
internal const int SIZE_3XSTORED = 196;
internal const int SIZE_3PARTY = 100;
internal const int SIZE_3STORED = 80;
internal const int SIZE_3BLOCK = 12;
@ -2228,5 +2231,20 @@ namespace PKHeX
.ToArray();
}
public static string getColoStr(byte[] data, int offset, int length)
{
return Util.TrimFromZero(Encoding.BigEndianUnicode.GetString(data, offset, length * 2));
}
public static byte[] setColoStr(string value, int length)
{
if (value.Length > length)
value = value.Substring(0, length); // Hard cap
string TempNick = value // Replace Special Characters and add Terminator
.Replace("\u2640", "\uE08F") // nidoran
.Replace("\u2642", "\uE08E") // nidoran
.Replace("\u0027", "\u2019") // farfetch'd
.PadRight(value.Length + 1, (char)0); // Null Terminator
return Encoding.BigEndianUnicode.GetBytes(TempNick);
}
}
}

217
PKHeX/PKM/XK3.cs Normal file
View file

@ -0,0 +1,217 @@
using System;
using System.Linq;
namespace PKHeX
{
public class XK3 : PKM // 3rd Generation PKM File
{
internal static readonly byte[] ExtraBytes =
{
0x0A, 0x0B, 0x0C, 0x0D, 0x1E, 0x1F,
0x2A, 0x2B,
0x7A, 0x7B,
0x7E, 0x7F
};
public sealed override int SIZE_PARTY => PKX.SIZE_3CSTORED;
public override int SIZE_STORED => PKX.SIZE_3CSTORED;
public override int Format => 3;
public XK3(byte[] decryptedData = null, string ident = null)
{
Data = (byte[])(decryptedData ?? new byte[SIZE_PARTY]).Clone();
PKMConverter.checkEncrypted(ref Data);
Identifier = ident;
if (Data.Length != SIZE_PARTY)
Array.Resize(ref Data, SIZE_PARTY);
}
public override PKM Clone() { return new XK3(Data); }
// Future Attributes
public override uint EncryptionConstant { get { return PID; } set { } }
public override int Nature { get { return (int)(PID % 25); } set { } }
public override int AltForm { get { return Species == 201 ? PKX.getUnownForm(PID) : 0; } 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; } }
public override int Ability { get { int[] abils = PersonalTable.RS.getAbilities(Species, 0); return abils[abils[1] == 0 ? 0 : AbilityNumber]; } set { } }
public override int CurrentHandler { get { return 0; } set { } }
public override int Egg_Location { get { return 0; } set { } }
// Silly Attributes
public override ushort Sanity { get { return 0; } set { } } // valid flag set in pkm structure.
public override ushort Checksum { get { return PKX.getCHK(Data); } set { } } // totally false, just a way to get a 'random' ident for the pkm.
public override int Species { get { return PKX.getG4Species(BigEndian.ToUInt16(Data, 0x00)); } set { BigEndian.GetBytes((ushort)PKX.getG3Species(value)).CopyTo(Data, 0x00); } }
public override int HeldItem { get { return PKX.getG4Item((ushort)G3Item); } set { } }
public int G3Item { get { return BigEndian.ToUInt16(Data, 0x02); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x02); } }
public override int Stat_HPCurrent { get { return BigEndian.ToUInt16(Data, 0x04); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x04); } }
public override int OT_Friendship { get { return Data[0x06]; } set { Data[0x06] = (byte)value; } }
public override int Met_Location { get { return BigEndian.ToUInt16(Data, 0x08); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x08); } }
// 0x0A-0x0B Unknown
// 0x0C-0x0D Unknown
public override int Met_Level { get { return Data[0x0E]; } set { Data[0x0E] = (byte)value; } }
public override int Ball { get { return Data[0x0F]; } set { Data[0x0F] = (byte)value; } }
public override int OT_Gender { get { return Data[0x10]; } set { Data[0x10] = (byte)value; } }
public override int Stat_Level { get { return Data[0x11]; } set { Data[0x11] = (byte)value; } }
public override int CNT_Sheen { get { return Data[0x12]; } set { Data[0x12] = (byte)value; } }
public override int PKRS_Strain { get { return Data[0x13] & 0xF; } set { Data[0x13] = (byte)(value & 0xF); } }
public override byte MarkByte { get { return Data[0x14]; } protected set { Data[0x14] = value; } }
public override int PKRS_Days { get { return Data[0x15] & 0xF; } set { Data[0x15] = (byte)(value & 0xF); } }
// 0x16-0x1C Battle Related
private int XDPKMFLAGS { get { return Data[0x1D]; } set { Data[0x1D] = (byte)value; } }
public bool UnusedFlag0 { get { return (XDPKMFLAGS & (1 << 0)) == 1 << 0; } set { XDPKMFLAGS = XDPKMFLAGS & ~(1 << 0) | (value ? 1 << 0 : 0); } }
public bool UnusedFlag1 { get { return (XDPKMFLAGS & (1 << 1)) == 1 << 1; } set { XDPKMFLAGS = XDPKMFLAGS & ~(1 << 1) | (value ? 1 << 1 : 0); } }
public bool CapturedFlag { get { return (XDPKMFLAGS & (1 << 2)) == 1 << 2; } set { XDPKMFLAGS = XDPKMFLAGS & ~(1 << 2) | (value ? 1 << 2 : 0); } }
public bool UnusedFlag3 { get { return (XDPKMFLAGS & (1 << 3)) == 1 << 3; } set { XDPKMFLAGS = XDPKMFLAGS & ~(1 << 3) | (value ? 1 << 3 : 0); } }
public bool BlockTrades { get { return (XDPKMFLAGS & (1 << 4)) == 1 << 4; } set { XDPKMFLAGS = XDPKMFLAGS & ~(1 << 4) | (value ? 1 << 4 : 0); } }
public override bool Valid => (XDPKMFLAGS & (1 << 5)) == 1 << 5;
public int AbilityNumber { get { return (XDPKMFLAGS >> 6) & 1; } set { XDPKMFLAGS = XDPKMFLAGS & ~(1 << 6) | (value << 6); } }
public override bool IsEgg { get { return (XDPKMFLAGS & (1 << 7)) == 1 << 7; } set { XDPKMFLAGS = XDPKMFLAGS & ~(1 << 7) | (value ? 1 << 7 : 0); } }
// 0x1E-0x1F Unknown
public override uint EXP { get { return BigEndian.ToUInt32(Data, 0x20); } set { BigEndian.GetBytes(value).CopyTo(Data, 0x20); } }
public override int SID { get { return BigEndian.ToUInt16(Data, 0x24); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x24); } }
public override int TID { get { return BigEndian.ToUInt16(Data, 0x26); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x26); } }
public override uint PID { get { return BigEndian.ToUInt32(Data, 0x28); } set { BigEndian.GetBytes(value).CopyTo(Data, 0x28); } }
// 0x2A-0x2B Unknown
// 0x2C-0x2F Battle Related
public override bool FatefulEncounter { get { return Data[0x30] == 1; } set { Data[0x30] = (byte)(value ? 1 : 0); } }
// 0x31-0x32 Unknown
public new int EncounterType { get { return Data[0x33]; } set { Data[0x33] = (byte)value; } }
public override int Version { get { return SaveUtil.getG3VersionID(Data[0x34]); } set { Data[0x34] = (byte)SaveUtil.getCXDVersionID(value); } }
public int CurrentRegion { get { return Data[0x35]; } set { Data[0x35] = (byte)value; } }
public int OriginalRegion { get { return Data[0x36]; } set { Data[0x36] = (byte)value; } }
public override int Language { get { return Data[0x37]; } set { Data[0x37] = (byte)value; } }
public override string OT_Name { get { return PKX.getColoStr(Data, 0x38, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x38); } } // +2 terminator
public override string Nickname { get { return PKX.getColoStr(Data, 0x4E, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x4E); Nickname2 = value; } } // +2 terminator
private string Nickname2 { get { return PKX.getColoStr(Data, 0x64, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x64); } } // +2 terminator
// 0x7A-0x7B Unknown
private ushort RIB0 { get { return BigEndian.ToUInt16(Data, 0x7C); } set { BigEndian.GetBytes(value).CopyTo(Data, 0x7C); } }
public bool RibbonChampionG3Hoenn { get { return (RIB0 & (1 << 00)) == 1 << 00; } set { RIB0 = (ushort)(RIB0 & ~(1 << 00) | (ushort)(value ? 1 << 00 : 0)); } }
public bool RibbonWinning { get { return (RIB0 & (1 << 01)) == 1 << 01; } set { RIB0 = (ushort)(RIB0 & ~(1 << 01) | (ushort)(value ? 1 << 01 : 0)); } }
public bool RibbonVictory { get { return (RIB0 & (1 << 02)) == 1 << 02; } set { RIB0 = (ushort)(RIB0 & ~(1 << 02) | (ushort)(value ? 1 << 02 : 0)); } }
public bool RibbonArtist { get { return (RIB0 & (1 << 03)) == 1 << 03; } set { RIB0 = (ushort)(RIB0 & ~(1 << 03) | (ushort)(value ? 1 << 03 : 0)); } }
public bool RibbonEffort { get { return (RIB0 & (1 << 04)) == 1 << 04; } set { RIB0 = (ushort)(RIB0 & ~(1 << 04) | (ushort)(value ? 1 << 04 : 0)); } }
public bool RibbonChampionBattle { get { return (RIB0 & (1 << 05)) == 1 << 05; } set { RIB0 = (ushort)(RIB0 & ~(1 << 05) | (ushort)(value ? 1 << 05 : 0)); } }
public bool RibbonChampionRegional { get { return (RIB0 & (1 << 06)) == 1 << 06; } set { RIB0 = (ushort)(RIB0 & ~(1 << 06) | (ushort)(value ? 1 << 06 : 0)); } }
public bool RibbonChampionNational { get { return (RIB0 & (1 << 07)) == 1 << 07; } set { RIB0 = (ushort)(RIB0 & ~(1 << 07) | (ushort)(value ? 1 << 07 : 0)); } }
public bool RibbonCountry { get { return (RIB0 & (1 << 08)) == 1 << 08; } set { RIB0 = (ushort)(RIB0 & ~(1 << 08) | (ushort)(value ? 1 << 08 : 0)); } }
public bool RibbonNational { get { return (RIB0 & (1 << 09)) == 1 << 09; } set { RIB0 = (ushort)(RIB0 & ~(1 << 09) | (ushort)(value ? 1 << 09 : 0)); } }
public bool RibbonEarth { get { return (RIB0 & (1 << 10)) == 1 << 10; } set { RIB0 = (ushort)(RIB0 & ~(1 << 10) | (ushort)(value ? 1 << 10 : 0)); } }
public bool RibbonWorld { get { return (RIB0 & (1 << 11)) == 1 << 11; } set { RIB0 = (ushort)(RIB0 & ~(1 << 11) | (ushort)(value ? 1 << 11 : 0)); } }
public bool Unused1 { get { return (RIB0 & (1 << 12)) == 1 << 12; } set { RIB0 = (ushort)(RIB0 & ~(1 << 12) | (ushort)(value ? 1 << 12 : 0)); } }
public bool Unused2 { get { return (RIB0 & (1 << 13)) == 1 << 13; } set { RIB0 = (ushort)(RIB0 & ~(1 << 13) | (ushort)(value ? 1 << 13 : 0)); } }
public bool Unused3 { get { return (RIB0 & (1 << 14)) == 1 << 14; } set { RIB0 = (ushort)(RIB0 & ~(1 << 14) | (ushort)(value ? 1 << 14 : 0)); } }
public bool Unused4 { get { return (RIB0 & (1 << 15)) == 1 << 15; } set { RIB0 = (ushort)(RIB0 & ~(1 << 15) | (ushort)(value ? 1 << 15 : 0)); } }
// 0x7E-0x7F Unknown
// Moves
public override int Move1 { get { return BigEndian.ToUInt16(Data, 0x80); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x80); } }
public override int Move1_PP { get { return Data[0x82]; } set { Data[0x82] = (byte)value; } }
public override int Move1_PPUps { get { return Data[0x83]; } set { Data[0x83] = (byte)value; } }
public override int Move2 { get { return BigEndian.ToUInt16(Data, 0x84); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x84); } }
public override int Move2_PP { get { return Data[0x86]; } set { Data[0x86] = (byte)value; } }
public override int Move2_PPUps { get { return Data[0x87]; } set { Data[0x87] = (byte)value; } }
public override int Move3 { get { return BigEndian.ToUInt16(Data, 0x88); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x88); } }
public override int Move3_PP { get { return Data[0x8A]; } set { Data[0x8A] = (byte)value; } }
public override int Move3_PPUps { get { return Data[0x8B]; } set { Data[0x8B] = (byte)value; } }
public override int Move4 { get { return BigEndian.ToUInt16(Data, 0x8C); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x8C); } }
public override int Move4_PP { get { return Data[0x8E]; } set { Data[0x8E] = (byte)value; } }
public override int Move4_PPUps { get { return Data[0x8F]; } set { Data[0x8F] = (byte)value; } }
// More party stats
public override int Stat_HPMax { get { return BigEndian.ToUInt16(Data, 0x90); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x90); } }
public override int Stat_ATK { get { return BigEndian.ToUInt16(Data, 0x92); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x92); } }
public override int Stat_DEF { get { return BigEndian.ToUInt16(Data, 0x94); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x94); } }
public override int Stat_SPE { get { return BigEndian.ToUInt16(Data, 0x96); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x96); } }
public override int Stat_SPA { get { return BigEndian.ToUInt16(Data, 0x98); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x98); } }
public override int Stat_SPD { get { return BigEndian.ToUInt16(Data, 0x9A); } set { BigEndian.GetBytes((ushort)value).CopyTo(Data, 0x9A); } }
// EVs
public override int EV_HP
{
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0x9C)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0x9C); }
}
public override int EV_ATK
{
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0x9E)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0x9E); }
}
public override int EV_DEF
{
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0xA0)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0xA0); }
}
public override int EV_SPA
{
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0xA2)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0xA2); }
}
public override int EV_SPD
{
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0xA4)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0xA4); }
}
public override int EV_SPE
{
get { return Math.Min(byte.MaxValue, BigEndian.ToUInt16(Data, 0xA6)); }
set { BigEndian.GetBytes((ushort)(value & 0xFF)).CopyTo(Data, 0xA6); }
}
// IVs
public override int IV_HP { get { return Data[0xA8]; } set { Data[0xA8] = (byte)(value & 0x1F); } }
public override int IV_ATK { get { return Data[0xA9]; } set { Data[0xA9] = (byte)(value & 0x1F); } }
public override int IV_DEF { get { return Data[0xAA]; } set { Data[0xAA] = (byte)(value & 0x1F); } }
public override int IV_SPA { get { return Data[0xAB]; } set { Data[0xAB] = (byte)(value & 0x1F); } }
public override int IV_SPD { get { return Data[0xAC]; } set { Data[0xAC] = (byte)(value & 0x1F); } }
public override int IV_SPE { get { return Data[0xAD]; } set { Data[0xAD] = (byte)(value & 0x1F); } }
// Contest
public override int CNT_Cool { get { return Data[0xAE]; } set { Data[0xAE] = (byte)value; } }
public override int CNT_Beauty { get { return Data[0xAF]; } set { Data[0xAF] = (byte)value; } }
public override int CNT_Cute { get { return Data[0xB0]; } set { Data[0xB0] = (byte)value; } }
public override int CNT_Smart { get { return Data[0xB1]; } set { Data[0xB1] = (byte)value; } }
public override int CNT_Tough { get { return Data[0xB2]; } set { Data[0xB2] = (byte)value; } }
public int RibbonCountG3Cool { get { return Data[0xB3]; } set { Data[0xB3] = (byte)value; } }
public int RibbonCountG3Beauty { get { return Data[0xB4]; } set { Data[0xB4] = (byte)value; } }
public int RibbonCountG3Cute { get { return Data[0xB5]; } set { Data[0xB5] = (byte)value; } }
public int RibbonCountG3Smart { get { return Data[0xB6]; } set { Data[0xB6] = (byte)value; } }
public int RibbonCountG3Tough { get { return Data[0xB7]; } set { Data[0xB7] = (byte)value; } }
public ushort ShadowID { get { return BigEndian.ToUInt16(Data, 0xBA); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xBA); } }
// Purification information is stored in the save file and accessed based on the Shadow ID.
// Generated Attributes
public override int PSV => (int)((PID >> 16 ^ PID & 0xFFFF) >> 3);
public override int TSV => (TID ^ SID) >> 3;
public bool Japanese => Language == 1;
public override byte[] Encrypt()
{
return (byte[])Data.Clone();
}
public override bool getGenderIsValid()
{
int gv = PersonalTable.RS[Species].Gender;
if (gv == 255)
return Gender == 2;
if (gv == 254)
return Gender == 0;
if (gv == 0)
return Gender == 1;
if (gv <= (PID & 0xFF))
return Gender == 0;
if ((PID & 0xFF) < gv)
return Gender == 1;
return false;
}
public override bool CanHoldItem(ushort[] ValidArray)
{
return ValidArray.Contains((ushort)G3Item);
}
}
}

View file

@ -63,7 +63,30 @@ namespace PKHeX
BitConverter.GetBytes((ushort)((ushort)Items[i].Count ^ (ushort)SecurityKey)).CopyTo(Data, Offset + i*4 + 2);
}
}
public void getPouchBigEndian(ref byte[] Data)
{
InventoryItem[] items = new InventoryItem[PouchDataSize];
for (int i = 0; i < items.Length; i++)
{
items[i] = new InventoryItem
{
Index = BigEndian.ToUInt16(Data, Offset + i * 4),
Count = BigEndian.ToUInt16(Data, Offset + i * 4 + 2) ^ (ushort)SecurityKey
};
}
Items = items;
}
public void setPouchBigEndian(ref byte[] Data)
{
if (Items.Length != PouchDataSize)
throw new ArgumentException("Item array length does not match original pouch size.");
for (int i = 0; i < Items.Length; i++)
{
BigEndian.GetBytes((ushort)Items[i].Index).CopyTo(Data, Offset + i * 4);
BigEndian.GetBytes((ushort)((ushort)Items[i].Count ^ (ushort)SecurityKey)).CopyTo(Data, Offset + i * 4 + 2);
}
}
public void getPouchG1(ref byte[] Data)
{
InventoryItem[] items = new InventoryItem[PouchDataSize];

View file

@ -0,0 +1,401 @@
using System;
using System.Linq;
using System.Security.Cryptography;
namespace PKHeX
{
public sealed class SAV3Colosseum : SaveFile
{
public override string BAKName => $"{FileName} [{OT} ({Version}) - {PlayTimeString}].bak";
public override string Filter => "GameCube Save File|*.gci";
public override string Extension => ".gci";
// 3 Save files are stored
// 0x0000-0x6000 contains memory card data
// 0x6000-0x60000 contains the 3 save slots
// 0x5A000 / 3 = 0x1E000 per save slot
// Checksum is SHA1 over 0-0x1DFD7, stored in the last 20 bytes of the save slot.
// Another SHA1 hash is 0x1DFD8, for 20 bytes. Unknown purpose.
// Checksum is used as the crypto key.
private const int SLOT_SIZE = 0x1E000;
private const int SLOT_START = 0x6000;
private const int SLOT_COUNT = 3;
private readonly int SaveCount = -1;
private readonly int SaveIndex = -1;
private readonly ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs, LegalBerries, LegalCologne;
private readonly int OFS_PouchCologne;
public SAV3Colosseum(byte[] data = null)
{
Data = data == null ? new byte[SaveUtil.SIZE_G3BOX] : (byte[])data.Clone();
BAK = (byte[])Data.Clone();
Exportable = !Data.SequenceEqual(new byte[Data.Length]);
if (SaveUtil.getIsG3CXDSAV(Data) != GameVersion.COLO)
return;
OriginalData = (byte[])Data.Clone();
// Scan all 3 save slots for the highest counter
for (int i = 0; i < SLOT_COUNT; i++)
{
int slotOffset = SLOT_START + i * SLOT_SIZE;
int SaveCounter = BigEndian.ToInt32(Data, slotOffset + 4);
if (SaveCounter <= SaveCount)
continue;
SaveCount = SaveCounter;
SaveIndex = i;
}
// Decrypt most recent save slot
{
byte[] slot = new byte[SLOT_SIZE];
int slotOffset = SLOT_START + SaveIndex * SLOT_SIZE;
Array.Copy(Data, slotOffset, slot, 0, slot.Length);
byte[] digest = new byte[20];
Array.Copy(slot, SLOT_SIZE - 20, digest, 0, digest.Length);
// Decrypt Slot
Data = DecryptColosseum(slot, digest);
}
Trainer1 = 0x00078;
Party = 0x000A8;
OFS_PouchHeldItem = 0x007F8;
OFS_PouchKeyItem = 0x00848;
OFS_PouchBalls = 0x0087C;
OFS_PouchTMHM = 0x00934;
OFS_PouchBerry = 0x009BC;
OFS_PouchCologne = 0x00AEC; // Cologne
Box = 0x00B90;
Daycare = 0x08170;
LegalItems = Legal.Pouch_Items_COLO;
LegalKeyItems = Legal.Pouch_Key_COLO;
LegalBalls = Legal.Pouch_Ball_RS;
LegalTMHMs = Legal.Pouch_TM_RS; // not HMs
LegalBerries = Legal.Pouch_Berries_RS;
LegalCologne = Legal.Pouch_Cologne_CXD;
Personal = PersonalTable.RS;
HeldItems = Legal.HeldItems_COLO;
if (!Exportable)
resetBoxes();
}
private readonly byte[] OriginalData;
public override byte[] Write(bool DSV)
{
setChecksums();
// Get updated save slot data
byte[] digest = Data.Skip(Data.Length - 20).Take(20).ToArray();
byte[] newSAV = EncryptColosseum(Data, digest);
// Put save slot back in original save data
byte[] newFile = (byte[])OriginalData.Clone();
Array.Copy(newSAV, 0, newFile, SLOT_START + SaveIndex*SLOT_SIZE, newSAV.Length);
return newFile;
}
// Configuration
public override SaveFile Clone() { return new SAV3Colosseum(Write(DSV: false)); }
public override int SIZE_STORED => PKX.SIZE_3CSTORED;
public override int SIZE_PARTY => PKX.SIZE_3CSTORED; // unused
public override PKM BlankPKM => new CK3();
protected override Type PKMType => typeof(CK3);
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 MaxEV => 255;
public override int Generation => 3;
protected override int GiftCountMax => 1;
public override int OTLength => 8;
public override int NickLength => 10;
public override int MaxMoney => 999999;
public override int BoxCount => 3;
// Checksums
private readonly SHA1 sha1 = SHA1.Create();
private byte[] EncryptColosseum(byte[] input, byte[] digest)
{
if (input.Length != SLOT_SIZE)
return null;
byte[] d = (byte[])input.Clone();
byte[] k = (byte[])digest.Clone(); // digest
// NOT key
for (int i = 0; i < 20; i++)
k[i] = (byte)~k[i];
for (int i = 0x18; i < 0x1DFD8; i += 20)
{
for (int j = 0; j < 20; j++)
d[i + j] ^= k[j];
k = sha1.ComputeHash(d, i, 20); // update digest
}
return d;
}
private byte[] DecryptColosseum(byte[] input, byte[] digest)
{
if (input.Length != SLOT_SIZE)
return null;
byte[] d = (byte[])input.Clone();
byte[] k = (byte[])digest.Clone();
// NOT key
for (int i = 0; i < 20; i++)
k[i] = (byte)~k[i];
for (int i = 0x18; i < 0x1DFD8; i += 20)
{
byte[] key = sha1.ComputeHash(d, i, 20); // update digest
for (int j = 0; j < 20; j++)
d[i + j] ^= k[j];
Array.Copy(key, k, 20); // for use in next loop
}
return d;
}
protected override void setChecksums()
{
// Clear Header Checksum
BitConverter.GetBytes(0).CopyTo(Data, 12);
// Compute checksum of data
byte[] checksum = sha1.ComputeHash(Data, 0, 0x1DFD8);
// Set Checksum to end
Array.Copy(checksum, 0, Data, Data.Length - 20, 20);
// Header Integrity
byte[] H = new byte[8]; Array.Copy(checksum, 0, H, 0, 8);
byte[] D = new byte[8]; Array.Copy(Data, 0x18, D, 0, 8);
// Decrypt Checksum
for (int i = 0; i < 8; i++)
D[i] ^= (byte)~H[i];
// Compute new header checksum
int newHC = 0;
for (int i = 0; i < 0x18; i += 4)
newHC -= BigEndian.ToInt32(Data, i);
newHC -= BigEndian.ToInt32(D, 0);
newHC -= BigEndian.ToInt32(D, 4);
// Set Header Checksum
BigEndian.GetBytes(newHC).CopyTo(Data, 12);
}
public override bool ChecksumsValid => !ChecksumInfo.Contains("Invalid");
public override string ChecksumInfo
{
get
{
byte[] data = (byte[])Data.Clone();
int oldHC = BigEndian.ToInt32(data, 12);
// Clear Header Checksum
BitConverter.GetBytes(0).CopyTo(data, 12);
byte[] checksum = sha1.ComputeHash(data, 0, 0x1DFD8);
// Header Integrity
byte[] H = new byte[8];
byte[] D = new byte[8];
Array.Copy(checksum, 0, H, 0, H.Length);
Array.Copy(data, 0x00018, D, 0, D.Length);
for (int i = 0; i < 8; i++)
D[i] ^= (byte)~H[i];
// Compute new header checksum
int newHC = 0;
for (int i = 0; i < 0x18; i += 4)
newHC -= BigEndian.ToInt32(data, i);
newHC -= BigEndian.ToInt32(D, 0);
newHC -= BigEndian.ToInt32(D, 4);
byte[] chk = data.Skip(data.Length - 20).Take(20).ToArray();
bool header = newHC == oldHC;
bool body = chk.SequenceEqual(checksum);
return $"Header Checksum {(header ? "V" : "Inv")}alid, Body Checksum {(body ? "V" : "Inv")}alid.";
}
}
// Trainer Info
public override GameVersion Version { get { return GameVersion.COLO; } protected set { } }
// Storage
public override int getPartyOffset(int slot)
{
return Party + SIZE_STORED * slot;
}
public override int getBoxOffset(int box)
{
return Box + (30 * SIZE_STORED + 0x14)*box + 0x14;
}
public override int CurrentBox { get { return 0; } set { } }
public override int getBoxWallpaper(int box)
{
return box;
}
public override string getBoxName(int box)
{
return PKX.getColoStr(Data, Box + 0x24A4*box, 8);
}
public override void setBoxName(int box, string value)
{
if (value.Length > 8)
value = value.Substring(0, 8); // Hard cap
PKX.setColoStr(value, 8).CopyTo(Data, Box + 0x24A4*box);
}
public override PKM getPKM(byte[] data)
{
return new CK3(data.Take(SIZE_STORED).ToArray());
}
public override byte[] decryptPKM(byte[] data)
{
return data;
}
protected override void setDex(PKM pkm) { }
private TimeSpan PlayedSpan
{
get { return TimeSpan.FromSeconds((double)(Util.SwapEndianness(BitConverter.ToUInt32(Data, 40)) - 0x47000000) / 128); }
set { BitConverter.GetBytes(Util.SwapEndianness((uint)(value.TotalSeconds * 128) + 0x47000000)).CopyTo(Data, 40); }
}
public override int PlayedHours
{
get { return (ushort)PlayedSpan.Hours; }
set { var time = PlayedSpan; PlayedSpan = time - TimeSpan.FromHours(time.Hours) + TimeSpan.FromHours(value); }
}
public override int PlayedMinutes
{
get { return (byte)PlayedSpan.Minutes; }
set { var time = PlayedSpan; PlayedSpan = time - TimeSpan.FromMinutes(time.Minutes) + TimeSpan.FromMinutes(value); }
}
public override int PlayedSeconds
{
get { return (byte)PlayedSpan.Seconds; }
set { var time = PlayedSpan; PlayedSpan = time - TimeSpan.FromSeconds(time.Seconds) + TimeSpan.FromSeconds(value); }
}
// Trainer Info (offset 0x78, length 0xB18, end @ 0xB90)
public override string OT { get { return PKX.getColoStr(Data, 0x78, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x78); } }
private string OT2 { get { return PKX.getColoStr(Data, 0x8C, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0x8C); OT = value; } }
public override ushort SID { get { return BigEndian.ToUInt16(Data, 0xA4); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xA4); } }
public override ushort TID { get { return BigEndian.ToUInt16(Data, 0xA6); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xA6); } }
public override int Gender { get { return Data[0xAF8]; } set { Data[0xAF8] = (byte)value; } }
public override uint Money { get { return BigEndian.ToUInt32(Data, 0xAFC); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xAFC); } }
public uint Coupons { get { return BigEndian.ToUInt32(Data, 0xB00); } set { BigEndian.GetBytes(value).CopyTo(Data, 0xB00); } }
public string RUI_Name { get { return PKX.getColoStr(Data, 0xB3A, 10); } set { PKX.setColoStr(value, 10).CopyTo(Data, 0xB3A); } }
public override InventoryPouch[] Inventory
{
get
{
InventoryPouch[] pouch =
{
new InventoryPouch(InventoryType.Items, LegalItems, 995, OFS_PouchHeldItem, 20), // 20 COLO, 30 XD
new InventoryPouch(InventoryType.KeyItems, LegalKeyItems, 1, OFS_PouchKeyItem, 43),
new InventoryPouch(InventoryType.TMHMs, LegalBalls, 995, OFS_PouchTMHM, 16),
new InventoryPouch(InventoryType.TMHMs, LegalTMHMs, 995, OFS_PouchTMHM, 64),
new InventoryPouch(InventoryType.Berries, LegalBerries, 995, OFS_PouchBerry, 46),
new InventoryPouch(InventoryType.Medicine, LegalCologne, 995, OFS_PouchCologne, 3), // Cologne
};
foreach (var p in pouch)
p.getPouchBigEndian(ref Data);
return pouch;
}
set
{
foreach (var p in value)
p.setPouchBigEndian(ref Data);
}
}
// Daycare Structure:
// 0x00 -- Occupied
// 0x01 -- Deposited Level
// 0x02-0x03 -- unused?
// 0x04-0x07 -- Initial EXP
public override int getDaycareSlotOffset(int loc, int slot) { return Daycare + 8; }
public override ulong? getDaycareRNGSeed(int loc) { return null; }
public override uint? getDaycareEXP(int loc, int slot) { return null; }
public override bool? getDaycareOccupied(int loc, int slot) { return null; }
public override void setDaycareEXP(int loc, int slot, uint EXP) { }
public override void setDaycareOccupied(int loc, int slot, bool occupied) { }
}
internal static class BigEndian
{
internal static uint ToUInt32(byte[] data, int offset)
{
int val = 0;
val |= data[offset + 0] << 24;
val |= data[offset + 1] << 16;
val |= data[offset + 2] << 8;
val |= data[offset + 3] << 0;
return (uint)val;
}
internal static ushort ToUInt16(byte[] data, int offset)
{
int val = 0;
val |= data[offset + 0] << 8;
val |= data[offset + 1] << 0;
return (ushort)val;
}
internal static int ToInt32(byte[] data, int offset)
{
int val = 0;
val |= data[offset + 0] << 24;
val |= data[offset + 1] << 16;
val |= data[offset + 2] << 8;
val |= data[offset + 3] << 0;
return val;
}
internal static short ToInt16(byte[] data, int offset)
{
int val = 0;
val |= data[offset + 0] << 8;
val |= data[offset + 1] << 0;
return (short)val;
}
internal static byte[] GetBytes(int value)
{
return Invert(BitConverter.GetBytes(value));
}
internal static byte[] GetBytes(short value)
{
return Invert(BitConverter.GetBytes(value));
}
internal static byte[] GetBytes(uint value)
{
return Invert(BitConverter.GetBytes(value));
}
internal static byte[] GetBytes(ushort value)
{
return Invert(BitConverter.GetBytes(value));
}
private static byte[] Invert(byte[] data)
{
byte[] result = new byte[data.Length];
int o = 0;
int i = data.Length;
while (o != data.Length)
result[--i] = data[o++];
return result;
}
}
}

187
PKHeX/Saves/SAV3XD.cs Normal file
View file

@ -0,0 +1,187 @@
using System;
using System.Linq;
namespace PKHeX
{
public sealed class SAV3XD : SaveFile
{
public override string BAKName => $"{FileName} [{Version} #{SaveCount.ToString("0000")}].bak";
public override string Filter => "GameCube Save File|*.gci";
public override string Extension => ".gci";
private const int SLOT_SIZE = 0x1E000;
private const int SLOT_START = 0x6000;
private const int SLOT_COUNT = 3;
private readonly int SaveCount = -1;
private readonly int SaveIndex = -1;
private readonly ushort[] LegalItems, LegalKeyItems, LegalBalls, LegalTMHMs, LegalBerries, LegalCologne, LegalDisc;
private readonly int OFS_PouchCologne, OFS_PouchDisc;
public SAV3XD(byte[] data = null)
{
Data = data == null ? new byte[SaveUtil.SIZE_G3BOX] : (byte[])data.Clone();
BAK = (byte[])Data.Clone();
Exportable = !Data.SequenceEqual(new byte[Data.Length]);
if (SaveUtil.getIsG3CXDSAV(Data) != GameVersion.XD)
return;
OriginalData = (byte[])Data.Clone();
// Scan all 3 save slots for the highest counter
for (int i = 0; i < SLOT_COUNT; i++)
{
int slotOffset = SLOT_START + i * SLOT_SIZE;
int SaveCounter = BigEndian.ToInt32(Data, slotOffset + 4);
if (SaveCounter <= SaveCount)
continue;
SaveCount = SaveCounter;
SaveIndex = i;
}
// Decrypt most recent save slot
{
}
OFS_PouchHeldItem = 1224;
OFS_PouchKeyItem = 1344;
OFS_PouchBalls = 1516;
OFS_PouchTMHM = 1580;
OFS_PouchBerry = 1836;
OFS_PouchCologne = 2020;
OFS_PouchDisc = 2032;
LegalItems = Legal.Pouch_Items_XD;
LegalKeyItems = Legal.Pouch_Key_XD;
LegalBalls = Legal.Pouch_Ball_RS;
LegalTMHMs = Legal.Pouch_TM_RS; // not HMs
LegalBerries = Legal.Pouch_Berries_RS;
LegalCologne = Legal.Pouch_Cologne_CXD;
LegalDisc = Legal.Pouch_Disc_XD;
Personal = PersonalTable.RS;
HeldItems = Legal.HeldItems_XD;
if (!Exportable)
resetBoxes();
}
private readonly byte[] OriginalData;
public override byte[] Write(bool DSV)
{
setChecksums();
// Get updated save slot data
byte[] newSAV = null;
// Put save slot back in original save data
byte[] newFile = (byte[])OriginalData.Clone();
Array.Copy(newSAV, 0, newFile, SLOT_START + SaveIndex * SLOT_SIZE, newSAV.Length);
return newFile;
}
// Configuration
public override SaveFile Clone() { return new SAV3(Write(DSV: false), Version); }
public override int SIZE_STORED => PKX.SIZE_3XSTORED;
public override int SIZE_PARTY => PKX.SIZE_3XSTORED; // unused
public override PKM BlankPKM => new XK3();
protected override Type PKMType => typeof(XK3);
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 MaxEV => 255;
public override int Generation => 3;
protected override int GiftCountMax => 1;
public override int OTLength => 8;
public override int NickLength => 10;
public override int MaxMoney => 999999;
public override int BoxCount => 8;
public override bool HasParty => false;
// Checksums
protected override void setChecksums()
{
}
public override bool ChecksumsValid
{
get { return false; }
}
public override string ChecksumInfo
{
get { return ""; }
}
// Trainer Info
public override GameVersion Version { get { return GameVersion.RSBOX; } protected set { } }
// Storage
public override int getPartyOffset(int slot)
{
return Party + SIZE_STORED * slot;
}
public override int getBoxOffset(int box)
{
return Box + (30 * SIZE_STORED + 0x14)*box + 0x14;
}
public override int CurrentBox { get { return 0; } set { } }
public override int getBoxWallpaper(int box)
{
return box;
}
public override string getBoxName(int box)
{
return PKX.getColoStr(Data, Box + 0x24A4*box, 8);
}
public override void setBoxName(int box, string value)
{
if (value.Length > 8)
value = value.Substring(0, 8); // Hard cap
PKX.setColoStr(value, 8).CopyTo(Data, Box + 0x24A4*box);
}
public override PKM getPKM(byte[] data)
{
return new XK3(data.Take(SIZE_STORED).ToArray());
}
public override byte[] decryptPKM(byte[] data)
{
return data;
}
protected override void setDex(PKM pkm) { }
public override InventoryPouch[] Inventory
{
get
{
InventoryPouch[] pouch =
{
new InventoryPouch(InventoryType.Items, LegalItems, 995, OFS_PouchHeldItem, 30), // 20 COLO, 30 XD
new InventoryPouch(InventoryType.KeyItems, LegalKeyItems, 1, OFS_PouchKeyItem, 43),
new InventoryPouch(InventoryType.TMHMs, LegalBalls, 995, OFS_PouchTMHM, 16),
new InventoryPouch(InventoryType.TMHMs, LegalTMHMs, 995, OFS_PouchTMHM, 64),
new InventoryPouch(InventoryType.Berries, LegalBerries, 995, OFS_PouchBerry, 46),
new InventoryPouch(InventoryType.Medicine, LegalCologne, 995, OFS_PouchCologne, 3), // Cologne
new InventoryPouch(InventoryType.Medicine, LegalDisc, 995, OFS_PouchDisc, 60), // Cologne
};
foreach (var p in pouch)
p.getPouchBigEndian(ref Data);
return pouch;
}
set
{
foreach (var p in value)
p.setPouchBigEndian(ref Data);
}
}
}
}

View file

@ -9,6 +9,8 @@ namespace PKHeX
public enum GameVersion
{
/* I don't want to assign Gen I/II... */
XD = -7,
COLO = -6,
RSBOX = -5,
GS = -4,
C = -3,
@ -49,6 +51,10 @@ namespace PKHeX
internal const int SIZE_G4RAW = 0x80000;
internal const int SIZE_G3BOX = 0x76000;
internal const int SIZE_G3BOXGCI = 0x76040; // +64 if has GCI data
internal const int SIZE_G3COLO = 0x60000;
internal const int SIZE_G3COLOGCI = 0x60040; // +64 if has GCI data
internal const int SIZE_G3XD = 0x56000;
internal const int SIZE_G3XDGCI = 0x56040; // +64 if has GCI data
internal const int SIZE_G3RAW = 0x20000;
internal const int SIZE_G3RAWHALF = 0x10000;
internal const int SIZE_G2RAW_U = 0x8000;
@ -60,7 +66,9 @@ namespace PKHeX
internal const int SIZE_G1BAT = 0x802C;
internal static readonly byte[] FOOTER_DSV = Encoding.ASCII.GetBytes("|-DESMUME SAVE-|");
internal static readonly byte[] HEADER_GCI = {0x47, 0x50, 0x58}; // GPX*
internal static readonly byte[] HEADER_BOX = Encoding.ASCII.GetBytes("GPX");
internal static readonly byte[] HEADER_COLO = Encoding.ASCII.GetBytes("GC6");
internal static readonly byte[] HEADER_XD = Encoding.ASCII.GetBytes("GXX");
/// <summary>Determines the generation of the given save data.</summary>
/// <param name="data">Save data of which to determine the generation</param>
@ -73,6 +81,8 @@ namespace PKHeX
return 2;
if (getIsG3SAV(data) != GameVersion.Invalid)
return 3;
if (getIsG3CXDSAV(data) != GameVersion.Invalid)
return (int)GameVersion.COLO;
if (getIsG3BOXSAV(data) != GameVersion.Invalid)
return (int)GameVersion.RSBOX;
if (getIsG4SAV(data) != GameVersion.Invalid)
@ -244,6 +254,32 @@ namespace PKHeX
return CHK_A == chkA && CHK_B == chkB ? GameVersion.RSBOX : GameVersion.Invalid;
}
/// <summary>Determines the type of 3rd gen Colosseum</summary>
/// <param name="data">Save data of which to determine the type</param>
/// <returns>Version Identifier or Invalid if type cannot be determined.</returns>
public static GameVersion getIsG3CXDSAV(byte[] data)
{
if (!new[] { SIZE_G3COLO, SIZE_G3COLOGCI }.Contains(data.Length))
return GameVersion.Invalid;
// Check the intro bytes for each save slot
byte[] slotintroColo = {0x01, 0x01, 0x00, 0x00};
byte[] slotintroXD = {0x01, 0x01, 0x01, 0x00};
int offset = data.Length - SIZE_G3COLO;
int coloct = 0;
for (int i = 0; i < 3; i++)
{
var ident = data.Skip(0x6000 + offset + 0x1E000*i).Take(4).ToArray();
if (ident.SequenceEqual(slotintroColo))
{
coloct++;
continue;
}
if (!ident.SequenceEqual(slotintroXD))
return GameVersion.Invalid;
}
return coloct == 3 ? GameVersion.COLO : GameVersion.XD;
}
/// <summary>Determines the type of 4th gen save</summary>
/// <param name="data">Save data of which to determine the type</param>
/// <returns>Version Identifier or Invalid if type cannot be determined.</returns>
@ -394,6 +430,10 @@ namespace PKHeX
return new SAV3(data);
case (int)GameVersion.RSBOX:
return new SAV3RSBox(data);
case (int)GameVersion.COLO:
return new SAV3Colosseum(data);
case (int)GameVersion.XD:
return new SAV3XD(data);
case 4:
return new SAV4(data);
case 5:
@ -525,13 +565,31 @@ namespace PKHeX
}
if (input.Length == SIZE_G3BOXGCI)
{
bool gci = HEADER_GCI.SequenceEqual(input.Take(HEADER_GCI.Length));
bool gci = HEADER_BOX.SequenceEqual(input.Take(HEADER_BOX.Length));
if (gci)
{
header = input.Take(SIZE_G3BOXGCI - SIZE_G3BOX).ToArray();
input = input.Skip(header.Length).ToArray();
}
}
if (input.Length == SIZE_G3COLOGCI)
{
bool gci = HEADER_COLO.SequenceEqual(input.Take(HEADER_COLO.Length));
if (gci)
{
header = input.Take(SIZE_G3COLOGCI - SIZE_G3COLO).ToArray();
input = input.Skip(header.Length).ToArray();
}
}
if (input.Length == SIZE_G3XDGCI)
{
bool gci = HEADER_XD.SequenceEqual(input.Take(HEADER_XD.Length));
if (gci)
{
header = input.Take(SIZE_G3XDGCI - SIZE_G3XD).ToArray();
input = input.Skip(header.Length).ToArray();
}
}
}
public static int getDexFormIndexBW(int species, int formct)
@ -652,5 +710,32 @@ namespace PKHeX
default: return getDexFormIndexXY(species, formct);
}
}
public static int getCXDVersionID(int gen3version)
{
switch ((GameVersion)gen3version)
{
case GameVersion.FR: return 1;
case GameVersion.LG: return 2;
case GameVersion.S: return 8;
case GameVersion.R: return 9;
case GameVersion.E: return 10;
case GameVersion.CXD: return 11;
default: return 0;
}
}
public static int getG3VersionID(int CXDversion)
{
switch (CXDversion)
{
case 1: return (int)GameVersion.FR;
case 2: return (int)GameVersion.LG;
case 8: return (int)GameVersion.S;
case 9: return (int)GameVersion.R;
case 10: return (int)GameVersion.E;
case 11: return (int)GameVersion.CXD;
default: return (int)GameVersion.Unknown;
}
}
}
}