diff --git a/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs b/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs index 1237fa432..26a5fc36c 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs @@ -2,7 +2,7 @@ namespace PKHeX.Core { - internal class EncounterStaticShadow : EncounterStatic + public class EncounterStaticShadow : EncounterStatic { public TeamLock[] Locks { get; internal set; } = Array.Empty(); public int Gauge { get; internal set; } diff --git a/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs b/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs index d83bfa3e7..53e79f9cc 100644 --- a/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs +++ b/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs @@ -152,6 +152,30 @@ namespace PKHeX.Core private static bool IsShiny(uint TID, uint SID, uint PID) => (TID ^ SID ^ (PID >> 16) ^ (PID & 0xFFFF)) < 8; private static bool IsShiny(int TID, int SID, uint PID) => (TID ^ SID ^ (PID >> 16) ^ (PID & 0xFFFF)) < 8; + public static bool IsFirstShadowLockValid(EncounterStaticShadow s, PIDIV pv) + { + return IsFirstShadowLockValid(pv, s.Locks, s.Version == GameVersion.XD); + } + + public static bool IsFirstShadowLockValid(PIDIV pv, TeamLock[] teams, bool XD) + { + if (teams.Length == 0) + return true; + + foreach (var t in teams) + { + var locks = new Stack(1); + locks.Push(t.Locks[t.Locks.Length - 1]); + var pids = new Stack(); + var originSeed = pv.OriginSeed; + var cache = new FrameCache(RNG.XDRNG.Reverse(originSeed, 2), RNG.XDRNG.Prev); + var result = FindLockSeed(cache, 0, locks, null, pids, XD, out var originFrame); + if (result) + return true; + } + return false; + } + // Colosseum/XD Starters public static bool IsXDStarterValid(uint seed, int TID, int SID) { diff --git a/Tests/PKHeX.Tests/Legality/ShadowTests.cs b/Tests/PKHeX.Tests/Legality/ShadowTests.cs index 1601b4404..97989bdbf 100644 --- a/Tests/PKHeX.Tests/Legality/ShadowTests.cs +++ b/Tests/PKHeX.Tests/Legality/ShadowTests.cs @@ -33,7 +33,7 @@ namespace PKHeX.Tests.Legality // Remoraid (M) (Docile) // Golbat (M) (Bashful) - // Verify(Encounters3Teams.Roselia, 0x30E87CC7, new[] { 22, 11, 8, 26, 4, 29 }); + VerifySingle(Encounters3Teams.Roselia, 0x30E87CC7, new[] { 22, 11, 8, 26, 4, 29 }); } [TestMethod] @@ -53,7 +53,7 @@ namespace PKHeX.Tests.Legality // Ralts (M) (Docile) // Voltorb (-) (Hardy) // Bagon (F) (Quirky) - // Verify(Encounters3Teams.Numel, 0x37F95B26, new[] { 11, 8, 5, 10, 28, 14 }); + VerifySingle(Encounters3Teams.Numel, 0x37F95B26, new[] { 11, 8, 5, 10, 28, 14 }); } [TestMethod] @@ -64,19 +64,19 @@ namespace PKHeX.Tests.Legality // Jumpluff (M) (Docile) // Azumarill (F) (Hardy) // Shadow Tangela - // Verify(Encounters3Teams.Butterfree, 0x2E49AC34, new[] { 15, 24, 7, 2, 11, 2 }); + VerifySingle(Encounters3Teams.Butterfree, 0x2E49AC34, new[] { 15, 24, 7, 2, 11, 2 }); // Huntail (M) (Docile) // Cacturne (F) (Hardy) // Weezing (F) (Serious) // Ursaring (F) (Bashful) - // Verify(Encounters3Teams.Arbok, 0x1973FD07, new[] { 13, 30, 3, 16, 20, 9 }); + VerifySingle(Encounters3Teams.Arbok, 0x1973FD07, new[] { 13, 30, 3, 16, 20, 9 }); // Lairon (F) (Bashful) // Sealeo (F) (Serious) // Slowking (F) (Docile) // Ursaring (M) (Quirky) - // Verify(Encounters3Teams.Primeape, 0x33893D4C, new[] { 26, 25, 24, 28, 29, 30 }); + VerifySingle(Encounters3Teams.Primeape, 0x33893D4C, new[] { 26, 25, 24, 28, 29, 30 }); } [TestMethod] @@ -84,7 +84,7 @@ namespace PKHeX.Tests.Legality public void VerifyLock5() { // many prior, all non shadow - // Verify(Encounters3Teams.Seedot, 0x8CBD29DB, new[] { 19, 29, 30, 0, 7, 2 }); + VerifySingle(Encounters3Teams.Seedot, 0x8CBD29DB, new[] { 19, 29, 30, 0, 7, 2 }); } private static void Verify(TeamLock[] teams, uint pid, int[] ivs, bool xd = true) @@ -96,6 +96,15 @@ namespace PKHeX.Tests.Legality Assert.IsTrue(match, "Unable to verify lock conditions: " + teams[0].Species); } + private static void VerifySingle(TeamLock[] teams, uint pid, int[] ivs, bool xd = true) + { + var pk3 = new PK3 { PID = pid, IVs = ivs }; + var info = MethodFinder.Analyze(pk3); + Assert.AreEqual(PIDType.CXD, info.Type, "Unable to match PID to CXD spread!"); + bool match = LockFinder.IsFirstShadowLockValid(info, teams, xd); + Assert.IsTrue(match, "Unable to verify lock conditions: " + teams[0].Species); + } + /// /// Checks if the PIDIV can originate from ///