mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-10-01 09:06:42 -05:00
Add more generator filtering criteria
Gen6+ slots now try to give shinies if possible & requested Gen3/4 slots now try to respect IV requests if only a couple are requested Removes PIDGenerator; no remaining uses (either all inlined or extracted to specialized generator classes). API usage wasn't recommended anyway, as it was incomplete and did not honor all correlations. We want to try to generate it right the first time.
This commit is contained in:
@@ -85,7 +85,7 @@ private void SetPINGA(CK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
if (!IsEReader)
|
||||
SetPINGA_Regular(pk, criteria, pi);
|
||||
else
|
||||
SetPINGA_EReader(pk);
|
||||
SetPINGA_EReader(pk, criteria);
|
||||
}
|
||||
|
||||
private void SetPINGA_Regular(CK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
@@ -98,7 +98,7 @@ private void SetPINGA_Regular(CK3 pk, EncounterCriteria criteria, PersonalInfo3
|
||||
this.SetRandom(pk, EncounterCriteria.Unrestricted, pi, noShiny: false, seed);
|
||||
}
|
||||
|
||||
private void SetPINGA_EReader(CK3 pk)
|
||||
private void SetPINGA_EReader(CK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
// E-Reader have all IVs == 0
|
||||
// Skip setting IVs.
|
||||
@@ -113,15 +113,27 @@ private void SetPINGA_EReader(CK3 pk)
|
||||
int ctr = 0;
|
||||
const int max = 100_000;
|
||||
var rnd = Util.Rand;
|
||||
var gr = pk.PersonalInfo.Gender;
|
||||
do
|
||||
{
|
||||
var seed = rnd.Rand32();
|
||||
PIDGenerator.SetValuesFromSeedXDRNG_EReader(pk, seed);
|
||||
if (pk.Nature != nature || pk.Gender != gender)
|
||||
var D = XDRNG.Prev3(seed); // PID
|
||||
var E = XDRNG.Next(D); // PID
|
||||
var pid = (D & 0xFFFF0000) | (E >> 16);
|
||||
|
||||
if ((Nature)(pid % 25) != nature || EntityGender.GetFromPIDAndRatio(pid, gr) != gender)
|
||||
continue;
|
||||
|
||||
if (criteria.Shiny.IsShiny() && !ShinyUtil.GetIsShiny(pk.ID32, pid, 8))
|
||||
continue;
|
||||
|
||||
var result = LockFinder.IsAllShadowLockValid(this, seed, pk);
|
||||
if (result)
|
||||
break;
|
||||
if (!result)
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.RefreshAbility(0);
|
||||
// IVs always 0 for E-Reader shadows.
|
||||
}
|
||||
while (++ctr <= max);
|
||||
}
|
||||
|
||||
@@ -98,15 +98,58 @@ private int GetTemplateLanguage(ITrainerInfo tr)
|
||||
private void SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
var gr = pi.Gender;
|
||||
bool truncate = IsRoamingTruncatedIVs;
|
||||
if (criteria.IsSpecifiedIVsAll() && !truncate)
|
||||
if (IsRoamingTruncatedIVs)
|
||||
{
|
||||
SetRoamerPINGA(pk, criteria);
|
||||
return;
|
||||
}
|
||||
if (criteria.IsSpecifiedIVsAll())
|
||||
{
|
||||
if (TrySetMethod1(pk, criteria, gr))
|
||||
return;
|
||||
}
|
||||
SetMethod1(pk, criteria, gr, Util.Rand32());
|
||||
if (truncate) // Never happens for eggs or dual-ability encounters.
|
||||
pk.IV32 &= 0xFF;
|
||||
}
|
||||
|
||||
private static bool SetRoamerPINGA(PK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
// For every possible 8-bit IV combination, check if it meets the criteria.
|
||||
var id32 = pk.ID32;
|
||||
for (uint i = 0; i <= byte.MaxValue; i++)
|
||||
{
|
||||
var iv32 = i;
|
||||
|
||||
// IVs can only ever be Hidden Power: Fighting. Don't bother checking if it matches.
|
||||
if (!criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
// Satisfactory IVs; now check PID/nature/shininess.
|
||||
var frame = iv32 << 16;
|
||||
for (uint hi = 0; hi <= byte.MaxValue; hi++)
|
||||
{
|
||||
for (uint lo = 0; lo <= ushort.MaxValue; lo++)
|
||||
{
|
||||
var state = frame | (hi << 24) | lo;
|
||||
var rand2 = LCRNG.Prev16(ref state);
|
||||
var rand1 = LCRNG.Prev16(ref state);
|
||||
var pid = (rand2 << 16) | rand1;
|
||||
if (criteria.IsSpecifiedNature() && !criteria.IsSatisfiedNature((Nature)(pid % 25)))
|
||||
continue;
|
||||
bool shiny = ShinyUtil.GetIsShiny(id32, pid, 8);
|
||||
if (criteria.Shiny.IsShiny() != shiny)
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.IV32 = iv32;
|
||||
pk.RefreshAbility(0);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Should never happen, but just in case.
|
||||
SetMethod1(pk, criteria, 255, Util.Rand32());
|
||||
pk.IV32 &= 0xFF; // truncate to 8 bits (value storage fail)
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool TrySetMethod1(PK3 pk, EncounterCriteria criteria, byte gr)
|
||||
@@ -143,6 +186,7 @@ private static bool TrySetMethod1(PK3 pk, EncounterCriteria criteria, byte gr)
|
||||
private static void SetMethod1(PK3 pk, in EncounterCriteria criteria, byte gr, uint seed)
|
||||
{
|
||||
var id32 = pk.ID32;
|
||||
bool filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
while (true)
|
||||
{
|
||||
var pid = ClassicEraRNG.GetSequentialPID(ref seed);
|
||||
@@ -164,6 +208,8 @@ private static void SetMethod1(PK3 pk, in EncounterCriteria criteria, byte gr, u
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.IV32 |= iv32;
|
||||
|
||||
@@ -208,7 +208,7 @@ private uint SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.IV32 = PIDGenerator.GetIVsFromSeedSequentialLCRNG(ref seed);
|
||||
pk.IV32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
pk.RefreshAbility((int)(pk.PID & 1));
|
||||
return seed;
|
||||
}
|
||||
@@ -220,7 +220,7 @@ public bool GenerateSeed32(PKM pk, uint seed)
|
||||
if (Method is Channel)
|
||||
{
|
||||
seed = ChannelJirachi.SkipToPIDIV(seed);
|
||||
PIDGenerator.SetValuesFromSeedChannel(pk3, seed);
|
||||
SetValuesFromSeedChannel(pk3, seed);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ public bool GenerateSeed32(PKM pk, uint seed)
|
||||
_ when Method is Method_2 => GetMethod2(ref seed),
|
||||
_ => GetRegular(ref seed),
|
||||
};
|
||||
pk3.IV32 = PIDGenerator.GetIVsFromSeedSequentialLCRNG(ref seed);
|
||||
pk3.IV32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -248,7 +248,7 @@ private static bool TrySetWishmkrShiny(PK3 pk, EncounterCriteria criteria)
|
||||
if (filterNature && !criteria.IsSatisfiedNature((Nature)(pid % 25)))
|
||||
continue; // try again
|
||||
|
||||
var iv32 = PIDGenerator.GetIVsFromSeedSequentialLCRNG(ref seed);
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue; // try again
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
@@ -278,7 +278,7 @@ private static uint SetPINGAChannel(PK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
if (!ChannelJirachi.IsPossible(seed))
|
||||
continue;
|
||||
PIDGenerator.SetValuesFromSeedChannel(pk, seed);
|
||||
SetValuesFromSeedChannel(pk, seed);
|
||||
var pid = pk.EncryptionConstant;
|
||||
if (criteria.IsSpecifiedNature() && !criteria.IsSatisfiedNature((Nature)(pid % 25)))
|
||||
continue; // try again
|
||||
@@ -288,24 +288,49 @@ private static uint SetPINGAChannel(PK3 pk, EncounterCriteria criteria)
|
||||
}
|
||||
}
|
||||
|
||||
bool filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
while (true)
|
||||
{
|
||||
uint seed = Util.Rand32();
|
||||
seed = ChannelJirachi.SkipToPIDIV(seed);
|
||||
PIDGenerator.SetValuesFromSeedChannel(pk, seed);
|
||||
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
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(pk.IV32))
|
||||
var iv32 = pk.IV32;
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue; // try again
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetValuesFromSeedChannel(PK3 pk, uint seed)
|
||||
{
|
||||
const ushort TID16 = 40122;
|
||||
var sid = XDRNG.Next16(ref seed);
|
||||
pk.ID32 = (sid << 16) | TID16;
|
||||
|
||||
var pid1 = XDRNG.Next16(ref seed);
|
||||
var pid2 = XDRNG.Next16(ref seed);
|
||||
var pid = (pid1 << 16) | pid2;
|
||||
if ((pid2 > 7 ? 0 : 1) != (pid1 ^ sid ^ TID16))
|
||||
pid ^= 0x80000000;
|
||||
pk.PID = pid;
|
||||
|
||||
pk.HeldItem = (ushort)((XDRNG.Next16(ref seed) >> 15) + 169u); // 0-Ganlon, 1-Salac
|
||||
pk.Version = GameVersion.S + (byte)(XDRNG.Next16(ref seed) >> 15); // 0-Sapphire, 1-Ruby
|
||||
pk.OriginalTrainerGender = (byte)(XDRNG.Next16(ref seed) >> 15);
|
||||
|
||||
var iv32 = XDRNG.GetSequentialIV32(seed);
|
||||
pk.SetIVs(iv32);
|
||||
}
|
||||
|
||||
private uint GetSaneSeed(uint seed) => Method switch
|
||||
{
|
||||
BACD_RBCD => Math.Clamp(seed, 3, 213), // BCD digit sum
|
||||
|
||||
@@ -73,6 +73,7 @@ public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
private static void SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
uint seed = Util.Rand32();
|
||||
var filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
var gr = pi.Gender;
|
||||
var idXor = pk.TID16; // no SID
|
||||
while (true)
|
||||
@@ -82,9 +83,14 @@ private static void SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 p
|
||||
continue; // try again
|
||||
if (criteria.IsSpecifiedGender() && !criteria.IsSatisfiedGender(EntityGender.GetFromPIDAndRatio(pid, gr)))
|
||||
continue;
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.IV32 = PIDGenerator.GetIVsFromSeedSequentialLCRNG(ref seed);
|
||||
pk.IV32 = iv32;
|
||||
pk.RefreshAbility((int)(pid & 1));
|
||||
pk.OriginalTrainerGender = (byte)GetGender(LCRNG.Next16(ref seed));
|
||||
return;
|
||||
|
||||
@@ -74,6 +74,7 @@ public PK3 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria)
|
||||
private static void SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
uint seed = Util.Rand32();
|
||||
var filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
var gr = pi.Gender;
|
||||
var idXor = pk.TID16; // no SID
|
||||
while (true)
|
||||
@@ -84,9 +85,13 @@ private static void SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 p
|
||||
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
|
||||
if (criteria.IsSpecifiedGender() && !criteria.IsSatisfiedGender(gender))
|
||||
continue;
|
||||
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
pk.PID = pid;
|
||||
pk.IV32 = PIDGenerator.GetIVsFromSeedSequentialLCRNG(ref seed);
|
||||
pk.IV32 = iv32;
|
||||
pk.RefreshAbility((int)(pid & 1));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -71,14 +71,7 @@ private void SetPINGA(XK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
if (Species == (int)Core.Species.Eevee)
|
||||
{
|
||||
// Prefer IVs if requested, rather than Trainer Matching.
|
||||
if (criteria.IsSpecifiedIVsAll() && MethodCXD.SetStarterFromIVs(pk, criteria))
|
||||
return;
|
||||
// Fall back to Trainer ID matching.
|
||||
if (MethodCXD.SetStarterFromTrainerID(pk, criteria, pk.TID16, pk.SID16))
|
||||
return;
|
||||
// Fall back to generating a random PID.
|
||||
MethodCXD.SetStarterRandom(pk, criteria, Util.Rand32());
|
||||
SetStarterPINGA(pk, criteria);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -86,6 +79,19 @@ private void SetPINGA(XK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
return;
|
||||
MethodCXD.SetRandom(pk, criteria, pi, noShiny: false, Util.Rand32());
|
||||
}
|
||||
|
||||
private static void SetStarterPINGA(XK3 pk, EncounterCriteria criteria)
|
||||
{
|
||||
// Prefer IVs if requested, rather than Trainer Matching.
|
||||
if (criteria.IsSpecifiedIVsAll() && MethodCXD.SetStarterFromIVs(pk, criteria))
|
||||
return;
|
||||
// Fall back to Trainer ID matching.
|
||||
if (MethodCXD.SetStarterFromTrainerID(pk, criteria, pk.TID16, pk.SID16))
|
||||
return;
|
||||
// Fall back to generating a random PID.
|
||||
MethodCXD.SetStarterRandom(pk, criteria, Util.Rand32());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Matching
|
||||
|
||||
@@ -159,6 +159,7 @@ private static bool TrySetMethod1(PK4 pk, in EncounterCriteria criteria, byte gr
|
||||
private static void SetMethod1(PK4 pk, in EncounterCriteria criteria, byte gr, uint seed)
|
||||
{
|
||||
var id32 = pk.ID32;
|
||||
var filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
while (true)
|
||||
{
|
||||
var pid = ClassicEraRNG.GetSequentialPID(ref seed);
|
||||
@@ -180,6 +181,8 @@ private static void SetMethod1(PK4 pk, in EncounterCriteria criteria, byte gr, u
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.IV32 |= iv32;
|
||||
@@ -227,6 +230,7 @@ private static bool TrySetChainShiny(PK4 pk, in EncounterCriteria criteria, byte
|
||||
private static void SetChainShiny(PK4 pk, in EncounterCriteria criteria, byte gr, uint seed)
|
||||
{
|
||||
var id32 = pk.ID32;
|
||||
var filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
while (true)
|
||||
{
|
||||
var pid = ClassicEraRNG.GetChainShinyPID(ref seed, id32);
|
||||
@@ -244,6 +248,8 @@ private static void SetChainShiny(PK4 pk, in EncounterCriteria criteria, byte gr
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.IV32 = iv32;
|
||||
|
||||
@@ -108,6 +108,11 @@ private void SetPINGA(PK6 pk, EncounterCriteria criteria, PersonalInfo6AO pi)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
pk.PID = rnd.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rnd.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.EncryptionConstant = rnd.Rand32();
|
||||
pk.Nature = criteria.GetNature();
|
||||
pk.Gender = criteria.GetGender(pi);
|
||||
|
||||
@@ -102,6 +102,11 @@ private void SetPINGA(PK6 pk, EncounterCriteria criteria, PersonalInfo6XY pi)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
pk.PID = rnd.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rnd.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.EncryptionConstant = rnd.Rand32();
|
||||
pk.Nature = criteria.GetNature();
|
||||
pk.Gender = criteria.GetGender(pi);
|
||||
|
||||
@@ -91,6 +91,11 @@ private void SetPINGA(PK7 pk, EncounterCriteria criteria, PersonalInfo7 pi)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
pk.PID = rnd.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rnd.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.EncryptionConstant = rnd.Rand32();
|
||||
pk.Nature = criteria.GetNature();
|
||||
pk.Gender = criteria.GetGender(pi);
|
||||
|
||||
@@ -64,6 +64,11 @@ private void SetPINGA(PB7 pk, EncounterCriteria criteria, PersonalInfo7GG pi)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
pk.PID = rnd.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rnd.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.EncryptionConstant = rnd.Rand32();
|
||||
pk.Nature = criteria.GetNature();
|
||||
pk.Gender = criteria.GetGender(pi);
|
||||
|
||||
@@ -104,6 +104,11 @@ private void SetPINGA(PK8 pk, EncounterCriteria criteria, PersonalInfo8SWSH pi)
|
||||
var rand = Util.Rand;
|
||||
pk.EncryptionConstant = rand.Rand32();
|
||||
pk.PID = rand.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rand.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.HeightScalar = PokeSizeUtil.GetRandomScalar(rand);
|
||||
pk.WeightScalar = PokeSizeUtil.GetRandomScalar(rand);
|
||||
criteria.SetRandomIVs(pk);
|
||||
|
||||
@@ -97,6 +97,11 @@ private void SetPINGA(PB8 pk, EncounterCriteria criteria, PersonalInfo8BDSP pi)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
pk.PID = rnd.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rnd.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.EncryptionConstant = rnd.Rand32();
|
||||
criteria.SetRandomIVs(pk);
|
||||
pk.Nature = pk.StatNature = criteria.GetNature();
|
||||
|
||||
@@ -172,6 +172,11 @@ private void SetPINGA(PK9 pk, EncounterCriteria criteria, PersonalInfo9SV pi)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
pk.PID = rnd.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rnd.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.EncryptionConstant = rnd.Rand32();
|
||||
criteria.SetRandomIVs(pk);
|
||||
|
||||
|
||||
@@ -129,6 +129,11 @@ private void SetPINGA(PK9 pk, EncounterCriteria criteria, PersonalInfo9SV pi)
|
||||
{
|
||||
var rnd = Util.Rand;
|
||||
pk.PID = rnd.Rand32();
|
||||
if (criteria.Shiny.IsShiny())
|
||||
pk.PID = ShinyUtil.GetShinyPID(pk.TID16, pk.SID16, pk.PID, criteria.Shiny == Shiny.AlwaysSquare ? 0 : (uint)rnd.Next(1, 15));
|
||||
else if (criteria.Shiny == Shiny.Never && pk.IsShiny)
|
||||
pk.PID ^= 0x80000000; // flip top bit to ensure non-shiny
|
||||
|
||||
pk.EncryptionConstant = rnd.Rand32();
|
||||
pk.Nature = pk.StatNature = criteria.GetNature(Nature);
|
||||
pk.Gender = criteria.GetGender(Gender, pi);
|
||||
|
||||
@@ -99,6 +99,7 @@ public static bool SetFromIVs<TEntity>(TEntity pk, in EncounterCriteria criteria
|
||||
/// </summary>
|
||||
public static bool SetStarterFromTrainerID(CK3 pk, in EncounterCriteria criteria, ushort tid, ushort sid)
|
||||
{
|
||||
var filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
var id32 = (uint)sid << 16 | tid;
|
||||
var species = pk.Species;
|
||||
// * => TID, SID, fakepid*2, [IVs, ability, PID]
|
||||
@@ -131,6 +132,8 @@ public static bool SetStarterFromTrainerID(CK3 pk, in EncounterCriteria criteria
|
||||
var iv32 = iv2 << 15 | iv1;
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
SetIVs(pk, iv1, iv2);
|
||||
@@ -265,6 +268,7 @@ private static bool IsValidTrainerCombination(in EncounterCriteria criteria, uin
|
||||
public static bool SetStarterFromTrainerID(XK3 pk, EncounterCriteria criteria, ushort tid, ushort sid)
|
||||
{
|
||||
// * => TID, SID, fakepid*2, [IVs, ability, PID]
|
||||
var filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
Span<uint> all = stackalloc uint[XDRNG.MaxCountSeedsPID];
|
||||
var count = XDRNG.GetSeeds(all, (uint)tid << 16, (uint)sid << 16);
|
||||
var seeds = all[..count];
|
||||
@@ -285,6 +289,8 @@ public static bool SetStarterFromTrainerID(XK3 pk, EncounterCriteria criteria, u
|
||||
var iv32 = iv2 << 15 | iv1;
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
SetIVs(pk, iv1, iv2);
|
||||
|
||||
@@ -15,6 +15,7 @@ public static void SetRandom<T>(this T enc, PK3 pk, PersonalInfo3 pi, EncounterC
|
||||
var (min, max) = SlotMethodH.GetRange(enc.Type, enc.SlotNumber);
|
||||
bool checkProc = MethodH.IsEncounterCheckApplicable(enc.Type);
|
||||
bool checkLevel = criteria.IsSpecifiedLevelRange() && enc.IsLevelWithinRange(criteria);
|
||||
bool filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
|
||||
// Generate Method H correlated PID and IVs, no lead (keep things simple).
|
||||
while (true)
|
||||
@@ -55,6 +56,8 @@ public static void SetRandom<T>(this T enc, PK3 pk, PersonalInfo3 pi, EncounterC
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
break; // try again
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
{
|
||||
var level = (byte)MethodH.GetRandomLevel(enc, lv, LeadRequired.None);
|
||||
@@ -78,6 +81,7 @@ public static void SetRandomUnown<T>(this T enc, PK3 pk, EncounterCriteria crite
|
||||
var (min, max) = SlotMethodH.GetRangeGrass(enc.SlotNumber);
|
||||
// Can't game the seed with % 100 increments as Unown's form calculation is based on the PID.
|
||||
|
||||
var filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
while (true)
|
||||
{
|
||||
var esv = LCRNG.Next16(ref seed) % 100;
|
||||
@@ -103,6 +107,8 @@ public static void SetRandomUnown<T>(this T enc, PK3 pk, EncounterCriteria crite
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.IV32 = iv32;
|
||||
|
||||
@@ -25,6 +25,7 @@ public static uint SetRandomJ<T>(this T enc, PK4 pk, PersonalInfo4 pi, Encounter
|
||||
bool randLevel = MethodJ.IsLevelRand(enc);
|
||||
bool checkProc = MethodJ.IsEncounterCheckApplicable(enc.Type);
|
||||
bool checkLevel = criteria.IsSpecifiedLevelRange() && enc.IsLevelWithinRange(criteria);
|
||||
bool filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
|
||||
// Generate Method J correlated PID and IVs, no lead (keep things simple).
|
||||
while (true)
|
||||
@@ -64,6 +65,8 @@ public static uint SetRandomJ<T>(this T enc, PK4 pk, PersonalInfo4 pi, Encounter
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
break; // try again
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
if (enc.Species is (ushort)Species.Unown)
|
||||
{
|
||||
|
||||
@@ -26,6 +26,7 @@ public static uint SetRandomK<T>(this T enc, PK4 pk, PersonalInfo4 pi, Encounter
|
||||
var modulo = enc.Type.IsSafari() ? 10u : 100u;
|
||||
bool checkProc = MethodK.IsEncounterCheckApplicable(enc.Type);
|
||||
bool checkLevel = criteria.IsSpecifiedLevelRange() && enc.IsLevelWithinRange(criteria);
|
||||
bool filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
|
||||
// Generate Method K correlated PID and IVs, no lead (keep things simple).
|
||||
while (true)
|
||||
@@ -88,6 +89,8 @@ public static uint SetRandomK<T>(this T enc, PK4 pk, PersonalInfo4 pi, Encounter
|
||||
var iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
break; // try again
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
|
||||
if (enc.Type is SlotType4.BugContest && !MethodK.IsAny31(iv32) && !MethodK.IsAny31(iv32 >> 16))
|
||||
break; // try again
|
||||
|
||||
@@ -325,8 +325,14 @@ public static bool GetRandomIVs(EncounterCriteria criteria, out uint iv32)
|
||||
private static bool TryApply(ref uint seed, out uint iv32, in EncounterCriteria criteria)
|
||||
{
|
||||
// Act like a Non-Stroll encounter, generate IV rand() results immediately.
|
||||
iv32 = PIDGenerator.GetIVsFromSeedSequentialLCRNG(ref seed);
|
||||
return criteria.IsSatisfiedIVs(iv32);
|
||||
var lo = LCRNG.Next15(ref seed);
|
||||
var hi = LCRNG.Next15(ref seed);
|
||||
iv32 = (hi << 15) | lo;
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
return false;
|
||||
if (!criteria.IsSatisfiedIVs(iv32))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
using System;
|
||||
using static PKHeX.Core.PIDType;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Contains a collection of methods that mutate the input Pokémon object, usually to obtain a <see cref="PIDType"/> correlation.
|
||||
/// </summary>
|
||||
public static class PIDGenerator
|
||||
{
|
||||
private static uint SetValuesFromSeedLCRNG(PKM pk, PIDType type, uint seed)
|
||||
{
|
||||
var a16 = LCRNG.Next16(ref seed);
|
||||
var b16 = LCRNG.Next16(ref seed);
|
||||
if (type is Method_3 or Method_3_Unown) // VBlank skip between PID rand() [RARE]
|
||||
b16 = LCRNG.Next16(ref seed);
|
||||
|
||||
// Unown has switched order of PID halves, "BA**"
|
||||
pk.PID = type.IsUnown() ? (a16 << 16) | b16 : (b16 << 16) | a16;
|
||||
|
||||
var c16 = LCRNG.Next15(ref seed);
|
||||
if (type is Method_2 or Method_2_Unown) // VBlank skip after PID
|
||||
c16 = LCRNG.Next15(ref seed);
|
||||
|
||||
var d16 = LCRNG.Next15(ref seed);
|
||||
if (type is Method_4 or Method_4_Unown) // VBlank skip between IVs
|
||||
d16 = LCRNG.Next15(ref seed);
|
||||
|
||||
uint iv32 = (d16 << 15) | c16;
|
||||
// Roamers only store lowest 8 bits of IV data; zero out the other bits.
|
||||
if (type == Method_1_Roamer)
|
||||
iv32 &= 0xFF;
|
||||
|
||||
pk.SetIVs(iv32);
|
||||
return d16;
|
||||
}
|
||||
|
||||
private static uint SetValuesFromSeedBACD(PKM pk, PIDType type, uint seed)
|
||||
{
|
||||
uint idxor = pk.TID16 ^ (uint)pk.SID16;
|
||||
pk.PID = GetPIDFromSeedBACD(ref seed, type, idxor);
|
||||
SetIVsFromSeedSequentialLCRNG(ref seed, pk);
|
||||
pk.RefreshAbility((int)(pk.PID & 1));
|
||||
return seed;
|
||||
}
|
||||
|
||||
private static uint GetPIDFromSeedBACD(ref uint seed, PIDType type, uint idXor) => type switch
|
||||
{
|
||||
BACD => CommonEvent3.GetRegular(ref seed),
|
||||
BACD_S => CommonEvent3.GetForceShiny(ref seed, idXor),
|
||||
BACD_AX => CommonEvent3.GetAntishiny(ref seed, idXor),
|
||||
_ => CommonEvent3.GetRegularAntishiny(ref seed, idXor),
|
||||
};
|
||||
|
||||
public static uint GetIVsFromSeedSequentialLCRNG(ref uint seed)
|
||||
{
|
||||
var c16 = LCRNG.Next15(ref seed);
|
||||
var d16 = LCRNG.Next15(ref seed);
|
||||
return (d16 << 15) | c16;
|
||||
}
|
||||
|
||||
public static void SetIVsFromSeedSequentialLCRNG(ref uint seed, PKM pk)
|
||||
{
|
||||
var iv32 = GetIVsFromSeedSequentialLCRNG(ref seed);
|
||||
pk.SetIVs(iv32);
|
||||
}
|
||||
|
||||
private static uint SetValuesFromSeedXDRNG(PKM pk, uint seed)
|
||||
{
|
||||
var species = pk.Species;
|
||||
switch (species)
|
||||
{
|
||||
case (int)Species.Umbreon or (int)Species.Eevee: // Colo Umbreon, XD Eevee
|
||||
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
|
||||
var tid = pk.TID16 = (ushort)XDRNG.Next16(ref seed);
|
||||
var sid = pk.SID16 = (ushort)XDRNG.Next16(ref seed);
|
||||
|
||||
seed = XDRNG.Next5(seed); // skip fakePID, IVs, ability
|
||||
MethodCXD.GetColoStarterPID(ref seed, tid, sid);
|
||||
seed = XDRNG.Next2(seed); // fake PID
|
||||
break;
|
||||
}
|
||||
var iv1 = XDRNG.Next15(ref seed); // IV1
|
||||
var iv2 = XDRNG.Next15(ref seed); // IV2
|
||||
|
||||
var iv32 = (iv2 << 15) | iv1;
|
||||
pk.SetIVs(iv32);
|
||||
|
||||
_ = XDRNG.Next16(ref seed); // Ability
|
||||
|
||||
if (species is (int)Species.Umbreon or (int)Species.Espeon)
|
||||
{
|
||||
// Reuse existing logic. Forced-male, never shiny.
|
||||
pk.PID = MethodCXD.GetColoStarterPID(ref seed, pk.TID16, pk.SID16);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Generate PID.
|
||||
var d16 = XDRNG.Next16(ref seed); // PID
|
||||
var e16 = XDRNG.Next16(ref seed); // PID
|
||||
pk.PID = (d16 << 16) | e16;
|
||||
}
|
||||
return seed;
|
||||
}
|
||||
|
||||
public static uint SetValuesFromSeedXDRNG_EReader(PKM pk, uint seed)
|
||||
{
|
||||
var D = XDRNG.Prev3(seed); // PID
|
||||
var E = XDRNG.Next(D); // PID
|
||||
|
||||
pk.PID = (D & 0xFFFF0000) | (E >> 16);
|
||||
return seed;
|
||||
}
|
||||
|
||||
public static uint SetValuesFromSeedChannel(PKM pk, uint seed)
|
||||
{
|
||||
const ushort TID16 = 40122;
|
||||
var sid = XDRNG.Next16(ref seed);
|
||||
pk.ID32 = (sid << 16) | TID16;
|
||||
|
||||
var pid1 = XDRNG.Next16(ref seed);
|
||||
var pid2 = XDRNG.Next16(ref seed);
|
||||
var pid = (pid1 << 16) | pid2;
|
||||
if ((pid2 > 7 ? 0 : 1) != (pid1 ^ sid ^ TID16))
|
||||
pid ^= 0x80000000;
|
||||
pk.PID = pid;
|
||||
|
||||
pk.HeldItem = (ushort)((XDRNG.Next16(ref seed) >> 15) + 169u); // 0-Ganlon, 1-Salac
|
||||
pk.Version = GameVersion.S + (byte)(XDRNG.Next16(ref seed) >> 15); // 0-Sapphire, 1-Ruby
|
||||
pk.OriginalTrainerGender = (byte)(XDRNG.Next16(ref seed) >> 15);
|
||||
|
||||
var iv32 = XDRNG.GetSequentialIV32(seed);
|
||||
pk.SetIVs(iv32);
|
||||
|
||||
return seed;
|
||||
}
|
||||
|
||||
public static void SetValuesFromSeed(PKM pk, PIDType type, uint seed)
|
||||
{
|
||||
var method = GetGeneratorMethod(type);
|
||||
method(pk, seed);
|
||||
}
|
||||
|
||||
private static Func<PKM, uint, uint> GetGeneratorMethod(PIDType t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case Channel:
|
||||
return SetValuesFromSeedChannel;
|
||||
case CXD:
|
||||
return SetValuesFromSeedXDRNG;
|
||||
|
||||
case Method_1 or Method_2 or Method_3 or Method_4:
|
||||
case Method_1_Unown or Method_2_Unown or Method_3_Unown or Method_4_Unown:
|
||||
case Method_1_Roamer:
|
||||
return (pk, seed) => SetValuesFromSeedLCRNG(pk, t, seed);
|
||||
|
||||
case BACD:
|
||||
case BACD_S:
|
||||
case BACD_A:
|
||||
case BACD_AX:
|
||||
return (pk, seed) => SetValuesFromSeedBACD(pk, t, seed);
|
||||
|
||||
case PokeSpot:
|
||||
return SetRandomPokeSpotPID;
|
||||
|
||||
case G5MGShiny:
|
||||
return SetValuesFromSeedMG5Shiny;
|
||||
|
||||
case Pokewalker:
|
||||
return (pk, seed) =>
|
||||
{
|
||||
var pid = pk.PID = PokewalkerRNG.GetPID(pk.TID16, pk.SID16, seed % 24, pk.Gender, pk.PersonalInfo.Gender);
|
||||
pk.RefreshAbility((int)(pid & 1));
|
||||
return seed;
|
||||
};
|
||||
|
||||
// others: unimplemented
|
||||
case CuteCharm:
|
||||
break;
|
||||
case ChainShiny:
|
||||
return SetRandomChainShinyPID;
|
||||
case G4MGAntiShiny:
|
||||
break;
|
||||
}
|
||||
return (_, seed) => seed;
|
||||
}
|
||||
|
||||
public static uint SetRandomChainShinyPID(PKM pk, uint seed)
|
||||
{
|
||||
pk.PID = ClassicEraRNG.GetChainShinyPID(ref seed, pk.ID32);
|
||||
SetIVsFromSeedSequentialLCRNG(ref seed, pk);
|
||||
return seed;
|
||||
}
|
||||
|
||||
private static uint SetRandomPokeSpotPID(PKM pk, uint seed)
|
||||
{
|
||||
var D = XDRNG.Next(seed); // PID
|
||||
var E = XDRNG.Next(D); // PID
|
||||
pk.PID = (D & 0xFFFF0000) | (E >> 16);
|
||||
return E;
|
||||
}
|
||||
|
||||
public static uint GetMG5ShinyPID(uint gval, uint av, ushort TID16, ushort SID16)
|
||||
{
|
||||
uint pid = ((gval ^ TID16 ^ SID16) << 16) | gval;
|
||||
if ((pid & 0x10000) != av << 16)
|
||||
pid ^= 0x10000;
|
||||
return pid;
|
||||
}
|
||||
|
||||
public static uint SetValuesFromSeedMG5Shiny(PKM pk, uint seed)
|
||||
{
|
||||
var gv = seed >> 24;
|
||||
var av = seed & 1; // arbitrary choice
|
||||
pk.PID = GetMG5ShinyPID(gv, av, pk.TID16, pk.SID16);
|
||||
pk.SetRandomIVs();
|
||||
return seed; // meh
|
||||
}
|
||||
|
||||
public static uint SetRandomWildPID4(PKM pk, Nature nature, int ability, byte gender, PIDType type)
|
||||
{
|
||||
pk.RefreshAbility(ability);
|
||||
pk.Gender = gender;
|
||||
var method = GetGeneratorMethod(type);
|
||||
|
||||
var rnd = Util.Rand;
|
||||
while (true)
|
||||
{
|
||||
var seed = rnd.Rand32();
|
||||
method(pk, seed);
|
||||
if (!IsValidCriteria4(pk, nature, ability, gender))
|
||||
continue;
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsValidCriteria4(PKM pk, Nature nature, int ability, byte gender)
|
||||
{
|
||||
if (pk.GetSaneGender() != gender)
|
||||
return false;
|
||||
|
||||
if (pk.Nature != nature)
|
||||
return false;
|
||||
|
||||
if ((pk.EncryptionConstant & 1) != ability)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void SetRandomWildPID5(PKM pk, Nature nature, int ability, byte gender, PIDType specific = None)
|
||||
{
|
||||
var tidbit = (pk.TID16 ^ pk.SID16) & 1;
|
||||
pk.RefreshAbility(ability);
|
||||
pk.Gender = gender;
|
||||
pk.Nature = nature;
|
||||
|
||||
if (ability == 2)
|
||||
ability = 0;
|
||||
|
||||
var rnd = Util.Rand;
|
||||
while (true)
|
||||
{
|
||||
uint seed = rnd.Rand32();
|
||||
if (specific == G5MGShiny)
|
||||
{
|
||||
SetValuesFromSeedMG5Shiny(pk, seed);
|
||||
seed = pk.PID;
|
||||
}
|
||||
else
|
||||
{
|
||||
var bitxor = (seed >> 31) ^ (seed & 1);
|
||||
if (bitxor != tidbit)
|
||||
seed ^= 1;
|
||||
}
|
||||
|
||||
if (((seed >> 16) & 1) != ability)
|
||||
continue;
|
||||
|
||||
pk.PID = seed;
|
||||
if (pk.GetSaneGender() != gender)
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,18 +339,16 @@ private static void SetPINGA(PK4 pk4, PersonalInfo4 pi, EncounterCriteria criter
|
||||
pk4.IV32 |= criteria.GetCombinedIVs();
|
||||
return;
|
||||
}
|
||||
if (criteria.IsSpecifiedIVs())
|
||||
{
|
||||
criteria.SetRandomIVs(pk4);
|
||||
return;
|
||||
}
|
||||
var seed = Util.Rand32(); // reseed, do not have method 1 correlation
|
||||
bool filterIVs = criteria.IsSpecifiedIVs(2);
|
||||
uint iv32;
|
||||
while (true)
|
||||
{
|
||||
iv32 = ClassicEraRNG.GetSequentialIVs(ref seed);
|
||||
if (criteria.IsSpecifiedHiddenPower() && !criteria.IsSatisfiedHiddenPower(iv32))
|
||||
continue;
|
||||
if (filterIVs && !criteria.IsSatisfiedIVs(iv32))
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
pk4.IV32 |= iv32;
|
||||
|
||||
Reference in New Issue
Block a user