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)