mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-05-16 09:02:19 -05:00
Add Wild8RNG generation method
This commit is contained in:
parent
682feab3d4
commit
96d2ca1dcc
|
|
@ -57,13 +57,16 @@ protected override void ApplyDetails(ITrainerInfo sav, EncounterCriteria criteri
|
|||
pk.Met_Location = pk.Egg_Location = Locations.Default8bNone;
|
||||
base.ApplyDetails(sav, criteria, pk);
|
||||
var req = GetRequirement(pk);
|
||||
if (req != MustHave)
|
||||
if (req == MustHave) // Roamers
|
||||
{
|
||||
pk.SetRandomEC();
|
||||
return;
|
||||
var shiny = Shiny == Shiny.Random ? Shiny.FixedValue : Shiny;
|
||||
Roaming8bRNG.ApplyDetails(pk, criteria, shiny, FlawlessIVCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
var shiny = Shiny == Shiny.Never ? Shiny.Never : Shiny.Random;
|
||||
Wild8bRNG.ApplyDetails(pk, criteria, shiny, FlawlessIVCount);
|
||||
}
|
||||
var shiny = Shiny == Shiny.Random ? Shiny.FixedValue : Shiny;
|
||||
Roaming8bRNG.ApplyDetails(pk, criteria, shiny, FlawlessIVCount);
|
||||
}
|
||||
|
||||
protected override void SetMetData(PKM pk, int level, DateTime today)
|
||||
|
|
|
|||
172
PKHeX.Core/Legality/RNG/Wild8bRNG.cs
Normal file
172
PKHeX.Core/Legality/RNG/Wild8bRNG.cs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
using System;
|
||||
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains logic for the Generation 8b (BD/SP) wild and stationary spawns.
|
||||
/// </summary>
|
||||
public static class Wild8bRNG
|
||||
{
|
||||
private const int UNSET = -1;
|
||||
|
||||
public static void ApplyDetails(PKM pk, EncounterCriteria criteria, Shiny shiny = Shiny.FixedValue, int flawless = -1)
|
||||
{
|
||||
if (shiny == Shiny.FixedValue)
|
||||
shiny = criteria.Shiny is Shiny.Random or Shiny.Never ? Shiny.Never : Shiny.Always;
|
||||
if (flawless == -1)
|
||||
flawless = 0;
|
||||
|
||||
int ctr = 0;
|
||||
const int maxAttempts = 50_000;
|
||||
var rnd = Util.Rand;
|
||||
do
|
||||
{
|
||||
ulong s0 = Util.Rand32(rnd) | (ulong)Util.Rand32(rnd) << 32;
|
||||
ulong s1 = Util.Rand32(rnd) | (ulong)Util.Rand32(rnd) << 32;
|
||||
var xors = new XorShift128(s0, s1);
|
||||
if (TryApplyFromSeed(pk, criteria, shiny, flawless, xors))
|
||||
return;
|
||||
} while (++ctr != maxAttempts);
|
||||
|
||||
{
|
||||
ulong s0 = Util.Rand32(rnd) | (ulong)Util.Rand32(rnd) << 32;
|
||||
ulong s1 = Util.Rand32(rnd) | (ulong)Util.Rand32(rnd) << 32;
|
||||
var xors = new XorShift128(s0, s1);
|
||||
TryApplyFromSeed(pk, EncounterCriteria.Unrestricted, shiny, flawless, xors);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool TryApplyFromSeed(PKM pk, EncounterCriteria criteria, Shiny shiny, int flawless, XorShift128 xors)
|
||||
{
|
||||
// Encryption Constant
|
||||
pk.EncryptionConstant = xors.NextUInt();
|
||||
|
||||
// PID
|
||||
var fakeTID = xors.NextUInt(); // fakeTID
|
||||
var pid = xors.NextUInt();
|
||||
pid = GetRevisedPID(fakeTID, pid, pk);
|
||||
if (shiny == Shiny.Never)
|
||||
{
|
||||
if (GetIsShiny(pk.TID, pk.SID, pid))
|
||||
return false;
|
||||
}
|
||||
else if (shiny != Shiny.Random)
|
||||
{
|
||||
if (!GetIsShiny(pk.TID, pk.SID, pid))
|
||||
return false;
|
||||
|
||||
if (shiny == Shiny.AlwaysSquare && pk.ShinyXor != 0)
|
||||
return false;
|
||||
if (shiny == Shiny.AlwaysStar && pk.ShinyXor == 0)
|
||||
return false;
|
||||
}
|
||||
pk.PID = pid;
|
||||
|
||||
// Check IVs: Create flawless IVs at random indexes, then the random IVs for not flawless.
|
||||
Span<int> ivs = stackalloc[] { UNSET, UNSET, UNSET, UNSET, UNSET, UNSET };
|
||||
const int MAX = 31;
|
||||
var determined = 0;
|
||||
while (determined < flawless)
|
||||
{
|
||||
var idx = (int)xors.NextUInt(6);
|
||||
if (ivs[idx] != UNSET)
|
||||
continue;
|
||||
ivs[idx] = 31;
|
||||
determined++;
|
||||
}
|
||||
|
||||
for (var i = 0; i < ivs.Length; i++)
|
||||
{
|
||||
if (ivs[i] == UNSET)
|
||||
ivs[i] = (int)xors.NextInt(0, MAX + 1);
|
||||
}
|
||||
|
||||
if (!criteria.IsIVsCompatible(ivs, 8))
|
||||
return false;
|
||||
|
||||
pk.IV_HP = ivs[0];
|
||||
pk.IV_ATK = ivs[1];
|
||||
pk.IV_DEF = ivs[2];
|
||||
pk.IV_SPA = ivs[3];
|
||||
pk.IV_SPD = ivs[4];
|
||||
pk.IV_SPE = ivs[5];
|
||||
|
||||
// Ability
|
||||
pk.SetAbilityIndex((int)xors.NextUInt(2));
|
||||
|
||||
// Gender (skip this if gender is fixed)
|
||||
var genderRatio = PersonalTable.BDSP.GetFormEntry(pk.Species, pk.Form).Gender;
|
||||
if (genderRatio == PersonalInfo.RatioMagicGenderless)
|
||||
{
|
||||
pk.Gender = 2;
|
||||
}
|
||||
else if (genderRatio == PersonalInfo.RatioMagicMale)
|
||||
{
|
||||
pk.Gender = 0;
|
||||
}
|
||||
else if (genderRatio == PersonalInfo.RatioMagicFemale)
|
||||
{
|
||||
pk.Gender = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
var next = (((int)xors.NextUInt(253) + 1 < genderRatio) ? 1 : 0);
|
||||
if (criteria.Gender is 0 or 1 && next != criteria.Gender)
|
||||
return false;
|
||||
pk.Gender = next;
|
||||
}
|
||||
|
||||
// Skip nature, assuming Synchronize
|
||||
if (criteria.Nature >= 0 && (int)criteria.Nature < 25)
|
||||
pk.Nature = (int)criteria.Nature;
|
||||
else
|
||||
pk.Nature = (int)xors.NextUInt(25);
|
||||
pk.StatNature = pk.Nature;
|
||||
|
||||
// Remainder
|
||||
var scale = (IScaledSize)pk;
|
||||
scale.HeightScalar = (int)xors.NextUInt(0x81) + (int)xors.NextUInt(0x80);
|
||||
scale.WeightScalar = (int)xors.NextUInt(0x81) + (int)xors.NextUInt(0x80);
|
||||
|
||||
// Item, don't care
|
||||
return true;
|
||||
}
|
||||
|
||||
private static uint GetRevisedPID(uint fakeTID, uint pid, ITrainerID tr)
|
||||
{
|
||||
var xor = GetShinyXor(pid, fakeTID);
|
||||
var newXor = GetShinyXor(pid, (uint)(tr.TID | (tr.SID << 16)));
|
||||
|
||||
var fakeRare = GetRareType(xor);
|
||||
var newRare = GetRareType(newXor);
|
||||
|
||||
if (fakeRare == newRare)
|
||||
return pid;
|
||||
|
||||
var isShiny = xor < 16;
|
||||
if (isShiny)
|
||||
return (((uint)(tr.TID ^ tr.SID) ^ (pid & 0xFFFF) ^ (xor == 0 ? 0u : 1u)) << 16) | (pid & 0xFFFF); // force same shiny star type
|
||||
return pid ^ 0x1000_0000;
|
||||
}
|
||||
|
||||
private static Shiny GetRareType(uint xor) => xor switch
|
||||
{
|
||||
0 => Shiny.AlwaysSquare,
|
||||
< 16 => Shiny.AlwaysStar,
|
||||
_ => Shiny.Never,
|
||||
};
|
||||
|
||||
private static bool GetIsShiny(int tid, int sid, uint pid)
|
||||
{
|
||||
return GetIsShiny(pid, (uint)((sid << 16) | tid));
|
||||
}
|
||||
|
||||
private static bool GetIsShiny(uint pid, uint oid) => GetShinyXor(pid, oid) < 16;
|
||||
|
||||
private static uint GetShinyXor(uint pid, uint oid)
|
||||
{
|
||||
var xor = pid ^ oid;
|
||||
return (xor ^ (xor >> 16)) & 0xFFFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Tests/PKHeX.Core.Tests/Legality/Wild8bRNGTests.cs
Normal file
28
Tests/PKHeX.Core.Tests/Legality/Wild8bRNGTests.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using FluentAssertions;
|
||||
using PKHeX.Core;
|
||||
using Xunit;
|
||||
|
||||
namespace PKHeX.Core.Tests.Legality
|
||||
{
|
||||
public static class Wild8bRNGTests
|
||||
{
|
||||
[Fact]
|
||||
public static void TryGenerateLatias()
|
||||
{
|
||||
PB8 test = new() { Species = (int)Species.Latias};
|
||||
ulong s0 = 0xdf9cf5c73e4a160b;
|
||||
ulong s1 = 0xd0b8383103a7f201;
|
||||
Wild8bRNG.TryApplyFromSeed(test, EncounterCriteria.Unrestricted, Shiny.Random, 3, new XorShift128(s0, s1));
|
||||
test.IV_HP.Should().Be(31);
|
||||
test.IV_ATK.Should().Be(4);
|
||||
test.IV_DEF.Should().Be(31);
|
||||
test.IV_SPA.Should().Be(31);
|
||||
test.IV_SPD.Should().Be(6);
|
||||
test.IV_SPE.Should().Be(8);
|
||||
test.HeightScalar.Should().Be(123);
|
||||
test.WeightScalar.Should().Be(115);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user