From be4d30bb6de068ed318d4f723be155ed2398845d Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 26 Nov 2017 20:07:38 -0800 Subject: [PATCH] Add pokeblock slot filtering since there's 300 calls to rand to shuffle, I wouldn't be surprised if there are vblanks messing up the frames judging from my data 6 years ago (wow, still wrong, just look at the frame offsets) http://www.smogon.com/forums/threads/past-gen-rng-research.61090/page-35#post-4021415 looks like it happens quite erratically. may have to just override this to return true for all gen3 safari mons as it's entirely unpredictable. --- PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs | 66 +++++++++++++++++++ .../Legality/RNG/Frame/FrameGenerator.cs | 3 + PKHeX.Core/Legality/RNG/Frame/Pokeblock.cs | 16 +++++ 3 files changed, 85 insertions(+) create mode 100644 PKHeX.Core/Legality/RNG/Frame/Pokeblock.cs diff --git a/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs b/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs index 7c19e5af5..a64fcf226 100644 --- a/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs +++ b/PKHeX.Core/Legality/RNG/Frame/FrameFinder.cs @@ -185,6 +185,18 @@ private static IEnumerable FilterNatureSync(IEnumerable seeds, foreach (var seed in seeds) { var s = seed.Seed; + + if (info.Safari3) + { + // successful pokeblock activation + bool result = IsValidPokeBlockNature(s, info.Nature, out uint blockSeed); + if (result) + yield return info.GetFrame(blockSeed, seed.Charm3 ? LeadRequired.CuteCharm : LeadRequired.None); + + // if no pokeblocks present (or failed call), fall out of the safari specific code and generate via the other scenarios + s = info.RNG.Prev(s); // wasted RNG call + } + var rand = s >> 16; bool sync = info.AllowLeads && !seed.Charm3 && (info.DPPt ? rand >> 15 : rand & 1) == 0; bool reg = (info.DPPt ? rand / 0xA3E : rand % 25) == info.Nature; @@ -209,6 +221,60 @@ private static IEnumerable FilterNatureSync(IEnumerable seeds, } } } + private static bool IsValidPokeBlockNature(uint seed, uint nature, out uint natureOrigin) + { + if (nature % 6 == 0) // neutral + { + natureOrigin = 0; + return false; + } + + // unroll the RNG to a stack of seeds + var stack = new Stack(); + for (uint i = 0; i < 25; i++) + for (uint j = 1 + i; j < 25; j++) + stack.Push(seed = RNG.LCRNG.Prev(seed)); + + natureOrigin = RNG.LCRNG.Prev(stack.Peek()); + if (natureOrigin >> 16 % 100 >= 80) // failed proc + return false; + + // init natures + uint[] natures = new uint[25]; + for (uint i = 0; i < 25; i++) + natures[i] = i; + + // shuffle nature list + for (uint i = 0; i < 25; i++) + for (uint j = 1 + i; j < 25; j++) + { + var s = stack.Pop(); + if ((s >> 16 & 1) == 0) + continue; // only swap if 1 + + var temp = natures[i]; + natures[i] = natures[j]; + natures[j] = temp; + } + + var likes = Pokeblock.GetLikedBlockFlavor(nature); + // best case scenario is a perfect flavored pokeblock for the nature. + // has liked flavor, and all other non-disliked flavors are present. + // is it possible to skip this step? + for (int i = 0; i < 25; i++) + { + var n = natures[i]; + if (n == nature) + break; + + var nl = Pokeblock.GetLikedBlockFlavor(natures[i]); + if (nl == likes) // next random nature likes the same block as the desired nature + return false; // current nature is chosen instead, fail! + } + // unroll once more to hit the level calc (origin with respect for beginning the nature calcs) + natureOrigin = RNG.LCRNG.Prev(natureOrigin); + return true; + } /// /// Filters the input according to a Cute Charm frame generation pattern. diff --git a/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs b/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs index 9dc565f5d..91cadbce2 100644 --- a/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs +++ b/PKHeX.Core/Legality/RNG/Frame/FrameGenerator.cs @@ -10,6 +10,8 @@ public class FrameGenerator public readonly bool AllowLeads; public readonly FrameType FrameType = FrameType.None; public readonly RNG RNG; + public readonly bool Safari3; + public Frame GetFrame(uint seed, LeadRequired lead) => new Frame(seed, FrameType, RNG, lead); public Frame GetFrame(uint seed, LeadRequired lead, uint esv) => new Frame(seed, FrameType, RNG, lead) {ESV = esv}; @@ -33,6 +35,7 @@ public FrameGenerator(PIDIV pidiv, PKM pk) DPPt = false; FrameType = FrameType.MethodH; RNG = pidiv.RNG; + Safari3 = pk.Ball == 5; if (ver != GameVersion.E) return; diff --git a/PKHeX.Core/Legality/RNG/Frame/Pokeblock.cs b/PKHeX.Core/Legality/RNG/Frame/Pokeblock.cs new file mode 100644 index 000000000..8f685ade1 --- /dev/null +++ b/PKHeX.Core/Legality/RNG/Frame/Pokeblock.cs @@ -0,0 +1,16 @@ +namespace PKHeX.Core +{ + public static class Pokeblock + { + public static Flavor GetLikedBlockFlavor(uint nature) => (Flavor)(nature/5); + public static Flavor GetDislikedBlockFlavor(uint nature) => (Flavor)(nature%5); + public enum Flavor + { + Spicy, + Sour, + Sweet, + Dry, + Bitter, + } + } +} \ No newline at end of file