Update current RNG frame detection methods

Still not hooked in or handling every case, but is enough progress for
now.
This commit is contained in:
Kurt 2017-05-14 12:42:27 -07:00
parent 404651774a
commit 9380ca25d9
9 changed files with 398 additions and 207 deletions

View file

@ -0,0 +1,20 @@
namespace PKHeX.Core
{
public enum LockInfo
{
/// <summary>
/// PID matches the required parameters.
/// </summary>
Pass,
/// <summary>
/// PID did not match the required Nature.
/// </summary>
Nature,
/// <summary>
/// PID did not match the required Gender.
/// </summary>
Gender,
}
}

View file

@ -261,9 +261,9 @@ namespace PKHeX.Core
var gr = pk.PersonalInfo.Gender;
if (254 <= gr) // no modification for PID
break;
if (pid < gr)
break;
if (pid >= gr + 25)
var rate = pk.Gender == 1 ? 0 : 25*(gr/25 + 1); // buffered
var nature = pid % 25;
if (nature + rate != pid)
break;
pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm};

View file

@ -0,0 +1,103 @@
namespace PKHeX.Core
{
public class SearchCriteria
{
public uint Nature;
public bool Gendered;
public int GenderHigh;
public int GenderLow;
public bool DPPt;
public bool CanSync;
public bool MethodH;
/// <summary>
/// Gets the Search Criteria parameters necessary for generating <see cref="SeedInfo"/> and <see cref="SlotResult"/> objects.
/// </summary>
/// <param name="pk"><see cref="PKM"/> object containing various accessible information required for the encounter.</param>
/// <returns>Object containing search criteria to be passed by reference to search/filter methods.</returns>
public static SearchCriteria getSearchCriteria(PKM pk)
{
var ver = (GameVersion)pk.Version;
switch (ver)
{
// Method H
case GameVersion.R:
case GameVersion.S:
case GameVersion.FR:
case GameVersion.LG:
return new SearchCriteria
{
Nature = pk.EncryptionConstant % 25,
DPPt = false,
MethodH = true,
};
// Method H with Emerald Features
case GameVersion.E:
// Cute Charm waits for gender too!
var gender = pk.Gender;
bool gendered = ver == GameVersion.E && gender != 2;
var criteria = new SearchCriteria
{
Nature = pk.EncryptionConstant % 25,
DPPt = false,
CanSync = true,
MethodH = true,
};
if (gendered)
{
var gr = pk.PersonalInfo.Gender;
criteria.Gendered = true;
criteria.GenderLow = getGenderMinMax(gender, gr, false);
criteria.GenderHigh = getGenderMinMax(gender, gr, true);
}
return criteria;
// Method J
case GameVersion.D:
case GameVersion.P:
case GameVersion.Pt:
return new SearchCriteria
{
Nature = pk.EncryptionConstant % 25,
DPPt = true,
CanSync = true,
};
// Method K
case GameVersion.HG:
case GameVersion.SS:
return new SearchCriteria
{
Nature = pk.EncryptionConstant % 25,
DPPt = false,
CanSync = true,
};
default:
return null;
}
}
/// <summary>
/// Gets the span of values for a given Gender
/// </summary>
/// <param name="gender">Gender</param>
/// <param name="ratio">Gender Ratio</param>
/// <param name="max">Return Max (or Min)</param>
/// <returns>Returns the maximum or minimum gender value that corresponds to the input gender ratio.</returns>
private static int getGenderMinMax(int gender, int ratio, bool max)
{
if (ratio == 0 || ratio == 0xFE || ratio == 0xFF)
gender = 2;
switch (gender)
{
case 0: return max ? 255 : ratio; // male
case 1: return max ? ratio - 1 : 0; // female
default: return max ? 255 : 0; // fixed/genderless
}
}
}
}

View file

@ -0,0 +1,60 @@
using System.Collections.Generic;
namespace PKHeX.Core
{
public class SeedInfo
{
public uint Seed;
public bool Charm3;
public static IEnumerable<SeedInfo> getSeedsUntilNature(PIDIV pidiv, SearchCriteria info)
{
bool reverse = pidiv.Type.IsReversedPID();
bool charm3 = false;
var seed = pidiv.OriginSeed;
yield return new SeedInfo { Seed = seed };
var s1 = seed;
var s2 = pidiv.RNG.Prev(s1);
while (true)
{
var a = s2 >> 16;
var b = s1 >> 16;
var pid = reverse ? a << 16 | b : b << 16 | a;
// Process Conditions
switch (verifyPIDCriteria(pid, info))
{
case LockInfo.Pass:
yield break;
case LockInfo.Gender:
charm3 = true;
break;
}
s1 = pidiv.RNG.Prev(s2);
s2 = pidiv.RNG.Prev(s1);
yield return new SeedInfo { Seed = s1, Charm3 = charm3 };
}
}
private static LockInfo verifyPIDCriteria(uint pid, SearchCriteria info)
{
// Nature locks are always a given
var nval = pid % 25;
if (nval != info.Nature)
return LockInfo.Nature;
if (!info.Gendered)
return LockInfo.Pass;
var gender = pid & 0xFF;
if (info.GenderLow > gender || gender > info.GenderHigh)
return LockInfo.Gender;
return LockInfo.Pass;
}
}
}

View file

