mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-26 05:50:22 +00:00
Memoize Ball Breeding permission tables (#4050)
O(1) lookup for arbitrary species, some edge handling rules for specific game islands/forms. With HOME, there's only 3 islands of permissions. No allocation besides the singletons which aren't really necessary.
No longer need to peek within multiple hashsets, just fetch the "is possible" bit from the species listing and check if the bit is set.
Will be fun if ball shell swaps are added 🤞, get to set all bits for anything that can enter game with that feature (if ever added).
Add unit test for gen67 no-patch exclusion
This commit is contained in:
parent
8e28ca8cf4
commit
bced546c63
13 changed files with 754 additions and 1367 deletions
|
@ -1,3 +1,4 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using static PKHeX.Core.GroundTileAllowed;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
@ -243,7 +244,7 @@ public sealed record EncounterStatic4(GameVersion Version)
|
|||
|
||||
private bool IsMatchPartial(PKM pk) => Gift && pk.Ball != (byte)FixedBall;
|
||||
|
||||
public static bool IsMatchRoamerLocation(ulong permit, int location, int first)
|
||||
public static bool IsMatchRoamerLocation([ConstantExpected] ulong permit, int location, int first)
|
||||
{
|
||||
var value = location - first;
|
||||
if ((uint)value >= 64)
|
||||
|
@ -251,7 +252,7 @@ public sealed record EncounterStatic4(GameVersion Version)
|
|||
return (permit & (1ul << value)) != 0;
|
||||
}
|
||||
|
||||
public static bool IsMatchRoamerLocation(uint permit, int location, int first)
|
||||
public static bool IsMatchRoamerLocation([ConstantExpected] uint permit, int location, int first)
|
||||
{
|
||||
var value = location - first;
|
||||
if ((uint)value >= 32)
|
||||
|
|
|
@ -16,7 +16,7 @@ public sealed record EncounterEgg(ushort Species, byte Form, byte Level, int Gen
|
|||
public bool IsShiny => false;
|
||||
public int Location => 0;
|
||||
public int EggLocation => Locations.GetDaycareLocation(Generation, Version);
|
||||
public Ball FixedBall => BallBreedLegality.GetDefaultBall(Version, Species);
|
||||
public Ball FixedBall => Generation <= 5 ? Ball.Poke : Ball.None;
|
||||
public Shiny Shiny => Shiny.Random;
|
||||
public AbilityPermission Ability => AbilityPermission.Any12H;
|
||||
|
||||
|
|
|
@ -144,28 +144,11 @@ internal static class AbilityBreedLegality
|
|||
(int)Rotom + (5 << 11),
|
||||
};
|
||||
|
||||
// <summary>
|
||||
// Species that cannot be bred with a Hidden Ability originating in <see cref="GameVersion.Gen8"/>
|
||||
// </summary>
|
||||
// internal static readonly HashSet<ushort> BanHidden8 = new(); // none as of DLC 1!
|
||||
|
||||
/// <summary>
|
||||
/// Species that cannot be bred with a Hidden Ability originating in <see cref="GameVersion.BDSP"/>
|
||||
/// </summary>
|
||||
internal static readonly HashSet<ushort> BanHidden8b = new()
|
||||
{
|
||||
(int)Rotom,
|
||||
(int)Rotom + (1 << 11),
|
||||
(int)Rotom + (2 << 11),
|
||||
(int)Rotom + (3 << 11),
|
||||
(int)Rotom + (4 << 11),
|
||||
(int)Rotom + (5 << 11),
|
||||
|
||||
(int)Baltoy,
|
||||
(int)Claydol,
|
||||
(int)Solrock,
|
||||
(int)Lunatone,
|
||||
|
||||
(int)Phione,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,985 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using static PKHeX.Core.Species;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Tables used for <see cref="BallVerifier"/>
|
||||
/// </summary>
|
||||
internal static class BallBreedLegality
|
||||
{
|
||||
/// <summary>
|
||||
/// Species that are male only in Generation 6; for ball inheritance, these behave the same as Genderless species (no ball inherited).
|
||||
/// </summary>
|
||||
internal static readonly HashSet<ushort> BreedMaleOnly6 = new()
|
||||
{
|
||||
(int)Tauros,
|
||||
(int)Rufflet,
|
||||
(int)Braviary,
|
||||
(int)Tyrogue,
|
||||
(int)Sawk,
|
||||
(int)Throh,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> PastGenAlolanScans = new()
|
||||
{
|
||||
(int)Bellsprout,
|
||||
(int)Rhyhorn,
|
||||
(int)Horsea,
|
||||
(int)Chikorita,
|
||||
(int)Cyndaquil,
|
||||
(int)Totodile,
|
||||
(int)Swinub,
|
||||
(int)Spheal,
|
||||
(int)Venipede,
|
||||
(int)Gothita,
|
||||
(int)Klink,
|
||||
(int)Litwick,
|
||||
(int)Axew,
|
||||
(int)Deino,
|
||||
(int)Honedge,
|
||||
(int)Marill, (int)Azurill,
|
||||
(int)Roselia, (int)Budew,
|
||||
(int)Togepi,
|
||||
(int)Slakoth,
|
||||
(int)Starly,
|
||||
(int)Shinx,
|
||||
(int)Snivy,
|
||||
(int)Solosis,
|
||||
(int)Tepig,
|
||||
(int)Oshawott,
|
||||
(int)Timburr,
|
||||
(int)Sewaddle,
|
||||
(int)Tynamo,
|
||||
(int)Charmander,
|
||||
(int)Squirtle,
|
||||
(int)Onix,
|
||||
(int)Talonflame,
|
||||
(int)Scatterbug,
|
||||
(int)Bulbasaur,
|
||||
(int)Ralts,
|
||||
(int)Weedle,
|
||||
(int)Torchic,
|
||||
(int)Treecko,
|
||||
(int)Mudkip,
|
||||
(int)Piplup,
|
||||
(int)Turtwig,
|
||||
(int)Pidgey,
|
||||
(int)Chimchar,
|
||||
(int)Aron,
|
||||
(int)Rotom,
|
||||
(int)Chespin,
|
||||
(int)Fennekin,
|
||||
(int)Froakie,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Inherit_Sport = new()
|
||||
{
|
||||
(int)Caterpie,
|
||||
(int)Weedle,
|
||||
(int)Paras,
|
||||
(int)Venonat,
|
||||
(int)Scyther,
|
||||
(int)Pinsir,
|
||||
(int)Wurmple,
|
||||
(int)Nincada,
|
||||
(int)Illumise,
|
||||
(int)Kricketot,
|
||||
(int)Combee,
|
||||
(int)Volbeat,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Inherit_Safari = new()
|
||||
{
|
||||
(int)Pidgey,
|
||||
(int)Rattata,
|
||||
(int)Spearow,
|
||||
(int)Ekans,
|
||||
(int)Sandshrew,
|
||||
(int)NidoranF,
|
||||
(int)Zubat,
|
||||
(int)Oddish,
|
||||
(int)Paras,
|
||||
(int)Venonat,
|
||||
(int)Diglett,
|
||||
(int)Psyduck,
|
||||
(int)Poliwag,
|
||||
(int)Abra,
|
||||
(int)Machop,
|
||||
(int)Bellsprout,
|
||||
(int)Geodude,
|
||||
(int)Ponyta,
|
||||
(int)Slowpoke,
|
||||
(int)Farfetchd,
|
||||
(int)Doduo,
|
||||
(int)Grimer,
|
||||
(int)Gastly,
|
||||
(int)Onix,
|
||||
(int)Drowzee,
|
||||
(int)Krabby,
|
||||
(int)Exeggcute,
|
||||
(int)Cubone,
|
||||
(int)Lickitung,
|
||||
(int)Koffing,
|
||||
(int)Rhyhorn,
|
||||
(int)Chansey,
|
||||
(int)Tangela,
|
||||
(int)Kangaskhan,
|
||||
(int)Goldeen,
|
||||
(int)MrMime,
|
||||
(int)Scyther,
|
||||
(int)Pinsir,
|
||||
(int)Magikarp,
|
||||
(int)Lapras,
|
||||
(int)Dratini,
|
||||
(int)Sentret,
|
||||
(int)Hoothoot,
|
||||
(int)Ledyba,
|
||||
(int)Spinarak,
|
||||
(int)Natu,
|
||||
(int)Mareep,
|
||||
(int)Marill,
|
||||
(int)Hoppip,
|
||||
(int)Jumpluff,
|
||||
(int)Aipom,
|
||||
(int)Sunkern,
|
||||
(int)Yanma,
|
||||
(int)Wooper,
|
||||
(int)Murkrow,
|
||||
(int)Misdreavus,
|
||||
(int)Wobbuffet,
|
||||
(int)Girafarig,
|
||||
(int)Pineco,
|
||||
(int)Gligar,
|
||||
(int)Snubbull,
|
||||
(int)Shuckle,
|
||||
(int)Heracross,
|
||||
(int)Teddiursa,
|
||||
(int)Remoraid,
|
||||
(int)Houndour,
|
||||
(int)Phanpy,
|
||||
(int)Stantler,
|
||||
(int)Smeargle,
|
||||
(int)Miltank,
|
||||
(int)Larvitar,
|
||||
(int)Zigzagoon,
|
||||
(int)Linoone,
|
||||
(int)Lotad,
|
||||
(int)Seedot,
|
||||
(int)Surskit,
|
||||
(int)Shroomish,
|
||||
(int)Slakoth,
|
||||
(int)Nosepass,
|
||||
(int)Aron,
|
||||
(int)Lairon,
|
||||
(int)Meditite,
|
||||
(int)Electrike,
|
||||
(int)Illumise,
|
||||
(int)Roselia,
|
||||
(int)Gulpin,
|
||||
(int)Carvanha,
|
||||
(int)Torkoal,
|
||||
(int)Spinda,
|
||||
(int)Trapinch,
|
||||
(int)Cacnea,
|
||||
(int)Zangoose,
|
||||
(int)Seviper,
|
||||
(int)Barboach,
|
||||
(int)Corphish,
|
||||
(int)Kecleon,
|
||||
(int)Shuppet,
|
||||
(int)Duskull,
|
||||
(int)Tropius,
|
||||
(int)Chimecho,
|
||||
(int)Spheal,
|
||||
(int)Bagon,
|
||||
(int)Starly,
|
||||
(int)Bidoof,
|
||||
(int)Shinx,
|
||||
(int)Budew,
|
||||
(int)Pachirisu,
|
||||
(int)Buizel,
|
||||
(int)Chingling,
|
||||
(int)Gible,
|
||||
(int)Riolu,
|
||||
(int)Hippopotas,
|
||||
(int)Skorupi,
|
||||
(int)Croagunk,
|
||||
(int)Carnivine,
|
||||
|
||||
// Splitbreed/Baby
|
||||
(int)NidoranM, // Via Nidoran-F
|
||||
(int)Volbeat, // Via Illumise
|
||||
(int)Pichu,
|
||||
(int)Cleffa,
|
||||
(int)Igglybuff,
|
||||
(int)Elekid,
|
||||
(int)Magby,
|
||||
(int)Azurill,
|
||||
(int)Wynaut,
|
||||
(int)Budew,
|
||||
(int)Chingling,
|
||||
(int)MimeJr,
|
||||
(int)Happiny,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Inherit_Dream = new()
|
||||
{
|
||||
(int)Caterpie,
|
||||
(int)Weedle,
|
||||
(int)Pidgey,
|
||||
(int)Rattata,
|
||||
(int)Spearow,
|
||||
(int)Ekans,
|
||||
(int)Sandshrew,
|
||||
(int)NidoranF,
|
||||
(int)Vulpix,
|
||||
(int)Zubat,
|
||||
(int)Oddish,
|
||||
(int)Paras,
|
||||
(int)Venonat,
|
||||
(int)Diglett,
|
||||
(int)Meowth,
|
||||
(int)Psyduck,
|
||||
(int)Mankey,
|
||||
(int)Growlithe,
|
||||
(int)Poliwag,
|
||||
(int)Abra,
|
||||
(int)Machop,
|
||||
(int)Bellsprout,
|
||||
(int)Tentacool,
|
||||
(int)Geodude,
|
||||
(int)Ponyta,
|
||||
(int)Slowpoke,
|
||||
(int)Farfetchd,
|
||||
(int)Doduo,
|
||||
(int)Seel,
|
||||
(int)Grimer,
|
||||
(int)Shellder,
|
||||
(int)Gastly,
|
||||
(int)Onix,
|
||||
(int)Drowzee,
|
||||
(int)Krabby,
|
||||
(int)Exeggcute,
|
||||
(int)Cubone,
|
||||
(int)Lickitung,
|
||||
(int)Koffing,
|
||||
(int)Rhyhorn,
|
||||
(int)Chansey,
|
||||
(int)Tangela,
|
||||
(int)Kangaskhan,
|
||||
(int)Horsea,
|
||||
(int)Goldeen,
|
||||
(int)MrMime,
|
||||
(int)Scyther,
|
||||
(int)Pinsir,
|
||||
(int)Magikarp,
|
||||
(int)Lapras,
|
||||
(int)Eevee,
|
||||
(int)Omanyte,
|
||||
(int)Kabuto,
|
||||
(int)Aerodactyl,
|
||||
(int)Snorlax,
|
||||
(int)Dratini,
|
||||
(int)Sentret,
|
||||
(int)Hoothoot,
|
||||
(int)Ledyba,
|
||||
(int)Spinarak,
|
||||
(int)Chinchou,
|
||||
(int)Cleffa,
|
||||
(int)Igglybuff,
|
||||
(int)Togepi,
|
||||
(int)Natu,
|
||||
(int)Mareep,
|
||||
(int)Marill,
|
||||
(int)Sudowoodo,
|
||||
(int)Hoppip,
|
||||
(int)Aipom,
|
||||
(int)Sunkern,
|
||||
(int)Yanma,
|
||||
(int)Wooper,
|
||||
(int)Murkrow,
|
||||
(int)Misdreavus,
|
||||
(int)Wobbuffet,
|
||||
(int)Girafarig,
|
||||
(int)Pineco,
|
||||
(int)Dunsparce,
|
||||
(int)Gligar,
|
||||
(int)Snubbull,
|
||||
(int)Qwilfish,
|
||||
(int)Shuckle,
|
||||
(int)Heracross,
|
||||
(int)Sneasel,
|
||||
(int)Teddiursa,
|
||||
(int)Slugma,
|
||||
(int)Swinub,
|
||||
(int)Corsola,
|
||||
(int)Remoraid,
|
||||
(int)Delibird,
|
||||
(int)Mantine,
|
||||
(int)Skarmory,
|
||||
(int)Houndour,
|
||||
(int)Phanpy,
|
||||
(int)Stantler,
|
||||
(int)Smeargle,
|
||||
(int)Smoochum,
|
||||
(int)Elekid,
|
||||
(int)Magby,
|
||||
(int)Miltank,
|
||||
(int)Larvitar,
|
||||
(int)Poochyena,
|
||||
(int)Zigzagoon,
|
||||
(int)Wurmple,
|
||||
(int)Lotad,
|
||||
(int)Seedot,
|
||||
(int)Taillow,
|
||||
(int)Wingull,
|
||||
(int)Ralts,
|
||||
(int)Surskit,
|
||||
(int)Shroomish,
|
||||
(int)Slakoth,
|
||||
(int)Nincada,
|
||||
(int)Whismur,
|
||||
(int)Makuhita,
|
||||
(int)Nosepass,
|
||||
(int)Skitty,
|
||||
(int)Sableye,
|
||||
(int)Mawile,
|
||||
(int)Aron,
|
||||
(int)Meditite,
|
||||
(int)Electrike,
|
||||
(int)Plusle,
|
||||
(int)Minun,
|
||||
(int)Illumise,
|
||||
(int)Roselia,
|
||||
(int)Gulpin,
|
||||
(int)Carvanha,
|
||||
(int)Wailmer,
|
||||
(int)Numel,
|
||||
(int)Torkoal,
|
||||
(int)Spoink,
|
||||
(int)Spinda,
|
||||
(int)Trapinch,
|
||||
(int)Cacnea,
|
||||
(int)Swablu,
|
||||
(int)Zangoose,
|
||||
(int)Seviper,
|
||||
(int)Barboach,
|
||||
(int)Corphish,
|
||||
(int)Lileep,
|
||||
(int)Anorith,
|
||||
(int)Feebas,
|
||||
(int)Castform,
|
||||
(int)Kecleon,
|
||||
(int)Shuppet,
|
||||
(int)Duskull,
|
||||
(int)Tropius,
|
||||
(int)Chimecho,
|
||||
(int)Absol,
|
||||
(int)Snorunt,
|
||||
(int)Spheal,
|
||||
(int)Clamperl,
|
||||
(int)Relicanth,
|
||||
(int)Luvdisc,
|
||||
(int)Bagon,
|
||||
(int)Starly,
|
||||
(int)Bidoof,
|
||||
(int)Kricketot,
|
||||
(int)Shinx,
|
||||
(int)Cranidos,
|
||||
(int)Shieldon,
|
||||
(int)Burmy,
|
||||
(int)Combee,
|
||||
(int)Pachirisu,
|
||||
(int)Buizel,
|
||||
(int)Cherubi,
|
||||
(int)Shellos,
|
||||
(int)Drifloon,
|
||||
(int)Buneary,
|
||||
(int)Glameow,
|
||||
(int)Stunky,
|
||||
(int)Chatot,
|
||||
(int)Spiritomb,
|
||||
(int)Gible,
|
||||
(int)Riolu,
|
||||
(int)Hippopotas,
|
||||
(int)Skorupi,
|
||||
(int)Croagunk,
|
||||
(int)Carnivine,
|
||||
(int)Finneon,
|
||||
(int)Snover,
|
||||
(int)Munna,
|
||||
(int)Pidove,
|
||||
(int)Boldore,
|
||||
(int)Drilbur,
|
||||
(int)Audino,
|
||||
(int)Gurdurr,
|
||||
(int)Tympole,
|
||||
(int)Scolipede,
|
||||
(int)Cottonee,
|
||||
(int)Petilil,
|
||||
(int)Basculin,
|
||||
(int)Krookodile,
|
||||
(int)Maractus,
|
||||
(int)Crustle,
|
||||
(int)Scraggy,
|
||||
(int)Sigilyph,
|
||||
(int)Tirtouga,
|
||||
(int)Duosion,
|
||||
(int)Ducklett,
|
||||
(int)Vanillish,
|
||||
(int)Emolga,
|
||||
(int)Karrablast,
|
||||
(int)Alomomola,
|
||||
(int)Galvantula,
|
||||
(int)Elgyem,
|
||||
(int)Axew,
|
||||
(int)Shelmet,
|
||||
(int)Stunfisk,
|
||||
(int)Druddigon,
|
||||
(int)Pawniard,
|
||||
(int)Heatmor,
|
||||
(int)Durant,
|
||||
(int)NidoranM, // Via Nidoran-F
|
||||
(int)Volbeat, // Via Illumise
|
||||
|
||||
// Via Evolution
|
||||
(int)Roggenrola,
|
||||
(int)Timburr,
|
||||
(int)Venipede,
|
||||
(int)Sandile,
|
||||
(int)Dwebble,
|
||||
(int)Solosis,
|
||||
(int)Vanillite,
|
||||
(int)Joltik,
|
||||
|
||||
// Via Incense Breeding
|
||||
(int)Azurill,
|
||||
(int)Wynaut,
|
||||
(int)Budew,
|
||||
(int)Chingling,
|
||||
(int)Bonsly,
|
||||
(int)MimeJr,
|
||||
(int)Happiny,
|
||||
(int)Munchlax,
|
||||
(int)Mantyke,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_DreamHidden = new()
|
||||
{
|
||||
(int)Plusle,
|
||||
(int)Minun,
|
||||
(int)Kecleon,
|
||||
(int)Duskull,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_Gen3Ball = new()
|
||||
{
|
||||
(int)Treecko, (int)Torchic, (int)Mudkip,
|
||||
(int)Turtwig, (int)Chimchar, (int)Piplup,
|
||||
(int)Snivy, (int)Tepig, (int)Oshawott,
|
||||
|
||||
// Fossil Only obtain
|
||||
(int)Archen, (int)Tyrunt, (int)Amaura,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_Gen3BallHidden = new()
|
||||
{
|
||||
// can have HA and can be in gen 3 ball as eggs but can not at same time.
|
||||
(int)Chikorita, (int)Cyndaquil, (int)Totodile,
|
||||
(int)Deerling + (1 << 11), //Deerling-Summer
|
||||
(int)Deerling + (2 << 11), //Deerling-Autumn
|
||||
(int)Deerling + (3 << 11), //Deerling-Winter
|
||||
(int)Pumpkaboo + (3 << 11), //Pumpkaboo-Super
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_Gen4Ball_6 = new()
|
||||
{
|
||||
(int)Chikorita, (int)Cyndaquil, (int)Totodile,
|
||||
(int)Treecko, (int)Torchic, (int)Mudkip,
|
||||
(int)Turtwig, (int)Chimchar, (int)Piplup,
|
||||
(int)Snivy, (int)Tepig, (int)Oshawott,
|
||||
|
||||
// Fossil Only obtain
|
||||
(int)Archen, (int)Tyrunt, (int)Amaura,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Inherit_Apricorn6 = new()
|
||||
{
|
||||
(int)Caterpie,
|
||||
(int)Weedle,
|
||||
(int)Pidgey,
|
||||
(int)Rattata,
|
||||
(int)Spearow,
|
||||
(int)Ekans,
|
||||
(int)Sandshrew,
|
||||
(int)NidoranF,
|
||||
(int)Vulpix,
|
||||
(int)Zubat,
|
||||
(int)Oddish,
|
||||
(int)Paras,
|
||||
(int)Venonat,
|
||||
(int)Diglett,
|
||||
(int)Meowth,
|
||||
(int)Psyduck,
|
||||
(int)Mankey,
|
||||
(int)Growlithe,
|
||||
(int)Poliwag,
|
||||
(int)Abra,
|
||||
(int)Machop,
|
||||
(int)Bellsprout,
|
||||
(int)Tentacool,
|
||||
(int)Geodude,
|
||||
(int)Ponyta,
|
||||
(int)Slowpoke,
|
||||
(int)Farfetchd,
|
||||
(int)Doduo,
|
||||
(int)Seel,
|
||||
(int)Grimer,
|
||||
(int)Shellder,
|
||||
(int)Gastly,
|
||||
(int)Onix,
|
||||
(int)Drowzee,
|
||||
(int)Krabby,
|
||||
(int)Exeggcute,
|
||||
(int)Cubone,
|
||||
(int)Lickitung,
|
||||
(int)Koffing,
|
||||
(int)Rhyhorn,
|
||||
(int)Chansey,
|
||||
(int)Tangela,
|
||||
(int)Kangaskhan,
|
||||
(int)Horsea,
|
||||
(int)Goldeen,
|
||||
(int)MrMime,
|
||||
(int)Magikarp,
|
||||
(int)Lapras,
|
||||
(int)Snorlax,
|
||||
(int)Dratini,
|
||||
(int)Sentret,
|
||||
(int)Hoothoot,
|
||||
(int)Ledyba,
|
||||
(int)Spinarak,
|
||||
(int)Chinchou,
|
||||
(int)Natu,
|
||||
(int)Mareep,
|
||||
(int)Marill,
|
||||
(int)Sudowoodo,
|
||||
(int)Hoppip,
|
||||
(int)Aipom,
|
||||
(int)Sunkern,
|
||||
(int)Yanma,
|
||||
(int)Wooper,
|
||||
(int)Murkrow,
|
||||
(int)Misdreavus,
|
||||
(int)Wobbuffet,
|
||||
(int)Girafarig,
|
||||
(int)Pineco,
|
||||
(int)Dunsparce,
|
||||
(int)Gligar,
|
||||
(int)Snubbull,
|
||||
(int)Qwilfish,
|
||||
(int)Shuckle,
|
||||
(int)Heracross,
|
||||
(int)Sneasel,
|
||||
(int)Teddiursa,
|
||||
(int)Slugma,
|
||||
(int)Swinub,
|
||||
(int)Corsola,
|
||||
(int)Remoraid,
|
||||
(int)Delibird,
|
||||
(int)Mantine,
|
||||
(int)Skarmory,
|
||||
(int)Houndour,
|
||||
(int)Phanpy,
|
||||
(int)Stantler,
|
||||
(int)Smeargle,
|
||||
(int)Miltank,
|
||||
(int)Larvitar,
|
||||
(int)Poochyena,
|
||||
(int)Zigzagoon,
|
||||
(int)Wurmple,
|
||||
(int)Seedot,
|
||||
(int)Taillow,
|
||||
(int)Wingull,
|
||||
(int)Ralts,
|
||||
(int)Shroomish,
|
||||
(int)Slakoth,
|
||||
(int)Whismur,
|
||||
(int)Makuhita,
|
||||
(int)Sableye,
|
||||
(int)Mawile,
|
||||
(int)Meditite,
|
||||
(int)Plusle,
|
||||
(int)Minun,
|
||||
(int)Gulpin,
|
||||
(int)Numel,
|
||||
(int)Spoink,
|
||||
(int)Spinda,
|
||||
(int)Swablu,
|
||||
(int)Barboach,
|
||||
(int)Absol,
|
||||
(int)Clamperl,
|
||||
(int)Relicanth,
|
||||
(int)Luvdisc,
|
||||
(int)Starly,
|
||||
(int)Bidoof,
|
||||
(int)Kricketot,
|
||||
(int)Shinx,
|
||||
(int)Budew,
|
||||
(int)Burmy,
|
||||
(int)Combee,
|
||||
(int)Buizel,
|
||||
(int)Cherubi,
|
||||
(int)Buneary,
|
||||
(int)Chingling,
|
||||
(int)Chatot,
|
||||
(int)Carnivine,
|
||||
(int)NidoranM, // Via Nidoran-F
|
||||
(int)Happiny, // Via Chansey
|
||||
(int)Smoochum, // Via Jynx
|
||||
(int)Elekid, // Via Electabuzz
|
||||
(int)Magby, // Via Magmar
|
||||
(int)Azurill, // Via Marill
|
||||
(int)Wynaut, // Via Wobbuffet
|
||||
(int)Bonsly, // Via Sudowoodo
|
||||
(int)MimeJr, // Via Mr. Mime
|
||||
(int)Munchlax, // Via Snorlax
|
||||
(int)Mantyke, // Via Mantine
|
||||
(int)Chimecho, // Via Chingling
|
||||
(int)Pichu, // Via Pikachu
|
||||
(int)Cleffa, // Via Clefairy
|
||||
(int)Igglybuff, // Via Jigglypuff
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> AlolanCaptureOffspring = new()
|
||||
{
|
||||
(int)Caterpie,
|
||||
(int)Rattata,
|
||||
(int)Spearow,
|
||||
(int)Sandshrew,
|
||||
(int)Vulpix,
|
||||
(int)Jigglypuff,
|
||||
(int)Zubat,
|
||||
(int)Paras,
|
||||
(int)Diglett,
|
||||
(int)Meowth,
|
||||
(int)Psyduck,
|
||||
(int)Mankey,
|
||||
(int)Growlithe,
|
||||
(int)Poliwag,
|
||||
(int)Abra,
|
||||
(int)Machop,
|
||||
(int)Tentacool,
|
||||
(int)Geodude,
|
||||
(int)Slowpoke,
|
||||
(int)Magnemite,
|
||||
(int)Grimer,
|
||||
(int)Shellder,
|
||||
(int)Gastly,
|
||||
(int)Drowzee,
|
||||
(int)Exeggcute,
|
||||
(int)Cubone,
|
||||
(int)Chansey,
|
||||
(int)Kangaskhan,
|
||||
(int)Goldeen,
|
||||
(int)Staryu,
|
||||
(int)Scyther,
|
||||
(int)Pinsir,
|
||||
(int)Tauros,
|
||||
(int)Magikarp,
|
||||
(int)Lapras,
|
||||
(int)Ditto,
|
||||
(int)Eevee,
|
||||
(int)Snorlax,
|
||||
(int)Dratini,
|
||||
(int)Ledyba,
|
||||
(int)Spinarak,
|
||||
(int)Chinchou,
|
||||
(int)Pichu,
|
||||
(int)Cleffa,
|
||||
(int)Igglybuff,
|
||||
(int)Sudowoodo,
|
||||
(int)Murkrow,
|
||||
(int)Misdreavus,
|
||||
(int)Snubbull,
|
||||
(int)Scizor,
|
||||
(int)Sneasel,
|
||||
(int)Corsola,
|
||||
(int)Delibird,
|
||||
(int)Skarmory,
|
||||
(int)Smeargle,
|
||||
(int)Elekid,
|
||||
(int)Magby,
|
||||
(int)Miltank,
|
||||
(int)Wingull,
|
||||
(int)Surskit,
|
||||
(int)Makuhita,
|
||||
(int)Nosepass,
|
||||
(int)Sableye,
|
||||
(int)Carvanha,
|
||||
(int)Wailmer,
|
||||
(int)Torkoal,
|
||||
(int)Spinda,
|
||||
(int)Trapinch,
|
||||
(int)Barboach,
|
||||
(int)Feebas,
|
||||
(int)Castform,
|
||||
(int)Absol,
|
||||
(int)Snorunt,
|
||||
(int)Relicanth,
|
||||
(int)Luvdisc,
|
||||
(int)Bagon,
|
||||
(int)Beldum,
|
||||
(int)Shellos,
|
||||
(int)Drifloon,
|
||||
(int)Bonsly,
|
||||
(int)Happiny,
|
||||
(int)Gible,
|
||||
(int)Munchlax,
|
||||
(int)Riolu,
|
||||
(int)Finneon,
|
||||
(int)Lillipup,
|
||||
(int)Roggenrola,
|
||||
(int)Cottonee,
|
||||
(int)Petilil,
|
||||
(int)Sandile,
|
||||
(int)Trubbish,
|
||||
(int)Vanillite,
|
||||
(int)Emolga,
|
||||
(int)Alomomola,
|
||||
(int)Rufflet,
|
||||
(int)Vullaby,
|
||||
(int)Fletchling,
|
||||
(int)Pancham,
|
||||
(int)Carbink,
|
||||
(int)Goomy,
|
||||
(int)Klefki,
|
||||
(int)Phantump,
|
||||
(int)Pikipek,
|
||||
(int)Yungoos,
|
||||
(int)Grubbin,
|
||||
(int)Crabrawler,
|
||||
(int)Oricorio,
|
||||
(int)Cutiefly,
|
||||
(int)Rockruff,
|
||||
(int)Wishiwashi,
|
||||
(int)Mareanie,
|
||||
(int)Mudbray,
|
||||
(int)Dewpider,
|
||||
(int)Fomantis,
|
||||
(int)Morelull,
|
||||
(int)Salandit,
|
||||
(int)Stufful,
|
||||
(int)Bounsweet,
|
||||
(int)Comfey,
|
||||
(int)Oranguru,
|
||||
(int)Passimian,
|
||||
(int)Wimpod,
|
||||
(int)Sandygast,
|
||||
(int)Pyukumuku,
|
||||
(int)Minior,
|
||||
(int)Komala,
|
||||
(int)Turtonator,
|
||||
(int)Togedemaru,
|
||||
(int)Mimikyu,
|
||||
(int)Bruxish,
|
||||
(int)Drampa,
|
||||
(int)Dhelmise,
|
||||
(int)Jangmoo,
|
||||
|
||||
// USUM Additions
|
||||
(int)Ekans,
|
||||
(int)Seel,
|
||||
(int)Lickitung,
|
||||
(int)MrMime,
|
||||
(int)Hoothoot,
|
||||
(int)Natu,
|
||||
(int)Mareep,
|
||||
(int)Aipom,
|
||||
(int)Pineco,
|
||||
(int)Dunsparce,
|
||||
(int)Heracross,
|
||||
(int)Remoraid,
|
||||
(int)Mantine,
|
||||
(int)Houndour,
|
||||
(int)Smoochum,
|
||||
(int)Larvitar,
|
||||
(int)Mawile,
|
||||
(int)Electrike,
|
||||
(int)Corphish,
|
||||
(int)Baltoy,
|
||||
(int)Kecleon,
|
||||
(int)Shuppet,
|
||||
(int)Tropius,
|
||||
(int)Clamperl,
|
||||
(int)Buneary,
|
||||
(int)MimeJr,
|
||||
(int)Mantyke,
|
||||
(int)Basculin,
|
||||
(int)Scraggy,
|
||||
(int)Zorua,
|
||||
(int)Minccino,
|
||||
(int)Frillish,
|
||||
(int)Elgyem,
|
||||
(int)Mienfoo,
|
||||
(int)Druddigon,
|
||||
(int)Golett,
|
||||
(int)Pawniard,
|
||||
(int)Larvesta,
|
||||
(int)Litleo,
|
||||
(int)Flabébé,
|
||||
(int)Furfrou,
|
||||
(int)Inkay,
|
||||
(int)Skrelp,
|
||||
(int)Clauncher,
|
||||
(int)Hawlucha,
|
||||
(int)Dedenne,
|
||||
(int)Noibat,
|
||||
|
||||
// Wormhole
|
||||
(int)Swablu,
|
||||
(int)Yanma,
|
||||
(int)Sigilyph,
|
||||
(int)Ducklett,
|
||||
(int)Taillow,
|
||||
(int)Skorupi,
|
||||
(int)Audino,
|
||||
(int)Helioptile,
|
||||
(int)Seedot,
|
||||
(int)Spoink,
|
||||
(int)Snover,
|
||||
(int)Meditite,
|
||||
(int)Hippopotas,
|
||||
(int)Dwebble,
|
||||
(int)Slugma,
|
||||
(int)Binacle,
|
||||
(int)Lotad,
|
||||
(int)Stunfisk,
|
||||
(int)Buizel,
|
||||
(int)Wooper,
|
||||
|
||||
// Static Encounters
|
||||
(int)Voltorb,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_NoHidden7Apricorn = new()
|
||||
{
|
||||
(int)NidoranF,
|
||||
(int)NidoranM,
|
||||
(int)Voltorb,
|
||||
(int)Bronzor,
|
||||
(int)Flabébé + (3 << 11), // Flabébé-Blue
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> AlolanCaptureNoHeavyBall = new() { (int)Beldum, (int)TapuKoko, (int)TapuLele, (int)TapuBulu, (int)TapuFini };
|
||||
|
||||
private static readonly HashSet<ushort> Inherit_ApricornMale7 = new()
|
||||
{
|
||||
(int)Voltorb,
|
||||
(int)Baltoy,
|
||||
(int)Bronzor,
|
||||
|
||||
// Others are capturable in the Alola region
|
||||
// Magnemite, Staryu, Tauros
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Inherit_Apricorn7 = new(Inherit_Apricorn6.Concat(Inherit_ApricornMale7).Concat(PastGenAlolanScans).Concat(AlolanCaptureOffspring).Distinct());
|
||||
|
||||
internal static readonly HashSet<ushort> Inherit_SafariMale = new()
|
||||
{
|
||||
(int)Tauros,
|
||||
|
||||
(int)Magnemite,
|
||||
(int)Voltorb,
|
||||
(int)Lunatone,
|
||||
(int)Solrock,
|
||||
(int)Beldum,
|
||||
(int)Bronzor,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Inherit_DreamMale = new()
|
||||
{
|
||||
// Starting with Gen7, Males pass Ball via breeding with Ditto.
|
||||
(int)Bulbasaur, (int)Charmander, (int)Squirtle,
|
||||
(int)Tauros,
|
||||
(int)Pichu,
|
||||
(int)Tyrogue,
|
||||
(int)Treecko,
|
||||
(int)Torchic, (int)Mudkip, (int)Turtwig,
|
||||
(int)Chimchar, (int)Piplup, (int)Pansage,
|
||||
(int)Pansear, (int)Panpour,
|
||||
(int)Throh, (int)Sawk,
|
||||
(int)Gothita,
|
||||
|
||||
(int)Magnemite,
|
||||
(int)Voltorb,
|
||||
(int)Staryu,
|
||||
(int)Porygon,
|
||||
(int)Lunatone,
|
||||
(int)Solrock,
|
||||
(int)Baltoy,
|
||||
(int)Beldum,
|
||||
(int)Bronzor,
|
||||
(int)Rotom,
|
||||
(int)Klink,
|
||||
(int)Golett,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_Gen3Ball_7 = new()
|
||||
{
|
||||
(int)Phione,
|
||||
(int)Archen,
|
||||
(int)Tyrunt,
|
||||
(int)Amaura,
|
||||
};
|
||||
|
||||
// Same as Gen3 Balls
|
||||
internal static readonly HashSet<ushort> Ban_Gen4Ball_7 = Ban_Gen3Ball_7;
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_SafariBallHidden_7 = new()
|
||||
{
|
||||
(int)NidoranF,
|
||||
(int)NidoranM,
|
||||
(int)Volbeat, (int)Illumise,
|
||||
(int)Magnemite,
|
||||
(int)Voltorb,
|
||||
(int)Kangaskhan,
|
||||
(int)Tauros,
|
||||
(int)Ditto,
|
||||
(int)Miltank,
|
||||
(int)Beldum,
|
||||
(int)Bronzor,
|
||||
(int)Happiny,
|
||||
(int)Tyrogue,
|
||||
(int)Staryu,
|
||||
(int)Lunatone,
|
||||
(int)Solrock,
|
||||
(int)Rotom,
|
||||
(int)Klink,
|
||||
(int)Golett,
|
||||
};
|
||||
|
||||
internal static readonly HashSet<ushort> Ban_NoHidden8Apricorn = new()
|
||||
{
|
||||
// Nidoran, Bronzor -- Used to not be encounterable in Gen7 with HA; Gen8 now can via Raids
|
||||
(int)Voltorb, // Voltorb
|
||||
(int)Flabébé + (3 << 11), // Flabébé-Blue
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Gets a legal <see cref="Ball"/> value for a bred egg encounter.
|
||||
/// </summary>
|
||||
/// <param name="version">Version the egg was created on.</param>
|
||||
/// <param name="species">Species the egg contained.</param>
|
||||
/// <returns>Valid ball to hatch with.</returns>
|
||||
/// <remarks>Not all things can hatch with a Poké Ball!</remarks>
|
||||
#pragma warning disable RCS1163, IDE0060 // Unused parameter.
|
||||
public static Ball GetDefaultBall(GameVersion version, ushort species)
|
||||
{
|
||||
if (version.GetGeneration() <= 5)
|
||||
return Ball.Poke;
|
||||
return Ball.None;
|
||||
}
|
||||
}
|
192
PKHeX.Core/Legality/Verifiers/Ball/BallContext6.cs
Normal file
192
PKHeX.Core/Legality/Verifiers/Ball/BallContext6.cs
Normal file
|
@ -0,0 +1,192 @@
|
|||
using System;
|
||||
using static PKHeX.Core.Ball;
|
||||
using static PKHeX.Core.Species;
|
||||
using static PKHeX.Core.BallInheritanceResult;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Ball Inheritance Permissions for <see cref="EntityContext.Gen6"/> games.
|
||||
/// </summary>
|
||||
public sealed class BallContext6 : IBallContext
|
||||
{
|
||||
public static readonly BallContext6 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, form),
|
||||
BallType.Gen4 => IsNotHidden(pk.AbilityNumber) || !IsBannedHiddenGen4(species),
|
||||
BallType.Safari => IsNotHidden(pk.AbilityNumber),
|
||||
BallType.Apricorn => IsNotHidden(pk.AbilityNumber),
|
||||
BallType.Sport => IsNotHidden(pk.AbilityNumber),
|
||||
BallType.Dream => IsNotHidden(pk.AbilityNumber) || !IsBannedHiddenDream(species),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
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, byte form) => species switch
|
||||
{
|
||||
// can have HA and can be in gen 3 ball as eggs but can not at same time.
|
||||
(int)Chikorita => true,
|
||||
(int)Cyndaquil => true,
|
||||
(int)Totodile => true,
|
||||
(int)Deerling => form != 0, // not Deerling-Spring
|
||||
(int)Pumpkaboo => form == 3, //Pumpkaboo-Super
|
||||
_ => false,
|
||||
};
|
||||
|
||||
private static bool IsBannedHiddenDream(ushort species) => species switch
|
||||
{
|
||||
(int)Plusle => true,
|
||||
(int)Minun => true,
|
||||
(int)Kecleon => true,
|
||||
(int)Duskull => 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,
|
||||
_ => BallType.None,
|
||||
};
|
||||
|
||||
public static ReadOnlySpan<byte> Permit => new byte[]
|
||||
{
|
||||
0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x3B, 0x03, 0x03, 0x3B, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x2F, // 000 - 019
|
||||
0x03, 0x2F, 0x03, 0x2F, 0x03, 0x03, 0x03, 0x2F, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x03, 0x03, 0x2B, 0x03, 0x03, // 020 - 039
|
||||
0x03, 0x2F, 0x03, 0x2F, 0x03, 0x03, 0x3F, 0x03, 0x3F, 0x03, 0x2F, 0x03, 0x2B, 0x03, 0x2F, 0x03, 0x2B, 0x03, 0x2B, 0x03, // 040 - 059
|
||||
0x2F, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x2B, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x03, 0x2F, // 060 - 079
|
||||
0x03, 0x00, 0x00, 0x2F, 0x2F, 0x03, 0x2B, 0x03, 0x2F, 0x03, 0x2B, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x2F, 0x03, 0x2F, 0x03, // 080 - 099
|
||||
0x00, 0x00, 0x2F, 0x03, 0x2F, 0x03, 0x03, 0x03, 0x2F, 0x2F, 0x03, 0x2F, 0x03, 0x2F, 0x2F, 0x2F, 0x2B, 0x03, 0x2F, 0x03, // 100 - 119
|
||||
0x00, 0x00, 0x2F, 0x37, 0x03, 0x03, 0x03, 0x37, 0x00, 0x2F, 0x03, 0x2F, 0x00, 0x23, 0x03, 0x03, 0x03, 0x00, 0x23, 0x03, // 120 - 139
|
||||
0x23, 0x03, 0x23, 0x2B, 0x00, 0x00, 0x00, 0x2F, 0x03, 0x03, 0x00, 0x00, 0x81, 0x03, 0x03, 0x81, 0x03, 0x03, 0x81, 0x03, // 140 - 159
|
||||
0x03, 0x2F, 0x03, 0x2F, 0x03, 0x2F, 0x03, 0x2F, 0x03, 0x03, 0x2B, 0x03, 0x0F, 0x2F, 0x2F, 0x23, 0x03, 0x2F, 0x03, 0x2F, // 160 - 179
|
||||
0x03, 0x03, 0x03, 0x2F, 0x03, 0x2B, 0x03, 0x2F, 0x03, 0x07, 0x2F, 0x2F, 0x03, 0x2F, 0x2F, 0x03, 0x03, 0x03, 0x2F, 0x03, // 180 - 199
|
||||
0x2F, 0x00, 0x2F, 0x2F, 0x2F, 0x03, 0x2B, 0x2F, 0x03, 0x2F, 0x03, 0x2B, 0x03, 0x2F, 0x2F, 0x2B, 0x2F, 0x03, 0x2B, 0x03, // 200 - 219
|
||||
0x2B, 0x03, 0x2B, 0x2F, 0x03, 0x2B, 0x2B, 0x2B, 0x2F, 0x03, 0x03, 0x2F, 0x03, 0x00, 0x2F, 0x2F, 0x00, 0x03, 0x2B, 0x2F, // 220 - 239
|
||||
0x2F, 0x2F, 0x03, 0x00, 0x00, 0x00, 0x2F, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x03, // 240 - 259
|
||||
0x03, 0x2B, 0x03, 0x2F, 0x07, 0x3B, 0x03, 0x03, 0x03, 0x03, 0x27, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x2B, 0x03, 0x2B, 0x03, // 260 - 279
|
||||
0x2B, 0x03, 0x03, 0x27, 0x03, 0x2F, 0x03, 0x2F, 0x03, 0x03, 0x33, 0x03, 0x00, 0x2B, 0x03, 0x03, 0x2B, 0x03, 0x2F, 0x27, // 280 - 299
|
||||
0x23, 0x03, 0x2B, 0x2B, 0x27, 0x07, 0x03, 0x2F, 0x03, 0x27, 0x03, 0x2B, 0x2B, 0x37, 0x37, 0x27, 0x2F, 0x03, 0x27, 0x03, // 300 - 319
|
||||
0x23, 0x03, 0x2B, 0x03, 0x27, 0x2B, 0x03, 0x2F, 0x27, 0x03, 0x03, 0x27, 0x03, 0x2B, 0x03, 0x27, 0x27, 0x00, 0x00, 0x2F, // 320 - 339
|
||||
0x03, 0x27, 0x03, 0x00, 0x00, 0x23, 0x03, 0x23, 0x03, 0x23, 0x03, 0x23, 0x27, 0x27, 0x03, 0x27, 0x03, 0x27, 0x2F, 0x2B, // 340 - 359
|
||||
0x2F, 0x23, 0x03, 0x27, 0x03, 0x03, 0x2B, 0x03, 0x03, 0x2B, 0x2B, 0x27, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 360 - 379
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x00, 0x03, 0x03, 0x2F, 0x03, 0x03, 0x2F, // 380 - 399
|
||||
0x03, 0x3B, 0x03, 0x2F, 0x03, 0x03, 0x2F, 0x03, 0x23, 0x03, 0x23, 0x03, 0x2B, 0x03, 0x03, 0x3B, 0x03, 0x27, 0x2F, 0x03, // 400 - 419
|
||||
0x2B, 0x03, 0x23, 0x03, 0x03, 0x23, 0x03, 0x2B, 0x03, 0x03, 0x03, 0x23, 0x03, 0x2F, 0x23, 0x03, 0x00, 0x00, 0x2B, 0x2F, // 420 - 439
|
||||
0x2F, 0x2B, 0x23, 0x27, 0x03, 0x03, 0x2B, 0x27, 0x03, 0x27, 0x03, 0x27, 0x03, 0x27, 0x03, 0x2F, 0x23, 0x03, 0x2B, 0x23, // 440 - 459
|
||||
0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x00, // 460 - 479
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x03, // 480 - 499
|
||||
0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x23, // 500 - 519
|
||||
0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x23, 0x23, 0x03, 0x03, 0x23, 0x03, 0x03, 0x00, 0x00, // 520 - 539
|
||||
0x03, 0x03, 0x03, 0x23, 0x03, 0x03, 0x23, 0x03, 0x23, 0x03, 0x23, 0x23, 0x03, 0x03, 0x03, 0x03, 0x23, 0x23, 0x03, 0x23, // 540 - 559
|
||||
0x03, 0x23, 0x03, 0x03, 0x23, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, // 560 - 579
|
||||
0x23, 0x03, 0x23, 0x03, 0x03, 0x83, 0x03, 0x23, 0x23, 0x03, 0x03, 0x03, 0x03, 0x03, 0x23, 0x23, 0x03, 0x03, 0x03, 0x00, // 580 - 599
|
||||
0x00, 0x00, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, 0x03, 0x03, 0x23, 0x03, 0x03, 0x03, 0x03, 0x00, 0x23, 0x03, 0x23, 0x03, // 600 - 619
|
||||
0x03, 0x23, 0x00, 0x00, 0x23, 0x03, 0x03, 0x00, 0x00, 0x03, 0x03, 0x23, 0x23, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, // 620 - 639
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 640 - 659
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, // 660 - 679
|
||||
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x03, 0x00, 0x03, // 680 - 699
|
||||
0x03, 0x03, 0x03, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x83, 0x03, 0x03, 0x03, 0x03, 0x03,
|
||||
};
|
||||
|
||||
private enum BallType : byte
|
||||
{
|
||||
Gen3 = 0,
|
||||
Gen4 = 1,
|
||||
Safari = 2,
|
||||
Apricorn = 3,
|
||||
Sport = 4,
|
||||
Dream = 5,
|
||||
|
||||
None = 9,
|
||||
}
|
||||
}
|
228
PKHeX.Core/Legality/Verifiers/Ball/BallContext7.cs
Normal file
228
PKHeX.Core/Legality/Verifiers/Ball/BallContext7.cs
Normal file
|
@ -0,0 +1,228 @@
|
|||
using System;
|
||||
using static PKHeX.Core.Ball;
|
||||
using static PKHeX.Core.Species;
|
||||
using static PKHeX.Core.BallInheritanceResult;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Ball Inheritance Permissions for <see cref="EntityContext.Gen7"/> games.
|
||||
/// </summary>
|
||||
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<byte> Permit => new byte[]
|
||||
{
|
||||
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,
|
||||
}
|
||||
}
|
158
PKHeX.Core/Legality/Verifiers/Ball/BallContextHOME.cs
Normal file
158
PKHeX.Core/Legality/Verifiers/Ball/BallContextHOME.cs
Normal file
|
@ -0,0 +1,158 @@
|
|||
using System;
|
||||
using static PKHeX.Core.Ball;
|
||||
using static PKHeX.Core.BallInheritanceResult;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Ball Inheritance Permissions for games interconnected to HOME.
|
||||
/// </summary>
|
||||
public sealed class BallContextHOME : IBallContext
|
||||
{
|
||||
public static readonly BallContextHOME 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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a past ball inheritance context's restriction for Hidden Ability exclusions can be ignored.
|
||||
/// </summary>
|
||||
/// <param name="format">Current Entity format</param>
|
||||
/// <param name="species">Original encounter species</param>
|
||||
/// <returns>True if the restriction can be ignored, false if not.</returns>
|
||||
/// <remarks>Ability Patch can be used on any species that has a Hidden Ability distinct from its regular ability.</remarks>
|
||||
public static bool IsAbilityPatchPossible(int format, ushort species)
|
||||
{
|
||||
if (format <= 7)
|
||||
return false;
|
||||
|
||||
// Species (that can breed, from Gen6/7) that have never had a Hidden Ability distinct from their regular ability
|
||||
// Gen8+ has encounters with HA, so this is no longer a concern for anything originating from Gen8+.
|
||||
return species switch
|
||||
{
|
||||
(int)Species.Lunatone => false, // Levitate
|
||||
(int)Species.Solrock => false, // Levitate
|
||||
(int)Species.Rotom => false, // Levitate
|
||||
(int)Species.Archen => false, // Defeatist
|
||||
_ => true,
|
||||
};
|
||||
}
|
||||
|
||||
public BallInheritanceResult CanBreedWithBall(ushort species, byte form, Ball ball, PKM pk) => CanBreedWithBall(species, form, ball) ? Valid : Invalid;
|
||||
|
||||
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<byte> Permit => new byte[]
|
||||
{
|
||||
0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7B, 0x0B, 0x0B, 0x6F, 0x0B, 0x0B, 0x6F, // 000-019
|
||||
0x0B, 0x6F, 0x0B, 0x6F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 020-039
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x0B, 0x7F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x6B, 0x7F, 0x7F, // 040-059
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x6B, 0x7F, 0x7F, 0x6F, 0x6B, 0x6B, 0x7F, 0x7F, 0x7F, // 060-079
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x2F, 0x0B, 0x6B, 0x0B, 0x6F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x7F, 0x7F, // 080-099
|
||||
0x6F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 100-119
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 120-139
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x4B, 0x0B, 0x0B, 0x6B, 0x6B, 0x6B, 0x4B, 0x0B, // 140-159
|
||||
0x0B, 0x6F, 0x6B, 0x7F, 0x7F, 0x6F, 0x0B, 0x6F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, // 160-179
|
||||
0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x6F, 0x6F, 0x6F, 0x6B, 0x6F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, 0x7F, // 180-199
|
||||
0x6F, 0x00, 0x7F, 0x6F, 0x6F, 0x6B, 0x7F, 0x6F, 0x7F, 0x6F, 0x0B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x6B, 0x6B, // 200-219
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x7F, 0x6F, 0x6B, 0x7F, 0x6F, 0x6F, 0x7F, 0x7F, 0x7F, 0x7F, // 220-239
|
||||
0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 240-259
|
||||
0x7F, 0x6B, 0x6B, 0x7F, 0x7F, 0x3B, 0x0B, 0x0B, 0x0B, 0x0B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x0B, 0x7F, 0x7F, // 260-279
|
||||
0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x6F, 0x6B, 0x6F, 0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x6B, 0x7F, 0x6F, // 280-299
|
||||
0x2B, 0x0B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x7F, 0x7F, 0x2B, 0x2B, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x7F, 0x7F, // 300-319
|
||||
0x7F, 0x7F, 0x6B, 0x6B, 0x7F, 0x6B, 0x6B, 0x6F, 0x7F, 0x7F, 0x7F, 0x6F, 0x6B, 0x7F, 0x7F, 0x6F, 0x6F, 0x7F, 0x7F, 0x7F, // 320-339
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x6F, 0x6F, 0x6B, 0x7F, 0x7F, 0x6F, 0x6F, 0x7F, // 340-359
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x0B, 0x0B, 0x7F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, // 360-379
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x0B, 0x0B, 0x6B, 0x0B, 0x0B, 0x6B, 0x0B, 0x0B, 0x6F, 0x6B, 0x6B, 0x2F, // 380-399
|
||||
0x0B, 0x7B, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x23, 0x0B, 0x23, 0x0B, 0x2B, 0x0B, 0x0B, 0x7F, 0x7F, 0x6F, 0x6F, 0x6B, // 400-419
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x6B, 0x2B, 0x0B, 0x6F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 420-439
|
||||
0x7F, 0x2B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x2F, 0x6B, 0x6B, 0x7F, 0x7F, // 440-459
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x7F, 0x7F, 0x6B, 0x7F, 0x7F, 0x7F, 0x6B, 0x7F, 0x7F, 0x7F, // 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, 0x6B, 0x6B, 0x6B, 0x03, 0x03, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x23, 0x03, 0x23, 0x03, 0x23, 0x03, 0x7F, 0x7F, 0x7F, // 500-519
|
||||
0x7F, 0x7F, 0x03, 0x03, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 520-539
|
||||
0x6B, 0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 540-559
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 560-579
|
||||
0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 580-599
|
||||
0x7F, 0x7F, 0x6B, 0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 600-619
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, // 620-639
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, // 640-659
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, 0x7F, 0x4B, 0x7F, 0x7F, 0x7F, // 660-679
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 680-699
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, // 700-719
|
||||
0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x4B, 0x43, 0x43, 0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x6B, // 720-739
|
||||
0x6B, 0x6B, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 740-759
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x4B, 0x6B, 0x7F, 0x7F, 0x7F, 0x6B, // 760-779
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 780-799
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x7F, // 800-819
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 820-839
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 840-859
|
||||
0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, // 860-879
|
||||
0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, // 880-899
|
||||
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, // 900-919
|
||||
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, // 920-939
|
||||
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, // 940-959
|
||||
0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, 0x6B, // 960-979
|
||||
0x6B, 0x6B, 0x6B, 0x6B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B, 0x00, // 980-999
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6B, 0x6B, 0x6B,
|
||||
};
|
||||
|
||||
private enum BallType : byte
|
||||
{
|
||||
Gen3 = 0,
|
||||
Gen4 = 1,
|
||||
Safari = 2,
|
||||
Apricorn = 3,
|
||||
Sport = 4,
|
||||
Dream = 5,
|
||||
Beast = 6,
|
||||
|
||||
None = 9,
|
||||
}
|
||||
}
|
25
PKHeX.Core/Legality/Verifiers/Ball/BallContextUtil.cs
Normal file
25
PKHeX.Core/Legality/Verifiers/Ball/BallContextUtil.cs
Normal file
|
@ -0,0 +1,25 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
#if DEBUG
|
||||
public static class BallContextUtil
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new string with the table formatted as is shown in the source code.
|
||||
/// </summary>
|
||||
public static string Export(ReadOnlySpan<byte> permit)
|
||||
{
|
||||
var sb = new StringBuilder(8 * permit.Length);
|
||||
const int entriesPerLine = 20;
|
||||
for (int i = 0; i < permit.Length; i++)
|
||||
{
|
||||
sb.Append($"0x{permit[i]:X2}, ");
|
||||
if (i % entriesPerLine == entriesPerLine - 1)
|
||||
sb.AppendLine($"// {i - 19:000}-{i:000}");
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
public enum BallInheritanceResult
|
||||
{
|
||||
Valid,
|
||||
BadAbility,
|
||||
Invalid,
|
||||
}
|
|
@ -1,10 +1,28 @@
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using static PKHeX.Core.Ball;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
internal static class BallUseLegality
|
||||
{
|
||||
internal static ulong GetWildBalls(int generation, GameVersion game) => generation switch
|
||||
/// <summary>
|
||||
/// In Sun/Moon, capturing with Heavy Ball is impossible in Sun/Moon for specific hard to catch species.
|
||||
/// </summary>
|
||||
/// <param name="species">Encounter species.</param>
|
||||
/// <remarks>
|
||||
/// Catch rate for these species is 3. Due to the heavy ball modifier adding [-20], the catch rate becomes 0.
|
||||
/// </remarks>
|
||||
/// <returns>True if it is impossible to capture in a <see cref="Heavy"/> ball.</returns>
|
||||
public static bool IsAlolanCaptureNoHeavyBall(ushort species) => species is (int)Species.Beldum or (int)Species.TapuKoko or (int)Species.TapuLele or (int)Species.TapuBulu or (int)Species.TapuFini;
|
||||
|
||||
public static bool IsBallPermitted([ConstantExpected] ulong permit, int ball)
|
||||
{
|
||||
if ((uint)ball >= 64)
|
||||
return false;
|
||||
return (permit & (1ul << ball)) != 0;
|
||||
}
|
||||
|
||||
public static ulong GetWildBalls(int generation, GameVersion game) => generation switch
|
||||
{
|
||||
1 => WildPokeBalls1,
|
||||
2 => WildPokeBalls2,
|
||||
|
@ -61,17 +79,17 @@ internal static class BallUseLegality
|
|||
private const ulong WildPokeBalls2 = WildPokeBalls1;
|
||||
private const ulong WildPokeBalls3 = WildPokeRegular | WildPokeEnhance3;
|
||||
private const ulong WildPokeBalls4_DPPt = WildPokeBalls3 | WildPokeEnhance4;
|
||||
private const ulong WildPokeBalls4_HGSS = WildPokeBalls4_DPPt | WildPokeKurt4;
|
||||
public const ulong WildPokeBalls4_HGSS = WildPokeBalls4_DPPt | WildPokeKurt4;
|
||||
private const ulong WildPokeBalls5 = WildPokeBalls4_DPPt;
|
||||
|
||||
internal const ulong DreamWorldBalls = WildPokeBalls5 | WildPokeEnhance5;
|
||||
internal const ulong WildPokeballs6 = WildPokeBalls5; // Same as Gen5
|
||||
internal const ulong WildPokeballs7 = WildPokeBalls4_HGSS | WildPokeEnhance7; // Same as HGSS + Beast
|
||||
internal const ulong WildPokeballs8 = WildPokeballs7 | WildPokeEnhance8;
|
||||
public const ulong DreamWorldBalls = WildPokeBalls5 | WildPokeEnhance5;
|
||||
private const ulong WildPokeballs6 = WildPokeBalls5; // Same as Gen5
|
||||
private const ulong WildPokeballs7 = WildPokeBalls4_HGSS | WildPokeEnhance7; // Same as HGSS + Beast
|
||||
private const ulong WildPokeballs8 = WildPokeballs7 | WildPokeEnhance8;
|
||||
|
||||
private const ulong WildPokeballs7b = WildPokeRegular | (1 << (int)Premier);
|
||||
internal const ulong WildPokeballs8g_WithRaid = WildPokeballs7b & ~(1ul << (int)Master); // Ultra Great Poke Premier, no Master
|
||||
internal const ulong WildPokeballs8g_WithoutRaid = WildPokeRegular & ~(1ul << (int)Master); // Ultra Great Poke, no Premier/Master
|
||||
public const ulong WildPokeballs8g_WithRaid = WildPokeballs7b & ~(1ul << (int)Master); // Ultra Great Poke Premier, no Master
|
||||
public const ulong WildPokeballs8g_WithoutRaid = WildPokeRegular & ~(1ul << (int)Master); // Ultra Great Poke, no Premier/Master
|
||||
|
||||
internal const ulong WildPokeballs9 = WildPokeballs7 | WildPokeEnhance5; // Same as Gen7 + Dream
|
||||
public const ulong WildPokeballs9 = WildPokeballs7 | WildPokeEnhance5; // Same as Gen7 + Dream
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
using static PKHeX.Core.Ball;
|
||||
|
||||
|
@ -9,7 +11,6 @@ namespace PKHeX.Core;
|
|||
public sealed class BallVerifier : Verifier
|
||||
{
|
||||
protected override CheckIdentifier Identifier => CheckIdentifier.Ball;
|
||||
private CheckResult NONE => GetInvalid(LBallNone);
|
||||
|
||||
public override void Verify(LegalityAnalysis data)
|
||||
{
|
||||
|
@ -60,438 +61,153 @@ public sealed class BallVerifier : Verifier
|
|||
}
|
||||
|
||||
// Capturing with Heavy Ball is impossible in Sun/Moon for specific species.
|
||||
if (pk is { Ball: (int)Heavy, SM: true } && enc is not EncounterEgg && BallBreedLegality.AlolanCaptureNoHeavyBall.Contains(enc.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 enc switch
|
||||
{
|
||||
EncounterStatic5Entree => VerifyBallEquals(data, BallUseLegality.DreamWorldBalls),
|
||||
EncounterStatic5Entree => VerifyBallEquals((Ball)pk.Ball, BallUseLegality.DreamWorldBalls),
|
||||
EncounterEgg => VerifyBallEgg(data),
|
||||
EncounterInvalid => VerifyBallEquals(data, pk.Ball), // ignore ball, pass whatever
|
||||
_ => VerifyBallEquals(data, BallUseLegality.GetWildBalls(data.Info.Generation, enc.Version)),
|
||||
_ => VerifyBallEquals((Ball)pk.Ball, BallUseLegality.GetWildBalls(data.Info.Generation, enc.Version)),
|
||||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyBallEgg(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
if (data.Info.Generation < 6) // No inheriting Balls
|
||||
var info = data.Info;
|
||||
if (info.Generation < 6) // No inheriting Balls
|
||||
return VerifyBallEquals(data, (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
|
||||
_ => VerifyBallInherited(data),
|
||||
_ => VerifyBallInherited(data, info.EncounterMatch.Context),
|
||||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyBallInherited(LegalityAnalysis data) => data.Info.EncounterMatch.Context switch
|
||||
private CheckResult VerifyBallInherited(LegalityAnalysis data, EntityContext context) => context switch
|
||||
{
|
||||
EntityContext.Gen6 => VerifyBallEggGen6(data), // Gen6 Inheritance Rules
|
||||
EntityContext.Gen7 => VerifyBallEggGen7(data), // Gen7 Inheritance Rules
|
||||
EntityContext.Gen8 => VerifyBallEggGen8(data),
|
||||
EntityContext.Gen8b => VerifyBallEggGen8BDSP(data),
|
||||
EntityContext.Gen9 => VerifyBallEggGen9(data),
|
||||
_ => NONE,
|
||||
_ => GetInvalid(LBallNone),
|
||||
};
|
||||
|
||||
private CheckResult VerifyBallEggGen6(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
if (pk.Ball == (int)Poke)
|
||||
return GetValid(LBallEnc); // Poké Ball
|
||||
|
||||
var enc = data.EncounterMatch;
|
||||
var species = enc.Species;
|
||||
if (pk.Gender == 2 || BallBreedLegality.BreedMaleOnly6.Contains(species)) // Genderless
|
||||
return VerifyBallEquals(data, (int)Poke); // Must be Pokéball as ball can only pass via mother (not Ditto!)
|
||||
|
||||
Ball ball = (Ball)pk.Ball;
|
||||
|
||||
if (ball == Safari) // Safari Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Safari.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball.IsApricornBall()) // Apricorn Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Apricorn6.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Sport) // Sport Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Sport.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Dream) // Dream Ball
|
||||
{
|
||||
if (BallBreedLegality.Ban_DreamHidden.Contains(species) && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
if (BallBreedLegality.Inherit_Dream.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
if (ball is >= Dusk and <= Quick) // Dusk Heal Quick
|
||||
{
|
||||
if (!BallBreedLegality.Ban_Gen4Ball_6.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
if (ball is >= Ultra and <= Premier) // Don't worry, Safari was already checked.
|
||||
{
|
||||
if (BallBreedLegality.Ban_Gen3Ball.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (BallBreedLegality.Ban_Gen3BallHidden.Contains((ushort)(species | (enc.Form << 11))) && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
|
||||
if (species > 650 && species != 700) // Sylveon
|
||||
{
|
||||
if (IsBallPermitted(BallUseLegality.WildPokeballs6, pk.Ball))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
|
||||
if (ball >= Dream)
|
||||
var ball = (Ball)pk.Ball;
|
||||
var instance = BallContext6.Instance;
|
||||
if (ball > Dream)
|
||||
return GetInvalid(LBallUnavailable);
|
||||
|
||||
return NONE;
|
||||
var enc = data.EncounterMatch;
|
||||
var result = instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk);
|
||||
return result switch
|
||||
{
|
||||
BallInheritanceResult.Valid => GetValid(LBallSpeciesPass),
|
||||
BallInheritanceResult.BadAbility => GetInvalid(LBallAbility),
|
||||
_ => GetInvalid(LBallSpecies),
|
||||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyBallEggGen7(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
if (pk.Ball == (int)Poke)
|
||||
return GetValid(LBallEnc); // Poké Ball
|
||||
|
||||
var species = data.EncounterMatch.Species;
|
||||
if (species is >= 722 and <= 730) // G7 Starters
|
||||
return VerifyBallEquals(data, (int)Poke);
|
||||
|
||||
Ball ball = (Ball)pk.Ball;
|
||||
|
||||
if (ball == Safari)
|
||||
{
|
||||
if (!(BallBreedLegality.Inherit_Safari.Contains(species) || BallBreedLegality.Inherit_SafariMale.Contains(species)))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (BallBreedLegality.Ban_SafariBallHidden_7.Contains(species) && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball.IsApricornBall()) // Apricorn Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Apricorn7.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (BallBreedLegality.Ban_NoHidden7Apricorn.Contains((ushort)(species | (pk.Form << 11))) && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Sport) // Sport Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Sport.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if ((species is (int)Species.Volbeat or (int)Species.Illumise) && IsHiddenAndNotPossible(pk)) // Volbeat/Illumise
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Dream) // Dream Ball
|
||||
{
|
||||
if (BallBreedLegality.Inherit_Dream.Contains(species) || BallBreedLegality.Inherit_DreamMale.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
if (ball is >= Dusk and <= Quick) // Dusk Heal Quick
|
||||
{
|
||||
if (!BallBreedLegality.Ban_Gen4Ball_7.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
if (ball is >= Ultra and <= Premier) // Don't worry, Safari was already checked.
|
||||
{
|
||||
if (!BallBreedLegality.Ban_Gen3Ball_7.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
|
||||
if (ball == Beast)
|
||||
{
|
||||
if (species == (int)Species.Flabébé && pk.Form == 3 && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility); // Can't obtain Flabébé-Blue with Hidden Ability in wild
|
||||
if (species == (int)Species.Voltorb && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility); // Can't obtain with Hidden Ability in wild (can only breed with Ditto)
|
||||
if ((species is >= (int)Species.Pikipek and <= (int)Species.Kommoo) || BallBreedLegality.AlolanCaptureOffspring.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
if (BallBreedLegality.PastGenAlolanScans.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
// next statement catches all new alolans
|
||||
}
|
||||
|
||||
if (species > (int)Species.Volcanion)
|
||||
return VerifyBallEquals(data, BallUseLegality.WildPokeballs7);
|
||||
|
||||
var ball = (Ball)pk.Ball;
|
||||
var instance = BallContext7.Instance;
|
||||
if (ball > Beast)
|
||||
return GetInvalid(LBallUnavailable);
|
||||
|
||||
return NONE;
|
||||
var enc = data.EncounterMatch;
|
||||
var result = instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk);
|
||||
return result switch
|
||||
{
|
||||
BallInheritanceResult.Valid => GetValid(LBallSpeciesPass),
|
||||
BallInheritanceResult.BadAbility => GetInvalid(LBallAbility),
|
||||
_ => GetInvalid(LBallSpecies),
|
||||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyBallEggGen8BDSP(LegalityAnalysis data)
|
||||
{
|
||||
var species = data.EncounterMatch.Species;
|
||||
if (species == (int)Species.Phione)
|
||||
return VerifyBallEquals(data, (int)Poke);
|
||||
|
||||
if (species is (int)Species.Cranidos or (int)Species.Shieldon)
|
||||
return VerifyBallEquals(data, BallUseLegality.DreamWorldBalls);
|
||||
|
||||
var pk = data.Entity;
|
||||
Ball ball = (Ball)pk.Ball;
|
||||
var balls = BallUseLegality.GetWildBalls(8, GameVersion.BDSP);
|
||||
if (IsBallPermitted(balls, (int)ball))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
|
||||
if (species is (int)Species.Spinda)
|
||||
return GetInvalid(LBallSpecies); // Can't enter or exit, needs to adhere to wild balls.
|
||||
|
||||
// Cross-game inheritance
|
||||
if (IsGalarCatchAndBreed(species))
|
||||
{
|
||||
if (IsBallPermitted(BallUseLegality.WildPokeballs8, (int)ball))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (IsPaldeaCatchAndBreed(species))
|
||||
{
|
||||
if (IsBallPermitted(BallUseLegality.WildPokeballs9, (int)ball))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
|
||||
if (ball == Safari)
|
||||
{
|
||||
if (!(BallBreedLegality.Inherit_Safari.Contains(species) || BallBreedLegality.Inherit_SafariMale.Contains(species)))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (BallBreedLegality.Ban_SafariBallHidden_7.Contains(species) && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball.IsApricornBall()) // Apricorn Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Apricorn7.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (BallBreedLegality.Ban_NoHidden8Apricorn.Contains((ushort)(species | (pk.Form << 11))) && IsHiddenAndNotPossible(pk)) // lineage is 3->2->origin
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Sport) // Sport Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Sport.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if ((species is (int)Species.Volbeat or (int)Species.Illumise) && IsHiddenAndNotPossible(pk)) // Volbeat/Illumise
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Dream) // Dream Ball
|
||||
{
|
||||
if (BallBreedLegality.Inherit_Dream.Contains(species) || BallBreedLegality.Inherit_DreamMale.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
if (ball is >= Dusk and <= Quick) // Dusk Heal Quick
|
||||
return GetValid(LBallSpeciesPass);
|
||||
if (ball is >= Ultra and <= Premier) // Don't worry, Safari was already checked.
|
||||
return GetValid(LBallSpeciesPass);
|
||||
|
||||
if (ball == Beast)
|
||||
{
|
||||
// Most were already caught by Galar ball logic. Check for stuff not in SW/SH.
|
||||
if (BallBreedLegality.AlolanCaptureOffspring.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
if (BallBreedLegality.PastGenAlolanScans.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
var ball = (Ball)pk.Ball;
|
||||
if (species is (int)Species.Spinda) // Can't transfer via HOME.
|
||||
return VerifyBallEquals(ball, BallUseLegality.WildPokeBalls4_HGSS);
|
||||
|
||||
var instance = BallContextHOME.Instance;
|
||||
if (ball > Beast)
|
||||
return GetInvalid(LBallUnavailable);
|
||||
|
||||
return GetInvalid(LBallEncMismatch);
|
||||
var enc = data.EncounterMatch;
|
||||
var result = instance.CanBreedWithBall(species, enc.Form, ball, pk);
|
||||
return result switch
|
||||
{
|
||||
BallInheritanceResult.Valid => GetValid(LBallSpeciesPass),
|
||||
BallInheritanceResult.BadAbility => GetInvalid(LBallAbility),
|
||||
_ => GetInvalid(LBallSpecies),
|
||||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyBallEggGen8(LegalityAnalysis data)
|
||||
{
|
||||
var pk = data.Entity;
|
||||
if (pk.Ball == (int)Poke)
|
||||
return GetValid(LBallEnc); // Poké Ball
|
||||
|
||||
var species = data.EncounterMatch.Species;
|
||||
if (IsGalarCatchAndBreed(species))
|
||||
{
|
||||
if (IsBallPermitted(BallUseLegality.WildPokeballs8, pk.Ball))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (IsPaldeaCatchAndBreed(species))
|
||||
{
|
||||
if (IsBallPermitted(BallUseLegality.WildPokeballs9, pk.Ball))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
|
||||
Ball ball = (Ball)pk.Ball;
|
||||
|
||||
if (ball == Safari)
|
||||
{
|
||||
if (!(BallBreedLegality.Inherit_Safari.Contains(species) || BallBreedLegality.Inherit_SafariMale.Contains(species)))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (BallBreedLegality.Ban_SafariBallHidden_7.Contains(species) && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball.IsApricornBall()) // Apricorn Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Apricorn7.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if (BallBreedLegality.Ban_NoHidden8Apricorn.Contains((ushort)(species | (pk.Form << 11))) && IsHiddenAndNotPossible(pk)) // lineage is 3->2->origin
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Sport) // Sport Ball
|
||||
{
|
||||
if (!BallBreedLegality.Inherit_Sport.Contains(species))
|
||||
return GetInvalid(LBallSpecies);
|
||||
if ((species is (int)Species.Volbeat or (int)Species.Illumise) && IsHiddenAndNotPossible(pk)) // Volbeat/Illumise
|
||||
return GetInvalid(LBallAbility);
|
||||
return GetValid(LBallSpeciesPass);
|
||||
}
|
||||
if (ball == Dream) // Dream Ball
|
||||
{
|
||||
if (BallBreedLegality.Inherit_Dream.Contains(species) || BallBreedLegality.Inherit_DreamMale.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
if (ball is >= Dusk and <= Quick) // Dusk Heal Quick
|
||||
{
|
||||
if (!BallBreedLegality.Ban_Gen4Ball_7.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
if (ball is >= Ultra and <= Premier) // Don't worry, Safari was already checked.
|
||||
{
|
||||
if (!BallBreedLegality.Ban_Gen3Ball_7.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
return GetInvalid(LBallSpecies);
|
||||
}
|
||||
|
||||
if (ball == Beast)
|
||||
{
|
||||
if (species == (int)Species.Flabébé && pk.Form == 3 && IsHiddenAndNotPossible(pk))
|
||||
return GetInvalid(LBallAbility); // Can't obtain Flabébé-Blue with Hidden Ability in wild
|
||||
if ((species is >= (int)Species.Pikipek and <= (int)Species.Kommoo) || BallBreedLegality.AlolanCaptureOffspring.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
if (BallBreedLegality.PastGenAlolanScans.Contains(species))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
// next statement catches all new alolans
|
||||
}
|
||||
|
||||
if (species > Legal.MaxSpeciesID_7_USUM)
|
||||
return VerifyBallEquals(data, BallUseLegality.WildPokeballs8);
|
||||
|
||||
if (species > (int)Species.Volcanion)
|
||||
return VerifyBallEquals(data, BallUseLegality.WildPokeballs7);
|
||||
|
||||
var ball = (Ball)pk.Ball;
|
||||
var instance = BallContextHOME.Instance;
|
||||
if (ball > Beast)
|
||||
return GetInvalid(LBallUnavailable);
|
||||
|
||||
return NONE;
|
||||
var enc = data.EncounterMatch;
|
||||
var result = instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk);
|
||||
return result switch
|
||||
{
|
||||
BallInheritanceResult.Valid => GetValid(LBallSpeciesPass),
|
||||
BallInheritanceResult.BadAbility => GetInvalid(LBallAbility),
|
||||
_ => GetInvalid(LBallSpecies),
|
||||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyBallEggGen9(LegalityAnalysis data)
|
||||
{
|
||||
var enc = data.EncounterMatch;
|
||||
var species = enc.Species;
|
||||
if (species == (int)Species.Phione)
|
||||
return VerifyBallEquals(data, (int)Poke);
|
||||
var pk = data.Entity;
|
||||
var ball = (Ball)pk.Ball;
|
||||
|
||||
// Paldea Starters: Only via GO (Adventures Abound)
|
||||
if (species is >= (int)Species.Sprigatito and <= (int)Species.Quaquaval)
|
||||
return VerifyBallEquals(data, BallUseLegality.WildPokeballs8g_WithoutRaid);
|
||||
return VerifyBallEquals(ball, BallUseLegality.WildPokeballs8g_WithoutRaid);
|
||||
|
||||
// PLA Voltorb: Only via PLA (transfer only, not wild) and GO
|
||||
if (enc is { Species: (ushort)Species.Voltorb, Form: 1 })
|
||||
return VerifyBallEquals(data, BallUseLegality.WildPokeballs8g_WithRaid);
|
||||
return VerifyBallEquals(ball, BallUseLegality.WildPokeballs8g_WithRaid);
|
||||
|
||||
// S/V Tauros forms > 1: Only local Wild Balls for Blaze/Aqua breeds -- can't inherit balls from Kantonian/Combat.
|
||||
if (enc is { Species: (ushort)Species.Tauros, Form: > 1 })
|
||||
return VerifyBallEquals(data, BallUseLegality.WildPokeballs9);
|
||||
return VerifyBallEquals(ball, BallUseLegality.WildPokeballs9);
|
||||
|
||||
var pk = data.Entity;
|
||||
if (IsPaldeaCatchAndBreed(species) && IsBallPermitted(BallUseLegality.WildPokeballs9, pk.Ball))
|
||||
return GetValid(LBallSpeciesPass);
|
||||
var instance = BallContextHOME.Instance;
|
||||
if (ball > Beast)
|
||||
return GetInvalid(LBallUnavailable);
|
||||
|
||||
if (species > Legal.MaxSpeciesID_8)
|
||||
return VerifyBallEquals(data, BallUseLegality.WildPokeballs9);
|
||||
|
||||
return VerifyBallEggGen8(data);
|
||||
}
|
||||
|
||||
private static bool IsHiddenAndNotPossible(PKM pk)
|
||||
var result = instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk);
|
||||
return result switch
|
||||
{
|
||||
if (pk.AbilityNumber != 4)
|
||||
return false;
|
||||
var abilities = (IPersonalAbility12H)pk.PersonalInfo;
|
||||
return !AbilityVerifier.CanAbilityPatch(pk.Format, abilities, pk.Species);
|
||||
}
|
||||
|
||||
private static bool IsGalarCatchAndBreed(ushort species)
|
||||
{
|
||||
if (species is >= (int)Species.Grookey and <= (int)Species.Inteleon) // starter
|
||||
return false;
|
||||
|
||||
// Everything breed-able that is in the Galar Dex can be captured in-game.
|
||||
var pt = PersonalTable.SWSH;
|
||||
var pi = pt.GetFormEntry(species, 0);
|
||||
if (pi.IsInDex)
|
||||
return true;
|
||||
|
||||
// Foreign Captures
|
||||
if (species is >= (int)Species.Treecko and <= (int)Species.Swampert) // Dynamax Adventures
|
||||
return true;
|
||||
if (species is >= (int)Species.Rowlet and <= (int)Species.Primarina) // Distribution Raids
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsPaldeaCatchAndBreed(ushort species)
|
||||
{
|
||||
if (species is >= (int)Species.Sprigatito and <= (int)Species.Quaquaval) // paldea starter
|
||||
return false;
|
||||
if (species is >= (int)Species.Turtwig and <= (int)Species.Empoleon) // sinnoh starter
|
||||
return false;
|
||||
var pt = PersonalTable.SV;
|
||||
var pi = pt.GetFormEntry(species, 0);
|
||||
if (pi.IsPresentInGame)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
BallInheritanceResult.Valid => GetValid(LBallSpeciesPass),
|
||||
BallInheritanceResult.BadAbility => GetInvalid(LBallAbility),
|
||||
_ => GetInvalid(LBallSpecies),
|
||||
};
|
||||
}
|
||||
|
||||
private CheckResult VerifyBallEquals(LegalityAnalysis data, int ball) => GetResult(ball == data.Entity.Ball);
|
||||
private CheckResult VerifyBallEquals(LegalityAnalysis data, ulong permit) => GetResult(IsBallPermitted(permit, data.Entity.Ball));
|
||||
|
||||
private static bool IsBallPermitted(ulong permit, int ball)
|
||||
{
|
||||
if ((uint)ball >= 64)
|
||||
return false;
|
||||
return (permit & (1ul << ball)) != 0;
|
||||
}
|
||||
private CheckResult VerifyBallEquals(Ball ball, [ConstantExpected] ulong permit) => GetResult(BallUseLegality.IsBallPermitted(permit, (int)ball));
|
||||
|
||||
private CheckResult GetResult(bool valid) => valid ? GetValid(LBallEnc) : GetInvalid(LBallEncMismatch);
|
||||
}
|
||||
|
|
19
PKHeX.Core/Legality/Verifiers/Ball/IBallContext.cs
Normal file
19
PKHeX.Core/Legality/Verifiers/Ball/IBallContext.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Context for determining if a ball can be inherited.
|
||||
/// </summary>
|
||||
public interface IBallContext
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the <see cref="PKM"/> can be bred with the given <see cref="Ball"/>.
|
||||
/// </summary>
|
||||
/// <param name="species">Encounter Species</param>
|
||||
/// <param name="form">Encounter Form</param>
|
||||
/// <param name="ball">Encounter Ball</param>
|
||||
/// <param name="pk">Current Entity</param>
|
||||
BallInheritanceResult CanBreedWithBall(ushort species, byte form, Ball ball, PKM pk);
|
||||
|
||||
/// <inheritdoc cref="CanBreedWithBall(ushort, byte, Ball, PKM)"/>
|
||||
bool CanBreedWithBall(ushort species, byte form, Ball ball);
|
||||
}
|
24
Tests/PKHeX.Core.Tests/Legality/BallTests.cs
Normal file
24
Tests/PKHeX.Core.Tests/Legality/BallTests.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using FluentAssertions;
|
||||
using Xunit;
|
||||
|
||||
namespace PKHeX.Core.Tests.Legality;
|
||||
|
||||
public class BallTests
|
||||
{
|
||||
/// <summary>
|
||||
/// Some species can't use ability patch yet.
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData(Species.Lunatone)]
|
||||
[InlineData(Species.Solrock)]
|
||||
[InlineData(Species.Rotom)]
|
||||
[InlineData(Species.Archen)]
|
||||
[InlineData(Species.Pikachu, true)] // can use ability patch
|
||||
public void IsAbilityPatchPossible(Species species, bool expect = false)
|
||||
{
|
||||
var p7 = BallContextHOME.IsAbilityPatchPossible(7, (ushort)species);
|
||||
p7.Should().Be(false);
|
||||
var p8 = BallContextHOME.IsAbilityPatchPossible(8, (ushort)species);
|
||||
p8.Should().Be(expect);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue