diff --git a/PKHeX.Core/Editing/WurmpleUtil.cs b/PKHeX.Core/Editing/WurmpleUtil.cs index 17d5cc95c..06564ae2e 100644 --- a/PKHeX.Core/Editing/WurmpleUtil.cs +++ b/PKHeX.Core/Editing/WurmpleUtil.cs @@ -28,6 +28,12 @@ public static WurmpleEvolution GetWurmpleEvoGroup(ushort species) return (WurmpleEvolution)(wIndex >> 1); // Silcoon, Cascoon } + /// + /// Checks to see if the input species is a Wurmple evolution + /// + /// True if Wurmple evolution, false if not + public static bool IsWurmpleEvo(ushort species) => GetWurmpleEvoGroup(species) != WurmpleEvolution.None; + /// /// Gets the Wurmple for a given Evolution Value /// diff --git a/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator8GO.cs b/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator8GO.cs index ab7ea3ad6..1952a7781 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator8GO.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator8GO.cs @@ -13,6 +13,7 @@ public record struct EncounterEnumerator8GO(PKM Entity, EvoCriteria[] Chain) : I private int Index; private int EvoIndex; private int SubIndex; + private SeekMode Mode; private EncounterMatchRating Rating = EncounterMatchRating.MaxNotMatch; public MatchedEncounter Current { get; private set; } private YieldState State; @@ -26,11 +27,19 @@ private enum YieldState : byte { Start, Seek, + SeekForward, + SeekReverse, Slot, Fallback, End, } + public enum SeekMode : byte + { + Forward, + Reverse, + } + public bool MoveNext() { switch (State) @@ -40,12 +49,24 @@ public bool MoveNext() break; if (!EncounterStateUtil.CanBeWildEncounter(Entity)) break; + Mode = GetSeekMode(); + if (Mode == SeekMode.Reverse) + Index = EncountersGO.SlotsGO.Length - 1; State = YieldState.Seek; goto case YieldState.Seek; case YieldState.Seek: - if (!SeekNextArea(EncountersGO.SlotsGO)) + if (Mode == SeekMode.Forward) + { State = YieldState.SeekForward; goto case YieldState.SeekForward; } + State = YieldState.SeekReverse; goto case YieldState.SeekReverse; + case YieldState.SeekForward: + if (!SeekForward(EncountersGO.SlotsGO)) goto case YieldState.Fallback; State = YieldState.Slot; goto case YieldState.Slot; + case YieldState.SeekReverse: + if (!SeekReverse(EncountersGO.SlotsGO)) + goto case YieldState.Fallback; + State = YieldState.Slot; goto case YieldState.Slot; + case YieldState.Slot: var group = EncountersGO.SlotsGO[Index]; if (TryGetNext(group.Slots)) @@ -61,7 +82,7 @@ public bool MoveNext() return false; } - private bool SeekNextArea(TArea[] areas) + private bool SeekForward(TArea[] areas) where TArea : ISpeciesForm { for (; Index < areas.Length; Index++, EvoIndex = 0) @@ -77,6 +98,41 @@ private bool SeekNextArea(TArea[] areas) return false; } + private bool SeekReverse(TArea[] areas) where TArea : ISpeciesForm + { + for (; Index > 0; Index--, EvoIndex = 0) // Only difference -- search in reverse! + { + var area = areas[Index]; + do + { + if (IsCompatible(area, Chain[EvoIndex])) + return true; + } + while (++EvoIndex < Chain.Length); + } + return false; + } + + private readonly SeekMode GetSeekMode() + { + var species = Entity.Species; + if (species is (int)Species.Dudunsparce or (int)Species.Maushold) + { + if (!EvolutionRestrictions.GetIsExpectedEvolveFormEC100(species, Entity.Form, Entity.EncryptionConstant % 100 == 0)) + return SeekMode.Reverse; + } + else if (EvolutionRestrictions.IsFormArgEvolution(species)) + { + if (Entity is IFormArgument { FormArgument: 0 }) + return SeekMode.Reverse; + } + else if (WurmpleUtil.IsWurmpleEvo(species) && !WurmpleUtil.IsWurmpleEvoValid(Entity)) + { + return SeekMode.Reverse; + } + return SeekMode.Forward; + } + private readonly bool IsCompatible(TArea area, EvoCriteria evo) where TArea : ISpeciesForm { if (area.Species != evo.Species) @@ -108,7 +164,11 @@ private bool TryGetNext(TSlot[] slots) Rating = rating; } } - EvoIndex = 0; SubIndex = 0; Index++; + EvoIndex = 0; SubIndex = 0; + if (Mode == SeekMode.Forward) + Index++; + else + Index--; return false; } diff --git a/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs b/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs index a46279e13..f69170edd 100644 --- a/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs +++ b/PKHeX.Core/Legality/Restrictions/EvolutionRestrictions.cs @@ -36,6 +36,29 @@ internal static class EvolutionRestrictions _ => NONE, }; + /// + /// Gets the species-form that it will evolve into. + /// + /// + public static (ushort Species, byte Form) GetEvolvedSpeciesFormEC100(ushort species, bool rare) => species switch + { + (ushort)Tandemaus => ((ushort)Maushold, (byte)(rare ? 0 : 1)), + (ushort)Dunsparce => ((ushort)Dudunsparce, (byte)(rare ? 1 : 0)), + _ => throw new ArgumentOutOfRangeException(nameof(species), species, "Incorrect EC%100 species."), + }; + + public static bool GetIsExpectedEvolveFormEC100(ushort species, byte form, bool rare) => species switch + { + (ushort)Maushold => form == (byte)(rare ? 0 : 1), + (ushort)Dudunsparce => form == (byte)(rare ? 1 : 0), + _ => throw new ArgumentOutOfRangeException(nameof(species), species, "Incorrect EC%100 species."), + }; + + public static bool IsFormArgEvolution(ushort species) + { + return species is (int)Runerigus or (int)Wyrdeer or (int)Annihilape or (int)Basculegion or (int)Kingambit or (int)Overqwil; + } + private const ushort NONE = 0; private const ushort EEVEE = ushort.MaxValue; diff --git a/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs b/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs index 18c3c52d9..7da5e2734 100644 --- a/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs @@ -1,4 +1,3 @@ -using System; using static PKHeX.Core.LegalityCheckStrings; namespace PKHeX.Core; @@ -105,20 +104,13 @@ private static void VerifyEC100(LegalityAnalysis data, ushort encSpecies) // Indicate the evolution for the user. uint evoVal = pk.EncryptionConstant % 100; bool rare = evoVal == 0; - var (species, form) = GetEvolvedSpeciesForm(encSpecies, rare); + var (species, form) = EvolutionRestrictions.GetEvolvedSpeciesFormEC100(encSpecies, rare); var str = GameInfo.Strings; var forms = FormConverter.GetFormList(species, str.Types, str.forms, GameInfo.GenderSymbolASCII, EntityContext.Gen9); var msg = string.Format(L_XRareFormEvo_0_1, forms[form], rare); data.AddLine(GetValid(msg, CheckIdentifier.EC)); } - private static (ushort, int) GetEvolvedSpeciesForm(ushort species, bool rare) => species switch - { - (int)Species.Tandemaus => ((ushort)Species.Maushold, rare ? 0 : 1), - (int)Species.Dunsparce => ((ushort)Species.Dudunsparce, rare ? 1 : 0), - _ => throw new ArgumentOutOfRangeException(nameof(species), species, "Incorrect EC%100 species."), - }; - private static void VerifyEC(LegalityAnalysis data) { var pk = data.Entity; diff --git a/PKHeX.Core/Resources/legality/wild/encounter_go_home.pkl b/PKHeX.Core/Resources/legality/wild/encounter_go_home.pkl index 23196e548..d6c7e8653 100644 Binary files a/PKHeX.Core/Resources/legality/wild/encounter_go_home.pkl and b/PKHeX.Core/Resources/legality/wild/encounter_go_home.pkl differ diff --git a/PKHeX.Core/Resources/legality/wild/encounter_go_lgpe.pkl b/PKHeX.Core/Resources/legality/wild/encounter_go_lgpe.pkl index d989ce6a4..7747d1f07 100644 Binary files a/PKHeX.Core/Resources/legality/wild/encounter_go_lgpe.pkl and b/PKHeX.Core/Resources/legality/wild/encounter_go_lgpe.pkl differ