using System; using System.Collections.Generic; using static PKHeX.Core.GameVersion; using static PKHeX.Core.Species; namespace PKHeX.Core { /// /// Logic related to breeding. /// public static class Breeding { /// /// Checks if the game has a Daycare, and returns true if it does. /// /// Version ID to check for. public static bool CanGameGenerateEggs(GameVersion game) => GamesWithEggs.Contains(game); private static readonly HashSet 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, GS, }; /// /// Species that have special handling for breeding. /// internal static readonly HashSet MixedGenderBreeding = new() { (int)NidoranF, (int)NidoranM, (int)Volbeat, (int)Illumise, (int)Indeedee, // male/female }; /// /// Checks if the can be born with inherited moves from the parents. /// /// Entity species ID /// True if can inherit moves, false if cannot. internal static bool GetCanInheritMoves(int species) { if (Legal.FixedGenderFromBiGender.Contains(species)) // Nincada -> Shedinja loses gender causing 'false', edge case return true; var pi = PKX.Personal[species]; if (!pi.Genderless && !pi.OnlyMale) return true; if (MixedGenderBreeding.Contains(species)) return true; return false; } private static readonly HashSet SplitBreed_3 = new() { // Incense (int)Marill, (int)Azumarill, (int)Wobbuffet, }; /// /// Species that can yield a different baby species when bred. /// private static readonly HashSet SplitBreed = new(SplitBreed_3) { // Incense (int)Chansey, (int)Blissey, (int)MrMime, (int)MrRime, (int)Snorlax, (int)Sudowoodo, (int)Mantine, (int)Roselia, (int)Roserade, (int)Chimecho, }; internal static ICollection GetSplitBreedGeneration(int generation) => generation switch { 3 => SplitBreed_3, 4 or 5 or 6 or 7 or 8 => SplitBreed, _ => Array.Empty(), }; /// /// Checks if the can be obtained from a daycare egg. /// /// Chained with the other 2 overloads for incremental checks with different parameters. /// Current species public static bool CanHatchAsEgg(int species) => !NoHatchFromEgg.Contains(species); /// /// Checks if the - can exist as a hatched egg in the requested . /// /// Chained with the other 2 overloads for incremental checks with different parameters. /// Current species /// Current form /// Generation of origin public static bool CanHatchAsEgg(int species, int form, int generation) { if (form == 0) return true; if (FormInfo.IsTotemForm(species, form, generation)) return false; if (FormInfo.IsLordForm(species, form, generation)) return false; return IsBreedableForm(species, form); } /// /// Some species can have forms that cannot exist as egg (event/special forms). Same idea as /// /// True if can be bred. private static bool IsBreedableForm(int species, int form) => species switch { (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 (int)Sinistea or (int)Polteageist => false, // can't get Antique eggs _ => true, }; /// /// Checks if the - can exist as a hatched egg in the requested . /// /// Chained with the other 2 overloads for incremental checks with different parameters. /// Current species /// Current form /// Game of origin public static bool CanHatchAsEgg(int species, int form, GameVersion game) { // Sanity check form for origin var pt = GameData.GetPersonal(game); if ((uint)species > pt.MaxSpeciesID) return false; var entry = pt.GetFormEntry(species, form); if (!entry.IsPresentInGame) return false; return form < entry.FormCount || (species == (int)Rotom && form <= 5); } /// /// Species that cannot hatch from an egg. /// private static readonly HashSet NoHatchFromEgg = new() { // 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, }; } }