using System; using static PKHeX.Core.Ball; using static PKHeX.Core.Species; using static PKHeX.Core.BallInheritanceResult; namespace PKHeX.Core; /// /// Ball Inheritance Permissions for games. /// public sealed class BallContext7 : IBallContext { public static readonly BallContext7 Instance = new(); public bool CanBreedWithBall(ushort species, byte form, Ball ball) { // Eagerly return true for the most common case if (ball is Poke) return true; if (species >= Permit.Length) return false; var permitBit = GetPermitBit(ball); if (permitBit == BallType.None) return false; var permit = Permit[species]; if ((permit & (1 << (byte)permitBit)) == 0) return false; return true; } public BallInheritanceResult CanBreedWithBall(ushort species, byte form, Ball ball, PKM pk) { // Eagerly return true for the most common case if (ball is Poke) return Valid; if (species >= Permit.Length) return Invalid; var permitBit = GetPermitBit(ball); if (permitBit == BallType.None) return Invalid; var permit = Permit[species]; if ((permit & (1 << (byte)permitBit)) == 0) return Invalid; if (!BallContextHOME.IsAbilityPatchPossible(pk.Format, species) && !IsAbilityAllowed(species, form, pk, permitBit)) return BadAbility; return Valid; } private static bool IsAbilityAllowed(ushort species, byte form, PKM pk, BallType permitBit) => permitBit switch { BallType.Gen3 => IsNotHidden(pk.AbilityNumber) || !IsBannedHiddenGen3(species), BallType.Gen4 => IsNotHidden(pk.AbilityNumber) || !IsBannedHiddenGen4(species), BallType.Safari => IsNotHidden(pk.AbilityNumber) || !IsBannedHiddenSafari(species), BallType.Apricorn => IsNotHidden(pk.AbilityNumber) || !IsBannedHiddenApricorn(species, form), BallType.Beast => IsNotHidden(pk.AbilityNumber) || !IsBannedHiddenBeast(species, form), _ => true, }; private static bool IsBannedHiddenBeast(ushort species, byte form) => species switch { (int)Voltorb => true, (int)Flabébé => form == 3, // Flabébé-Blue _ => false, }; private static bool IsBannedHiddenApricorn(ushort species, byte form) => species switch { (int)NidoranF => true, (int)NidoranM => true, (int)Voltorb => true, (int)Bronzor => true, (int)Flabébé => form == 3, // Flabébé-Blue _ => false, }; private static bool IsBannedHiddenSafari(ushort species) => species switch { (int)NidoranF => true, (int)NidoranM => true, (int)Volbeat => true, (int)Illumise => true, (int)Magnemite => true, (int)Voltorb => true, (int)Kangaskhan => true, (int)Tauros => true, (int)Ditto => true, (int)Miltank => true, (int)Beldum => true, (int)Bronzor => true, (int)Happiny => true, (int)Tyrogue => true, (int)Staryu => true, (int)Lunatone => true, (int)Solrock => true, (int)Rotom => true, (int)Klink => true, (int)Golett => true, _ => false, }; private static bool IsNotHidden(int pkAbilityNumber) => pkAbilityNumber != 4; private static bool IsBannedHiddenGen4(ushort species) => species switch { (int)Chikorita => true, (int)Cyndaquil => true, (int)Totodile => true, (int)Treecko => true, (int)Torchic => true, (int)Mudkip => true, (int)Turtwig => true, (int)Chimchar => true, (int)Piplup => true, (int)Snivy => true, (int)Tepig => true, (int)Oshawott => true, // Fossil Only obtain (int)Archen => true, (int)Tyrunt => true, (int)Amaura => true, _ => false, }; private static bool IsBannedHiddenGen3(ushort species) => species switch { // Fossil Only obtain (int)Archen => true, (int)Tyrunt => true, (int)Amaura => true, _ => false, }; private static BallType GetPermitBit(Ball ball) => ball switch { Ultra => BallType.Gen3, Great => BallType.Gen3, Poke => BallType.Gen3, Safari => BallType.Safari, Net => BallType.Gen3, Dive => BallType.Gen3, Nest => BallType.Gen3, Repeat => BallType.Gen3, Timer => BallType.Gen3, Luxury => BallType.Gen3, Premier => BallType.Gen3, Dusk => BallType.Gen4, Heal => BallType.Gen4, Quick => BallType.Gen4, Fast => BallType.Apricorn, Level => BallType.Apricorn, Lure => BallType.Apricorn, Heavy => BallType.Apricorn, Love => BallType.Apricorn, Friend => BallType.Apricorn, Moon => BallType.Apricorn, Sport => BallType.Sport, Dream => BallType.Dream, Beast => BallType.Beast, _ => BallType.None, }; public static ReadOnlySpan Permit => [ 0x00, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x7B, 0x03, 0x03, 0x7B, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x6F, // 000-019 0x03, 0x6F, 0x03, 0x6F, 0x03, 0x03, 0x03, 0x6F, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x03, 0x03, 0x6B, 0x03, 0x4B, // 020-039 0x03, 0x6F, 0x03, 0x2F, 0x03, 0x03, 0x7F, 0x03, 0x3F, 0x03, 0x6F, 0x03, 0x6B, 0x03, 0x6F, 0x03, 0x6B, 0x03, 0x6B, 0x03, // 040-059 0x6F, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x6B, 0x03, 0x6F, 0x03, 0x03, 0x2F, 0x03, 0x6F, // 060-079 0x03, 0x6F, 0x03, 0x2F, 0x2F, 0x03, 0x6B, 0x03, 0x6F, 0x03, 0x6B, 0x03, 0x6F, 0x03, 0x03, 0x6F, 0x6F, 0x03, 0x2F, 0x03, // 080-099 0x6F, 0x03, 0x6F, 0x03, 0x6F, 0x03, 0x03, 0x03, 0x6F, 0x2F, 0x03, 0x6F, 0x03, 0x6F, 0x2F, 0x6F, 0x6B, 0x03, 0x6F, 0x03, // 100-119 0x6B, 0x03, 0x6F, 0x7F, 0x03, 0x03, 0x03, 0x7F, 0x6F, 0x6F, 0x03, 0x6F, 0x00, 0x6B, 0x03, 0x03, 0x03, 0x23, 0x23, 0x03, // 120-139 0x23, 0x03, 0x23, 0x6B, 0x00, 0x00, 0x00, 0x6F, 0x03, 0x03, 0x00, 0x00, 0x4B, 0x03, 0x03, 0x4B, 0x03, 0x03, 0x4B, 0x03, // 140-159 0x03, 0x2F, 0x03, 0x6F, 0x03, 0x6F, 0x03, 0x6F, 0x03, 0x03, 0x6B, 0x03, 0x6F, 0x6F, 0x6F, 0x6B, 0x03, 0x6F, 0x03, 0x6F, // 160-179 0x03, 0x03, 0x03, 0x6F, 0x03, 0x6B, 0x03, 0x2F, 0x03, 0x07, 0x6F, 0x2F, 0x03, 0x6F, 0x6F, 0x03, 0x03, 0x03, 0x6F, 0x03, // 180-199 0x6F, 0x00, 0x2F, 0x2F, 0x6F, 0x03, 0x6B, 0x2F, 0x03, 0x6F, 0x03, 0x2B, 0x4B, 0x2F, 0x6F, 0x6B, 0x2F, 0x03, 0x6B, 0x03, // 200-219 0x6B, 0x03, 0x6B, 0x6F, 0x03, 0x6B, 0x6B, 0x6B, 0x6F, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x6F, 0x23, 0x03, 0x6B, 0x6F, // 220-239 0x6F, 0x6F, 0x03, 0x00, 0x00, 0x00, 0x6F, 0x03, 0x03, 0x00, 0x00, 0x00, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x6B, 0x03, // 240-259 0x03, 0x2B, 0x03, 0x2F, 0x07, 0x3B, 0x03, 0x03, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x6B, 0x03, 0x6B, 0x03, // 260-279 0x6B, 0x03, 0x03, 0x6F, 0x03, 0x2F, 0x03, 0x6F, 0x03, 0x03, 0x33, 0x03, 0x03, 0x2B, 0x03, 0x03, 0x6B, 0x03, 0x6F, 0x6F, // 280-299 0x23, 0x03, 0x6B, 0x6B, 0x6F, 0x07, 0x03, 0x6F, 0x03, 0x6F, 0x03, 0x2B, 0x2B, 0x37, 0x37, 0x6F, 0x2F, 0x03, 0x6F, 0x03, // 300-319 0x6B, 0x03, 0x2B, 0x03, 0x6F, 0x6B, 0x03, 0x6F, 0x6F, 0x03, 0x03, 0x27, 0x03, 0x6B, 0x03, 0x27, 0x27, 0x27, 0x27, 0x6F, // 320-339 0x03, 0x6F, 0x03, 0x6B, 0x03, 0x23, 0x03, 0x23, 0x03, 0x6B, 0x03, 0x6B, 0x6F, 0x6F, 0x03, 0x27, 0x03, 0x6F, 0x2F, 0x6B, // 340-359 0x2F, 0x6B, 0x03, 0x6F, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x6B, 0x6B, 0x6F, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x00, 0x00, 0x00, // 360-379 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x6F, 0x03, 0x03, 0x2F, // 380-399 0x03, 0x3B, 0x03, 0x6F, 0x03, 0x03, 0x6F, 0x03, 0x23, 0x03, 0x23, 0x03, 0x2B, 0x03, 0x03, 0x3B, 0x03, 0x27, 0x6F, 0x03, // 400-419 0x2B, 0x03, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x6B, 0x03, 0x03, 0x03, 0x23, 0x03, 0x2F, 0x23, 0x03, 0x2F, 0x03, 0x6B, 0x6F, // 420-439 0x6F, 0x2B, 0x23, 0x6F, 0x03, 0x03, 0x6B, 0x6F, 0x03, 0x6F, 0x03, 0x6F, 0x03, 0x27, 0x03, 0x2F, 0x6B, 0x03, 0x6B, 0x6B, // 440-459 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x6B, // 460-479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x03, 0x03, 0x4B, 0x03, // 480-499 0x03, 0x4B, 0x03, 0x03, 0x03, 0x03, 0x4B, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x23, 0x03, 0x23, 0x03, 0x23, 0x03, 0x23, // 500-519 0x03, 0x03, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x6B, 0x6B, 0x03, 0x03, 0x23, 0x03, 0x03, 0x23, 0x23, // 520-539 0x4B, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x6B, 0x03, 0x6B, 0x6B, 0x03, 0x03, 0x03, 0x03, 0x23, 0x6B, 0x03, 0x6B, // 540-559 0x03, 0x6B, 0x03, 0x03, 0x23, 0x03, 0x00, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x6B, 0x03, 0x03, 0x6B, 0x03, 0x03, // 560-579 0x6B, 0x03, 0x6B, 0x03, 0x03, 0x03, 0x03, 0x6B, 0x23, 0x03, 0x03, 0x03, 0x4B, 0x03, 0x6B, 0x23, 0x03, 0x03, 0x03, 0x6B, // 580-599 0x03, 0x03, 0x4B, 0x03, 0x03, 0x6B, 0x03, 0x4B, 0x03, 0x03, 0x6B, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x6B, 0x4B, // 600-619 0x03, 0x6B, 0x6B, 0x03, 0x6B, 0x03, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x23, 0x23, 0x4B, 0x03, 0x03, 0x4B, 0x03, 0x00, 0x00, // 620-639 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x03, 0x03, 0x4B, 0x03, 0x03, 0x4B, 0x03, 0x03, 0x03, // 640-659 0x03, 0x4B, 0x03, 0x4B, 0x4B, 0x03, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x03, 0x03, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x03, 0x4B, // 660-679 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x4B, 0x03, 0x00, 0x03, 0x00, 0x03, // 680-699 0x03, 0x4B, 0x4B, 0x4B, 0x4B, 0x03, 0x03, 0x4B, 0x4B, 0x03, 0x03, 0x03, 0x03, 0x03, 0x4B, 0x03, 0x00, 0x00, 0x00, 0x00, // 700-719 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4B, 0x43, 0x43, 0x4B, 0x43, 0x4B, 0x43, 0x43, 0x4B, // 720-739 0x43, 0x4B, 0x4B, 0x43, 0x4B, 0x43, 0x4B, 0x4B, 0x43, 0x4B, 0x43, 0x4B, 0x43, 0x4B, 0x43, 0x4B, 0x43, 0x4B, 0x43, 0x4B, // 740-759 0x43, 0x4B, 0x43, 0x43, 0x4B, 0x4B, 0x4B, 0x4B, 0x43, 0x4B, 0x43, 0x4B, 0x00, 0x00, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, 0x4B, // 760-779 0x4B, 0x4B, 0x4B, 0x43, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 780-799 ]; private enum BallType : byte { Gen3 = 0, Gen4 = 1, Safari = 2, Apricorn = 3, Sport = 4, Dream = 5, Beast = 6, None = 9, } }