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 = PIDIV.Pokewalker; return(true); }
/// <summary> /// Gets the Search Criteria parameters necessary for generating <see cref="SeedInfo"/> and <see cref="Frame"/> objects. /// </summary> /// <param name="pidiv">Info used to determine the <see cref="FrameType"/>.</param> /// <param name="pk"><see cref="PKM"/> object containing various accessible information required for the encounter.</param> /// <returns>Object containing search criteria to be passed by reference to search/filter methods.</returns> public FrameGenerator(PIDIV pidiv, PKM pk) { var ver = (GameVersion)pk.Version; switch (ver) { // Method H case GameVersion.R: case GameVersion.S: case GameVersion.FR: case GameVersion.LG: case GameVersion.E: DPPt = false; FrameType = FrameType.MethodH; RNG = pidiv.RNG; Safari3 = pk.Ball == 5 && !pk.FRLG; if (ver != GameVersion.E) { return; } AllowLeads = true; // Cute Charm waits for gender too! var gender = pk.Gender; bool gendered = gender != 2; if (!gendered) { return; } var gr = pk.PersonalInfo.Gender; Gendered = true; GenderLow = GetGenderMinMax(gender, gr, false); GenderHigh = GetGenderMinMax(gender, gr, true); return; // Method J case GameVersion.D: case GameVersion.P: case GameVersion.Pt: DPPt = true; AllowLeads = true; FrameType = FrameType.MethodJ; RNG = pidiv.RNG; return; // Method K case GameVersion.HG: case GameVersion.SS: DPPt = false; AllowLeads = true; FrameType = FrameType.MethodK; RNG = pidiv.RNG; return; } }
// 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)); }
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 GetXDRNGMatch(PKM pk, uint top, uint bot, ReadOnlySpan <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(CXD, RNG.XDRNG.Prev(A)); 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(CXDAnti, RNG.XDRNG.Prev(A)); return(true); } p2 = RNG.XDRNG.Prev(p1); p1 = RNG.XDRNG.Prev(p2); psv = (p2 ^ p1) >> 19; }while (psv == tsv); } return(GetNonMatch(out pidiv)); }
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)); }
/// <summary> /// Checks if the PIDIV can originate from /// </summary> /// <param name="possibleTeams"></param> /// <param name="info"></param> /// <returns></returns> private static bool GetCanOriginateFrom(TeamLock[] possibleTeams, PIDIV info, bool XD, out uint origin) { foreach (var team in possibleTeams) { var result = LockFinder.FindLockSeed(info.OriginSeed, team.Locks, XD, out origin); if (result) { return(true); } } origin = 0; return(false); }
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)); }
public static bool IsAllShadowLockValid(EncounterStaticShadow s, PIDIV pv, PKM pk) { if (s.Version == GameVersion.XD && pk.IsShiny) { return(false); // no xd shiny shadow mons } var teams = s.Locks; if (teams.Length == 0) { return(true); } var tsv = s.Version == GameVersion.XD ? (pk.TID ^ pk.SID) >> 3 : -1; // no xd shiny shadow mons return(IsAllShadowLockValid(pv, teams, tsv)); }
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 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 pk 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)); }
/// <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 GetMG4Match(uint pid, ReadOnlySpan <uint> IVs, out PIDIV pidiv) { uint mg4Rev = RNG.ARNG.Prev(pid); var mg4 = GetSeedsFromPID(RNG.LCRNG, mg4Rev >> 16, mg4Rev & 0xFFFF); foreach (var seed in mg4) { var B = RNG.LCRNG.Advance(seed, 2); var C = RNG.LCRNG.Next(B); var D = RNG.LCRNG.Next(C); if (!IVsMatch(C >> 16, D >> 16, IVs)) { continue; } pidiv = new PIDIV(G4MGAntiShiny, seed); return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetLCRNGRoamerMatch(uint top, uint bot, ReadOnlySpan <uint> IVs, out PIDIV pidiv) { if (IVs[2] != 0 || IVs[3] != 0 || IVs[4] != 0 || IVs[5] != 0 || IVs[1] > 7) { return(GetNonMatch(out pidiv)); } 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(Method_1_Roamer, seed); return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetColoStarterMatch(PKM pk, uint top, uint bot, ReadOnlySpan <uint> IVs, out PIDIV pidiv) { if (pk.Version != (int)GameVersion.CXD || pk.Species is not((int)Species.Espeon or(int) Species.Umbreon)) { 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(CXD_ColoStarter, origin); return(true); } return(GetNonMatch(out pidiv)); }
/// <summary> /// Checks if the PIDIV can originate from /// </summary> private static bool GetCanOriginateFrom(TeamLock[] possibleTeams, PIDIV info) { return(LockFinder.IsAllShadowLockValid(info, possibleTeams)); }
private static IEnumerable <Frame> GetRefinedSeeds(IEnumerable <Frame> frames, FrameGenerator info, PIDIV pidiv) { var refined = RefineFrames(frames, info); if (pidiv.Type == PIDType.CuteCharm && info.FrameType != FrameType.MethodH) // only permit cute charm successful frames { return(refined.Where(z => (z.Lead & ~LeadRequired.UsesLevelCall) == LeadRequired.CuteCharm)); } return(refined); }
private static bool GetModified8BitMatch(PKM pk, uint pid, out PIDIV pidiv) { return(pk.Gen4 ? (pid <= 0xFF && GetCuteCharmMatch(pk, pid, out pidiv)) || GetG5MGShinyMatch(pk, pid, out pidiv) : GetG5MGShinyMatch(pk, pid, out pidiv) || (pid <= 0xFF && GetCuteCharmMatch(pk, pid, out pidiv))); }
private static bool GetModifiedPIDMatch(PKM pk, uint pid, ReadOnlySpan <uint> IVs, out PIDIV pidiv) { if (pk.IsShiny) { if (GetChainShinyMatch(pk, pid, IVs, out pidiv)) { return(true); } if (GetModified8BitMatch(pk, pid, out pidiv)) { return(true); } } else { if (pid <= 0xFF && GetCuteCharmMatch(pk, pid, out pidiv)) { return(true); } } return(GetPokewalkerMatch(pk, pid, out pidiv)); }
private static bool GetNonMatch(out PIDIV pidiv) { pidiv = PIDIV.None; return(false); }
private static bool GetLCRNGMatch(uint top, uint bot, ReadOnlySpan <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(Method_1, seed); return(true); } var E = RNG.LCRNG.Next(D); var ivE = E >> 16 & 0x7FFF; if (iv2 == ivE) // ABCE { pidiv = new PIDIV(Method_4, seed); 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(Method_2, seed); return(true); } } } reg = GetSeedsFromPIDSkip(RNG.LCRNG, top, bot); foreach (var seed in reg) { // A and B are already used by PID var C = RNG.LCRNG.Advance(seed, 3); // Method 3 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) { continue; } pidiv = new PIDIV(Method_3, seed); return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetBACDMatch(PKM pk, uint pid, ReadOnlySpan <uint> IVs, out PIDIV pidiv) { var bot = GetIVChunk(IVs, 0); var top = GetIVChunk(IVs, 3); var reg = GetSeedsFromIVs(RNG.LCRNG, top, bot); PIDType type = BACD_U; foreach (var seed in reg) { var B = seed; var A = RNG.LCRNG.Prev(B); var low = B >> 16; var PID = (A & 0xFFFF0000) | low; if (PID != pid) { uint idxor = (uint)(pk.TID ^ pk.SID); bool isShiny = (idxor ^ PID >> 16 ^ (PID & 0xFFFF)) < 8; if (!isShiny) { if (!pk.IsShiny) // check for nyx antishiny { if (!IsBACD_U_AX(idxor, pid, low, A, ref type)) { continue; } } else // check for force shiny pk { if (!IsBACD_U_S(idxor, pid, low, ref A, ref type)) { continue; } } } else if (!IsBACD_U_AX(idxor, pid, low, A, ref type)) { if ((PID + 8 & 0xFFFFFFF8) != pid) { continue; } type = BACD_U_A; } } var s = RNG.LCRNG.Prev(A); // Check for prior Restricted seed var sn = s; for (int i = 0; i < 3; i++, sn = RNG.LCRNG.Prev(sn)) { if ((sn & 0xFFFF0000) != 0) { continue; } // shift from unrestricted enum val to restricted enum val pidiv = new PIDIV(--type, sn); return(true); } // no restricted seed found, thus unrestricted pidiv = new PIDIV(type, s); return(true); } return(GetNonMatch(out pidiv)); }
private static bool GetLCRNGUnownMatch(uint top, uint bot, ReadOnlySpan <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(Method_1_Unown, seed); return(true); } var E = RNG.LCRNG.Next(D); var ivE = E >> 16 & 0x7FFF; if (iv2 == ivE) // BACE { pidiv = new PIDIV(Method_4_Unown, seed); 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(Method_2_Unown, seed); return(true); } } } reg = GetSeedsFromPIDSkip(RNG.LCRNG, bot, top); // reversed! foreach (var seed in reg) { // A and B are already used by PID var C = RNG.LCRNG.Advance(seed, 3); // Method 3 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) { continue; } pidiv = new PIDIV(Method_3_Unown, seed); return(true); } return(GetNonMatch(out pidiv)); }