mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 06:34:19 +00:00
Remove nature from FRLG Unown method loop
Only checks for Form.
c6a2f50491/src/wild_encounter.c (L238)
Closes #4332
make the private FrameCheckDetails<T> actually <T> instead of specific, to match MethodJ/K.
This commit is contained in:
parent
1b3544ce78
commit
c9f3894076
3 changed files with 41 additions and 29 deletions
|
@ -69,22 +69,22 @@ public static class GenerateMethodH
|
|||
if (esv < min || esv > max)
|
||||
continue;
|
||||
// Skip the level roll, always results in the same level value.
|
||||
seed = LCRNG.Next2(seed);
|
||||
var nature = (seed >> 16) % 25;
|
||||
if (criteria.IsSpecifiedNature() && nature != (byte)criteria.Nature)
|
||||
continue;
|
||||
seed = LCRNG.Next(seed);
|
||||
// Nature is not used in the loop.
|
||||
|
||||
while (true)
|
||||
{
|
||||
var a = LCRNG.Next16(ref seed);
|
||||
var b = LCRNG.Next16(ref seed);
|
||||
var pid = a << 16 | b;
|
||||
if (pid % 25 != nature)
|
||||
continue;
|
||||
var form = EntityPID.GetUnownForm3(pid);
|
||||
if (form != enc.Form)
|
||||
continue;
|
||||
|
||||
// Check the nature is what the user requested.
|
||||
if (criteria.IsSpecifiedNature() && pid % 25 != (byte)criteria.Nature)
|
||||
break;
|
||||
|
||||
SetPIDIVSequential(pk, pid, seed);
|
||||
return;
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ public static class GenerateMethodH
|
|||
seed = LCRNG.Prev(seed);
|
||||
}
|
||||
var lead = MethodH.GetSeed(enc, seed, enc, false, 2, 3);
|
||||
if (!lead.IsValid()) // Verifies the slot and nature loop; if it passes, apply the details.
|
||||
if (!lead.IsValid()) // Verifies the slot and form loop; if it passes, apply the details.
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
|
@ -213,7 +213,7 @@ public static class GenerateMethodH
|
|||
if (form != enc.Form)
|
||||
continue;
|
||||
var lead = MethodH.GetSeed(enc, seed, enc, false, 2, 3);
|
||||
if (!lead.IsValid()) // Verifies the slot and nature loop; if it passes, apply the details.
|
||||
if (!lead.IsValid()) // Verifies the slot and form loop; if it passes, apply the details.
|
||||
continue;
|
||||
|
||||
pk.PID = pid;
|
||||
|
|
|
@ -63,7 +63,6 @@ public static class MethodH
|
|||
private static bool IsSafariBlockProc(uint seed) => (seed >> 16) % 100 < 80;
|
||||
|
||||
private static uint GetNature(uint rand) => rand % 25;
|
||||
private static bool IsMatchUnown(uint pid, byte nature, byte form) => pid % 25 == nature && EntityPID.GetUnownForm3(pid) == form;
|
||||
|
||||
private static bool IsMatchGender(uint pid, byte genderMin, byte genderMax)
|
||||
{
|
||||
|
@ -102,7 +101,7 @@ public static class MethodH
|
|||
}
|
||||
if (enc.Species == (int)Species.Unown) // Never Emerald
|
||||
{
|
||||
var result = GetReversalWindow(seed, nature, enc.Form);
|
||||
var result = GetReversalWindowUnown(seed, enc.Form);
|
||||
return new((ushort)result, Unown);
|
||||
}
|
||||
// Otherwise...
|
||||
|
@ -248,10 +247,9 @@ public static class MethodH
|
|||
|
||||
/// <inheritdoc cref="MethodJ.GetReversalWindow"/>
|
||||
/// <param name="seed">Seed that generates the expected resulting PID.</param>
|
||||
/// <param name="nature">Nature of the resulting PID.</param>
|
||||
/// <param name="form">Form of the resulting PID.</param>
|
||||
/// <remarks>Only used for FR/LG <see cref="Species.Unown"/>.</remarks>
|
||||
private static int GetReversalWindow(uint seed, byte nature, byte form)
|
||||
/// <remarks>Only used for FR/LG <see cref="Species.Unown"/>. Loop does not calculate nature!</remarks>
|
||||
private static int GetReversalWindowUnown(uint seed, byte form)
|
||||
{
|
||||
// Reverses the PID calls, and ensures the form matches.
|
||||
int ctr = 0;
|
||||
|
@ -260,7 +258,7 @@ public static class MethodH
|
|||
{
|
||||
var a = LCRNG.Prev16(ref seed);
|
||||
var pid = a << 16 | b;
|
||||
if (IsMatchUnown(pid, nature, form))
|
||||
if (EntityPID.GetUnownForm3(pid) == form)
|
||||
break; // Correct Nature and Form.
|
||||
b = LCRNG.Prev16(ref seed);
|
||||
ctr++;
|
||||
|
@ -288,15 +286,22 @@ public static class MethodH
|
|||
{ result = new(origin, None); return true; }
|
||||
}
|
||||
}
|
||||
var reg = GetNature(p0) == nature;
|
||||
if (reg)
|
||||
if (enc.Species is (ushort)Species.Unown) // No Nature in loop
|
||||
{
|
||||
// Consumers of the seed will assume nature is used; shift the frames so the values line up with their uses.
|
||||
var noNatureCallUsed = LCRNG.Next(seed);
|
||||
var ctx = new FrameCheckDetails<T>(enc, noNatureCallUsed, levelMin, levelMax, format);
|
||||
if (IsSlotValidRegular(ctx, out uint origin))
|
||||
{ result = new(origin, None); return true; }
|
||||
}
|
||||
else if (GetNature(p0) == nature)
|
||||
{
|
||||
// Still consumes a dummy call between nature and prior.
|
||||
// Assume no Safari Block was placed, so that the nature rolls are used.
|
||||
if (rseSafari)
|
||||
seed = LCRNG.Prev(seed);
|
||||
|
||||
var ctx = new FrameCheckDetails<IEncounterSlot3>(enc, seed, levelMin, levelMax, format);
|
||||
var ctx = new FrameCheckDetails<T>(enc, seed, levelMin, levelMax, format);
|
||||
if (IsSlotValidRegular(ctx, out uint origin))
|
||||
{ result = new(origin, None); return true; }
|
||||
}
|
||||
|
@ -317,7 +322,7 @@ public static class MethodH
|
|||
var safariBlockSeed = (0xC048C851u * seed) + 0x196302B4u;
|
||||
if (IsSafariBlockProc(safariBlockSeed))
|
||||
{
|
||||
var ctx = new FrameCheckDetails<IEncounterSlot3>(enc, safariBlockSeed, levelMin, levelMax, format);
|
||||
var ctx = new FrameCheckDetails<T>(enc, safariBlockSeed, levelMin, levelMax, format);
|
||||
if (TryGetMatchNoSync(ctx, out result))
|
||||
return true;
|
||||
}
|
||||
|
@ -331,7 +336,7 @@ public static class MethodH
|
|||
var syncProc = IsSyncPass(p0);
|
||||
if (syncProc)
|
||||
{
|
||||
var ctx = new FrameCheckDetails<IEncounterSlot3>(enc, seed, levelMin, levelMax, format);
|
||||
var ctx = new FrameCheckDetails<T>(enc, seed, levelMin, levelMax, format);
|
||||
if (IsSlotValidRegular(ctx, out seed))
|
||||
{
|
||||
result = new(seed, Synchronize);
|
||||
|
@ -341,14 +346,15 @@ public static class MethodH
|
|||
var reg = GetNature(p0) == nature;
|
||||
if (reg)
|
||||
{
|
||||
var ctx = new FrameCheckDetails<IEncounterSlot3>(enc, seed, levelMin, levelMax, format);
|
||||
var ctx = new FrameCheckDetails<T>(enc, seed, levelMin, levelMax, format);
|
||||
if (TryGetMatchNoSync(ctx, out result))
|
||||
return true;
|
||||
}
|
||||
result = default; return false;
|
||||
}
|
||||
|
||||
private static bool TryGetMatchCuteCharm(in FrameCheckDetails<IEncounterSlot3> ctx, out uint result)
|
||||
private static bool TryGetMatchCuteCharm<T>(in FrameCheckDetails<T> ctx, out uint result)
|
||||
where T : IEncounterSlot3
|
||||
{
|
||||
// Cute Charm
|
||||
// -3 ESV
|
||||
|
@ -361,7 +367,8 @@ public static class MethodH
|
|||
return IsSlotValidFrom1Skip(ctx, out result);
|
||||
}
|
||||
|
||||
private static bool IsSlotValidCuteCharmFail(in FrameCheckDetails<IEncounterSlot3> ctx, out uint result)
|
||||
private static bool IsSlotValidCuteCharmFail<T>(in FrameCheckDetails<T> ctx, out uint result)
|
||||
where T : IEncounterSlot3
|
||||
{
|
||||
// Cute Charm
|
||||
// -3 ESV
|
||||
|
@ -374,7 +381,8 @@ public static class MethodH
|
|||
return IsSlotValidFrom1Skip(ctx, out result);
|
||||
}
|
||||
|
||||
private static bool IsSlotValidSyncFail(in FrameCheckDetails<IEncounterSlot3> ctx, out uint result)
|
||||
private static bool IsSlotValidSyncFail<T>(in FrameCheckDetails<T> ctx, out uint result)
|
||||
where T : IEncounterSlot3
|
||||
{
|
||||
// Keen Eye, Intimidate (Not compatible with Sweet Scent)
|
||||
// -3 ESV
|
||||
|
@ -387,7 +395,8 @@ public static class MethodH
|
|||
return IsSlotValidFrom1Skip(ctx, out result);
|
||||
}
|
||||
|
||||
private static bool IsSlotValidIntimidate(in FrameCheckDetails<IEncounterSlot3> ctx, out uint result)
|
||||
private static bool IsSlotValidIntimidate<T>(in FrameCheckDetails<T> ctx, out uint result)
|
||||
where T : IEncounterSlot3
|
||||
{
|
||||
// Keen Eye, Intimidate (Not compatible with Sweet Scent)
|
||||
// -3 ESV
|
||||
|
@ -401,7 +410,8 @@ public static class MethodH
|
|||
return IsSlotValidFrom1Skip(ctx, out result);
|
||||
}
|
||||
|
||||
private static bool IsSlotValidHustleVitalFail(in FrameCheckDetails<IEncounterSlot3> ctx, out uint result)
|
||||
private static bool IsSlotValidHustleVitalFail<T>(in FrameCheckDetails<T> ctx, out uint result)
|
||||
where T : IEncounterSlot3
|
||||
{
|
||||
// Pressure, Hustle, Vital Spirit = Force Maximum Level from slot
|
||||
// -3 ESV
|
||||
|
@ -414,7 +424,8 @@ public static class MethodH
|
|||
return IsSlotValidFrom1Skip(ctx, out result);
|
||||
}
|
||||
|
||||
private static bool TryGetMatchNoSync(in FrameCheckDetails<IEncounterSlot3> ctx, out LeadSeed result)
|
||||
private static bool TryGetMatchNoSync<T>(in FrameCheckDetails<T> ctx, out LeadSeed result)
|
||||
where T : IEncounterSlot3
|
||||
{
|
||||
if (IsSlotValidRegular(ctx, out uint seed))
|
||||
{ result = new(seed, None); return true; }
|
||||
|
@ -441,7 +452,8 @@ public static class MethodH
|
|||
result = default; return false;
|
||||
}
|
||||
|
||||
private static bool IsSlotValidFrom1Skip(FrameCheckDetails<IEncounterSlot3> ctx, out uint result)
|
||||
private static bool IsSlotValidFrom1Skip<T>(FrameCheckDetails<T> ctx, out uint result)
|
||||
where T : IEncounterSlot3
|
||||
{
|
||||
// -3 ESV
|
||||
// -2 Level
|
||||
|
|
|
@ -66,10 +66,10 @@ public static class EntityPID
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Unown Forme ID from PID.
|
||||
/// Gets the Unown Form ID from PID.
|
||||
/// </summary>
|
||||
/// <param name="pid">Personality ID</param>
|
||||
/// <remarks>Should only be used for 3rd Generation origin specimens.</remarks>
|
||||
/// <remarks>Should only be used for FireRed/LeafGreen origin Unown.</remarks>
|
||||
public static byte GetUnownForm3(uint pid)
|
||||
{
|
||||
var value = ((pid & 0x3000000) >> 18) | ((pid & 0x30000) >> 12) | ((pid & 0x300) >> 6) | (pid & 0x3);
|
||||
|
|
Loading…
Reference in a new issue