mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-04-25 08:10:48 -05:00
EncDB: Fix colo starter yield
Improve enc->ck3 creation, inline the shiny/gender reroll logic instead of trying again outside the loop. Rewrite the pidiv logic to be more obvious colo starters now show up in encdb list
This commit is contained in:
parent
325f75e3d3
commit
16aba45371
|
|
@ -66,7 +66,8 @@ public bool MoveNext()
|
|||
Index = 0; State = YieldState.StaticColoStarters; goto case YieldState.StaticColoStarters;
|
||||
case YieldState.StaticColoStarters:
|
||||
if (TryGetNext(Encounters3Colo.Starters))
|
||||
Index = 0; State = YieldState.StaticColoGift; goto case YieldState.StaticColoGift;
|
||||
return true;
|
||||
Index = 0; State = YieldState.StaticColoGift; goto case YieldState.StaticColoGift;
|
||||
case YieldState.StaticColoGift:
|
||||
if (TryGetNext(Encounters3Colo.Gifts))
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,15 @@ public static class XDRNG
|
|||
private const uint Add9 = unchecked((Add8 * Mult) + Add); // 0xA8D2826B
|
||||
private const uint rAdd9 = unchecked((rAdd8 * rMult) + rAdd);// 0x46C51ED9
|
||||
|
||||
private const uint rMult10 = unchecked(rMult9 * rMult); // 0xC6169599
|
||||
private const uint rAdd10 = unchecked((rAdd9 * rMult) + rAdd);// 0x3E86BD4E
|
||||
|
||||
private const uint rMult11 = unchecked(rMult10 * rMult);
|
||||
private const uint rAdd11 = unchecked((rAdd10 * rMult) + rAdd);
|
||||
|
||||
private const uint rMult12 = unchecked(rMult11 * rMult);
|
||||
private const uint rAdd12 = unchecked((rAdd11 * rMult) + rAdd);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Next (uint seed) => (seed * Mult ) + Add ;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Next2(uint seed) => (seed * Mult2) + Add2;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Next3(uint seed) => (seed * Mult3) + Add3;
|
||||
|
|
@ -81,6 +90,31 @@ public static class XDRNG
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev7(uint seed) => (seed * rMult7) + rAdd7;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev8(uint seed) => (seed * rMult8) + rAdd8;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev9(uint seed) => (seed * rMult9) + rAdd9;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev10(uint seed) => (seed * rMult10) + rAdd10;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev11(uint seed) => (seed * rMult11) + rAdd11;
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint Prev12(uint seed) => (seed * rMult12) + rAdd12;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next 16 bits of the next RNG seed.
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed to advance one step.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Next16(ref uint seed)
|
||||
{
|
||||
seed = Next(seed);
|
||||
return seed >> 16;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the next 16 bits of the next RNG seed.
|
||||
/// </summary>
|
||||
/// <param name="seed">Seed to advance one step.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static uint Next15(ref uint seed)
|
||||
{
|
||||
seed = Next(seed);
|
||||
return (seed >> 16) & 0x7FFF;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the RNG seed to the next state value a specified amount of times.
|
||||
|
|
|
|||
|
|
@ -62,41 +62,39 @@ public static bool IsXDStarterValid(uint seed, uint TID16, uint SID16)
|
|||
/// Checks if the Colosseum starter correlation can be obtained with the trainer's IDs.
|
||||
/// </summary>
|
||||
/// <param name="species">Species of the starter, to indicate Espeon vs Umbreon</param>
|
||||
/// <param name="seed">Seed the PID/IV is generated with</param>
|
||||
/// <param name="origin">Seed the PID/IV is generated with</param>
|
||||
/// <param name="TID16">Trainer ID of the trainer</param>
|
||||
/// <param name="SID16">Secret ID of the trainer</param>
|
||||
/// <param name="pkPID">PID of the entity</param>
|
||||
/// <param name="IV1">First 3 IVs combined</param>
|
||||
/// <param name="IV2">Last 3 IVs combined</param>
|
||||
public static bool IsColoStarterValid(ushort species, ref uint seed, ushort TID16, ushort SID16, uint pkPID, uint IV1, uint IV2)
|
||||
public static bool IsColoStarterValid(ushort species, ref uint origin, ushort TID16, ushort SID16, uint pkPID, uint IV1, uint IV2)
|
||||
{
|
||||
// reverse the seed the bare minimum
|
||||
uint SIDf = species == (int)Species.Espeon
|
||||
? XDRNG.Prev9(seed)
|
||||
: XDRNG.Prev2(seed);
|
||||
// Input seed is right after the TID/SID and 2x fake rolls. Reverse the seed to the first possible SID seed value.
|
||||
var seed = species == (int)Species.Espeon
|
||||
? XDRNG.Prev12(origin)
|
||||
: XDRNG.Prev3(origin);
|
||||
|
||||
// reverse until we find the TID16/SID16, then run the generation forward to see if it matches our inputs.
|
||||
// Reverse until we find the TID16/SID16, then run the generation forward to see if it matches our inputs.
|
||||
const int arbitraryLookback = 8;
|
||||
int ctr = 0;
|
||||
uint temp;
|
||||
while ((temp = XDRNG.Prev(SIDf)) >> 16 != TID16 || SIDf >> 16 != SID16)
|
||||
while (true)
|
||||
{
|
||||
SIDf = temp;
|
||||
if (ctr > 32) // arbitrary
|
||||
return false;
|
||||
ctr++;
|
||||
if (seed >> 16 == SID16 && XDRNG.Prev(seed) >> 16 == TID16)
|
||||
{
|
||||
origin = XDRNG.Prev2(seed);
|
||||
break; // result!
|
||||
}
|
||||
if (++ctr == arbitraryLookback)
|
||||
return false; // no valid seed found
|
||||
seed = XDRNG.Prev2(seed);
|
||||
}
|
||||
|
||||
var next = XDRNG.Next(SIDf);
|
||||
|
||||
// generate Umbreon
|
||||
var PIDIV = GenerateValidColoStarterPID(ref next, TID16, SID16);
|
||||
var PIDIV = GenerateValidColoStarter(ref seed, TID16, SID16);
|
||||
if (species == (int)Species.Espeon) // need Espeon, which is immediately next
|
||||
PIDIV = GenerateValidColoStarterPID(ref next, TID16, SID16);
|
||||
|
||||
if (!PIDIV.Equals(pkPID, IV1, IV2))
|
||||
return false;
|
||||
seed = XDRNG.Prev2(SIDf);
|
||||
return true;
|
||||
PIDIV = GenerateValidColoStarter(ref seed, TID16, SID16);
|
||||
return PIDIV.Equals(pkPID, IV1, IV2);
|
||||
}
|
||||
|
||||
private readonly record struct PIDIVGroup(uint PID, uint IV1, uint IV2)
|
||||
|
|
@ -104,36 +102,31 @@ public static bool IsColoStarterValid(ushort species, ref uint seed, ushort TID1
|
|||
public bool Equals(uint pid, uint iv1, uint iv2) => PID == pid && IV1 == iv1 && IV2 == iv2;
|
||||
}
|
||||
|
||||
private static PIDIVGroup GenerateValidColoStarterPID(ref uint uSeed, ushort TID16, ushort SID16)
|
||||
{
|
||||
uSeed = XDRNG.Next2(uSeed); // skip fakePID
|
||||
var IV1 = (uSeed >> 16) & 0x7FFF;
|
||||
uSeed = XDRNG.Next(uSeed);
|
||||
var IV2 = (uSeed >> 16) & 0x7FFF;
|
||||
uSeed = XDRNG.Next(uSeed);
|
||||
uSeed = XDRNG.Next(uSeed); // skip ability call
|
||||
var PID = GenerateStarterPID(ref uSeed, TID16, SID16);
|
||||
public static void SkipValidColoStarter(ref uint seed, ushort TID16, ushort SID16) => GenerateValidColoStarter(ref seed, TID16, SID16);
|
||||
|
||||
uSeed = XDRNG.Next2(uSeed); // PID calls consumed
|
||||
private static PIDIVGroup GenerateValidColoStarter(ref uint seed, ushort TID16, ushort SID16)
|
||||
{
|
||||
seed = XDRNG.Next2(seed); // skip fakePID
|
||||
var IV1 = XDRNG.Next15(ref seed);
|
||||
var IV2 = XDRNG.Next15(ref seed);
|
||||
seed = XDRNG.Next(seed); // ability call
|
||||
var PID = GenerateStarterPID(ref seed, TID16, SID16);
|
||||
|
||||
return new PIDIVGroup(PID, IV1, IV2);
|
||||
}
|
||||
|
||||
private static bool IsShiny(ushort TID16, ushort SID16, uint PID) => ((PID >> 16) ^ TID16 ^ SID16 ^ (PID & 0xFFFF)) < 8;
|
||||
|
||||
private static uint GenerateStarterPID(ref uint uSeed, ushort TID16, ushort SID16)
|
||||
public static uint GenerateStarterPID(ref uint seed, ushort TID16, ushort SID16)
|
||||
{
|
||||
uint PID;
|
||||
const byte ratio = 0x1F; // 12.5% F (can't be female)
|
||||
while (true)
|
||||
{
|
||||
var next = XDRNG.Next(uSeed);
|
||||
PID = (uSeed & 0xFFFF0000) | (next >> 16);
|
||||
var first = seed = XDRNG.Next(seed); // first PID roll
|
||||
var second = seed = XDRNG.Next(seed); // second PID roll
|
||||
var PID = (first & 0xFFFF0000) | (second >> 16);
|
||||
if ((PID & 0xFF) >= ratio && !IsShiny(TID16, SID16, PID))
|
||||
break;
|
||||
uSeed = XDRNG.Next(next);
|
||||
return PID;
|
||||
}
|
||||
|
||||
return PID;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,26 +81,38 @@ private static void SetValuesFromSeedBACD(PKM pk, PIDType type, uint seed)
|
|||
|
||||
private static void SetValuesFromSeedXDRNG(PKM pk, uint seed)
|
||||
{
|
||||
switch (pk.Species)
|
||||
var species = pk.Species;
|
||||
switch (species)
|
||||
{
|
||||
case (int)Species.Umbreon or (int)Species.Eevee: // Colo Umbreon, XD Eevee
|
||||
pk.TID16 = (ushort)((seed = XDRNG.Next(seed)) >> 16);
|
||||
pk.SID16 = (ushort)((seed = XDRNG.Next(seed)) >> 16);
|
||||
seed = XDRNG.Next2(seed); // PID calls consumed
|
||||
pk.TID16 = (ushort)XDRNG.Next16(ref seed);
|
||||
pk.SID16 = (ushort)XDRNG.Next16(ref seed);
|
||||
seed = XDRNG.Next2(seed); // fake PID
|
||||
break;
|
||||
case (int)Species.Espeon: // Colo Espeon
|
||||
pk.TID16 = (ushort)((seed = XDRNG.Next(seed)) >> 16);
|
||||
pk.SID16 = (ushort)((seed = XDRNG.Next(seed)) >> 16);
|
||||
seed = XDRNG.Next9(seed); // PID calls consumed, skip over Umbreon
|
||||
var tid = pk.TID16 = (ushort)XDRNG.Next16(ref seed);
|
||||
var sid = pk.SID16 = (ushort)XDRNG.Next16(ref seed);
|
||||
LockFinder.SkipValidColoStarter(ref seed, tid, sid);
|
||||
seed = XDRNG.Next2(seed); // fake PID
|
||||
break;
|
||||
}
|
||||
var A = XDRNG.Next(seed); // IV1
|
||||
var B = XDRNG.Next(A); // IV2
|
||||
var C = XDRNG.Next(B); // Ability?
|
||||
var D = XDRNG.Next(C); // PID
|
||||
var E = XDRNG.Next(D); // PID
|
||||
var C = XDRNG.Next(B); // Ability
|
||||
|
||||
if (species is (int)Species.Umbreon or (int)Species.Espeon)
|
||||
{
|
||||
// Reuse existing logic.
|
||||
pk.PID = LockFinder.GenerateStarterPID(ref C, pk.TID16, pk.SID16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate PID.
|
||||
var D = XDRNG.Next(C); // PID
|
||||
var E = XDRNG.Next(D); // PID
|
||||
pk.PID = (D & 0xFFFF0000) | (E >> 16);
|
||||
}
|
||||
|
||||
pk.PID = (D & 0xFFFF0000) | (E >> 16);
|
||||
Span<int> IVs = stackalloc int[6];
|
||||
MethodFinder.GetIVsInt32(IVs, A >> 16, B >> 16);
|
||||
pk.SetIVs(IVs);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user