mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-23 20:43:07 +00:00
Handle Ability Patch changed abilities (#3024)
Handles conditions when Ability Patch has been used to modify the PKM's ability => hidden ability. Per the description, it goes 1/2=>H, not the other way around. Verify ability bit first, as mystery gift case handling skips the bit check logic :P
This commit is contained in:
parent
e6e3166f13
commit
a0a8dd0f91
5 changed files with 73 additions and 34 deletions
|
@ -64,6 +64,7 @@ namespace PKHeX.Core
|
||||||
public static string L_XWurmpleEvo_0 { get; set; } = "Wurmple Evolution: {0}";
|
public static string L_XWurmpleEvo_0 { get; set; } = "Wurmple Evolution: {0}";
|
||||||
|
|
||||||
public static string LAbilityCapsuleUsed { get; set; } = "Ability modified with Ability Capsule.";
|
public static string LAbilityCapsuleUsed { get; set; } = "Ability modified with Ability Capsule.";
|
||||||
|
public static string LAbilityPatchUsed { get; set; } = "Ability modified with Ability Patch.";
|
||||||
public static string LAbilityFlag { get; set; } = "Ability matches ability number.";
|
public static string LAbilityFlag { get; set; } = "Ability matches ability number.";
|
||||||
public static string LAbilityHiddenFail { get; set; } = "Hidden Ability mismatch for encounter type.";
|
public static string LAbilityHiddenFail { get; set; } = "Hidden Ability mismatch for encounter type.";
|
||||||
public static string LAbilityHiddenUnavailable { get; set; } = "Hidden Ability not available.";
|
public static string LAbilityHiddenUnavailable { get; set; } = "Hidden Ability not available.";
|
||||||
|
|
|
@ -111,8 +111,15 @@ namespace PKHeX.Core
|
||||||
abil = ability_param;
|
abil = ability_param;
|
||||||
abil <<= 1; // 1/2/4
|
abil <<= 1; // 1/2/4
|
||||||
|
|
||||||
if ((pk.AbilityNumber == 4) != (abil == 4))
|
var current = pk.AbilityNumber;
|
||||||
|
if (current == 4 && abil != 4)
|
||||||
|
{
|
||||||
|
// Defer for Ability Checks
|
||||||
|
}
|
||||||
|
else if (abil == 4)
|
||||||
|
{
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
switch (gender_ratio)
|
switch (gender_ratio)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,24 +36,34 @@ namespace PKHeX.Core
|
||||||
if (abilval < 0)
|
if (abilval < 0)
|
||||||
return GetInvalid(LAbilityUnexpected);
|
return GetInvalid(LAbilityUnexpected);
|
||||||
|
|
||||||
var enc = data.EncounterMatch;
|
|
||||||
var abilities = pi.Abilities;
|
var abilities = pi.Abilities;
|
||||||
|
int format = pkm.Format;
|
||||||
|
if (format >= 6)
|
||||||
|
{
|
||||||
|
// Check AbilityNumber is a single set bit
|
||||||
|
var num = pkm.AbilityNumber;
|
||||||
|
if (!(num != 0 && (num & (num - 1)) == 0)) // not [!zero, and power of 2]
|
||||||
|
return GetInvalid(LAbilityMismatchFlag);
|
||||||
|
|
||||||
|
// Check AbilityNumber points to ability
|
||||||
|
int an = num >> 1;
|
||||||
|
if (an >= abilities.Count || abilities[an] != ability)
|
||||||
|
return GetInvalid(LAbilityMismatchFlag);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format >= 8) // Ability Patch
|
||||||
|
{
|
||||||
|
if (pkm.AbilityNumber == 4 && CanAbilityPatch(format, abilities))
|
||||||
|
return GetValid(LAbilityPatchUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
var enc = data.EncounterMatch;
|
||||||
if (enc is MysteryGift g && g.Format >= 4)
|
if (enc is MysteryGift g && g.Format >= 4)
|
||||||
return VerifyAbilityMG(data, g, abilities);
|
return VerifyAbilityMG(data, g, abilities);
|
||||||
|
|
||||||
if (pkm.Format < 6)
|
if (format < 6)
|
||||||
return VerifyAbility345(data, enc, abilities, abilval);
|
return VerifyAbility345(data, enc, abilities, abilval);
|
||||||
|
|
||||||
// Check AbilityNumber is a single set bit
|
|
||||||
var num = pkm.AbilityNumber;
|
|
||||||
if (num == 0 || num == 0b101 || num == 0b110 || num == 0b011)
|
|
||||||
return GetInvalid(LAbilityMismatchFlag);
|
|
||||||
|
|
||||||
// Check AbilityNumber points to ability
|
|
||||||
int an = num >> 1;
|
|
||||||
if (an >= abilities.Count || abilities[an] != ability)
|
|
||||||
return GetInvalid(LAbilityMismatchFlag);
|
|
||||||
|
|
||||||
return VerifyAbility(data, abilities, abilval);
|
return VerifyAbility(data, abilities, abilval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,9 +235,10 @@ namespace PKHeX.Core
|
||||||
private CheckResult VerifyAbilityPCD(LegalityAnalysis data, IReadOnlyList<int> abilities, PCD pcd)
|
private CheckResult VerifyAbilityPCD(LegalityAnalysis data, IReadOnlyList<int> abilities, PCD pcd)
|
||||||
{
|
{
|
||||||
var pkm = data.pkm;
|
var pkm = data.pkm;
|
||||||
if (pkm.Format >= 6)
|
var format = pkm.Format;
|
||||||
|
if (format >= 6)
|
||||||
{
|
{
|
||||||
if (abilities[0] == abilities[1])
|
if (CanAbilityCapsule(format, abilities))
|
||||||
{
|
{
|
||||||
// Gen3-5 transfer with same ability -> 1st ability that matches
|
// Gen3-5 transfer with same ability -> 1st ability that matches
|
||||||
if (pkm.AbilityNumber == 1)
|
if (pkm.AbilityNumber == 1)
|
||||||
|
@ -334,10 +345,8 @@ namespace PKHeX.Core
|
||||||
// Ability Capsule can change between 1/2
|
// Ability Capsule can change between 1/2
|
||||||
private static bool IsAbilityCapsuleModified(PKM pkm, IReadOnlyList<int> abilities, int EncounterAbility)
|
private static bool IsAbilityCapsuleModified(PKM pkm, IReadOnlyList<int> abilities, int EncounterAbility)
|
||||||
{
|
{
|
||||||
if (pkm.Format < 6)
|
if (!CanAbilityCapsule(pkm.Format, abilities))
|
||||||
return false; // Ability Capsule does not exist
|
return false;
|
||||||
if (abilities[0] == abilities[1])
|
|
||||||
return false; // Cannot alter ability index if it is the same as the other ability.
|
|
||||||
if (pkm.AbilityNumber == 4)
|
if (pkm.AbilityNumber == 4)
|
||||||
return false; // Cannot alter to hidden ability.
|
return false; // Cannot alter to hidden ability.
|
||||||
if (EncounterAbility == 4)
|
if (EncounterAbility == 4)
|
||||||
|
@ -345,6 +354,21 @@ namespace PKHeX.Core
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool CanAbilityCapsule(int format, IReadOnlyList<int> abilities)
|
||||||
|
{
|
||||||
|
if (format < 6) // Ability Capsule does not exist
|
||||||
|
return false;
|
||||||
|
return abilities[0] != abilities[1]; // Cannot alter ability index if it is the same as the other ability.
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanAbilityPatch(int format, IReadOnlyList<int> abilities)
|
||||||
|
{
|
||||||
|
if (format < 8) // Ability Patch does not exist
|
||||||
|
return false;
|
||||||
|
var h = abilities[2];
|
||||||
|
return h != abilities[0] || h != abilities[1]; // Cannot alter ability index if it is the same as the other abilities.
|
||||||
|
}
|
||||||
|
|
||||||
private static int GetEncounterFixedAbilityNumber(IEncounterable enc)
|
private static int GetEncounterFixedAbilityNumber(IEncounterable enc)
|
||||||
{
|
{
|
||||||
return enc switch
|
return enc switch
|
||||||
|
|
|
@ -122,7 +122,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!Legal.Inherit_Safari.Contains(species))
|
if (!Legal.Inherit_Safari.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4)
|
if (IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!Legal.Inherit_Apricorn6.Contains(species))
|
if (!Legal.Inherit_Apricorn6.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4)
|
if (IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -138,13 +138,13 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!Legal.Inherit_Sport.Contains(species))
|
if (!Legal.Inherit_Sport.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4)
|
if (IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
if (ball == Dream) // Dream Ball
|
if (ball == Dream) // Dream Ball
|
||||||
{
|
{
|
||||||
if (pkm.AbilityNumber == 4 && Legal.Ban_DreamHidden.Contains(species))
|
if (Legal.Ban_DreamHidden.Contains(species) && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
if (Legal.Inherit_Dream.Contains(species))
|
if (Legal.Inherit_Dream.Contains(species))
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
|
@ -160,7 +160,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (Legal.Ban_Gen3Ball.Contains(species))
|
if (Legal.Ban_Gen3Ball.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4 && Legal.Ban_Gen3BallHidden.Contains(pkm.SpecForm))
|
if (Legal.Ban_Gen3BallHidden.Contains(pkm.SpecForm) && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!(Legal.Inherit_Safari.Contains(species) || Legal.Inherit_SafariMale.Contains(species)))
|
if (!(Legal.Inherit_Safari.Contains(species) || Legal.Inherit_SafariMale.Contains(species)))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4 && Legal.Ban_SafariBallHidden_7.Contains(species))
|
if (Legal.Ban_SafariBallHidden_7.Contains(species) && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -199,7 +199,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!Legal.Inherit_Apricorn7.Contains(species))
|
if (!Legal.Inherit_Apricorn7.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4 && Legal.Ban_NoHidden7Apricorn.Contains(species | pkm.AltForm << 11)) // lineage is 3->2->origin
|
if (Legal.Ban_NoHidden7Apricorn.Contains(species | pkm.AltForm << 11) && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -207,7 +207,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!Legal.Inherit_Sport.Contains(species))
|
if (!Legal.Inherit_Sport.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4 && (species == (int)Species.Volbeat || species == (int)Species.Illumise)) // Volbeat/Illumise
|
if ((species == (int)Species.Volbeat || species == (int)Species.Illumise) && IsHiddenAndNotPossible(pkm)) // Volbeat/Illumise
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -232,9 +232,9 @@ namespace PKHeX.Core
|
||||||
|
|
||||||
if (ball == Beast)
|
if (ball == Beast)
|
||||||
{
|
{
|
||||||
if (species == (int)Species.Flabébé && pkm.AltForm == 3 && pkm.AbilityNumber == 4)
|
if (species == (int)Species.Flabébé && pkm.AltForm == 3 && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility); // Can't obtain Flabébé-Blue with Hidden Ability in wild
|
return GetInvalid(LBallAbility); // Can't obtain Flabébé-Blue with Hidden Ability in wild
|
||||||
if (species == (int)Species.Voltorb && pkm.AbilityNumber == 4)
|
if (species == (int)Species.Voltorb && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility); // Can't obtain with Hidden Ability in wild (can only breed with Ditto)
|
return GetInvalid(LBallAbility); // Can't obtain with Hidden Ability in wild (can only breed with Ditto)
|
||||||
if (((int)Species.Pikipek <= species && species <= (int)Species.Kommoo) || (Legal.AlolanCaptureOffspring.Contains(species) && !Legal.PastGenAlolanNativesUncapturable.Contains(species)))
|
if (((int)Species.Pikipek <= species && species <= (int)Species.Kommoo) || (Legal.AlolanCaptureOffspring.Contains(species) && !Legal.PastGenAlolanNativesUncapturable.Contains(species)))
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
|
@ -275,7 +275,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!(Legal.Inherit_Safari.Contains(species) || Legal.Inherit_SafariMale.Contains(species)))
|
if (!(Legal.Inherit_Safari.Contains(species) || Legal.Inherit_SafariMale.Contains(species)))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4 && Legal.Ban_SafariBallHidden_7.Contains(species))
|
if (Legal.Ban_SafariBallHidden_7.Contains(species) && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -283,7 +283,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!Legal.Inherit_Apricorn7.Contains(species))
|
if (!Legal.Inherit_Apricorn7.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4 && Legal.Ban_NoHidden8Apricorn.Contains(species | pkm.AltForm << 11)) // lineage is 3->2->origin
|
if (Legal.Ban_NoHidden8Apricorn.Contains(species | pkm.AltForm << 11) && IsHiddenAndNotPossible(pkm)) // lineage is 3->2->origin
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -291,7 +291,7 @@ namespace PKHeX.Core
|
||||||
{
|
{
|
||||||
if (!Legal.Inherit_Sport.Contains(species))
|
if (!Legal.Inherit_Sport.Contains(species))
|
||||||
return GetInvalid(LBallSpecies);
|
return GetInvalid(LBallSpecies);
|
||||||
if (pkm.AbilityNumber == 4 && (species == (int)Species.Volbeat || species == (int)Species.Illumise)) // Volbeat/Illumise
|
if ((species == (int)Species.Volbeat || species == (int)Species.Illumise) && IsHiddenAndNotPossible(pkm)) // Volbeat/Illumise
|
||||||
return GetInvalid(LBallAbility);
|
return GetInvalid(LBallAbility);
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
}
|
}
|
||||||
|
@ -316,7 +316,7 @@ namespace PKHeX.Core
|
||||||
|
|
||||||
if (ball == Beast)
|
if (ball == Beast)
|
||||||
{
|
{
|
||||||
if (species == (int)Species.Flabébé && pkm.AltForm == 3 && pkm.AbilityNumber == 4)
|
if (species == (int)Species.Flabébé && pkm.AltForm == 3 && IsHiddenAndNotPossible(pkm))
|
||||||
return GetInvalid(LBallAbility); // Can't obtain Flabébé-Blue with Hidden Ability in wild
|
return GetInvalid(LBallAbility); // Can't obtain Flabébé-Blue with Hidden Ability in wild
|
||||||
if (((int)Species.Pikipek <= species && species <= (int)Species.Kommoo) || (Legal.AlolanCaptureOffspring.Contains(species) && !Legal.PastGenAlolanNativesUncapturable.Contains(species)))
|
if (((int)Species.Pikipek <= species && species <= (int)Species.Kommoo) || (Legal.AlolanCaptureOffspring.Contains(species) && !Legal.PastGenAlolanNativesUncapturable.Contains(species)))
|
||||||
return GetValid(LBallSpeciesPass);
|
return GetValid(LBallSpeciesPass);
|
||||||
|
@ -337,6 +337,13 @@ namespace PKHeX.Core
|
||||||
return NONE;
|
return NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsHiddenAndNotPossible(PKM pkm)
|
||||||
|
{
|
||||||
|
if (pkm.AbilityNumber != 4)
|
||||||
|
return false;
|
||||||
|
return !AbilityVerifier.CanAbilityPatch(pkm.Format, pkm.PersonalInfo.Abilities);
|
||||||
|
}
|
||||||
|
|
||||||
public static bool IsGalarCatchAndBreed(int species)
|
public static bool IsGalarCatchAndBreed(int species)
|
||||||
{
|
{
|
||||||
if ((int)Species.Grookey <= species && species <= (int)Species.Inteleon) // starter
|
if ((int)Species.Grookey <= species && species <= (int)Species.Inteleon) // starter
|
||||||
|
|
|
@ -80,7 +80,7 @@ namespace PKHeX.Core
|
||||||
var pkm = data.pkm;
|
var pkm = data.pkm;
|
||||||
if (pkm.GO)
|
if (pkm.GO)
|
||||||
VerifyIVsGoTransfer(data);
|
VerifyIVsGoTransfer(data);
|
||||||
else if (pkm.AbilityNumber == 4)
|
else if (pkm.AbilityNumber == 4 && !AbilityVerifier.CanAbilityPatch(pkm.Format, pkm.PersonalInfo.Abilities))
|
||||||
VerifyIVsFlawless(data, 2); // Chain of 10 yields 5% HA and 2 flawless IVs
|
VerifyIVsFlawless(data, 2); // Chain of 10 yields 5% HA and 2 flawless IVs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue