diff --git a/PKHeX.Core/Legality/Areas/EncounterArea4.cs b/PKHeX.Core/Legality/Areas/EncounterArea4.cs index 82563ee81..3d45bef9d 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea4.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea4.cs @@ -73,7 +73,7 @@ private IEnumerable GetSlotsMatching(IReadOnlyList c if (slot.Species != evo.Species) continue; - if (slot.Form != evo.Form && !Legal.WildChangeFormAfter.Contains(slot.Species) && slot.Species != (int)Species.Unown) + if (slot.Form != evo.Form && !AltFormInfo.WildChangeFormAfter.Contains(slot.Species) && slot.Species != (int)Species.Unown) break; if (!slot.IsLevelWithinRange(lvl)) break; @@ -93,7 +93,7 @@ private IEnumerable GetSlotsFuzzy(IReadOnlyList chai if (slot.Species != evo.Species) continue; - if (slot.Form != evo.Form && !Legal.WildChangeFormAfter.Contains(slot.Species) && slot.Species != (int)Species.Unown) + if (slot.Form != evo.Form && !AltFormInfo.WildChangeFormAfter.Contains(slot.Species) && slot.Species != (int)Species.Unown) break; if (slot.LevelMin > evo.Level) break; diff --git a/PKHeX.Core/Legality/Areas/EncounterArea5.cs b/PKHeX.Core/Legality/Areas/EncounterArea5.cs index 085a587a2..ebd469552 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea5.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea5.cs @@ -56,7 +56,7 @@ public override IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyLi if (!slot.IsLevelWithinRange(pkm.Met_Level)) break; - if (slot.Form != evo.Form && !Legal.WildChangeFormAfter.Contains(slot.Species)) + if (slot.Form != evo.Form && !AltFormInfo.WildChangeFormAfter.Contains(slot.Species)) break; yield return slot; diff --git a/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs b/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs index 287d5d8dd..a2567d4fe 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea6XY.cs @@ -75,7 +75,7 @@ public override IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyLi if (!slot.IsLevelWithinRange(pkm.Met_Level)) break; - if (slot.Form != evo.Form && slot.Form < RandomFormVivillon && !Legal.WildChangeFormAfter.Contains(slot.Species)) + if (slot.Form != evo.Form && slot.Form < RandomFormVivillon && !AltFormInfo.WildChangeFormAfter.Contains(slot.Species)) { if (slot.Species != (int)Species.Flabébé) break; diff --git a/PKHeX.Core/Legality/Areas/EncounterArea7.cs b/PKHeX.Core/Legality/Areas/EncounterArea7.cs index 7bc9fb900..0afe24c1b 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea7.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea7.cs @@ -56,7 +56,7 @@ public override IEnumerable GetMatchingSlots(PKM pkm, IReadOnlyLi if (!slot.IsLevelWithinRange(pkm.Met_Level)) break; - if (slot.Form != evo.Form && !Legal.WildChangeFormAfter.Contains(slot.Species)) + if (slot.Form != evo.Form && !AltFormInfo.WildChangeFormAfter.Contains(slot.Species)) { if (slot.Species != (int)Species.Minior) // Random Color, edge case break; diff --git a/PKHeX.Core/Legality/Areas/EncounterArea8.cs b/PKHeX.Core/Legality/Areas/EncounterArea8.cs index 4ea883e36..72a18439f 100644 --- a/PKHeX.Core/Legality/Areas/EncounterArea8.cs +++ b/PKHeX.Core/Legality/Areas/EncounterArea8.cs @@ -49,7 +49,7 @@ private IEnumerable GetUnboostedMatches(IReadOnlyList GetBoostedMatches(IReadOnlyList // Ignore met level comparison; we already know it is permissible to boost to level 60. - if (slot.Form != evo.Form && !Legal.WildChangeFormAfter.Contains(evo.Species)) + if (slot.Form != evo.Form && !AltFormInfo.WildChangeFormAfter.Contains(evo.Species)) break; yield return slot; diff --git a/PKHeX.Core/Legality/Core.cs b/PKHeX.Core/Legality/Core.cs index c9f931ff5..bf41ff0d3 100644 --- a/PKHeX.Core/Legality/Core.cs +++ b/PKHeX.Core/Legality/Core.cs @@ -183,51 +183,6 @@ internal static int GetMaxLanguageID(int generation) }; } - internal static bool IsEvolutionValid(PKM pkm, int minSpecies = -1, int minLevel = -1) - { - var curr = EvolutionChain.GetValidPreEvolutions(pkm, minLevel: minLevel); - var min = curr.FindLast(z => z.Species == minSpecies); - if (min != null && min.Level < minLevel) - return false; - var poss = EvolutionChain.GetValidPreEvolutions(pkm, maxLevel: 100, minLevel: minLevel, skipChecks: true); - - if (minSpecies != -1) - { - int last = poss.FindLastIndex(z => z.Species == minSpecies); - return curr.Count >= last; - } - int gen = pkm.GenNumber; - if (gen >= 3 && GetSplitBreedGeneration(gen).Contains(EvoBase.GetBaseSpecies(poss, 1).Species)) - return curr.Count >= poss.Count - 1; - return curr.Count >= poss.Count; - } - - /// Checks if the form may be different than the original encounter detail. - /// Original species - /// Original form - /// Current form - /// Current format - internal static bool IsFormChangeable(int species, int oldForm, int newForm, int format) - { - if (FormChange.Contains(species)) - return true; - - // Zygarde Form Changing - // Gen6: Introduced; no form changing. - // Gen7: Form changing introduced; can only change to Form 2/3 (Power Construct), never to 0/1 (Aura Break). A form-1 can be boosted to form-0. - // Gen8: Form changing improved; can pick any Form & Ability combination. - if (species == (int)Species.Zygarde) - { - return format switch - { - 6 => false, - 7 => newForm >= 2 || (oldForm == 1 && newForm == 0), - _ => true, - }; - } - return false; - } - internal static bool GetCanInheritMoves(int species) { if (FixedGenderFromBiGender.Contains(species)) // Nincada -> Shedinja loses gender causing 'false', edge case @@ -267,15 +222,6 @@ internal static bool GetCanKnowMove(PKM pkm, int move, int generation, IReadOnly internal static bool HasVisitedUSUM(this PKM pkm, int species) => pkm.InhabitedGeneration(7, species) && (pkm.USUM || !pkm.IsUntraded); internal static bool IsMovesetRestricted(this PKM pkm, int gen) => (pkm.GG && gen == 7) || pkm.IsUntraded; - public static bool HasMetLocationUpdatedTransfer(int originalGeneration, int currentGeneration) - { - if (originalGeneration < 3) - return currentGeneration >= 3; - if (originalGeneration <= 4) - return currentGeneration != originalGeneration; - return false; - } - public static bool IsValidMissingLanguage(PKM pkm) { return pkm.Format == 5 && pkm.BW; diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs index e186d810a..aa329ee22 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic.cs @@ -257,7 +257,7 @@ protected virtual bool IsMatchForm(PKM pkm, DexLevel evo) { if (SkipFormCheck) return true; - return Form == evo.Form || Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format); + return Form == evo.Form || AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format); } protected virtual bool IsMatchEggLocation(PKM pkm) diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs index ce53ab99b..8b2fda96b 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic/EncounterStatic7.cs @@ -26,7 +26,7 @@ protected override bool IsMatchForm(PKM pkm, DexLevel evo) return expectForm == evo.Form; } - return Form == evo.Form || Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format); + return Form == evo.Form || AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format); } protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteria, PKM pk) diff --git a/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs b/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs index e6f3861cd..c5f765cbf 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTrade/EncounterTrade.cs @@ -242,7 +242,7 @@ public virtual bool IsMatch(PKM pkm, DexLevel evo) if (CurrentLevel != -1 && CurrentLevel > pkm.CurrentLevel) return false; - if (Form != evo.Form && !Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) + if (Form != evo.Form && !AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) return false; if (OTGender != -1 && OTGender != pkm.OT_Gender) return false; diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs index d14ffef86..cec0dbb2a 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterEggGenerator.cs @@ -146,5 +146,24 @@ private static bool GetCanBeEgg2(PKM pkm) return pkm.CurrentLevel >= 5; } + + private static bool IsEvolutionValid(PKM pkm, int minSpecies = -1, int minLevel = -1) + { + var curr = EvolutionChain.GetValidPreEvolutions(pkm, minLevel: minLevel); + var min = curr.FindLast(z => z.Species == minSpecies); + if (min != null && min.Level < minLevel) + return false; + var poss = EvolutionChain.GetValidPreEvolutions(pkm, maxLevel: 100, minLevel: minLevel, skipChecks: true); + + if (minSpecies != -1) + { + int last = poss.FindLastIndex(z => z.Species == minSpecies); + return curr.Count >= last; + } + int gen = pkm.GenNumber; + if (gen >= 3 && GetSplitBreedGeneration(gen).Contains(EvoBase.GetBaseSpecies(poss, 1).Species)) + return curr.Count >= poss.Count - 1; + return curr.Count >= poss.Count; + } } } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs b/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs index d2c9cfaec..7ca95de86 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionChain.cs @@ -136,6 +136,15 @@ private static List[] GetChainAll(PKM pkm, IEncounterable enc, IRea return GensEvoChains; } + private static bool HasMetLocationUpdatedTransfer(int originalGeneration, int currentGeneration) + { + if (originalGeneration < 3) + return currentGeneration >= 3; + if (originalGeneration <= 4) + return currentGeneration != originalGeneration; + return false; + } + private static void TrimVC1Transfer(PKM pkm, IList> GensEvoChains) { if (GensEvoChains[7].All(z => z.Species > MaxSpeciesID_1)) diff --git a/PKHeX.Core/Legality/Tables/AltFormInfo.cs b/PKHeX.Core/Legality/Tables/AltFormInfo.cs index 9c9d2cb3f..3b7fe3dba 100644 --- a/PKHeX.Core/Legality/Tables/AltFormInfo.cs +++ b/PKHeX.Core/Legality/Tables/AltFormInfo.cs @@ -73,6 +73,65 @@ public static bool IsFusedForm(int species, int form, int format) }; } + /// Checks if the form may be different than the original encounter detail. + /// Original species + /// Original form + /// Current form + /// Current format + public static bool IsFormChangeable(int species, int oldForm, int newForm, int format) + { + if (FormChange.Contains(species)) + return true; + + // Zygarde Form Changing + // Gen6: Introduced; no form changing. + // Gen7: Form changing introduced; can only change to Form 2/3 (Power Construct), never to 0/1 (Aura Break). A form-1 can be boosted to form-0. + // Gen8: Form changing improved; can pick any Form & Ability combination. + if (species == (int)Zygarde) + { + return format switch + { + 6 => false, + 7 => newForm >= 2 || (oldForm == 1 && newForm == 0), + _ => true, + }; + } + return false; + } + + /// + /// Species that can be captured normally in the wild and can change between their forms. + /// + public static readonly HashSet WildChangeFormAfter = new HashSet + { + 412, // Burmy + 479, // Rotom + 676, // Furfrou + 741, // Oricorio + }; + + /// + /// Species that can change between their forms, regardless of origin. + /// + /// Excludes Zygarde as it has special conditions. Check separately. + private static readonly HashSet FormChange = new HashSet(WildChangeFormAfter) + { + 386, // Deoxys + 487, // Giratina + 492, // Shaymin + 493, // Arceus + 641, // Tornadus + 642, // Thundurus + 645, // Landorus + 646, // Kyurem + 647, // Keldeo + 649, // Genesect + 720, // Hoopa + 773, // Silvally + 800, // Necrozma + 898, // Calyrex + }; + /// /// Species that have an alternate form that cannot exist outside of battle. /// diff --git a/PKHeX.Core/Legality/Tables/Tables.cs b/PKHeX.Core/Legality/Tables/Tables.cs index 32d26ab8e..1df5d6074 100644 --- a/PKHeX.Core/Legality/Tables/Tables.cs +++ b/PKHeX.Core/Legality/Tables/Tables.cs @@ -9,17 +9,6 @@ public static partial class Legal /// public static readonly HashSet LightBall = new HashSet { 25, 26, 172 }; - /// - /// Species that can be captured normally in the wild and can change between their forms. - /// - public static readonly HashSet WildChangeFormAfter = new HashSet - { - 412, // Burmy - 479, // Rotom - 676, // Furfrou - 741, // Oricorio - }; - /// /// Species that can yield a different baby species when bred. /// @@ -37,28 +26,6 @@ public static partial class Legal 358, // Chimecho }; - /// - /// Species that can change between their forms, regardless of origin. - /// - /// Excludes Zygarde as it has special conditions. Check separately. - public static readonly HashSet FormChange = new HashSet(WildChangeFormAfter) - { - 386, // Deoxys - 487, // Giratina - 492, // Shaymin - 493, // Arceus - 641, // Tornadus - 642, // Thundurus - 645, // Landorus - 646, // Kyurem - 647, // Keldeo - 649, // Genesect - 720, // Hoopa - 773, // Silvally - 800, // Necrozma - 898, // Calyrex - }; - /// /// Species that can change between their forms and get access to form-specific moves. /// diff --git a/PKHeX.Core/MysteryGifts/PCD.cs b/PKHeX.Core/MysteryGifts/PCD.cs index 258102050..50db6d359 100644 --- a/PKHeX.Core/MysteryGifts/PCD.cs +++ b/PKHeX.Core/MysteryGifts/PCD.cs @@ -157,7 +157,7 @@ protected override bool IsMatchExact(PKM pkm, DexLevel evo) return false; } - if (wc.AltForm != evo.Form && !Legal.IsFormChangeable(wc.Species, wc.AltForm, pkm.AltForm, pkm.Format)) + if (wc.AltForm != evo.Form && !AltFormInfo.IsFormChangeable(wc.Species, wc.AltForm, pkm.AltForm, pkm.Format)) return false; if (wc.Ball != pkm.Ball) return false; diff --git a/PKHeX.Core/MysteryGifts/PGF.cs b/PKHeX.Core/MysteryGifts/PGF.cs index a9242af5d..b84f92500 100644 --- a/PKHeX.Core/MysteryGifts/PGF.cs +++ b/PKHeX.Core/MysteryGifts/PGF.cs @@ -369,7 +369,7 @@ protected override bool IsMatchExact(PKM pkm, DexLevel evo) return false; } - if (Form != evo.Form && !Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) + if (Form != evo.Form && !AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) return false; if (Level != pkm.Met_Level) return false; diff --git a/PKHeX.Core/MysteryGifts/WB7.cs b/PKHeX.Core/MysteryGifts/WB7.cs index 6d09f95f0..5ee0b569b 100644 --- a/PKHeX.Core/MysteryGifts/WB7.cs +++ b/PKHeX.Core/MysteryGifts/WB7.cs @@ -471,7 +471,7 @@ protected override bool IsMatchExact(PKM pkm, DexLevel evo) if (EncryptionConstant != 0 && EncryptionConstant != pkm.EncryptionConstant) return false; } - if (Form != evo.Form && !Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) + if (Form != evo.Form && !AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) return false; if (IsEgg) diff --git a/PKHeX.Core/MysteryGifts/WC3.cs b/PKHeX.Core/MysteryGifts/WC3.cs index 8a8b44d69..db36314ef 100644 --- a/PKHeX.Core/MysteryGifts/WC3.cs +++ b/PKHeX.Core/MysteryGifts/WC3.cs @@ -249,7 +249,7 @@ protected override bool IsMatchExact(PKM pkm, DexLevel evo) } } - if (Form != evo.Form && !Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) + if (Form != evo.Form && !AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) return false; if (Language != -1 && Language != pkm.Language) return false; diff --git a/PKHeX.Core/MysteryGifts/WC6.cs b/PKHeX.Core/MysteryGifts/WC6.cs index 64deaa186..142ccb713 100644 --- a/PKHeX.Core/MysteryGifts/WC6.cs +++ b/PKHeX.Core/MysteryGifts/WC6.cs @@ -487,7 +487,7 @@ protected override bool IsMatchExact(PKM pkm, DexLevel evo) if (EncryptionConstant != 0 && EncryptionConstant != pkm.EncryptionConstant) return false; if (Language != 0 && Language != pkm.Language) return false; } - if (Form != evo.Form && !Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) + if (Form != evo.Form && !AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) return false; if (IsEgg) diff --git a/PKHeX.Core/MysteryGifts/WC7.cs b/PKHeX.Core/MysteryGifts/WC7.cs index 51daa698d..6f96082ef 100644 --- a/PKHeX.Core/MysteryGifts/WC7.cs +++ b/PKHeX.Core/MysteryGifts/WC7.cs @@ -518,7 +518,7 @@ protected override bool IsMatchExact(PKM pkm, DexLevel evo) if (Language != 0 && Language != pkm.Language) return false; } - if (Form != evo.Form && !Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) + if (Form != evo.Form && !AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) return false; if (IsEgg) diff --git a/PKHeX.Core/MysteryGifts/WC8.cs b/PKHeX.Core/MysteryGifts/WC8.cs index 35b5f5cf5..ac1c28e4f 100644 --- a/PKHeX.Core/MysteryGifts/WC8.cs +++ b/PKHeX.Core/MysteryGifts/WC8.cs @@ -561,7 +561,7 @@ protected override bool IsMatchExact(PKM pkm, DexLevel evo) } } - if (Form != evo.Form && !Legal.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) + if (Form != evo.Form && !AltFormInfo.IsFormChangeable(Species, Form, pkm.AltForm, pkm.Format)) return false; if (IsEgg)