diff --git a/PKHeX/Legality/Checks.cs b/PKHeX/Legality/Checks.cs index 2d60aa058..fbec56178 100644 --- a/PKHeX/Legality/Checks.cs +++ b/PKHeX/Legality/Checks.cs @@ -494,7 +494,7 @@ private CheckResult verifyEncounterEvent() private CheckResult verifyEncounterEgg() { // Check Species - if (Legal.NoHatchFromEgg.Contains(pkm.Species)) + if (Legal.NoHatchFromEgg.Contains(pkm.Species) && (pkm.GenNumber != 4 || pkm.Species == 490)) return new CheckResult(Severity.Invalid, V50, CheckIdentifier.Encounter); switch (pkm.GenNumber) @@ -659,6 +659,19 @@ private CheckResult verifyEncounterStatic() { var s = (EncounterStatic)EncounterMatch; + if (pkm.GenNumber == 3 && pkm.Species == 151 && s.Location == 201 && pkm.Language != 1) + { + return new CheckResult(Severity.Invalid, V353, CheckIdentifier.Encounter); + } + if (pkm.GenNumber == 4 && pkm.Species == 493 && s.Location == 086) + { + return new CheckResult(Severity.Invalid, V352, CheckIdentifier.Encounter); + } + if (pkm.GenNumber == 4 && pkm.Species == 492 && s.Location == 063 && pkm.Version != (int)GameVersion.Pt) + { + return new CheckResult(Severity.Invalid, V354, CheckIdentifier.Encounter); + } + // Re-parse relearn moves if (s.EggLocation != 60002 || vRelearn.Any(rl => !rl.Valid)) { @@ -722,6 +735,16 @@ private CheckResult verifyEncounter() if (pkm.WasLink) return verifyEncounterLink(); + if (pkm.Gen3 && !pkm.HasOriginalMetLocation) + { + return verifyEncounterG3Transfer(); + } + + if (pkm.Gen4 && !pkm.HasOriginalMetLocation) + { + return verifyEncounterG4Transfer(); + } + bool wasEvent = pkm.WasEvent || pkm.WasEventEgg; if (wasEvent) { @@ -729,7 +752,7 @@ private CheckResult verifyEncounter() if (result != null) return result; } - + if (null != (EncounterMatch = Legal.getValidStaticEncounter(pkm))) { var result = verifyEncounterStatic(); @@ -738,7 +761,7 @@ private CheckResult verifyEncounter() EncounterMatch = null; // Reset Encounter Object, test for remaining encounters } - + if (pkm.WasEgg) return verifyEncounterEgg(); @@ -755,6 +778,120 @@ private CheckResult verifyEncounter() ? new CheckResult(Severity.Invalid, V78, CheckIdentifier.Encounter) : new CheckResult(Severity.Invalid, V80, CheckIdentifier.Encounter); } + + private CheckResult verifyEncounterG3Transfer() + { + CheckResult InvalidTransferResult = null; + CheckResult EggResult = null; + CheckResult NonEggResult = null; + bool WasEgg = Legal.getWasEgg23(pkm) && !Legal.NoHatchFromEgg.Contains(pkm.Species); + if (WasEgg) + { + pkm.WasEgg = true; + EggResult = verifyEncounterEgg3Transfer(); + if (pkm.IsEgg) + return EggResult; + } + + if (pkm.Format == 4 && pkm.Met_Location != 0x37) // Pal Park + InvalidTransferResult = new CheckResult(Severity.Invalid, V60, CheckIdentifier.Encounter); + if (pkm.Format != 4 && pkm.Met_Location != 30001) + InvalidTransferResult = new CheckResult(Severity.Invalid, V61, CheckIdentifier.Encounter); + + // TODO: Include also gen 3 events + if (null != (EncounterMatch = Legal.getValidStaticEncounter(pkm))) + { + NonEggResult = verifyEncounterStatic(); + } + + if (NonEggResult !=null) + { + EncounterMatch = null; // Reset Encounter Object, test for remaining encounters + if (null != (EncounterMatch = Legal.getValidWildEncounters(pkm))) + NonEggResult = verifyEncounterWild(); + + if (null != (EncounterMatch = Legal.getValidIngameTrade(pkm))) + NonEggResult = verifyEncounterTrade(); + } + + // InvalidTransferResult have preference, because is invalid that from the current generation + if (InvalidTransferResult != null) + return InvalidTransferResult; + + // Even if EggResult is not returned WasEgg is keep true to check in verifymoves first the + // non egg encounter moves and after that egg encounter moves, because there is no way to tell + // what of the two encounters was the real origin + if (EggResult != null && NonEggResult!=null) + { + // InvalidTransferResult have preference, because is invalid data from the current generation + if (NonEggResult.Valid) + return NonEggResult; + if (EggResult.Valid) + return EggResult; + // if both are invalid returns non egg information, because + // there is more data in the pokemon to found normal encounter + return NonEggResult; + } + + // No egg result then it can be from egg, no non egg result then return there is no valid encounter found + if (EggResult == null && NonEggResult == null) + { + return new CheckResult(Severity.Invalid, V80, CheckIdentifier.Encounter); + } + + return NonEggResult ?? InvalidTransferResult; + } + private CheckResult verifyEncounterG4Transfer() + { + CheckResult Gen4Result = null; + CheckResult InvalidTransferResult = null; + + var CrownLocation = -1; + var AllowCrownLocation = pkm.Gen4 && pkm.FatefulEncounter && Legal.CrownBeasts.Contains(pkm.Species); + if (AllowCrownLocation) + CrownLocation = pkm.Species == 251 ? 30010 : 30012; // Celebi : Beast + + if (pkm.Met_Location != 30001 && (!AllowCrownLocation || pkm.Met_Location != CrownLocation)) + InvalidTransferResult = new CheckResult(Severity.Invalid, AllowCrownLocation ? V351 : V61, CheckIdentifier.Encounter); + + bool wasEvent = pkm.WasEvent || pkm.WasEventEgg; + if (wasEvent) + { + var result = verifyEncounterEvent(); + if (result != null) + Gen4Result = result; + } + + if (Gen4Result == null && null != (EncounterMatch = Legal.getValidStaticEncounter(pkm))) + { + var result = verifyEncounterStatic(); + if (result != null) + return result.Valid && InvalidTransferResult != null ? InvalidTransferResult : result; + + EncounterMatch = null; // Reset Encounter Object, test for remaining encounters + } + + if (pkm.WasEgg) // Invalid transfer is already checked in encounter egg + return verifyEncounterEgg(); + + if (Gen4Result == null && null != (EncounterMatch = Legal.getValidFriendSafari(pkm))) + Gen4Result = verifyEncounterSafari(); + + if (Gen4Result == null && null != (EncounterMatch = Legal.getValidWildEncounters(pkm))) + Gen4Result = verifyEncounterWild(); + + if (Gen4Result == null && null != (EncounterMatch = Legal.getValidIngameTrade(pkm))) + Gen4Result = verifyEncounterTrade(); + + if (Gen4Result != null && InvalidTransferResult != null) + return Gen4Result.Valid ? InvalidTransferResult : Gen4Result; + if (Gen4Result != null || InvalidTransferResult != null) + return Gen4Result ?? InvalidTransferResult; + + return wasEvent + ? new CheckResult(Severity.Invalid, V78, CheckIdentifier.Encounter) + : new CheckResult(Severity.Invalid, V80, CheckIdentifier.Encounter); + } private CheckResult verifyVCEncounter(int baseSpecies) { // Sanitize Species to non-future species# @@ -2202,6 +2339,16 @@ private CheckResult[] verifyMovesWasEggPreRelearn(int[] Moves, List[] valid { CheckResult[] res = new CheckResult[4]; + if(pkm.GenNumber == 3 && !pkm.HasOriginalMetLocation && EncounterMatch !=null) + { + if (EventGiftMatch?.Count > 1) // Multiple possible Mystery Gifts matched, get the best match too + res = parseMovesGetGift(Moves, validLevelMoves, validTMHM, validTutor); + else // Everything else + res = parseMovesRegular(Moves, validLevelMoves, validTMHM, validTutor, new int[0], GameVersion.Any); + if (res.All(r => r.Valid)) // moves is satisfactory + return res; + } + // Some games can have different egg movepools. Have to check all situations. GameVersion[] Games = { }; switch (pkm.GenNumber) diff --git a/PKHeX/Legality/Core.cs b/PKHeX/Legality/Core.cs index 4594a099b..a28585106 100644 --- a/PKHeX/Legality/Core.cs +++ b/PKHeX/Legality/Core.cs @@ -1090,7 +1090,7 @@ private static EncounterTrade getValidEncounterTradeVC1(PKM pkm, DexLevel[] p, E } internal static Tuple getEncounter12(PKM pkm, bool gen2) { - var g1 = getEncounter12(pkm, GameVersion.RBY); + var g1 = pkm.IsEgg ? null :getEncounter12(pkm, GameVersion.RBY); var g2 = gen2 ? getEncounter12(pkm, GameVersion.GSC) : null; if (g1 == null || g2 == null) @@ -1139,15 +1139,22 @@ internal static EncounterSlot[] getValidFriendSafari(PKM pkm) return slots.Any() ? slots.ToArray() : null; } - private static bool getWasEgg23(PKM pkm) + internal static bool getWasEgg23(PKM pkm) { + if (pkm.IsEgg) + return true; if (pkm.Format > 2 && pkm.Ball != 4) return false; + if (pkm.Format == 3) + return pkm.WasEgg; int lvl = pkm.CurrentLevel; if (lvl < 5) return false; + if(pkm.Format > 3 && pkm.Met_Level <5) + return false; + return getEvolutionValid(pkm); } diff --git a/PKHeX/Legality/LegalityCheckStrings.cs b/PKHeX/Legality/LegalityCheckStrings.cs index ecee05022..7cd14a948 100644 --- a/PKHeX/Legality/LegalityCheckStrings.cs +++ b/PKHeX/Legality/LegalityCheckStrings.cs @@ -336,7 +336,11 @@ public static class LegalityCheckStrings public static string V347 {get; set;} = "Inherited move learned by Level-up.Not expected in an event egg."; public static string V348 {get; set;} = "Inherited tutor move. Not expected in an event egg."; public static string V350 {get; set;} = "Inherited TM/HM move. Not expected in an event egg."; + public static string V351 {get; set;} = "Invalid Met Location, expected Transporter or Crown."; // Invalid + public static string V352 {get; set;} = "Arceus from Hall of Origin. Unreleased event."; + public static string V353 {get; set;} = "Non japanese Mew from Faraway Island. Unreleased event."; + public static string V354 {get; set;} = "Non Platinum Shaymin from Flower Paradise. Unreleased event."; #endregion - } + } } diff --git a/PKHeX/Legality/Tables3.cs b/PKHeX/Legality/Tables3.cs index 1c6a35ceb..7e8cca95c 100644 --- a/PKHeX/Legality/Tables3.cs +++ b/PKHeX/Legality/Tables3.cs @@ -265,7 +265,7 @@ public static partial class Legal new EncounterStatic { Species = 384, Level = 70, Location = 085, }, // Rayquaza @ Sky Pillar // Event - new EncounterStatic { Species = 151, Level = 30, Location = 201, Version = GameVersion.E, Fateful = true }, // Mew @ Faraway Island + new EncounterStatic { Species = 151, Level = 30, Location = 201, Version = GameVersion.E, Fateful = true }, // Mew @ Faraway Island (Unreleased outside of Japan) new EncounterStatic { Species = 249, Level = 70, Location = 211, Version = GameVersion.E, }, // Lugia @ Navel Rock new EncounterStatic { Species = 250, Level = 70, Location = 211, Version = GameVersion.E, }, // Ho-Oh @ Navel Rock new EncounterStatic { Species = 386, Level = 30, Location = 200, Version = GameVersion.E, Form = 3, Fateful = true }, // Deoxys @ Birth Island diff --git a/PKHeX/Legality/Tables4.cs b/PKHeX/Legality/Tables4.cs index 8c6cf3c6e..f89b46f45 100644 --- a/PKHeX/Legality/Tables4.cs +++ b/PKHeX/Legality/Tables4.cs @@ -441,8 +441,8 @@ public static partial class Legal new EncounterStatic { Species = 490, Level = 01, EggLocation = 3001, Fateful = true, Gift = true }, //Manaphy from Pokemon Ranger new EncounterStatic { Species = 491, Level = 40, Location = 079, Version = GameVersion.DP,}, //Darkrai @ Newmoon Island new EncounterStatic { Species = 491, Level = 50, Location = 079, Version = GameVersion.Pt,}, //Darkrai @ Newmoon Island - new EncounterStatic { Species = 492, Form = 0, Level = 30, Location = 063, Fateful = true,}, //Shaymin @ Flower Paradise - //new EncounterStatic { Species = 493, Level = 80, Location = 086,}, //Arceus @ Hall of Origin + new EncounterStatic { Species = 492, Form = 0, Level = 30, Location = 063, Fateful = true,}, //Shaymin @ Flower Paradise (Unreleased in Diamond and Pearl) + new EncounterStatic { Species = 493, Form = 0, Level = 80, Location = 086,}, //Arceus @ Hall of Origin (Unreleased) }; internal static readonly EncounterStatic[] Encounter_DPPt = Encounter_DPPt_Roam.SelectMany(e => e.Clone(Roaming_MetLocation_DPPt)).Concat(Encounter_DPPt_Regular).ToArray(); diff --git a/PKHeX/PKM/PK4.cs b/PKHeX/PKM/PK4.cs index 12429b38c..0b75e248d 100644 --- a/PKHeX/PKM/PK4.cs +++ b/PKHeX/PKM/PK4.cs @@ -383,7 +383,9 @@ public override int Characteristic return pm6stat * 5 + maxIV % 5; } } - + // Legality Extensions + public override bool WasEgg => GenNumber < 4 ? base.WasEgg : Egg_Location > 0; + public override bool WasEvent => Met_Location >= 3000 && Met_Location <= 3076 || FatefulEncounter && Species != 386; // Methods public override byte[] Encrypt() { diff --git a/PKHeX/PKM/PK5.cs b/PKHeX/PKM/PK5.cs index e14917bac..3b928f2fb 100644 --- a/PKHeX/PKM/PK5.cs +++ b/PKHeX/PKM/PK5.cs @@ -299,7 +299,10 @@ public override int Characteristic return pm6stat * 5 + maxIV % 5; } } - + + // Legality Extensions + public override bool WasEgg => GenNumber < 4 ? base.WasEgg : GenNumber == 4 ? Egg_Location > 0 : Legal.EggLocations.Contains(Egg_Location); + // Methods public override byte[] Encrypt() { diff --git a/PKHeX/PKM/PK6.cs b/PKHeX/PKM/PK6.cs index 6872d60f5..bee8a0071 100644 --- a/PKHeX/PKM/PK6.cs +++ b/PKHeX/PKM/PK6.cs @@ -584,11 +584,11 @@ public void TradeMemory(bool Bank) // Legality Properties public override bool WasLink => Met_Location == 30011; - public override bool WasEgg => Legal.EggLocations.Contains(Egg_Location); + public override bool WasEgg => GenNumber < 4 ? base.WasEgg : GenNumber == 4 ? Egg_Location > 0 : Legal.EggLocations.Contains(Egg_Location); public override bool WasEvent => Met_Location > 40000 && Met_Location < 50000 || FatefulEncounter && Species != 386; public override bool WasEventEgg => ((Egg_Location > 40000 && Egg_Location < 50000) || (FatefulEncounter && Egg_Location == 30002)) && Met_Level == 1; - public override bool WasTradedEgg => Egg_Location == 30002; - public override bool WasIngameTrade => Met_Location == 30001; + public override bool WasTradedEgg => Egg_Location == 30002 || GenNumber == 4 && Egg_Location == 2002; + public override bool WasIngameTrade => Met_Location == 30001 || GenNumber == 4 && Egg_Location == 2001; public PK7 convertToPK7() { diff --git a/PKHeX/PKM/PK7.cs b/PKHeX/PKM/PK7.cs index 2e66ca784..9a576865f 100644 --- a/PKHeX/PKM/PK7.cs +++ b/PKHeX/PKM/PK7.cs @@ -621,10 +621,10 @@ public void TradeMemory(bool Bank) // Legality Properties public override bool WasLink => Met_Location == 30011; - public override bool WasEgg => Legal.EggLocations.Contains(Egg_Location); + public override bool WasEgg => GenNumber < 4 ? base.WasEgg : GenNumber == 4 ? Egg_Location > 0 : Legal.EggLocations.Contains(Egg_Location); public override bool WasEvent => Met_Location > 40000 && Met_Location < 50000 || FatefulEncounter && Species != 386; public override bool WasEventEgg => ((Egg_Location > 40000 && Egg_Location < 50000) || (FatefulEncounter && Egg_Location == 30002)) && Met_Level == 1; - public override bool WasTradedEgg => Egg_Location == 30002; - public override bool WasIngameTrade => Met_Location == 30001; + public override bool WasTradedEgg => Egg_Location == 30002 || GenNumber == 4 && Egg_Location == 2002; + public override bool WasIngameTrade => Met_Location == 30001 || GenNumber == 4 && Egg_Location == 2001; } } diff --git a/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt b/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt index d706d8f3e..c9842eade 100644 --- a/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt +++ b/PKHeX/Resources/text/en/LegalityCheckStrings_en.txt @@ -270,4 +270,8 @@ V342 = Event egg move missing. V343 = Expected the following Moves: {0} V347 = Inherited move learned by Level-up. Not expected in an event egg. V348 = Inherited tutor move. Not expected in an event egg. -V350 = Inherited TM/HM move. Not expected in an event egg. \ No newline at end of file +V350 = Inherited TM/HM move. Not expected in an event egg. +V351 = Invalid Met Location, expected Transporter or Crown. +V352 = Arceus from Hall of Origin. Unreleased event. +V353 = Non japanese Mew from Faraway Island. Unreleased event. +V354 = Non Platinum Shaymin from Flower Paradise. Unreleased event. \ No newline at end of file