diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs index 8ed97eefb..3b45f1f06 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen4/EncounterArea4.cs @@ -161,3 +161,10 @@ public enum SlotType4 : byte Safari_Good_Rod = 13, Safari_Super_Rod = 14, } + +public static class SlotType4Extensions +{ + public static bool IsSafari(this SlotType4 type) => type >= SlotType4.Safari_Grass; + public static bool IsLevelRandDPPt(this SlotType4 type) => type != SlotType4.Grass; + public static bool IsLevelRandHGSS(this SlotType4 type) => type != SlotType4.Grass && !type.IsSafari(); +} diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs index 326e312f9..74b9dde22 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodJ.cs @@ -148,7 +148,7 @@ public static class MethodJ /// /// Attempts to find a matching seed for the given encounter and constraints for Cute Charm buffered PIDs. /// - public static bool TryGetMatchCuteCharm(T enc, ReadOnlySpan seeds, byte nature, byte levelMin, byte levelMax, out uint result) + public static bool TryGetMatchCuteCharm(T enc, ReadOnlySpan seeds, byte nature, byte levelMin, byte levelMax, byte format, out uint result) where T : IEncounterSlot4 { foreach (uint seed in seeds) @@ -157,7 +157,7 @@ public static class MethodJ var reg = GetNature(p0) == nature; if (!reg) continue; - var ctx = new FrameCheckDetails(enc, seed, levelMin, levelMax, 4); + var ctx = new FrameCheckDetails(enc, seed, levelMin, levelMax, format); if (!TryGetMatchCuteCharm(ctx, out result)) continue; if (!CheckEncounterActivation(enc, ref result)) @@ -264,12 +264,14 @@ public static class MethodJ result = default; return false; } + private static bool IsLevelRand(T enc) where T : IEncounterSlot4 => enc.Type.IsLevelRandDPPt(); + private static bool IsSlotValidFrom1Skip(FrameCheckDetails ctx, out uint result) where T : IEncounterSlot4 { - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev2)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev2)) { if (IsSlotValid(ctx.Encounter, ctx.Prev3)) { result = ctx.Seed4; return true; } @@ -286,9 +288,9 @@ public static class MethodJ private static bool IsSlotValidRegular(in FrameCheckDetails ctx, out uint result) where T : IEncounterSlot4 { - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) { if (IsSlotValid(ctx.Encounter, ctx.Prev2)) { result = ctx.Seed3; return true; } @@ -312,7 +314,7 @@ public static class MethodJ if (!IsOriginalLevelValid(ctx.LevelMin, ctx.LevelMax, ctx.Format, expectLevel)) { result = default; return false; } - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { // Don't bother evaluating Prev1 for level, as it's always bumped to max after. if (IsSlotValid(ctx.Encounter, ctx.Prev3)) @@ -330,12 +332,12 @@ public static class MethodJ where T : IEncounterSlot4 { lead = None; - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { if (IsStaticMagnetFail(ctx.Prev3)) // should have triggered { result = default; return false; } - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) { if (ctx.Encounter.IsSlotValidStaticMagnet(ctx.Prev2, out lead)) { result = ctx.Seed4; return true; } @@ -355,12 +357,12 @@ public static class MethodJ private static bool IsSlotValidStaticMagnetFail(in FrameCheckDetails ctx, out uint result) where T : IEncounterSlot4 { - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { if (IsStaticMagnetPass(ctx.Prev3)) // should have triggered { result = default; return false; } - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) { if (IsSlotValid(ctx.Encounter, ctx.Prev2)) { result = ctx.Seed4; return true; } diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs index b4f131d85..1f38aaf76 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/Gen4/MethodK.cs @@ -134,7 +134,7 @@ public static class MethodK /// /// Attempts to find a matching seed for the given encounter and constraints for Cute Charm buffered PIDs. /// - public static bool TryGetMatchCuteCharm(T enc, ReadOnlySpan seeds, byte nature, byte levelMin, byte levelMax, out uint result) + public static bool TryGetMatchCuteCharm(T enc, ReadOnlySpan seeds, byte nature, byte levelMin, byte levelMax, byte format, out uint result) where T : IEncounterSlot4 { foreach (uint seed in seeds) @@ -143,7 +143,7 @@ public static class MethodK var reg = GetNature(p0) == nature; if (!reg) continue; - var ctx = new FrameCheckDetails(enc, seed, levelMin, levelMax, 4); + var ctx = new FrameCheckDetails(enc, seed, levelMin, levelMax, format); if (!TryGetMatchCuteCharm(ctx, out result)) continue; if (CheckEncounterActivationCuteCharm(enc, ref result)) @@ -320,12 +320,14 @@ public static class MethodK result = default; return false; } + private static bool IsLevelRand(T enc) where T : IEncounterSlot4 => enc.Type.IsLevelRandHGSS(); + private static bool IsSlotValidFrom1Skip(FrameCheckDetails ctx, out uint result) where T : IEncounterSlot4 { - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev2)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev2)) { if (IsSlotValid(ctx.Encounter, ctx.Prev3)) { result = ctx.Seed4; return true; } @@ -342,9 +344,9 @@ public static class MethodK private static bool IsSlotValidRegular(in FrameCheckDetails ctx, out uint result) where T : IEncounterSlot4 { - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) { if (IsSlotValid(ctx.Encounter, ctx.Prev2)) { result = ctx.Seed3; return true; } @@ -368,7 +370,7 @@ public static class MethodK if (!IsOriginalLevelValid(ctx.LevelMin, ctx.LevelMax, ctx.Format, expectLevel)) { result = default; return false; } - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { // Don't bother evaluating Prev1 for level, as it's always bumped to max after. if (IsSlotValid(ctx.Encounter, ctx.Prev3)) @@ -391,12 +393,12 @@ public static class MethodK // -1 Level // 0 Nature lead = None; - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { if (IsStaticMagnetFail(ctx.Prev3)) // should have triggered { result = default; return false; } - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) { if (ctx.Encounter.IsSlotValidStaticMagnet(ctx.Prev2, out lead)) { result = ctx.Seed4; return true; } @@ -416,12 +418,12 @@ public static class MethodK private static bool IsSlotValidStaticMagnetFail(in FrameCheckDetails ctx, out uint result) where T : IEncounterSlot4 { - if (!ctx.Encounter.IsFixedLevel()) + if (IsLevelRand(ctx.Encounter)) { if (IsStaticMagnetPass(ctx.Prev3)) // should have triggered { result = default; return false; } - if (IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) + if (ctx.Encounter.IsFixedLevel() || IsLevelValid(ctx.Encounter, ctx.LevelMin, ctx.LevelMax, ctx.Format, ctx.Prev1)) { if (IsSlotValid(ctx.Encounter, ctx.Prev2)) { result = ctx.Seed4; return true; } diff --git a/PKHeX.Core/Legality/RNG/ClassicEra/LeadFinder.cs b/PKHeX.Core/Legality/RNG/ClassicEra/LeadFinder.cs index cb1b81902..abf23cd53 100644 --- a/PKHeX.Core/Legality/RNG/ClassicEra/LeadFinder.cs +++ b/PKHeX.Core/Legality/RNG/ClassicEra/LeadFinder.cs @@ -48,7 +48,7 @@ public static class LeadFinder { // Needs to fetch all possible seeds for IVs. // Kinda sucks to do this every encounter, but it's relatively rare -- still good enough perf. - var result = TryGetMatchCuteCharm4(enc, pk, evo, out var seed); + var result = TryGetMatchCuteCharm4(enc, pk, evo, pk.Format, out var seed); if (result) return new(seed, LeadRequired.CuteCharm); } @@ -69,7 +69,7 @@ public static class LeadFinder return result.IsValid(); } - private static bool TryGetMatchCuteCharm4(TEnc enc, PKM pk, TEvo evo, out uint seed) + private static bool TryGetMatchCuteCharm4(TEnc enc, PKM pk, TEvo evo, byte format, out uint seed) where TEnc : IEncounterSlot4 where TEvo : ILevelRange { @@ -81,8 +81,8 @@ public static class LeadFinder var nature = (byte)(pk.EncryptionConstant % 25); var (min, max) = (evo.LevelMin, evo.LevelMax); return pk.HGSS - ? MethodK.TryGetMatchCuteCharm(enc, seeds, nature, min, max, out seed) - : MethodJ.TryGetMatchCuteCharm(enc, seeds, nature, min, max, out seed); + ? MethodK.TryGetMatchCuteCharm(enc, seeds, nature, min, max, format, out seed) + : MethodJ.TryGetMatchCuteCharm(enc, seeds, nature, min, max, format, out seed); } private static int GetSeedsIVs(PKM pk, Span seeds)