Fix T2/Channel jirachi enc->pk3 generating

This commit is contained in:
Kurt 2024-11-10 15:00:31 -06:00
parent 1ffbd46e3c
commit c8726c4e2d
7 changed files with 94 additions and 37 deletions

View file

@ -28,16 +28,16 @@ internal static class EncountersWC3
new(263, 05, S) { Moves = new(033,045,039,000), Language = (int)Japanese, Method = BACD_RBCD, ID32 = 21121, Shiny = Always, OriginalTrainerName = "ルビー", OriginalTrainerGender = RandD3_1 }, // Berry Fix Ruby
new(263, 05, S) { Moves = new(033,045,039,000), Language = (int)Japanese, Method = BACD_RBCD, ID32 = 21121, Shiny = Always, OriginalTrainerName = "サファイア", OriginalTrainerGender = RandD3_0 }, // Berry Fix Sapphire
new(385, 05, R) { Moves = new(001,144,000,000), Language = (int)Japanese, Method = BACD_T2, ID32 = 30719, Shiny = Never, OriginalTrainerName = "ネガイボシ", OriginalTrainerGender = Only0 }, // Negai Boshi Jirachi
new(385, 05, RS){ Moves = new(001,144,000,000), Language = (int)Japanese, Method = BACD_U_AX, ID32 = 30719, Shiny = Never, OriginalTrainerName = "ネガイボシ", OriginalTrainerGender = Recipient }, // Negai Boshi Jirachi (Match Recipient)
new(385, 05, R) { Moves = new(001,144,000,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 40707, Shiny = Never, OriginalTrainerName = "タナバタ", OriginalTrainerGender = Only1 }, // Tanabata Jirachi (2004)
new(385, 05, R) { Moves = new(273,093,156,000), Language = (int)Japanese, Method = BACD_T2, ID32 = 30719, Shiny = Never, OriginalTrainerName = "ネガイボシ", OriginalTrainerGender = Only0 }, // Negai Boshi Jirachi
new(385, 05, RS){ Moves = new(273,093,156,000), Language = (int)Japanese, Method = BACD_U_AX, ID32 = 30719, Shiny = Never, OriginalTrainerName = "ネガイボシ", OriginalTrainerGender = Recipient }, // Negai Boshi Jirachi (Match Recipient)
new(385, 05, R) { Moves = new(273,093,156,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 40707, Shiny = Never, OriginalTrainerName = "タナバタ", OriginalTrainerGender = Only1 }, // Tanabata Jirachi (2004)
new(025, 10, R) { Moves = new(019,084,039,086), Language = (int)Japanese, Method = BACD_R_A, ID32 = 41205, Shiny = Never, OriginalTrainerName = "", OriginalTrainerGender = Only0 }, // ANA Pikachu
new(052, 05, R) { Moves = new(010,045,000,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50318, Shiny = Never, OriginalTrainerName = "ポケパーク", OriginalTrainerGender = Only0 }, // PokéPark Meowth
new(025, 10, R) { Moves = new(084,045,086,057), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50319, Shiny = Never, OriginalTrainerName = "ヨコハマ", OriginalTrainerGender = Only0 }, // Yokohama Pikachu
new(151, 10, R) { Moves = new(001,144,000,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50716, Shiny = Never, OriginalTrainerName = "ハドウ", OriginalTrainerGender = RandD3, FatefulEncounter = true }, // Hadou Mew
new(025, 10, R) { Moves = new(045,039,086,019), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50425, Shiny = Never, OriginalTrainerName = "", OriginalTrainerGender = RandS3 }, // GW Pikachu
new(025, 10, R) { Moves = new(045,039,086,019), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50701, Shiny = Never, OriginalTrainerName = "サッポロ", OriginalTrainerGender = Only0 }, // Sapporo Pikachu
new(385, 05, R) { Moves = new(001,144,000,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50707, Shiny = Never, OriginalTrainerName = "タナバタ", OriginalTrainerGender = Only1 }, // Tanabata Jirachi (2005)
new(385, 05, R) { Moves = new(273,093,156,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50707, Shiny = Never, OriginalTrainerName = "タナバタ", OriginalTrainerGender = Only1 }, // Tanabata Jirachi (2005)
new(375, 30, R) { Moves = new(036,093,232,287), Language = (int)Japanese, Method = BACD_R_A, ID32 = 02005, Shiny = Never, OriginalTrainerName = "フェスタ", OriginalTrainerGender = Only0, RibbonNational = true }, // Festa Metang
new(202, 05, R) { Moves = new(068,243,219,194), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50701, Shiny = Never, OriginalTrainerName = "サンデー", OriginalTrainerGender = RandS3 }, // Sunday Wobbuffet
new(377, 40, R) { Moves = new(174,276,246,063), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50901, Shiny = Never, OriginalTrainerName = "ハドウ", OriginalTrainerGender = RandSG15 }, // Regirock
@ -45,7 +45,7 @@ internal static class EncountersWC3
new(379, 40, R) { Moves = new(174,276,246,063), Language = (int)Japanese, Method = BACD_R_A, ID32 = 50901, Shiny = Never, OriginalTrainerName = "ハドウ", OriginalTrainerGender = RandSG15 }, // Registeel
new(151, 30, R) { Moves = new(001,144,005,118), Language = (int)Japanese, Method = BACD_R_A, ID32 = 60510, Shiny = Never, OriginalTrainerName = "ポケパーク", OriginalTrainerGender = RandD3, FatefulEncounter = true }, // PokéPark Mew
new(251, 30, R) { Moves = new(215,219,246,248), Language = (int)Japanese, Method = BACD_R_A, ID32 = 60623, Shiny = Never, OriginalTrainerName = "ポケパーク", OriginalTrainerGender = RandS7 }, // PokéPark Celebi
new(385, 05, R) { Moves = new(001,144,000,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 60707, Shiny = Never, OriginalTrainerName = "タナバタ", OriginalTrainerGender = RandS7 }, // Tanabata Jirachi (2006)
new(385, 05, R) { Moves = new(273,093,156,000), Language = (int)Japanese, Method = BACD_R_A, ID32 = 60707, Shiny = Never, OriginalTrainerName = "タナバタ", OriginalTrainerGender = RandS7 }, // Tanabata Jirachi (2006)
new(251, 10, R) { Moves = new(073,105,215,219), Language = (int)Japanese, Method = BACD_R_A, ID32 = 60720, Shiny = Never, OriginalTrainerName = "ミツリン", OriginalTrainerGender = RandS7 }, // Mitsurin Celebi (2006)
new(385, 30, R) { Moves = new(273,094,270,156), Language = (int)Japanese, Method = BACD_R_A, ID32 = 60731, Shiny = Never, OriginalTrainerName = "ポケパーク", OriginalTrainerGender = RandD3 }, // PokéPark Jirachi (2006)
new(385, 30, R) { Moves = new(273,094,270,156), Language = (int)Japanese, Method = BACD_R_A, ID32 = 60830, Shiny = Never, OriginalTrainerName = "ポケパーク", OriginalTrainerGender = RandD3 }, // PokéPark Jirachi (2006)

View file

@ -96,6 +96,11 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
Version = GetVersion(tr),
EXP = Experience.GetEXP(Level, pi.EXPGrowth),
};
if (TID16 is not UnspecifiedID)
pk.TID16 = TID16;
if (SID16 is not UnspecifiedID)
pk.SID16 = SID16;
pk.SetMoves(Moves);
pk.SetMaximumPPCurrent(Moves);
@ -108,11 +113,10 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
}
else
{
pk.ID32 = TID16;
pk.SID16 = SID16;
pk.Language = (int)GetSafeLanguage((LanguageID)tr.Language);
pk.OriginalTrainerName = !string.IsNullOrWhiteSpace(OriginalTrainerName) ? OriginalTrainerName : tr.OT;
pk.OriginalTrainerGender = OriginalTrainerGender == GiftGender3.Recipient ? tr.Gender : (byte)GetGender(seed);
if (OriginalTrainerGender is not GiftGender3.RandAlgo)
pk.OriginalTrainerGender = OriginalTrainerGender == GiftGender3.Recipient ? tr.Gender : (byte)GetGender(seed);
if (IsEgg)
{
@ -180,6 +184,8 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
{
var gr = pi.Gender;
uint idXor = pk.TID16 ^ (uint)pk.SID16;
if (Method is Channel)
return SetPINGAChannel(pk, criteria);
while (true)
{
uint seed = Util.Rand32();
@ -198,7 +204,21 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
continue;
pk.PID = pid;
PIDGenerator.SetIVsFromSeedSequentialLCRNG(ref seed, pk);
pk.IV32 = PIDGenerator.SetIVsFromSeedSequentialLCRNG(ref seed);
pk.RefreshAbility((int)(pk.PID & 1));
return seed;
}
}
private static uint SetPINGAChannel(PK3 pk, EncounterCriteria criteria)
{
while (true)
{
uint seed = Util.Rand32();
seed = ChannelJirachi.SkipToPIDIV(seed);
PIDGenerator.SetValuesFromSeedChannel(pk, seed);
if (criteria.IsSpecifiedNature() && criteria.Nature != pk.Nature)
continue; // try again
pk.RefreshAbility((int)(pk.PID & 1));
return seed;
}
@ -207,8 +227,9 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
private uint GetSaneSeed(uint seed) => Method switch
{
BACD_RBCD => Math.Clamp(seed, 3, 213), // BCD digit sum
Channel => ChannelJirachi.SkipToPIDIV(seed),
BACD_T2 when Species is not (ushort)Core.Species.Jirachi
BACD_T2 when Species is (ushort)Core.Species.Jirachi
=> LCRNG.Next2(seed & 0xFFFF),
BACD_T2
=> LCRNG.Next2(PCJPFifthAnniversary.GetSeedForResult(Species, Shiny == Shiny.Always, Moves.Contains((ushort)Move.Wish), seed)),
BACD_T3
=> LCRNG.Next2(PCJPFifthAnniversary.GetSeedForResult(Species, Shiny == Shiny.Always, Moves.Contains((ushort)Move.Wish), seed)),
@ -257,6 +278,9 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
if (!Version.Contains(pk.Version))
return false;
if (pk.IsEgg && !IsEgg)
return false;
bool hatchedEgg = IsEgg && !pk.IsEgg;
if (!hatchedEgg)
{
@ -320,7 +344,7 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
if (type is BACD_EA or BACD_ES && !IsEgg)
return false;
if (OriginalTrainerGender is not GiftGender3.Recipient && (!IsEgg || pk.IsEgg) && !IsMatchGender(pk, value.OriginSeed))
if (OriginalTrainerGender is not (GiftGender3.RandAlgo or GiftGender3.Recipient) && (!IsEgg || pk.IsEgg) && !IsMatchGender(pk, value.OriginSeed))
return false;
return Method switch
@ -328,8 +352,9 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
BACD_U => true,
BACD_R => IsRestrictedSimple(ref value, type),
BACD_R_A => IsRestrictedAnti(ref value, type),
BACD_U_AX => IsUnrestrictedAntiX(ref value, type),
BACD_T2 => IsRestrictedTable2(ref value, type, Species, Moves.Contains((ushort)Move.Wish)),
BACD_T2 => IsRestrictedTable2(ref value, type, Species, Moves.Contains((ushort)Move.Wish)),
BACD_T3 => IsRestrictedTable3(ref value, type, Species, Moves.Contains((ushort)Move.Wish)),
BACD_RBCD => IsBerryFixShiny(ref value, type),
BACD_M => IsMystryMew(ref value, type),
@ -341,9 +366,11 @@ public sealed class EncounterGift3 : IEncounterable, IEncounterMatch, IMoveset,
private bool IsMatchGender(PKM pk, uint seed)
{
var expect = OriginalTrainerGender is GiftGender3.RandD3_0 or GiftGender3.RandD3_1
? GetGenderBit0(LCRNG.Next6(seed) >> 16)
: GetGender(LCRNG.Next4(seed)); // another implicit advance inside the method
var expect = OriginalTrainerGender switch
{
GiftGender3.RandD3_0 or GiftGender3.RandD3_1 => GetGenderBit0(LCRNG.Next6(seed) >> 16),
_ => GetGender(LCRNG.Next4(seed)),
}; // another implicit advance inside the method
return pk.OriginalTrainerGender == expect;
}
}

View file

@ -83,9 +83,8 @@ public sealed class EncounterGift3JPN(ushort Species, Distribution3JPN Distribut
if (!criteria.IsGenderSatisfied(gender))
continue;
PIDGenerator.SetIVsFromSeedSequentialLCRNG(ref seed, pk);
pk.PID = pid;
pk.IV32 = PIDGenerator.SetIVsFromSeedSequentialLCRNG(ref seed);
pk.RefreshAbility((int)(pid & 1));
pk.OriginalTrainerGender = (byte)GetGender(LCRNG.Next16(ref seed));
return;
@ -101,6 +100,9 @@ public sealed class EncounterGift3JPN(ushort Species, Distribution3JPN Distribut
if (Version != 0 && !Version.Contains(pk.Version))
return false;
if (pk.IsEgg)
return false;
if (pk.SID16 != 0)
return false;
if (!IsValidTrainerID(pk.TID16))

View file

@ -84,9 +84,8 @@ public sealed class EncounterGift3NY(ushort Species, Distribution3NY Distributio
if (!criteria.IsGenderSatisfied(gender))
continue;
PIDGenerator.SetIVsFromSeedSequentialLCRNG(ref seed, pk);
pk.PID = pid;
pk.IV32 = PIDGenerator.SetIVsFromSeedSequentialLCRNG(ref seed);
pk.RefreshAbility((int)(pid & 1));
pk.OriginalTrainerGender = (byte)GetGender(LCRNG.Next16(ref seed));
return;
@ -100,6 +99,9 @@ public sealed class EncounterGift3NY(ushort Species, Distribution3NY Distributio
if (Version != 0 && !Version.Contains(pk.Version))
return false;
if (pk.IsEgg)
return false;
if (pk.SID16 != 0)
return false;
if (!Distribution.IsValidTrainerID(pk.TID16))

View file

@ -121,8 +121,6 @@ public static class CommonEvent3Checker
{
if (observed is not (BACD or BACD_A or BACD_EA))
return false;
if (value.OriginSeed > ushort.MaxValue)
return false;
value = value.AsMutated(BACD_U);
return true;
}
@ -139,6 +137,16 @@ public static class CommonEvent3Checker
return true;
}
/// <remarks>Regular Antishiny without seed restriction constraint.</remarks>
/// <inheritdoc cref="IsRestrictedTable2"/>
public static bool IsUnrestrictedAntiX(ref PIDIV value, PIDType observed)
{
if (observed is not (BACD_AX))
return false;
value = value.AsMutated(BACD_AX);
return true;
}
/// <remarks>Berry Fix Zigzagoon seed restriction constraint.</remarks>
/// <inheritdoc cref="IsRestrictedTable2"/>
public static bool IsBerryFixShiny(ref PIDIV value, PIDType observed)

View file

@ -8,7 +8,7 @@ namespace PKHeX.Core;
/// </summary>
public static class PIDGenerator
{
private static void SetValuesFromSeedLCRNG(PKM pk, PIDType type, uint seed)
private static uint SetValuesFromSeedLCRNG(PKM pk, PIDType type, uint seed)
{
var A = LCRNG.Next(seed);
var B = LCRNG.Next(A);
@ -41,14 +41,16 @@ public static class PIDGenerator
IVs[2..].Clear();
}
pk.SetIVs(IVs);
return D;
}
private static void SetValuesFromSeedBACD(PKM pk, PIDType type, uint seed)
private static uint SetValuesFromSeedBACD(PKM pk, PIDType type, uint seed)
{
uint idxor = pk.TID16 ^ (uint)pk.SID16;
pk.PID = GetPIDFromSeedBACD(ref seed, type, idxor);
SetIVsFromSeedSequentialLCRNG(ref seed, pk);
pk.RefreshAbility((int)(pk.PID & 1));
return seed;
}
private static uint GetPIDFromSeedBACD(ref uint seed, PIDType type, uint idXor) => type switch
@ -59,6 +61,13 @@ public static class PIDGenerator
_ => CommonEvent3.GetRegularAntishiny(ref seed, idXor),
};
public static uint SetIVsFromSeedSequentialLCRNG(ref uint seed)
{
var c16 = LCRNG.Next16(ref seed) & 0x7FFF;
var d16 = LCRNG.Next16(ref seed) & 0x7FFF;
return (d16 << 15) | c16;
}
public static void SetIVsFromSeedSequentialLCRNG(ref uint seed, PKM pk)
{
var c16 = LCRNG.Next16(ref seed);
@ -68,7 +77,7 @@ public static class PIDGenerator
pk.SetIVs(IVs);
}
private static void SetValuesFromSeedXDRNG(PKM pk, uint seed)
private static uint SetValuesFromSeedXDRNG(PKM pk, uint seed)
{
var species = pk.Species;
switch (species)
@ -106,17 +115,19 @@ public static class PIDGenerator
var e16 = XDRNG.Next16(ref seed); // PID
pk.PID = (d16 << 16) | e16;
}
return seed;
}
public static void SetValuesFromSeedXDRNG_EReader(PKM pk, uint seed)
public static uint SetValuesFromSeedXDRNG_EReader(PKM pk, uint seed)
{
var D = XDRNG.Prev3(seed); // PID
var E = XDRNG.Next(D); // PID
pk.PID = (D & 0xFFFF0000) | (E >> 16);
return seed;
}
private static void SetValuesFromSeedChannel(PKM pk, uint seed)
public static uint SetValuesFromSeedChannel(PKM pk, uint seed)
{
const ushort TID16 = 40122;
var sid = XDRNG.Next16(ref seed);
@ -134,6 +145,7 @@ public static class PIDGenerator
Span<int> ivs = stackalloc int[6];
XDRNG.GetSequentialIVsInt32(seed, ivs);
pk.SetIVs(ivs);
return seed;
}
public static void SetValuesFromSeed(PKM pk, PIDType type, uint seed)
@ -142,7 +154,7 @@ public static class PIDGenerator
method(pk, seed);
}
private static Action<PKM, uint> GetGeneratorMethod(PIDType t)
private static Func<PKM, uint, uint> GetGeneratorMethod(PIDType t)
{
switch (t)
{
@ -173,6 +185,7 @@ public static class PIDGenerator
{
var pid = pk.PID = PokewalkerRNG.GetPID(pk.TID16, pk.SID16, seed % 24, pk.Gender, pk.PersonalInfo.Gender);
pk.RefreshAbility((int)(pid & 1));
return seed;
};
// others: unimplemented
@ -183,20 +196,22 @@ public static class PIDGenerator
case G4MGAntiShiny:
break;
}
return (_, _) => { };
return (_, seed) => seed;
}
public static void SetRandomChainShinyPID(PKM pk, uint seed)
public static uint SetRandomChainShinyPID(PKM pk, uint seed)
{
pk.PID = ClassicEraRNG.GetChainShinyPID(ref seed, pk.ID32);
SetIVsFromSeedSequentialLCRNG(ref seed, pk);
return seed;
}
private static void SetRandomPokeSpotPID(PKM pk, uint seed)
private static uint SetRandomPokeSpotPID(PKM pk, uint seed)
{
var D = XDRNG.Next(seed); // PID
var E = XDRNG.Next(D); // PID
pk.PID = (D & 0xFFFF0000) | (E >> 16);
return E;
}
public static void SetRandomPokeSpotPID(PKM pk, Nature nature, byte gender, int ability, int slot)
@ -226,12 +241,13 @@ public static class PIDGenerator
return PID;
}
public static void SetValuesFromSeedMG5Shiny(PKM pk, uint seed)
public static uint SetValuesFromSeedMG5Shiny(PKM pk, uint seed)
{
var gv = seed >> 24;
var av = seed & 1; // arbitrary choice
pk.PID = GetMG5ShinyPID(gv, av, pk.TID16, pk.SID16);
SetRandomIVs(pk);
return seed; // meh
}
public static uint SetRandomWildPID4(PKM pk, Nature nature, int ability, byte gender, PIDType type)

View file

@ -24,9 +24,11 @@ public sealed class BallVerifier : Verifier
PK8 when enc.Version == GameVersion.PLA => (int)Poke,
// No replacement done.
_ => (int)None,
_ => NoBallReplace,
};
private const int NoBallReplace = (int)None;
private CheckResult VerifyBall(LegalityAnalysis data)
{
var info = data.Info;
@ -34,7 +36,7 @@ public sealed class BallVerifier : Verifier
var pk = data.Entity;
var ball = IsReplacedBall(enc, pk);
if (ball != 0)
if (ball != NoBallReplace)
return VerifyBallEquals(pk, ball);
// Capture / Inherit cases -- can be one of many balls
@ -118,7 +120,7 @@ public sealed class BallVerifier : Verifier
if (species is (int)Species.Spinda) // Can't transfer via HOME.
return VerifyBallEquals(ball, BallUseLegality.WildPokeBalls4_HGSS);
var result = BallContextHOME.Instance.CanBreedWithBall(species, enc.Form, ball, pk);
var result = BallContextHOME.Instance.CanBreedWithBall(species, enc.Form, ball);
return GetResult(result);
}
@ -128,7 +130,7 @@ public sealed class BallVerifier : Verifier
if (ball > Beast)
return GetInvalid(LBallUnavailable);
var result = BallContextHOME.Instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk);
var result = BallContextHOME.Instance.CanBreedWithBall(enc.Species, enc.Form, ball);
return GetResult(result);
}
@ -143,7 +145,7 @@ public sealed class BallVerifier : Verifier
if (species is >= (int)Species.Sprigatito and <= (int)Species.Quaquaval)
return VerifyBallEquals(ball, BallUseLegality.WildPokeballs8g_WithoutRaid);
var result = BallContextHOME.Instance.CanBreedWithBall(enc.Species, enc.Form, ball, pk);
var result = BallContextHOME.Instance.CanBreedWithBall(species, enc.Form, ball);
return GetResult(result);
}