diff --git a/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs b/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs index 7d4567de7..6faaa3a52 100644 --- a/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs +++ b/PKHeX.Core/Legality/Encounters/Data/Encounters5.cs @@ -633,21 +633,21 @@ private static void MarkG5Slots(ref EncounterArea[] Areas) new EncounterStatic { Species = 644, Level = 70, Location = 039, Shiny = Shiny.Never, Version = GameVersion.B2, }, // Zekrom @ Dragonspiral Tower new EncounterStatic { Species = 646, Level = 70, Location = 061, Form = 0}, // Kyurem @ Giant Chasm //N's Pokemon - new EncounterStaticPID { Species = 509, Level = 07, Location = 15, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Timid }, // Purloin @ Route 2 - new EncounterStaticPID { Species = 519, Level = 13, Location = 33, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Sassy }, // Pidove @ Pinwheel Forest - new EncounterStaticPID { Species = 532, Level = 13, Location = 33, NSparkle = true, Ability = 1, PID = 0xFF00003F, Nature = Nature.Rash }, // Timburr @ Pinwheel Forest - new EncounterStaticPID { Species = 535, Level = 13, Location = 33, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Modest }, // Tympole @ Pinwheel Forest - new EncounterStaticPID { Species = 527, Level = 55, Location = 53, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Timid }, // Woobat @ Wellspring Cave - new EncounterStaticPID { Species = 551, Level = 22, Location = 34, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Docile }, // Sandile @ Desert Resort - new EncounterStaticPID { Species = 554, Level = 22, Location = 34, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Naive }, // Darumaka @ Desert Resort - new EncounterStaticPID { Species = 555, Level = 35, Location = 34, NSparkle = true, Ability = 4, PID = 0xFF00007F, Nature = Nature.Calm }, // Darmanitan @ Desert Resort - new EncounterStaticPID { Species = 559, Level = 22, Location = 34, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Lax }, // Scraggy @ Desert Resort - new EncounterStaticPID { Species = 561, Level = 22, Location = 34, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Gentle }, // Sigilyph @ Desert Resort - new EncounterStaticPID { Species = 525, Level = 28, Location = 37, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Naive }, // Boldore @ Chargestone Cave - new EncounterStaticPID { Species = 595, Level = 28, Location = 37, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Docile }, // Joltik @ Chargestone Cave - new EncounterStaticPID { Species = 597, Level = 28, Location = 37, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Bashful }, // Ferroseed @ Chargestone Cave - new EncounterStaticPID { Species = 599, Level = 28, Location = 37, NSparkle = true, Ability = 1, PID = 0xFF000000, Nature = Nature.Rash }, // Klink @ Chargestone Cave - new EncounterStaticPID { Species = 570, Level = 25, Location = 10, NSparkle = true, Ability = 1, PID = 0xFF00001F, Nature = Nature.Hasty, Gift = true} // N's Zorua @ Driftveil City + new EncounterStaticN { Species = 509, Level = 07, Location = 15, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Timid }, // Purloin @ Route 2 + new EncounterStaticN { Species = 519, Level = 13, Location = 33, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Sassy }, // Pidove @ Pinwheel Forest + new EncounterStaticN { Species = 532, Level = 13, Location = 33, NSparkle = true, Ability = 1, PID = 0xFF00003F, Nature = Nature.Rash }, // Timburr @ Pinwheel Forest + new EncounterStaticN { Species = 535, Level = 13, Location = 33, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Modest }, // Tympole @ Pinwheel Forest + new EncounterStaticN { Species = 527, Level = 55, Location = 53, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Timid }, // Woobat @ Wellspring Cave + new EncounterStaticN { Species = 551, Level = 22, Location = 34, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Docile }, // Sandile @ Desert Resort + new EncounterStaticN { Species = 554, Level = 22, Location = 34, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Naive }, // Darumaka @ Desert Resort + new EncounterStaticN { Species = 555, Level = 35, Location = 34, NSparkle = true, Ability = 4, PID = 0xFF00007F, Nature = Nature.Calm }, // Darmanitan @ Desert Resort + new EncounterStaticN { Species = 559, Level = 22, Location = 34, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Lax }, // Scraggy @ Desert Resort + new EncounterStaticN { Species = 561, Level = 22, Location = 34, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Gentle }, // Sigilyph @ Desert Resort + new EncounterStaticN { Species = 525, Level = 28, Location = 37, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Naive }, // Boldore @ Chargestone Cave + new EncounterStaticN { Species = 595, Level = 28, Location = 37, NSparkle = true, Ability = 2, PID = 0xFF01007F, Nature = Nature.Docile }, // Joltik @ Chargestone Cave + new EncounterStaticN { Species = 597, Level = 28, Location = 37, NSparkle = true, Ability = 1, PID = 0xFF00007F, Nature = Nature.Bashful }, // Ferroseed @ Chargestone Cave + new EncounterStaticN { Species = 599, Level = 28, Location = 37, NSparkle = true, Ability = 1, PID = 0xFF000000, Nature = Nature.Rash }, // Klink @ Chargestone Cave + new EncounterStaticN { Species = 570, Level = 25, Location = 10, NSparkle = true, Ability = 1, PID = 0xFF00001F, Nature = Nature.Hasty, Gift = true} // N's Zorua @ Driftveil City }; private static readonly EncounterStatic[] Encounter_B2W2 = Encounter_DreamRadar.SelectMany(e => e.DreamRadarClone()).Concat(Encounter_B2W2_Regular).ToArray(); diff --git a/PKHeX.Core/Legality/Encounters/EncounterEgg.cs b/PKHeX.Core/Legality/Encounters/EncounterEgg.cs index be2a294ad..007f334fc 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterEgg.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterEgg.cs @@ -22,28 +22,27 @@ public class EncounterEgg : IEncounterable, IVersion public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { int gen = Version.GetGeneration(); + var version = Version; if (gen < 2) { gen = 2; - Version = GameVersion.C; + version = GameVersion.C; } - var pk = PKMConverter.GetBlank(gen, Version); + var pk = PKMConverter.GetBlank(gen, version); SAV.ApplyToPKM(pk); pk.Species = Species; pk.Nickname = PKX.GetSpeciesNameGeneration(Species, SAV.Language, gen); pk.CurrentLevel = Level; - pk.Version = (int)Version; + pk.Version = (int)version; pk.Ball = 4; - int[] moves = GetCurrentEggMoves(pk); - pk.Moves = moves; - pk.SetMaximumPPCurrent(moves); pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; - pk.SetRandomIVs(flawless: 3); + int[] moves = SetEncounterMoves(pk, version); + SetPINGA(pk, criteria); - if (pk.Format <= 2 && Version != GameVersion.C) + if (pk.Format <= 2 && version != GameVersion.C) return pk; SetMetData(pk); @@ -51,14 +50,13 @@ public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) if (pk.Format < 3) return pk; - SetNatureGenderAbility(pk, criteria); if (pk.GenNumber >= 4) - pk.SetEggMetData(Version, (GameVersion)SAV.Game); + pk.SetEggMetData(version, (GameVersion)SAV.Game); if (pk.Format < 6) return pk; - if (pk.Gen6) + if (pk.Format == 6) pk.SetHatchMemory6(); SetAltForm(pk, SAV); @@ -84,8 +82,12 @@ private void SetAltForm(PKM pk, ITrainerInfo SAV) } } - private static void SetNatureGenderAbility(PKM pk, EncounterCriteria criteria) + private static void SetPINGA(PKM pk, EncounterCriteria criteria) { + pk.SetRandomIVs(flawless: 3); + if (pk.Format <= 2) + return; + int gender = criteria.GetGender(-1, pk.PersonalInfo); int nature = (int)criteria.GetNature(Nature.Random); @@ -112,16 +114,24 @@ private static void SetMetData(PKM pk) pk.Met_Location = Math.Max(0, EncounterSuggestion.GetSuggestedEggMetLocation(pk)); } - private int[] GetCurrentEggMoves(PKM pk) + private int[] SetEncounterMoves(PKM pk, GameVersion version) { - var moves = MoveEgg.GetEggMoves(pk, Species, pk.AltForm, Version); + int[] moves = GetCurrentEggMoves(pk, version); + pk.Moves = moves; + pk.SetMaximumPPCurrent(moves); + return moves; + } + + private int[] GetCurrentEggMoves(PKM pk, GameVersion version) + { + var moves = MoveEgg.GetEggMoves(pk, Species, pk.AltForm, version); if (moves.Length == 0) - return MoveLevelUp.GetEncounterMoves(pk, Level, Version); + return MoveLevelUp.GetEncounterMoves(pk, Level, version); if (moves.Length >= 4 || pk.Format < 6) return moves; // Sprinkle in some default level up moves - var lvl = Legal.GetBaseEggMoves(pk, Species, Version, Level); + var lvl = Legal.GetBaseEggMoves(pk, Species, version, Level); return lvl.Concat(moves).ToArray(); } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot.cs index 9429bc342..1cf7e041a 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot.cs @@ -69,14 +69,11 @@ public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) pk.AltForm = GetWildAltForm(pk, Form, SAV); SetMetData(pk, level, Location); - SetNatureGenderAbility(pk, criteria); + SetPINGA(pk, criteria); + SetEncounterMoves(pk, version, level); SetFormatSpecificData(pk); - var moves = this is EncounterSlotMoves m ? m.Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); - pk.Moves = moves; - pk.SetMaximumPPCurrent(moves); - if (pk.Format < 6) return pk; @@ -86,6 +83,13 @@ public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) return pk; } + private void SetEncounterMoves(PKM pk, GameVersion version, int level) + { + var moves = this is EncounterSlotMoves m ? m.Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); + pk.Moves = moves; + pk.SetMaximumPPCurrent(moves); + } + private void SetFormatSpecificData(PKM pk) { if (pk is PK1 pk1) @@ -122,7 +126,7 @@ private void SetFormatSpecificData(PKM pk) } } - private void SetNatureGenderAbility(PKM pk, EncounterCriteria criteria) + private void SetPINGA(PKM pk, EncounterCriteria criteria) { int gender = criteria.GetGender(-1, pk.PersonalInfo); int nature = (int)criteria.GetNature(Nature.Random); diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic.cs index bbcca0687..8fdef8cd4 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic.cs @@ -71,80 +71,34 @@ internal virtual EncounterStatic Clone() public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { - var version = this.GetCompatibleVersion((GameVersion)SAV.Game); - SanityCheckVersion(ref version); - - int lang = (int)Legal.GetSafeLanguage(Generation, (LanguageID)SAV.Language); - int level = LevelMin; var pk = PKMConverter.GetBlank(Generation, Version); - int nature = Nature == Nature.Random ? Util.Rand.Next(25) : (int)Nature; - var today = DateTime.Today; SAV.ApplyToPKM(pk); pk.EncryptionConstant = Util.Rand32(); pk.Species = Species; - int gender = Gender < 0 ? pk.PersonalInfo.RandomGender : Gender; + pk.AltForm = Form; + + int lang = (int)Legal.GetSafeLanguage(Generation, (LanguageID)SAV.Language); + int level = LevelMin; + var version = this.GetCompatibleVersion((GameVersion)SAV.Game); + SanityCheckVersion(ref version); + pk.Language = lang = GetEdgeCaseLanguage(pk, lang); + pk.Nickname = PKX.GetSpeciesNameGeneration(Species, lang, Generation); + pk.CurrentLevel = level; pk.Version = (int)version; - pk.Nickname = PKX.GetSpeciesNameGeneration(Species, lang, Generation); pk.Ball = Ball; - pk.AltForm = Form; pk.HeldItem = HeldItem; pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; - if (pk.Format > 2 || Version == GameVersion.C) - { - pk.Met_Location = Location; - pk.Met_Level = level; - if (Version == GameVersion.C && pk is PK2 pk2) - pk2.Met_TimeOfDay = EncounterTime.Any.RandomValidTime(); - - if (pk.Format >= 4) - pk.MetDate = DateTime.Today; - } - + var today = DateTime.Today; + SetMetData(pk, level, today); if (EggEncounter) - { - pk.Met_Location = Math.Max(0, EncounterSuggestion.GetSuggestedEggMetLocation(pk)); - pk.Met_Level = EncounterSuggestion.GetSuggestedEncounterEggMetLevel(pk); + SetEggMetData(pk, SAV, today); - bool traded = (int)Version == SAV.Game; - if (pk.GenNumber >= 4) - { - pk.Egg_Location = EncounterSuggestion.GetSuggestedEncounterEggLocationEgg(pk, traded); - pk.EggMetDate = today; - } - pk.Egg_Location = EggLocation; - pk.EggMetDate = today; - } - - if (this is EncounterStaticPID p) - { - pk.PID = p.PID; - pk.Gender = PKX.GetGenderFromPID(Species, p.PID); - if (pk is PK5 pk5) - { - pk5.IVs = new[] {30, 30, 30, 30, 30, 30}; - pk5.NPokémon = p.NSparkle; - pk5.OT_Name = Legal.GetG5OT_NSparkle(lang); - pk5.TID = 00002; - pk5.SID = 00000; - } - else - { - SetIVs(pk); - } - if (Generation >= 5) - pk.Nature = nature; - pk.RefreshAbility(Ability >> 1); - } - else - { - var pidtype = GetPIDType(); - PIDGenerator.SetRandomWildPID(pk, pk.Format, nature, Ability >> 1, gender, pidtype); - SetIVs(pk); - } + SetPINGA(pk, criteria); + SetEncounterMoves(pk, version, level); switch (pk) { @@ -159,28 +113,73 @@ public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) break; } + if (RibbonWishing && pk is IRibbonSetEvent4 e4) + e4.RibbonWishing = true; + if (this is EncounterStaticN n) + n.SetNPokemonData((PK5)pk, lang); if (pk is IContestStats s) this.CopyContestStatsTo(s); - - var moves = Moves ?? MoveLevelUp.GetEncounterMoves(pk, level, version); - pk.Moves = moves; - pk.SetMaximumPPCurrent(moves); - if (pk.Format >= 6 && Relearn.Length > 0) - pk.RelearnMoves = Relearn; if (Fateful) pk.FatefulEncounter = true; if (pk.Format < 6) return pk; - if (RibbonWishing && pk is IRibbonSetEvent4 e4) - e4.RibbonWishing = true; + if (Relearn.Length > 0) + pk.RelearnMoves = Relearn; SAV.ApplyHandlingTrainerInfo(pk); pk.SetRandomEC(); return pk; } + protected virtual void SetPINGA(PKM pk, EncounterCriteria criteria) + { + int gender = criteria.GetGender(Gender, pk.PersonalInfo); + int nature = (int)criteria.GetNature(Nature); + int ability = Ability; + + var pidtype = GetPIDType(); + PIDGenerator.SetRandomWildPID(pk, pk.Format, nature, ability >> 1, gender, pidtype); + SetIVs(pk); + } + + private void SetEggMetData(PKM pk, ITrainerInfo tr, DateTime today) + { + pk.Met_Location = Math.Max(0, EncounterSuggestion.GetSuggestedEggMetLocation(pk)); + pk.Met_Level = EncounterSuggestion.GetSuggestedEncounterEggMetLevel(pk); + + if (pk.GenNumber >= 4) + { + bool traded = (int)Version == tr.Game; + pk.Egg_Location = EncounterSuggestion.GetSuggestedEncounterEggLocationEgg(pk, traded); + pk.EggMetDate = today; + } + pk.Egg_Location = EggLocation; + pk.EggMetDate = today; + } + + private void SetMetData(PKM pk, int level, DateTime today) + { + if (pk.Format > 2 || Version == GameVersion.C) + { + pk.Met_Location = Location; + pk.Met_Level = level; + if (Version == GameVersion.C && pk is PK2 pk2) + pk2.Met_TimeOfDay = EncounterTime.Any.RandomValidTime(); + + if (pk.Format >= 4) + pk.MetDate = today; + } + } + + private void SetEncounterMoves(PKM pk, GameVersion version, int level) + { + var moves = Moves?.Length > 0 ? Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); + pk.Moves = moves; + pk.SetMaximumPPCurrent(moves); + } + private void SanityCheckVersion(ref GameVersion version) { if (Generation != 4 || version == GameVersion.Pt) @@ -194,7 +193,7 @@ private void SanityCheckVersion(ref GameVersion version) } } - private void SetIVs(PKM pk) + protected void SetIVs(PKM pk) { if (IVs != null) pk.SetRandomIVs(IVs, FlawlessIVCount); diff --git a/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs b/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs index 716e95f09..ebe4a1fbd 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs @@ -1,9 +1,37 @@ namespace PKHeX.Core { - internal sealed class EncounterStaticPID : EncounterStatic + internal class EncounterStaticPID : EncounterStatic { public uint PID { get; set; } - public bool NSparkle { get; set; } public override Shiny Shiny { get; set; } = Shiny.FixedValue; + + protected override void SetPINGA(PKM pk, EncounterCriteria criteria) + { + int gender = criteria.GetGender(PKX.GetGenderFromPID(Species, PID), pk.PersonalInfo); + int nature = (int)(PID % 25); + int ability = Ability; + + pk.PID = PID; + pk.Gender = gender; + SetIVs(pk); + + if (Generation >= 5) + pk.Nature = nature; + pk.RefreshAbility(ability >> 1); + } + } + + internal sealed class EncounterStaticN : EncounterStaticPID + { + public bool NSparkle { get; set; } + + internal void SetNPokemonData(PK5 pk5, int lang) + { + pk5.IV_HP = pk5.IV_ATK = pk5.IV_DEF = pk5.IV_SPA = pk5.IV_SPD = pk5.IV_SPE = 30; + pk5.NPokémon = NSparkle; + pk5.OT_Name = Legal.GetG5OT_NSparkle(lang); + pk5.TID = 00002; + pk5.SID = 00000; + } } } \ No newline at end of file diff --git a/PKHeX.Core/Legality/Encounters/EncounterTrade.cs b/PKHeX.Core/Legality/Encounters/EncounterTrade.cs index d002cb624..08b6877c7 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTrade.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTrade.cs @@ -73,46 +73,44 @@ public int TID7 public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { var pk = PKMConverter.GetBlank(Generation, Version); + SAV.ApplyToPKM(pk); + var version = this.GetCompatibleVersion((GameVersion)SAV.Game); int lang = (int)Legal.GetSafeLanguage(Generation, (LanguageID)SAV.Language); int level = CurrentLevel > 0 ? CurrentLevel : LevelMin; if (level == 0) level = 25; // avoid some cases - SAV.ApplyToPKM(pk); - int species = Species; if (EvolveOnTrade) species++; pk.EncryptionConstant = Util.Rand32(); pk.Species = species; - pk.CurrentLevel = level; - pk.Version = (int)version; pk.AltForm = Form; - pk.Ball = Ball; pk.Language = lang; - pk.TID = TID; - pk.SID = SID; pk.OT_Name = pk.Format == 1 ? StringConverter.G1TradeOTStr : GetOT(lang) ?? SAV.OT; pk.OT_Gender = GetOT(lang) != null ? Math.Max(0, OTGender) : SAV.Gender; pk.SetNickname(GetNickname(lang)); + + pk.CurrentLevel = level; + pk.Version = (int)version; + pk.TID = TID; + pk.SID = SID; + pk.Ball = Ball; pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; - SetNatureGenderAbility(pk, criteria); - - if (IVs != null) - pk.SetRandomIVs(IVs, 0); - else - pk.SetRandomIVs(flawless: 3); + SetPINGA(pk, criteria); + SetMoves(pk, version, level); + var time = DateTime.Now; if (pk.Format != 2 || version == GameVersion.C) { var location = Location > 0 ? Location : DefaultMetLocation[Generation - 1]; - SetMetData(pk, level, location); + SetMetData(pk, level, location, time); } if (EggLocation != 0) - SetEggMetData(pk); + SetEggMetData(pk, time); if (pk is PK1 pk1 && this is EncounterTradeCatchRate c) pk1.Catch_Rate = (int)c.Catch_Rate; @@ -120,8 +118,6 @@ public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) if (pk is IContestStats s) this.CopyContestStatsTo(s); - SetMoves(pk, version, level); - if (Fateful) pk.FatefulEncounter = true; @@ -141,26 +137,26 @@ public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) return pk; } - private void SetNatureGenderAbility(PKM pk, EncounterCriteria criteria) + protected virtual void SetPINGA(PKM pk, EncounterCriteria criteria) { int gender = criteria.GetGender(Gender, pk.PersonalInfo); int nature = (int)criteria.GetNature(Nature); int ability = Ability >> 1; - if (this is EncounterTradePID p) - { - pk.PID = p.PID; - pk.Nature = nature; - pk.Gender = PKX.GetGenderFromPID(Species, p.PID); - pk.RefreshAbility(ability); - } + PIDGenerator.SetRandomWildPID(pk, Generation, nature, ability, gender); + pk.Nature = nature; + pk.Gender = gender; + pk.RefreshAbility(ability); + + SetIVs(pk); + } + + protected void SetIVs(PKM pk) + { + if (IVs != null) + pk.SetRandomIVs(IVs, 0); else - { - PIDGenerator.SetRandomWildPID(pk, Generation, nature, ability, gender); - pk.Nature = nature; - pk.Gender = gender; - pk.RefreshAbility(ability); - } + pk.SetRandomIVs(flawless: 3); } private void SetMoves(PKM pk, GameVersion version, int level) @@ -172,17 +168,17 @@ private void SetMoves(PKM pk, GameVersion version, int level) pk.SetMaximumPPCurrent(moves); } - private void SetEggMetData(PKM pk) + private void SetEggMetData(PKM pk, DateTime time) { pk.Egg_Location = EggLocation; - pk.EggMetDate = DateTime.Today; + pk.EggMetDate = time; } - private static void SetMetData(PKM pk, int level, int location) + private static void SetMetData(PKM pk, int level, int location, DateTime time) { pk.Met_Level = level; pk.Met_Location = location; - pk.MetDate = DateTime.Today; + pk.MetDate = time; } private void UpdateEdgeCase(PKM pkm) diff --git a/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs b/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs index 90c452989..fc4c3c041 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs @@ -7,5 +7,19 @@ public sealed class EncounterTradePID : EncounterTrade { public uint PID; public override Shiny Shiny { get; set; } = Shiny.FixedValue; + + protected override void SetPINGA(PKM pk, EncounterCriteria criteria) + { + int gender = criteria.GetGender(PKX.GetGenderFromPID(Species, PID), pk.PersonalInfo); + int nature = (int)criteria.GetNature(Nature); + int ability = Ability >> 1; + + pk.PID = PID; + pk.Nature = nature; + pk.Gender = gender; + pk.RefreshAbility(ability); + + SetIVs(pk); + } } } \ No newline at end of file diff --git a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs index 012973e4a..47ce4db87 100644 --- a/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs +++ b/PKHeX.Core/Legality/Encounters/Generator/EncounterCriteria.cs @@ -1,4 +1,6 @@ -namespace PKHeX.Core +using System; + +namespace PKHeX.Core { /// /// Object that can be fed to a converter to ensure that the resulting meets rough specifications. @@ -65,7 +67,7 @@ public static EncounterCriteria GetCriteria(ShowdownSet s) public Nature GetNature(Nature encValue) { - if (encValue != Nature.Random) + if ((uint)encValue < 25) return encValue; if (Nature != Nature.Random) return Nature; @@ -74,7 +76,7 @@ public Nature GetNature(Nature encValue) public int GetGender(int gender, PersonalInfo pkPersonalInfo) { - if (gender >= 0) + if ((uint)gender < 3) return gender; if (!pkPersonalInfo.IsDualGender) return pkPersonalInfo.FixedGender; @@ -82,5 +84,18 @@ public int GetGender(int gender, PersonalInfo pkPersonalInfo) return Gender; return pkPersonalInfo.RandomGender; } + + public int GetAbility(int abilityType, PersonalInfo pkPersonalInfo) + { + if (abilityType < 3) + return abilityType; + + var abils = pkPersonalInfo.Abilities; + if (abilityType == 4 && abils.Length > 2 && abils[2] == Ability) // hidden allowed + return 2; + if (abils[1] == Ability) + return 1; + return 0; + } } } diff --git a/PKHeX.Core/Legality/RNG/PIDType.cs b/PKHeX.Core/Legality/RNG/PIDType.cs index 2ca57c99a..8c251f6fe 100644 --- a/PKHeX.Core/Legality/RNG/PIDType.cs +++ b/PKHeX.Core/Legality/RNG/PIDType.cs @@ -58,7 +58,7 @@ public enum PIDType BACD_U_A, /// - /// Event Reversed Order PID restricted to 16bit Origin Seed, shiny + /// Event Reversed Order PID restricted to 8bit Origin Seed, shiny /// /// BACD_R_S, diff --git a/PKHeX.Core/Legality/Verifiers/NHarmoniaVerifier.cs b/PKHeX.Core/Legality/Verifiers/NHarmoniaVerifier.cs index 5531b6e9d..28e84edf8 100644 --- a/PKHeX.Core/Legality/Verifiers/NHarmoniaVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/NHarmoniaVerifier.cs @@ -14,7 +14,7 @@ public override void Verify(LegalityAnalysis data) var pkm = data.pkm; var EncounterMatch = data.EncounterMatch; - bool checksRequired = EncounterMatch is EncounterStaticPID s && s.NSparkle; + bool checksRequired = EncounterMatch is EncounterStaticN s && s.NSparkle; if (pkm is PK5 pk5) { bool has = pk5.NPokémon; diff --git a/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs b/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs index d6e196f9f..44d195900 100644 --- a/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/PIDVerifier.cs @@ -50,7 +50,7 @@ private void VerifyShiny(LegalityAnalysis data) break; if (s.Gift || s.Roaming || s.Ability != 4) break; - if (s is EncounterStaticPID p && p.NSparkle) + if (s is EncounterStaticN p && p.NSparkle) break; VerifyG5PID_IDCorrelation(data); break; diff --git a/PKHeX.Core/Legality/Verifiers/TrainerNameVerifier.cs b/PKHeX.Core/Legality/Verifiers/TrainerNameVerifier.cs index 1c1b7317c..ec4fce19d 100644 --- a/PKHeX.Core/Legality/Verifiers/TrainerNameVerifier.cs +++ b/PKHeX.Core/Legality/Verifiers/TrainerNameVerifier.cs @@ -22,7 +22,7 @@ public override void Verify(LegalityAnalysis data) { case EncounterTrade _: case MysteryGift g when !g.IsEgg: - case EncounterStaticPID s when s.NSparkle: + case EncounterStaticN s when s.NSparkle: return; // already verified } diff --git a/PKHeX.Core/MysteryGifts/PGF.cs b/PKHeX.Core/MysteryGifts/PGF.cs index 5b64f16b5..dbe30bea9 100644 --- a/PKHeX.Core/MysteryGifts/PGF.cs +++ b/PKHeX.Core/MysteryGifts/PGF.cs @@ -167,13 +167,14 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) if (!IsPokémon) return null; - DateTime dt = DateTime.Now; + var dt = DateTime.Now; if (Day == 0) { Day = (byte)dt.Day; Month = (byte)dt.Month; Year = (byte)dt.Year; } + int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1; var pi = PersonalTable.B2W2.GetFormeEntry(Species, Form); PK5 pk = new PK5 @@ -201,7 +202,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) CNT_Tough = CNT_Tough, CNT_Sheen = CNT_Sheen, - EXP = Experience.GetEXP(Level, Species, 0), + EXP = Experience.GetEXP(currentLevel, Species, 0), // Ribbons RibbonCountry = RibbonCountry, @@ -230,12 +231,13 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) pk.Moves = MoveLevelUp.GetEncounterMoves(Species, Form, Level, (GameVersion)pk.Version); pk.SetMaximumPPCurrent(); + if (IsEgg) // User's { pk.TID = SAV.TID; pk.SID = SAV.SID; pk.OT_Name = SAV.OT; - pk.OT_Gender = 1; // Red PKHeX OT + pk.OT_Gender = SAV.Gender; } else // Hardcoded { @@ -244,74 +246,92 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) pk.OT_Name = OT_Name; pk.OT_Gender = (OTGender == 3 ? SAV.Gender : OTGender) & 1; // some events have variable gender based on receiving SaveFile } + pk.IsNicknamed = IsNicknamed; pk.Nickname = IsNicknamed ? Nickname : PKX.GetSpeciesNameGeneration(Species, pk.Language, Format); - // More 'complex' logic to determine final values + SetPINGA(pk, criteria); - // Dumb way to generate random IVs. - int[] finalIVs = new int[6]; - for (int i = 0; i < IVs.Length; i++) - finalIVs[i] = IVs[i] == 0xFF ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; - pk.IVs = finalIVs; + if (IsEgg) + SetEggMetDetails(pk); - int av = 0; + pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + + pk.RefreshChecksum(); + return pk; + } + + private void SetEggMetDetails(PK5 pk) + { + pk.IsEgg = true; + pk.EggMetDate = Date; + pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); + pk.IsNicknamed = true; + } + + private void SetPINGA(PKM pk, EncounterCriteria criteria) + { + var pi = PersonalTable.B2W2.GetFormeEntry(Species, Form); + pk.Nature = (int)criteria.GetNature((Nature)Nature); + pk.Gender = criteria.GetGender(Gender, pi); + var av = GetAbilityIndex(criteria, pi); + SetPID(pk, av); + pk.RefreshAbility(av); + SetIVs(pk); + } + + private int GetAbilityIndex(EncounterCriteria criteria, PersonalInfo pi) + { switch (AbilityType) { case 00: // 0 - 0 case 01: // 1 - 1 case 02: // 2 - H - av = AbilityType; - break; + return AbilityType; case 03: // 0/1 case 04: // 0/1/H - av = Util.Rand.Next(AbilityType - 1); - break; + return criteria.GetAbility(AbilityType, pi); // 3 or 2 + default: + throw new ArgumentException(nameof(AbilityType)); } - pk.HiddenAbility = av == 2; - pk.Ability = pi.Abilities[av]; + } + private void SetPID(PKM pk, int av) + { if (PID != 0) { pk.PID = PID; + return; } + + pk.PID = Util.Rand32(); + // Force Gender + do { pk.PID = (pk.PID & 0xFFFFFF00) | (uint)Util.Rand.Next(0x100); } + while (!pk.IsGenderValid()); + + if (PIDType == 2) // Always + { + uint gb = pk.PID & 0xFF; + pk.PID = PIDGenerator.GetMG5ShinyPID(gb, (uint)av, pk.TID, pk.SID); + } + else if (PIDType != 1) // Force Not Shiny + { + if (pk.IsShiny) + pk.PID ^= 0x10000000; + } + + if (av == 1) + pk.PID |= 0x10000; else - { - pk.PID = Util.Rand32(); + pk.PID &= 0xFFFEFFFF; + } - // Force Gender - do { pk.PID = (pk.PID & 0xFFFFFF00) | (uint)Util.Rand.Next(0x100); } - while (!pk.IsGenderValid()); - - // Force Ability - if (av == 1) - pk.PID |= 0x10000; - else - pk.PID &= 0xFFFEFFFF; - - if (PIDType == 2) // Force Shiny - { - uint gb = pk.PID & 0xFF; - pk.PID = PIDGenerator.GetMG5ShinyPID(gb, (uint)av, pk.TID, pk.SID); - } - else if (PIDType != 1) // Force Not Shiny - { - if (pk.IsShiny) - pk.PID ^= 0x10000000; - } - } - - if (IsEgg) - { - pk.IsEgg = true; - pk.EggMetDate = Date; - pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); - pk.IsNicknamed = true; - } - pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; - - pk.RefreshChecksum(); - return pk; + private void SetIVs(PKM pk) + { + int[] finalIVs = new int[6]; + for (int i = 0; i < IVs.Length; i++) + finalIVs[i] = IVs[i] == 0xFF ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; + pk.IVs = finalIVs; } protected override bool IsMatchExact(PKM pkm, IEnumerable vs) diff --git a/PKHeX.Core/MysteryGifts/PGT.cs b/PKHeX.Core/MysteryGifts/PGT.cs index d8bb57fb9..c77b2f330 100644 --- a/PKHeX.Core/MysteryGifts/PGT.cs +++ b/PKHeX.Core/MysteryGifts/PGT.cs @@ -124,7 +124,8 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) if (!IsPokémon) return null; - PK4 pk4 = new PK4((byte[])PK.Data.Clone()) {Sanity = 0}; + // template is already filled out, only minor mutations required + PK4 pk4 = new PK4((byte[])PK.Data.Clone()) { Sanity = 0 }; if (!IsHatched && Detail == 0) { pk4.OT_Name = SAV.OT; @@ -134,31 +135,67 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) pk4.Language = SAV.Language; } - uint seed = Util.Rand32(); if (IsManaphyEgg) + SetDefaultManaphyEggDetails(pk4); + + SetPINGA(pk4, criteria); + SetMetData(pk4, SAV); + + var pi = pk4.PersonalInfo; + pk4.CurrentFriendship = pk4.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + + pk4.RefreshChecksum(); + return pk4; + } + + private void SetMetData(PK4 pk4, ITrainerInfo trainer) + { + if (!EggEncounter) { - // Since none of this data is populated, fill in default info. - pk4.Species = 490; - pk4.Gender = 2; - // Level 1 Moves - pk4.Move1 = 294; - pk4.Move2 = 145; - pk4.Move3 = 346; - pk4.Ability = pk4.PersonalInfo.Abilities[0]; - pk4.FatefulEncounter = true; - pk4.Ball = 4; - pk4.Version = 10; // Diamond - pk4.Language = (int)LanguageID.English; // English - pk4.Nickname = "MANAPHY"; - pk4.Egg_Location = 1; // Ranger (will be +3000 later) - pk4.Move1_PP = pk4.GetMovePP(pk4.Move1, 0); - pk4.Move2_PP = pk4.GetMovePP(pk4.Move2, 0); - pk4.Move3_PP = pk4.GetMovePP(pk4.Move3, 0); - seed = GeneratePID(seed, pk4); + pk4.Met_Location = pk4.Egg_Location + 3000; + pk4.Egg_Location = 0; + pk4.MetDate = DateTime.Now; + pk4.IsEgg = false; } + else + { + pk4.Egg_Location += 3000; + if (trainer.Generation == 4) + SetUnhatchedEggDetails(pk4); + else + SetHatchedEggDetails(pk4); + } + } + + private static void SetDefaultManaphyEggDetails(PK4 pk4) + { + // Since none of this data is populated, fill in default info. + pk4.Species = 490; + pk4.Gender = 2; + // Level 1 Moves + pk4.Move1 = 294; + pk4.Move2 = 145; + pk4.Move3 = 346; + pk4.Ability = pk4.PersonalInfo.Abilities[0]; + pk4.FatefulEncounter = true; + pk4.Ball = 4; + pk4.Version = 10; // Diamond + pk4.Language = (int)LanguageID.English; // English + pk4.Nickname = "MANAPHY"; + pk4.Egg_Location = 1; // Ranger (will be +3000 later) + pk4.Move1_PP = pk4.GetMovePP(pk4.Move1, 0); + pk4.Move2_PP = pk4.GetMovePP(pk4.Move2, 0); + pk4.Move3_PP = pk4.GetMovePP(pk4.Move3, 0); + } + + private void SetPINGA(PK4 pk4, EncounterCriteria criteria) + { + // Ability is forced already, can't force anything + // todo: loop force the Nature/Gender // Generate IV - if (pk4.PID == 1) // Create Nonshiny + uint seed = Util.Rand32(); + if (pk4.PID == 1 || IsManaphyEgg) // Create Nonshiny seed = GeneratePID(seed, pk4); if (!IsManaphyEgg) @@ -171,41 +208,21 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) uint iv2 = (PKX.LCRNG(ref seed) >> 16) & 0x7FFF; pk4.IV32 = iv1 | iv2 << 15; } + } - // Generate Met Info - if (!IsEgg && !IsManaphyEgg) - { - pk4.Met_Location = pk4.Egg_Location + 3000; - pk4.Egg_Location = 0; - pk4.MetDate = DateTime.Now; - pk4.IsEgg = false; - } - else - { - pk4.Egg_Location += 3000; - if (SAV.Generation == 4) - { - pk4.IsEgg = true; - pk4.IsNicknamed = false; - pk4.Nickname = PKX.GetSpeciesNameGeneration(0, pk4.Language, Format); - pk4.MetDate = DateTime.Now; - } - else - { - pk4.IsEgg = false; - // Met Location is modified when transferred to pk5; don't worry about it. - pk4.EggMetDate = DateTime.Now; - } - while (pk4.IsShiny) - pk4.PID = RNG.ARNG.Next(pk4.PID); - } - var pi = pk4.PersonalInfo; - pk4.CurrentFriendship = pk4.IsEgg ? pi.HatchCycles : pi.BaseFriendship; - if (pk4.Species == 201) // Never will be true; Unown was never distributed. - pk4.AltForm = PKX.GetUnownForm(pk4.PID); + private static void SetHatchedEggDetails(PK4 pk4) + { + pk4.IsEgg = false; + // Met Location is modified when transferred to pk5; don't worry about it. + pk4.EggMetDate = DateTime.Now; + } - pk4.RefreshChecksum(); - return pk4; + private void SetUnhatchedEggDetails(PK4 pk4) + { + pk4.IsEgg = true; + pk4.IsNicknamed = false; + pk4.Nickname = PKX.GetSpeciesNameGeneration(0, pk4.Language, Format); + pk4.MetDate = DateTime.Now; } private static uint GeneratePID(uint seed, PK4 pk4) diff --git a/PKHeX.Core/MysteryGifts/WB7.cs b/PKHeX.Core/MysteryGifts/WB7.cs index c20a35cc7..fccde0b49 100644 --- a/PKHeX.Core/MysteryGifts/WB7.cs +++ b/PKHeX.Core/MysteryGifts/WB7.cs @@ -319,8 +319,9 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) int currentLevel = Level > 0 ? Level : Util.Rand.Next(100) + 1; int metLevel = MetLevel > 0 ? MetLevel : currentLevel; - var pi = PersonalTable.USUM.GetFormeEntry(Species, Form); + var pi = PersonalTable.GG.GetFormeEntry(Species, Form); var OT = GetOT(SAV.Language); + var pk = new PB7 { Species = Species, @@ -328,8 +329,6 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) TID = TID, SID = SID, Met_Level = metLevel, - Nature = Nature != -1 ? Nature : Util.Rand.Next(25), - Gender = Gender != 3 ? Gender : pi.RandomGender, AltForm = Form, EncryptionConstant = EncryptionConstant != 0 ? EncryptionConstant : Util.Rand32(), Version = OriginGame != 0 ? OriginGame : SAV.Game, @@ -338,9 +337,14 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) Country = SAV.Country, Region = SAV.SubRegion, ConsoleRegion = SAV.ConsoleRegion, - Move1 = Move1, Move2 = Move2, Move3 = Move3, Move4 = Move4, - RelearnMove1 = RelearnMove1, RelearnMove2 = RelearnMove2, - RelearnMove3 = RelearnMove3, RelearnMove4 = RelearnMove4, + Move1 = Move1, + Move2 = Move2, + Move3 = Move3, + Move4 = Move4, + RelearnMove1 = RelearnMove1, + RelearnMove2 = RelearnMove2, + RelearnMove3 = RelearnMove3, + RelearnMove4 = RelearnMove4, Met_Location = MetLocation, Egg_Location = EggLocation, AV_HP = AV_HP, @@ -361,6 +365,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) OT_Friendship = pi.BaseFriendship, FatefulEncounter = true, }; + pk.SetMaximumPPCurrent(); if ((SAV.Generation > Format && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version)) { @@ -369,8 +374,6 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) while (!CanBeReceivedByVersion(pk.Version)); } - pk.SetMaximumPPCurrent(); - if (OTGender == 3) { pk.TID = SAV.TID; @@ -378,43 +381,60 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) } pk.MetDate = Date ?? DateTime.Now; - pk.IsNicknamed = GetIsNicknamed(pk.Language); pk.Nickname = pk.IsNicknamed ? GetNickname(pk.Language) : PKX.GetSpeciesNameGeneration(Species, pk.Language, Format); - int[] finalIVs = new int[6]; - var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3); - if (ivflag == 0) // Random IVs - { - for (int i = 0; i < 6; i++) - finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; - } - else // 1/2/3 perfect IVs - { - int IVCount = ivflag - 0xFB; - do { finalIVs[Util.Rand.Next(6)] = 31; } - while (finalIVs.Count(iv => iv == 31) < IVCount); - for (int i = 0; i < 6; i++) - finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1); - } - pk.IVs = finalIVs; + SetPINGA(pk, criteria); - int av = 0; + if (IsEgg) + SetEggMetData(pk); + pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + + pk.HeightScalar = Util.Rand.Next(0x100); + pk.WeightScalar = Util.Rand.Next(0x100); + pk.ResetCalculatedValues(); // cp & dimensions + + pk.RefreshChecksum(); + return pk; + } + + private void SetEggMetData(PKM pk) + { + pk.IsEgg = true; + pk.EggMetDate = Date; + pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); + pk.IsNicknamed = true; + } + + private void SetPINGA(PKM pk, EncounterCriteria criteria) + { + var pi = PersonalTable.GG.GetFormeEntry(Species, Form); + pk.Nature = (int)criteria.GetNature((Nature)Nature); + pk.Gender = criteria.GetGender(Gender, pi); + var av = GetAbilityIndex(criteria, pi); + pk.RefreshAbility(av); + SetPID(pk); + SetIVs(pk); + } + + private int GetAbilityIndex(EncounterCriteria criteria, PersonalInfo pi) + { switch (AbilityType) { case 00: // 0 - 0 case 01: // 1 - 1 case 02: // 2 - H - av = AbilityType; - break; + return AbilityType; case 03: // 0/1 case 04: // 0/1/H - av = Util.Rand.Next(AbilityType - 1); - break; + return criteria.GetAbility(AbilityType, pi); // 3 or 2 + default: + throw new ArgumentException(nameof(AbilityType)); } - pk.Ability = pi.Abilities[av]; - pk.AbilityNumber = 1 << av; + } + private void SetPID(PKM pk) + { switch (PIDType) { case Shiny.FixedValue: // Specified @@ -432,22 +452,26 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) if (pk.IsShiny) pk.PID ^= 0x10000000; break; } + } - if (IsEgg) + private void SetIVs(PKM pk) + { + int[] finalIVs = new int[6]; + var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3); + if (ivflag == 0) // Random IVs { - pk.IsEgg = true; - pk.EggMetDate = Date; - pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); - pk.IsNicknamed = true; + for (int i = 0; i < 6; i++) + finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; } - pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; - - pk.HeightScalar = Util.Rand.Next(0x100); - pk.WeightScalar = Util.Rand.Next(0x100); - pk.ResetCalculatedValues(); // cp & dimensions - - pk.RefreshChecksum(); - return pk; + else // 1/2/3 perfect IVs + { + int IVCount = ivflag - 0xFB; + do { finalIVs[Util.Rand.Next(6)] = 31; } + while (finalIVs.Count(iv => iv == 31) < IVCount); + for (int i = 0; i < 6; i++) + finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1); + } + pk.IVs = finalIVs; } protected override bool IsMatchExact(PKM pkm, IEnumerable vs) diff --git a/PKHeX.Core/MysteryGifts/WC3.cs b/PKHeX.Core/MysteryGifts/WC3.cs index adb33217d..9ba9537c3 100644 --- a/PKHeX.Core/MysteryGifts/WC3.cs +++ b/PKHeX.Core/MysteryGifts/WC3.cs @@ -90,77 +90,72 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) RibbonChampionNational = RibbonChampionNational, FatefulEncounter = Fateful, + Version = GetVersion(SAV), }; - var pi = pk.PersonalInfo; + SetMoves(pk); + - if (Version == 0) - { - bool gen3 = SAV.Game <= 15 && GameVersion.Gen3.Contains((GameVersion)SAV.Game); - pk.Version = gen3 ? SAV.Game : (int)GameVersion.R; - } - else - { - pk.Version = (int)GetRandomVersion(Version); - } - int lang = (int)GetSafeLanguage((LanguageID)SAV.Language, (LanguageID)Language); bool hatchedEgg = IsEgg && SAV.Generation != 3; - if (hatchedEgg) // ugly workaround for character table interactions + if (hatchedEgg) { - pk.Language = (int)LanguageID.English; - pk.OT_Name = "PKHeX"; - pk.OT_Gender = SAV.Gender; - pk.TID = SAV.TID; - pk.SID = SAV.SID; - pk.OT_Friendship = pi.BaseFriendship; - pk.Met_Location = pk.FRLG ? 146 /* Four Island */ : 32; // Route 117 - pk.FatefulEncounter &= pk.FRLG; // clear flag for RSE - pk.Met_Level = 0; // hatched + SetForceHatchDetails(pk, SAV); } else { - if (IsEgg) - { - pk.IsEgg = true; - pk.IsNicknamed = true; - pk.Language = (int)LanguageID.Japanese; // JPN - if (SID >= 0) - pk.SID = SID; - if (TID >= 0) - pk.SID = TID; - } - else - { - pk.Language = lang; - } - - pk.OT_Name = OT_Name ?? SAV.OT; - if (string.IsNullOrWhiteSpace(pk.OT_Name)) - { - // Try again (only happens for eggs) - pk.IsEgg = false; - pk.Language = (int)LanguageID.English; - pk.OT_Name = SAV.OT; - pk.Language = (int)LanguageID.Japanese; // as egg is Japanese until hatched - pk.IsEgg = true; - } pk.OT_Gender = OT_Gender != 3 ? OT_Gender & 1 : SAV.Gender; pk.TID = TID; pk.SID = SID; - pk.OT_Friendship = IsEgg ? pi.HatchCycles : pi.BaseFriendship; + + pk.Language = (int)GetSafeLanguage((LanguageID)SAV.Language, (LanguageID)Language); + pk.OT_Name = OT_Name ?? SAV.OT; + if (IsEgg) + pk.IsEgg = true; // lang should be set to japanese by IsEgg setter } pk.Nickname = PKX.GetSpeciesNameGeneration(Species, pk.Language, 3); // will be set to Egg nickname if appropriate by PK3 setter + var pi = pk.PersonalInfo; + pk.OT_Friendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + // Generate PIDIV - SetPIDValues(pk); + SetPINGA(pk, criteria); pk.HeldItem = 0; // clear, only random for Jirachis(?), no loss if (Version == GameVersion.XD) pk.FatefulEncounter = true; // pk3 is already converted from xk3 - SetMoves(pk); + pk.RefreshChecksum(); return pk; } + private static void SetForceHatchDetails(PK3 pk, ITrainerInfo SAV) + { + // ugly workaround for character table interactions + pk.Language = (int)LanguageID.English; + pk.OT_Name = "PKHeX"; + pk.OT_Gender = SAV.Gender; + pk.TID = SAV.TID; + pk.SID = SAV.SID; + pk.Met_Location = pk.FRLG ? 146 /* Four Island */ : 32; // Route 117 + pk.FatefulEncounter &= pk.FRLG; // clear flag for RSE + pk.Met_Level = 0; // hatched + } + + private int GetVersion(ITrainerInfo SAV) + { + int version; + if (Version == 0) + { + bool gen3 = SAV.Game <= 15 && GameVersion.Gen3.Contains((GameVersion)SAV.Game); + version = gen3 ? SAV.Game : (int)GameVersion.R; + } + else + { + version = (int)GetRandomVersion(Version); + } + + return version; + } + private void SetMoves(PK3 pk) { if (Moves.Length == 0) // not completely defined @@ -176,24 +171,24 @@ private void SetMoves(PK3 pk) pk.SetMaximumPPCurrent(Moves); } - private void SetPIDValues(PK3 pk) + private void SetPINGA(PK3 pk, EncounterCriteria criteria) { var seed = Util.Rand32(); - SetPIDValues(pk, seed); + seed = GetSaneSeed(seed); + PIDGenerator.SetValuesFromSeed(pk, Method, seed); } - private void SetPIDValues(PK3 pk, uint seed) + private uint GetSaneSeed(uint seed) { switch (Method) { case PIDType.BACD_R: - seed &= 0xFFFF; - break; + return seed & 0x0000FFFF; case PIDType.BACD_R_S: - seed &= 0xFF; - break; + return seed & 0x000000FF; + default: + return seed; // unmodified } - PIDGenerator.SetValuesFromSeed(pk, Method, seed); } private static LanguageID GetSafeLanguage(LanguageID hatchLang, LanguageID supplied) diff --git a/PKHeX.Core/MysteryGifts/WC6.cs b/PKHeX.Core/MysteryGifts/WC6.cs index 8d51fbc6b..c48322d05 100644 --- a/PKHeX.Core/MysteryGifts/WC6.cs +++ b/PKHeX.Core/MysteryGifts/WC6.cs @@ -298,8 +298,6 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) TID = TID, SID = SID, Met_Level = currentLevel, - Nature = Nature != -1 ? Nature : Util.Rand.Next(25), - Gender = Gender != 3 ? Gender : pi.RandomGender, AltForm = Form, EncryptionConstant = EncryptionConstant != 0 ? EncryptionConstant : Util.Rand32(), Version = OriginGame != 0 ? OriginGame : SAV.Game, @@ -389,39 +387,53 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) pk.IsNicknamed = IsNicknamed; pk.Nickname = IsNicknamed ? Nickname : PKX.GetSpeciesNameGeneration(Species, pk.Language, Format); - int[] finalIVs = new int[6]; - var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3); - if (ivflag == 0) // Random IVs - { - for (int i = 0; i < 6; i++) - finalIVs[i] = IVs[i] > pk.MaxIV ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; - } - else // 1/2/3 perfect IVs - { - int IVCount = ivflag - 0xFB; - do { finalIVs[Util.Rand.Next(6)] = 31; } - while (finalIVs.Count(iv => iv == 31) < IVCount); - for (int i = 0; i < 6; i++) - finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1); - } - pk.IVs = finalIVs; + SetPINGA(pk, criteria); - int av = 0; + if (IsEgg) + SetEggMetData(pk); + pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + + pk.RefreshChecksum(); + return pk; + } + + private void SetEggMetData(PKM pk) + { + pk.IsEgg = true; + pk.EggMetDate = Date; + pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); + pk.IsNicknamed = true; + } + + private void SetPINGA(PKM pk, EncounterCriteria criteria) + { + var pi = PersonalTable.AO.GetFormeEntry(Species, Form); + pk.Nature = (int)criteria.GetNature((Nature)Nature); + pk.Gender = criteria.GetGender(Gender, pi); + var av = GetAbilityIndex(criteria, pi); + pk.RefreshAbility(av); + SetPID(pk); + SetIVs(pk); + } + + private int GetAbilityIndex(EncounterCriteria criteria, PersonalInfo pi) + { switch (AbilityType) { case 00: // 0 - 0 case 01: // 1 - 1 case 02: // 2 - H - av = AbilityType; - break; + return AbilityType; case 03: // 0/1 case 04: // 0/1/H - av = Util.Rand.Next(AbilityType - 1); - break; + return criteria.GetAbility(AbilityType, pi); // 3 or 2 + default: + throw new ArgumentException(nameof(AbilityType)); } - pk.Ability = pi.Abilities[av]; - pk.AbilityNumber = 1 << av; + } + private void SetPID(PKM pk) + { switch (PIDType) { case Shiny.FixedValue: // Specified @@ -439,18 +451,26 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) if (pk.IsShiny) pk.PID ^= 0x10000000; break; } + } - if (IsEgg) + private void SetIVs(PKM pk) + { + int[] finalIVs = new int[6]; + var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3); + if (ivflag == 0) // Random IVs { - pk.IsEgg = true; - pk.EggMetDate = Date; - pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); - pk.IsNicknamed = true; + for (int i = 0; i < 6; i++) + finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; } - pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; - - pk.RefreshChecksum(); - return pk; + else // 1/2/3 perfect IVs + { + int IVCount = ivflag - 0xFB; + do { finalIVs[Util.Rand.Next(6)] = 31; } + while (finalIVs.Count(iv => iv == 31) < IVCount); + for (int i = 0; i < 6; i++) + finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1); + } + pk.IVs = finalIVs; } protected override bool IsMatchExact(PKM pkm, IEnumerable vs) diff --git a/PKHeX.Core/MysteryGifts/WC7.cs b/PKHeX.Core/MysteryGifts/WC7.cs index ebe3358ff..f559d0b8d 100644 --- a/PKHeX.Core/MysteryGifts/WC7.cs +++ b/PKHeX.Core/MysteryGifts/WC7.cs @@ -341,8 +341,6 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) TID = TID, SID = SID, Met_Level = metLevel, - Nature = Nature != -1 ? Nature : Util.Rand.Next(25), - Gender = Gender != 3 ? Gender : pi.RandomGender, AltForm = Form, EncryptionConstant = EncryptionConstant != 0 ? EncryptionConstant : Util.Rand32(), Version = OriginGame != 0 ? OriginGame : SAV.Game, @@ -399,6 +397,7 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) EVs = EVs, }; + pk.SetMaximumPPCurrent(); if ((SAV.Generation > Format && OriginGame == 0) || !CanBeReceivedByVersion(pk.Version)) { @@ -407,8 +406,6 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) while (!CanBeReceivedByVersion(pk.Version)); } - pk.SetMaximumPPCurrent(); - if (OTGender == 3) { pk.TID = SAV.TID; @@ -420,39 +417,53 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) pk.IsNicknamed = IsNicknamed; pk.Nickname = IsNicknamed ? Nickname : PKX.GetSpeciesNameGeneration(Species, pk.Language, Format); - int[] finalIVs = new int[6]; - var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3); - if (ivflag == 0) // Random IVs - { - for (int i = 0; i < 6; i++) - finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; - } - else // 1/2/3 perfect IVs - { - int IVCount = ivflag - 0xFB; - do { finalIVs[Util.Rand.Next(6)] = 31; } - while (finalIVs.Count(iv => iv == 31) < IVCount); - for (int i = 0; i < 6; i++) - finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1); - } - pk.IVs = finalIVs; + SetPINGA(pk, criteria); - int av = 0; + if (IsEgg) + SetEggMetData(pk); + pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; + + pk.RefreshChecksum(); + return pk; + } + + private void SetEggMetData(PKM pk) + { + pk.IsEgg = true; + pk.EggMetDate = Date; + pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); + pk.IsNicknamed = true; + } + + private void SetPINGA(PKM pk, EncounterCriteria criteria) + { + var pi = PersonalTable.USUM.GetFormeEntry(Species, Form); + pk.Nature = (int)criteria.GetNature((Nature)Nature); + pk.Gender = criteria.GetGender(Gender, pi); + var av = GetAbilityIndex(criteria, pi); + pk.RefreshAbility(av); + SetPID(pk); + SetIVs(pk); + } + + private int GetAbilityIndex(EncounterCriteria criteria, PersonalInfo pi) + { switch (AbilityType) { case 00: // 0 - 0 case 01: // 1 - 1 case 02: // 2 - H - av = AbilityType; - break; + return AbilityType; case 03: // 0/1 case 04: // 0/1/H - av = Util.Rand.Next(AbilityType - 1); - break; + return criteria.GetAbility(AbilityType, pi); // 3 or 2 + default: + throw new ArgumentException(nameof(AbilityType)); } - pk.Ability = pi.Abilities[av]; - pk.AbilityNumber = 1 << av; + } + private void SetPID(PKM pk) + { switch (PIDType) { case Shiny.FixedValue: // Specified @@ -470,18 +481,26 @@ public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) if (pk.IsShiny) pk.PID ^= 0x10000000; break; } + } - if (IsEgg) + private void SetIVs(PKM pk) + { + int[] finalIVs = new int[6]; + var ivflag = Array.Find(IVs, iv => (byte)(iv - 0xFC) < 3); + if (ivflag == 0) // Random IVs { - pk.IsEgg = true; - pk.EggMetDate = Date; - pk.Nickname = PKX.GetSpeciesNameGeneration(0, pk.Language, Format); - pk.IsNicknamed = true; + for (int i = 0; i < 6; i++) + finalIVs[i] = IVs[i] > 31 ? Util.Rand.Next(pk.MaxIV + 1) : IVs[i]; } - pk.CurrentFriendship = pk.IsEgg ? pi.HatchCycles : pi.BaseFriendship; - - pk.RefreshChecksum(); - return pk; + else // 1/2/3 perfect IVs + { + int IVCount = ivflag - 0xFB; + do { finalIVs[Util.Rand.Next(6)] = 31; } + while (finalIVs.Count(iv => iv == 31) < IVCount); + for (int i = 0; i < 6; i++) + finalIVs[i] = finalIVs[i] == 31 ? pk.MaxIV : Util.Rand.Next(pk.MaxIV + 1); + } + pk.IVs = finalIVs; } public bool IsAshGreninjaWC7(PKM pkm)