Add specialized PIDIV generator for gen4 slots

extract gen3's to a static class
This commit is contained in:
Kurt 2024-03-17 13:54:36 -05:00
parent 3dd60890fb
commit bc7118b493
10 changed files with 517 additions and 105 deletions

View file

@ -1,4 +1,3 @@
using System;
using static PKHeX.Core.PIDType;
using static PKHeX.Core.SlotType3;
@ -69,98 +68,20 @@ public record EncounterSlot3(EncounterArea3 Parent, ushort Species, byte Form, b
private void SetPINGA(PK3 pk, EncounterCriteria criteria, PersonalInfo3 pi)
{
var gender = criteria.GetGender(pi);
var nature = criteria.GetNature();
var ability = criteria.GetAbilityFromNumber(Ability);
var lvl = new SingleLevelRange(LevelMin);
int ctr = 0;
if (Species == (int)Core.Species.Unown)
if (Species != (int)Core.Species.Unown)
{
if (criteria.IsSpecifiedIVs() && SetUnownFromIVs(pk, criteria))
if (criteria.IsSpecifiedIVs() && this.SetFromIVs(pk, criteria))
return;
// Generate a random Unown with the correct form and desired nature.
SetUnownRandom(pk, criteria);
return;
this.SetRandom(pk, pi, criteria, Util.Rand32());
}
do
else
{
var seed = PIDGenerator.SetRandomWildPID4(pk, nature, ability, gender, Method_1);
var result = MethodH.GetSeed(this, seed, lvl, pk.E, pk.Gender, 3);
if (result.IsValid())
if (criteria.IsSpecifiedIVs() && this.SetFromIVsUnown(pk, criteria))
return;
} while (ctr++ < 10_000);
}
private void SetUnownRandom(PK3 pk, EncounterCriteria criteria)
{
//bool checkForm = forms.Contains(criteria.Form); // not a property :(
var (min, max) = SlotMethodH.GetRangeGrass(SlotNumber);
var seed = Util.Rand32() & 0x7FFF_FFFF;
// Can't game the seed with % 100 increments as Unown's form calculation is based on the PID.
while (true)
{
var esv = LCRNG.Next16(ref seed) % 100;
if (esv < min || esv > max)
continue;
// Skip the level roll, always results in the same level value.
var rand = LCRNG.Next2(seed);
if (criteria.Nature != Nature.Random && (rand >> 16) % 25 != (byte)criteria.Nature)
continue;
while (true)
{
var a = LCRNG.Next16(ref rand);
var b = LCRNG.Next16(ref rand);
var pid = a << 16 | b;
var form = EntityPID.GetUnownForm3(pid);
if (form != Form)
continue;
pk.PID = pid;
var iv1 = LCRNG.Next16(ref rand);
var iv2 = LCRNG.Next16(ref rand);
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
return;
}
this.SetRandomUnown(pk, criteria);
}
}
private bool SetUnownFromIVs(PK3 pk, EncounterCriteria criteria)
{
Span<uint> seeds = stackalloc uint[LCRNG.MaxCountSeedsIV];
var count = LCRNGReversal.GetSeedsIVs(seeds, (byte)criteria.IV_HP, (byte)criteria.IV_ATK, (byte)criteria.IV_DEF, (byte)criteria.IV_SPA, (byte)criteria.IV_SPD, (byte)criteria.IV_SPE);
seeds = seeds[..count];
foreach (ref var seed in seeds)
{
seed = LCRNG.Prev2(seed);
var s = seed;
var a = LCRNG.Next16(ref s);
var b = LCRNG.Next16(ref s);
var pid = a << 16 | b;
if (criteria.Nature != Nature.Random && (Nature)(pid % 25) != criteria.Nature)
continue;
var form = EntityPID.GetUnownForm3(pid);
if (form != Form)
continue;
var lead = MethodH.GetSeed(this, seed, this, false, 2, 3);
if (!lead.IsValid()) // Verifies the slot and nature loop; if it passes, apply the details.
continue;
pk.PID = pid;
var iv1 = LCRNG.Next16(ref s);
var iv2 = LCRNG.Next16(ref s);
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
return true;
}
return false;
}
protected virtual void SetEncounterMoves(PKM pk) => EncounterUtil.SetEncounterMoves(pk, Version, LevelMin);
#endregion

View file

@ -84,21 +84,20 @@ public sealed record EncounterSlot4(EncounterArea4 Parent, ushort Species, byte
private void SetPINGA(PK4 pk, EncounterCriteria criteria, PersonalInfo4 pi)
{
var gender = criteria.GetGender(pi);
var nature = criteria.GetNature();
var ability = criteria.GetAbilityFromNumber(Ability);
var lvl = new SingleLevelRange(LevelMin);
bool hgss = pk.HGSS;
int ctr = 0;
do
uint seed;
if (hgss)
{
var seed = PIDGenerator.SetRandomWildPID4(pk, nature, ability, gender, PIDType.Method_1);
if (!LeadFinder.TryGetLeadInfo4(this, lvl, hgss, seed, 4, out _))
continue;
if (Species == (int)Core.Species.Unown)
pk.Form = GetUnownForm(seed, hgss);
break;
} while (ctr++ < 10_000);
if (!criteria.IsSpecifiedIVs() || !this.SetFromIVsK(pk, pi, criteria, out seed))
seed = this.SetRandomK(pk, pi, criteria, Util.Rand32());
}
else
{
if (!criteria.IsSpecifiedIVs() || !this.SetFromIVsJ(pk, pi, criteria, out seed))
seed = this.SetRandomJ(pk, pi, criteria, Util.Rand32());
}
if (Species == (int)Core.Species.Unown)
pk.Form = GetUnownForm(seed, hgss);
}
/// <summary>

View file

@ -0,0 +1,232 @@
using System;
namespace PKHeX.Core;
/// <summary>
/// Generator methods for Generation 3.
/// </summary>
public static class GenerateMethodH
{
public static void SetRandom<T>(this T enc, PK3 pk, PersonalInfo3 pi, EncounterCriteria criteria, uint seed)
where T : IEncounterSlot3
{
var gr = pi.Gender;
var ability = criteria.GetAbilityFromNumber(AbilityPermission.Any12);
var (min, max) = SlotMethodH.GetRange(enc.Type, enc.SlotNumber);
// Generate Method H correlated PID and IVs, no lead (keep things simple).
while (true)
{
var esv = LCRNG.Next16(ref seed) % 100;
if (esv < min || esv > max)
continue;
var lv = LCRNG.Next16(ref seed);
var nature = LCRNG.Next16(ref seed) % 25;
if (criteria.IsSpecifiedNature() && nature != (byte)criteria.Nature)
continue;
while (true)
{
var a = LCRNG.Next16(ref seed);
var b = LCRNG.Next16(ref seed);
var pid = GetPIDRegular(a, b);
if (pid % 25 != nature)
continue;
if ((pid & 1) != ability)
break; // try again
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
if (!criteria.IsGenderSatisfied(gender))
break; // try again
pk.MetLevel = pk.CurrentLevel = (byte)((lv % (enc.LevelMax - enc.LevelMin + 1)) + enc.LevelMin);
SetPIDIVSequential(pk, pid, seed);
return;
}
}
}
public static void SetRandomUnown<T>(this T enc, PK3 pk, EncounterCriteria criteria)
where T : INumberedSlot, ISpeciesForm
{
//bool checkForm = forms.Contains(criteria.Form); // not a property :(
var (min, max) = SlotMethodH.GetRangeGrass(enc.SlotNumber);
var seed = Util.Rand32();
// Can't game the seed with % 100 increments as Unown's form calculation is based on the PID.
while (true)
{
var esv = LCRNG.Next16(ref seed) % 100;
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;
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;
SetPIDIVSequential(pk, pid, seed);
return;
}
}
}
public static bool SetFromIVs<T>(this T enc, PK3 pk, EncounterCriteria criteria)
where T : IEncounterSlot3
{
var gr = pk.PersonalInfo.Gender;
(uint iv1, uint iv2) = GetCombinedIVs(criteria);
Span<uint> all = stackalloc uint[LCRNG.MaxCountSeedsIV];
var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
var seeds = all[..count];
foreach (ref var seed in seeds)
{
seed = LCRNG.Prev2(seed);
var s = seed;
var a = LCRNG.Next16(ref s);
var b = LCRNG.Next16(ref s);
var pid = GetPIDRegular(a, b);
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
{
// Try again as Method 2 (BA-DE)
var o = s >> 16;
pid = GetPIDRegular(o, a);
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
continue;
seed = LCRNG.Prev(seed);
}
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
if (!criteria.IsGenderSatisfied(gender))
continue;
var lead = MethodH.GetSeed(enc, seed, enc, pk.E, gender, 3);
if (!lead.IsValid()) // Verifies the slot, (min) level, and nature loop; if it passes, apply the details.
continue;
pk.PID = pid;
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
return true;
}
// Try again as Method 4 (BAC-E)
count = LCRNGReversalSkip.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
seeds = all[..count];
foreach (ref var seed in seeds)
{
seed = LCRNG.Prev2(seed);
var s = seed;
var a = LCRNG.Next16(ref s);
var b = LCRNG.Next16(ref s);
var pid = GetPIDRegular(a, b);
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
continue;
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
if (!criteria.IsGenderSatisfied(gender))
continue;
var lead = MethodH.GetSeed(enc, seed, enc, pk.E, gender, 3);
if (!lead.IsValid()) // Verifies the slot and nature loop; if it passes, apply the details.
continue;
pk.PID = pid;
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
return true;
}
return false;
}
public static bool SetFromIVsUnown<T>(this T enc, PK3 pk, EncounterCriteria criteria)
where T : IEncounterSlot3
{
(uint iv1, uint iv2) = GetCombinedIVs(criteria);
Span<uint> all = stackalloc uint[LCRNG.MaxCountSeedsIV];
var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
var seeds = all[..count];
foreach (ref var seed in seeds)
{
seed = LCRNG.Prev2(seed);
var s = seed;
var a = LCRNG.Next16(ref s);
var b = LCRNG.Next16(ref s);
var pid = GetPIDUnown(a, b);
if ((criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature) || EntityPID.GetUnownForm3(pid) != enc.Form)
{
// Try again as Method 2 (BA-DE)
var o = s >> 16;
pid = GetPIDUnown(o, a);
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
continue;
var form = EntityPID.GetUnownForm3(pid);
if (form != enc.Form)
continue;
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.
continue;
pk.PID = pid;
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
return true;
}
// Try again as Method 4 (BAC-E)
count = LCRNGReversalSkip.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
seeds = all[..count];
foreach (ref var seed in seeds)
{
seed = LCRNG.Prev2(seed);
var s = seed;
var a = LCRNG.Next16(ref s);
var b = LCRNG.Next16(ref s);
var pid = GetPIDUnown(a, b);
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
continue;
var form = EntityPID.GetUnownForm3(pid);
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.
continue;
pk.PID = pid;
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
return true;
}
return false;
}
public static uint GetPIDUnown(uint a, uint b) => a << 16 | b;
public static uint GetPIDRegular(uint a, uint b) => b << 16 | a;
private static void SetPIDIVSequential(PK3 pk, uint pid, uint rand)
{
pk.PID = pid;
var iv1 = LCRNG.Next16(ref rand);
var iv2 = LCRNG.Next16(ref rand);
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
}
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);
}
}