@ -4,97 +4,96 @@ namespace PKHeX.Core
{
public static class SlotFinder
{
public static List<uint> getSlotSeeds(PIDIV pidiv, uint nature, GameVersion v)
/// <summary>
/// Checks a <see cref="PIDIV"/> to see if any encounter frames can generate the spread. Requires further filtering against matched Encounter Slots and generation patterns.
/// </summary>
/// <param name="pidiv">Matched <see cref="PIDIV"/> containing <see cref="PIDIV.RNG"/> info and <see cref="PIDIV.OriginSeed"/>.</param>
/// <param name="pk"><see cref="PKM"/> object containing various accessible information required for the encounter.</param>
/// <returns><see cref="IEnumerable{SlotResult}"/> to yield possible encounter details for further filtering</returns>
public static IEnumerable<SlotResult> getSlotSeeds(PIDIV pidiv, PKM pk)
{
// gather possible nature determination seeds until a same-nature PID breaks the unrolling
var seeds = getSeedsUntilNature(pidiv, nature);
SearchCriteria criteria = SearchCriteria.getSearchCriteria(pk);
if (criteria == null)
yield break;
IEnumerable<SeedInfo> seeds = SeedInfo.getSeedsUntilNature(pidiv, criteria);
// get game generation criteria
bool dppt = v == GameVersion.D || v == GameVersion.D || v == GameVersion.Pt;
IEnumerable<SlotResult> info;
switch (pidiv.Type)
{
case PIDType.CuteCharm:
info = filterCuteCharm(seeds, pidiv, dppt);
info = filterCuteCharm(seeds, pidiv, criteria);
break;
default:
bool canSync = v == GameVersion.E || (int)v > 5; // Emerald and Gen4
info = filterNatureSync(seeds, pidiv, nature, dppt, canSync);
info = filterNatureSync(seeds, pidiv, criteria);
break;
}
// games need to map 0-65535 to 0-99
// dppt use /656, hgss&gen3 use %100
foreach (var z in info)
{
}
return null;
yield return z;
}
private static IEnumerable<uint> getSeedsUntilNature(PIDIV pidiv, uint nature)
/// <summary>
/// Filters the input <see cref="SeedInfo"/> according to a Nature Lock frame generation pattern.
/// </summary>
/// <param name="seeds">Seed Information for the frame</param>
/// <param name="pidiv">PIDIV Info for the frame</param>
/// <param name="info">Search Info for the frame</param>
/// <returns>Possible matches to the Nature Lock frame generation pattern</returns>
private static IEnumerable<SlotResult> filterNatureSync(IEnumerable<SeedInfo> seeds, PIDIV pidiv, SearchCriteria info)
{
bool reverse = pidiv.Type.IsReversedPID();
var seed = pidiv.OriginSeed;
yield return seed;
var s1 = pidiv.RNG.Prev(seed);
var s2 = pidiv.RNG.Prev(s1);
while (true)
{
var a = s2 >> 16;
var b = s1 >> 16;
var pid = reverse ? b << 16 | a : a << 16 | b;
if (pid % 25 == nature)
break;
s1 = pidiv.RNG.Prev(s2);
s2 = pidiv.RNG.Prev(s1);
yield return s1;
}
}
private static IEnumerable<SlotResult> filterNatureSync(IEnumerable<uint> seeds, PIDIV pidiv, uint nature, bool dppt, bool canSync)
{
foreach (var s in seeds)
foreach (var seed in seeds)
{
var s = seed.Seed;
var rand = s >> 16;
bool sync = canSync && (rand & 1) == 0;
bool reg = (dppt ? rand / 0xA3E : rand % 25) == nature;
bool sync = info.CanSync && !seed.Charm3 && (info.DPPt ? rand >> 15 : rand & 1) == 0;
bool reg = (info.DPPt ? rand / 0xA3E : rand % 25) == info.Nature;
if (!sync && !reg) // doesn't generate nature frame
continue;
uint prev = pidiv.RNG.Prev(s);
if (canSync && reg) // check for failed sync
if (info.CanSync && reg) // check for failed sync
{
var failsync = prev >> 31 != 0;
var failsync = (info.DPPt ? prev >> 31 : (prev >> 16) & 1) != 1;
if (failsync)
yield return new SlotResult {Seed = pidiv.RNG.Prev(prev), Sync = false};
yield return new SlotResult {Seed = pidiv.RNG.Prev(prev), Sync = true, FailedSync = true};
}
if (sync)
yield return new SlotResult {Seed = prev, Sync = true};
if (reg)
yield return new SlotResult {Seed = prev, Sync = false};
yield return new SlotResult {Seed = prev, Sync = false, CuteCharm = seed.Charm3};
}
}
private static IEnumerable<SlotResult> filterCuteCharm(IEnumerable<uint> seeds, PIDIV pidiv, bool dppt)
/// <summary>
/// Filters the input <see cref="SeedInfo"/> according to a Cute Charm frame generation pattern.
/// </summary>
/// <param name="seeds">Seed Information for the frame</param>
/// <param name="pidiv">PIDIV Info for the frame</param>
/// <param name="info">Search Info for the frame</param>
/// <returns>Possible matches to the Cute Charm frame generation pattern</returns>
private static IEnumerable<SlotResult> filterCuteCharm(IEnumerable<SeedInfo> seeds, PIDIV pidiv, SearchCriteria info)
{
foreach (var s in seeds)
foreach (var seed in seeds)
{
var s = seed.Seed;
var rand = s >> 16;
bool charmProc = (dppt ? rand / 0x5556 : rand%3) == 0;
if (charmProc)
yield return new SlotResult {Seed = pidiv.RNG.Prev(s)};
var nature = info.DPPt ? rand / 0xA3E : rand % 25;
if (nature != info.Nature)
continue;
var prev = pidiv.RNG.Prev(s);
var proc = prev >> 16;
bool charmProc = (info.DPPt ? proc / 0x5556 : proc % 3) == 0;
if (!charmProc)
continue;
yield return new SlotResult {Seed = prev, CuteCharm = true};
}
}
public class SlotResult
{
public uint Seed { get; set; }
public bool Sync { get; set; }
}
}
}

View file

@ -0,0 +1,14 @@
namespace PKHeX.Core
{
public class SlotResult
{
public uint Seed { get; set; }
public bool Sync { get; set; }
public bool FailedSync { get; set; }
public bool CuteCharm { get; set; }
public bool SuctionCups { get; set; }
public uint ESV { get; set; }
}
}

View file

@ -88,6 +88,7 @@
</Choose>
<ItemGroup>
<Compile Include="PKM\DateTestPKM.cs" />
<Compile Include="PKM\PIDIVTests.cs" />
<Compile Include="PKM\PKMTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Saves\Substructures\MemeCryptoTests.cs" />

View file

