mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-10-01 08:46:40 -05:00
Add ivs->channel seed recovery
Still lack IVs/nature/shiny request for the BACD/M2 variants, maybe in the future those can be added.
This commit is contained in:
@@ -269,6 +269,24 @@ private static uint GetMethod2(ref uint seed)
|
||||
|
||||
private static uint SetPINGAChannel(PK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
if (criteria.IsSpecifiedIVsAll())
|
||||
{
|
||||
Span<uint> seeds = stackalloc uint[XDRNG.MaxCountSeedsChannel];
|
||||
var count = XDRNG.GetSeedsChannel(seeds, (uint)criteria.IV_HP, (uint)criteria.IV_ATK, (uint)criteria.IV_DEF, (uint)criteria.IV_SPA, (uint)criteria.IV_SPD, (uint)criteria.IV_SPE);
|
||||
foreach (var seed in seeds[..count])
|
||||
{
|
||||
if (!ChannelJirachi.IsPossible(seed))
|
||||
continue;
|
||||
PIDGenerator.SetValuesFromSeedChannel(pk, seed);
|
||||
var pid = pk.EncryptionConstant;
|
||||
if (criteria.IsSpecifiedNature() && !criteria.IsSatisfiedNature((Nature)(pid % 25)))
|
||||
continue; // try again
|
||||
if (criteria.Shiny.IsShiny() != ShinyUtil.GetIsShiny(pk.ID32, pid, 8))
|
||||
continue; // try again
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
uint seed = Util.Rand32();
|
||||
|
||||
@@ -105,6 +105,17 @@ public static uint Next16(ref uint seed)
|
||||
return seed >> 16;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the upper 5 bits of the next RNG seed.
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed to advance one step.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Next5(ref uint seed)
|
||||
{
|
||||
seed = Next(seed);
|
||||
return seed >> 27;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the upper 0x7FFF bits of the next RNG seed.
|
||||
/// </summary>
|
||||
@@ -177,8 +188,7 @@ public static uint GetSequentialIV32(uint seed)
|
||||
uint result = 0;
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
seed = Next(seed);
|
||||
var value = seed >> 27; // extract top 5 bits
|
||||
var value = Next5(ref seed); // extract top 5 bits
|
||||
result |= value << (i * 5);
|
||||
}
|
||||
return result;
|
||||
@@ -190,6 +200,7 @@ public static uint GetSequentialIV32(uint seed)
|
||||
// Instead of using yield and iterators, we calculate all results in a tight loop and return the count found.
|
||||
public const int MaxCountSeedsPID = 2;
|
||||
public const int MaxCountSeedsIV = 6;
|
||||
public const int MaxCountSeedsChannel = 12;
|
||||
|
||||
// Euclidean division constants
|
||||
private const uint Sub = Add - 0xFFFF;
|
||||
@@ -272,6 +283,67 @@ public static int GetSeedsIVs(Span<uint> result, uint first, uint second)
|
||||
return ctr;
|
||||
}
|
||||
|
||||
public static int GetSeedsChannel(Span<uint> result, uint hp, uint atk, uint def, uint spa, uint spd, uint spe)
|
||||
{
|
||||
// Recovers seeds from 6 successive calls to rand() that returns the top 5 bits of each.
|
||||
// Mult(j) = Mult^j
|
||||
// Add(j) = Add * (Mult^0 + Mult^1 + ... + Mult^(j-1))
|
||||
// Using j = 3 and XDRNG gives Mult = 0x45c82be5 and Add = 0xd2f65b55
|
||||
const uint mult = Mult3; // Modified mult (3 advances)
|
||||
const uint sub = 0xcaf65b56; // Modified add - 0x7ffffff
|
||||
const ulong b = 0x22e415e_ea37d41a; // (Modified mult + 1) * 0x7ffffff
|
||||
|
||||
const ulong prime = 3;
|
||||
const ulong add = 0x3_0000_0000; // prime * 0x1_0000_0000
|
||||
const uint rmax = 0x__1800_0000; // prime * 0x__0800_0000
|
||||
const ulong skip = 0x661D29; // prime * 2^32 % mult
|
||||
|
||||
uint first = hp << 27;
|
||||
uint t = (((spe << 27) - mult * first) - sub);
|
||||
uint kmax = (uint)((b - t) >> 32);
|
||||
ulong x = (t * prime) % mult;
|
||||
|
||||
int ctr = 0;
|
||||
for (ulong k = 0; k <= kmax;)
|
||||
{
|
||||
var r = (x + skip * k) % mult;
|
||||
var m = r % prime;
|
||||
if (m != 0)
|
||||
{
|
||||
m = m == 1 ? 2u : 1u;
|
||||
r += m * skip;
|
||||
k += (byte)m;
|
||||
}
|
||||
|
||||
var tmp = k << 32 | t;
|
||||
while (r < rmax && k <= kmax)
|
||||
{
|
||||
uint seed = first | (uint)(tmp / mult); // hp
|
||||
if (Next5(ref seed) == atk)
|
||||
{
|
||||
if (Next5(ref seed) == def)
|
||||
{
|
||||
_ = Next5(ref seed); // spe
|
||||
if (Next5(ref seed) == spa)
|
||||
{
|
||||
if (Next5(ref seed) == spd)
|
||||
result[ctr++] = Prev12(seed); // unroll to origin
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
r += prime * skip;
|
||||
k += prime;
|
||||
tmp += add;
|
||||
}
|
||||
|
||||
// Rounding up without using floats
|
||||
k += ((mult - r) + skip - 1) / skip;
|
||||
}
|
||||
|
||||
return ctr;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Multiplication constants for jumping 2^(index) frames forward.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user