View file

@ -0,0 +1,129 @@
using System;
namespace PKHeX.Core;
/// <summary>
/// Generator methods for Generation 4.
/// </summary>
public static class GenerateMethodJ
{
/// <summary>
/// Applies a random PID and IVs to the entity, based on the <see cref="PersonalInfo4"/> and <see cref="EncounterCriteria"/>.
/// </summary>
/// <param name="enc">Encounter slot to generate for</param>
/// <param name="pk">Entity to modify</param>
/// <param name="pi">Personal Info of the entity</param>
/// <param name="criteria">Criteria to match</param>
/// <param name="seed">Initial seed to use; will be modified during the loop if the first seed fails</param>
/// <returns>Method 1 origin seed applied</returns>
public static uint SetRandomJ<T>(this T enc, PK4 pk, PersonalInfo4 pi, EncounterCriteria criteria, uint seed)
where T : IEncounterSlot4
{
var gr = pi.Gender;
var ability = criteria.GetAbilityFromNumber(AbilityPermission.Any12);
var (min, max) = SlotMethodJ.GetRange(enc.Type, enc.SlotNumber);
bool randLevel = MethodJ.IsLevelRand(enc);
// Generate Method J correlated PID and IVs, no lead (keep things simple).
while (true)
{
var esv = LCRNG.Next16(ref seed) / 656;
if (esv < min || esv > max)
continue;
var lv = randLevel ? LCRNG.Next16(ref seed) : 0;
var nature = LCRNG.Next16(ref seed) % 25;
if (criteria.IsSpecifiedNature() && nature != (byte)criteria.Nature)
continue;
while (true)
{
var a = LCRNG.Next16(ref seed);
var b = LCRNG.Next16(ref seed);
var pid = GetPIDRegular(a, b);
if (pid % 25 != nature)
continue;
if ((pid & 1) != ability)
break; // try again
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
if (!criteria.IsGenderSatisfied(gender))
break; // try again
if (randLevel)
{
var lvl = enc.Type is SlotType4.HoneyTree
? MethodJ.GetHoneyTreeLevel(lv)
: ((lv % (enc.LevelMax - enc.LevelMin + 1)) + enc.LevelMin);
pk.MetLevel = pk.CurrentLevel = (byte)lvl;
}
SetPIDIVSequential(pk, pid, seed);
pk.Gender = gender;
pk.Ability = (pid & 1) == 0 ? pi.Ability1 : pi.Ability2;
return LCRNG.Prev4(seed);
}
}
}
/// <summary>
/// Applies the IVs from the <see cref="EncounterCriteria"/>, assuming the IVs are possible and a Method 1 spread is possible.
/// </summary>
/// <param name="enc">Encounter slot to generate for</param>
/// <param name="pk">Entity to modify</param>
/// <param name="pi">Personal Info of the entity</param>
/// <param name="criteria">Criteria to match</param>
/// <param name="origin">Method 1 origin seed applied</param>
/// <returns>True if the PID/IV was valid &amp; applied to the entity.</returns>
public static bool SetFromIVsJ<T>(this T enc, PK4 pk, PersonalInfo4 pi, EncounterCriteria criteria, out uint origin)
where T : IEncounterSlot4
{
var gr = pi.Gender;
(uint iv1, uint iv2) = GetCombinedIVs(criteria);
Span<uint> all = stackalloc uint[LCRNG.MaxCountSeedsIV];
var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
var seeds = all[..count];
foreach (ref var seed in seeds)
{
seed = LCRNG.Prev2(seed);
var s = seed;
var a = LCRNG.Next16(ref s);
var b = LCRNG.Next16(ref s);
var pid = GetPIDRegular(a, b);
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
continue;
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
if (!criteria.IsGenderSatisfied(gender))
continue;
var lead = MethodJ.GetSeed(enc, seed, enc, 4);
if (!lead.IsValid()) // Verifies the slot, (min) level, and nature loop; if it passes, apply the details.
continue;
pk.PID = pid;
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
pk.Gender = gender;
pk.Ability = (pid & 1) == 0 ? pi.Ability1 : pi.Ability2;
origin = seed;
return true;
}
origin = 0;
return false;
}
public static uint GetPIDRegular(uint a, uint b) => b << 16 | a;
private static void SetPIDIVSequential(PK4 pk, uint pid, uint rand)
{
pk.PID = pid;
var iv1 = LCRNG.Next16(ref rand);
var iv2 = LCRNG.Next16(ref rand);
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
}
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);
}
}

