diff --git a/PKHeX.Core/Legality/Tables5.cs b/PKHeX.Core/Legality/Tables5.cs index 7a150a217..a8427af78 100644 --- a/PKHeX.Core/Legality/Tables5.cs +++ b/PKHeX.Core/Legality/Tables5.cs @@ -174,7 +174,7 @@ namespace PKHeX.Core /// /// Some mixed-gender species were only distributed male-only. Ban hidden abilities on these species when bred in Gen5. /// - internal static readonly HashSet Ban_BreedHidden = new HashSet + internal static readonly HashSet Ban_BreedHidden5 = new HashSet { 001, // Bulbasaur 004, // Charmander diff --git a/PKHeX.Core/Legality/Verifiers/AbilityVerifier.cs b/PKHeX.Core/Legality/Verifiers/AbilityVerifier.cs index 5f17520bf..050ab36af 100644 --- a/PKHeX.Core/Legality/Verifiers/AbilityVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/AbilityVerifier.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using static PKHeX.Core.LegalityCheckStrings; namespace PKHeX.Core @@ -11,103 +10,281 @@ namespace PKHeX.Core public sealed class AbilityVerifier : Verifier { protected override CheckIdentifier Identifier => CheckIdentifier.Ability; + public override void Verify(LegalityAnalysis data) { - var pkm = data.pkm; - var Info = data.Info; - var EncounterMatch = data.EncounterMatch; + var result = VerifyAbility(data); + data.AddLine(result); + } - int[] abilities = pkm.PersonalInfo.Abilities; - int abilval = Array.IndexOf(abilities, pkm.Ability); + private CheckResult VALID => GetValid(V115); + private CheckResult INVALID => GetInvalid(V223); + + private enum AbilityState : byte + { + CanMismatch, + MustMatch, + } + + private CheckResult VerifyAbility(LegalityAnalysis data) + { + var pkm = data.pkm; + var abilities = pkm.PersonalInfo.Abilities; + + // Check ability is possible (within bounds) + int ability = pkm.Ability; + int abilval = Array.IndexOf(abilities, ability); if (abilval < 0) - { - data.AddLine(GetInvalid(V107)); - return; - } + return GetInvalid(V107); - bool? AbilityUnchanged = true; - // 3 states flag: true for unchanged, false for changed, null for uncertain/allowing PID mismatch - // if true, check encounter ability - // if true or false, check PID/AbilityNumber - if (3 <= pkm.Format && pkm.Format <= 5 && abilities[0] != abilities[1]) // 3-5 and have 2 distinct ability now - AbilityUnchanged = VerifyAbilityPreCapsule(data, abilities, abilval); + if (data.EncounterMatch is MysteryGift g && g.Format >= 4) + return VerifyAbilityMG(data, abilities, g.AbilityType); - if (EncounterMatch is PCD d) - { - if (VerifyAbilityPCD(data, d, AbilityUnchanged, abilities)) - return; - } - else // Check Ability Mismatches - { - int? EncounterAbility = (EncounterMatch as EncounterStatic)?.Ability ?? - (EncounterMatch as EncounterTrade)?.Ability ?? - (EncounterMatch as EncounterLink)?.Ability; + if (pkm.Format < 6) + return VerifyAbility345(data, abilities, abilval); - if (EncounterAbility != null && VerifySetAbility(data, EncounterAbility, AbilityUnchanged, abilities, abilval)) - return; // result added via VerifySetAbility - } - switch (Info.Generation) - { - case 5: VerifyAbility5(data, abilities); break; - case 6: VerifyAbility6(data, abilities); break; - case 7: VerifyAbility7(data, abilities); break; - } + // Check AbilityNumber points to ability + int an = pkm.AbilityNumber >> 1; + if (an >= abilities.Length || abilities[an] != ability) + return GetInvalid(V114); - if (3 <= Info.Generation && Info.Generation <= 4 && pkm.AbilityNumber == 4) - data.AddLine(GetInvalid(V112)); - else if (AbilityUnchanged != null && abilities[pkm.AbilityNumber >> 1] != pkm.Ability) - data.AddLine(GetInvalid(pkm.Format < 6 ? V113 : V114)); - else - data.AddLine(GetValid(V115)); + return VerifyAbility(data, abilities, abilval); } - private bool VerifyAbilityPCD(LegalityAnalysis data, PCD pcd, bool? abilityUnchanged, int[] abilities) + + private CheckResult VerifyAbility(LegalityAnalysis data, IReadOnlyList abilities, int abilnum) + { + var EncounterMatch = data.EncounterMatch; + var eabil = GetEncounterFixedAbilityNumber(EncounterMatch); + if (eabil > 0) + return VerifyFixedAbility(data, abilities, AbilityState.CanMismatch, eabil, abilnum); + + var gen = data.Info.Generation; + switch (gen) + { + case 5: return VerifyAbility5(data, abilities); + case 6: return VerifyAbility6(data); + case 7: return VerifyAbility7(data); + } + + return CheckMatch(data.pkm, abilities, gen, AbilityState.CanMismatch); + } + private CheckResult VerifyAbility345(LegalityAnalysis data, IReadOnlyList abilities, int abilnum) { var pkm = data.pkm; - if (pcd.Species == pkm.Species && pkm.Ability == pcd.Gift.PK.Ability) // Edge case (PID ability gift mismatch) - data.AddLine(GetValid(V115)); - else if (pkm.Format >= 6 && abilities[0] == abilities[1] && pkm.AbilityNumber == 1) - data.AddLine(GetValid(V115)); // gen3-5 transfer with same ability -> 1st ability that matches - else if (pkm.Format >= 6 && abilities[0] != abilities[1] && pkm.AbilityNumber < 4) // Ability Capsule can change between 1/2 - data.AddLine(GetValid(V109)); - else - { - if (!(abilityUnchanged ?? false)) - return false; - data.AddLine(GetInvalid(V223)); - } - return true; + var state = AbilityState.MustMatch; + if (3 <= pkm.Format && pkm.Format <= 5 && abilities[0] != abilities[1]) // 3-4/5 and have 2 distinct abilities now + state = VerifyAbilityPreCapsule(data, abilities); + + var EncounterMatch = data.EncounterMatch; + int eabil = GetEncounterFixedAbilityNumber(EncounterMatch); + if (eabil > 0) + return VerifyFixedAbility(data, abilities, state, eabil, abilnum); + + int gen = data.Info.Generation; + if (gen == 5) + return VerifyAbility5(data, abilities); + + return CheckMatch(pkm, abilities, gen, state); } - private bool VerifySetAbility(LegalityAnalysis data, int? EncounterAbility, bool? AbilityUnchanged, int[] abilities, int abilval) + + private CheckResult VerifyFixedAbility(LegalityAnalysis data, IReadOnlyList abilities, AbilityState state, int EncounterAbility, int abilval) { var pkm = data.pkm; - if (pkm.AbilityNumber == 4 && EncounterAbility != 4) - { - data.AddLine(GetInvalid(V108)); - return true; - } + if ((pkm.AbilityNumber == 4) != (EncounterAbility == 4)) + return GetInvalid(V108); - if (data.EncounterMatch is EncounterTradePID z) - { - if (z.Species != pkm.Species) - return false; // Must match PID ability, handle via default check path - if (EncounterAbility == 1 << abilval) - { - data.AddLine(GetValid(V115)); - return true; - } - } + if (data.EncounterMatch.Species != pkm.Species) // evolved + return CheckMatch(pkm, abilities, data.Info.Generation, AbilityState.MustMatch); + + if (EncounterAbility == 1 << abilval) + return GetValid(V115); + + if (pkm.AbilityNumber == EncounterAbility) + return VALID; + + if (state == AbilityState.CanMismatch || EncounterAbility == 0) + return CheckMatch(pkm, abilities, data.Info.Generation, AbilityState.MustMatch); - if (!(AbilityUnchanged ?? false) || EncounterAbility == 0 || pkm.AbilityNumber == EncounterAbility) - return false; if (IsAbilityCapsuleModified(pkm, abilities, EncounterAbility)) - data.AddLine(GetValid(V109)); - else - data.AddLine(GetInvalid(V223)); - return true; + return GetValid(V109); + + return INVALID; + } + + private AbilityState VerifyAbilityPreCapsule(LegalityAnalysis data, IReadOnlyList abilities) + { + var pkm = data.pkm; + // CXD pokemon can have any ability without matching PID + if (pkm.Version == (int)GameVersion.CXD && pkm.Format == 3) + return AbilityState.CanMismatch; + + // Gen3 native or Gen4/5 origin + if (pkm.Format == 3 || !pkm.InhabitedGeneration(3)) + return AbilityState.MustMatch; + + // Evovled in Gen4/5 + if (pkm.Species > Legal.MaxSpeciesID_3) + return AbilityState.MustMatch; + + // If the species could not exist in Gen3, must match. + if (data.Info.EvoChainsAllGens[3].Count == 0) + return AbilityState.MustMatch; + + // Fall through when gen3 pkm transferred to gen4/5 + return VerifyAbilityGen3Transfer(data, abilities, data.Info.EvoChainsAllGens[3][0].Species); + } + private AbilityState VerifyAbilityGen3Transfer(LegalityAnalysis data, IReadOnlyList abilities, int maxGen3Species) + { + var pkm = data.pkm; + var pers = (PersonalInfoG3)PersonalTable.E[maxGen3Species]; + if (pers.Ability1 != pers.Ability2) // Excluding Colosseum/XD, a Gen3 pkm must match PID if it has 2 unique abilities + return pkm.Version == (int) GameVersion.CXD ? AbilityState.CanMismatch : AbilityState.MustMatch; + + if (pkm.Species != maxGen3Species) // it has evolved in either gen 4 or gen 5; the ability must match PID + return AbilityState.MustMatch; + + var chain = data.Info.EvoChainsAllGens; + bool evolved45 = chain[4].Count > 1 || (pkm.Format == 5 && chain[5].Count > 1); + if (evolved45) + { + if (pkm.Ability == pers.Ability1) // Could evolve in Gen4/5 and have a Gen3 only ability + return AbilityState.CanMismatch; // Not evolved in Gen4/5, doesn't need to match PIDAbility + + if (pkm.Ability == abilities[1]) // It could evolve in Gen4/5 and have Gen4 second ability + return AbilityState.MustMatch; // Evolved in Gen4/5, must match PIDAbility + } + + // If we reach here, it has not evolved in Gen4/5 games or has an invalid ability. + // The ability does not need to match the PIDAbility, but only Gen3 ability is allowed. + if (pkm.Ability != pers.Ability1) // Not evolved in Gen4/5, but doesn't have Gen3 only ability + data.AddLine(GetInvalid(V373)); // probably bad to do this here + + return AbilityState.CanMismatch; + } + + private CheckResult VerifyAbilityMG(LegalityAnalysis data, IReadOnlyList abilities, int cardtype) + { + if (data.EncounterMatch is PCD d) + return VerifyAbilityPCD(data, abilities, d); + + var pkm = data.pkm; + int abilNumber = pkm.AbilityNumber; + if (cardtype == 4) // 1/2/H + return VALID; + if (cardtype == 3) // 1/2 + return abilNumber == 4 ? GetInvalid(V110) : VALID; + + int cardAbilIndex = 1 << cardtype; + if (abilNumber == cardAbilIndex) + return VALID; + + if (abilNumber == 2 || cardtype == 2) + return GetInvalid(V108); + + // Ability can be flipped 0/1 if Ability Capsule is available, is not Hidden Ability, and Abilities are different. + if (pkm.Format >= 6 && abilities[0] != abilities[1]) + return GetValid(V109); + + return GetInvalid(pkm.Format < 6 ? V113 : V114); + } + private CheckResult VerifyAbilityPCD(LegalityAnalysis data, IReadOnlyList abilities, PCD pcd) + { + var pkm = data.pkm; + if (pkm.Format >= 6) + { + if (abilities[0] == abilities[1]) + { + // Gen3-5 transfer with same ability -> 1st ability that matches + if (pkm.AbilityNumber == 1) + return GetValid(V115); + return CheckMatch(pkm, abilities, 4, AbilityState.MustMatch); // evolved, must match + } + if (pkm.AbilityNumber < 4) // Ability Capsule can change between 1/2 + return GetValid(V109); + } + + if (pcd.Species != pkm.Species) + return CheckMatch(pkm, abilities, 4, AbilityState.MustMatch); // evolved, must match + + // Edge case (PID ability gift mismatch) -- must match gift ability. + return pkm.Ability == pcd.Gift.PK.Ability ? VALID : INVALID; + } + + private CheckResult VerifyAbility5(LegalityAnalysis data, IReadOnlyList abilities) + { + var pkm = data.pkm; + switch (data.EncounterMatch) + { + case EncounterSlot w: + // Hidden Abilities for Wild Encounters are only available at a Hidden Grotto + bool grotto = w.Type == SlotType.HiddenGrotto; + if (pkm.AbilityNumber == 4 ^ grotto) + return GetInvalid(grotto ? V217 : V108); + break; + + case EncounterEgg e when pkm.AbilityNumber == 4: + // Hidden Abilities for some are unbreedable (male only distribution) + if (Legal.MixedGenderBreeding.Contains(e.Species) || Legal.FixedGenderFromBiGender.Contains(e.Species)) + break; // from female + if (pkm.PersonalInfo.OnlyMale || Legal.Ban_BreedHidden5.Contains(e.Species)) + return GetInvalid(V112); + break; + } + var state = pkm.Format == 5 ? AbilityState.MustMatch : AbilityState.CanMismatch; + return CheckMatch(data.pkm, abilities, 5, state); + } + private CheckResult VerifyAbility6(LegalityAnalysis data) + { + var pkm = data.pkm; + var EncounterMatch = data.EncounterMatch; + if (EncounterMatch is EncounterSlot slot && pkm.AbilityNumber == 4) + { + bool valid = slot.Permissions.DexNav || slot.Type == SlotType.FriendSafari || slot.Type == SlotType.Horde; + if (!valid) + return GetInvalid(V300); + } + if (Legal.Ban_NoHidden6.Contains(pkm.SpecForm) && pkm.AbilityNumber == 4) + return GetInvalid(V112); + + return VALID; + } + private CheckResult VerifyAbility7(LegalityAnalysis data) + { + var pkm = data.pkm; + var EncounterMatch = data.EncounterMatch; + if (EncounterMatch is EncounterSlot slot && pkm.AbilityNumber == 4) + { + bool valid = slot.Type == SlotType.SOS; + if (!valid) + return GetInvalid(V111); + } + if (Legal.Ban_NoHidden7.Contains(pkm.SpecForm) && pkm.AbilityNumber == 4) + return GetInvalid(V112); + + return VALID; + } + + /// + /// Final checks assuming nothing else has flagged the ability. + /// + /// Pokémon + /// Current abilities + /// Generation + /// Permissive to allow ability to deviate under special circumstances + private CheckResult CheckMatch(PKM pkm, IReadOnlyList abilities, int gen, AbilityState state) + { + if (3 <= gen && gen <= 4 && pkm.AbilityNumber == 4) + return GetInvalid(V112); + + // other cases of hidden ability already flagged, all that is left is 1/2 mismatching + if (state == AbilityState.MustMatch && abilities[pkm.AbilityNumber >> 1] != pkm.Ability) + return GetInvalid(pkm.Format < 6 ? V113 : V114); + + return VALID; } // Ability Capsule can change between 1/2 - private static bool IsAbilityCapsuleModified(PKM pkm, IReadOnlyList abilities, int? EncounterAbility) + private static bool IsAbilityCapsuleModified(PKM pkm, IReadOnlyList abilities, int EncounterAbility) { if (pkm.Format < 6) return false; // Ability Capsule does not exist @@ -119,131 +296,15 @@ namespace PKHeX.Core return false; // Cannot alter from hidden ability. return true; } - private bool? VerifyAbilityPreCapsule(LegalityAnalysis data, int[] abilities, int abilval) + private static int GetEncounterFixedAbilityNumber(IEncounterable enc) { - var pkm = data.pkm; - // CXD pokemon could have any ability without maching PID - if (pkm.Version == (int)GameVersion.CXD && pkm.Format == 3) - return null; - - // gen3 native or gen4/5 origin - if (pkm.Format == 3 || !pkm.InhabitedGeneration(3)) - return true; - - // Evovled in gen4/5 - if (pkm.Species > Legal.MaxSpeciesID_3) - return false; - - // gen3Species will be zero for pokemon with illegal gen 3 encounters, like Infernape with gen 3 "origin" - var gen3Species = data.Info.EvoChainsAllGens[3].FirstOrDefault()?.Species ?? 0; - if (gen3Species == 0) - return true; - - // Fall through when gen3 pkm transferred to gen4/5 - return VerifyAbilityGen3Transfer(data, abilities, abilval, gen3Species); - } - private bool? VerifyAbilityGen3Transfer(LegalityAnalysis data, int[] abilities, int abilval, int Species_g3) - { - var pkm = data.pkm; - var Info = data.Info; - var pers = (PersonalInfoG3)PersonalTable.E[Species_g3]; - if (pers.Ability1 != pers.Ability2) // Excluding Colosseum/XD, a gen3 pkm must match PID if it has 2 unique abilities - return pkm.Version != (int)GameVersion.CXD; - - int Species_g4 = Info.EvoChainsAllGens[4].FirstOrDefault()?.Species ?? 0; - int Species_g5 = pkm.Format == 5 ? Info.EvoChainsAllGens[5].FirstOrDefault()?.Species ?? 0 : 0; - if (Math.Max(Species_g5, Species_g4) > Species_g3) // it has evolved in either gen 4 or gen 5; the ability must match PID - return false; - - var Evolutions_g45 = Math.Max(Info.EvoChainsAllGens[4].Count, pkm.Format == 5 ? Info.EvoChainsAllGens[5].Count : 0); - if (Evolutions_g45 > 1) + switch (enc) { - // Evolutions_g45 > 1 and Species_g45 = Species_g3 with means both options, evolve in gen 4-5 or not evolve, are possible - if (pkm.Ability == pers.Ability1) - // It could evolve in gen 4-5 an have generation 3 only ability - // that means it have not actually evolved in gen 4-5, ability do not need to match PID - return null; - if (pkm.Ability == abilities[1]) - // It could evolve in gen4-5 an have generation 4 second ability - // that means it have actually evolved in gen 4-5, ability must match PID - return false; + case EncounterStatic s: return s.Ability; + case EncounterTrade t: return t.Ability; + case EncounterLink l: return l.Ability; + default: return -1; } - // Evolutions_g45 == 1 means it have not evolved in gen 4-5 games, - // ability do not need to match PID, but only generation 3 ability is allowed - if (pkm.Ability != pers.Ability1) - // Not evolved in gen4-5 but do not have generation 3 only ability - data.AddLine(GetInvalid(V373)); - return null; - } - private void VerifyAbility5(LegalityAnalysis data, int[] abilities) - { - var pkm = data.pkm; - switch (data.EncounterMatch) - { - case PGF g: - VerifyAbilityMG456(data, abilities, g.AbilityType); - break; - - case EncounterSlot w: - // Hidden Abilities for Wild Encounters are only available at a Hidden Grotto - bool grotto = w.Type == SlotType.HiddenGrotto; - if (pkm.AbilityNumber == 4 ^ grotto) - data.AddLine(GetInvalid(grotto ? V217 : V108)); - break; - - case EncounterEgg e when pkm.AbilityNumber == 4: - // Hidden Abilities for some are unbreedable (male only distribution) - if (Legal.MixedGenderBreeding.Contains(e.Species) || Legal.FixedGenderFromBiGender.Contains(e.Species)) - break; // from female - if ((pkm.PersonalInfo.Gender & 0xFF) == 0 || Legal.Ban_BreedHidden.Contains(e.Species)) - data.AddLine(GetInvalid(V112)); - break; - } - } - private void VerifyAbility6(LegalityAnalysis data, int[] abilities) - { - var pkm = data.pkm; - var EncounterMatch = data.EncounterMatch; - if (EncounterMatch is EncounterSlot slot && pkm.AbilityNumber == 4) - { - bool valid = slot.Permissions.DexNav || slot.Type == SlotType.FriendSafari || slot.Type == SlotType.Horde; - if (!valid) - data.AddLine(GetInvalid(V300)); - } - else if (EncounterMatch is WC6 g) - VerifyAbilityMG456(data, abilities, g.AbilityType); - else if (Legal.Ban_NoHidden6.Contains(pkm.SpecForm) && pkm.AbilityNumber == 4) - data.AddLine(GetInvalid(V112)); - } - private void VerifyAbility7(LegalityAnalysis data, int[] abilities) - { - var pkm = data.pkm; - var EncounterMatch = data.EncounterMatch; - if (EncounterMatch is EncounterSlot slot && pkm.AbilityNumber == 4) - { - bool valid = slot.Type == SlotType.SOS; - if (!valid) - data.AddLine(GetInvalid(V111)); - } - else if (EncounterMatch is WC7 g) - VerifyAbilityMG456(data, abilities, g.AbilityType); - else if (Legal.Ban_NoHidden7.Contains(pkm.SpecForm) && pkm.AbilityNumber == 4) - data.AddLine(GetInvalid(V112)); - } - private void VerifyAbilityMG456(LegalityAnalysis data, int[] abilities, int cardtype) - { - var pkm = data.pkm; - int abilNumber = pkm.AbilityNumber; - if (cardtype < 3 && abilNumber != 1 << cardtype) // set number - { - // Ability can be flipped 0/1 if Ability Capsule is available, is not Hidden Ability, and Abilities are different. - if (pkm.Format >= 6 && cardtype < 2 && abilNumber < 3 && abilities[0] != abilities[1]) - data.AddLine(GetValid(V109)); - else - data.AddLine(GetInvalid(V110)); - } - else if (cardtype == 3 && abilNumber == 4) // 1/2 only - data.AddLine(GetInvalid(V110)); } } } diff --git a/PKHeX.Core/MysteryGifts/MysteryGift.cs b/PKHeX.Core/MysteryGifts/MysteryGift.cs index bfa0aa03a..ce6ec453d 100644 --- a/PKHeX.Core/MysteryGifts/MysteryGift.cs +++ b/PKHeX.Core/MysteryGifts/MysteryGift.cs @@ -137,6 +137,7 @@ namespace PKHeX.Core public virtual bool IsShiny => false; public virtual bool IsEgg { get => false; set { } } public virtual int HeldItem { get => -1; set { } } + public virtual int AbilityType { get => -1; set { } } public virtual object Content => this; public abstract int Gender { get; set; } public abstract int Form { get; set; } diff --git a/PKHeX.Core/MysteryGifts/PGF.cs b/PKHeX.Core/MysteryGifts/PGF.cs index 3e16c05f4..ec9748ed0 100644 --- a/PKHeX.Core/MysteryGifts/PGF.cs +++ b/PKHeX.Core/MysteryGifts/PGF.cs @@ -57,7 +57,7 @@ namespace PKHeX.Core } public int Nature { get => Data[0x34]; set => Data[0x34] = (byte)value; } public override int Gender { get => Data[0x35]; set => Data[0x35] = (byte)value; } - public int AbilityType { get => Data[0x36]; set => Data[0x36] = (byte)value; } + public override int AbilityType { get => Data[0x36]; set => Data[0x36] = (byte)value; } public int PIDType { get => Data[0x37]; set => Data[0x37] = (byte)value; } public override int EggLocation { get => BitConverter.ToUInt16(Data, 0x38); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, 0x38); } public ushort MetLocation { get => BitConverter.ToUInt16(Data, 0x3A); set => BitConverter.GetBytes(value).CopyTo(Data, 0x3A); } diff --git a/PKHeX.Core/MysteryGifts/WC6.cs b/PKHeX.Core/MysteryGifts/WC6.cs index 71d10918c..caa42bd3b 100644 --- a/PKHeX.Core/MysteryGifts/WC6.cs +++ b/PKHeX.Core/MysteryGifts/WC6.cs @@ -152,7 +152,7 @@ namespace PKHeX.Core public override int Gender { get => Data[0xA1]; set => Data[0xA1] = (byte)value; } - public int AbilityType { + public override int AbilityType { get => Data[0xA2]; set => Data[0xA2] = (byte)value; } public Shiny PIDType { diff --git a/PKHeX.Core/MysteryGifts/WC7.cs b/PKHeX.Core/MysteryGifts/WC7.cs index 622bcd42c..9d1c437ab 100644 --- a/PKHeX.Core/MysteryGifts/WC7.cs +++ b/PKHeX.Core/MysteryGifts/WC7.cs @@ -174,7 +174,7 @@ namespace PKHeX.Core public override int Gender { get => Data[0xA1]; set => Data[0xA1] = (byte)value; } - public int AbilityType { + public override int AbilityType { get => Data[0xA2]; set => Data[0xA2] = (byte)value; } public Shiny PIDType { diff --git a/Tests/PKHeX.Tests/Legality/Illegal/WC3/001 - Bulbasaur - 4543EBE98C5F.pk7 b/Tests/PKHeX.Tests/Legality/Illegal/WC3/001 - Bulbasaur - 4543EBE98C5F.pk7 new file mode 100644 index 000000000..380e4470a Binary files /dev/null and b/Tests/PKHeX.Tests/Legality/Illegal/WC3/001 - Bulbasaur - 4543EBE98C5F.pk7 differ diff --git a/Tests/PKHeX.Tests/Legality/Illegal/WC3/004 - ヒトカゲ - 1CCD0A2B1E99.pk7 b/Tests/PKHeX.Tests/Legality/Illegal/WC3/004 - ヒトカゲ - 1CCD0A2B1E99.pk7 new file mode 100644 index 000000000..a9042e066 Binary files /dev/null and b/Tests/PKHeX.Tests/Legality/Illegal/WC3/004 - ヒトカゲ - 1CCD0A2B1E99.pk7 differ diff --git a/Tests/PKHeX.Tests/Legality/Legal/Generation 4 Transfer/323 - CAMERUPT - 1EAB066E02B3.pk4 b/Tests/PKHeX.Tests/Legality/Legal/Generation 4 Transfer/323 - CAMERUPT - 1EAB066E02B3.pk4 new file mode 100644 index 000000000..db10d19f0 Binary files /dev/null and b/Tests/PKHeX.Tests/Legality/Legal/Generation 4 Transfer/323 - CAMERUPT - 1EAB066E02B3.pk4 differ diff --git a/Tests/PKHeX.Tests/Legality/Legal/Generation 4/470 - LEAFEON - 65B05FEF8D69.pk4 b/Tests/PKHeX.Tests/Legality/Legal/Generation 4/470 - LEAFEON - 65B05FEF8D69.pk4 new file mode 100644 index 000000000..77db1dfa4 Binary files /dev/null and b/Tests/PKHeX.Tests/Legality/Legal/Generation 4/470 - LEAFEON - 65B05FEF8D69.pk4 differ