@ -0,0 +1,144 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using PKHeX.Core;
namespace PKHeX.Tests.PKM
{
[TestClass]
public class PIDIVTest
{
private const string PIDIVTestCategory = "PKM PIDIV Matching Tests";
// Note: IVs are stored HP/ATK/DEF/SPE/SPA/SPD
[TestMethod]
[TestCategory(PIDIVTestCategory)]
public void PIDIVMatchingTest3()
{
// Method 1/2/4
var pk1 = new PK3 {PID = 0xE97E0000, IVs = new[] {17, 19, 20, 16, 13, 12}};
Assert.AreEqual(PIDType.Method_1, MethodFinder.Analyze(pk1)?.Type, "Unable to match PID to Method 1 spread");
var pk2 = new PK3 {PID = 0x5271E97E, IVs = new[] {02, 18, 03, 12, 22, 24}};
Assert.AreEqual(PIDType.Method_2, MethodFinder.Analyze(pk2)?.Type, "Unable to match PID to Method 2 spread");
var pk4 = new PK3 {PID = 0x31B05271, IVs = new[] {02, 18, 03, 05, 30, 11}};
Assert.AreEqual(PIDType.Method_4, MethodFinder.Analyze(pk4)?.Type, "Unable to match PID to Method 4 spread");
// Method 1/2/4, reversed for Unown.
var pk1U = new PK3 {PID = 0x815549A2, IVs = new[] {02, 26, 30, 30, 11, 26}, Species = 201}; // Unown-C
Assert.AreEqual(PIDType.Method_1_Unown, MethodFinder.Analyze(pk1U)?.Type, "Unable to match PID to Method 1 Unown spread");
var pk2U = new PK3 {PID = 0x8A7B5190, IVs = new[] {14, 02, 21, 30, 29, 15}, Species = 201}; // Unown-M
Assert.AreEqual(PIDType.Method_2_Unown, MethodFinder.Analyze(pk2U)?.Type, "Unable to match PID to Method 2 Unown spread");
var pk4U = new PK3 {PID = 0x5FA80D70, IVs = new[] {02, 06, 03, 26, 04, 19}, Species = 201}; // Unown-A
Assert.AreEqual(PIDType.Method_4_Unown, MethodFinder.Analyze(pk4U)?.Type, "Unable to match PID to Method 4 Unown spread");
// Colosseum / XD
var pk3 = new PK3 {PID = 0x0985A297, IVs = new[] {06, 01, 00, 07, 17, 07}};
Assert.AreEqual(PIDType.CXD, MethodFinder.Analyze(pk3)?.Type, "Unable to match PID to CXD spread");
// Channel Jirachi
var pkC = new PK3 {PID = 0x9E27D2F6, IVs = new[] {04, 15, 21, 14, 18, 29}};
Assert.AreEqual(PIDType.Channel, MethodFinder.Analyze(pkC)?.Type, "Unable to match PID to Channel spread");
}
[TestMethod]
[TestCategory(PIDIVTestCategory)]
public void PIDIVMatchingTest3Event()
{
// Restricted: TID/SID are zero.
var pkR = new PK3 {PID = 0x0000E97E, IVs = new[] {17, 19, 20, 16, 13, 12}};
Assert.AreEqual(PIDType.BACD_R, MethodFinder.Analyze(pkR)?.Type, "Unable to match PID to BACD-R spread");
// Restricted Antishiny: PID is incremented 2 times to lose shininess.
var pkRA = new PK3 {PID = 0x0000E980, IVs = new[] {17, 19, 20, 16, 13, 12}, TID = 01337, SID = 60486};
Assert.AreEqual(PIDType.BACD_R_A, MethodFinder.Analyze(pkRA)?.Type, "Unable to match PID to BACD-R antishiny spread");
// Unrestricted: TID/SID are zero.
var pkU = new PK3 {PID = 0x67DBFC33, IVs = new[] {12, 25, 27, 30, 02, 31}};
Assert.AreEqual(PIDType.BACD_U, MethodFinder.Analyze(pkU)?.Type, "Unable to match PID to BACD-U spread");
// Unrestricted Antishiny: PID is incremented 5 times to lose shininess.
var pkUA = new PK3 {PID = 0x67DBFC38, IVs = new[] {12, 25, 27, 30, 02, 31}, TID = 01337, SID = 40657};
Assert.AreEqual(PIDType.BACD_U_A, MethodFinder.Analyze(pkUA)?.Type, "Unable to match PID to BACD-U antishiny spread");
// berry fix zigzagoon: seed 0x0020
var pkRS = new PK3 {PID = 0x38CA4EA0, IVs = new[] {00, 20, 28, 11, 19, 00}, TID = 30317, SID = 00000};
var a_pkRS = MethodFinder.Analyze(pkRS);
Assert.AreEqual(PIDType.BACD_R_S, a_pkRS?.Type, "Unable to match PID to BACD-R shiny spread");
Assert.IsTrue(0x0020 == a_pkRS?.OriginSeed, "Unable to match PID to BACD-R shiny spread origin seed");
}
[TestMethod]
[TestCategory(PIDIVTestCategory)]
public void PIDIVMatchingTest4()
{
// Cute Charm: Male Bulbasaur
var pkCC = new PK4 {PID = 0x00000037, IVs = new[] {16, 13, 12, 02, 18, 03}, Species = 1, Gender = 0};
Assert.AreEqual(PIDType.CuteCharm, MethodFinder.Analyze(pkCC)?.Type, "Unable to match PID to Cute Charm spread");
// Antishiny Mystery Gift: TID/SID are zero. Original PID of 0x5271E97E is rerolled.
var pkASR = new PK4 {PID = 0x07578CB7, IVs = new[] {16, 13, 12, 02, 18, 03}};
Assert.AreEqual(PIDType.G4MGAntiShiny, MethodFinder.Analyze(pkASR)?.Type, "Unable to match PID to Antishiny4 spread");
// Chain Shiny: TID/SID are zero.
var pkCS = new PK4 {PID = 0xA9C1A9C6, IVs = new[] {22, 14, 23, 24, 11, 04}};
Assert.AreEqual(PIDType.ChainShiny, MethodFinder.Analyze(pkCS)?.Type, "Unable to match PID to Chain Shiny spread");
}
[TestMethod]
[TestCategory(PIDIVTestCategory)]
public void PIDIVMatchingTest5()
{
// Shiny Mystery Gift PGF; IVs are unrelated.
var pkS5 = new PK5 {PID = 0xBEEF0037, TID = 01337, SID = 48097};
Assert.AreEqual(PIDType.G5MGShiny, MethodFinder.Analyze(pkS5)?.Type, "Unable to match PID to PGF Shiny spread");
}
[TestMethod]
[TestCategory(PIDIVTestCategory)]
public void PIDIVPokeSpotTest()
{
// XD PokeSpots: Check all 3 Encounter Slots (examples are one for each location).
var pkPS0 = new PK3 { PID = 0x7B2D9DA7 }; // Zubat (Cave)
Assert.IsTrue(MethodFinder.getPokeSpotSeeds(pkPS0, 0).Any(), "PokeSpot encounter info mismatch (Common)");
var pkPS1 = new PK3 { PID = 0x3EE9AF66 }; // Gligar (Rock)
Assert.IsTrue(MethodFinder.getPokeSpotSeeds(pkPS1, 1).Any(), "PokeSpot encounter info mismatch (Uncommon)");
var pkPS2 = new PK3 { PID = 0x9B667F3C }; // Surskit (Oasis)
Assert.IsTrue(MethodFinder.getPokeSpotSeeds(pkPS2, 2).Any(), "PokeSpot encounter info mismatch (Rare)");
}
[TestMethod]
[TestCategory(PIDIVTestCategory)]
public void PIDIVEncounterSlotTest()
{
// Modest Method 1
var pk = new PK3 {PID = 0x6937DA48, IVs = new[] {31, 31, 31, 31, 31, 31}};
var pidiv = MethodFinder.Analyze(pk);
Assert.AreEqual(PIDType.Method_1, pidiv?.Type, "Unable to match PID to Method 1 spread");
// Test for Method J
{
// Pearl
pk.Version = (int) GameVersion.P;
var results = SlotFinder.getSlotSeeds(pidiv, pk);
const int failSyncCount = 1;
const int noSyncCount = 2;
const int SyncCount = 37;
var r2 = results.ToArray();
var failSync = r2.Where(z => z.FailedSync);
var noSync = r2.Where(z => !z.Sync);
var sync = r2.Where(z => z.Sync && !z.FailedSync);
Assert.AreEqual(failSync.Count(), failSyncCount, "Failed Sync count mismatch.");
Assert.AreEqual(sync.Count(), SyncCount, "Sync count mismatch.");
Assert.AreEqual(noSync.Count(z => !z.Sync), noSyncCount, "Non-Sync count mismatch.");
// var slots = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 9 };
}
// Test for Method H and K
{
// Sapphire
// pk.Version = (int)GameVersion.S;
// var results = SlotFinder.getSlotSeeds(pidiv, pk);
}
}
}
}