View file

@ -0,0 +1,127 @@
using System;
namespace PKHeX.Core;
/// <summary>
/// Generator methods for Generation 4.
/// </summary>
public static class GenerateMethodK
{
/// <summary>
/// Applies a random PID and IVs to the entity, based on the <see cref="PersonalInfo4"/> and <see cref="EncounterCriteria"/>.
/// </summary>
/// <param name="enc">Encounter slot to generate for</param>
/// <param name="pk">Entity to modify</param>
/// <param name="pi">Personal Info of the entity</param>
/// <param name="criteria">Criteria to match</param>
/// <param name="seed">Initial seed to use; will be modified during the loop if the first seed fails</param>
/// <returns>Method 1 origin seed applied</returns>
public static uint SetRandomK<T>(this T enc, PK4 pk, PersonalInfo4 pi, EncounterCriteria criteria, uint seed)
where T : IEncounterSlot4
{
var gr = pi.Gender;
var ability = criteria.GetAbilityFromNumber(AbilityPermission.Any12);
var (min, max) = SlotMethodK.GetRange(enc.Type, enc.SlotNumber);
bool randLevel = MethodK.IsLevelRand(enc);
var modulo = enc.Type.IsSafari() ? 10 : 100;
// Generate Method K correlated PID and IVs, no lead (keep things simple).
while (true)
{
var esv = LCRNG.Next16(ref seed) % modulo;
if (esv < min || esv > max)
continue;
var lv = randLevel ? LCRNG.Next16(ref seed) : 0;
var nature = LCRNG.Next16(ref seed) % 25;
if (criteria.IsSpecifiedNature() && nature != (byte)criteria.Nature)
continue;
while (true)
{
var a = LCRNG.Next16(ref seed);
var b = LCRNG.Next16(ref seed);
var pid = GetPIDRegular(a, b);
if (pid % 25 != nature)
continue;
if ((pid & 1) != ability)
break; // try again
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
if (!criteria.IsGenderSatisfied(gender))
break; // try again
if (randLevel)
pk.MetLevel = pk.CurrentLevel = (byte)((lv % (enc.LevelMax - enc.LevelMin + 1)) + enc.LevelMin);
pk.PID = pid;
var iv1 = LCRNG.Next16(ref seed);
var iv2 = LCRNG.Next16(ref seed);
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
if (enc.Type is SlotType4.BugContest && !MethodK.IsAny31(iv1) && !MethodK.IsAny31(iv2))
break; // try again
pk.Gender = gender;
pk.Ability = (pid & 1) == 0 ? pi.Ability1 : pi.Ability2;
return LCRNG.Prev4(seed);
}
}
}
/// <summary>
/// Applies the IVs from the <see cref="EncounterCriteria"/>, assuming the IVs are possible and a Method 1 spread is possible.
/// </summary>
/// <param name="enc">Encounter slot to generate for</param>
/// <param name="pk">Entity to modify</param>
/// <param name="pi">Personal Info of the entity</param>
/// <param name="criteria">Criteria to match</param>
/// <param name="origin">Method 1 origin seed applied</param>
/// <returns>True if the PID/IV was valid &amp; applied to the entity.</returns>
public static bool SetFromIVsK<T>(this T enc, PK4 pk, PersonalInfo4 pi, EncounterCriteria criteria, out uint origin)
where T : IEncounterSlot4
{
var gr = pi.Gender;
(uint iv1, uint iv2) = GetCombinedIVs(criteria);
Span<uint> all = stackalloc uint[LCRNG.MaxCountSeedsIV];
var count = LCRNGReversal.GetSeedsIVs(all, iv1 << 16, iv2 << 16);
var seeds = all[..count];
foreach (ref var seed in seeds)
{
seed = LCRNG.Prev2(seed);
var s = seed;
var a = LCRNG.Next16(ref s);
var b = LCRNG.Next16(ref s);
var pid = GetPIDRegular(a, b);
if (criteria.IsSpecifiedNature() && (Nature)(pid % 25) != criteria.Nature)
continue;
var gender = EntityGender.GetFromPIDAndRatio(pid, gr);
if (!criteria.IsGenderSatisfied(gender))
continue;
var lead = MethodK.GetSeed(enc, seed, enc, 4);
if (!lead.IsValid()) // Verifies the slot, (min) level, and nature loop; if it passes, apply the details.
continue;
pk.PID = pid;
pk.IV32 = ((iv2 & 0x7FFF) << 15) | (iv1 & 0x7FFF);
pk.Gender = gender;
pk.Ability = (pid & 1) == 0 ? pi.Ability1 : pi.Ability2;
origin = seed;
return true;
}
origin = 0;
return false;
}
public static uint GetPIDRegular(uint a, uint b) => b << 16 | a;
private static void SetPIDIVSequential(PK4 pk, uint pid, uint rand)
{
}
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);
}
}

