diff --git a/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs b/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs index 7bae0cc14..aa4028728 100644 --- a/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs +++ b/PKHeX.Core/Legality/RNG/Locks/LockFinder.cs @@ -24,7 +24,7 @@ namespace PKHeX.Core public static bool FindLockSeed(uint originSeed, IEnumerable lockList, bool XD, out uint origin) { var locks = new Stack(lockList); - var pids = new Stack(); + var pids = new Stack(); var cache = new FrameCache(RNG.XDRNG.Reverse(originSeed, 2), RNG.XDRNG.Prev); var result = FindLockSeed(cache, 0, locks, null, pids, XD, out var originFrame); origin = cache.GetSeed(originFrame); @@ -32,19 +32,19 @@ namespace PKHeX.Core } // Recursively iterates to visit possible locks until all locks (or none) are satisfied. - private static bool FindLockSeed(FrameCache cache, int ctr, Stack Locks, NPCLock prior, Stack PIDs, bool XD, out int originFrame) + private static bool FindLockSeed(FrameCache cache, int ctr, Stack Locks, NPCLock prior, Stack team, bool XD, out int originFrame) { if (Locks.Count == 0) - return VerifyNPC(cache, ctr, PIDs, XD, out originFrame); + return VerifyNPC(cache, ctr, team, XD, out originFrame); var l = Locks.Pop(); var frames = FindPossibleLockFrames(cache, ctr, l, prior); foreach (var poss in frames) { - PIDs.Push(poss.PID); // possible match - if (FindLockSeed(cache, poss.FrameID, Locks, l, PIDs, XD, out originFrame)) + team.Push(poss); // possible match + if (FindLockSeed(cache, poss.FrameID, Locks, l, team, XD, out originFrame)) return true; // all locks are satisfied - PIDs.Pop(); // no match, remove + team.Pop(); // no match, remove } Locks.Push(l); // return the lock, lock is impossible @@ -86,22 +86,22 @@ namespace PKHeX.Core } uint pid = cache[ctr + 1] << 16 | cache[ctr]; if (l.MatchesLock(pid)) - yield return new SeedFrame { FrameID = ctr + 6, PID = pid }; + yield return new SeedFrame { FrameID = ctr + (l.Seen ? 5 : 7), PID = pid }; ctr += 2; } } - private static bool VerifyNPC(FrameCache cache, int ctr, IEnumerable PIDs, bool XD, out int originFrame) + private static bool VerifyNPC(FrameCache cache, int ctr, IEnumerable team, bool XD, out int originFrame) { originFrame = ctr+2; var tid = cache[ctr+1]; var sid = cache[ctr]; // verify none are shiny - foreach (var pid in PIDs) + foreach (var pid in team) { - if (IsShiny(tid, sid, pid)) + if (IsShiny(tid, sid, pid.PID)) return true; // todo } @@ -126,10 +126,10 @@ namespace PKHeX.Core { var locks = new Stack(1); locks.Push(t.Locks[t.Locks.Length - 1]); - var pids = new Stack(); + var team = 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 _); + var result = FindLockSeed(cache, 0, locks, null, team, XD, out var _); if (result) return true; } diff --git a/Tests/PKHeX.Tests/Legality/ShadowTests.cs b/Tests/PKHeX.Tests/Legality/ShadowTests.cs index 998ccf00f..3da09945f 100644 --- a/Tests/PKHeX.Tests/Legality/ShadowTests.cs +++ b/Tests/PKHeX.Tests/Legality/ShadowTests.cs @@ -1,4 +1,5 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Collections.Generic; +using Microsoft.VisualStudio.TestTools.UnitTesting; using PKHeX.Core; namespace PKHeX.Tests.Legality @@ -7,6 +8,7 @@ namespace PKHeX.Tests.Legality public class ShadowTests { private const string LegalityValidCategory = "Shadow Lock Validity Tests"; + private const string VerifyPIDCategory = "Shadow Lock Result Tests"; [TestMethod] [TestCategory(LegalityValidCategory)] @@ -58,7 +60,7 @@ namespace PKHeX.Tests.Legality // Luvdisc (F) (Docile) // Beautifly (M) (Hardy) // Roselia (M) (Quirky) - VerifySingle(Encounters3Teams.Delcatty, 0x9BECA2A6, new[] { 31, 31, 25, 13, 22, 1 }); + Verify(Encounters3Teams.Delcatty, 0x9BECA2A6, new[] { 31, 31, 25, 13, 22, 1 }); // Kadabra (M) (Docile) // Sneasel (F) (Hardy) @@ -68,7 +70,7 @@ namespace PKHeX.Tests.Legality // Ralts (M) (Docile) // Voltorb (-) (Hardy) // Bagon (F) (Quirky) - VerifySingle(Encounters3Teams.Numel, 0x37F95B26, new[] { 11, 8, 5, 10, 28, 14 }); + Verify(Encounters3Teams.Numel, 0x37F95B26, new[] { 11, 8, 5, 10, 28, 14 }); } [TestMethod] @@ -85,13 +87,13 @@ namespace PKHeX.Tests.Legality // Cacturne (F) (Hardy) // Weezing (F) (Serious) // Ursaring (F) (Bashful) - VerifySingle(Encounters3Teams.Arbok, 0x1973FD07, new[] { 13, 30, 3, 16, 20, 9 }); + Verify(Encounters3Teams.Arbok, 0x1973FD07, new[] { 13, 30, 3, 16, 20, 9 }); // Lairon (F) (Bashful) // Sealeo (F) (Serious) // Slowking (F) (Docile) // Ursaring (M) (Quirky) - VerifySingle(Encounters3Teams.Primeape, 0x33893D4C, new[] { 26, 25, 24, 28, 29, 30 }); + Verify(Encounters3Teams.Primeape, 0x33893D4C, new[] { 26, 25, 24, 28, 29, 30 }); } [TestMethod] @@ -120,6 +122,60 @@ namespace PKHeX.Tests.Legality Assert.IsTrue(match, "Unable to verify lock conditions: " + teams[0].Species); } + + [TestMethod] + [TestCategory(VerifyPIDCategory)] + public void VerifyPIDResults() + { + var results = new[] + { + new uint[] {0xD118BA52, 0xA3127782, 0x16D95FA5, 0x31538B48}, + new uint[] {0x7D5FFE3E, 0x1D5720ED, 0xE0D89C99, 0x3494CDA1}, + new uint[] {0xAEB0C3A6, 0x956DC2FD, 0x3C11DCE8, 0xC93DF897}, + new uint[] {0xACCE2655, 0xFF2BA0A2, 0x22A8A7E6, 0x5F5380F4}, + new uint[] {0xDC1D1894, 0xFC0F75E2, 0x97BFAEBC, 0x38DDE117}, + new uint[] {0xDE278967, 0xFD86C9F7, 0x3E16FCFD, 0x1956D8B5}, + new uint[] {0xF8CB4CAE, 0x42DE628B, 0x48796CDA, 0xF6EAD3E2}, + new uint[] {0x56548F49, 0xA308E7DA, 0x28CB8ADF, 0xBEADBDC3}, + new uint[] {0xF2AC8419, 0xADA208E3, 0xDB3A0BA6, 0x5EEF1076}, + new uint[] {0x9D28899D, 0xA3ECC9F0, 0x606EC6F0, 0x451FAE3C}, + }; + VerifyResults(results, Encounters3Teams.Delcatty); + } + + private static void VerifyResults(IReadOnlyList results, TeamLock[] team) + { + var pkm = new PK3(); + for (int i = 0; i < results.Count; i++) + { + var result = results[i]; + var seeds = getSeeds(result[result.Length - 1]); + bool match = false; + foreach (var seed in seeds) + { + PIDGenerator.SetValuesFromSeed(pkm, PIDType.CXD, seed); + var info = MethodFinder.Analyze(pkm); + Assert.IsTrue(seed == info.OriginSeed); + Assert.AreEqual(PIDType.CXD, info.Type, "Unable to match PID to CXD spread!"); + if (!GetCanOriginateFrom(team, info, false, out var _)) + continue; + match = true; + break; + } + Assert.IsTrue(match, $"Unable to verify lock conditions for result {i}: " + team[0].Species); + } + + IEnumerable getSeeds(uint PID) + { + var top = PID >> 16; + var bot = PID & 0xFFFF; + + var seeds = MethodFinder.GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot); + foreach (var s in seeds) + yield return RNG.XDRNG.Reverse(s, 3); + } + } + /// /// Checks if the PIDIV can originate from ///