2020-12-08 04:54:55 +00:00
using System.Collections.Generic ;
2021-01-01 23:01:22 +00:00
using static PKHeX . Core . GameVersion ;
using static PKHeX . Core . Species ;
2020-12-08 04:54:55 +00:00
2022-06-18 18:04:24 +00:00
namespace PKHeX.Core ;
/// <summary>
/// Logic related to breeding.
/// </summary>
public static class Breeding
2020-12-08 04:54:55 +00:00
{
/// <summary>
2022-06-18 18:04:24 +00:00
/// Checks if the game has a Daycare, and returns true if it does.
/// </summary>
/// <param name="game">Version ID to check for.</param>
public static bool CanGameGenerateEggs ( GameVersion game ) = > GamesWithEggs . Contains ( game ) ;
private static readonly HashSet < GameVersion > GamesWithEggs = new ( )
{
GD , SI , C ,
R , S , E , FR , LG ,
D , P , Pt , HG , SS ,
B , W , B2 , W2 ,
X , Y , OR , AS ,
SN , MN , US , UM ,
SW , SH , BD , SP ,
2022-11-25 01:42:17 +00:00
SL , VL ,
2022-06-18 18:04:24 +00:00
GS ,
} ;
/// <summary>
/// Species that have special handling for breeding.
/// </summary>
2022-08-27 06:43:36 +00:00
internal static readonly HashSet < ushort > MixedGenderBreeding = new ( )
2022-06-18 18:04:24 +00:00
{
( int ) NidoranF ,
( int ) NidoranM ,
( int ) Volbeat ,
( int ) Illumise ,
( int ) Indeedee , // male/female
} ;
/// <summary>
/// Checks if the <see cref="species"/> can be born with inherited moves from the parents.
/// </summary>
/// <param name="species">Entity species ID</param>
/// <returns>True if can inherit moves, false if cannot.</returns>
2022-08-27 06:43:36 +00:00
internal static bool GetCanInheritMoves ( ushort species )
2022-06-18 18:04:24 +00:00
{
if ( Legal . FixedGenderFromBiGender . Contains ( species ) ) // Nincada -> Shedinja loses gender causing 'false', edge case
return true ;
var pi = PKX . Personal [ species ] ;
2023-01-22 04:02:33 +00:00
if ( pi is { Genderless : false , OnlyMale : false } )
2022-06-18 18:04:24 +00:00
return true ;
if ( MixedGenderBreeding . Contains ( species ) )
return true ;
return false ;
}
2022-08-27 06:43:36 +00:00
private static readonly HashSet < ushort > SplitBreed_3 = new ( )
2022-06-18 18:04:24 +00:00
{
// Incense
2023-01-22 04:02:33 +00:00
( int ) Marill ,
2022-06-18 18:04:24 +00:00
( int ) Wobbuffet ,
} ;
/// <summary>
/// Species that can yield a different baby species when bred.
/// </summary>
2022-08-27 06:43:36 +00:00
private static readonly HashSet < ushort > SplitBreed = new ( SplitBreed_3 )
2022-06-18 18:04:24 +00:00
{
// Incense
2023-01-22 04:02:33 +00:00
( int ) Chansey ,
( int ) MrMime ,
2022-06-18 18:04:24 +00:00
( int ) Snorlax ,
( int ) Sudowoodo ,
( int ) Mantine ,
2023-01-22 04:02:33 +00:00
( int ) Roselia ,
2022-06-18 18:04:24 +00:00
( int ) Chimecho ,
} ;
2023-01-22 04:02:33 +00:00
internal static IReadOnlySet < ushort > ? GetSplitBreedGeneration ( int generation ) = > generation switch
2022-06-18 18:04:24 +00:00
{
3 = > SplitBreed_3 ,
4 or 5 or 6 or 7 or 8 = > SplitBreed ,
2022-11-25 01:42:17 +00:00
// Gen9 does not have split-breed egg generation.
2023-01-22 04:02:33 +00:00
_ = > null ,
2022-06-18 18:04:24 +00:00
} ;
/// <summary>
/// Checks if the <see cref="species"/> can be obtained from a daycare egg.
/// </summary>
/// <remarks>Chained with the other 2 overloads for incremental checks with different parameters.</remarks>
/// <param name="species">Current species</param>
2022-08-27 06:43:36 +00:00
public static bool CanHatchAsEgg ( ushort species ) = > ! NoHatchFromEgg . Contains ( species ) ;
2022-06-18 18:04:24 +00:00
/// <summary>
2023-01-22 04:02:33 +00:00
/// Checks if the <see cref="species"/>-<see cref="form"/> can exist as a hatched egg in the requested <see cref="context"/>.
2022-06-18 18:04:24 +00:00
/// </summary>
/// <remarks>Chained with the other 2 overloads for incremental checks with different parameters.</remarks>
/// <param name="species">Current species</param>
/// <param name="form">Current form</param>
2022-12-18 08:16:29 +00:00
/// <param name="context">Generation of origin</param>
public static bool CanHatchAsEgg ( ushort species , byte form , EntityContext context )
2022-06-18 18:04:24 +00:00
{
if ( form = = 0 )
return true ;
2022-12-18 08:16:29 +00:00
if ( FormInfo . IsTotemForm ( species , form , context ) )
2022-06-18 18:04:24 +00:00
return false ;
2022-12-18 08:16:29 +00:00
if ( FormInfo . IsLordForm ( species , form , context ) )
2022-06-18 18:04:24 +00:00
return false ;
return IsBreedableForm ( species , form ) ;
}
/// <summary>
2023-01-22 04:02:33 +00:00
/// Some species can have forms that cannot exist as egg (event/special forms). Same idea as <see cref="FormInfo.IsTotemForm(ushort,byte,EntityContext)"/>
2022-06-18 18:04:24 +00:00
/// </summary>
/// <returns>True if can be bred.</returns>
2022-08-27 19:53:30 +00:00
private static bool IsBreedableForm ( ushort species , byte form ) = > species switch
2022-06-18 18:04:24 +00:00
{
( int ) Pikachu or ( int ) Eevee = > false , // can't get these forms as egg
( int ) Pichu = > false , // can't get Spiky Ear Pichu eggs
( int ) Floette when form = = 5 = > false , // can't get Eternal Flower from egg
2023-01-27 03:03:06 +00:00
( int ) Greninja when form = = 1 = > false , // can't get Battle Bond Greninja from egg
2022-06-18 18:04:24 +00:00
( int ) Sinistea or ( int ) Polteageist = > false , // can't get Antique eggs
_ = > true ,
} ;
/// <summary>
/// Species that cannot hatch from an egg.
/// </summary>
2022-08-27 06:43:36 +00:00
private static readonly HashSet < ushort > NoHatchFromEgg = new ( )
2022-06-18 18:04:24 +00:00
{
// Gen1
( int ) Ditto ,
( int ) Articuno , ( int ) Zapdos , ( int ) Moltres ,
( int ) Mewtwo , ( int ) Mew ,
// Gen2
( int ) Unown ,
( int ) Raikou , ( int ) Entei , ( int ) Suicune ,
( int ) Lugia , ( int ) HoOh , ( int ) Celebi ,
// Gen3
( int ) Regirock , ( int ) Regice , ( int ) Registeel ,
( int ) Latias , ( int ) Latios ,
( int ) Kyogre , ( int ) Groudon , ( int ) Rayquaza ,
( int ) Jirachi , ( int ) Deoxys ,
// Gen4
( int ) Uxie , ( int ) Mesprit , ( int ) Azelf ,
( int ) Dialga , ( int ) Palkia , ( int ) Heatran ,
( int ) Regigigas , ( int ) Giratina , ( int ) Cresselia ,
( int ) Manaphy , ( int ) Darkrai , ( int ) Shaymin , ( int ) Arceus ,
// Gen5
( int ) Victini ,
( int ) Cobalion , ( int ) Terrakion , ( int ) Virizion ,
( int ) Tornadus , ( int ) Thundurus ,
( int ) Reshiram , ( int ) Zekrom ,
( int ) Landorus , ( int ) Kyurem ,
( int ) Keldeo , ( int ) Meloetta , ( int ) Genesect ,
// Gen6
( int ) Xerneas , ( int ) Yveltal , ( int ) Zygarde ,
( int ) Diancie , ( int ) Hoopa , ( int ) Volcanion ,
// Gen7
( int ) TypeNull , ( int ) Silvally ,
( int ) TapuKoko , ( int ) TapuLele , ( int ) TapuBulu , ( int ) TapuFini ,
( int ) Cosmog , ( int ) Cosmoem , ( int ) Solgaleo , ( int ) Lunala ,
( int ) Nihilego , ( int ) Buzzwole , ( int ) Pheromosa , ( int ) Xurkitree , ( int ) Celesteela , ( int ) Kartana , ( int ) Guzzlord , ( int ) Necrozma ,
( int ) Magearna , ( int ) Marshadow ,
( int ) Poipole , ( int ) Naganadel , ( int ) Stakataka , ( int ) Blacephalon , ( int ) Zeraora ,
( int ) Meltan , ( int ) Melmetal ,
// Gen8
( int ) Dracozolt , ( int ) Arctozolt , ( int ) Dracovish , ( int ) Arctovish ,
( int ) Zacian , ( int ) Zamazenta , ( int ) Eternatus ,
( int ) Kubfu , ( int ) Urshifu , ( int ) Zarude ,
( int ) Regieleki , ( int ) Regidrago ,
( int ) Glastrier , ( int ) Spectrier , ( int ) Calyrex ,
( int ) Enamorus ,
2022-11-25 01:42:17 +00:00
// Gen9
( int ) Gimmighoul , ( int ) Gholdengo ,
( int ) GreatTusk , ( int ) BruteBonnet , ( int ) _980 , ( int ) SandyShocks , ( int ) ScreamTail , ( int ) FlutterMane , ( int ) SlitherWing , ( int ) RoaringMoon ,
( int ) IronTreads , ( int ) _987 , ( int ) IronMoth , ( int ) IronHands , ( int ) IronJugulis , ( int ) IronThorns , ( int ) IronBundle , ( int ) IronValiant ,
( int ) TingLu , ( int ) ChienPao , ( int ) WoChien , ( int ) ChiYu ,
( int ) Koraidon , ( int ) Miraidon ,
2022-06-18 18:04:24 +00:00
} ;
2020-12-08 04:54:55 +00:00
}