diff --git a/PKHeX/Legality/Checks.cs b/PKHeX/Legality/Checks.cs index 0063b0e85..7d84d5fd0 100644 --- a/PKHeX/Legality/Checks.cs +++ b/PKHeX/Legality/Checks.cs @@ -166,7 +166,7 @@ private void verifyECPIDWurmple() } // Check if Wurmple was the origin (only Egg and Wild Encounter) - bool wasWurmple = pkm.WasEgg || (Type == typeof (EncounterSlot[]) && ((EncounterSlot[])EncounterMatch).Any(slot => slot.Species == 265)); + bool wasWurmple = pkm.WasEgg || (Type == typeof (EncounterSlot[]) && ((EncounterSlot[])EncounterMatch).All(slot => slot.Species == 265)); if (!wasWurmple) return; diff --git a/PKHeX/Legality/RNG/MethodFinder.cs b/PKHeX/Legality/RNG/MethodFinder.cs index 8ed37005f..0622dcd77 100644 --- a/PKHeX/Legality/RNG/MethodFinder.cs +++ b/PKHeX/Legality/RNG/MethodFinder.cs @@ -38,6 +38,8 @@ public static PIDIV Analyze(PKM pk) return pidiv; // Special cases + if (getLCRNGRoamerMatch(top, bot, IVs, out pidiv)) + return pidiv; if (getChannelMatch(top, bot, IVs, out pidiv)) return pidiv; if (getMG4Match(pid, IVs, out pidiv)) @@ -61,6 +63,8 @@ public static PIDIV Analyze(PKM pk) private static bool getLCRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv) { var reg = getSeedsFromPID(RNG.LCRNG, top, bot); + var iv1 = getIVChunk(IVs, 0); + var iv2 = getIVChunk(IVs, 3); foreach (var seed in reg) { // A and B are already used by PID @@ -68,25 +72,39 @@ private static bool getLCRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidi // Method 1/2/4 can use 3 different RNG frames var C = RNG.LCRNG.Next(B); - var D = RNG.LCRNG.Next(C); - - if (getIVs(C >> 16, D >> 16).SequenceEqual(IVs)) // ABCD + var ivC = C >> 16 & 0x7FFF; + if (iv1 == ivC) { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1}; - return true; + var D = RNG.LCRNG.Next(C); + var ivD = D >> 16 & 0x7FFF; + if (iv2 == ivD) // ABCD + { + pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1}; + return true; + } + + var E = RNG.LCRNG.Next(D); + var ivE = E >> 16 & 0x7FFF; + if (iv2 == ivE) // ABCE + { + pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4}; + return true; + } } - - var E = RNG.LCRNG.Next(D); - if (getIVs(D >> 16, E >> 16).SequenceEqual(IVs)) // ABDE + else { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2}; - return true; - } + var D = RNG.LCRNG.Next(C); + var ivD = D >> 16 & 0x7FFF; + if (iv1 != ivD) + continue; - if (getIVs(C >> 16, E >> 16).SequenceEqual(IVs)) // ABCE - { - pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4}; - return true; + var E = RNG.LCRNG.Next(D); + var ivE = E >> 16 & 0x7FFF; + if (iv2 == ivE) // ABDE + { + pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2}; + return true; + } } } pidiv = null; @@ -96,6 +114,8 @@ private static bool getLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV { // this is an exact copy of LCRNG 1,2,4 matching, except the PID has its halves switched (BACD, BADE, BACE) var reg = getSeedsFromPID(RNG.LCRNG, bot, top); // reversed! + var iv1 = getIVChunk(IVs, 0); + var iv2 = getIVChunk(IVs, 3); foreach (var seed in reg) { // A and B are already used by PID @@ -103,30 +123,67 @@ private static bool getLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV // Method 1/2/4 can use 3 different RNG frames var C = RNG.LCRNG.Next(B); - var D = RNG.LCRNG.Next(C); - - if (getIVs(C >> 16, D >> 16).SequenceEqual(IVs)) // BACD + var ivC = C >> 16 & 0x7FFF; + if (iv1 == ivC) { - pidiv = new PIDIV { OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1_Unown }; - return true; - } + var D = RNG.LCRNG.Next(C); + var ivD = D >> 16 & 0x7FFF; + if (iv2 == ivD) // BACD + { + pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1_Unown}; + return true; + } - var E = RNG.LCRNG.Next(D); - if (getIVs(D >> 16, E >> 16).SequenceEqual(IVs)) // BADE - { - pidiv = new PIDIV { OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2_Unown }; - return true; + var E = RNG.LCRNG.Next(D); + var ivE = E >> 16 & 0x7FFF; + if (iv2 == ivE) // BACE + { + pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4_Unown}; + return true; + } } + else + { + var D = RNG.LCRNG.Next(C); + var ivD = D >> 16 & 0x7FFF; + if (iv1 != ivD) + continue; - if (getIVs(C >> 16, E >> 16).SequenceEqual(IVs)) // BACE - { - pidiv = new PIDIV { OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_4_Unown }; - return true; + var E = RNG.LCRNG.Next(D); + var ivE = E >> 16 & 0x7FFF; + if (iv2 != ivE) // BADE + { + pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_2_Unown}; + return true; + } } } pidiv = null; return false; } + private static bool getLCRNGRoamerMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv) + { + var iv2 = getIVChunk(IVs, 3); + if (iv2 != 0 || IVs[2] != 0) + { + pidiv = null; + return false; + } + var iv1 = getIVChunk(IVs, 0); + var reg = getSeedsFromPID(RNG.LCRNG, top, bot); + foreach (var seed in reg) + { + // Only the first two IVs are kept + var ivC = RNG.LCRNG.Advance(seed, 3) >> 16 & 0x03FF; + if (iv1 != ivC) + continue; + + pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.Method_1_Roamer}; + return true; + } + pidiv = null; + return false; + } private static bool getXDRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv) { var xdc = getSeedsFromPID(RNG.XDRNG, bot, top); @@ -280,8 +337,8 @@ private static bool getBACDMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv) var B = seed; var A = RNG.LCRNG.Prev(B); - var PID = A & 0xFFFF0000 | (B >> 16); - bool isShiny = (pk.TID ^ pk.SID ^ (PID >> 16) ^ (PID & 0xFFFF)) < 8; + var PID = A & 0xFFFF0000 | B >> 16; + bool isShiny = (pk.TID ^ pk.SID ^ PID >> 16 ^ PID & 0xFFFF) < 8; bool forceShiny = false; if (PID != pid) { @@ -306,12 +363,12 @@ private static bool getBACDMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv) continue; forceShiny = true; } - if (!forceShiny && ((PID + 8) & 0xFFFFFFF8) != pid) + if (!forceShiny && (PID + 8 & 0xFFFFFFF8) != pid) continue; } var s = RNG.LCRNG.Prev(A); - // Check for Restricted generation pattern + // Check for prior Restricted seed var sn = s; for (int i = 0; i < 3; i++, sn = RNG.LCRNG.Prev(sn)) { @@ -321,7 +378,7 @@ private static bool getBACDMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv) pidiv = new PIDIV {OriginSeed = sn, RNG = RNG.LCRNG, Type = type}; return true; } - + // no restricted seed found, thus unrestricted var t = forceShiny ? PIDType.BACD_U_S : isShiny ? PIDType.BACD_U_A : PIDType.BACD_U; pidiv = new PIDIV {OriginSeed = s, RNG = RNG.LCRNG, Type = t}; return true; diff --git a/PKHeX/Legality/RNG/PIDType.cs b/PKHeX/Legality/RNG/PIDType.cs index d7e199d05..1aeaf4483 100644 --- a/PKHeX/Legality/RNG/PIDType.cs +++ b/PKHeX/Legality/RNG/PIDType.cs @@ -17,6 +17,8 @@ public enum PIDType Method_2_Unown, /// Method H4_Unown (FRLG) Method_4_Unown, + /// Method 1 Roamer (Gen3) + Method_1_Roamer, /// /// Event Reversed Order PID restricted to 16bit Origin Seed diff --git a/PKHeX/Legality/Tables4.cs b/PKHeX/Legality/Tables4.cs index 413b7a727..1572cf7e6 100644 --- a/PKHeX/Legality/Tables4.cs +++ b/PKHeX/Legality/Tables4.cs @@ -723,7 +723,7 @@ public static partial class Legal new EncounterStatic { Species = 143, Level = 50, Location = 159, }, //Snorlax @ Route 11 new EncounterStatic { Species = 143, Level = 50, Location = 160, }, //Snorlax @ Route 12 new EncounterStatic { Species = 185, Level = 20, Location = 184, }, //Sudowoodo @ Route 36, Encounter does not have type - new EncounterStaticTyped { Species = 172, Level = 30, Location = 214, Gender = 1, Form = 1, Moves = new[]{344,270,207,220}, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio }, //Spiky-eared Pichu @ Ilex forest + new EncounterStaticTyped { Species = 172, Level = 30, Location = 214, Gender = 1, Form = 1, Moves = new[]{344,270,207,220}, TypeEncounter = EncounterType.Starter_Fossil_Gift_Pt_DPTrio, Shiny = false }, //Spiky-eared Pichu @ Ilex forest //Stationary Lengerdary new EncounterStaticTyped { Species = 144, Level = 50, Location = 203, TypeEncounter = EncounterType.Cave_HallOfOrigin }, //Articuno @ Seafoam Islands new EncounterStatic { Species = 145, Level = 50, Location = 158, }, //Zapdos @ Route 10