diff --git a/PKHeX.Core/Legality/Tables/AltFormInfo.cs b/PKHeX.Core/Legality/Tables/AltFormInfo.cs new file mode 100644 index 000000000..a145bfd2b --- /dev/null +++ b/PKHeX.Core/Legality/Tables/AltFormInfo.cs @@ -0,0 +1,145 @@ +using System.Collections.Generic; + +namespace PKHeX.Core +{ + public static class AltFormInfo + { + /// + /// Checks if the form cannot exist outside of a Battle. + /// + /// Entity species + /// Entity form + /// Current generation format + /// True if it can only exist in a battle, false if it can exist outside of battle. + public static bool IsBattleOnlyForm(int species, int form, int format) + { + if (!BattleOnly.Contains(species)) + return false; + + // Some species have battle only forms as well as out-of-battle forms (other than base form). + switch (species) + { + case (int)Species.Slowbro when form == 2 && format >= 8: // Only mark Ultra Necrozma as Battle Only + case (int)Species.Darmanitan when form == 2 && format >= 8: // this one is OK, Galarian Slowbro (not a Mega) + case (int)Species.Zygarde when form < 4: // Zygarde Complete + case (int)Species.Mimikyu when form == 2: // Totem disguise Mimikyu + case (int)Species.Necrozma when form < 3: // this one is OK, Galarian non-Zen + case (int)Species.Minior when form >= 7: // Minior Shields-Down + return false; + + default: + return true; + } + } + + /// + /// Reverts the Battle Form to the form it would have outside of Battle. + /// + /// Only call this if you've already checked that returns true. + /// Entity species + /// Entity form + /// Current generation format + /// Suggested alt form value. + public static int GetOutOfBattleForm(int species, int form, int format) + { + return species switch + { + (int)Species.Darmanitan => form & 2, + (int)Species.Zygarde when format > 6 => 3, + (int)Species.Minior => form + 7, + _ => 0 + }; + } + + /// + /// Checks if the is a fused form, which indicates it cannot be traded away. + /// + /// Entity species + /// Entity form + /// Current generation format + /// True if it is a fused species-form, false if it is not fused. + public static bool IsFusedForm(int species, int form, int format) + { + return species switch + { + (int)Species.Kyurem when form != 0 && format >= 5 => true, + (int)Species.Necrozma when form != 0 && format >= 7 => true, + (int)Species.Calyrex when form != 0 && format >= 8 => true, + _ => false + }; + } + + /// + /// Species that have an alternate form that cannot exist outside of battle. + /// + private static readonly HashSet BattleForms = new HashSet + { + (int)Species.Castform, + (int)Species.Cherrim, + (int)Species.Darmanitan, + (int)Species.Meloetta, + (int)Species.Aegislash, + (int)Species.Xerneas, + (int)Species.Zygarde, + + (int)Species.Wishiwashi, + (int)Species.Mimikyu, + + (int)Species.Cramorant, + (int)Species.Morpeko, + (int)Species.Eiscue, + + (int)Species.Zacian, + (int)Species.Zamazenta, + (int)Species.Eternatus, + }; + + /// + /// Species that have a mega form that cannot exist outside of battle. + /// + /// Using a held item to change form during battle, via an in-battle transformation feature. + private static readonly HashSet BattleMegas = new HashSet + { + // XY + (int)Species.Venusaur, (int)Species.Charizard, (int)Species.Blastoise, + (int)Species.Alakazam, (int)Species.Gengar, (int)Species.Kangaskhan, (int)Species.Pinsir, + (int)Species.Gyarados, (int)Species.Aerodactyl, (int)Species.Mewtwo, + + (int)Species.Ampharos, (int)Species.Scizor, (int)Species.Heracross, (int)Species.Houndoom, (int)Species.Tyranitar, + + (int)Species.Blaziken, (int)Species.Gardevoir, (int)Species.Mawile, (int)Species.Aggron, (int)Species.Medicham, + (int)Species.Manectric, (int)Species.Banette, (int)Species.Absol, (int)Species.Latios, (int)Species.Latias, + + (int)Species.Garchomp, (int)Species.Lucario, (int)Species.Abomasnow, + + // AO + (int)Species.Beedrill, (int)Species.Pidgeot, (int)Species.Slowbro, + + (int)Species.Steelix, + + (int)Species.Sceptile, (int)Species.Swampert, (int)Species.Sableye, (int)Species.Sharpedo, (int)Species.Camerupt, + (int)Species.Altaria, (int)Species.Glalie, (int)Species.Salamence, (int)Species.Metagross, (int)Species.Rayquaza, + + (int)Species.Lopunny, (int)Species.Gallade, + (int)Species.Audino, (int)Species.Diancie, + + // USUM + (int)Species.Necrozma, // Ultra Necrozma + }; + + /// + /// Species that have a primal form that cannot exist outside of battle. + /// + private static readonly HashSet BattlePrimals = new HashSet { 382, 383 }; + + private static readonly HashSet BattleOnly = GetBattleFormSet(); + + private static HashSet GetBattleFormSet() + { + var hs = new HashSet(BattleForms); + hs.UnionWith(BattleMegas); + hs.UnionWith(BattlePrimals); + return hs; + } + } +} diff --git a/PKHeX.Core/Legality/Tables/Tables.cs b/PKHeX.Core/Legality/Tables/Tables.cs index 05b474a78..6fdcbb420 100644 --- a/PKHeX.Core/Legality/Tables/Tables.cs +++ b/PKHeX.Core/Legality/Tables/Tables.cs @@ -257,58 +257,6 @@ namespace PKHeX.Core 809, // Melmetal }; - /// - /// Species that have an alternate form that cannot exist outside of battle. - /// - public static readonly HashSet BattleForms = new HashSet - { - 351, // Castform - 421, // Cherrim - 555, // Darmanitan - 648, // Meloetta - 681, // Aegislash - 716, // Xerneas - 746, // Wishiwashi - 778, // Mimikyu - - (int)Species.Cramorant, - (int)Species.Morpeko, - (int)Species.Eiscue, - - (int)Species.Zacian, - (int)Species.Zamazenta, - (int)Species.Eternatus, - }; - - /// - /// Species that have a mega form that cannot exist outside of battle. - /// - public static readonly HashSet BattleMegas = new HashSet - { - // XY - 3,6,9,65,80, - 115,127,130,142,150,181, - 212,214,229,248,282, - 303,306,308,310,354,359,380,381, - 445,448,460, - - // AO - 15,18,94, - 208,254,257,260, - 302,319,323,334,362,373,376,384, - 428,475, - 531, - 719, - - // USUM - 800, // Ultra Necrozma - }; - - /// - /// Species that have a primal form that cannot exist outside of battle. - /// - public static readonly HashSet BattlePrimals = new HashSet { 382, 383 }; - public static readonly HashSet Z_Moves = new HashSet { 622, 623, 624, 625, 626, 627, 628, 629, 630, 631, 632, 633, 634, 635, 636, 637, 638, 639, 640, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650, 651, 652, 653, 654, 655, 656, 657, 658, diff --git a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs index fe301035e..1b8681c7b 100644 --- a/PKHeX.Core/Legality/Verifiers/FormVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/FormVerifier.cs @@ -173,22 +173,16 @@ namespace PKHeX.Core if (form != 0 && pkm.Box > -1 && pkm.Format <= 6) // has form but stored in box return GetInvalid(LFormParty); break; - - // Battle only Forms with other legal forms allowed - case (int)Species.Zygarde when form >= 4: // Zygarde Complete - case (int)Species.Minior when form < 7: // Minior Shield - case (int)Species.Necrozma when form == 3: // Ultra Necrozma - return GetInvalid(LFormBattle); - case (int)Species.Necrozma when form < 3: // Necrozma Fused forms & default - case (int)Species.Mimikyu when form == 2: // Totem disguise Mimikyu - return VALID; } + var format = pkm.Format; + if (AltFormInfo.IsBattleOnlyForm(species, form, format)) + return GetInvalid(LFormBattle); + if (form == 0) return VALID; // everything below here is currently an altform - var format = pkm.Format; if (format >= 7 && Info.Generation < 7) { if (species == 25 || Legal.AlolanOriginForms.Contains(species) || Legal.AlolanVariantEvolutions12.Contains(data.EncounterOriginal.Species)) @@ -214,25 +208,9 @@ namespace PKHeX.Core } } - if (IsBattleOnlyForm(species, form, format)) - return GetInvalid(LFormBattle); - return VALID; } - public static bool IsBattleOnlyForm(int species, int form, int format) - { - if (!BattleOnly.Contains(species)) - return false; - if (species == (int) Species.Darmanitan && form == 2 && format >= 8) - return false; // this one is OK, Galarian non-Zen - if (species == (int) Species.Slowbro && form == 2 && format >= 8) - return false; // this one is OK, Galarian Slowbro (not a Mega) - if (species == (int) Species.Necrozma && form != 3) - return false; // Only mark Ultra Necrozma as Battle Only - return true; - } - public static int GetArceusFormFromHeldItem(int item, int format) { if (777 <= item && item <= 793) @@ -260,17 +238,6 @@ namespace PKHeX.Core return 0; } - private static readonly HashSet BattleOnly = GetBattleFormSet(); - - private static HashSet GetBattleFormSet() - { - var hs = new HashSet(); - hs.UnionWith(Legal.BattleForms); - hs.UnionWith(Legal.BattleMegas); - hs.UnionWith(Legal.BattlePrimals); - return hs; - } - private static readonly HashSet SafariFloette = new HashSet { 0, 1, 3 }; // 0/1/3 - RBY private void VerifyFormFriendSafari(LegalityAnalysis data)