View file

@ -9,7 +9,6 @@ namespace PKHeX.Tests.PKM
public class PKMTests
{
private const string DateTestCategory = "PKM Date Tests";
private const string PIDIVTestCategory = "PKM PIDIV Matching Tests";
[TestMethod]
[TestCategory(DateTestCategory)]
@ -128,154 +127,5 @@ namespace PKHeX.Tests.PKM
Assert.AreEqual(now.Month, pk.EggMetMonth, "Egg_Month was not correctly set");
Assert.AreEqual(now.Year - 2000, pk.EggMetYear, "Egg_Year was not correctly set");
}
[TestMethod]
[TestCategory(PIDIVTestCategory)]
public void PIDIVMatchingTest()
{
// IVs are stored HP/ATK/DEF/SPE/SPA/SPD
var pk1 = new PK3
{
PID = 0xE97E0000,
IVs = new[] {17, 19, 20, 16, 13, 12}
};
Assert.AreEqual(PIDType.Method_1, MethodFinder.Analyze(pk1)?.Type, "Unable to match PID to Method 1 spread");
var pk2 = new PK3
{
PID = 0x5271E97E,
IVs = new[] {02, 18, 03, 12, 22, 24}
};
Assert.AreEqual(PIDType.Method_2, MethodFinder.Analyze(pk2)?.Type, "Unable to match PID to Method 2 spread");
var pk4 = new PK3
{
PID = 0x31B05271,
IVs = new[] {02, 18, 03, 05, 30, 11}
};
Assert.AreEqual(PIDType.Method_4, MethodFinder.Analyze(pk4)?.Type, "Unable to match PID to Method 4 spread");
var pk3 = new PK3
{
PID = 0x0985A297,
IVs = new[] {06, 01, 00, 07, 17, 07}
};
Assert.AreEqual(PIDType.CXD, MethodFinder.Analyze(pk3)?.Type, "Unable to match PID to CXD spread");
var pkC = new PK3
{
PID = 0x9E27D2F6,
IVs = new[] {04, 15, 21, 14, 18, 29}
};
Assert.AreEqual(PIDType.Channel, MethodFinder.Analyze(pkC)?.Type, "Unable to match PID to Channel spread");
var pkCC = new PK4
{
PID = 0x00000037,
IVs = new[] {16, 13, 12, 02, 18, 03},
Species = 1,
Gender = 0,
};
Assert.AreEqual(PIDType.CuteCharm, MethodFinder.Analyze(pkCC)?.Type, "Unable to match PID to Cute Charm spread");
var pkASR = new PK4
{
PID = 0x07578CB7, // 0x5271E97E rerolled
IVs = new[] {16, 13, 12, 02, 18, 03},
};
Assert.AreEqual(PIDType.G4MGAntiShiny, MethodFinder.Analyze(pkASR)?.Type, "Unable to match PID to Antishiny4 spread");
var pkCS = new PK4
{
PID = 0xA9C1A9C6,
// TID = 0,
// SID = 0, // already default values, necessary for the forcing of a shiny PID
IVs = new[] {22, 14, 23, 24, 11, 04}
};
Assert.AreEqual(PIDType.ChainShiny, MethodFinder.Analyze(pkCS)?.Type, "Unable to match PID to Chain Shiny spread");
var pkS5 = new PK5
{
PID = 0xBEEF0037,
TID = 01337,
SID = 48097,
// IVs = new[] {22, 14, 23, 24, 11, 04} // unnecessary
};
Assert.AreEqual(PIDType.G5MGShiny, MethodFinder.Analyze(pkS5)?.Type, "Unable to match PID to PGF Shiny spread");
var pkR = new PK3
{
PID = 0x0000E97E,
// TID = 0,
// SID = 0, // already default values, necessary for the forcing of a shiny PID
IVs = new[] {17, 19, 20, 16, 13, 12}
};
Assert.AreEqual(PIDType.BACD_R, MethodFinder.Analyze(pkR)?.Type, "Unable to match PID to BACD-R spread");
var pkRA = new PK3
{
PID = 0x0000E980, // +2 of 8 to flip first shiny bit
TID = 01337,
SID = 60486,
IVs = new[] {17, 19, 20, 16, 13, 12}
};
Assert.AreEqual(PIDType.BACD_R_A, MethodFinder.Analyze(pkRA)?.Type, "Unable to match PID to BACD-R antishiny spread");
var pkU = new PK3
{
PID = 0x67DBFC33,
// TID = 0,
// SID = 0, // already default values, necessary for the forcing of a shiny PID
IVs = new[] {12, 25, 27, 30, 02, 31}
};
Assert.AreEqual(PIDType.BACD_U, MethodFinder.Analyze(pkU)?.Type, "Unable to match PID to BACD-U spread");
var pkUA = new PK3
{
PID = 0x67DBFC38, // +5 of 8 to flip first shiny bit
TID = 01337,
SID = 40657,
IVs = new[] {12, 25, 27, 30, 02, 31}
};
Assert.AreEqual(PIDType.BACD_U_A, MethodFinder.Analyze(pkUA)?.Type, "Unable to match PID to BACD-U antishiny spread");
var pkRS = new PK3 // berry fix zigzagoon: seed 0x0020
{
PID = 0x38CA4EA0,
TID = 30317,
SID = 00000,
IVs = new[] { 00, 20, 28, 11, 19, 00 }
};
var a_pkRS = MethodFinder.Analyze(pkRS);
Assert.AreEqual(PIDType.BACD_R_S, a_pkRS?.Type, "Unable to match PID to BACD-R shiny spread");
Assert.IsTrue(0x0020 == a_pkRS?.OriginSeed, "Unable to match PID to BACD-R shiny spread origin seed");
var pkPS0 = new PK3 {PID = 0x7B2D9DA7}; // Zubat (Cave)
Assert.IsTrue(MethodFinder.getPokeSpotSeeds(pkPS0, 0).Any(), "PokeSpot encounter info mismatch (Common)");
var pkPS1 = new PK3 {PID = 0x3EE9AF66}; // Gligar (Rock)
Assert.IsTrue(MethodFinder.getPokeSpotSeeds(pkPS1, 1).Any(), "PokeSpot encounter info mismatch (Uncommon)");
var pkPS2 = new PK3 {PID = 0x9B667F3C}; // Surskit (Oasis)
Assert.IsTrue(MethodFinder.getPokeSpotSeeds(pkPS2, 2).Any(), "PokeSpot encounter info mismatch (Rare)");
var pk1U = new PK3
{
Species = 201, // Unown-C
PID = 0x815549A2,
IVs = new[] {02, 26, 30, 30, 11, 26}
};
Assert.AreEqual(PIDType.Method_1_Unown, MethodFinder.Analyze(pk1U)?.Type, "Unable to match PID to Method 1 Unown spread");
var pk2U = new PK3
{
Species = 201, // Unown-M
PID = 0x8A7B5190,
IVs = new[] {14, 02, 21, 30, 29, 15}
};
Assert.AreEqual(PIDType.Method_2_Unown, MethodFinder.Analyze(pk2U)?.Type, "Unable to match PID to Method 2 Unown spread");
var pk4U = new PK3
{
Species = 201, // Unown-C
PID = 0x5FA80D70,
IVs = new[] {02, 06, 03, 26, 04, 19}
};
Assert.AreEqual(PIDType.Method_4_Unown, MethodFinder.Analyze(pk4U)?.Type, "Unable to match PID to Method 4 Unown spread");
}
}
}