/// <summary> /// Yields an enumerable list of seeds until another valid PID breaks the chain. /// </summary> /// <param name="pidiv">Seed and RNG data</param> /// <param name="info">Verification information</param> /// <param name="form">Unown Form lock value</param> /// <returns>Seed information data, which needs to be unrolled once for the nature call.</returns> public static IEnumerable <SeedInfo> GetSeedsUntilUnownForm(PIDIV pidiv, FrameGenerator info, int form) { var seed = pidiv.OriginSeed; yield return(new SeedInfo(seed)); var s1 = seed; var s2 = RNG.LCRNG.Prev(s1); while (true) { var a = s2 >> 16; var b = s1 >> 16; // PID is in reverse for FRLG Unown var pid = a << 16 | b; // Process Conditions if (PKX.GetUnownForm(pid) == form) // matches form, does it match nature? { switch (VerifyPIDCriteria(pid, info)) { case LockInfo.Pass: // yes yield break; } } s1 = RNG.LCRNG.Prev(s2); s2 = RNG.LCRNG.Prev(s1); yield return(new SeedInfo(s1)); } }
/// <summary> /// Yields an enumerable list of seeds until another valid PID breaks the chain. /// </summary> /// <param name="pidiv">Seed and RNG data</param> /// <param name="info">Verification information</param> /// <returns>Seed information data, which needs to be unrolled once for the nature call.</returns> public static IEnumerable <SeedInfo> GetSeedsUntilNature(PIDIV pidiv, FrameGenerator info) { bool charm3 = false; var seed = pidiv.OriginSeed; yield return(new SeedInfo(seed)); var s1 = seed; var s2 = RNG.LCRNG.Prev(s1); while (true) { var a = s2 >> 16; var b = s1 >> 16; var pid = b << 16 | a; // Process Conditions switch (VerifyPIDCriteria(pid, info)) { case LockInfo.Pass: yield break; case LockInfo.Gender: charm3 = true; break; } s1 = RNG.LCRNG.Prev(s2); s2 = RNG.LCRNG.Prev(s1); yield return(new SeedInfo(s1, charm3)); } }
private static bool GetColoStarterMatch(PKM pk, uint top, uint bot, uint[] IVs, out PIDIV pidiv) { if (pk.Version != 15 || (pk.Species != 196 && pk.Species != 197)) { return(GetNonMatch(out pidiv)); } var iv1 = GetIVChunk(IVs, 0); var iv2 = GetIVChunk(IVs, 3); var xdc = GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot); foreach (var seed in xdc) { uint origin = seed; if (!LockFinder.IsColoStarterValid(pk.Species, ref origin, pk.TID, pk.SID, pk.PID, iv1, iv2)) { continue; } pidiv = new PIDIV { OriginSeed = origin, RNG = RNG.XDRNG, Type = PIDType.CXD_ColoStarter }; return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetPokewalkerMatch(PKM pk, uint oldpid, out PIDIV pidiv) { // check surface compatibility var mid = oldpid & 0x00FFFF00; if (mid != 0 && mid != 0x00FFFF00) // not expected bits { return(GetNonMatch(out pidiv)); } var nature = oldpid % 25; if (nature == 24) // impossible nature { return(GetNonMatch(out pidiv)); } var gender = pk.Gender; uint pid = PIDGenerator.GetPokeWalkerPID(pk.TID, pk.SID, nature, gender, pk.PersonalInfo.Gender); if (pid != oldpid) { if (!(gender == 0 && IsAzurillEdgeCaseM(pk, nature, oldpid))) { return(GetNonMatch(out pidiv)); } } pidiv = new PIDIV { NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.Pokewalker }; return(true); }
private static bool GetLCRNGUnownMatch(uint top, uint bot, uint[] IVs, out PIDIV 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 var B = RNG.LCRNG.Advance(seed, 2); // Method 1/2/4 can use 3 different RNG frames var C = RNG.LCRNG.Next(B); var ivC = C >> 16 & 0x7FFF; if (iv1 == ivC) { 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); 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; } 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); }
/// <summary> /// Checks a <see cref="PIDIV"/> to see if any encounter frames can generate the spread. Requires further filtering against matched Encounter Slots and generation patterns. /// </summary> /// <param name="pidiv">Matched <see cref="PIDIV"/> containing <see cref="PIDIV.RNG"/> info and <see cref="PIDIV.OriginSeed"/>.</param> /// <param name="pk"><see cref="PKM"/> object containing various accessible information required for the encounter.</param> /// <returns><see cref="IEnumerable{Frame}"/> to yield possible encounter details for further filtering</returns> public static IEnumerable <Frame> GetFrames(PIDIV pidiv, PKM pk) { FrameGenerator info = new FrameGenerator(pidiv, pk); if (info.FrameType == FrameType.None) { yield break; } info.Nature = pk.EncryptionConstant % 25; // gather possible nature determination seeds until a same-nature PID breaks the unrolling IEnumerable <SeedInfo> seeds = SeedInfo.GetSeedsUntilNature(pidiv, info); var frames = pidiv.Type == PIDType.CuteCharm ? FilterCuteCharm(seeds, pidiv, info) : FilterNatureSync(seeds, pidiv, info); var refined = RefineFrames(frames, info); foreach (var z in refined) { yield return(z); } }
private static bool GetLCRNGRoamerMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv) { if (IVs.Skip(2).Any(iv => iv != 0) || IVs[1] > 7) { pidiv = null; return(false); } var iv1 = GetIVChunk(IVs, 0); var reg = GetSeedsFromPID(RNG.LCRNG, top, bot); foreach (var seed in reg) { // Only the first 8 bits are kept var ivC = RNG.LCRNG.Advance(seed, 3) >> 16 & 0x00FF; 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 GetChainShinyMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv) { // 13 shiny bits // PIDH & 7 // PIDL & 7 // IVs var bot = GetIVChunk(IVs, 0); var top = GetIVChunk(IVs, 3); var reg = GetSeedsFromIVs(RNG.LCRNG, top, bot); foreach (var seed in reg) { // check the individual bits var s = seed; int i = 15; while (true) { var bit = s >> 16 & 1; if (bit != (pid >> i & 1)) { break; } s = RNG.LCRNG.Prev(s); if (--i == 2) { break; } } if (i != 2) // bit failed { continue; } // Shiny Bits of PID validated var upper = s; if ((upper >> 16 & 7) != (pid >> 16 & 7)) { continue; } var lower = RNG.LCRNG.Prev(upper); if ((lower >> 16 & 7) != (pid & 7)) { continue; } var upid = ((pid & 0xFFFF) ^ pk.TID ^ pk.SID) & 0xFFF8 | (upper >> 16) & 0x7; if (upid != pid >> 16) { continue; } s = RNG.LCRNG.Reverse(lower, 2); // unroll one final time to get the origin seed pidiv = new PIDIV { OriginSeed = s, RNG = RNG.LCRNG, Type = PIDType.ChainShiny }; 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 = GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot); foreach (var seed in xdc) { var B = RNG.XDRNG.Prev(seed); var A = RNG.XDRNG.Prev(B); if (!GetIVs(A >> 16, B >> 16).SequenceEqual(IVs)) { // check for antishiny (once), unroll 2x B = RNG.XDRNG.Prev(A); A = RNG.XDRNG.Prev(B); if (!GetIVs(A >> 16, B >> 16).SequenceEqual(IVs)) { continue; } } pidiv = new PIDIV { OriginSeed = RNG.XDRNG.Prev(A), RNG = RNG.XDRNG, Type = PIDType.CXD }; return(true); } return(GetNonMatch(out pidiv)); }
/// <summary> /// Checks a <see cref="PIDIV"/> to see if any encounter frames can generate the spread. Requires further filtering against matched Encounter Slots and generation patterns. /// </summary> /// <param name="pidiv">Matched <see cref="PIDIV"/> containing <see cref="PIDIV.RNG"/> info and <see cref="PIDIV.OriginSeed"/>.</param> /// <param name="pk"><see cref="PKM"/> object containing various accessible information required for the encounter.</param> /// <returns><see cref="IEnumerable{Frame}"/> to yield possible encounter details for further filtering</returns> public static IEnumerable <Frame> GetFrames(PIDIV pidiv, PKM pk) { if (pidiv.RNG == null) { return(Enumerable.Empty <Frame>()); } FrameGenerator info = new FrameGenerator(pidiv, pk); if (info.FrameType == FrameType.None) { return(Enumerable.Empty <Frame>()); } info.Nature = pk.EncryptionConstant % 25; // gather possible nature determination seeds until a same-nature PID breaks the unrolling var seeds = pk.Species == 201 && pk.FRLG // reversed await case ? SeedInfo.GetSeedsUntilUnownForm(pidiv, info, pk.AltForm) : SeedInfo.GetSeedsUntilNature(pidiv, info); var frames = pidiv.Type == PIDType.CuteCharm ? FilterCuteCharm(seeds, pidiv, info) : FilterNatureSync(seeds, pidiv, info); var refined = RefineFrames(frames, info); if (pk.Gen4 && pidiv.Type == PIDType.CuteCharm) // only permit cute charm successful frames { return(refined.Where(z => (z.Lead & ~LeadRequired.UsesLevelCall) == LeadRequired.CuteCharm)); } return(refined); }
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 var B = RNG.LCRNG.Advance(seed, 2); // Method 1/2/4 can use 3 different RNG frames var C = RNG.LCRNG.Next(B); var ivC = C >> 16 & 0x7FFF; if (iv1 == ivC) { 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); } } else { var D = RNG.LCRNG.Next(C); var ivD = D >> 16 & 0x7FFF; if (iv1 != ivD) { continue; } 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; return(false); }
private static bool GetPokewalkerMatch(PKM pk, uint oldpid, out PIDIV pidiv) { // check surface compatibility var mid = oldpid & 0x00FFFF00; if (mid != 0 && mid != 0x00FFFF00) // not expected bits { return(GetNonMatch(out pidiv)); } var nature = oldpid % 25; if (nature == 24) // impossible nature { return(GetNonMatch(out pidiv)); } uint pid = (uint)((pk.TID ^ pk.SID) >> 8 ^ 0xFF) << 24; // the most significant byte of the PID is chosen so the Pokémon can never be shiny. // Ensure nature is set to required nature without affecting shininess pid += nature - pid % 25; // Ensure Gender is set to required gender without affecting other properties // If Gender is modified, modify the ability if appropriate int currentGender = pk.Gender; if (currentGender != 2) // either m/f { var gr = pk.PersonalInfo.Gender; var pidGender = (pid & 0xFF) < gr ? 1 : 0; if (currentGender != pidGender) { if (currentGender == 0) // Male { pid += (uint)(((gr - (pid & 0xFF)) / 25 + 1) * 25); if ((nature & 1) != (pid & 1)) { pid += 25; } } else { pid -= (uint)((((pid & 0xFF) - gr) / 25 + 1) * 25); if ((nature & 1) != (pid & 1)) { pid -= 25; } } } } if (pid != oldpid) { return(GetNonMatch(out pidiv)); } pidiv = new PIDIV { NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.Pokewalker }; return(true); }
private static bool GetXDRNGMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv) { var xdc = GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot); foreach (var seed in xdc) { var B = RNG.XDRNG.Prev(seed); var A = RNG.XDRNG.Prev(B); var hi = A >> 16; var lo = B >> 16; if (!IVsMatch(hi, lo, IVs)) { // check for antishiny // allow 2 different TSVs to proc antishiny for XD var tsv1 = (int)((hi ^ lo) >> 3); var tsv2 = -1; while (true) { B = RNG.XDRNG.Prev(A); A = RNG.XDRNG.Prev(B); hi = A >> 16; lo = B >> 16; if (!IVsMatch(hi, lo, IVs)) { var anti = (int)(hi ^ lo) >> 3; if (anti == tsv1) { continue; } if (anti == tsv2) { continue; } if (tsv2 >= 0) // already set { break; // can't have this many shiny TSVs } tsv2 = anti; continue; } pidiv = new PIDIVTSV { OriginSeed = RNG.XDRNG.Prev(A), RNG = RNG.XDRNG, Type = PIDType.CXDAnti, TSV1 = tsv1, TSV2 = tsv2, }; return(true); } continue; } pidiv = new PIDIV { OriginSeed = RNG.XDRNG.Prev(A), RNG = RNG.XDRNG, Type = PIDType.CXD }; return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetXDRNGMatch(PKM pk, uint top, uint bot, uint[] IVs, out PIDIV pidiv) { var xdc = GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot); foreach (var seed in xdc) { var B = RNG.XDRNG.Prev(seed); var A = RNG.XDRNG.Prev(B); var hi = A >> 16; var lo = B >> 16; if (IVsMatch(hi, lo, IVs)) { pidiv = new PIDIV { OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXD }; return(true); } // check for anti-shiny against player TSV var tsv = (uint)(pk.TID ^ pk.SID) >> 3; var psv = (top ^ bot) >> 3; if (psv == tsv) // already shiny, wouldn't be anti-shiny { continue; } var p2 = seed; var p1 = B; psv = ((p2 ^ p1) >> 19); if (psv != tsv) // prior PID must be shiny { continue; } do { B = RNG.XDRNG.Prev(A); A = RNG.XDRNG.Prev(B); hi = A >> 16; lo = B >> 16; if (IVsMatch(hi, lo, IVs)) { pidiv = new PIDIV { OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXDAnti }; return(true); } p2 = RNG.XDRNG.Prev(p1); p1 = RNG.XDRNG.Prev(p2); psv = (p2 ^ p1) >> 19; }while (psv == tsv); } return(GetNonMatch(out pidiv)); }
// gather possible nature determination seeds until a same-nature PID breaks the unrolling private static IEnumerable <SeedInfo> GetSeeds(PIDIV pidiv, FrameGenerator info, PKM pk) { if (pk.Species == (int)Species.Unown && pk.FRLG) // Gen3 FRLG Unown: reversed await case { return(SeedInfo.GetSeedsUntilUnownForm(pidiv, info, pk.Form)); } if (pidiv.Type == PIDType.CuteCharm && info.FrameType != FrameType.MethodH) // Gen4: ambiguous seed due to gender-buffered PID { return(SeedInfo.GetSeedsUntilNature4Cute(pk)); } return(SeedInfo.GetSeedsUntilNature(pidiv, info)); }
private static bool GetChannelMatch(uint top, uint bot, uint[] IVs, out PIDIV pidiv, PKM pk) { var ver = pk.Version; if (ver != (int)GameVersion.R && ver != (int)GameVersion.S) { pidiv = null; return(false); } var undo = top ^ 0x8000; if ((undo > 7 ? 0 : 1) != (bot ^ pk.SID ^ 40122)) { top = undo; } var channel = GetSeedsFromPID(RNG.XDRNG, bot, top); foreach (var seed in channel) { var C = RNG.XDRNG.Advance(seed, 3); // held item // no checks, held item can be swapped var D = RNG.XDRNG.Next(C); // Version if ((D >> 31) + 1 != ver) // (0-Sapphire, 1-Ruby) { continue; } var E = RNG.XDRNG.Next(D); // OT Gender if (E >> 31 != pk.OT_Gender) { continue; } if (!RNG.XDRNG.GetSequentialIVsUInt32(E).SequenceEqual(IVs)) { continue; } if (seed >> 16 != pk.SID) { continue; } pidiv = new PIDIV { OriginSeed = RNG.XDRNG.Prev(seed), RNG = RNG.XDRNG, Type = PIDType.Channel }; return(true); } pidiv = null; return(false); }
public static bool IsAllShadowLockValid(EncounterStaticShadow s, PIDIV pv, PKM pkm) { var teams = s.Locks; if (teams.Length == 0) { return(s.Version == GameVersion.COLO || !pkm.IsShiny); // no xd shiny shadow mons } var tsv = s.Version == GameVersion.XD ? (pkm.TID ^ pkm.SID) >> 3 : -1; // no xd shiny shadow mons return(IsAllShadowLockValid(pv, teams, tsv)); }
public static bool IsAllShadowLockValid(PIDIV pv, IEnumerable <TeamLock> teams, int tsv = -1) { foreach (var t in teams) { var result = new TeamLockResult(t, pv.OriginSeed, tsv); if (result.Valid) { return(true); } } return(false); }
private static bool GetChainShinyMatch(PKM pk, uint pid, ReadOnlySpan <uint> IVs, out PIDIV pidiv) { // 13 shiny bits // PIDH & 7 // PIDL & 7 // IVs var bot = GetIVChunk(IVs, 0); var top = GetIVChunk(IVs, 3); var reg = GetSeedsFromIVs(RNG.LCRNG, top, bot); foreach (var seed in reg) { // check the individual bits var s = seed; int i = 15; do { var bit = s >> 16 & 1; if (bit != (pid >> i & 1)) { break; } s = RNG.LCRNG.Prev(s); }while (--i != 2); if (i != 2) // bit failed { continue; } // Shiny Bits of PID validated var upper = s; if ((upper >> 16 & 7) != (pid >> 16 & 7)) { continue; } var lower = RNG.LCRNG.Prev(upper); if ((lower >> 16 & 7) != (pid & 7)) { continue; } var upid = (((pid & 0xFFFF) ^ pk.TID ^ pk.SID) & 0xFFF8) | ((upper >> 16) & 0x7); if (upid != pid >> 16) { continue; } s = RNG.LCRNG.Reverse(lower, 2); // unroll one final time to get the origin seed pidiv = new PIDIV(ChainShiny, s); return(true); } return(GetNonMatch(out pidiv)); }
public static bool IsAllShadowLockValid(EncounterStaticShadow s, PIDIV pv, PKM pkm) { var teams = s.Locks; if (teams.Length == 0) { return(true); } var tsv = s.Version == GameVersion.XD ? pkm.TSV : -1; // no xd shiny shadow mons return(IsAllShadowLockValid(pv, teams, tsv)); }
private static bool GetCuteCharmMatch(PKM pk, uint pid, out PIDIV pidiv) { if (pid > 0xFF) { return(GetNonMatch(out pidiv)); } GetCuteCharmGenderSpecies(pk, pid, out int genderValue, out int species); int getRatio() => PersonalTable.HGSS[species].Gender; switch (genderValue) { case 2: break; // can't cute charm a genderless pkm case 0: // male var gr = getRatio(); if (254 <= gr) // no modification for PID { break; } var rate = 25 * ((gr / 25) + 1); // buffered var nature = pid % 25; if (nature + rate != pid) { break; } pidiv = new PIDIV { NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm }; return(true); case 1: // female if (pid >= 25) { break; // nope, this isn't a valid nature } if (254 <= getRatio()) // no modification for PID { break; } pidiv = new PIDIV { NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm }; return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetChannelMatch(uint top, uint bot, ReadOnlySpan <uint> IVs, out PIDIV pidiv, PKM pk) { var ver = pk.Version; if (ver is not((int)GameVersion.R or(int) GameVersion.S)) { return(GetNonMatch(out pidiv)); } var undo = top ^ 0x8000; if ((undo > 7 ? 0 : 1) != (bot ^ pk.SID ^ 40122)) { top = undo; } var channel = GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot); foreach (var seed in channel) { var C = RNG.XDRNG.Advance(seed, 3); // held item // no checks, held item can be swapped var D = RNG.XDRNG.Next(C); // Version if ((D >> 31) + 1 != ver) // (0-Sapphire, 1-Ruby) { continue; } var E = RNG.XDRNG.Next(D); // OT Gender if (E >> 31 != pk.OT_Gender) { continue; } if (!RNG.XDRNG.GetSequentialIVsUInt32(E, IVs)) { continue; } if (seed >> 16 != pk.SID) { continue; } pidiv = new PIDIV(Channel, RNG.XDRNG.Prev(seed)); return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetCuteCharmMatch(PKM pk, uint pid, out PIDIV pidiv) { if (pid > 0xFF) { return(GetNonMatch(out pidiv)); } int genderValue = pk.Gender; switch (genderValue) { case 2: break; // can't cute charm a genderless pkm case 0: // male var gr = pk.PersonalInfo.Gender; if (254 <= gr) // no modification for PID { break; } var rate = pk.Gender == 1 ? 0 : 25 * (gr / 25 + 1); // buffered var nature = pid % 25; if (nature + rate != pid) { break; } pidiv = new PIDIV { NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm }; return(true); case 1: // female if (pid >= 25) { break; // nope } if (254 <= pk.PersonalInfo.Gender) // no modification for PID { break; } pidiv = new PIDIV { NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm }; return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetG5MGShinyMatch(PKM pk, uint pid, out PIDIV pidiv) { var low = pid & 0xFFFF; // generation 5 shiny PIDs if (low <= 0xFF) { var av = (pid >> 16) & 1; var genPID = PIDGenerator.GetMG5ShinyPID(low, av, pk.TID, pk.SID); if (genPID == pid) { pidiv = PIDIV.G5MGShiny; return(true); } } return(GetNonMatch(out pidiv)); }
private static bool GetXDRNGMatch(PKM pk, uint top, uint bot, uint[] IVs, out PIDIV pidiv) { var xdc = GetSeedsFromPIDEuclid(RNG.XDRNG, top, bot); foreach (var seed in xdc) { var B = RNG.XDRNG.Prev(seed); var A = RNG.XDRNG.Prev(B); var hi = A >> 16; var lo = B >> 16; if (IVsMatch(hi, lo, IVs)) { pidiv = new PIDIV { OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXD }; return(true); } // check for anti-shiny against player TSV var tsv = (pk.TID ^ pk.SID) >> 3; var psv = (int)((hi ^ lo) >> 3); if (psv != tsv) { continue; } do { B = RNG.XDRNG.Prev(A); A = RNG.XDRNG.Prev(B); hi = A >> 16; lo = B >> 16; psv = (int)((hi ^ lo) >> 3); }while (psv == tsv); if (IVsMatch(hi, lo, IVs)) { pidiv = new PIDIV { OriginSeed = RNG.XDRNG.Prev(A), RNG = RNGType.XDRNG, Type = PIDType.CXDAnti }; return(true); } } return(GetNonMatch(out pidiv)); }
private static bool GetCuteCharmMatch(PKM pk, uint pid, out PIDIV pidiv) { if (pid > 0xFF) { return(GetNonMatch(out pidiv)); } (int species, int genderValue) = GetCuteCharmGenderSpecies(pk, pid, pk.Species); int getRatio() => PersonalTable.HGSS[species].Gender; switch (genderValue) { case 2: break; // can't cute charm a genderless pkm case 0: // male var gr = getRatio(); if (gr >= PersonalInfo.RatioMagicFemale) // no modification for PID { break; } var rate = 25 * ((gr / 25) + 1); // buffered var nature = pid % 25; if (nature + rate != pid) { break; } pidiv = PIDIV.CuteCharm; return(true); case 1: // female if (pid >= 25) { break; // nope, this isn't a valid nature } if (getRatio() >= PersonalInfo.RatioMagicFemale) // no modification for PID { break; } pidiv = PIDIV.CuteCharm; return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetG5MGShinyMatch(PKM pk, uint pid, out PIDIV pidiv) { var low = pid & 0xFFFF; // generation 5 shiny PIDs if (low <= 0xFF) { var high = pid >> 16; if (((pk.TID ^ pk.SID ^ low) - high & 0xFFFE) == 0) { pidiv = new PIDIV { NoSeed = true, Type = PIDType.G5MGShiny }; return(true); } } return(GetNonMatch(out pidiv)); }
/// <summary> /// Checks a <see cref="PIDIV"/> to see if any encounter frames can generate the spread. Requires further filtering against matched Encounter Slots and generation patterns. /// </summary> /// <param name="pidiv">Matched <see cref="PIDIV"/> containing info and <see cref="PIDIV.OriginSeed"/>.</param> /// <param name="pk"><see cref="PKM"/> object containing various accessible information required for the encounter.</param> /// <returns><see cref="IEnumerable{Frame}"/> to yield possible encounter details for further filtering</returns> public static IEnumerable <Frame> GetFrames(PIDIV pidiv, PKM pk) { if (pk.Version == (int)GameVersion.CXD) { return(Array.Empty <Frame>()); } var info = new FrameGenerator(pk) { Nature = pk.EncryptionConstant % 25 }; var seeds = GetSeeds(pidiv, info, pk); var frames = pidiv.Type == PIDType.CuteCharm ? FilterCuteCharm(seeds, info) : FilterNatureSync(seeds, info); return(GetRefinedSeeds(frames, info, pidiv)); }
private static bool GetPokewalkerMatch(PKM pk, uint oldpid, out PIDIV pidiv) { var nature = oldpid % 25; if (nature == 24) { pidiv = null; return(false); } uint pid = (uint)((pk.TID ^ pk.SID) >> 8 ^ 0xFF) << 24; // the most significant byte of the PID is chosen so the Pokémon can never be shiny. pid += nature - pid % 25; uint gv = 0; switch (pk.Gender) { case 0: // Male var gr = pk.PersonalInfo.Gender + 1; gv = (uint)(((gr - (pid & 0xFF)) / 25 + 1) * 25); // Ensures gender is set to male without affecting nature. break; case 1: // Female var gr2 = pk.PersonalInfo.Gender; gv = (uint)((((pid & 0xFF) - gr2) / 25 + 1) * 25); // Ensures gender is set to female without affecting nature break; } pid += gv; if ((nature & 1) != (pid & 1)) // If ability does not match the chosen ability { pid -= 25; // Switches ability without affecting nature } if (pid == oldpid) { pidiv = new PIDIV { NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.Pokewalker }; return(true); } pidiv = null; return(false); }