mirror of
https://github.com/kwsch/PKHeX
synced 2024-11-10 14:44:24 +00:00
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:
parent
6685ae6228
commit
e814e7291f
7 changed files with 109 additions and 11 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -35,10 +35,10 @@
|
|||
Channel,
|
||||
|
||||
// ARNG Based
|
||||
G4AntiShiny,
|
||||
G4MGAntiShiny,
|
||||
|
||||
// Formulaic
|
||||
G5AntiShiny,
|
||||
G5MGShiny,
|
||||
|
||||
// Specified
|
||||
Static,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue