From 1c4070b6a876a5eb1d22beccd044efb26e7a2b5c Mon Sep 17 00:00:00 2001 From: Kurt Date: Sun, 14 Dec 2025 20:01:07 -0600 Subject: [PATCH] Update hyperspace encounters, misc checks Adds pickle from all possible random encounter sets in hyperspace Updates some formarg checks for certain species Updates plus move checks for movesets that were revised by DLC Hyperspace encounters are in a separate array, with a different slot type Add note for Teensy/Humungo for wild encounters causing a fixed scale value rather than random. Should be noted that this is a first-stab at encounters, and things have not been tested sufficiently to ensure the level ranges/etc are actually good data. please don't use the encounters yet; this just gets it out to testers for finding more edge cases. --- .../Encounters/Data/Gen9/Encounters9a.cs | 3 +- .../Generator/Possible/EncounterPossible9a.cs | 7 +++ .../Generator/Search/EncounterEnumerator9a.cs | 5 ++ .../Templates/Gen9a/EncounterArea9a.cs | 14 +++-- .../Templates/Gen9a/EncounterSlot9a.cs | 27 ++++++-- .../Templates/Gen9a/EncounterStatic9a.cs | 19 +++++- .../Encounters/Templates/Gen9a/LumioseRNG.cs | 4 ++ .../Encounters/Templates/Gen9a/SlotType9a.cs | 11 ++++ .../EvolutionGroup/EvolutionGroupHOME.cs | 10 ++- .../Evolutions/Methods/EvolutionType.cs | 4 +- .../Verifiers/FormArgumentVerifier.cs | 10 ++- .../Legality/Verifiers/LegendsZAVerifier.cs | 58 +++++++++++++++++- .../PersonalInfo/Info/PersonalInfo9ZA.cs | 2 + .../wild/Gen9/encounter_hyperspace_za.pkl | Bin 0 -> 9164 bytes PKHeX.WinForms/Subforms/KChart.cs | 2 +- 15 files changed, 153 insertions(+), 23 deletions(-) create mode 100644 PKHeX.Core/Resources/legality/wild/Gen9/encounter_hyperspace_za.pkl diff --git a/PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs b/PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs index 4ef0b5f5a..1f68a0978 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Gen9/Encounters9a.cs @@ -5,7 +5,8 @@ namespace PKHeX.Core; internal static class Encounters9a { - internal static readonly EncounterArea9a[] Slots = EncounterArea9a.GetAreas(Get16("za", "za"u8)); + internal static readonly EncounterArea9a[] Slots = EncounterArea9a.GetAreas(Get16("za", "za"u8), SlotType9a.Standard); + internal static readonly EncounterArea9a[] Hyperspace = EncounterArea9a.GetAreas(Get16("hyperspace_za", "za"u8), SlotType9a.Hyperspace); internal static readonly EncounterGift9a[] Gifts = [ diff --git a/PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs b/PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs index 593f46b70..28728d0f1 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/Possible/EncounterPossible9a.cs @@ -33,6 +33,7 @@ private enum YieldState : byte SlotStart, Slot, + Hyperspace, SlotEnd, StaticCapture, @@ -91,10 +92,16 @@ public bool MoveNext() case YieldState.SlotStart: if (!Flags.HasFlag(EncounterTypeGroup.Slot)) goto case YieldState.End; + State = YieldState.Slot; goto case YieldState.Slot; case YieldState.Slot: if (TryGetNext(Encounters9a.Slots)) return true; + Index = 0; State = YieldState.Hyperspace; + goto case YieldState.Hyperspace; + case YieldState.Hyperspace: + if (TryGetNext(Encounters9a.Hyperspace)) + return true; goto case YieldState.SlotEnd; case YieldState.SlotEnd: goto case YieldState.End; diff --git a/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs b/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs index f75b116d0..31a6bf4e9 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/Search/EncounterEnumerator9a.cs @@ -38,6 +38,7 @@ private enum YieldState : byte SlotStart, Slot, + Hyperspace, SlotEnd, StaticCapture, @@ -95,6 +96,10 @@ public bool MoveNext() case YieldState.Slot: if (TryGetNext(Encounters9a.Slots)) return true; + Index = 0; State = YieldState.Hyperspace; goto case YieldState.Hyperspace; + case YieldState.Hyperspace: + if (TryGetNext(Encounters9a.Hyperspace)) + return true; Index = 0; goto case YieldState.SlotEnd; case YieldState.SlotEnd: if (!mustBeSlot) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs index 787711a91..fc77f1293 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterArea9a.cs @@ -8,24 +8,26 @@ namespace PKHeX.Core; /// public sealed record EncounterArea9a : IEncounterArea, IAreaLocation { + public const ushort LocationHyperspace = 273; + public EncounterSlot9a[] Slots { get; } - public readonly byte Location; + public readonly ushort Location; public readonly SlotType9a Type; public bool IsMatchLocation(ushort location) => Location == location; // no crossovers! - public static EncounterArea9a[] GetAreas(BinLinkerAccessor16 input) + public static EncounterArea9a[] GetAreas(BinLinkerAccessor16 input, SlotType9a type) { var result = new EncounterArea9a[input.Length]; for (int i = 0; i < result.Length; i++) - result[i] = new EncounterArea9a(input[i]); + result[i] = new EncounterArea9a(input[i], type); return result; } - private EncounterArea9a(ReadOnlySpan areaData) + private EncounterArea9a(ReadOnlySpan areaData, SlotType9a type) { - Location = areaData[0]; // 235 max, will overflow in DLC, probably. - Type = SlotType9a.Standard; + Location = ReadUInt16LittleEndian(areaData); + Type = type; // 2..3 reserved Slots = ReadSlots(areaData[4..]); } diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs index b2420f95b..12becdb69 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterSlot9a.cs @@ -10,6 +10,9 @@ public sealed record EncounterSlot9a(EncounterArea9a Parent, ushort Species, byt { public byte Generation => 9; private const GameVersion Version = GameVersion.ZA; + + private bool IsHyperspace => Location == EncounterArea9a.LocationHyperspace; + GameVersion IVersion.Version => GameVersion.ZA; public EntityContext Context => EntityContext.Gen9a; public bool IsEgg => false; @@ -65,7 +68,8 @@ public PA9 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) private void SetPINGA(PA9 pk, EncounterCriteria criteria, PersonalInfo9ZA pi) { - var param = GetParams(pi, criteria.Shiny.IsShiny()); + bool shinyPlease = criteria.Shiny.IsShiny(); + var param = GetParams(pi, shinyPlease, shinyPlease); ulong init = Util.Rand.Rand64(); var success = this.TryApply64(pk, init, param, criteria); if (!success && !this.TryApply64(pk, init, param, criteria.WithoutIVs())) @@ -117,6 +121,9 @@ public EncounterMatchRating GetMatchRating(PKM pk) if (Shiny is Shiny.Never && pk.IsShiny) // Some encounters are shiny locked until a sub-quest is completed. return EncounterMatchRating.DeferredErrors; + if (IsFormArgMismatch(pk)) + return EncounterMatchRating.DeferredErrors; + var pidiv = TryGetSeed(pk, out _); if (pidiv is SeedCorrelationResult.Invalid) return EncounterMatchRating.DeferredErrors; @@ -126,17 +133,24 @@ public EncounterMatchRating GetMatchRating(PKM pk) return EncounterMatchRating.Match; } + private bool IsFormArgMismatch(PKM pk) => pk.Species switch + { + (int)Core.Species.Overqwil when Species is not (int)Core.Species.Overqwil && pk is IFormArgument { FormArgument: 0 } and IHomeTrack { HasTracker: false } => true, + _ => false, + }; + #endregion public SeedCorrelationResult TryGetSeed(PKM pk, out ulong seed) { - var param = GetParams(PersonalTable.ZA[Species, Form], false); + var param = GetParams(PersonalTable.ZA[Species, Form], false, false); if (param.TryGetSeed(pk, out seed)) return SeedCorrelationResult.Success; if (pk.IsShiny && !LumioseSolver.SearchShiny1 || !LumioseSolver.SearchShinyN) return SeedCorrelationResult.Ignore; - param = param with { RollCount = 1 + ShinyCharm }; + var rollCount = (byte)(1 + ShinyCharm + (IsHyperspace ? ShinyHyperspace : 0)); + param = param with { RollCount = rollCount }; if (param.TryGetSeed(pk, out seed)) return SeedCorrelationResult.Success; return SeedCorrelationResult.Invalid; @@ -145,13 +159,14 @@ public SeedCorrelationResult TryGetSeed(PKM pk, out ulong seed) public LumioseCorrelation Correlation => IsAlpha ? LumioseCorrelation.PreApplyIVs : LumioseCorrelation.Normal; private const byte ShinyCharm = 3; + private const byte ShinyHyperspace = 3; - public GenerateParam9a GetParams(PersonalInfo9ZA pi) => GetParams(pi, shinyCharm: false); + public GenerateParam9a GetParams(PersonalInfo9ZA pi) => GetParams(pi, shinyCharm: false, activeShinyPower: false); - public GenerateParam9a GetParams(PersonalInfo9ZA pi, bool shinyCharm) + public GenerateParam9a GetParams(PersonalInfo9ZA pi, bool shinyCharm, bool activeShinyPower) { // Give the +3 for Shiny Charm so that the generator search is more likely to succeed. - var rollCount = (byte)(1 + (shinyCharm ? ShinyCharm : 0)); + var rollCount = (byte)(1 + (shinyCharm ? ShinyCharm : 0) + (IsHyperspace && activeShinyPower ? ShinyHyperspace : 0)); var scaleValue = IsAlpha ? (byte)255 : (byte)0; var scaleType = IsAlpha ? SizeType9.VALUE : SizeType9.RANDOM; var gender = Gender switch diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs index 656a61831..f2ba88b0e 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/EncounterStatic9a.cs @@ -35,6 +35,8 @@ public sealed record EncounterStatic9a(ushort Species, byte Form, byte Level, by ushort ILocation.Location => Location; + private bool HyperspaceShinyPossible => Shiny != Shiny.Never && Location == EncounterArea9a.LocationHyperspace; + public string Name => "Static Encounter"; public string LongName => Name; @@ -166,8 +168,10 @@ private EncounterMatchRating IsMatchDeferred(PKM pk) return EncounterMatchRating.DeferredErrors; var pidiv = TryGetSeed(pk, out _); - if (pidiv is not SeedCorrelationResult.Success) + if (pidiv is SeedCorrelationResult.Invalid) return EncounterMatchRating.DeferredErrors; + if (pidiv is SeedCorrelationResult.Ignore) + return EncounterMatchRating.Deferred; // might be a better match with another template return EncounterMatchRating.Match; } @@ -191,7 +195,16 @@ private bool IsMatchPartial(PKM pk) public SeedCorrelationResult TryGetSeed(PKM pk, out ulong seed) { - if (GetParams(PersonalTable.ZA[Species, Form]).TryGetSeed(pk, out seed)) + var param = GetParams(PersonalTable.ZA[Species, Form]); + if (param.TryGetSeed(pk, out seed)) + return SeedCorrelationResult.Success; + if (!HyperspaceShinyPossible) + return SeedCorrelationResult.Invalid; + if (pk.IsShiny && !LumioseSolver.SearchShiny1 || !LumioseSolver.SearchShinyN) + return SeedCorrelationResult.Ignore; + + param = param with { RollCount = 7 }; + if (param.TryGetSeed(pk, out seed)) return SeedCorrelationResult.Success; return SeedCorrelationResult.Invalid; } @@ -210,7 +223,7 @@ public LumioseCorrelation Correlation public GenerateParam9a GetParams(PersonalInfo9ZA pi) { - const byte rollCount = 1; + byte rollCount = HyperspaceShinyPossible ? (byte)7 : (byte)1; var gender = Gender switch { 0 => PersonalInfo.RatioMagicMale, diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs index 92ecff5dc..26e67b0cb 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/LumioseRNG.cs @@ -112,6 +112,8 @@ public static bool GenerateData(PA9 pk, in GenerateParam9a enc, in EncounterCrit return false; pk.Nature = pk.StatNature = nature; + // If Hyperspace, the player can have an active Teensy/Humungo boost. The scale is pre-determined outside of the seed=>pa9, consider it not correlated or traceable. + // When calling the method to verify the entity, pass SizeType9.VALUE instead. pk.Scale = enc.SizeType.GetSizeValue(enc.Scale, ref rand); return true; } @@ -268,6 +270,8 @@ private static bool IsMatchIVsAndFollowing(PKM pk, in GenerateParam9a enc, Xoros return false; // Scale + // If Hyperspace, the player can have an active Teensy/Humungo boost. The scale is pre-determined outside of the seed=>pa9, consider it not correlated or traceable. + // When calling the method to verify the entity, pass SizeType9.VALUE instead. { var value = enc.SizeType.GetSizeValue(enc.Scale, ref rand); if (pk is IScaledSize3 s) diff --git a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs index 80bd90426..12786b0f3 100644 --- a/PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs +++ b/PKHeX.Core/Legality/Encounters/Templates/Gen9a/SlotType9a.cs @@ -1,6 +1,17 @@ namespace PKHeX.Core; +/// +/// Encounter method for wild encounters in Legends: Z-A +/// public enum SlotType9a : byte { + /// + /// Overworld Lumiose + /// Standard = 0, + + /// + /// Hyperspace Lumiose + /// + Hyperspace = 1, } diff --git a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs index 7a66e1662..ad5c34290 100644 --- a/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs +++ b/PKHeX.Core/Legality/Evolutions/EvolutionGroup/EvolutionGroupHOME.cs @@ -226,7 +226,15 @@ private int EvolveSingle(Span result, PKM pk, in EvolutionOrigin en PA8 => LA, PB8 => BDSP, PK9 => SV, - _ => throw new ArgumentOutOfRangeException(nameof(pk), pk, null), + _ => pk.Version switch // transferred to another game (Z-A) + { + GameVersion.PLA => LA, + GameVersion.SW or GameVersion.SH => SWSH, + GameVersion.BD or GameVersion.SP => BDSP, + GameVersion.SL or GameVersion.VL => SV, + _ => throw new ArgumentOutOfRangeException(nameof(pk), pk, null), + }, + }; } diff --git a/PKHeX.Core/Legality/Evolutions/Methods/EvolutionType.cs b/PKHeX.Core/Legality/Evolutions/Methods/EvolutionType.cs index fd8f9c65a..d0d0c5f24 100644 --- a/PKHeX.Core/Legality/Evolutions/Methods/EvolutionType.cs +++ b/PKHeX.Core/Legality/Evolutions/Methods/EvolutionType.cs @@ -74,7 +74,7 @@ public enum EvolutionType : byte LevelUpRecoilDamageFemale = 60, // Basculegion-1 Hisui = 61, - UseMovePlusStyle = 62, + UseMoveBarbBarrage = 62, // Qwilfish (Z-A) // These are fake IDs as PLA indexes clashed with mainline. UseItemFullMoon = 90, // Ursaluna @@ -173,7 +173,7 @@ public static class EvolutionTypeExtensions UseItemFullMoon => false, UseMoveAgileStyle => false, UseMoveStrongStyle => false, - UseMovePlusStyle => false, + UseMoveBarbBarrage => false, _ => throw new ArgumentOutOfRangeException(nameof(type), type, null), }; } diff --git a/PKHeX.Core/Legality/Verifiers/FormArgumentVerifier.cs b/PKHeX.Core/Legality/Verifiers/FormArgumentVerifier.cs index 5e433445f..183d2b70a 100644 --- a/PKHeX.Core/Legality/Verifiers/FormArgumentVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/FormArgumentVerifier.cs @@ -91,12 +91,21 @@ private CheckResult VerifyFormArgument(LegalityAnalysis data, IFormArgument f) }, Gimmighoul => arg switch { + // Z-A evolutions do not set form argument to Gimmighoul. + 0 when data.Info.EvoChainsAllGens.HasVisitedZA => GetValid(FormArgumentValid), + // When leveled up, the game copies the save file's current coin count to the arg (clamped to <=999). If >=999, evolution is triggered. // Without being leveled up at least once, it cannot have a form arg value. >= 999 => GetInvalid(FormArgumentLEQ_0, 999), 0 => GetValid(FormArgumentValid), + + // S/V sets form argument to match coin count. + _ when !data.Info.EvoChainsAllGens.HasVisitedGen9 => GetInvalid(FormArgumentInvalid), _ => pk.CurrentLevel != pk.MetLevel ? GetValid(FormArgumentValid) : GetInvalid(FormArgumentNotAllowed), }, + Gholdengo when !data.Info.EvoChainsAllGens.HasVisitedGen9 => arg == 0 ? GetValid(FormArgumentValid) : GetInvalid(FormArgumentInvalid), + Gholdengo => VerifyFormArgumentRange(enc.Species, Gholdengo, arg, 999, 999), + Runerigus => VerifyFormArgumentRange(enc.Species, Runerigus, arg, 49, 9999), Alcremie => VerifyFormArgumentRange(enc.Species, Alcremie, arg, 0, (ushort)AlcremieDecoration.Ribbon), Wyrdeer when enc.Species != (int)Wyrdeer && pk.CurrentLevel < 31 => GetInvalid(EvoInvalid), @@ -104,7 +113,6 @@ private CheckResult VerifyFormArgument(LegalityAnalysis data, IFormArgument f) Basculegion => VerifyFormArgumentRange(enc.Species, Basculegion, arg, 294, 9999), Annihilape => VerifyFormArgumentRange(enc.Species, Annihilape, arg, 20, 9999), Kingambit => VerifyFormArgumentRange(enc.Species, Kingambit, arg, 3, 9999), - Gholdengo => VerifyFormArgumentRange(enc.Species, Gholdengo, arg, 999, 999), Koraidon or Miraidon => enc switch { // Starter Legend has '1' when present in party, to differentiate. diff --git a/PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs b/PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs index 0d430ecaf..9a4a44a9a 100644 --- a/PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/LegendsZAVerifier.cs @@ -1,4 +1,7 @@ using System; +using static PKHeX.Core.Ball; +using static PKHeX.Core.Move; +using static PKHeX.Core.Species; using static PKHeX.Core.LegalityCheckResultCode; namespace PKHeX.Core; @@ -169,7 +172,7 @@ private void CheckFlagsPlus(LegalityAnalysis la, PA9 pk) la.AddLine(msg); } - private void CheckPlusMoveFlags(LegalityAnalysis la, T pk, IPermitPlus permit, Learnset plus, byte currentLevel) where T : IPlusRecord + private void CheckPlusMoveFlags(LegalityAnalysis la, T pk, IPermitPlus permit, Learnset plus, byte currentLevel) where T : PKM, IPlusRecord { var levels = plus.GetAllLevels(); var moves = plus.GetAllMoves(); @@ -193,6 +196,9 @@ private void CheckFlagsPlus(LegalityAnalysis la, PA9 pk) if (IsTradeEvoSkip(la.Info.EvoChainsAllGens.Gen9a, move)) continue; + if (WasPossiblyObtainedBeforeDLC(pk, la.EncounterMatch) && IsPermittedUnsetPlusMove((Species)pk.Species, (Move)move)) + continue; + la.AddLine(GetInvalid(PlusMoveSufficientLevelMissing_0, move, level)); } } @@ -229,7 +235,7 @@ private static bool IsTradeEvoSkip(ReadOnlySpan evos, ushort move) private const ushort MultipleInvalidPlusMoves = ushort.MaxValue; private static ushort GetInvalidPlusMove(T pk, int maxIndex, IPermitPlus permit, ReadOnlySpan evos) - where T : IPlusRecord + where T : PKM, IPlusRecord { ushort invalid = 0; for (int i = 0; i < maxIndex; i++) @@ -272,4 +278,52 @@ private static ushort GetInvalidPlusMove(T pk, int maxIndex, IPermitPlus perm } return false; } + + private static bool WasPossiblyObtainedBeforeDLC(PKM pk, IEncounterTemplate enc) + { + if (pk.Version is not GameVersion.ZA) + return false; // HOME transfer (after DLC). + + if (pk.Ball is (int)Safari or (int)Beast) + return false; // Ball not introduced until DLC. + if (enc.Location is (>= EncounterArea9a.LocationHyperspace and <= 3000)) + return false; // Hyperspace encounter location + + var dex = PersonalTable.ZA[enc.Species, enc.Form]; + if (!dex.IsLumioseNative) + return false; // Additional wild encounter in the overworld not originally present in base game. + if (enc is EncounterStatic9a { Species: (int)Sandile or (int)Krokorok }) + return false; // Additional static encounter in the overworld not originally present in base game. + + return true; + } + + /// + /// DLC added new moves to learnsets. Pokémon that could not have been obtained before DLC can lack these automatic plus moves. + /// + /// if the Plus move flag is not required to be set. + /// + /// Pokémon can always be awarded the Plus move flag via the Seed of Mastery manually. The game does not retroactively set the Plus move flag for existing Pokémon. + /// + private static bool IsPermittedUnsetPlusMove(Species species, Move move) => species switch + { + // Relearn moves added in DLC: + Pichu or Pikachu or Raichu when move is DrainingKiss => true, + Onix when move is RockBlast => true, + Absol when move is Snarl or PhantomForce => true, + Roserade or Whirlipede or Scolipede when move is MortalSpin => true, + Abomasnow when move is IceHammer => true, + Gallade when move is SacredSword => true, + Espurr or Meowstic when move is Teleport => true, + Meowstic when move is Moonblast => true, + Honedge when move is SacredSword => true, + Malamar when move is Octolock => true, + Heliolisk when move is ShedTail => true, + Aurorus when move is IceHammer => true, + + // Level-up moves added in DLC: + Absol when move is ConfuseRay or ShadowSneak => true, + + _ => false, + }; } diff --git a/PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs b/PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs index 8e4eb85c9..616765cf2 100644 --- a/PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs +++ b/PKHeX.Core/PersonalInfo/Info/PersonalInfo9ZA.cs @@ -64,6 +64,8 @@ public sealed class PersonalInfo9ZA(Memory Raw) : PersonalInfo, IPersonalA /// Checks if the entry shows up in any of the built-in Pokédex. /// public bool IsInDex => DexIndex != 0; + public bool IsLumioseNative => DexIndex is (not 0) and <= 232; + public bool IsHyperspaceNative => DexIndex > 232; public override int AbilityCount => 3; public override int GetIndexOfAbility(int abilityID) => abilityID == Ability1 ? 0 : abilityID == Ability2 ? 1 : abilityID == AbilityH ? 2 : -1; diff --git a/PKHeX.Core/Resources/legality/wild/Gen9/encounter_hyperspace_za.pkl b/PKHeX.Core/Resources/legality/wild/Gen9/encounter_hyperspace_za.pkl new file mode 100644 index 0000000000000000000000000000000000000000..95abb8c64230deb8b610788d945e80d828d82d35 GIT binary patch literal 9164 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 f#n+<03+V5Jzr>xVG`DUm<*#X bs.IsInDex, PersonalInfo8LA bs => bs.IsPresentInGame, PersonalInfo9SV sv => sv.IsInDex, - PersonalInfo9ZA za => za is { IsInDex: true, DexIndex: <= 232 }, + PersonalInfo9ZA za => za is { IsLumioseNative: true }, _ => true, };