From 93c7b765c3f37d6d482ccfa598037efdd2e4e6fc Mon Sep 17 00:00:00 2001 From: Kurt Date: Wed, 8 Jan 2025 00:36:02 -0600 Subject: [PATCH] Minor tweaks Handle ARNG egg manaphy for gen4 trainer, force hatch add xmldoc/comments expand expressions for version/language selection, disallow languages correctly --- PKHeX.Core/Game/GameUtil.cs | 3 ++ PKHeX.Core/MysteryGifts/PGT.cs | 65 ++++++++++++++++++++++++++-------- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/PKHeX.Core/Game/GameUtil.cs b/PKHeX.Core/Game/GameUtil.cs index c824a3eb3..c3a4ec18c 100644 --- a/PKHeX.Core/Game/GameUtil.cs +++ b/PKHeX.Core/Game/GameUtil.cs @@ -172,6 +172,9 @@ public static bool Contains(this GameVersion g1, GameVersion g2) return g1.ContainsFromLumped(g2); } + /// + /// Checks if the version is the lump of the requested saved . + /// public static bool ContainsFromLumped(this GameVersion lump, GameVersion version) => lump switch { RB => version is RD or BU or GN, diff --git a/PKHeX.Core/MysteryGifts/PGT.cs b/PKHeX.Core/MysteryGifts/PGT.cs index 8f117dba6..a389b43c0 100644 --- a/PKHeX.Core/MysteryGifts/PGT.cs +++ b/PKHeX.Core/MysteryGifts/PGT.cs @@ -95,7 +95,6 @@ private void EncryptPK() public Accessory4 Accessory { get => (Accessory4)ItemSubID; set => ItemSubID = (int)value; } public Backdrop4 Backdrop { get => (Backdrop4)ItemSubID; set => ItemSubID = (int)value; } - public bool IsHatched => GiftType is Pokémon or PokémonMovie; public override bool IsEgg { get => GiftType == PokémonEgg || IsManaphyEgg; set { if (value) { GiftType = PokémonEgg; PK.IsEgg = true; } } } public bool IsManaphyEgg { get => GiftType == ManaphyEgg; set { if (value) GiftType = ManaphyEgg; } } public override bool IsItem { get => GiftType == Item; set { if (value) GiftType = Item; } } @@ -125,19 +124,27 @@ public override PK4 ConvertToPKM(ITrainerInfo tr, EncounterCriteria criteria) if (!IsEntity) throw new ArgumentException(nameof(IsEntity)); - // template is already filled out, only minor mutations required - PK4 pk4 = new((byte[])PK.Data.Clone()) { Sanity = 0 }; - if (!IsHatched && Detail == 0) + // Template is already filled out, only minor mutations required + byte[] clone = [.. PK.Data]; // disassociate from gift template + PK4 pk4 = new(clone) { Sanity = 0 }; // clear for the bad WORLD08 Lucario (0x0100) + var pi = pk4.PersonalInfo; + + if (IsEgg) { + // Only hits here for the Manaphy gift. No gift eggs (type 2) were officially distributed. pk4.OriginalTrainerName = tr.OT; pk4.TID16 = tr.TID16; pk4.SID16 = tr.SID16; pk4.OriginalTrainerGender = tr.Gender; - pk4.Language = tr.Language; - } + // Set Language and Version later for Manaphy, as we need to sanity check the input Trainer info. + // No need to worry about regular egg gifts, because again, none exist. - var pi = pk4.PersonalInfo; - pk4.OriginalTrainerFriendship = pk4.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + pk4.OriginalTrainerFriendship = pi.HatchCycles; + } + else + { + pk4.OriginalTrainerFriendship = pi.BaseFriendship; + } if (IsManaphyEgg) { @@ -226,7 +233,7 @@ private static bool TrySetManaphyFromIVs(PK4 pk4, EncounterCriteria criteria, IT if (criteria.Shiny.IsShiny() != shiny) continue; - if (shiny || arng) + if (shiny || arng) // set even for ARNG to ensure was shiny for the original recipient SetAsTradedManaphy(pk4, shiny); pk4.PID = pid; pk4.IV32 |= iv2 << 15 | iv1; @@ -247,6 +254,8 @@ private static void SetAsTradedManaphy(PK4 pk4, bool shiny) return; } + // Force hatch, we want to retain the trainer IDs from the request rather than leave the egg unhatched. + pk4.IsEgg = false; pk4.IsNicknamed = false; pk4.Nickname = SpeciesName.GetSpeciesNameGeneration((ushort)Core.Species.Manaphy, pk4.Language, 4); } @@ -265,6 +274,7 @@ private void SetMetData(PK4 pk4, ITrainerInfo trainer, EncounterCriteria criteri } else { + // Never reaches here because no egg PGTs were distributed besides Manaphy. if (criteria.Shiny.IsShiny()) pk4.EggLocation = Locations.LinkTrade4; else @@ -289,8 +299,16 @@ private static void SetDefaultManaphyEggDetails(PK4 pk4, ITrainerInfo trainer) pk4.Ability = (int)Core.Ability.Hydration; pk4.FatefulEncounter = true; pk4.Ball = (int)Core.Ball.Poke; - pk4.Version = trainer.Version.IsValidSavedVersion() && GameVersion.Gen4.Contains(trainer.Version) ? trainer.Version : GameVersion.D; - var lang = trainer.Language is < (int)LanguageID.Korean and not (int)LanguageID.Korean ? trainer.Language : (int)LanguageID.English; + + // Manaphy is the only PGT gift egg! (and the only gift that needs a version to be set) + var version = trainer.Version; + if (!version.IsValidSavedVersion() || !GameVersion.Gen4.ContainsFromLumped(version)) + version = GameVersion.D; + pk4.Version = version; + + var lang = trainer.Language; + if ((uint)lang is >= (uint)LanguageID.Korean or (0 or (int)LanguageID.UNUSED_6)) + lang = (int)LanguageID.English; // Don't allow Korean or unused languages pk4.Language = lang; pk4.IsEgg = true; @@ -378,22 +396,39 @@ private void SetUnhatchedEggDetails(PK4 pk4) pk4.EggMetDate = EncounterDate.GetDateNDS(); } + /// + /// Rough check to see if the matches the expected Ranger Manaphy details. + /// public static bool IsRangerManaphy(PKM pk) { - if (pk.Language >= (int)LanguageID.Korean) // never korean + if (pk.Species is not (ushort)Core.Species.Manaphy) + return false; + + // Never Korean or future language values; others (0, 6) will get flagged by other checks. + if (pk.Language >= (int)LanguageID.Korean) return false; var egg = pk.EggLocation; - if (!pk.IsEgg) // Link Trade Egg or Ranger + if (!pk.IsEgg) // Link Trade Egg or Ranger must be present in the Egg Met field. Met location is hatch location or Transfer (Gen5+). return egg is Locations.LinkTrade4 or Locations.Ranger4; + + if (pk.Format != 4) + return false; // Can't be an Egg if it must be transferred. + + // Logic below only applies to Eggs. + // While an egg, Egg Location must still be Ranger. + // If traded while an egg, the Met Location will be updated from 0 => Link Trade. + // When hatched, the Met Location will move to Egg Location, if non-zero (aka, Traded). if (egg != Locations.Ranger4) return false; - var met = pk.MetLocation; return met is Locations.LinkTrade4 or 0; } - // Nothing is stored as a PGT besides Ranger Manaphy. Nothing should trigger these. + /// + /// Nothing should call these methods. Should be checked via the static method prior to yielding the match. + /// + /// objects will instead call their respective methods. public override bool IsMatchExact(PKM pk, EvoCriteria evo) => false; protected override bool IsMatchDeferred(PKM pk) => false; protected override bool IsMatchPartial(PKM pk) => false;