diff --git a/PKHeX.Core/PKM/CK3.cs b/PKHeX.Core/PKM/CK3.cs index 5f84e18eb..7d18a2f23 100644 --- a/PKHeX.Core/PKM/CK3.cs +++ b/PKHeX.Core/PKM/CK3.cs @@ -3,7 +3,7 @@ namespace PKHeX.Core { /// Generation 3 format, exclusively for Pokémon Colosseum. - public sealed class CK3 : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonSetUnique3, IRibbonSetOnly3, IShadowPKM + public sealed class CK3 : _K3, IShadowPKM { public static readonly byte[] ExtraBytes = { @@ -26,6 +26,7 @@ public CK3(byte[] decryptedData = null, string ident = null) if (Data.Length != SIZE_PARTY) Array.Resize(ref Data, SIZE_PARTY); } + public CK3() => Data = new byte[SIZE_PARTY]; public override PKM Clone() => new CK3((byte[])Data.Clone(), Identifier); private string GetString(int Offset, int Count) => StringConverter.GetBEString3(Data, Offset, Count); @@ -36,17 +37,6 @@ public CK3(byte[] decryptedData = null, string ident = null) public override byte[] OT_Trash { get => GetData(0x18, 20); set { if (value?.Length == 20) value.CopyTo(Data, 0x18); } } // Future Attributes - public override uint EncryptionConstant { get => PID; set { } } - public override int Nature { get => (int)(PID % 25); set { } } - public override int AltForm { get => Species == 201 ? PKX.GetUnownForm(PID) : 0; set { } } - - public override bool IsNicknamed { get => PKX.IsNicknamedAnyLanguage(Species, Nickname, Format); set { } } - public override int Gender { get => PKX.GetGenderFromPID(Species, PID); set { } } - public override int Characteristic => -1; - public override int CurrentFriendship { get => 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 >> 1]; } set { } } - public override int CurrentHandler { get => 0; set { } } - public override int Egg_Location { get => 0; set { } } // Silly Attributes public override ushort Sanity { get => 0; set { } } // valid flag set in pkm structure. @@ -149,30 +139,30 @@ public CK3(byte[] decryptedData = null, string ident = null) public override int CNT_Cute { get => Data[0xB4]; set => Data[0xB4] = (byte)value; } public override int CNT_Smart { get => Data[0xB5]; set => Data[0xB5] = (byte)value; } public override int CNT_Tough { get => Data[0xB6]; set => Data[0xB6] = (byte)value; } - public int RibbonCountG3Cool { get => Data[0xB7]; set => Data[0xB7] = (byte)value; } - public int RibbonCountG3Beauty { get => Data[0xB8]; set => Data[0xB8] = (byte)value; } - public int RibbonCountG3Cute { get => Data[0xB9]; set => Data[0xB9] = (byte)value; } - public int RibbonCountG3Smart { get => Data[0xBA]; set => Data[0xBA] = (byte)value; } - public int RibbonCountG3Tough { get => Data[0xBB]; set => Data[0xBB] = (byte)value; } + public override int RibbonCountG3Cool { get => Data[0xB7]; set => Data[0xB7] = (byte)value; } + public override int RibbonCountG3Beauty { get => Data[0xB8]; set => Data[0xB8] = (byte)value; } + public override int RibbonCountG3Cute { get => Data[0xB9]; set => Data[0xB9] = (byte)value; } + public override int RibbonCountG3Smart { get => Data[0xBA]; set => Data[0xBA] = (byte)value; } + public override int RibbonCountG3Tough { get => Data[0xBB]; set => Data[0xBB] = (byte)value; } public override int CNT_Sheen { get => Data[0xBC]; set => Data[0xBC] = (byte)value; } // Ribbons - public bool RibbonChampionG3Hoenn { get => Data[0xBD] == 1; set => Data[0xBD] = (byte)(value ? 1 : 0); } - public bool RibbonWinning { get => Data[0xBE] == 1; set => Data[0xBE] = (byte)(value ? 1 : 0); } - public bool RibbonVictory { get => Data[0xBF] == 1; set => Data[0xBF] = (byte)(value ? 1 : 0); } - public bool RibbonArtist { get => Data[0xC0] == 1; set => Data[0xC0] = (byte)(value ? 1 : 0); } - public bool RibbonEffort { get => Data[0xC1] == 1; set => Data[0xC1] = (byte)(value ? 1 : 0); } - public bool RibbonChampionBattle { get => Data[0xC2] == 1; set => Data[0xC2] = (byte)(value ? 1 : 0); } - public bool RibbonChampionRegional { get => Data[0xC3] == 1; set => Data[0xC3] = (byte)(value ? 1 : 0); } - public bool RibbonChampionNational { get => Data[0xC4] == 1; set => Data[0xC4] = (byte)(value ? 1 : 0); } - public bool RibbonCountry { get => Data[0xC5] == 1; set => Data[0xC5] = (byte)(value ? 1 : 0); } - public bool RibbonNational { get => Data[0xC6] == 1; set => Data[0xC6] = (byte)(value ? 1 : 0); } - public bool RibbonEarth { get => Data[0xC7] == 1; set => Data[0xC7] = (byte)(value ? 1 : 0); } - public bool RibbonWorld { get => Data[0xC8] == 1; set => Data[0xC8] = (byte)(value ? 1 : 0); } - public bool Unused1 { get => ((Data[0xC9] >> 0) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~1 | (value ? 1 : 0)); } - public bool Unused2 { get => ((Data[0xC9] >> 1) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~2 | (value ? 2 : 0)); } - public bool Unused3 { get => ((Data[0xC9] >> 2) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~4 | (value ? 4 : 0)); } - public bool Unused4 { get => ((Data[0xC9] >> 3) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~8 | (value ? 8 : 0)); } + public override bool RibbonChampionG3Hoenn { get => Data[0xBD] == 1; set => Data[0xBD] = (byte)(value ? 1 : 0); } + public override bool RibbonWinning { get => Data[0xBE] == 1; set => Data[0xBE] = (byte)(value ? 1 : 0); } + public override bool RibbonVictory { get => Data[0xBF] == 1; set => Data[0xBF] = (byte)(value ? 1 : 0); } + public override bool RibbonArtist { get => Data[0xC0] == 1; set => Data[0xC0] = (byte)(value ? 1 : 0); } + public override bool RibbonEffort { get => Data[0xC1] == 1; set => Data[0xC1] = (byte)(value ? 1 : 0); } + public override bool RibbonChampionBattle { get => Data[0xC2] == 1; set => Data[0xC2] = (byte)(value ? 1 : 0); } + public override bool RibbonChampionRegional { get => Data[0xC3] == 1; set => Data[0xC3] = (byte)(value ? 1 : 0); } + public override bool RibbonChampionNational { get => Data[0xC4] == 1; set => Data[0xC4] = (byte)(value ? 1 : 0); } + public override bool RibbonCountry { get => Data[0xC5] == 1; set => Data[0xC5] = (byte)(value ? 1 : 0); } + public override bool RibbonNational { get => Data[0xC6] == 1; set => Data[0xC6] = (byte)(value ? 1 : 0); } + public override bool RibbonEarth { get => Data[0xC7] == 1; set => Data[0xC7] = (byte)(value ? 1 : 0); } + public override bool RibbonWorld { get => Data[0xC8] == 1; set => Data[0xC8] = (byte)(value ? 1 : 0); } + public override bool Unused1 { get => ((Data[0xC9] >> 0) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~1 | (value ? 1 : 0)); } + public override bool Unused2 { get => ((Data[0xC9] >> 1) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~2 | (value ? 2 : 0)); } + public override bool Unused3 { get => ((Data[0xC9] >> 2) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~4 | (value ? 4 : 0)); } + public override bool Unused4 { get => ((Data[0xC9] >> 3) & 1) == 1; set => Data[0xC9] = (byte)(Data[0xC9] & ~8 | (value ? 8 : 0)); } public override int PKRS_Strain { get => Data[0xCA] & 0xF; set => Data[0xCA] = (byte)(value & 0xF); } public override bool IsEgg { get => Data[0xCB] == 1; set => Data[0xCB] = (byte)(value ? 1 : 0); } @@ -187,26 +177,15 @@ public CK3(byte[] decryptedData = null, string ident = null) public override bool FatefulEncounter { get => Data[0x11C] == 1; set => Data[0x11C] = (byte)(value ? 1 : 0); } public new int EncounterType { get => 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 override bool Japanese => Language == (int)LanguageID.Japanese; - protected override byte[] Encrypt() { return (byte[])Data.Clone(); } - - // Maximums - public override int MaxMoveID => Legal.MaxMoveID_3; - public override int MaxSpeciesID => Legal.MaxSpeciesID_3; - public override int MaxAbilityID => Legal.MaxAbilityID_3; - public override int MaxItemID => Legal.MaxItemID_3; - public override int MaxBallID => Legal.MaxBallID_3; - public override int MaxGameID => Legal.MaxGameID_3; - public override int MaxIV => 31; - public override int MaxEV => 252; - public override int OTLength => 7; - public override int NickLength => 10; + public PK3 ConvertToPK3() + { + var pk = ConvertTo(); + pk.RefreshChecksum(); + return pk; + } } } diff --git a/PKHeX.Core/PKM/PK3.cs b/PKHeX.Core/PKM/PK3.cs index 75bf6383e..463a0420d 100644 --- a/PKHeX.Core/PKM/PK3.cs +++ b/PKHeX.Core/PKM/PK3.cs @@ -3,7 +3,7 @@ namespace PKHeX.Core { /// Generation 3 format. - public sealed class PK3 : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonSetUnique3, IRibbonSetOnly3 + public sealed class PK3 : _K3 { public static readonly byte[] ExtraBytes = { @@ -22,6 +22,7 @@ public PK3(byte[] decryptedData = null, string ident = null) if (Data.Length != SIZE_PARTY) Array.Resize(ref Data, SIZE_PARTY); } + public PK3() => Data = new byte[SIZE_PARTY]; public override PKM Clone() => new PK3((byte[])Data.Clone(), Identifier); private string GetString(int Offset, int Count) => StringConverter.GetString3(Data, Offset, Count, Japanese); @@ -31,25 +32,16 @@ public PK3(byte[] decryptedData = null, string ident = null) public override byte[] Nickname_Trash { get => GetData(0x08, 10); set { if (value?.Length == 10) value.CopyTo(Data, 0x08); } } public override byte[] OT_Trash { get => GetData(0x14, 7); set { if (value?.Length == 7) value.CopyTo(Data, 0x14); } } - // Future Attributes - public override uint EncryptionConstant { get => PID; set { } } - public override int Nature { get => (int)(PID % 25); set { } } - public override int AltForm { get => Species == 201 ? PKX.GetUnownForm(PID) : 0; set { } } - - public override bool IsNicknamed { get => PKX.IsNicknamedAnyLanguage(Species, Nickname, Format); set { } } - public override int Gender { get => PKX.GetGenderFromPID(Species, PID); set { } } - public override int Characteristic => -1; - public override int CurrentFriendship { get => OT_Friendship; set => OT_Friendship = value; } - public override int Ability { get { int[] abils = PersonalInfo.Abilities; return abils[AbilityBit && abils[1] != 0 ? 1 : 0]; } set { } } - public override int CurrentHandler { get => 0; set { } } - public override int Egg_Location { get => 0; set { } } + // At top for System.Reflection execution order hack + public override bool IsEgg { get => egg; set => egg = value; } + public override int Language { get => lang; set => lang = value; } // 0x20 Intro public override uint PID { get => BitConverter.ToUInt32(Data, 0x00); set => BitConverter.GetBytes(value).CopyTo(Data, 0x00); } public override int TID { get => BitConverter.ToUInt16(Data, 0x04); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x04); } public override int SID { get => BitConverter.ToUInt16(Data, 0x06); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x06); } public override string Nickname { get => GetString(0x08, 10); set => SetString(IsEgg ? "タマゴ" : value, 10).CopyTo(Data, 0x08); } - public override int Language { get => BitConverter.ToUInt16(Data, 0x12) & 0xFF; set => BitConverter.GetBytes((ushort)(IsEgg ? 0x601 : value | 0x200)).CopyTo(Data, 0x12); } + private int lang{ get => BitConverter.ToUInt16(Data, 0x12) & 0xFF; set => BitConverter.GetBytes((ushort)(IsEgg ? 0x601 : value | 0x200)).CopyTo(Data, 0x12); } public override string OT_Name { get => GetString(0x14, 7); set => SetString(value, 7).CopyTo(Data, 0x14); } public override int MarkValue { get => SwapBits(Data[0x1B], 1, 2); protected set => Data[0x1B] = (byte)SwapBits(value, 1, 2); } public override ushort Checksum { get => BitConverter.ToUInt16(Data, 0x1C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x1C); } @@ -115,35 +107,36 @@ public PK3(byte[] decryptedData = null, string ident = null) public override int IV_SPE { get => (int)(IV32 >> 15) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 15)) | (uint)((value > 31 ? 31 : value) << 15)); } public override int IV_SPA { get => (int)(IV32 >> 20) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 20)) | (uint)((value > 31 ? 31 : value) << 20)); } public override int IV_SPD { get => (int)(IV32 >> 25) & 0x1F; set => IV32 = (uint)((IV32 & ~(0x1F << 25)) | (uint)((value > 31 ? 31 : value) << 25)); } - public override bool IsEgg { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (uint)((IV32 & ~0x40000000) | (uint)(value ? 0x40000000 : 0)); } + private bool egg { get => ((IV32 >> 30) & 1) == 1; set => IV32 = (uint)((IV32 & ~0x40000000) | (uint)(value ? 0x40000000 : 0)); } public bool AbilityBit { get => IV32 >> 31 == 1; set => IV32 = (IV32 & 0x7FFFFFFF) | (uint)(value ? 1 << 31 : 0); } private uint RIB0 { get => BitConverter.ToUInt32(Data, 0x4C); set => BitConverter.GetBytes(value).CopyTo(Data, 0x4C); } - public int RibbonCountG3Cool { get => (int)(RIB0 >> 00) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 00)) | (uint)(value & 7) << 00); } - public int RibbonCountG3Beauty { get => (int)(RIB0 >> 03) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 03)) | (uint)(value & 7) << 03); } - public int RibbonCountG3Cute { get => (int)(RIB0 >> 06) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 06)) | (uint)(value & 7) << 06); } - public int RibbonCountG3Smart { get => (int)(RIB0 >> 09) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 09)) | (uint)(value & 7) << 09); } - public int RibbonCountG3Tough { get => (int)(RIB0 >> 12) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 12)) | (uint)(value & 7) << 12); } - public bool RibbonChampionG3Hoenn { get => (RIB0 & (1 << 15)) == 1 << 15; set => RIB0 = (uint)(RIB0 & ~(1 << 15) | (uint)(value ? 1 << 15 : 0)); } - public bool RibbonWinning { get => (RIB0 & (1 << 16)) == 1 << 16; set => RIB0 = (uint)(RIB0 & ~(1 << 16) | (uint)(value ? 1 << 16 : 0)); } - public bool RibbonVictory { get => (RIB0 & (1 << 17)) == 1 << 17; set => RIB0 = (uint)(RIB0 & ~(1 << 17) | (uint)(value ? 1 << 17 : 0)); } - public bool RibbonArtist { get => (RIB0 & (1 << 18)) == 1 << 18; set => RIB0 = (uint)(RIB0 & ~(1 << 18) | (uint)(value ? 1 << 18 : 0)); } - public bool RibbonEffort { get => (RIB0 & (1 << 19)) == 1 << 19; set => RIB0 = (uint)(RIB0 & ~(1 << 19) | (uint)(value ? 1 << 19 : 0)); } - public bool RibbonChampionBattle { get => (RIB0 & (1 << 20)) == 1 << 20; set => RIB0 = (uint)(RIB0 & ~(1 << 20) | (uint)(value ? 1 << 20 : 0)); } - public bool RibbonChampionRegional { get => (RIB0 & (1 << 21)) == 1 << 21; set => RIB0 = (uint)(RIB0 & ~(1 << 21) | (uint)(value ? 1 << 21 : 0)); } - public bool RibbonChampionNational { get => (RIB0 & (1 << 22)) == 1 << 22; set => RIB0 = (uint)(RIB0 & ~(1 << 22) | (uint)(value ? 1 << 22 : 0)); } - public bool RibbonCountry { get => (RIB0 & (1 << 23)) == 1 << 23; set => RIB0 = (uint)(RIB0 & ~(1 << 23) | (uint)(value ? 1 << 23 : 0)); } - public bool RibbonNational { get => (RIB0 & (1 << 24)) == 1 << 24; set => RIB0 = (uint)(RIB0 & ~(1 << 24) | (uint)(value ? 1 << 24 : 0)); } - public bool RibbonEarth { get => (RIB0 & (1 << 25)) == 1 << 25; set => RIB0 = (uint)(RIB0 & ~(1 << 25) | (uint)(value ? 1 << 25 : 0)); } - public bool RibbonWorld { get => (RIB0 & (1 << 26)) == 1 << 26; set => RIB0 = (uint)(RIB0 & ~(1 << 26) | (uint)(value ? 1 << 26 : 0)); } - public bool Unused1 { get => (RIB0 & (1 << 27)) == 1 << 27; set => RIB0 = (uint)(RIB0 & ~(1 << 27) | (uint)(value ? 1 << 27 : 0)); } - public bool Unused2 { get => (RIB0 & (1 << 28)) == 1 << 28; set => RIB0 = (uint)(RIB0 & ~(1 << 28) | (uint)(value ? 1 << 28 : 0)); } - public bool Unused3 { get => (RIB0 & (1 << 29)) == 1 << 29; set => RIB0 = (uint)(RIB0 & ~(1 << 29) | (uint)(value ? 1 << 29 : 0)); } - public bool Unused4 { get => (RIB0 & (1 << 30)) == 1 << 30; set => RIB0 = (uint)(RIB0 & ~(1 << 30) | (uint)(value ? 1 << 30 : 0)); } + public override int RibbonCountG3Cool { get => (int)(RIB0 >> 00) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 00)) | (uint)(value & 7) << 00); } + public override int RibbonCountG3Beauty { get => (int)(RIB0 >> 03) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 03)) | (uint)(value & 7) << 03); } + public override int RibbonCountG3Cute { get => (int)(RIB0 >> 06) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 06)) | (uint)(value & 7) << 06); } + public override int RibbonCountG3Smart { get => (int)(RIB0 >> 09) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 09)) | (uint)(value & 7) << 09); } + public override int RibbonCountG3Tough { get => (int)(RIB0 >> 12) & 7; set => RIB0 = (uint)((RIB0 & ~(7 << 12)) | (uint)(value & 7) << 12); } + public override bool RibbonChampionG3Hoenn { get => (RIB0 & (1 << 15)) == 1 << 15; set => RIB0 = (uint)(RIB0 & ~(1 << 15) | (uint)(value ? 1 << 15 : 0)); } + public override bool RibbonWinning { get => (RIB0 & (1 << 16)) == 1 << 16; set => RIB0 = (uint)(RIB0 & ~(1 << 16) | (uint)(value ? 1 << 16 : 0)); } + public override bool RibbonVictory { get => (RIB0 & (1 << 17)) == 1 << 17; set => RIB0 = (uint)(RIB0 & ~(1 << 17) | (uint)(value ? 1 << 17 : 0)); } + public override bool RibbonArtist { get => (RIB0 & (1 << 18)) == 1 << 18; set => RIB0 = (uint)(RIB0 & ~(1 << 18) | (uint)(value ? 1 << 18 : 0)); } + public override bool RibbonEffort { get => (RIB0 & (1 << 19)) == 1 << 19; set => RIB0 = (uint)(RIB0 & ~(1 << 19) | (uint)(value ? 1 << 19 : 0)); } + public override bool RibbonChampionBattle { get => (RIB0 & (1 << 20)) == 1 << 20; set => RIB0 = (uint)(RIB0 & ~(1 << 20) | (uint)(value ? 1 << 20 : 0)); } + public override bool RibbonChampionRegional { get => (RIB0 & (1 << 21)) == 1 << 21; set => RIB0 = (uint)(RIB0 & ~(1 << 21) | (uint)(value ? 1 << 21 : 0)); } + public override bool RibbonChampionNational { get => (RIB0 & (1 << 22)) == 1 << 22; set => RIB0 = (uint)(RIB0 & ~(1 << 22) | (uint)(value ? 1 << 22 : 0)); } + public override bool RibbonCountry { get => (RIB0 & (1 << 23)) == 1 << 23; set => RIB0 = (uint)(RIB0 & ~(1 << 23) | (uint)(value ? 1 << 23 : 0)); } + public override bool RibbonNational { get => (RIB0 & (1 << 24)) == 1 << 24; set => RIB0 = (uint)(RIB0 & ~(1 << 24) | (uint)(value ? 1 << 24 : 0)); } + public override bool RibbonEarth { get => (RIB0 & (1 << 25)) == 1 << 25; set => RIB0 = (uint)(RIB0 & ~(1 << 25) | (uint)(value ? 1 << 25 : 0)); } + public override bool RibbonWorld { get => (RIB0 & (1 << 26)) == 1 << 26; set => RIB0 = (uint)(RIB0 & ~(1 << 26) | (uint)(value ? 1 << 26 : 0)); } + public override bool Unused1 { get => (RIB0 & (1 << 27)) == 1 << 27; set => RIB0 = (uint)(RIB0 & ~(1 << 27) | (uint)(value ? 1 << 27 : 0)); } + public override bool Unused2 { get => (RIB0 & (1 << 28)) == 1 << 28; set => RIB0 = (uint)(RIB0 & ~(1 << 28) | (uint)(value ? 1 << 28 : 0)); } + public override bool Unused3 { get => (RIB0 & (1 << 29)) == 1 << 29; set => RIB0 = (uint)(RIB0 & ~(1 << 29) | (uint)(value ? 1 << 29 : 0)); } + public override bool Unused4 { get => (RIB0 & (1 << 30)) == 1 << 30; set => RIB0 = (uint)(RIB0 & ~(1 << 30) | (uint)(value ? 1 << 30 : 0)); } public override bool FatefulEncounter { get => RIB0 >> 31 == 1; set => RIB0 = (RIB0 & ~(1 << 31)) | (uint)(value ? 1 << 31 : 0); } #endregion public override int Stat_Level { get => Data[0x54]; set => Data[0x54] = (byte)value; } + public sbyte HeldMailID { get => (sbyte)Data[0x55]; set => Data[0x55] = (byte)value; } public override int Stat_HPCurrent { get => BitConverter.ToUInt16(Data, 0x56); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x56); } public override int Stat_HPMax { get => BitConverter.ToUInt16(Data, 0x58); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x58); } public override int Stat_ATK { get => BitConverter.ToUInt16(Data, 0x5A); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x5A); } @@ -151,29 +144,10 @@ public PK3(byte[] decryptedData = null, string ident = null) public override int Stat_SPE { get => BitConverter.ToUInt16(Data, 0x5E); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x5E); } public override int Stat_SPA { get => BitConverter.ToUInt16(Data, 0x60); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x60); } public override int Stat_SPD { get => BitConverter.ToUInt16(Data, 0x62); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x62); } - public sbyte HeldMailID { get => (sbyte)Data[0x55]; set => Data[0x55] = (byte)value; } // Generated Attributes public override int AbilityNumber { get => 1 << (AbilityBit ? 1 : 0); set => AbilityBit = value > 1; } // 1/2 -> 0/1 - public override int PSV => (int)((PID >> 16 ^ PID & 0xFFFF) >> 3); - public override int TSV => (TID ^ SID) >> 3; public override bool Japanese => IsEgg || Language == (int)LanguageID.Japanese; - public override bool WasEvent => Met_Location == 255; // Fateful - public override bool WasIngameTrade => Met_Location == 254; // Trade - public override bool WasGiftEgg => IsEgg && Met_Location == 253; // Gift Egg, indistinguible from normal eggs after hatch - public override bool WasEventEgg => IsEgg && Met_Location == 255; // Event Egg, indistinguible from normal eggs after hatch - - // Maximums - public override int MaxMoveID => Legal.MaxMoveID_3; - public override int MaxSpeciesID => Legal.MaxSpeciesID_3; - public override int MaxAbilityID => Legal.MaxAbilityID_3; - public override int MaxItemID => Legal.MaxItemID_3; - public override int MaxBallID => Legal.MaxBallID_3; - public override int MaxGameID => Legal.MaxGameID_3; - public override int MaxIV => 31; - public override int MaxEV => 255; - public override int OTLength => 7; - public override int NickLength => 10; protected override byte[] Encrypt() { @@ -305,5 +279,20 @@ public PK4 ConvertToPK4() pk4.RefreshChecksum(); return pk4; } + + public XK3 ConvertToXK3() + { + var pk = ConvertTo(); + pk.SetStats(GetStats(PersonalTable.RS[pk.Species])); + pk.Stat_Level = pk.CurrentLevel; + return pk; + } + public CK3 ConvertToCK3() + { + var pk = ConvertTo(); + pk.SetStats(GetStats(PersonalTable.RS[pk.Species])); + pk.Stat_Level = pk.CurrentLevel; + return pk; + } } } diff --git a/PKHeX.Core/PKM/PKM.cs b/PKHeX.Core/PKM/PKM.cs index 02155c017..e48d79f18 100644 --- a/PKHeX.Core/PKM/PKM.cs +++ b/PKHeX.Core/PKM/PKM.cs @@ -901,59 +901,6 @@ public int GetFlawlessIVCount() return 0; } - /// - /// Converts a or to . - /// - /// format - public PKM ConvertToCK3() - { - if (Format != 3) - return null; - if (GetType() == typeof(CK3)) - return this; - var pk = new CK3(); - TransferPropertiesWithReflection(this is XK3 ? ConvertToPK3() : this, pk); - pk.SetStats(GetStats(PersonalTable.RS[pk.Species])); - pk.Stat_Level = pk.CurrentLevel; - return pk; - } - /// - /// Converts a or to . - /// - /// format - public PKM ConvertToXK3() - { - if (Format != 3) - return null; - if (GetType() == typeof(XK3)) - return this; - var pk = new XK3(); - TransferPropertiesWithReflection(this is CK3 ? ConvertToPK3() : this, pk); - pk.SetStats(GetStats(PersonalTable.RS[pk.Species])); - pk.Stat_Level = pk.CurrentLevel; - return pk; - } - /// - /// Converts a or to . - /// - /// format - public PKM ConvertToPK3() - { - if (Format != 3) - return null; - if (GetType() == typeof(PK3)) - return this; - var pk = new PK3(); - TransferPropertiesWithReflection(this, pk); - - // Transferring XK3 to PK3 when it originates from XD sets the fateful encounter (obedience) flag. - if (this is XK3 xk3 && xk3.Version == 15 && xk3.IsOriginXD()) - pk.FatefulEncounter = true; - - pk.RefreshChecksum(); - return pk; - } - /// /// Applies all shared properties from to . /// @@ -964,7 +911,7 @@ public void TransferPropertiesWithReflection(PKM Source, PKM Destination) // Only transfer declared properties not defined in PKM.cs but in the actual type var SourceProperties = ReflectUtil.GetPropertiesCanWritePublicDeclared(Source.GetType()); var DestinationProperties = ReflectUtil.GetPropertiesCanWritePublicDeclared(Destination.GetType()); - foreach (string property in SourceProperties.Intersect(DestinationProperties).Reverse()) + foreach (string property in SourceProperties.Intersect(DestinationProperties)) { var prop = ReflectUtil.GetValue(this, property); if (prop != null && !(prop is byte[])) diff --git a/PKHeX.Core/PKM/PKMConverter.cs b/PKHeX.Core/PKM/PKMConverter.cs index 88f385050..c94d6c774 100644 --- a/PKHeX.Core/PKM/PKMConverter.cs +++ b/PKHeX.Core/PKM/PKMConverter.cs @@ -280,19 +280,20 @@ private static PKM ConvertPKM(PKM pk, Type PKMType, Type fromType, int toFormat, } break; case nameof(CK3): + pkm = ((CK3)pkm).ConvertToPK3(); + goto case nameof(PK3); // fall through case nameof(XK3): - // interconverting C/XD needs to visit main series format - // ends up stripping purification/shadow etc stats - pkm = pkm.ConvertToPK3(); + pkm = ((XK3)pkm).ConvertToPK3(); goto case nameof(PK3); // fall through case nameof(PK3): - if (toFormat == 3) // Gen3 Inter-trading + if (toFormat == 3) { - pkm = InterConvertPK3(pkm, PKMType); + if (PKMType == typeof(CK3)) + pkm = ((PK3)pkm).ConvertToCK3(); + else if (PKMType == typeof(XK3)) + pkm = ((PK3)pkm).ConvertToXK3(); break; } - if (fromType.Name != nameof(PK3)) - pkm = pkm.ConvertToPK3(); pkm = ((PK3) pkm).ConvertToPK4(); if (toFormat == 4) @@ -356,28 +357,6 @@ private static bool IsNotTransferrable(PKM pk, out string comment) } } - /// - /// Converts a PKM from one Generation 3 format to another. If it matches the destination format, the conversion will automatically return. - /// - /// PKM to convert - /// Format/Type to convert to - /// , , and are supported. - /// Converted PKM - private static PKM InterConvertPK3(PKM pk, Type desiredFormatType) - { - // if already converted it instantly returns - switch (desiredFormatType.Name) - { - case nameof(CK3): - return pk.ConvertToCK3(); - case nameof(XK3): - return pk.ConvertToXK3(); - case nameof(PK3): - return pk.ConvertToPK3(); - default: throw new FormatException(); - } - } - /// /// Force hatches a PKM by applying the current species name and a valid Met Location from the origin game. /// diff --git a/PKHeX.Core/PKM/Shared/_K3.cs b/PKHeX.Core/PKM/Shared/_K3.cs new file mode 100644 index 000000000..599be1d37 --- /dev/null +++ b/PKHeX.Core/PKM/Shared/_K3.cs @@ -0,0 +1,152 @@ +namespace PKHeX.Core +{ + /// + /// Generation 3 Base Class + /// + public abstract class _K3 : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonSetUnique3, IRibbonSetOnly3 + { + // Maximums + public override int MaxMoveID => Legal.MaxMoveID_3; + public override int MaxSpeciesID => Legal.MaxSpeciesID_3; + public override int MaxAbilityID => Legal.MaxAbilityID_3; + public override int MaxItemID => Legal.MaxItemID_3; + public override int MaxBallID => Legal.MaxBallID_3; + public override int MaxGameID => Legal.MaxGameID_3; + public override int MaxIV => 31; + public override int MaxEV => 255; + public override int OTLength => 7; + public override int NickLength => 10; + + // Generated Attributes + public override int PSV => (int)((PID >> 16 ^ PID & 0xFFFF) >> 3); + public override int TSV => (TID ^ SID) >> 3; + public override bool Japanese => Language == (int)LanguageID.Japanese; + public override bool WasEvent => Met_Location == 255; // Fateful + public override bool WasIngameTrade => Met_Location == 254; // Trade + public override bool WasGiftEgg => IsEgg && Met_Location == 253; // Gift Egg, indistinguible from normal eggs after hatch + public override bool WasEventEgg => IsEgg && Met_Location == 255; // Event Egg, indistinguible from normal eggs after hatch + + public override int Ability { get { int[] abils = PersonalInfo.Abilities; return abils[abils[1] == 0 ? 0 : AbilityNumber >> 1]; } set { } } + public override uint EncryptionConstant { get => PID; set { } } + public override int Nature { get => (int)(PID % 25); set { } } + public override int AltForm { get => Species == 201 ? PKX.GetUnownForm(PID) : 0; set { } } + public override bool IsNicknamed { get => PKX.IsNicknamedAnyLanguage(Species, Nickname, Format); set { } } + public override int Gender { get => PKX.GetGenderFromPID(Species, PID); set { } } + public override int Characteristic => -1; + public override int CurrentFriendship { get => OT_Friendship; set => OT_Friendship = value; } + public override int CurrentHandler { get => 0; set { } } + public override int Egg_Location { get => 0; set { } } + + public abstract bool RibbonEarth { get; set; } + public abstract bool RibbonNational { get; set; } + public abstract bool RibbonCountry { get; set; } + public abstract bool RibbonChampionBattle { get; set; } + public abstract bool RibbonChampionRegional { get; set; } + public abstract bool RibbonChampionNational { get; set; } + public abstract bool RibbonChampionG3Hoenn { get; set; } + public abstract bool RibbonArtist { get; set; } + public abstract bool RibbonEffort { get; set; } + public abstract bool RibbonWinning { get; set; } + public abstract bool RibbonVictory { get; set; } + public abstract int RibbonCountG3Cool { get; set; } + public abstract int RibbonCountG3Beauty { get; set; } + public abstract int RibbonCountG3Cute { get; set; } + public abstract int RibbonCountG3Smart { get; set; } + public abstract int RibbonCountG3Tough { get; set; } + public abstract bool RibbonWorld { get; set; } + public abstract bool Unused1 { get; set; } + public abstract bool Unused2 { get; set; } + public abstract bool Unused3 { get; set; } + public abstract bool Unused4 { get; set; } + + /// + /// Interconversion for Generation 3 formats. + /// + /// Generation 3 format to convert to + /// New object with transferred properties. + protected T ConvertTo() where T : _K3, new() + { + return new T // Convert away! + { + Species = Species, + Language = Language, + PID = PID, + TID = TID, + SID = SID, + EXP = EXP, + HeldItem = HeldItem, + AbilityNumber = AbilityNumber, + IsEgg = IsEgg, + FatefulEncounter = FatefulEncounter, + + Met_Location = Met_Location, + Met_Level = Met_Level, + Version = Version, + Ball = Ball, + + Nickname = Nickname, + OT_Name = OT_Name, + OT_Gender = OT_Gender, + OT_Friendship = OT_Friendship, + + Move1_PPUps = Move1_PPUps, + Move2_PPUps = Move2_PPUps, + Move3_PPUps = Move3_PPUps, + Move4_PPUps = Move4_PPUps, + Move1 = Move1, + Move2 = Move2, + Move3 = Move3, + Move4 = Move4, + Move1_PP = Move1_PP, + Move2_PP = Move2_PP, + Move3_PP = Move3_PP, + Move4_PP = Move4_PP, + + IV_HP = IV_HP, + IV_ATK = IV_ATK, + IV_DEF = IV_DEF, + IV_SPE = IV_SPE, + IV_SPA = IV_SPA, + IV_SPD = IV_SPD, + EV_HP = EV_HP, + EV_ATK = EV_ATK, + EV_DEF = EV_DEF, + EV_SPE = EV_SPE, + EV_SPA = EV_SPA, + EV_SPD = EV_SPD, + CNT_Cool = CNT_Cool, + CNT_Beauty = CNT_Beauty, + CNT_Cute = CNT_Cute, + CNT_Smart = CNT_Smart, + CNT_Tough = CNT_Tough, + CNT_Sheen = CNT_Sheen, + + PKRS_Days = PKRS_Days, + PKRS_Strain = PKRS_Strain, + + // Transfer Ribbons + RibbonCountG3Cool = RibbonCountG3Cool, + RibbonCountG3Beauty = RibbonCountG3Beauty, + RibbonCountG3Cute = RibbonCountG3Cute, + RibbonCountG3Smart = RibbonCountG3Smart, + RibbonCountG3Tough = RibbonCountG3Tough, + RibbonChampionG3Hoenn = RibbonChampionG3Hoenn, + RibbonWinning = RibbonWinning, + RibbonVictory = RibbonVictory, + RibbonArtist = RibbonArtist, + RibbonEffort = RibbonEffort, + RibbonChampionBattle = RibbonChampionBattle, + RibbonChampionRegional = RibbonChampionRegional, + RibbonChampionNational = RibbonChampionNational, + RibbonCountry = RibbonCountry, + RibbonNational = RibbonNational, + RibbonEarth = RibbonEarth, + RibbonWorld = RibbonWorld, + Unused1 = Unused1, + Unused2 = Unused2, + Unused3 = Unused3, + Unused4 = Unused4, + }; + } + } +} diff --git a/PKHeX.Core/PKM/XK3.cs b/PKHeX.Core/PKM/XK3.cs index 7658c1a48..db73bfbaa 100644 --- a/PKHeX.Core/PKM/XK3.cs +++ b/PKHeX.Core/PKM/XK3.cs @@ -3,7 +3,7 @@ namespace PKHeX.Core { /// Generation 3 format, exclusively for Pokémon XD. - public sealed class XK3 : PKM, IRibbonSetEvent3, IRibbonSetCommon3, IRibbonSetUnique3, IRibbonSetOnly3, IShadowPKM + public sealed class XK3 : _K3, IShadowPKM { public static readonly byte[] ExtraBytes = { @@ -24,6 +24,7 @@ public XK3(byte[] decryptedData = null, string ident = null) if (Data.Length != SIZE_PARTY) Array.Resize(ref Data, SIZE_PARTY); } + public XK3() => Data = new byte[SIZE_PARTY]; public override PKM Clone() => new XK3((byte[])Data.Clone(), Identifier) {Purification = Purification}; private string GetString(int Offset, int Count) => StringConverter.GetBEString3(Data, Offset, Count); @@ -33,19 +34,6 @@ public XK3(byte[] decryptedData = null, string ident = null) public override byte[] Nickname_Trash { get => GetData(0x4E, 20); set { if (value?.Length == 20) value.CopyTo(Data, 0x4E); } } public override byte[] OT_Trash { get => GetData(0x38, 20); set { if (value?.Length == 20) value.CopyTo(Data, 0x38); } } - // Future Attributes - public override uint EncryptionConstant { get => PID; set { } } - public override int Nature { get => (int)(PID % 25); set { } } - public override int AltForm { get => Species == 201 ? PKX.GetUnownForm(PID) : 0; set { } } - - public override bool IsNicknamed { get => PKX.IsNicknamedAnyLanguage(Species, Nickname, Format); set { } } - public override int Gender { get => PKX.GetGenderFromPID(Species, PID); set { } } - public override int Characteristic => -1; - public override int CurrentFriendship { get => 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 >> 1]; } set { } } - public override int CurrentHandler { get => 0; set { } } - public override int Egg_Location { get => 0; set { } } - // Silly Attributes public override ushort Sanity { get => 0; set { } } // valid flag set in pkm structure. public override ushort Checksum { get => SaveUtil.CRC16_CCITT(Data); set { } } // totally false, just a way to get a 'random' ident for the pkm. @@ -96,22 +84,22 @@ public XK3(byte[] decryptedData = null, string ident = null) private string Nickname2 { get => GetString(0x64, 20); set => SetString(value, 10).CopyTo(Data, 0x64); } // +2 terminator // 0x7A-0x7B Unknown private ushort RIB0 { get => BigEndian.ToUInt16(Data, 0x7C); set => BigEndian.GetBytes(value).CopyTo(Data, 0x7C); } - public bool RibbonChampionG3Hoenn { get => (RIB0 & (1 << 15)) == 1 << 15; set => RIB0 = (ushort)(RIB0 & ~(1 << 15) | (ushort)(value ? 1 << 15 : 0)); } - public bool RibbonWinning { get => (RIB0 & (1 << 14)) == 1 << 14; set => RIB0 = (ushort)(RIB0 & ~(1 << 14) | (ushort)(value ? 1 << 14 : 0)); } - public bool RibbonVictory { get => (RIB0 & (1 << 13)) == 1 << 13; set => RIB0 = (ushort)(RIB0 & ~(1 << 13) | (ushort)(value ? 1 << 13 : 0)); } - public bool RibbonArtist { get => (RIB0 & (1 << 12)) == 1 << 12; set => RIB0 = (ushort)(RIB0 & ~(1 << 12) | (ushort)(value ? 1 << 12 : 0)); } - public bool RibbonEffort { get => (RIB0 & (1 << 11)) == 1 << 11; set => RIB0 = (ushort)(RIB0 & ~(1 << 11) | (ushort)(value ? 1 << 11 : 0)); } - public bool RibbonChampionBattle { get => (RIB0 & (1 << 10)) == 1 << 10; set => RIB0 = (ushort)(RIB0 & ~(1 << 10) | (ushort)(value ? 1 << 10 : 0)); } - public bool RibbonChampionRegional { get => (RIB0 & (1 << 09)) == 1 << 09; set => RIB0 = (ushort)(RIB0 & ~(1 << 09) | (ushort)(value ? 1 << 09 : 0)); } - public bool RibbonChampionNational { get => (RIB0 & (1 << 08)) == 1 << 08; set => RIB0 = (ushort)(RIB0 & ~(1 << 08) | (ushort)(value ? 1 << 08 : 0)); } - public bool RibbonCountry { get => (RIB0 & (1 << 07)) == 1 << 07; set => RIB0 = (ushort)(RIB0 & ~(1 << 07) | (ushort)(value ? 1 << 07 : 0)); } - public bool RibbonNational { get => (RIB0 & (1 << 06)) == 1 << 06; set => RIB0 = (ushort)(RIB0 & ~(1 << 06) | (ushort)(value ? 1 << 06 : 0)); } - public bool RibbonEarth { get => (RIB0 & (1 << 05)) == 1 << 05; set => RIB0 = (ushort)(RIB0 & ~(1 << 05) | (ushort)(value ? 1 << 05 : 0)); } - public bool RibbonWorld { get => (RIB0 & (1 << 04)) == 1 << 04; set => RIB0 = (ushort)(RIB0 & ~(1 << 04) | (ushort)(value ? 1 << 04 : 0)); } - public bool Unused1 { get => (RIB0 & (1 << 03)) == 1 << 03; set => RIB0 = (ushort)(RIB0 & ~(1 << 03) | (ushort)(value ? 1 << 03 : 0)); } - public bool Unused2 { get => (RIB0 & (1 << 02)) == 1 << 02; set => RIB0 = (ushort)(RIB0 & ~(1 << 02) | (ushort)(value ? 1 << 02 : 0)); } - public bool Unused3 { get => (RIB0 & (1 << 01)) == 1 << 01; set => RIB0 = (ushort)(RIB0 & ~(1 << 01) | (ushort)(value ? 1 << 01 : 0)); } - public bool Unused4 { get => (RIB0 & (1 << 00)) == 1 << 00; set => RIB0 = (ushort)(RIB0 & ~(1 << 00) | (ushort)(value ? 1 << 00 : 0)); } + public override bool RibbonChampionG3Hoenn { get => (RIB0 & (1 << 15)) == 1 << 15; set => RIB0 = (ushort)(RIB0 & ~(1 << 15) | (ushort)(value ? 1 << 15 : 0)); } + public override bool RibbonWinning { get => (RIB0 & (1 << 14)) == 1 << 14; set => RIB0 = (ushort)(RIB0 & ~(1 << 14) | (ushort)(value ? 1 << 14 : 0)); } + public override bool RibbonVictory { get => (RIB0 & (1 << 13)) == 1 << 13; set => RIB0 = (ushort)(RIB0 & ~(1 << 13) | (ushort)(value ? 1 << 13 : 0)); } + public override bool RibbonArtist { get => (RIB0 & (1 << 12)) == 1 << 12; set => RIB0 = (ushort)(RIB0 & ~(1 << 12) | (ushort)(value ? 1 << 12 : 0)); } + public override bool RibbonEffort { get => (RIB0 & (1 << 11)) == 1 << 11; set => RIB0 = (ushort)(RIB0 & ~(1 << 11) | (ushort)(value ? 1 << 11 : 0)); } + public override bool RibbonChampionBattle { get => (RIB0 & (1 << 10)) == 1 << 10; set => RIB0 = (ushort)(RIB0 & ~(1 << 10) | (ushort)(value ? 1 << 10 : 0)); } + public override bool RibbonChampionRegional { get => (RIB0 & (1 << 09)) == 1 << 09; set => RIB0 = (ushort)(RIB0 & ~(1 << 09) | (ushort)(value ? 1 << 09 : 0)); } + public override bool RibbonChampionNational { get => (RIB0 & (1 << 08)) == 1 << 08; set => RIB0 = (ushort)(RIB0 & ~(1 << 08) | (ushort)(value ? 1 << 08 : 0)); } + public override bool RibbonCountry { get => (RIB0 & (1 << 07)) == 1 << 07; set => RIB0 = (ushort)(RIB0 & ~(1 << 07) | (ushort)(value ? 1 << 07 : 0)); } + public override bool RibbonNational { get => (RIB0 & (1 << 06)) == 1 << 06; set => RIB0 = (ushort)(RIB0 & ~(1 << 06) | (ushort)(value ? 1 << 06 : 0)); } + public override bool RibbonEarth { get => (RIB0 & (1 << 05)) == 1 << 05; set => RIB0 = (ushort)(RIB0 & ~(1 << 05) | (ushort)(value ? 1 << 05 : 0)); } + public override bool RibbonWorld { get => (RIB0 & (1 << 04)) == 1 << 04; set => RIB0 = (ushort)(RIB0 & ~(1 << 04) | (ushort)(value ? 1 << 04 : 0)); } + public override bool Unused1 { get => (RIB0 & (1 << 03)) == 1 << 03; set => RIB0 = (ushort)(RIB0 & ~(1 << 03) | (ushort)(value ? 1 << 03 : 0)); } + public override bool Unused2 { get => (RIB0 & (1 << 02)) == 1 << 02; set => RIB0 = (ushort)(RIB0 & ~(1 << 02) | (ushort)(value ? 1 << 02 : 0)); } + public override bool Unused3 { get => (RIB0 & (1 << 01)) == 1 << 01; set => RIB0 = (ushort)(RIB0 & ~(1 << 01) | (ushort)(value ? 1 << 01 : 0)); } + public override bool Unused4 { get => (RIB0 & (1 << 00)) == 1 << 00; set => RIB0 = (ushort)(RIB0 & ~(1 << 00) | (ushort)(value ? 1 << 00 : 0)); } // 0x7E-0x7F Unknown // Moves @@ -182,45 +170,44 @@ public override int EV_SPE public override int CNT_Cute { get => Data[0xB0]; set => Data[0xB0] = (byte)value; } public override int CNT_Smart { get => Data[0xB1]; set => Data[0xB1] = (byte)value; } public override int CNT_Tough { get => Data[0xB2]; set => Data[0xB2] = (byte)value; } - public int RibbonCountG3Cool { get => Data[0xB3]; set => Data[0xB3] = (byte)value; } - public int RibbonCountG3Beauty { get => Data[0xB4]; set => Data[0xB4] = (byte)value; } - public int RibbonCountG3Cute { get => Data[0xB5]; set => Data[0xB5] = (byte)value; } - public int RibbonCountG3Smart { get => Data[0xB6]; set => Data[0xB6] = (byte)value; } - public int RibbonCountG3Tough { get => Data[0xB7]; set => Data[0xB7] = (byte)value; } + public override int RibbonCountG3Cool { get => Data[0xB3]; set => Data[0xB3] = (byte)value; } + public override int RibbonCountG3Beauty { get => Data[0xB4]; set => Data[0xB4] = (byte)value; } + public override int RibbonCountG3Cute { get => Data[0xB5]; set => Data[0xB5] = (byte)value; } + public override int RibbonCountG3Smart { get => Data[0xB6]; set => Data[0xB6] = (byte)value; } + public override int RibbonCountG3Tough { get => Data[0xB7]; set => Data[0xB7] = (byte)value; } public int ShadowID { get => BigEndian.ToUInt16(Data, 0xBA); set => BigEndian.GetBytes((ushort)value).CopyTo(Data, 0xBA); } // Purification information is stored in the save file and accessed based on the Shadow ID. public int Purification { get; set; } - // Generated Attributes - public override int PSV => (int)((PID >> 16 ^ PID & 0xFFFF) >> 3); - public override int TSV => (TID ^ SID) >> 3; - public override bool Japanese => Language == (int)LanguageID.Japanese; - protected override byte[] Encrypt() { return (byte[])Data.Clone(); } - // Maximums - public override int MaxMoveID => Legal.MaxMoveID_3; - public override int MaxSpeciesID => Legal.MaxSpeciesID_3; - public override int MaxAbilityID => Legal.MaxAbilityID_3; - public override int MaxItemID => Legal.MaxItemID_3; - public override int MaxBallID => Legal.MaxBallID_3; - public override int MaxGameID => Legal.MaxGameID_3; - public override int MaxIV => 31; - public override int MaxEV => 252; - public override int OTLength => 7; - public override int NickLength => 10; - public bool IsOriginXD() + public PK3 ConvertToPK3() + { + var pk = ConvertTo(); + if (Version == 15) + { + // Transferring XK3 to PK3 when it originates from XD sets the fateful encounter (obedience) flag. + if (ShadowID != 0) + pk.RibbonEarth = true; // must be purified before trading away; force purify + if (IsOriginXD()) + pk.FatefulEncounter = true; + } + pk.RefreshChecksum(); + return pk; + } + + private bool IsOriginXD() { if (ShadowID != 0) return true; return IsOriginXD(Species, Met_Level); } - public static bool IsOriginXD(int species, int metLevel) + private static bool IsOriginXD(int species, int metLevel) { switch (species) { diff --git a/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs b/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs index a385b4bda..a312195f3 100644 --- a/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs +++ b/PKHeX.Core/Ribbons/IRibbonSetOnly3.cs @@ -8,6 +8,12 @@ internal interface IRibbonSetOnly3 int RibbonCountG3Cute { get; set; } int RibbonCountG3Smart { get; set; } int RibbonCountG3Tough { get; set; } + + bool RibbonWorld { get; set; } + bool Unused1 { get; set; } + bool Unused2 { get; set; } + bool Unused3 { get; set; } + bool Unused4 { get; set; } } internal static partial class RibbonExtensions @@ -16,6 +22,10 @@ internal static partial class RibbonExtensions { nameof(IRibbonSetOnly3.RibbonCountG3Cool), nameof(IRibbonSetOnly3.RibbonCountG3Beauty), nameof(IRibbonSetOnly3.RibbonCountG3Cute), nameof(IRibbonSetOnly3.RibbonCountG3Smart), nameof(IRibbonSetOnly3.RibbonCountG3Tough), + + nameof(IRibbonSetOnly3.RibbonWorld), + nameof(IRibbonSetOnly3.Unused1), nameof(IRibbonSetOnly3.Unused2), + nameof(IRibbonSetOnly3.Unused3), nameof(IRibbonSetOnly3.Unused4), }; internal static int[] RibbonCounts(this IRibbonSetOnly3 set) {