View file

@ -317,7 +317,7 @@ public static class MethodJ
result = default; return false;
}
private static bool IsLevelRand<T>(T enc) where T : IEncounterSlot4 => enc.Type.IsLevelRandDPPt();
public static bool IsLevelRand<T>(T enc) where T : IEncounterSlot4 => enc.Type.IsLevelRandDPPt();
private static bool IsSlotValidFrom1Skip<T>(FrameCheckDetails<T> ctx, out uint result)
where T : IEncounterSlot4

View file

@ -243,8 +243,12 @@ public static class MethodK
}
}
/// <summary>
/// Checks if any IV component value is 31.
/// </summary>
/// <remarks>BCC re-rolls 3x if none are 31.</remarks>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsAny31(uint iv16)
public static bool IsAny31(uint iv16)
=> IsLow5Bits31(iv16)
|| IsLow5Bits31(iv16 >> 5)
|| IsLow5Bits31(iv16 >> 10);
@ -336,7 +340,7 @@ public static class MethodK
result = default; return false;
}
private static bool IsLevelRand<T>(T enc) where T : IEncounterSlot4 => enc.Type.IsLevelRandHGSS();
public static bool IsLevelRand<T>(T enc) where T : IEncounterSlot4 => enc.Type.IsLevelRandHGSS();
private static bool IsSlotValidFrom1Skip<T>(FrameCheckDetails<T> ctx, out uint result)
where T : IEncounterSlot4

