mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-10-01 09:06:42 -05:00
CXD: check naming screen->TID/SID frame pattern
Adapted from e5255b1313/PokemonCoRNGLibrary/Util/LCGExtensions.cs (L15)
This commit is contained in:
@@ -94,6 +94,9 @@ public static class XDRNG
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev11(uint seed) => (seed * rMult11) + rAdd11;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev12(uint seed) => (seed * rMult12) + rAdd12;
|
||||
|
||||
public static uint Next1000(uint seed) => 0xDD867B21 * seed + 0xD252C5A8;
|
||||
public static uint Prev1000(uint seed) => 0x251CC8E1 * seed + 0x94750758;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the upper 16 bits of the next RNG seed.
|
||||
/// </summary>
|
||||
|
||||
@@ -100,20 +100,20 @@ public static bool SetFromIVsCXD<TEntity>(TEntity pk, EncounterCriteria criteria
|
||||
/// </summary>
|
||||
/// <param name="tid">Generation 3 Trainer ID</param>
|
||||
/// <param name="sid">Generation 3 Secret ID</param>
|
||||
/// <param name="seed">Possible starting seed</param>
|
||||
/// <param name="origin">Possible starting seed</param>
|
||||
/// <returns>True if a seed was found, false if no seed was found</returns>
|
||||
public static bool TryGetSeedTrainerID(ushort tid, ushort sid, out uint seed)
|
||||
public static bool TryGetSeedTrainerID(ushort tid, ushort sid, out uint origin)
|
||||
{
|
||||
Span<uint> seeds = stackalloc uint[XDRNG.MaxCountSeedsPID];
|
||||
var count = XDRNG.GetSeeds(seeds, (uint)tid << 16, (uint)sid << 16);
|
||||
|
||||
if (count == 0)
|
||||
foreach (var s in seeds[..count])
|
||||
{
|
||||
seed = 0;
|
||||
return false;
|
||||
var prev1k = XDRNG.Prev1000(s);
|
||||
if (IsReachableFromNameScreen(prev1k, out origin))
|
||||
return true;
|
||||
}
|
||||
seed = seeds[0];
|
||||
return true;
|
||||
origin = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool TryGetShinySID(ushort tid, out ushort sid, uint xor, uint bits)
|
||||
@@ -626,4 +626,36 @@ public static bool TryGetOriginSeedStarterXD(PKM pk, out uint result)
|
||||
result = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the provided <see cref="seed"/> can be landed at after confirming the player name.
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed that goes on to generate the player TID/SID (after advancing 1000 frames)</param>
|
||||
/// <param name="origin">Current seed that confirms the player name</param>
|
||||
/// <returns>True if <see cref="seed"/> can be reached via <see cref="origin"/></returns>
|
||||
/// <remarks>https://github.com/yatsuna827/PokemonCoRNGLibrary/blob/e5255b13134ab3a2119788c40b5e71ee48d849b0/PokemonCoRNGLibrary/Util/LCGExtensions.cs#L15</remarks>
|
||||
public static bool IsReachableFromNameScreen(uint seed, out uint origin)
|
||||
{
|
||||
// rand() / 10 == 0 is a skip
|
||||
const ushort SEED_THRESHOLD = 0x1999; // Only need the upper 16 bits
|
||||
|
||||
var p1 = XDRNG.Prev16(ref seed) > SEED_THRESHOLD;
|
||||
var p2 = XDRNG.Prev16(ref seed) > SEED_THRESHOLD;
|
||||
var p3 = XDRNG.Prev16(ref seed) > SEED_THRESHOLD;
|
||||
var p4 = XDRNG.Prev16(ref seed) > SEED_THRESHOLD;
|
||||
|
||||
if (p1 && p2 && p3 && p4)
|
||||
{
|
||||
origin = seed;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (XDRNG.Prev16(ref seed) <= SEED_THRESHOLD && IsReachableFromNameScreen(XDRNG.Prev(seed), out origin)) return true;
|
||||
if (XDRNG.Prev16(ref seed) <= SEED_THRESHOLD && p1 && IsReachableFromNameScreen(XDRNG.Prev(seed), out origin)) return true;
|
||||
if (XDRNG.Prev16(ref seed) <= SEED_THRESHOLD && p1 && p2 && IsReachableFromNameScreen(XDRNG.Prev(seed), out origin)) return true;
|
||||
if (XDRNG.Prev16(ref seed) <= SEED_THRESHOLD && p1 && p2 && p3 && IsReachableFromNameScreen(XDRNG.Prev(seed), out origin)) return true;
|
||||
|
||||
origin = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,14 +142,20 @@ public void PIDIVMatchingTest5()
|
||||
MethodFinder.Analyze(pkS5).Type.Should().Be(PIDType.G5MGShiny);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void PIDIVPokeSpotTest()
|
||||
{
|
||||
// XD PokeSpots: Check all 3 Encounter Slots (examples are one for each location).
|
||||
MethodPokeSpot.TryGetOriginSeedPID(0x7B2D9DA7, 0, out _).Should().BeTrue(); // Zubat (Cave) (Common)
|
||||
MethodPokeSpot.TryGetOriginSeedPID(0x3EE9AF66, 1, out _).Should().BeTrue(); // Gligar (Rock) (Uncommon)
|
||||
MethodPokeSpot.TryGetOriginSeedPID(0x9B667F3C, 2, out _).Should().BeTrue(); // Surskit (Oasis) (Rare)
|
||||
}
|
||||
[Theory]
|
||||
[InlineData(0x7B2D9DA7, 0)] // Zubat (Cave) (Common)
|
||||
[InlineData(0x3EE9AF66, 1)] // Gligar (Rock) (Uncommon)
|
||||
[InlineData(0x9B667F3C, 2)] // Surskit (Oasis) (Rare)
|
||||
public void PIDIVPokeSpotTest(uint pid, byte slot) => MethodPokeSpot.TryGetOriginSeedPID(pid, slot, out _).Should().BeTrue();
|
||||
|
||||
[Theory]
|
||||
[InlineData(62714, 62938)]
|
||||
[InlineData(05724, 31840)]
|
||||
[InlineData(31827, 52374)]
|
||||
[InlineData(34952, 34952)]
|
||||
[InlineData(31827, 00123, false)]
|
||||
[InlineData(34952, 01337, false)]
|
||||
public void CXDTrainerTest(ushort tid, ushort sid, bool expect = true) => MethodCXD.TryGetSeedTrainerID(tid, sid, out _).Should().Be(expect);
|
||||
|
||||
[Theory]
|
||||
[InlineData(30, 31, 31, 14, 31, 31, 0x28070031, 024, PokewalkerSeedType.NoStroll)]
|
||||
|
||||
Reference in New Issue
Block a user