Add chain shiny and shinyPGF pidiv detection

delete incorrect legality message entry (used a few lines up for super
training flags), is unused.
fix for transferred 8<=xor<16 PIDs in which case the encryption constant
is used (as it is the unmodified PID)
This commit is contained in:
Kurt 2017-04-29 20:04:54 -07:00
parent 6685ae6228
commit e814e7291f
7 changed files with 109 additions and 11 deletions

View file

@ -364,6 +364,13 @@ namespace PKHeX.Core
lines.AddRange(br);
lines.Add(string.Format(V195, EncounterName));
var pidiv = MethodFinder.Analyze(pkm);
if (pidiv != null)
{
if (!pidiv.NoSeed)
lines.Add(string.Format(V248, pidiv.OriginSeed.ToString("X8")));
lines.Add(string.Format(V249, pidiv.Type));
}
return getLegalityReport() + string.Join(Environment.NewLine, lines);
}

View file

@ -24,6 +24,10 @@ namespace PKHeX.Core
public static string V192 {get; set;} = "{0} Relearn Move {1}: {2}";
/// <summary>Format text for exporting the type of Encounter that was matched for the the <see cref="PKM"/></summary>
public static string V195 {get; set;} = "Encounter Type: {0}";
/// <summary>Format text for exporting the <see cref="PIDIV.OriginSeed"/> that was matched for the the <see cref="PKM"/></summary>
public static string V248 {get; set;} = "Origin Seed: {0}";
/// <summary>Format text for exporting the <see cref="PIDIV.Type"/> that was matched for the the <see cref="PKM"/></summary>
public static string V249 {get; set;} = "PID Type: {0}";
/// <summary>Severity string for <see cref="Severity.Indeterminate"/></summary>
public static string V500 { get; set; } = "Indeterminate";

View file

@ -17,7 +17,10 @@ namespace PKHeX.Core
{
if (pk.Format < 3)
return AnalyzeGB(pk);
var pid = pk.PID;
var pid = pk.Format >= 6 && pk.GenNumber >= 3 && pk.GenNumber < 6
? pk.EncryptionConstant // use unmodified PID, quicker than checking if bit was flipped
: pk.PID; // use actual PID
var top = pid >> 16;
var bot = pid & 0xFFFF;
@ -37,10 +40,13 @@ namespace PKHeX.Core
return pidiv;
if (getMG4Match(pid, IVs, out pidiv))
return pidiv;
if (getModifiedPID(pid, out pidiv))
if (getModifiedPID(pk, pid, out pidiv))
return pidiv;
if (pid <= 0xFF && getCuteCharmMatch(pk, pid, out pidiv))
return pidiv;
if (pk.IsShiny && getChainShinyMatch(pk, pid, IVs, out pidiv))
return pidiv;
return pidiv; // no match
}
@ -125,16 +131,26 @@ namespace PKHeX.Core
if (!getIVs(C >> 16, D >> 16).SequenceEqual(IVs))
continue;
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.G4AntiShiny};
pidiv = new PIDIV {OriginSeed = seed, RNG = RNG.LCRNG, Type = PIDType.G4MGAntiShiny};
return true;
}
pidiv = null;
return false;
}
private static bool getModifiedPID(uint pid, out PIDIV pidiv)
private static bool getModifiedPID(PKM pk, uint pid, out PIDIV pidiv)
{
var low = pid & 0xFFFF;
// generation 5 shiny PIDs
// todo
if (low <= 0xFF)
{
var high = pid >> 16;
if ((pk.TID ^ pk.SID ^ low) == high)
{
pidiv = new PIDIV {NoSeed = true, Type = PIDType.G5MGShiny};
return true;
}
}
pidiv = null;
return false;
}
@ -153,7 +169,7 @@ namespace PKHeX.Core
if (pk.PID >= gr + 25)
break;
pidiv = new PIDIV { OriginSeed = 0, RNG = RNG.LCRNG, Type = PIDType.CuteCharm };
pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm};
return true;
case 1: // female
if (pk.PID >= 25)
@ -161,12 +177,57 @@ namespace PKHeX.Core
if (254 <= pk.PersonalInfo.Gender) // no modification for PID
break;
pidiv = new PIDIV { OriginSeed = 0, RNG = RNG.LCRNG, Type = PIDType.CuteCharm };
pidiv = new PIDIV {NoSeed = true, RNG = RNG.LCRNG, Type = PIDType.CuteCharm};
return true;
}
pidiv = null;
return false;
}
private static bool getChainShinyMatch(PKM pk, uint pid, uint[] IVs, out PIDIV pidiv)
{
// 13 shiny bits
// PIDH & 7
// PIDL & 7
// IVs
var bot = getIVChunk(IVs, 0);
var top = getIVChunk(IVs, 3);
var reg = getSeedsFromIVs(RNG.LCRNG, top, bot);
foreach (var seed in reg)
{
// check the individual bits
var s = seed;
int i = 15;
while (true)
{
var bit = s >> 16 & 1;
if (bit != (pid >> i & 1))
break;
s = RNG.LCRNG.Prev(s);
if (--i == 2)
break;
}
if (i != 2) // bit failed
break;
// Shiny Bits of PID validated
var upper = s;
if ((upper >> 16 & 7) != (pid >> 16 & 7))
break;
var lower = RNG.LCRNG.Prev(upper);
if ((lower >> 16 & 7) != (pid & 7))
break;
var upid = ((pid & 0xFFFF) ^ pk.TID ^ pk.SID) & 0xFFF8 | (upper >> 16) & 0x7;
if (upid != pid >> 16)
break;
s = RNG.LCRNG.Reverse(lower, 2); // unroll one final time to get the origin seed
pidiv = new PIDIV {OriginSeed = s, RNG = RNG.LCRNG, Type = PIDType.ChainShiny};
return true;
}
pidiv = null;
return false;
}
private static PIDIV AnalyzeGB(PKM pk)
{
@ -232,5 +293,12 @@ namespace PKHeX.Core
}
return ivs;
}
private static uint getIVChunk(uint[] IVs, int start)
{
uint val = 0;
for (int i = 0; i < 3; i++)
val |= IVs[i+start] << (5*i);
return val;
}
}
}

View file

@ -8,6 +8,8 @@
/// <summary> The RNG seed which immediately generates the PIDIV (starting with PID or IVs, whichever comes first). </summary>
public uint OriginSeed;
public bool NoSeed;
/// <summary> Type of PIDIV correlation </summary>
public PIDType Type;
}

View file

@ -35,10 +35,10 @@
Channel,
// ARNG Based
G4AntiShiny,
G4MGAntiShiny,
// Formulaic
G5AntiShiny,
G5MGShiny,
// Specified
Static,

View file

@ -162,7 +162,6 @@ V98 = Unused Super Training Flag is flagged.
V95 = Can't receive Ribbon(s) as an egg.
V96 = GBA Champion Ribbon
V97 = Artist Ribbon
V98 = National Ribbon (Purified)
V99 = Sinnoh Champion Ribbon
V100 = Legend Ribbon
V104 = Record Ribbon

View file

@ -180,7 +180,25 @@ namespace PKHeX.Tests.PKM
PID = 0x07578CB7, // 0x5271E97E rerolled
IVs = new[] {16, 13, 12, 02, 18, 03},
};
Assert.AreEqual(PIDType.G4AntiShiny, MethodFinder.Analyze(pkASR)?.Type, "Unable to match PID to Antishiny4 spread");
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");
}
}
}