View file

@ -188,7 +188,7 @@ public partial class SAV_Encounters : Form
var set = new ShowdownSet(editor);
var criteria = EncounterCriteria.GetCriteria(set, editor.PersonalInfo);
if (!isInChain)
criteria = criteria with { Gender = FixedGenderUtil.GenderRandom }; // Genderless tabs and a gendered enc -> let's play safe.
criteria = criteria with { Gender = default }; // Genderless tabs and a gendered enc -> let's play safe.
return criteria;
}

View file

@ -621,10 +621,10 @@ public partial class SAV_Misc5 : Form
source.Remove(slot);
s.Species = slot.Species;
s.Form = slot.Form;
s.Gender = slot.Gender == FixedGenderUtil.GenderRandom ? PersonalTable.B2W2[slot.Species].RandomGender() : slot.Gender;
s.Gender = !((IFixedGender)slot).IsFixedGender ? PersonalTable.B2W2[slot.Species].RandomGender() : slot.Gender;
slot.Moves.CopyTo(moves);
var count = moves.Length - moves.Count((ushort)0);
var count = moves.Length - moves.Count<ushort>(0);
s.Move = count == 0 ? (ushort)0 : moves[rnd.Next(count)];
}
ChangeArea(this, EventArgs.Empty); // refresh

View file

@ -87,6 +87,6 @@ public class BreedTests
// fixed order should be different now.
expected.SequenceEqual(moves).Should().BeFalse();
// nonzero move count should be same
expected.Count((ushort)0).Should().Be(moves.Count((ushort)0));
expected.Count<ushort>(0).Should().Be(moves.Count<ushort>(0));
}
}