diff --git a/PKHeX.Core/Legality/Verifiers/Ball/BallVerifier.cs b/PKHeX.Core/Legality/Verifiers/Ball/BallVerifier.cs index 189d90d0d..b9b663214 100644 --- a/PKHeX.Core/Legality/Verifiers/Ball/BallVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/Ball/BallVerifier.cs @@ -1,5 +1,7 @@ +using System; using static PKHeX.Core.LegalityCheckStrings; using static PKHeX.Core.Ball; +using static PKHeX.Core.BallVerificationResult; namespace PKHeX.Core; @@ -15,7 +17,7 @@ public sealed class BallVerifier : Verifier if (data.Entity.Format <= 2) return; // no ball info saved var result = VerifyBall(data); - data.AddLine(result); + data.AddLine(Localize(result)); } private static byte IsReplacedBall(IVersion enc, PKM pk) => pk switch @@ -29,31 +31,40 @@ public sealed class BallVerifier : Verifier private const int NoBallReplace = (int)None; - private CheckResult VerifyBall(LegalityAnalysis data) + public static BallVerificationResult VerifyBall(LegalityAnalysis data) { var info = data.Info; var enc = info.EncounterOriginal; var pk = data.Entity; - var ball = IsReplacedBall(enc, pk); - if (ball != NoBallReplace) - return VerifyBallEquals(pk, ball); - // Capture / Inherit cases -- can be one of many balls if (pk.Species == (int)Species.Shedinja && enc.Species != (int)Species.Shedinja) // Shedinja. For Gen3, copy the ball from Nincada { // Only a Gen3 origin Shedinja can copy the wild ball. // Evolution chains will indicate if it could have existed as Shedinja in Gen3. // The special move verifier has a similar check! - if (pk is { HGSS: true, Ball: (int)Sport }) // Can evolve in D/P to retain the HG/SS ball (separate byte) -- not able to be captured in any other ball + if (enc is { Version: GameVersion.HG or GameVersion.SS, IsEgg: false } && pk is { Ball: (int)Sport }) // Can evolve in D/P to retain the HG/SS ball (separate byte) -- not able to be captured in any other ball return GetResult(true); if (enc.Generation != 3 || info.EvoChainsAllGens.Gen3.Length != 2) // not evolved in Gen3 Nincada->Shedinja return VerifyBallEquals(pk, (int)Poke); // Poké Ball Only } + return VerifyBall(pk, enc); + } + + /// + /// Verifies the currently set ball for the . + /// + /// Call this directly instead of the overload if you've already ruled out the above cases needing Evolution chains. + public static BallVerificationResult VerifyBall(PKM pk, IEncounterTemplate enc) + { + var ball = IsReplacedBall(enc, pk); + if (ball != NoBallReplace) + return VerifyBallEquals(pk, ball); + // Capturing with Heavy Ball is impossible in Sun/Moon for specific species. if (pk is { Ball: (int)Heavy, SM: true } && enc is not EncounterEgg && BallUseLegality.IsAlolanCaptureNoHeavyBall(enc.Species)) - return GetInvalid(LBallHeavy); // Heavy Ball, can inherit if from egg (US/UM fixed catch rate calc) + return BadCaptureHeavy; // Heavy Ball, can inherit if from egg (US/UM fixed catch rate calc) return enc switch { @@ -67,54 +78,54 @@ public sealed class BallVerifier : Verifier }; } - private CheckResult VerifyBallEgg(PKM pk, IEncounterTemplate enc) + private static BallVerificationResult VerifyBallEgg(PKM pk, IEncounterTemplate enc) { if (enc.Generation < 6) // No inheriting Balls return VerifyBallEquals(pk, (int)Poke); // Must be Poké Ball -- no ball inheritance. return pk.Ball switch { - (int)Master => GetInvalid(LBallEggMaster), // Master Ball - (int)Cherish => GetInvalid(LBallEggCherish), // Cherish Ball + (int)Master => BadInheritMaster, + (int)Cherish => BadInheritCherish, _ => VerifyBallInherited(pk, enc), }; } - private CheckResult VerifyBallInherited(PKM pk, IEncounterTemplate enc) => enc.Context switch + private static BallVerificationResult VerifyBallInherited(PKM pk, IEncounterTemplate enc) => enc.Context switch { EntityContext.Gen6 => VerifyBallEggGen6(pk, enc), // Gen6 Inheritance Rules EntityContext.Gen7 => VerifyBallEggGen7(pk, enc), // Gen7 Inheritance Rules EntityContext.Gen8 => VerifyBallEggGen8(pk, enc), EntityContext.Gen8b => VerifyBallEggGen8BDSP(pk, enc), EntityContext.Gen9 => VerifyBallEggGen9(pk, enc), - _ => GetInvalid(LBallNone), + _ => BadEncounter, }; - private CheckResult VerifyBallEggGen6(PKM pk, IEncounterTemplate enc) + private static BallVerificationResult VerifyBallEggGen6(PKM pk, IEncounterTemplate enc) { var ball = (Ball)pk.Ball; if (ball > Dream) - return GetInvalid(LBallUnavailable); + return BadOutOfRange; var result = BallContext6.Instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk); return GetResult(result); } - private CheckResult VerifyBallEggGen7(PKM pk, IEncounterTemplate enc) + private static BallVerificationResult VerifyBallEggGen7(PKM pk, IEncounterTemplate enc) { var ball = (Ball)pk.Ball; if (ball > Beast) - return GetInvalid(LBallUnavailable); + return BadOutOfRange; var result = BallContext7.Instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk); return GetResult(result); } - private CheckResult VerifyBallEggGen8BDSP(PKM pk, IEncounterTemplate enc) + private static BallVerificationResult VerifyBallEggGen8BDSP(PKM pk, IEncounterTemplate enc) { var ball = (Ball)pk.Ball; if (ball > Beast) - return GetInvalid(LBallUnavailable); + return BadOutOfRange; var species = enc.Species; if (species is (int)Species.Spinda) // Can't transfer via HOME. @@ -124,21 +135,21 @@ public sealed class BallVerifier : Verifier return GetResult(result); } - private CheckResult VerifyBallEggGen8(PKM pk, IEncounterTemplate enc) + private static BallVerificationResult VerifyBallEggGen8(PKM pk, IEncounterTemplate enc) { var ball = (Ball)pk.Ball; if (ball > Beast) - return GetInvalid(LBallUnavailable); + return BadOutOfRange; var result = BallContextHOME.Instance.CanBreedWithBall(enc.Species, enc.Form, ball); return GetResult(result); } - private CheckResult VerifyBallEggGen9(PKM pk, IEncounterTemplate enc) + private static BallVerificationResult VerifyBallEggGen9(PKM pk, IEncounterTemplate enc) { var ball = (Ball)pk.Ball; if (ball > Beast) - return GetInvalid(LBallUnavailable); + return BadOutOfRange; // Paldea Starters: Only via GO (Adventures Abound) var species = enc.Species; @@ -149,15 +160,62 @@ public sealed class BallVerifier : Verifier return GetResult(result); } - private CheckResult VerifyBallEquals(PKM pk, byte ball) => GetResult(ball == pk.Ball); - private CheckResult VerifyBallEquals(Ball ball, ulong permit) => GetResult(BallUseLegality.IsBallPermitted(permit, (byte)ball)); + private static BallVerificationResult VerifyBallEquals(PKM pk, byte ball) => GetResult(ball == pk.Ball); + private static BallVerificationResult VerifyBallEquals(Ball ball, ulong permit) => GetResult(BallUseLegality.IsBallPermitted(permit, (byte)ball)); - private CheckResult GetResult(bool valid) => valid ? GetValid(LBallEnc) : GetInvalid(LBallEncMismatch); + private static BallVerificationResult GetResult(bool valid) => valid ? ValidEncounter : BadEncounter; - private CheckResult GetResult(BallInheritanceResult result) => result switch + private static BallVerificationResult GetResult(BallInheritanceResult result) => result switch { - BallInheritanceResult.Valid => GetValid(LBallSpeciesPass), - BallInheritanceResult.BadAbility => GetInvalid(LBallAbility), - _ => GetInvalid(LBallSpecies), + BallInheritanceResult.Valid => ValidInheritedSpecies, + BallInheritanceResult.BadAbility => BadInheritAbility, + _ => BadInheritSpecies, + }; + + private CheckResult Localize(BallVerificationResult value) + { + bool valid = value.IsValid(); + string msg = value.GetMessage(); + return Get(msg, valid ? Severity.Valid : Severity.Invalid); + } +} + +public enum BallVerificationResult +{ + ValidEncounter, + ValidInheritedSpecies, + + BadEncounter, + BadCaptureHeavy, + + BadInheritAbility, + BadInheritSpecies, + BadInheritCherish, + BadInheritMaster, + + BadOutOfRange, +} + +public static class BallVerificationResultExtensions +{ + public static bool IsValid(this BallVerificationResult value) => value switch + { + ValidEncounter => true, + ValidInheritedSpecies => true, + _ => false, + }; + + public static string GetMessage(this BallVerificationResult value) => value switch + { + ValidEncounter => LBallEnc, + ValidInheritedSpecies => LBallSpeciesPass, + BadEncounter => LBallEncMismatch, + BadCaptureHeavy => LBallHeavy, + BadInheritAbility => LBallAbility, + BadInheritSpecies => LBallSpecies, + BadInheritCherish => LBallEggCherish, + BadInheritMaster => LBallEggMaster, + BadOutOfRange => LBallUnavailable, + _ => throw new ArgumentOutOfRangeException(nameof(value), value, null), }; } diff --git a/PKHeX.Core/PKM/PB8.cs b/PKHeX.Core/PKM/PB8.cs index 1d8dafa7a..c28ac2e16 100644 --- a/PKHeX.Core/PKM/PB8.cs +++ b/PKHeX.Core/PKM/PB8.cs @@ -134,8 +134,6 @@ public sealed class PB8 : G8PKM public override int MaxBallID => Legal.MaxBallID_8b; public override GameVersion MaxGameID => Legal.MaxGameID_HOME; - public override bool WasEgg => IsEgg || EggDay != 0; - public override bool HasOriginalMetLocation => base.HasOriginalMetLocation && !(LA && MetLocation == LocationsHOME.SWLA); public override string GetString(ReadOnlySpan data)