using System.Collections.Generic; namespace PKHeX.Core { public static class FormConverter { /// /// Gets a list of formes that the species can have. /// /// National Dex number of the Pokémon. /// List of type names /// List of form names /// List of genders names /// Generation number for exclusive formes /// A list of strings corresponding to the formes that a Pokémon can have. internal static string[] GetFormList(int species, IReadOnlyList types, IReadOnlyList forms, IReadOnlyList genders, int generation) { // Mega List if (IsFormListSingleMega(species)) { return new[] { types[000], // Normal forms[804], // Mega }; } if (generation == 7 && Legal.Totem_USUM.Contains(species)) return GetFormsTotem(species, types, forms); if (species <= Legal.MaxSpeciesID_1) return GetFormsGen1(species, types, forms, generation); if (species <= Legal.MaxSpeciesID_2) return GetFormsGen2(species, types, forms, generation); if (species <= Legal.MaxSpeciesID_3) return GetFormsGen3(species, types, forms); if (species <= Legal.MaxSpeciesID_4) return GetFormsGen4(species, types, forms, generation); if (species <= Legal.MaxSpeciesID_5) return GetFormsGen5(species, types, forms); if (species <= Legal.MaxSpeciesID_6) return GetFormsGen6(species, types, forms, genders); //if (species <= Legal.MaxSpeciesID_7) return GetFormsGen7(species, types, forms); } public static bool IsTotemForm(int species, int form, int generation = 7) { if (generation != 7) return false; if (form == 0) return false; if (!Legal.Totem_USUM.Contains(species)) return false; if (species == 778) // Mimikyu return form == 2 || form == 3; if (Legal.Totem_Alolan.Contains(species)) return form == 2; return form == 1; } public static int GetTotemBaseForm(int species, int form) { if (species == 778) // Mimikyu return form -2; return form - 1; } public static bool IsValidOutOfBoundsForme(int species, int form, int generation) { switch (species) { case 201: // Unown return form < (generation == 2 ? 26 : 28); // A-Z : A-Z?! case 414: // Wormadam base form is kept return form < 3; case 664: case 665: // Vivillon Pre-evolutions return form < 18; default: return false; } } private static readonly string[] EMPTY = {""}; private static string[] GetFormsGen1(int species, IReadOnlyList types, IReadOnlyList forms, int generation) { switch (species) { case 6: case 150: return new[] { types[000], // Normal forms[805], // Mega X forms[806], // Mega Y }; case 025: return GetFormsPikachu(generation, types, forms); default: return GetFormsAlolan(generation, types, forms, species); } } private static string[] GetFormsGen2(int species, IReadOnlyList types, IReadOnlyList forms, int generation) { switch (species) { default: return EMPTY; case 172: return GetFormsPichu(generation, types, forms); case 201: return GetFormsUnown(generation); } } private static string[] GetFormsGen3(int species, IReadOnlyList types, IReadOnlyList forms) { switch (species) { default: return EMPTY; case 351: // Casftorm return new[] { types[000], // Normal forms[889], // Sunny forms[890], // Rainy forms[891], // Snowy }; case 382: // Kyogre case 383: // Groudon return new[] { types[000], // Normal forms[899], // Primal }; case 386: // Deoxys return new[] { types[000], // Normal forms[902], // Attack forms[903], // Defense forms[904], // Speed }; } } private static string[] GetFormsGen4(int species, IReadOnlyList types, IReadOnlyList forms, int generation) { switch (species) { default: return EMPTY; case 412: case 413: case 414: return new[] { forms[412], // Plant forms[905], // Sandy forms[906], // Trash }; case 421: return new[] { forms[421], // Overcast forms[909], // Sunshine }; case 422: case 423: return new[] { forms[422], // West forms[911], // East }; case 479: return new[] { types[000], // Normal forms[917], // Heat forms[918], // Wash forms[919], // Frost forms[920], // Fan forms[921], // Mow }; case 487: return new[] { forms[487], // Altered forms[922], // Origin }; case 492: return new[] { forms[492], // Land forms[923], // Sky }; case 493: // Arceus case 773: // Silvally return GetFormsArceus(generation, types); } } private static string[] GetFormsGen5(int species, IReadOnlyList types, IReadOnlyList forms) { switch (species) { default: return EMPTY; case 550: return new[] { forms[550], // Red forms[942], // Blue }; case 555: return new[] { forms[555], // Standard forms[943], // Zen }; case 585: case 586: return new[] { forms[585], // Spring forms[947], // Summer forms[948], // Autumn forms[949], // Winter }; case 641: case 642: case 645: return new[] { forms[641], // Incarnate forms[952], // Therian }; case 646: return new[] { types[000], // Normal forms[953], // White forms[954], // Black }; case 647: return new[] { forms[647], // Ordinary forms[955], // Resolute }; case 648: return new[] { forms[648], // Aria forms[956], // Pirouette }; case 649: return new[] { types[000], // Normal types[010], // Douse (Water) types[012], // Shock (Electric) types[009], // Burn (Fire) types[014], // Chill (Ice) }; } } private static string[] GetFormsGen6(int species, IReadOnlyList types, IReadOnlyList forms, IReadOnlyList genders) { switch (species) { default: return EMPTY; case 658: return new[] { types[000], // Normal forms[962], // "Ash", forms[1012], // "Bonded" - Active }; case 664: case 665: case 666: return new[] { forms[666], // Icy Snow forms[963], // Polar forms[964], // Tundra forms[965], // Continental forms[966], // Garden forms[967], // Elegant forms[968], // Meadow forms[969], // Modern forms[970], // Marine forms[971], // Archipelago forms[972], // High-Plains forms[973], // Sandstorm forms[974], // River forms[975], // Monsoon forms[976], // Savannah forms[977], // Sun forms[978], // Ocean forms[979], // Jungle forms[980], // Fancy forms[981], // Poké Ball }; case 669: case 671: return new[] { forms[669], // Red forms[986], // Yellow forms[987], // Orange forms[988], // Blue forms[989], // White }; case 670: return new[] { forms[669], // Red forms[986], // Yellow forms[987], // Orange forms[988], // Blue forms[989], // White forms[990], // Eternal }; case 676: return new[] { forms[676], // Natural forms[995], // Heart forms[996], // Star forms[997], // Diamond forms[998], // Deputante forms[999], // Matron forms[1000], // Dandy forms[1001], // La Reine forms[1002], // Kabuki forms[1003], // Pharaoh }; case 678: return new[] { genders[000], // Male genders[001], // Female }; case 681: return new[] { forms[681], // Shield forms[1005], // Blade }; case 710: case 711: return new[] { forms[710], // Average forms[1006], // Small forms[1007], // Large forms[1008], // Super }; case 716: return new[] { forms[716], // Neutral forms[1012], // Active }; case 720: return new[] { forms[720], // Confined forms[1018], // Unbound }; case 718: // Zygarde return new[] { forms[718], // 50% (Aura Break) "10%", // (Aura Break) "10%-C", // Cell (Power Construct) "50%-C", // Cell (Power Construct) "100%-C" // Cell (Power Construct) }; } } private static string[] GetFormsGen7(int species, IReadOnlyList types, IReadOnlyList forms) { switch (species) { default: return EMPTY; case 741: // Oricorio return new[] { forms[741], // "RED" - Baile forms[1021], // "YLW" - Pom-Pom forms[1022], // "PNK" - Pa'u forms[1023], // "BLU" - Sensu }; case 744: // Rockruff return new[] { types[0], // Normal forms[1064], // Dusk }; case 745: // Lycanroc return new[] { forms[745], // Midday forms[1024], // Midnight forms[1064], // Dusk }; case 746: // Wishiwashi return new[] { forms[746], forms[1025], // School }; case 773: // Silvally return GetFormsArceus(7, types); case 774: // Minior return new[] { forms[774], // "R-Meteor", // Meteor Red forms[1045], // "O-Meteor", // Meteor Orange forms[1046], // "Y-Meteor", // Meteor Yellow forms[1047], // "G-Meteor", // Meteor Green forms[1048], // "B-Meteor", // Meteor Blue forms[1049], // "I-Meteor", // Meteor Indigo forms[1050], // "V-Meteor", // Meteor Violet forms[1051], // "R-Core", // Core Red forms[1052], // "O-Core", // Core Orange forms[1053], // "Y-Core", // Core Yellow forms[1054], // "G-Core", // Core Green forms[1055], // "B-Core", // Core Blue forms[1056], // "I-Core", // Core Indigo forms[1057], // "V-Core", // Core Violet }; case 800: return new[] { types[000], // Normal forms[1065], // Dusk Mane forms[1066], // Dawn Wings forms[1067], // Ultra Necrozma }; case 801: // Magearna return new[] { types[000], forms[1062], // Original }; } } private static string[] GetFormsAlolan (int generation, IReadOnlyList types, IReadOnlyList forms, int species) { if (generation < 7) return EMPTY; switch (species) { default: return EMPTY; case 19: // Rattata case 26: // Raichu case 27: // Sandshrew case 28: // Sandslash case 37: // Vulpix case 38: // Ninetails case 50: // Diglett case 51: // Dugtrio case 52: // Meowth case 53: // Persian case 74: // Geodude case 75: // Graveler case 76: // Golem case 88: // Grimer case 89: // Muk case 103: // Exeggutor return new[] { types[000], forms[810] // Alolan }; } } private static string[] GetFormsPikachu(int generation, IReadOnlyList types, IReadOnlyList forms) { switch (generation) { default: return EMPTY; case 6: return new[] { types[000], // Normal forms[729], // Rockstar forms[730], // Belle forms[731], // Pop forms[732], // PhD forms[733], // Libre forms[734], // Cosplay }; case 7: return new[] { types[000], // Normal forms[813], // Original forms[814], // Hoenn forms[815], // Sinnoh forms[816], // Unova forms[817], // Kalos forms[818], // Alola forms[1063] // Partner }; } } private static string[] GetFormsPichu (int generation, IReadOnlyList types, IReadOnlyList forms) { if (generation == 4) { return new[] { types[000], // Normal forms[000], // Spiky }; } return EMPTY; } private static string[] GetFormsArceus (int generation, IReadOnlyList types) { switch (generation) { case 4: return new[] { types[00], // Normal types[01], // Fighting types[02], // Flying types[03], // Poison types[04], // etc types[05], types[06], types[07], types[08], "???", // ???-type arceus types[09], types[10], types[11], types[12], types[13], types[14], types[15], types[16] // No Fairy Type }; case 5: return new[] { types[00], // Normal types[01], // Fighting types[02], // Flying types[03], // Poison types[04], // etc types[05], types[06], types[07], types[08], types[09], types[10], types[11], types[12], types[13], types[14], types[15], types[16] // No Fairy type }; default: return new[] { types[00], // Normal types[01], // Fighting types[02], // Flying types[03], // Poison types[04], // etc types[05], types[06], types[07], types[08], types[09], types[10], types[11], types[12], types[13], types[14], types[15], types[16], types[17], }; } } private static string[] GetFormsTotem (int species, IReadOnlyList types, IReadOnlyList forms) { if (species == 778) // Mimikyu { return new[] { forms[778], // Disguised forms[1058], // Busted forms[1007], // Large "*" + forms[1058], // Busted }; } if (Legal.Totem_Alolan.Contains(species)) { return new[] { types[0], // Normal forms[810], // Alolan forms[1007], // Large }; } return new[] { types[0], // Normal forms[1007], // Large }; } private static string[] GetFormsUnown(int generation) { switch (generation) { case 2: return new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", // "!", "?", not in Gen II }; default: return new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "!", "?", }; } } private static bool IsFormListSingleMega(int species) => Mega_6_Single.Contains(species); private static readonly HashSet Mega_6_Single = new HashSet { // XY 003, 009, 065, 094, 115, 127, 130, 142, 181, 212, 214, 229, 248, 257, 282, 303, 306, 308, 310, 354, 359, 380, 381, 445, 448, 460, // AO 015, 018, 080, 208, 254, 260, 302, 319, 323, 334, 362, 373, 376, 384, 428, 475, 531, 719, }; /// /// Checks if the data should have a drop-down selection visible for the value. /// /// Game specific personal info /// ID /// ID /// True if has formes that can be provided by , otherwise false for none. public static bool HasFormSelection(PersonalInfo pi, int species, int format) { if (format <= 3 && species != 201) return false; if (HasFormeValuesNotIndicatedByPersonal.Contains(species)) return true; int count = pi.FormeCount; return count > 1; } private static readonly HashSet HasFormeValuesNotIndicatedByPersonal = new HashSet { 201, // Unown 414, // Mothim (Burmy forme carried over, not cleared) 664, 665, // Vivillon pre-evos }; } }