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)