mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-22 03:53:08 +00:00
Add targeted generator methods for CXD pidiv
If IVs are specified, will try to search for all seeds that originate them. Same as was done for Method H/J/K of mainline games, this allows sets to be more-quickly generated if the criteria is provided.
This commit is contained in:
parent
f35a8d8496
commit
ea4ff5714c
6 changed files with 213 additions and 14 deletions
|
@ -42,8 +42,6 @@ public sealed record EncounterGift3Colo : IEncounterable, IEncounterMatch, IEnco
|
|||
public byte LevelMin => Level;
|
||||
public byte LevelMax => Level;
|
||||
|
||||
public bool IsColoStarter => Species is (ushort)Core.Species.Espeon or (ushort)Core.Species.Umbreon;
|
||||
|
||||
#region Generating
|
||||
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria);
|
||||
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr);
|
||||
|
@ -90,6 +88,9 @@ public sealed record EncounterGift3Colo : IEncounterable, IEncounterMatch, IEnco
|
|||
|
||||
private void SetPINGA(CK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
if (criteria.IsSpecifiedIVs() && MethodCXD.SetFromIVsCXD(pk, criteria, pi, Shiny == Shiny.Never))
|
||||
return;
|
||||
|
||||
var gender = criteria.GetGender(pi);
|
||||
var nature = criteria.GetNature();
|
||||
var ability = criteria.GetAbilityFromNumber(Ability);
|
||||
|
@ -156,12 +157,7 @@ public sealed record EncounterGift3Colo : IEncounterable, IEncounterMatch, IEnco
|
|||
}
|
||||
#endregion
|
||||
|
||||
public bool IsCompatible(PIDType val, PKM pk)
|
||||
{
|
||||
if (IsColoStarter)
|
||||
return val is PIDType.CXD_ColoStarter;
|
||||
return val is PIDType.CXD;
|
||||
}
|
||||
public bool IsCompatible(PIDType val, PKM pk) => val is PIDType.CXD;
|
||||
|
||||
public PIDType GetSuggestedCorrelation() => PIDType.CXD;
|
||||
|
||||
|
|
|
@ -89,6 +89,9 @@ public sealed record EncounterShadow3Colo(byte ID, short Gauge, ReadOnlyMemory<T
|
|||
|
||||
private void SetPINGA_Regular(CK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
if (criteria.IsSpecifiedIVs() && this.SetFromIVs(pk, criteria, pi))
|
||||
return;
|
||||
|
||||
var gender = criteria.GetGender(pi);
|
||||
var nature = criteria.GetNature();
|
||||
int ability = criteria.GetAbilityFromNumber(Ability);
|
||||
|
@ -107,8 +110,6 @@ public sealed record EncounterShadow3Colo(byte ID, short Gauge, ReadOnlyMemory<T
|
|||
break;
|
||||
}
|
||||
while (++ctr <= max);
|
||||
|
||||
System.Diagnostics.Debug.Assert(ctr < max);
|
||||
}
|
||||
|
||||
private void SetPINGA_EReader(CK3 pk)
|
||||
|
|
|
@ -71,6 +71,9 @@ public sealed record EncounterStatic3Colo(ushort Species, byte Level)
|
|||
|
||||
private void SetPINGA(CK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
if (MethodCXD.SetFromTrainerIDStarter(pk, criteria, pi, pk.TID16, pk.SID16))
|
||||
return;
|
||||
|
||||
var gender = criteria.GetGender(Gender, pi);
|
||||
var nature = criteria.GetNature();
|
||||
var ability = criteria.GetAbilityFromNumber(Ability);
|
||||
|
|
|
@ -79,6 +79,9 @@ public sealed record EncounterShadow3XD(byte ID, short Gauge, ReadOnlyMemory<Tea
|
|||
|
||||
private void SetPINGA(XK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
if (criteria.IsSpecifiedIVs() && this.SetFromIVs(pk, criteria, pi, noShiny: true))
|
||||
return;
|
||||
|
||||
var gender = criteria.GetGender(pi);
|
||||
var nature = criteria.GetNature();
|
||||
int ability = criteria.GetAbilityFromNumber(Ability);
|
||||
|
|
|
@ -29,8 +29,6 @@ public sealed record EncounterStatic3XD(ushort Species, byte Level)
|
|||
public byte LevelMin => Level;
|
||||
public byte LevelMax => Level;
|
||||
|
||||
public bool IsColoStarter => Species is (ushort)Core.Species.Espeon or (ushort)Core.Species.Umbreon;
|
||||
|
||||
#region Generating
|
||||
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) => ConvertToPKM(tr, criteria);
|
||||
PKM IEncounterConvertible.ConvertToPKM(ITrainerInfo tr) => ConvertToPKM(tr);
|
||||
|
@ -71,6 +69,16 @@ public sealed record EncounterStatic3XD(ushort Species, byte Level)
|
|||
|
||||
private void SetPINGA(XK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
|
||||
{
|
||||
if (Species == (int)Core.Species.Eevee)
|
||||
{
|
||||
if (MethodCXD.SetFromTrainerIDStarter(pk, criteria, pi, pk.TID16, pk.SID16))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (criteria.IsSpecifiedIVs() && MethodCXD.SetFromIVsCXD(pk, criteria, pi, noShiny: true))
|
||||
return;
|
||||
}
|
||||
var gender = criteria.GetGender(pi);
|
||||
var nature = criteria.GetNature();
|
||||
var ability = criteria.GetAbilityFromNumber(Ability);
|
||||
|
@ -137,8 +145,6 @@ public sealed record EncounterStatic3XD(ushort Species, byte Level)
|
|||
|
||||
public bool IsCompatible(PIDType val, PKM pk)
|
||||
{
|
||||
if (IsColoStarter)
|
||||
return val is PIDType.CXD_ColoStarter;
|
||||
if (val is PIDType.CXD)
|
||||
return true;
|
||||
return val is PIDType.CXDAnti && FatefulEncounter;
|
||||
|
|
190
PKHeX.Core/Legality/RNG/CXD/MethodCXD.cs
Normal file
190
PKHeX.Core/Legality/RNG/CXD/MethodCXD.cs
Normal file
|
@ -0,0 +1,190 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core;
|
||||
|
||||
/// <summary>
|
||||
/// Generator methods for <see cref="GameVersion.CXD"/>.
|
||||
/// </summary>
|
||||
public static class MethodCXD
|
||||
{
|
||||
/// <summary>
|
||||
/// Tries to set a valid PID/IV for the requested criteria for an <see cref="IShadow3"/> object.
|
||||
/// </summary>
|
||||
/// <remarks>Only called if <see cref="EncounterCriteria.IsSpecifiedIVs"/> is true.</remarks>
|
||||
public static bool SetFromIVs<T>(this T enc, G3PKM pk, EncounterCriteria criteria, PersonalInfo3 pi, bool noShiny = false) where T : IShadow3
|
||||
{
|
||||
var gr = pi.Gender;
|
||||
(uint iv1, uint iv2) = GetCombinedIVs(criteria);
|
||||
Span<uint> all = stackalloc uint[XDRNG.MaxCountSeedsIV];
|
||||
var count = XDRNG.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
|
||||
var seeds = all[..count];
|
||||
foreach (var seed in seeds)
|
||||
{
|
||||
// * => IV, IV, ability, PID, PID
|
||||
var s = XDRNG.Next3(seed);
|
||||
uint pid = GetPID(pk, s, noShiny);
|
||||
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
|
||||
continue;
|
||||
|
||||
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
|
||||
if (!criteria.IsGenderSatisfied(gender))
|
||||
continue;
|
||||
|
||||
var origin = XDRNG.Prev(seed);
|
||||
var pidiv = new PIDIV(PIDType.CXD, origin);
|
||||
var result = LockFinder.IsAllShadowLockValid(enc, pidiv, pk);
|
||||
if (!result)
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.Ability = ((XDRNG.Next2(seed) >> 16) & 1) == 0 ? pi.Ability1 : pi.Ability2;
|
||||
criteria.SetRandomIVs(pk);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to set a valid PID/IV for the requested criteria for a non-shadow encounter.
|
||||
/// </summary>
|
||||
/// <remarks>Only called if <see cref="EncounterCriteria.IsSpecifiedIVs"/> is true.</remarks>
|
||||
public static bool SetFromIVsCXD(G3PKM pk, EncounterCriteria criteria, PersonalInfo3 pi, bool noShiny = true)
|
||||
{
|
||||
var gr = pi.Gender;
|
||||
(uint iv1, uint iv2) = GetCombinedIVs(criteria);
|
||||
Span<uint> all = stackalloc uint[XDRNG.MaxCountSeedsIV];
|
||||
var count = XDRNG.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
|
||||
var seeds = all[..count];
|
||||
foreach (var seed in seeds)
|
||||
{
|
||||
// * => IV, IV, ability, PID, PID
|
||||
var s = XDRNG.Next3(seed);
|
||||
uint pid = GetPID(pk, s, noShiny);
|
||||
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
|
||||
continue;
|
||||
|
||||
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
|
||||
if (!criteria.IsGenderSatisfied(gender))
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
pk.Ability = ((XDRNG.Next2(seed) >> 16) & 1) == 0 ? pi.Ability1 : pi.Ability2;
|
||||
criteria.SetRandomIVs(pk);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to set a valid PID/IV for the requested criteria for a Colosseum starter (Umbreon and Espeon), preferring to match Trainer IDs.
|
||||
/// </summary>
|
||||
public static bool SetFromTrainerIDStarter(CK3 pk, EncounterCriteria criteria, PersonalInfo3 pi, ushort tid, ushort sid)
|
||||
{
|
||||
// * => TID, SID, fakepid*2, [IVs, ability, PID]
|
||||
Span<uint> all = stackalloc uint[XDRNG.MaxCountSeedsPID];
|
||||
var count = XDRNG.GetSeeds(all, (uint)tid << 16, (uint)sid << 16);
|
||||
var seeds = all[..count];
|
||||
foreach (ref var seed in seeds)
|
||||
{
|
||||
var s = XDRNG.Next7(seed);
|
||||
uint pid = GetPIDStarterMale(ref s, pk.ID32);
|
||||
if (pk.Species == (int)Species.Espeon) // After Umbreon
|
||||
{
|
||||
s = XDRNG.Next2(s);
|
||||
pid = GetPIDStarterMale(ref s, pk.ID32);
|
||||
}
|
||||
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
|
||||
continue;
|
||||
|
||||
var ivSeed = XDRNG.Next4(seed);
|
||||
var iv1 = XDRNG.Next15(ref ivSeed);
|
||||
var iv2 = XDRNG.Next15(ref ivSeed);
|
||||
|
||||
SetIVs(pk, iv1, iv2);
|
||||
pk.PID = pid;
|
||||
pk.Ability = ((XDRNG.Next2(seed) >> 16) & 1) == 0 ? pi.Ability1 : pi.Ability2;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to set a valid PID/IV for the requested criteria for the XD starter (Eevee), preferring to match Trainer IDs.
|
||||
/// </summary>
|
||||
public static bool SetFromTrainerIDStarter(XK3 pk, EncounterCriteria criteria, PersonalInfo3 pi, ushort tid, ushort sid)
|
||||
{
|
||||
// * => TID, SID, fakepid*2, [IVs, ability, PID]
|
||||
Span<uint> all = stackalloc uint[XDRNG.MaxCountSeedsPID];
|
||||
var count = XDRNG.GetSeeds(all, (uint)tid << 16, (uint)sid << 16);
|
||||
var seeds = all[..count];
|
||||
foreach (ref var seed in seeds)
|
||||
{
|
||||
var s = XDRNG.Next7(seed);
|
||||
uint pid = GetPID(s);
|
||||
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
|
||||
continue;
|
||||
|
||||
var ivSeed = XDRNG.Next4(seed);
|
||||
var iv1 = XDRNG.Next15(ref ivSeed);
|
||||
var iv2 = XDRNG.Next15(ref ivSeed);
|
||||
|
||||
SetIVs(pk, iv1, iv2);
|
||||
pk.PID = pid;
|
||||
pk.Ability = ((XDRNG.Next2(seed) >> 16) & 1) == 0 ? pi.Ability1 : pi.Ability2;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static uint GetPID(uint seed)
|
||||
{
|
||||
var a = XDRNG.Next16(ref seed);
|
||||
var b = XDRNG.Next16(ref seed);
|
||||
return GetPIDRegular(a, b);
|
||||
}
|
||||
|
||||
private static uint GetPID(G3PKM pk, uint seed, bool noShiny)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var a = XDRNG.Next16(ref seed);
|
||||
var b = XDRNG.Next16(ref seed);
|
||||
var pid = GetPIDRegular(a, b);
|
||||
if (!noShiny || !ShinyUtil.GetIsShiny(pk.ID32, pid))
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint GetPIDStarterMale(ref uint seed, uint id32)
|
||||
{
|
||||
const byte ratio = 0x1F; // 12.5% F (can't be female)
|
||||
while (true)
|
||||
{
|
||||
var a = XDRNG.Next16(ref seed);
|
||||
var b = XDRNG.Next16(ref seed);
|
||||
var pid = GetPIDRegular(a, b);
|
||||
if ((pid & 0xFF) >= ratio && !ShinyUtil.GetIsShiny(id32, pid))
|
||||
return pid;
|
||||
}
|
||||
}
|
||||
|
||||
private static uint GetPIDRegular(uint a, uint b) => a << 16 | b;
|
||||
|
||||
private static (uint iv1, uint iv2) GetCombinedIVs(EncounterCriteria criteria)
|
||||
{
|
||||
uint iv1 = (uint)criteria.IV_HP | (uint)criteria.IV_ATK << 5 | (uint)criteria.IV_DEF << 10;
|
||||
uint iv2 = (uint)criteria.IV_SPE | (uint)criteria.IV_SPA << 5 | (uint)criteria.IV_SPD << 10;
|
||||
return (iv1, iv2);
|
||||
}
|
||||
|
||||
private static void SetIVs(G3PKM pk, uint iv1, uint iv2)
|
||||
{
|
||||
Span<int> ivs = stackalloc int[6];
|
||||
MethodFinder.GetIVsInt32(ivs, iv1, iv2);
|
||||
pk.SetIVs(ivs);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue