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