From 78ff441e8b04d010fb68502d211e435cc05e8208 Mon Sep 17 00:00:00 2001 From: Kurt Date: Sat, 29 Dec 2018 22:24:34 -0800 Subject: [PATCH] Update iencounterable api with new criteria arg rearrange some logic for clearer function (extract some methods) --- .../Legality/Encounters/EncounterEgg.cs | 82 +++++---- .../Legality/Encounters/EncounterInvalid.cs | 5 +- .../Legality/Encounters/EncounterLink.cs | 31 +++- .../Legality/Encounters/EncounterRejected.cs | 5 +- .../Legality/Encounters/EncounterSlot.cs | 158 +++++++++--------- .../Legality/Encounters/EncounterSlot1.cs | 2 +- .../Legality/Encounters/EncounterSlotMoves.cs | 2 +- .../Encounters/EncounterSlotPermissions.cs | 19 +++ .../Legality/Encounters/EncounterStatic.cs | 33 ++-- .../Legality/Encounters/EncounterStaticPID.cs | 2 +- .../Encounters/EncounterStaticShadow.cs | 2 +- .../Encounters/EncounterStaticTyped.cs | 2 +- .../Legality/Encounters/EncounterTrade.cs | 134 +++++++++------ .../Encounters/EncounterTradeCatchRate.cs | 2 +- .../Legality/Encounters/EncounterTradePID.cs | 2 +- PKHeX.Core/Legality/Encounters/LegalInfo.cs | 2 +- .../Legality/Structures/IEncounterable.cs | 1 + PKHeX.Core/MysteryGifts/MysteryGift.cs | 3 +- PKHeX.Core/MysteryGifts/PCD.cs | 4 +- PKHeX.Core/MysteryGifts/PGF.cs | 2 +- PKHeX.Core/MysteryGifts/PGT.cs | 2 +- PKHeX.Core/MysteryGifts/WB7.cs | 10 +- PKHeX.Core/MysteryGifts/WC3.cs | 46 +++-- PKHeX.Core/MysteryGifts/WC6.cs | 2 +- PKHeX.Core/MysteryGifts/WC7.cs | 2 +- 25 files changed, 316 insertions(+), 239 deletions(-) create mode 100644 PKHeX.Core/Legality/Encounters/EncounterSlotPermissions.cs diff --git a/PKHeX.Core/Legality/Encounters/EncounterEgg.cs b/PKHeX.Core/Legality/Encounters/EncounterEgg.cs index 5bad6b694..be2a294ad 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterEgg.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterEgg.cs @@ -17,7 +17,9 @@ public class EncounterEgg : IEncounterable, IVersion public GameVersion Version { get; set; } - public PKM ConvertToPKM(ITrainerInfo SAV) + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + + public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { int gen = Version.GetGeneration(); if (gen < 2) @@ -26,12 +28,14 @@ public PKM ConvertToPKM(ITrainerInfo SAV) Version = GameVersion.C; } 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.Ball = 4; int[] moves = GetCurrentEggMoves(pk); pk.Moves = moves; pk.SetMaximumPPCurrent(moves); @@ -42,16 +46,48 @@ public PKM ConvertToPKM(ITrainerInfo SAV) if (pk.Format <= 2 && Version != GameVersion.C) return pk; - pk.Met_Level = EncounterSuggestion.GetSuggestedEncounterEggMetLevel(pk); - pk.Met_Location = Math.Max(0, EncounterSuggestion.GetSuggestedEggMetLocation(pk)); + SetMetData(pk); if (pk.Format < 3) return pk; - pk.Ball = 4; + SetNatureGenderAbility(pk, criteria); - int gender = pk.PersonalInfo.RandomGender; - int nature = Util.Rand.Next(25); + if (pk.GenNumber >= 4) + pk.SetEggMetData(Version, (GameVersion)SAV.Game); + + if (pk.Format < 6) + return pk; + if (pk.Gen6) + pk.SetHatchMemory6(); + + SetAltForm(pk, SAV); + + pk.SetRandomEC(); + pk.RelearnMoves = moves; + + return pk; + } + + private void SetAltForm(PKM pk, ITrainerInfo SAV) + { + switch (Species) + { + case 774: // Minior + pk.AltForm = Util.Rand.Next(7, 14); + break; + case 664: // Scatterbug + case 665: + case 666: + pk.AltForm = Legal.GetVivillonPattern(SAV.Country, SAV.SubRegion); + break; + } + } + + private static void SetNatureGenderAbility(PKM pk, EncounterCriteria criteria) + { + int gender = criteria.GetGender(-1, pk.PersonalInfo); + int nature = (int)criteria.GetNature(Nature.Random); if (pk.Format <= 5) { @@ -68,34 +104,12 @@ public PKM ConvertToPKM(ITrainerInfo SAV) pk.Gender = gender; pk.RefreshAbility(Util.Rand.Next(2)); } + } - bool traded = (int)Version == SAV.Game; - var today = pk.MetDate = DateTime.Today; - if (pk.GenNumber >= 4) - { - pk.Egg_Location = EncounterSuggestion.GetSuggestedEncounterEggLocationEgg(pk, traded); - pk.EggMetDate = today; - } - - if (pk.Format < 6) - return pk; - if (pk.Gen6) - pk.SetHatchMemory6(); - - switch (Species) - { - case 774: // Minior - pk.AltForm = Util.Rand.Next(7, 14); - break; - case 664: // Scatterbug - pk.AltForm = Legal.GetVivillonPattern(SAV.Country, SAV.SubRegion); - break; - } - - pk.SetRandomEC(); - pk.RelearnMoves = moves; - - return pk; + private static void SetMetData(PKM pk) + { + pk.Met_Level = EncounterSuggestion.GetSuggestedEncounterEggMetLevel(pk); + pk.Met_Location = Math.Max(0, EncounterSuggestion.GetSuggestedEggMetLocation(pk)); } private int[] GetCurrentEggMoves(PKM pk) @@ -112,7 +126,7 @@ private int[] GetCurrentEggMoves(PKM pk) } } - public class EncounterEggSplit : EncounterEgg + public sealed class EncounterEggSplit : EncounterEgg { public int OtherSpecies; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs b/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs index e65e3cd89..c30737fff 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterInvalid.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core /// /// Invalid Encounter Data /// - public class EncounterInvalid : IEncounterable + public sealed class EncounterInvalid : IEncounterable { public int Species { get; } public int LevelMin { get; } @@ -22,6 +22,7 @@ public EncounterInvalid(PKM pkm) EggEncounter = pkm.WasEgg; } - public PKM ConvertToPKM(ITrainerInfo SAV) => throw new ArgumentException($"Cannot convert an {nameof(EncounterInvalid)} to PKM."); + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) => throw new ArgumentException($"Cannot convert an {nameof(EncounterInvalid)} to PKM."); } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterLink.cs b/PKHeX.Core/Legality/Encounters/EncounterLink.cs index 432b7188f..9720fb89d 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterLink.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterLink.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core /// /// Pokémon Link Encounter Data /// - public class EncounterLink : IEncounterable, IRibbonSetEvent4, IMoveset, ILocation, IVersion + public sealed class EncounterLink : IEncounterable, IRibbonSetEvent4, IMoveset, ILocation, IVersion { public int Species { get; set; } public int Level { get; set; } @@ -37,7 +37,9 @@ public class EncounterLink : IEncounterable, IRibbonSetEvent4, IMoveset, ILocati public bool RibbonChampionWorld { get; set; } public bool RibbonSouvenir { get; set; } - public PKM ConvertToPKM(ITrainerInfo SAV) + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + + public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { const int gen = 6; var version = this.GetCompatibleVersion((GameVersion)SAV.Game); @@ -52,21 +54,21 @@ public PKM ConvertToPKM(ITrainerInfo SAV) PID = Util.Rand32(), Nickname = PKX.GetSpeciesNameGeneration(Species, lang, gen), Ball = Ball, - Met_Level = Level, - Met_Location = Location, - MetDate = DateTime.Today }; SAV.ApplyToPKM(pk); + SetMetData(pk); + SetNatureGender(pk, criteria); + pk.RefreshAbility(Ability >> 1); + pk.SetRandomIVs(flawless: 3); + pk.Version = (int)version; - pk.Gender = pk.PersonalInfo.RandomGender; pk.Language = lang; pk.Moves = Moves; pk.SetMaximumPPCurrent(Moves); pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; - pk.SetRandomIVs(flawless: 3); - pk.RefreshAbility(Ability >> 1); + if (RelearnMoves.Length > 0) pk.RelearnMoves = RelearnMoves; if (RibbonClassic) @@ -78,5 +80,18 @@ public PKM ConvertToPKM(ITrainerInfo SAV) return pk; } + + private static void SetNatureGender(PKM pk, EncounterCriteria criteria) + { + pk.Nature = (int)criteria.GetNature(Nature.Random); + pk.Gender = criteria.GetGender(-1, pk.PersonalInfo); + } + + private void SetMetData(PKM pk) + { + pk.MetDate = DateTime.Today; + pk.Met_Level = Level; + pk.Met_Location = Location; + } } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterRejected.cs b/PKHeX.Core/Legality/Encounters/EncounterRejected.cs index 70cd1bf3b..c90e6e32a 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterRejected.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterRejected.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core /// /// Rejected Encounter Data containing a reason why the encounter was rejected (not compatible). /// - public class EncounterRejected : IEncounterable + public sealed class EncounterRejected : IEncounterable { public readonly IEncounterable Encounter; public readonly CheckResult Check; @@ -23,6 +23,7 @@ public EncounterRejected(IEncounterable encounter, CheckResult check) Check = check; } - public PKM ConvertToPKM(ITrainerInfo SAV) => throw new ArgumentException($"Cannot convert an {nameof(EncounterRejected)} to PKM."); + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) => throw new ArgumentException($"Cannot convert an {nameof(EncounterRejected)} to PKM."); } } \ No newline at end of file diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot.cs index 9fb53c3ac..7577b9ad5 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot.cs @@ -2,23 +2,6 @@ namespace PKHeX.Core { - public class EncounterSlotPermissions - { - public int StaticIndex { get; set; } = -1; - public int MagnetPullIndex { get; set; } = -1; - public int StaticCount { get; set; } - public int MagnetPullCount { get; set; } - - public bool AllowDexNav { get; set; } - public bool Pressure { get; set; } - public bool DexNav { get; set; } - public bool WhiteFlute { get; set; } - public bool BlackFlute { get; set; } - public bool IsNormalLead => !(WhiteFlute || BlackFlute || DexNav); - public bool IsDexNav => AllowDexNav && DexNav; - public EncounterSlotPermissions Clone() => (EncounterSlotPermissions)MemberwiseClone(); - } - /// /// Wild Encounter Slot data /// @@ -65,80 +48,35 @@ public string Name } } - public PKM ConvertToPKM(ITrainerInfo SAV) + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + + public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { var version = this.GetCompatibleVersion((GameVersion)SAV.Game); int lang = (int)Legal.GetSafeLanguage(Generation, (LanguageID)SAV.Language); int level = LevelMin; var pk = PKMConverter.GetBlank(Generation, Version); - int nature = Util.Rand.Next(25); SAV.ApplyToPKM(pk); pk.Species = Species; - int gender = pk.PersonalInfo.RandomGender; pk.Language = lang; pk.CurrentLevel = level; pk.Version = (int)version; pk.Nickname = PKX.GetSpeciesNameGeneration(Species, lang, Generation); - pk.Ball = GetBall(); - pk.AltForm = GetWildAltForm(Form, pk, SAV); - - if (pk.Format > 2 || Version == GameVersion.C) - { - pk.Met_Location = Location; - pk.Met_Level = level; - if (Version == GameVersion.C && pk is PK2 pk2 && this is EncounterSlot1 slot) - pk2.Met_TimeOfDay = slot.Time.RandomValidTime(); - - if (pk.Format >= 4) - pk.MetDate = DateTime.Today; - } + pk.Ball = (int)Type.GetBall(); pk.Language = lang; + pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; + pk.AltForm = GetWildAltForm(pk, Form, SAV); - var ability = Util.Rand.Next(2); - var pidtype = GetPIDType(); - if (pidtype == PIDType.PokeSpot) - PIDGenerator.SetRandomPokeSpotPID(pk, nature, gender, ability, SlotNumber); - else - PIDGenerator.SetRandomWildPID(pk, pk.Format, nature, ability, gender, pidtype); + SetMetData(pk, level, Location); + SetNatureGenderAbility(pk, criteria); - if (Permissions.IsDexNav) - { - pk.RefreshAbility(2); - var eggMoves = MoveEgg.GetEggMoves(pk, Species, pk.AltForm, Version); - if (eggMoves.Length > 0) - pk.RelearnMove1 = eggMoves[Util.Rand.Next(eggMoves.Length)]; - } - - switch (pk.Format) - { - case 1 when Species == 64 && Version == GameVersion.YW: // Kadabra - ((PK1)pk).Catch_Rate = 96; - break; - case 1 when Species == 148 && Version == GameVersion.YW: // Dragonair - ((PK1)pk).Catch_Rate = 27; - break; - case 3: - case 4: - if (pk.Format == 4) - pk.EncounterType = TypeEncounter.GetIndex(); - pk.Gender = gender; - break; - case 5: - if (Type == SlotType.HiddenGrotto) - pk.RefreshAbility(2); - break; - case 6: - pk.SetRandomMemory6(); - break; - } + SetFormatSpecificData(pk); var moves = this is EncounterSlotMoves m ? m.Moves : MoveLevelUp.GetEncounterMoves(pk, level, version); - if (Version == GameVersion.XD) - pk.FatefulEncounter = true; pk.Moves = moves; pk.SetMaximumPPCurrent(moves); - pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; + if (pk.Format < 6) return pk; @@ -148,7 +86,72 @@ public PKM ConvertToPKM(ITrainerInfo SAV) return pk; } - private static int GetWildAltForm(int form, PKM pk, ITrainerInfo SAV) + private void SetFormatSpecificData(PKM pk) + { + if (pk is PK1 pk1) + { + if (Species == 64 && Version == GameVersion.YW) // Kadabra + pk1.Catch_Rate = 96; + else if (Species == 148 && Version == GameVersion.YW) // Dragonair + pk1.Catch_Rate = 27; + else + pk1.Catch_Rate = PersonalTable.RB[Species].CatchRate; // RB + } + else if (pk is PK2 pk2) + { + if (Version == GameVersion.C && this is EncounterSlot1 slot) + pk2.Met_TimeOfDay = slot.Time.RandomValidTime(); + } + else if (pk is XK3 xk3) + { + xk3.FatefulEncounter = true; // PokeSpot + } + else if (pk is PK4 pk4) + { + pk4.EncounterType = TypeEncounter.GetIndex(); + } + else if (pk is PK6 pk6) + { + if (Permissions.IsDexNav) + { + var eggMoves = MoveEgg.GetEggMoves(pk, Species, pk.AltForm, Version); + if (eggMoves.Length > 0) + pk6.RelearnMove1 = eggMoves[Util.Rand.Next(eggMoves.Length)]; + } + pk.SetRandomMemory6(); + } + } + + private void SetNatureGenderAbility(PKM pk, EncounterCriteria criteria) + { + int gender = criteria.GetGender(-1, pk.PersonalInfo); + int nature = (int)criteria.GetNature(Nature.Random); + + var ability = Util.Rand.Next(2); + if (Type == SlotType.HiddenGrotto) // don't force hidden for DexNav + ability = 2; + + var pidtype = GetPIDType(); + if (pidtype == PIDType.PokeSpot) + PIDGenerator.SetRandomPokeSpotPID(pk, nature, gender, ability, SlotNumber); + else + PIDGenerator.SetRandomWildPID(pk, pk.Format, nature, ability, gender, pidtype); + pk.Gender = gender; + } + + private void SetMetData(PKM pk, int level, int location) + { + if (pk.Format <= 2 && Version != GameVersion.C) + return; + + pk.Met_Location = location; + pk.Met_Level = level; + + if (pk.Format >= 4) + pk.MetDate = DateTime.Today; + } + + private static int GetWildAltForm(PKM pk, int form, ITrainerInfo SAV) { if (form < 30) { @@ -171,14 +174,5 @@ private PIDType GetPIDType() return PIDType.PokeSpot; return PIDType.None; // depends on format, let the program auto-detect. } - - private int GetBall() - { - if (Type == SlotType.BugContest) - return 24; // Sport - if (Type.IsSafariType()) - return 5; // Safari - return 4; // Poké Ball - } } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlot1.cs b/PKHeX.Core/Legality/Encounters/EncounterSlot1.cs index 6bc64c828..9a5f2ab89 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlot1.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlot1.cs @@ -7,7 +7,7 @@ /// Contains Time data which is present in origin data. /// Contains identification, as this Version value is not stored in or formats. /// - internal class EncounterSlot1 : EncounterSlot + internal sealed class EncounterSlot1 : EncounterSlot { public int Rate; internal EncounterTime Time; diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlotMoves.cs b/PKHeX.Core/Legality/Encounters/EncounterSlotMoves.cs index e387be192..0d7890986 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterSlotMoves.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterSlotMoves.cs @@ -1,6 +1,6 @@ namespace PKHeX.Core { - internal class EncounterSlotMoves : EncounterSlot, IMoveset + internal sealed class EncounterSlotMoves : EncounterSlot, IMoveset { public int[] Moves { get; set; } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterSlotPermissions.cs b/PKHeX.Core/Legality/Encounters/EncounterSlotPermissions.cs new file mode 100644 index 000000000..dc6fb6f27 --- /dev/null +++ b/PKHeX.Core/Legality/Encounters/EncounterSlotPermissions.cs @@ -0,0 +1,19 @@ +namespace PKHeX.Core +{ + public sealed class EncounterSlotPermissions + { + public int StaticIndex { get; set; } = -1; + public int MagnetPullIndex { get; set; } = -1; + public int StaticCount { get; set; } + public int MagnetPullCount { get; set; } + + public bool AllowDexNav { get; set; } + public bool Pressure { get; set; } + public bool DexNav { get; set; } + public bool WhiteFlute { get; set; } + public bool BlackFlute { get; set; } + public bool IsNormalLead => !(WhiteFlute || BlackFlute || DexNav); + public bool IsDexNav => AllowDexNav && DexNav; + public EncounterSlotPermissions Clone() => (EncounterSlotPermissions)MemberwiseClone(); + } +} \ No newline at end of file diff --git a/PKHeX.Core/Legality/Encounters/EncounterStatic.cs b/PKHeX.Core/Legality/Encounters/EncounterStatic.cs index ab6cd4610..77bf08c3f 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStatic.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStatic.cs @@ -68,7 +68,9 @@ internal virtual EncounterStatic Clone() private const string _name = "Static Encounter"; public string Name => Version == GameVersion.Any ? _name : $"{_name} ({Version})"; - public PKM ConvertToPKM(ITrainerInfo SAV) + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + + public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { var version = this.GetCompatibleVersion((GameVersion)SAV.Game); SanityCheckVersion(ref version); @@ -88,6 +90,9 @@ public PKM ConvertToPKM(ITrainerInfo SAV) 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) { @@ -99,11 +104,13 @@ public PKM ConvertToPKM(ITrainerInfo SAV) if (pk.Format >= 4) pk.MetDate = DateTime.Today; } + if (EggEncounter) { - bool traded = (int)Version == SAV.Game; pk.Met_Location = Math.Max(0, EncounterSuggestion.GetSuggestedEggMetLocation(pk)); pk.Met_Level = EncounterSuggestion.GetSuggestedEncounterEggMetLevel(pk); + + bool traded = (int)Version == SAV.Game; if (pk.GenNumber >= 4) { pk.Egg_Location = EncounterSuggestion.GetSuggestedEncounterEggLocationEgg(pk, traded); @@ -113,8 +120,6 @@ public PKM ConvertToPKM(ITrainerInfo SAV) pk.EggMetDate = today; } - pk.AltForm = Form; - if (this is EncounterStaticPID p) { pk.PID = p.PID; @@ -142,18 +147,16 @@ public PKM ConvertToPKM(ITrainerInfo SAV) SetIVs(pk); } - switch (pk.Format) + switch (pk) { - case 3: - if (this is EncounterStaticShadow) - ((PK3)pk).RibbonNational = true; + case PK3 pk3 when this is EncounterStaticShadow: + pk3.RibbonNational = true; break; - case 4: - if (this is EncounterStaticTyped t) - pk.EncounterType = t.TypeEncounter.GetIndex(); + case PK4 pk4 when this is EncounterStaticTyped t: + pk4.EncounterType = t.TypeEncounter.GetIndex(); break; - case 6: - pk.SetRandomMemory6(); + case PK6 pk6: + pk6.SetRandomMemory6(); break; } @@ -161,12 +164,10 @@ public PKM ConvertToPKM(ITrainerInfo SAV) this.CopyContestStatsTo(s); var moves = Moves ?? MoveLevelUp.GetEncounterMoves(pk, level, version); - pk.HeldItem = HeldItem; pk.Moves = moves; pk.SetMaximumPPCurrent(moves); if (pk.Format >= 6 && Relearn.Length > 0) pk.RelearnMoves = Relearn; - pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; if (Fateful) pk.FatefulEncounter = true; @@ -347,7 +348,7 @@ public bool IsMatch(PKM pkm, int lvl) { for (int i = 0; i < 6; i++) { - if (IVs[i] != -1 && IVs[i] != pkm.IVs[i]) + if (IVs[i] != -1 && IVs[i] != pkm.GetIV(i)) return false; } } diff --git a/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs b/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs index cab084fec..716e95f09 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStaticPID.cs @@ -1,6 +1,6 @@ namespace PKHeX.Core { - internal class EncounterStaticPID : EncounterStatic + internal sealed class EncounterStaticPID : EncounterStatic { public uint PID { get; set; } public bool NSparkle { get; set; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs b/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs index 9b918b8fd..dee6de8c0 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStaticShadow.cs @@ -2,7 +2,7 @@ namespace PKHeX.Core { - public class EncounterStaticShadow : EncounterStatic + public sealed class EncounterStaticShadow : EncounterStatic { public TeamLock[] Locks { get; internal set; } = Array.Empty(); public int Gauge { get; internal set; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterStaticTyped.cs b/PKHeX.Core/Legality/Encounters/EncounterStaticTyped.cs index c6f3bdb38..e4403928a 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterStaticTyped.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterStaticTyped.cs @@ -1,6 +1,6 @@ namespace PKHeX.Core { - public class EncounterStaticTyped : EncounterStatic + public sealed class EncounterStaticTyped : EncounterStatic { public EncounterType TypeEncounter { get; internal set; } = EncounterType.None; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterTrade.cs b/PKHeX.Core/Legality/Encounters/EncounterTrade.cs index 3a6793361..b54f6cacc 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTrade.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTrade.cs @@ -25,13 +25,6 @@ public class EncounterTrade : IEncounterable, IMoveset, IGeneration, ILocation, public int SID { get; set; } public GameVersion Version { get; set; } = GameVersion.Any; public int[] IVs { get; set; } - public int[] Contest { set => this.SetContestStats(value); } - public int CNT_Cool { get; set; } - public int CNT_Beauty { get; set; } - public int CNT_Cute { get; set; } - public int CNT_Smart { get; set; } - public int CNT_Tough { get; set; } - public int CNT_Sheen { get; set; } public int Form { get; set; } public virtual Shiny Shiny { get; set; } = Shiny.Never; public int Gender { get; set; } = -1; @@ -42,6 +35,14 @@ public class EncounterTrade : IEncounterable, IMoveset, IGeneration, ILocation, public int Ball { get; set; } = 4; public int CurrentLevel { get; set; } = -1; + public int[] Contest { set => this.SetContestStats(value); } + public int CNT_Cool { get; set; } + public int CNT_Beauty { get; set; } + public int CNT_Cute { get; set; } + public int CNT_Smart { get; set; } + public int CNT_Tough { get; set; } + public int CNT_Sheen { get; set; } + public int TID7 { set @@ -67,67 +68,51 @@ public int TID7 0, 126, 254, 2001, 30002, 30001, 30001, }; - public PKM ConvertToPKM(ITrainerInfo SAV) + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + + public PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { + var pk = PKMConverter.GetBlank(Generation, Version); 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 - var pk = PKMConverter.GetBlank(Generation, Version); - - pk.EncryptionConstant = Util.Rand32(); - pk.Species = Species; - pk.CurrentLevel = level; - int gender = Gender < 0 ? pk.PersonalInfo.RandomGender : Gender; - int nature = Nature == Nature.Random ? Util.Rand.Next(25) : (int)Nature; SAV.ApplyToPKM(pk); - pk.Nature = nature; + + int species = Species; + if (EvolveOnTrade) + species++; + + pk.EncryptionConstant = Util.Rand32(); + pk.Species = species; + pk.CurrentLevel = level; pk.Version = (int)version; pk.AltForm = Form; - - if (this is EncounterTradePID p) - { - pk.PID = p.PID; - pk.Gender = PKX.GetGenderFromPID(Species, p.PID); - pk.RefreshAbility(Ability >> 1); - } - else - { - int ability = Ability >> 1; - PIDGenerator.SetRandomWildPID(pk, Generation, nature, ability, gender); - pk.Gender = gender; - pk.RefreshAbility(ability); - } pk.Ball = Ball; - if (pk.Format != 2 || version == GameVersion.C) - { - pk.Met_Level = level; - pk.Met_Location = Location > 0 ? Location : DefaultMetLocation[Generation - 1]; - } - var today = DateTime.Today; - pk.MetDate = today; - if (EggLocation != 0) - { - pk.Egg_Location = EggLocation; - pk.EggMetDate = today; - } - 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.OT_Friendship = pk.PersonalInfo.BaseFriendship; + + SetNatureGenderAbility(pk, criteria); if (IVs != null) pk.SetRandomIVs(IVs, 0); else pk.SetRandomIVs(flawless: 3); - if (pk.Format == 6) - pk.SetRandomMemory6(); + if (pk.Format != 2 || version == GameVersion.C) + { + var location = Location > 0 ? Location : DefaultMetLocation[Generation - 1]; + SetMetData(pk, level, location); + } + if (EggLocation != 0) + SetEggMetData(pk); if (pk is PK1 pk1 && this is EncounterTradeCatchRate c) pk1.Catch_Rate = (int)c.Catch_Rate; @@ -135,32 +120,71 @@ public PKM ConvertToPKM(ITrainerInfo SAV) if (pk is IContestStats s) this.CopyContestStatsTo(s); - var moves = Moves ?? MoveLevelUp.GetEncounterMoves(pk, level, version); - if (pk.Format == 1 && moves.All(z => z == 0)) - moves = ((PersonalInfoG1)PersonalTable.RB[Species]).Moves; - pk.Moves = moves; - pk.SetMaximumPPCurrent(moves); - pk.OT_Friendship = pk.PersonalInfo.BaseFriendship; + SetMoves(pk, version, level); + if (Fateful) pk.FatefulEncounter = true; UpdateEdgeCase(pk); - if (EvolveOnTrade) - ++pk.Species; - if (pk.Format < 6) return pk; SAV.ApplyHandlingTrainerInfo(pk, force: true); pk.SetRandomEC(); - if (pk.Format == 7) + if (pk.Format == 6) + pk.SetRandomMemory6(); + else if (pk.Format == 7) SetSMOTMemory(pk); return pk; } + private void SetNatureGenderAbility(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); + } + else + { + PIDGenerator.SetRandomWildPID(pk, Generation, nature, ability, gender); + pk.Nature = nature; + pk.Gender = gender; + pk.RefreshAbility(ability); + } + } + + private void SetMoves(PKM pk, GameVersion version, int level) + { + var moves = Moves ?? MoveLevelUp.GetEncounterMoves(pk, level, version); + if (pk.Format == 1 && moves.All(z => z == 0)) + moves = ((PersonalInfoG1)PersonalTable.RB[Species]).Moves; + pk.Moves = moves; + pk.SetMaximumPPCurrent(moves); + } + + private void SetEggMetData(PKM pk) + { + pk.Egg_Location = EggLocation; + pk.EggMetDate = DateTime.Today; + } + + private static void SetMetData(PKM pk, int level, int location) + { + pk.Met_Level = level; + pk.Met_Location = location; + pk.MetDate = DateTime.Today; + } + private void UpdateEdgeCase(PKM pkm) { switch (Generation) diff --git a/PKHeX.Core/Legality/Encounters/EncounterTradeCatchRate.cs b/PKHeX.Core/Legality/Encounters/EncounterTradeCatchRate.cs index 926827caf..0af0dc180 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTradeCatchRate.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTradeCatchRate.cs @@ -6,7 +6,7 @@ /// /// Generation 1 specific value used in detecting unmodified/untraded Generation 1 Trade Encounter data. /// - public class EncounterTradeCatchRate : EncounterTrade + public sealed class EncounterTradeCatchRate : EncounterTrade { public uint Catch_Rate; } diff --git a/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs b/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs index ba0238508..90c452989 100644 --- a/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs +++ b/PKHeX.Core/Legality/Encounters/EncounterTradePID.cs @@ -3,7 +3,7 @@ /// /// Trade Encounter data with a fixed PID. /// - public class EncounterTradePID : EncounterTrade + public sealed class EncounterTradePID : EncounterTrade { public uint PID; public override Shiny Shiny { get; set; } = Shiny.FixedValue; diff --git a/PKHeX.Core/Legality/Encounters/LegalInfo.cs b/PKHeX.Core/Legality/Encounters/LegalInfo.cs index 9020d0684..b62f761db 100644 --- a/PKHeX.Core/Legality/Encounters/LegalInfo.cs +++ b/PKHeX.Core/Legality/Encounters/LegalInfo.cs @@ -5,7 +5,7 @@ namespace PKHeX.Core /// /// Calculated Information storage with properties useful for parsing the legality of the input . /// - public class LegalInfo + public sealed class LegalInfo { /// The object used for comparisons. private readonly PKM pkm; diff --git a/PKHeX.Core/Legality/Structures/IEncounterable.cs b/PKHeX.Core/Legality/Structures/IEncounterable.cs index 683dd1691..b336acd08 100644 --- a/PKHeX.Core/Legality/Structures/IEncounterable.cs +++ b/PKHeX.Core/Legality/Structures/IEncounterable.cs @@ -12,6 +12,7 @@ public interface IEncounterable int LevelMax { get; } PKM ConvertToPKM(ITrainerInfo SAV); + PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria); } public static partial class Extensions diff --git a/PKHeX.Core/MysteryGifts/MysteryGift.cs b/PKHeX.Core/MysteryGifts/MysteryGift.cs index 6893d746e..03b9c902a 100644 --- a/PKHeX.Core/MysteryGifts/MysteryGift.cs +++ b/PKHeX.Core/MysteryGifts/MysteryGift.cs @@ -82,7 +82,8 @@ public static MysteryGift GetMysteryGift(byte[] data) public byte[] Data { get; set; } public abstract int Format { get; } - public abstract PKM ConvertToPKM(ITrainerInfo SAV); + public PKM ConvertToPKM(ITrainerInfo SAV) => ConvertToPKM(SAV, EncounterCriteria.Unrestricted); + public abstract PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria); protected abstract bool IsMatchExact(PKM pkm, IEnumerable vs); protected abstract bool IsMatchDeferred(PKM pkm); diff --git a/PKHeX.Core/MysteryGifts/PCD.cs b/PKHeX.Core/MysteryGifts/PCD.cs index 825fa3ee1..a76aec861 100644 --- a/PKHeX.Core/MysteryGifts/PCD.cs +++ b/PKHeX.Core/MysteryGifts/PCD.cs @@ -126,9 +126,9 @@ public bool GiftEquals(PGT pgt) return true; } - public override PKM ConvertToPKM(ITrainerInfo SAV) + public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { - return Gift.ConvertToPKM(SAV); + return Gift.ConvertToPKM(SAV, criteria); } public bool CanBeReceivedBy(int pkmVersion) => (CardCompatibility >> pkmVersion & 1) == 1; diff --git a/PKHeX.Core/MysteryGifts/PGF.cs b/PKHeX.Core/MysteryGifts/PGF.cs index 056b89f9b..5b64f16b5 100644 --- a/PKHeX.Core/MysteryGifts/PGF.cs +++ b/PKHeX.Core/MysteryGifts/PGF.cs @@ -162,7 +162,7 @@ public override int[] IVs public override bool IsItem { get => CardType == 2; set { if (value) CardType = 2; } } public bool IsPower { get => CardType == 3; set { if (value) CardType = 3; } } - public override PKM ConvertToPKM(ITrainerInfo SAV) + public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) return null; diff --git a/PKHeX.Core/MysteryGifts/PGT.cs b/PKHeX.Core/MysteryGifts/PGT.cs index 00bc80297..d8bb57fb9 100644 --- a/PKHeX.Core/MysteryGifts/PGT.cs +++ b/PKHeX.Core/MysteryGifts/PGT.cs @@ -119,7 +119,7 @@ private void EncryptPK() public override int Location { get => PK.Met_Location; set => PK.Met_Location = value; } public override int EggLocation { get => PK.Egg_Location; set => PK.Egg_Location = value; } - public override PKM ConvertToPKM(ITrainerInfo SAV) + public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) return null; diff --git a/PKHeX.Core/MysteryGifts/WB7.cs b/PKHeX.Core/MysteryGifts/WB7.cs index 9993ede07..8805ebf90 100644 --- a/PKHeX.Core/MysteryGifts/WB7.cs +++ b/PKHeX.Core/MysteryGifts/WB7.cs @@ -116,14 +116,6 @@ private uint Day public bool MultiObtain { get => Data[CardStart + 0x53] == 1; set => Data[CardStart + 0x53] = (byte)(value ? 1 : 0); } - // BP Properties - public override bool IsBP { get => CardType == 3; set { if (value) CardType = 3; } } - public override int BP { get => ItemID; set => ItemID = value; } - - // Bean (Mame) Properties - public override bool IsBean { get => CardType == 2; set { if (value) CardType = 2; } } - public override int Bean { get => ItemID; set => ItemID = value; } - // Item Properties public override bool IsItem { get => CardType == 1; set { if (value) CardType = 1; } } public override int ItemID { get => BitConverter.ToUInt16(Data, CardStart + 0x68); set => BitConverter.GetBytes((ushort)value).CopyTo(Data, CardStart + 0x68); } @@ -320,7 +312,7 @@ private int GetOTOffset(int language) return 0xEE + (index * 0x1A); } - public override PKM ConvertToPKM(ITrainerInfo SAV) + public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) return null; diff --git a/PKHeX.Core/MysteryGifts/WC3.cs b/PKHeX.Core/MysteryGifts/WC3.cs index 1982638c6..adb33217d 100644 --- a/PKHeX.Core/MysteryGifts/WC3.cs +++ b/PKHeX.Core/MysteryGifts/WC3.cs @@ -70,7 +70,7 @@ public int Met_Level set => _metLevel = value; } - public override PKM ConvertToPKM(ITrainerInfo SAV) + public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { PK3 pk = new PK3 { @@ -151,22 +151,19 @@ public override PKM ConvertToPKM(ITrainerInfo SAV) pk.Nickname = PKX.GetSpeciesNameGeneration(Species, pk.Language, 3); // will be set to Egg nickname if appropriate by PK3 setter // Generate PIDIV - var seed = Util.Rand32(); - switch (Method) - { - case PIDType.BACD_R: - seed &= 0xFFFF; - break; - case PIDType.BACD_R_S: - seed &= 0xFF; - break; - } - PIDGenerator.SetValuesFromSeed(pk, Method, seed); + SetPIDValues(pk); + 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; + } - if (Moves == null || Moves.Length == 0) // not completely defined + private void SetMoves(PK3 pk) + { + if (Moves.Length == 0) // not completely defined Moves = Legal.GetBaseEggMoves(pk, Species, (GameVersion)pk.Version, Level); if (Moves.Length != 4) { @@ -177,9 +174,26 @@ public override PKM ConvertToPKM(ITrainerInfo SAV) pk.Moves = Moves; pk.SetMaximumPPCurrent(Moves); - pk.HeldItem = 0; // clear, only random for Jirachis(?), no loss - pk.RefreshChecksum(); - return pk; + } + + private void SetPIDValues(PK3 pk) + { + var seed = Util.Rand32(); + SetPIDValues(pk, seed); + } + + private void SetPIDValues(PK3 pk, uint seed) + { + switch (Method) + { + case PIDType.BACD_R: + seed &= 0xFFFF; + break; + case PIDType.BACD_R_S: + seed &= 0xFF; + break; + } + 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 55f2ac8ae..154a60418 100644 --- a/PKHeX.Core/MysteryGifts/WC6.cs +++ b/PKHeX.Core/MysteryGifts/WC6.cs @@ -284,7 +284,7 @@ public override int[] RelearnMoves } } - public override PKM ConvertToPKM(ITrainerInfo SAV) + public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) return null; diff --git a/PKHeX.Core/MysteryGifts/WC7.cs b/PKHeX.Core/MysteryGifts/WC7.cs index 68ddbb110..b6c970bac 100644 --- a/PKHeX.Core/MysteryGifts/WC7.cs +++ b/PKHeX.Core/MysteryGifts/WC7.cs @@ -326,7 +326,7 @@ public override int[] RelearnMoves } } - public override PKM ConvertToPKM(ITrainerInfo SAV) + public override PKM ConvertToPKM(ITrainerInfo SAV, EncounterCriteria criteria) { if (!IsPokémon) return null;