diff --git a/PKHeX.WinForms/Util/NetUtil.cs b/PKHeX.WinForms/Util/NetUtil.cs index 1c792e0e7..b05913564 100644 --- a/PKHeX.WinForms/Util/NetUtil.cs +++ b/PKHeX.WinForms/Util/NetUtil.cs @@ -12,8 +12,8 @@ public static string getStringFromURL(string webURL) try { HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(webURL); - HttpWebResponse httpWebReponse = (HttpWebResponse)httpWebRequest.GetResponse(); - var reader = new StreamReader(httpWebReponse.GetResponseStream()); + HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + var reader = new StreamReader(httpWebResponse.GetResponseStream()); return reader.ReadToEnd(); } catch (Exception e) @@ -27,8 +27,8 @@ public static Image getImageFromURL(string webURL) try { HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(webURL); - HttpWebResponse httpWebReponse = (HttpWebResponse)httpWebRequest.GetResponse(); - Stream stream = httpWebReponse.GetResponseStream(); + HttpWebResponse httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse(); + Stream stream = httpWebResponse.GetResponseStream(); return stream != null ? Image.FromStream(stream) : null; } catch (Exception e) diff --git a/PKHeX/Legality/CheckStrings.cs b/PKHeX/Legality/CheckStrings.cs index a907e6f53..761b8ae31 100644 --- a/PKHeX/Legality/CheckStrings.cs +++ b/PKHeX/Legality/CheckStrings.cs @@ -35,7 +35,7 @@ public static void setLocalization(IEnumerable lines) try { - ReflectUtil.SetValue(t, prop, value); + ReflectUtil.SetValue(t, prop.ToUpper(), value); } catch { @@ -146,7 +146,7 @@ public static string[] getLocalization(string[] existingLines = null) public static string V32 {get; set;} = "All IVs are equal."; // Fishy public static string V28 {get; set;} = "Should have at least {0} IVs {get; set;} = 31."; // Invalid - public static string V29 {get; set;} = "Friend Safari captures should have at least 2 IVs {get; set;} = 31."; // Invalid + public static string V29 {get; set;} = "Friend Safari captures should have at least 2 IVs = 31."; // Invalid public static string V30 {get; set;} = "IVs do not match Mystery Gift Data."; // Invalid public static string V38 {get; set;} = "OT Name too long."; // Invalid @@ -240,9 +240,9 @@ public static string[] getLocalization(string[] existingLines = null) public static string V109 {get; set;} = "Ability modified with Ability Capsule."; public static string V110 {get; set;} = "Ability does not match Mystery Gift."; public static string V111 {get; set;} = "Hidden Ability on non-SOS wild encounter."; + public static string V300 {get; set;} = "Hidden Ability on non-horde/friend safari wild encounter."; public static string V112 {get; set;} = "Hidden Ability not available."; public static string V217 {get; set;} = "Hidden Grotto captures should have Hidden Ability."; - public static string V218 {get; set;} = "Hidden Ability not available from Wild Encounter."; public static string V115 {get; set;} = "Ability matches ability number."; // Valid public static string V113 {get; set;} = "Ability does not match PID."; @@ -272,6 +272,9 @@ public static string[] getLocalization(string[] existingLines = null) public static string V133 {get; set;} = "Event OT Affection should be zero."; public static string V134 {get; set;} = "Current handler should not be Event OT."; public static string V138 {get; set;} = "Contest Stats should be 0."; + public static string V301 {get; set;} = "Invalid Console Region."; + public static string V302 {get; set;} = "Geolocation: Country is not in 3DS region."; + public static string V303 {get; set;} = "Geolocation: Country is in 3DS region."; public static string V137 {get; set;} = "GeoLocation Memory: Memories should be present."; public static string V135 {get; set;} = "GeoLocation Memory: Gap/Blank present."; public static string V136 {get; set;} = "GeoLocation Memory: Region without Country."; @@ -286,6 +289,7 @@ public static string[] getLocalization(string[] existingLines = null) public static string V148 {get; set;} = "Memory: Handling Trainer Memory present with no Handling Trainer name."; public static string V150 {get; set;} = "Memory: Handling Trainer Memory missing."; public static string V152 {get; set;} = "Memory: Original Trainer Memory missing."; + public static string V329 {get; set;} = "Memory: Not cleared properly."; public static string V149 {get; set;} = "Memory: Can't have Handling Trainer Memory as egg."; public static string V151 {get; set;} = "Memory: Can't have Original Trainer Memory as egg."; public static string V164 {get; set;} = "{0} Memory: Species can be captured in game."; @@ -322,6 +326,33 @@ public static string[] getLocalization(string[] existingLines = null) public static string V158 {get; set;} = "Should have a HT Memory Intensity value (1st)."; public static string V159 {get; set;} = "Should have a HT Memory Feeling value 0-9."; + public static string V318 {get; set;} = "Form is Valid."; + public static string V304 {get; set;} = "Form Count is out of range. Expected <= {0}, got {1}."; + public static string V305 {get; set;} = "Cosplay Pikachu cannot have the default form."; + public static string V306 {get; set;} = "Only Cosplay Pikachu can have this form."; + public static string V307 {get; set;} = "Event Pikachu cannot have the default form."; + public static string V308 {get; set;} = "Held item does not match Form."; + public static string V309 {get; set;} = "Held item matches Form."; + public static string V310 {get; set;} = "Form cannot exist outside of a battle."; + public static string V311 {get; set;} = "Event Vivillon pattern on pre-evolution."; + public static string V312 {get; set;} = "Invalid Vivillon pattern."; + public static string V313 {get; set;} = "Valid Vivillon pattern."; + public static string V314 {get; set;} = "Invalid Eternal Flower encounter."; + public static string V315 {get; set;} = "Valid Eternal Flower encounter."; + public static string V316 {get; set;} = "Form cannot exist outside of Party."; + public static string V317 {get; set;} = "Form cannot be obtained for pre-Alola generation games."; + + public static string V319 {get; set;} = "Cannot apply PP Ups to an Egg."; + public static string V320 {get; set;} = "Cannot increase Contest Stats of an Egg."; + public static string V321 {get; set;} = "Mystery Gift Fateful Encounter."; + public static string V322 {get; set;} = "Mystery Gift Fateful Encounter flag missing."; + public static string V323 {get; set;} = "Special ingame Fateful Encounter."; + public static string V324 {get; set;} = "Special ingame Fateful Encounter flag missing."; + public static string V325 {get; set;} = "Fateful Encounter should not be checked."; + public static string V326 {get; set;} = "Special ingame N's Sparkle flag missing."; + public static string V327 {get; set;} = "Special ingame N's Sparkle flag should not be checked."; + public static string V328 {get; set;} = "Version Specific evolution requires a trade to opposite version. A Handling Trainer is required."; + #endregion } diff --git a/PKHeX/Legality/Checks.cs b/PKHeX/Legality/Checks.cs index 98f04dfcd..372d84da8 100644 --- a/PKHeX/Legality/Checks.cs +++ b/PKHeX/Legality/Checks.cs @@ -992,7 +992,7 @@ private void verifyAbility() bool grotto = ((EncounterSlot[])EncounterMatch).All(slot => slot.Type == SlotType.HiddenGrotto); //encounter only at HiddenGrotto if (pkm.AbilityNumber == 4 ^ grotto) { - AddLine(Severity.Invalid, grotto ? V217 : V218, CheckIdentifier.Ability); + AddLine(Severity.Invalid, grotto ? V217 : V108, CheckIdentifier.Ability); return; } } @@ -1023,7 +1023,7 @@ private void verifyAbility() if (!valid) { - AddLine(Severity.Invalid, "Hidden Ability on non-horde/friend safari wild encounter.", CheckIdentifier.Ability); + AddLine(Severity.Invalid, V300, CheckIdentifier.Ability); return; } } @@ -1673,7 +1673,7 @@ private void verifyHTMemory() if (pkm.HT_Memory == 0) { if (pkm.HT_TextVar != 0 || pkm.HT_Intensity != 0 || pkm.HT_Feeling != 0) - AddLine(Severity.Invalid, "HT memory not cleared properly.", CheckIdentifier.Memory); + AddLine(Severity.Invalid, V329, CheckIdentifier.Memory); return; } @@ -1736,14 +1736,14 @@ private void verifyRegion() pass = pkm.Country == 128; break; default: - AddLine(new CheckResult(Severity.Invalid, "Invalid Console Region.", CheckIdentifier.Geography)); + AddLine(new CheckResult(Severity.Invalid, V301, CheckIdentifier.Geography)); return; } if (!pass) - AddLine(Severity.Invalid, "Geolocation: Country is not in 3DS region.", CheckIdentifier.Geography); + AddLine(Severity.Invalid, V302, CheckIdentifier.Geography); else - AddLine(Severity.Valid, "Geolocation: Country is in 3DS region.", CheckIdentifier.Geography); + AddLine(Severity.Valid, V303, CheckIdentifier.Geography); } private void verifyForm() { @@ -1771,7 +1771,7 @@ private void verifyForm() valid = true; if (!valid) // ignore list - { AddLine(Severity.Invalid, $"Form Count is out of range. Expected <= {pkm.PersonalInfo.FormeCount}, got {pkm.AltForm}", CheckIdentifier.Form); return; } + { AddLine(Severity.Invalid, string.Format(V304, pkm.PersonalInfo.FormeCount, pkm.AltForm), CheckIdentifier.Form); return; } } switch (pkm.Species) @@ -1779,9 +1779,7 @@ private void verifyForm() case 25: // Pikachu if (pkm.Format == 6 && pkm.AltForm != 0 ^ EncounterType == typeof(EncounterStatic)) { - string msg = EncounterType == typeof (EncounterStatic) - ? "Cosplay Pikachu cannot have the default form." - : "Only Cosplay Pikachu can have this form."; + string msg = EncounterType == typeof (EncounterStatic) ? V305 : V306; AddLine(Severity.Invalid, msg, CheckIdentifier.Form); return; } @@ -1790,7 +1788,7 @@ private void verifyForm() var gift = EncounterMatch as WC7; if (gift != null && gift.Form != pkm.AltForm) { - AddLine(Severity.Invalid, "Event Pikachu cannot have the default form.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V307, CheckIdentifier.Form); return; } } @@ -1798,7 +1796,7 @@ private void verifyForm() case 487: // Giratina if (pkm.AltForm == 1 ^ pkm.HeldItem == 112) // Origin form only with Griseous Orb { - AddLine(Severity.Invalid, "Held item does not match Form.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V308, CheckIdentifier.Form); return; } break; @@ -1811,11 +1809,19 @@ private void verifyForm() else if (777 <= item && item <= 793) form = Array.IndexOf(Legal.Arceus_ZCrystal, item) + 1; if (form != pkm.AltForm) - AddLine(Severity.Invalid, "Held item does not match Form.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V308, CheckIdentifier.Form); else if (form != 0) - AddLine(Severity.Valid, "Held item matches Form.", CheckIdentifier.Form); + AddLine(Severity.Valid, V309, CheckIdentifier.Form); } break; + case 647: // Keldeo + { + int index = Array.IndexOf(pkm.Moves, 548); // Secret Sword + bool noSword = index < 0; + if (pkm.AltForm == 0 ^ noSword) // mismatch + vMoves[noSword ? 0 : index] = new CheckResult(Severity.Invalid, V169, CheckIdentifier.Move); + break; + } case 649: // Genesect { int item = pkm.HeldItem; @@ -1824,15 +1830,15 @@ private void verifyForm() form = item - 115; if (form != pkm.AltForm) - AddLine(Severity.Invalid, "Held item does not match Form.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V308, CheckIdentifier.Form); else - AddLine(Severity.Valid, "Held item matches Form.", CheckIdentifier.Form); + AddLine(Severity.Valid, V309, CheckIdentifier.Form); } break; case 658: // Greninja if (pkm.AltForm > 1) // Ash Battle Bond active { - AddLine(Severity.Invalid, "Form cannot exist outside of a battle.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V310, CheckIdentifier.Form); return; } break; @@ -1840,7 +1846,7 @@ private void verifyForm() case 665: // Spewpa if (pkm.AltForm > 17) // Fancy & Pokéball { - AddLine(Severity.Invalid, "Event Vivillon pattern on pre-evolution.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V311, CheckIdentifier.Form); return; } break; @@ -1848,9 +1854,9 @@ private void verifyForm() if (pkm.AltForm > 17) // Fancy & Pokéball { if (!EncounterIsMysteryGift) - AddLine(Severity.Invalid, "Invalid Vivillon pattern.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V312, CheckIdentifier.Form); else - AddLine(Severity.Valid, "Valid Vivillon pattern.", CheckIdentifier.Form); + AddLine(Severity.Valid, V313, CheckIdentifier.Form); return; } @@ -1859,9 +1865,9 @@ private void verifyForm() if (pkm.AltForm == 5) // Eternal Flower -- Never Released { if (!EncounterIsMysteryGift) - AddLine(Severity.Invalid, "Invalid Eternal Flower encounter.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V314, CheckIdentifier.Form); else - AddLine(Severity.Valid, "Valid Eternal Flower encounter.", CheckIdentifier.Form); + AddLine(Severity.Valid, V315, CheckIdentifier.Form); return; } @@ -1869,7 +1875,7 @@ private void verifyForm() case 718: // Zygarde if (pkm.AltForm >= 4) { - AddLine(Severity.Invalid, "Form cannot exist outside of a battle.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V310, CheckIdentifier.Form); return; } break; @@ -1880,15 +1886,15 @@ private void verifyForm() if ((904 <= item && item <= 920) || item == 644) form = item - 903; if (form != pkm.AltForm) - AddLine(Severity.Invalid, "Held item does not match Form.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V308, CheckIdentifier.Form); else if (form != 0) - AddLine(Severity.Valid, "Held item matches Form.", CheckIdentifier.Form); + AddLine(Severity.Valid, V309, CheckIdentifier.Form); break; } case 774: // Minior if (pkm.AltForm < 7) { - AddLine(Severity.Invalid, "Form cannot exist outside of a battle.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V310, CheckIdentifier.Form); return; } break; @@ -1899,7 +1905,7 @@ private void verifyForm() case 720: // Hoopa if (pkm.AltForm != 0 && pkm.Box > -1) // has form but stored in box { - AddLine(Severity.Invalid, "Form cannot exist outside of Party.", CheckIdentifier.Form); + AddLine(Severity.Invalid, V316, CheckIdentifier.Form); return; } break; @@ -1908,12 +1914,12 @@ private void verifyForm() if (pkm.Format >= 7 && pkm.GenNumber < 7 && pkm.AltForm != 0) { if (pkm.Species == 25 || Legal.AlolanOriginForms.Contains(pkm.Species)) - { AddLine(Severity.Invalid, "Form cannot be obtained for pre-Alola generation games.", CheckIdentifier.Form); return; } + { AddLine(Severity.Invalid, V317, CheckIdentifier.Form); return; } } if (pkm.AltForm > 0 && new[] {Legal.BattleForms, Legal.BattleMegas, Legal.BattlePrimals}.Any(arr => arr.Contains(pkm.Species))) - { AddLine(Severity.Invalid, "Form cannot exist outside of a battle.", CheckIdentifier.Form); return; } + { AddLine(Severity.Invalid, V310, CheckIdentifier.Form); return; } - AddLine(Severity.Valid, "Form is Valid.", CheckIdentifier.Form); + AddLine(Severity.Valid, V318, CheckIdentifier.Form); } private void verifyMisc() { @@ -1925,9 +1931,9 @@ private void verifyMisc() if (pkm.IsEgg) { if (new[] {pkm.Move1_PPUps, pkm.Move2_PPUps, pkm.Move3_PPUps, pkm.Move4_PPUps}.Any(ppup => ppup > 0)) - { AddLine(Severity.Invalid, "Cannot apply PP Ups to an Egg.", CheckIdentifier.Misc); return; } + { AddLine(Severity.Invalid, V319, CheckIdentifier.Misc); return; } if (pkm.CNTs.Any(stat => stat > 0)) - { AddLine(Severity.Invalid, "Cannot increase Contest Stats of an Egg.", CheckIdentifier.Misc); return; } + { AddLine(Severity.Invalid, V320, CheckIdentifier.Misc); return; } } if (Encounter.Valid) @@ -1935,9 +1941,9 @@ private void verifyMisc() if (EncounterIsMysteryGift) { if (pkm.FatefulEncounter) - AddLine(Severity.Valid, "Mystery Gift Fateful Encounter.", CheckIdentifier.Fateful); + AddLine(Severity.Valid, V321, CheckIdentifier.Fateful); else - AddLine(Severity.Invalid, "Mystery Gift Fateful Encounter flag missing.", CheckIdentifier.Fateful); + AddLine(Severity.Invalid, V322, CheckIdentifier.Fateful); return; } if (EncounterType == typeof (EncounterStatic)) @@ -1946,25 +1952,25 @@ private void verifyMisc() if (enc.Fateful) { if (pkm.FatefulEncounter) - AddLine(Severity.Valid, "Special ingame Fateful Encounter.", CheckIdentifier.Fateful); + AddLine(Severity.Valid, V323, CheckIdentifier.Fateful); else - AddLine(Severity.Invalid, "Special ingame Fateful Encounter flag missing.", CheckIdentifier.Fateful); + AddLine(Severity.Invalid, V324, CheckIdentifier.Fateful); } else if (pkm.FatefulEncounter) - AddLine(Severity.Invalid, "Fateful Encounter should not be checked.", CheckIdentifier.Fateful); + AddLine(Severity.Invalid, V325, CheckIdentifier.Fateful); return; } if (pkm.FatefulEncounter) - AddLine(Severity.Invalid, "Fateful Encounter should not be checked.", CheckIdentifier.Fateful); + AddLine(Severity.Invalid, V325, CheckIdentifier.Fateful); if (pkm.Format == 5) { var enc = EncounterMatch as EncounterStatic; bool req = enc?.NSparkle ?? false; bool has = ((PK5) pkm).NPokémon; if (req && !has) - AddLine(Severity.Invalid, "Special ingame N's Sparkle flag missing.", CheckIdentifier.Fateful); + AddLine(Severity.Invalid, V326, CheckIdentifier.Fateful); if (!req && has) - AddLine(Severity.Invalid, "Special ingame N's Sparkle flag should not be checked.", CheckIdentifier.Fateful); + AddLine(Severity.Invalid, V327, CheckIdentifier.Fateful); } } } @@ -1983,7 +1989,7 @@ private void verifyVersionEvolution() if (pkm.AltForm == 0 && pkm.Version == 31 // Moon || pkm.AltForm == 1 && pkm.Version == 30) // Sun if (pkm.IsUntraded) - AddLine(Severity.Invalid, "Version Specific evolution requires a trade to opposite version. A Handling Trainer is required.", CheckIdentifier.Evolution); + AddLine(Severity.Invalid, V328, CheckIdentifier.Evolution); break; case 791: // Solgaleo @@ -1991,7 +1997,7 @@ private void verifyVersionEvolution() { if (EncounterIsMysteryGift && (EncounterMatch as MysteryGift).Species == pkm.Species) // Gifted via Mystery Gift break; - AddLine(Severity.Invalid, "Version Specific evolution requires a trade to opposite version. A Handling Trainer is required.", CheckIdentifier.Evolution); + AddLine(Severity.Invalid, V328, CheckIdentifier.Evolution); } break; case 792: // Lunala @@ -1999,7 +2005,7 @@ private void verifyVersionEvolution() { if (EncounterIsMysteryGift && (EncounterMatch as MysteryGift).Species == pkm.Species) // Gifted via Mystery Gift break; - AddLine(Severity.Invalid, "Version Specific evolution requires a trade to opposite version. A Handling Trainer is required.", CheckIdentifier.Evolution); + AddLine(Severity.Invalid, V328, CheckIdentifier.Evolution); } break; } @@ -2007,63 +2013,71 @@ private void verifyVersionEvolution() private CheckResult[] verifyMoves(GameVersion game = GameVersion.Any) { - int[] Moves = pkm.Moves; - CheckResult[] res = new CheckResult[4]; - for (int i = 0; i < 4; i++) - res[i] = new CheckResult(CheckIdentifier.Move); - var validLevelMoves = Legal.getValidMoves(pkm, EvoChainsAllGens, Tutor: false, Machine: false).ToArray(); var validTMHM = Legal.getValidMoves(pkm, EvoChainsAllGens, LVL: false, Tutor: false, MoveReminder: false).ToArray(); var validTutor = Legal.getValidMoves(pkm, EvoChainsAllGens, LVL: false, Machine: false, MoveReminder: false).ToArray(); - if (pkm.Species == 235) // Smeargle - { - for (int i = 0; i < 4; i++) - res[i] = Legal.InvalidSketch.Contains(Moves[i]) - ? new CheckResult(Severity.Invalid, V166, CheckIdentifier.Move) - : new CheckResult(CheckIdentifier.Move); - } - else if (EventGiftMatch?.Count > 1) // Multiple possible Mystery Gifts matched - { - int[] RelearnMoves = pkm.RelearnMoves; - foreach (MysteryGift mg in EventGiftMatch) - { - int[] SpecialMoves = mg.Moves; - res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, new int[0]); - if (res.Any(r => !r.Valid)) - continue; - EncounterMatch = mg; - RelearnBase = mg.RelearnMoves; - break; - } - } - else - { - int[] EggMoves = pkm.WasEgg ? Legal.getEggMoves(pkm, game).ToArray() : new int[0]; - int[] RelearnMoves = pkm.RelearnMoves; - int[] SpecialMoves = (EncounterMatch as MysteryGift)?.Moves ?? - (EncounterMatch as EncounterStatic)?.Moves ?? - (EncounterMatch as EncounterTrade)?.Moves ?? - new int[0]; - - res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, EggMoves); - - if (pkm.GenNumber >= 6) - for (int i = 0; i < 4; i++) - if (res[i].Flag && !RelearnMoves.Contains(Moves[i])) - res[i] = new CheckResult(Severity.Invalid, string.Format(V170, res[i].Comment), res[i].Identifier); - } - if (Moves[0] == 0) // None - res[0] = new CheckResult(Severity.Invalid, V167, CheckIdentifier.Move); - - if (pkm.Species == 647) // Keldeo - if (pkm.AltForm == 1 ^ pkm.Moves.Contains(548)) - res[Math.Max(Array.IndexOf(pkm.Moves, 548), 0)] = new CheckResult(Severity.Invalid, V169, CheckIdentifier.Move); + CheckResult[] res; + int[] Moves = pkm.Moves; + if (pkm.Species == 235) // Smeargle can have any move except a few + res = parseMovesSketch(Moves); + else 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, game); // Duplicate Moves Check + verifyNoEmptyDuplicates(Moves, res); + if (Moves[0] == 0) // Can't have an empty moveslot for the first move. + res[0] = new CheckResult(Severity.Invalid, V167, CheckIdentifier.Move); + + return res; + } + private CheckResult[] parseMovesSketch(int[] Moves) + { + CheckResult[] res = new CheckResult[4]; for (int i = 0; i < 4; i++) - if (Moves.Count(m => m != 0 && m == Moves[i]) > 1) - res[i] = new CheckResult(Severity.Invalid, V168, CheckIdentifier.Move); + res[i] = Legal.InvalidSketch.Contains(Moves[i]) + ? new CheckResult(Severity.Invalid, V166, CheckIdentifier.Move) + : new CheckResult(CheckIdentifier.Move); + return res; + } + private CheckResult[] parseMovesGetGift(int[] Moves, int[] validLevelMoves, int[] validTMHM, int[] validTutor) + { + int[] RelearnMoves = pkm.RelearnMoves; + foreach (MysteryGift mg in EventGiftMatch) + { + int[] SpecialMoves = mg.Moves; + CheckResult[] res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, new int[0]); + if (res.Any(r => !r.Valid)) + continue; + + // Match Found + EncounterMatch = mg; + RelearnBase = mg.RelearnMoves; + return res; + } + + // no Mystery Gifts matched + return parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, new int[0], new int[0]); + } + private CheckResult[] parseMovesRegular(int[] Moves, int[] validLevelMoves, int[] validTMHM, int[] validTutor, GameVersion game) + { + int[] EggMoves = pkm.WasEgg ? Legal.getEggMoves(pkm, game).ToArray() : new int[0]; + int[] RelearnMoves = pkm.RelearnMoves; + int[] SpecialMoves = (EncounterMatch as MysteryGift)?.Moves ?? + (EncounterMatch as EncounterStatic)?.Moves ?? + (EncounterMatch as EncounterTrade)?.Moves ?? + new int[0]; + + CheckResult[] res = parseMoves(Moves, validLevelMoves, RelearnMoves, validTMHM, validTutor, SpecialMoves, EggMoves); + + if (pkm.GenNumber < 6) + return res; + + for (int i = 0; i < 4; i++) + if (res[i].Flag && !RelearnMoves.Contains(Moves[i])) + res[i] = new CheckResult(Severity.Invalid, string.Format(V170, res[i].Comment), res[i].Identifier); return res; } @@ -2091,176 +2105,236 @@ private static CheckResult[] parseMoves(int[] moves, int[] learn, int[] relearn, } return res; } + private CheckResult[] verifyRelearn() { RelearnBase = null; - CheckResult[] res = new CheckResult[4]; - - int[] Moves = pkm.RelearnMoves; + if (pkm.GenNumber < 6 || pkm.VC1) - goto noRelearn; + return verifyRelearnNone(); if (pkm.WasLink) - { - var Link = Legal.getValidLinkGifts(pkm); - if (Link == null) - { - for (int i = 0; i < 4; i++) - res[i] = new CheckResult(CheckIdentifier.RelearnMove); - return res; - } - EncounterMatch = Link; + return verifyRelearnLink(); - int[] moves = ((EncounterLink)EncounterMatch).RelearnMoves; - RelearnBase = moves; - for (int i = 0; i < 4; i++) - res[i] = moves[i] != Moves[i] - ? new CheckResult(Severity.Invalid, string.Format(V178, movelist[moves[i]]), CheckIdentifier.RelearnMove) - : new CheckResult(CheckIdentifier.RelearnMove); - return res; - } if (pkm.WasEvent || pkm.WasEventEgg) - { - // Get WC6's that match - EventGiftMatch = new List(Legal.getValidGifts(pkm)); - foreach (MysteryGift mg in EventGiftMatch.ToArray()) - { - int[] moves = mg.RelearnMoves; - for (int i = 0; i < 4; i++) - res[i] = moves[i] != Moves[i] - ? new CheckResult(Severity.Invalid, string.Format(V178, movelist[moves[i]]), CheckIdentifier.RelearnMove) - : new CheckResult(CheckIdentifier.RelearnMove); - if (res.Any(r => !r.Valid)) - EventGiftMatch.Remove(mg); - } - if (EventGiftMatch.Count > 1) - return res; - if (EventGiftMatch.Count == 1) - { EncounterMatch = EventGiftMatch[0]; RelearnBase = EventGiftMatch[0].RelearnMoves; return res; } - - EncounterMatch = EncounterType = null; - goto noRelearn; // No WC match - } + return verifyRelearnMysteryGift(); if (pkm.WasEgg && !Legal.NoHatchFromEgg.Contains(pkm.Species)) + return verifyRelearnEgg(); + + if (pkm.RelearnMove1 != 0 && Legal.getDexNavValid(pkm)) + return verifyRelearnDexNav(); + + return verifyRelearnNone(); + } + private CheckResult[] verifyRelearnMysteryGift() + { + CheckResult[] res = new CheckResult[4]; + int[] RelearnMoves = pkm.RelearnMoves; + // Get gifts that match + + EventGiftMatch = new List(Legal.getValidGifts(pkm)); + foreach (MysteryGift mg in EventGiftMatch.ToArray()) { - GameVersion[] Games = {}; - switch (pkm.GenNumber) - { - case 6: - Games = new[] {GameVersion.XY, GameVersion.ORAS}; - break; - case 7: - Games = new[] {GameVersion.SM}; - break; - } - - bool checkAllGames = pkm.WasTradedEgg; - bool splitBreed = Legal.SplitBreed.Contains(pkm.Species); - - int iterate = (checkAllGames ? Games.Length : 1) * (splitBreed ? 2 : 1); - for (int i = 0; i < iterate; i++) - { - int gameSource = !checkAllGames ? -1 : i % iterate / (splitBreed ? 2 : 1); - int skipOption = splitBreed && iterate / 2 <= i ? 1 : 0; - GameVersion ver = gameSource == -1 ? GameVersion.Any : Games[gameSource]; - - // Obtain level1 moves - List baseMoves = new List(Legal.getBaseEggMoves(pkm, skipOption, ver)); - int baseCt = baseMoves.Count; - if (baseCt > 4) baseCt = 4; - - // Obtain Nonstandard moves - var relearnMoves = Legal.getValidRelearn(pkm, skipOption).ToList(); - var relearn = pkm.RelearnMoves.Where(move => move != 0 - && (!baseMoves.Contains(move) || relearnMoves.Contains(move)) - ).ToArray(); - int relearnCt = relearn.Length; - - // Get Move Window - List window = new List(baseMoves); - window.AddRange(relearn); - int[] moves = window.Skip(baseCt + relearnCt - 4).Take(4).ToArray(); - Array.Resize(ref moves, 4); - - int reqBase; - int unique = baseMoves.Concat(relearn).Distinct().Count(); - if (relearnCt == 4) - reqBase = 0; - else if (baseCt + relearnCt > 4) - reqBase = 4 - relearnCt; - else - reqBase = baseCt; - - if (pkm.RelearnMoves.Where(m => m != 0).Count() < Math.Min(4, baseMoves.Count)) - reqBase = Math.Min(4, unique); - - // Movepool finalized! Check validity. - - int[] rl = pkm.RelearnMoves; - string em = string.Join(", ", baseMoves.Select(r => r >= movelist.Length ? V190 : movelist[r])); - RelearnBase = baseMoves.ToArray(); - // Base Egg Move - for (int j = 0; j < reqBase; j++) - { - if (baseMoves.Contains(rl[j])) - res[j] = new CheckResult(Severity.Valid, V179, CheckIdentifier.RelearnMove); - else - { - res[j] = new CheckResult(Severity.Invalid, V180, CheckIdentifier.RelearnMove); - for (int f = j+1; f < reqBase; f++) - res[f] = new CheckResult(Severity.Invalid, V180, CheckIdentifier.RelearnMove); - res[reqBase-1].Comment += string.Format(Environment.NewLine + V181, em); - break; - } - } - - // Non-Base - if (Legal.LightBall.Contains(pkm.Species)) - relearnMoves.Add(344); - for (int j = reqBase; j < 4; j++) - res[j] = !relearnMoves.Contains(rl[j]) - ? new CheckResult(Severity.Invalid, V182, CheckIdentifier.RelearnMove) - : new CheckResult(Severity.Valid, rl[j] == 0 ? V167 : V172, CheckIdentifier.RelearnMove); - - if (res.All(r => r.Valid)) - break; - } - - // Duplicate Moves Check + int[] moves = mg.RelearnMoves; for (int i = 0; i < 4; i++) - if (Moves.Count(m => m != 0 && m == Moves[i]) > 1) - res[i] = new CheckResult(Severity.Invalid, V168, CheckIdentifier.RelearnMove); - - return res; + res[i] = moves[i] != RelearnMoves[i] + ? new CheckResult(Severity.Invalid, string.Format(V178, movelist[moves[i]]), CheckIdentifier.RelearnMove) + : new CheckResult(CheckIdentifier.RelearnMove); + if (res.Any(r => !r.Valid)) + EventGiftMatch.Remove(mg); } - if (Moves[0] != 0) // DexNav only? + if (EventGiftMatch.Count > 1) + return res; + + if (EventGiftMatch.Count == 1) { - // Check DexNav - if (!Legal.getDexNavValid(pkm)) - goto noRelearn; - - res[0] = !Legal.getValidRelearn(pkm, 0).Contains(Moves[0]) - ? new CheckResult(Severity.Invalid, V183, CheckIdentifier.RelearnMove) - : new CheckResult(CheckIdentifier.RelearnMove); - for (int i = 1; i < 4; i++) - res[i] = Moves[i] != 0 - ? new CheckResult(Severity.Invalid, V184, CheckIdentifier.RelearnMove) - : new CheckResult(CheckIdentifier.RelearnMove); - - if (res[0].Valid) - RelearnBase = new[] { Moves[0], 0, 0, 0 }; + EncounterMatch = EventGiftMatch[0]; + RelearnBase = EventGiftMatch[0].RelearnMoves; return res; } - // Should have no relearn moves. - noRelearn: - for (int i = 0; i < 4; i++) - res[i] = Moves[i] != 0 + // No gift match, thus no relearn moves + EncounterMatch = EncounterType = null; + return verifyRelearnNone(); + } + private CheckResult[] verifyRelearnDexNav() + { + CheckResult[] res = new CheckResult[4]; + int[] RelearnMoves = pkm.RelearnMoves; + + // DexNav Pokémon can have 1 random egg move as a relearn move. + res[0] = !Legal.getValidRelearn(pkm, 0).Contains(RelearnMoves[0]) + ? new CheckResult(Severity.Invalid, V183, CheckIdentifier.RelearnMove) + : new CheckResult(CheckIdentifier.RelearnMove); + + // All other relearn moves must be empty. + for (int i = 1; i < 4; i++) + res[i] = RelearnMoves[i] != 0 ? new CheckResult(Severity.Invalid, V184, CheckIdentifier.RelearnMove) : new CheckResult(CheckIdentifier.RelearnMove); + + // Update the relearn base moves if the first relearn move is okay. + if (res[0].Valid) + RelearnBase = new[] { RelearnMoves[0], 0, 0, 0 }; + return res; } + private CheckResult[] verifyRelearnNone() + { + CheckResult[] res = new CheckResult[4]; + int[] RelearnMoves = pkm.RelearnMoves; + + // No relearn moves should be present. + for (int i = 0; i < 4; i++) + res[i] = RelearnMoves[i] != 0 + ? new CheckResult(Severity.Invalid, V184, CheckIdentifier.RelearnMove) + : new CheckResult(CheckIdentifier.RelearnMove); + + return res; + } + private CheckResult[] verifyRelearnLink() + { + // The WasLink check indicated that it was from the Pokémon Link + var Link = Legal.getValidLinkGifts(pkm); + + // But no encounter was able to be matched. Abort! + if (Link == null) + return verifyRelearnNone(); + + EncounterMatch = Link; + CheckResult[] res = new CheckResult[4]; + int[] RelearnMoves = pkm.RelearnMoves; + int[] LinkRelearn = ((EncounterLink)EncounterMatch).RelearnMoves; + + // Pokémon Link encounters should have their relearn moves match exactly. + RelearnBase = LinkRelearn; + for (int i = 0; i < 4; i++) + res[i] = LinkRelearn[i] != RelearnMoves[i] + ? new CheckResult(Severity.Invalid, string.Format(V178, movelist[LinkRelearn[i]]), CheckIdentifier.RelearnMove) + : new CheckResult(CheckIdentifier.RelearnMove); + + return res; + } + private CheckResult[] verifyRelearnEgg() + { + CheckResult[] res = new CheckResult[4]; + int[] RelearnMoves = pkm.RelearnMoves; + + // Some games can have different egg movepools. Have to check all situations. + GameVersion[] Games = { }; + switch (pkm.GenNumber) + { + case 6: + Games = new[] { GameVersion.XY, GameVersion.ORAS }; + break; + case 7: + Games = new[] { GameVersion.SM }; + break; + } + + bool checkAllGames = pkm.WasTradedEgg; + bool splitBreed = Legal.SplitBreed.Contains(pkm.Species); + int iterate = (checkAllGames ? Games.Length : 1) * (splitBreed ? 2 : 1); + + for (int i = 0; i < iterate; i++) + { + // Obtain parameters for the Egg's Base Moves + int gameSource = !checkAllGames ? -1 : i % iterate / (splitBreed ? 2 : 1); + int skipOption = splitBreed && iterate / 2 <= i ? 1 : 0; + GameVersion ver = gameSource == -1 ? GameVersion.Any : Games[gameSource]; + + // Generate & Analyze compatibility + res = verifyRelearnEggBase(RelearnMoves, skipOption, ver); + if (res.All(r => r.Valid)) // egg is satisfactory + break; + } + + verifyNoEmptyDuplicates(RelearnMoves, res); + return res; + } + private CheckResult[] verifyRelearnEggBase(int[] RelearnMoves, int skipOption, GameVersion ver) + { + CheckResult[] res = new CheckResult[4]; + + // Obtain level1 moves + List baseMoves = new List(Legal.getBaseEggMoves(pkm, skipOption, ver)); + int baseCt = baseMoves.Count; + if (baseCt > 4) baseCt = 4; + + // Obtain Inherited moves + var inheritMoves = Legal.getValidRelearn(pkm, skipOption).ToList(); + var inherited = RelearnMoves.Where(m => m != 0 && (!baseMoves.Contains(m) || inheritMoves.Contains(m))).ToList(); + int inheritCt = inherited.Count; + + // Get Move Window + var window = new List(); + window.AddRange(baseMoves); // initial moves (levelup for current level of egg) + window.AddRange(inherited); // nonstandard (egg or higher levelup moves) + + // Get required amount of base moves + int unique = baseMoves.Concat(inherited).Distinct().Count(); + int reqBase = inheritCt == 4 || baseCt + inheritCt > 4 ? 4 - inheritCt : baseCt; + if (RelearnMoves.Where(m => m != 0).Count() < Math.Min(4, baseMoves.Count)) + reqBase = Math.Min(4, unique); + + // Store the base moves suggestion. + string em = string.Join(", ", baseMoves.Select(m => m >= movelist.Length ? V190 : movelist[m])); + + // Store the suggested relearn moves. + int[] moves = window.Skip(baseCt + inheritCt - 4).Take(4).ToArray(); + Array.Resize(ref moves, 4); + RelearnBase = moves; + + // Check if the required amount of Base Egg Moves are present. + for (int i = 0; i < reqBase; i++) + { + if (baseMoves.Contains(RelearnMoves[i])) + res[i] = new CheckResult(Severity.Valid, V179, CheckIdentifier.RelearnMove); + else + { + // mark remaining base egg moves missing + for (int z = i; z < reqBase; z++) + res[z] = new CheckResult(Severity.Invalid, V180, CheckIdentifier.RelearnMove); + + // provide the list of suggested base moves for the last required slot + res[reqBase - 1].Comment += string.Format(Environment.NewLine + V181, em); + break; + } + } + + // Non-Base moves that can magically appear in the regular movepool + if (Legal.LightBall.Contains(pkm.Species)) + inheritMoves.Add(344); + + // Inherited moves appear after the required base moves. + for (int i = reqBase; i < 4; i++) + { + if (RelearnMoves[i] == 0) // empty + res[i] = new CheckResult(Severity.Valid, V167, CheckIdentifier.RelearnMove); + else if (inheritMoves.Contains(RelearnMoves[i])) // inherited + res[i] = new CheckResult(Severity.Valid, V172, CheckIdentifier.RelearnMove); + else // not inheritable, flag + res[i] = new CheckResult(Severity.Invalid, V182, CheckIdentifier.RelearnMove); + } + + return res; + } + + private void verifyNoEmptyDuplicates(int[] Moves, CheckResult[] res) + { + bool emptySlot = false; + for (int i = 0; i < 4; i++) + { + if (Moves[i] == 0) + emptySlot = true; + else if (emptySlot) + res[i] = new CheckResult(Severity.Invalid, V167, res[i].Identifier); + else if (Moves.Count(m => m == Moves[i]) > 1) + res[i] = new CheckResult(Severity.Invalid, V168, res[i].Identifier); + } + } + private CheckResult verifyEggMoves() { if (!pkm.WasEgg || vMoves.All(m => m.Valid)) diff --git a/PKHeX/Resources/text/en/legality_en.txt b/PKHeX/Resources/text/en/legality_en.txt index 352f34b57..64c45d171 100644 Binary files a/PKHeX/Resources/text/en/legality_en.txt and b/PKHeX/Resources/text/en/legality_en.txt differ diff --git a/PKHeX/Resources/text/zh/legality_zh.txt b/PKHeX/Resources/text/zh/legality_zh.txt index d41cb0bbf..fdc137dfe 100644 --- a/PKHeX/Resources/text/zh/legality_zh.txt +++ b/PKHeX/Resources/text/zh/legality_zh.txt @@ -1,4 +1,4 @@ -V = 有效。 +V = 有效。 V193 = 合法。 V190 = 内部错误。 V189 = 无法对该宝可梦分析。 @@ -142,8 +142,9 @@ V108 = 隐藏特性与相遇方式不一致。 V109 = 特性被特性胶囊改变。 V110 = 特性与神秘礼物不一致。 V111 = 非帮手宝可梦拥有隐藏特性。 +V300 = Hidden Ability on non-horde/friend safari wild encounter. V112 = 隐藏特性不可获得。 -v217 = 隐藏洞穴捕获的宝可梦必定为隐藏特性。 +V217 = 隐藏洞穴捕获的宝可梦必定为隐藏特性。 V115 = 特性与特性值一致。 V113 = 特性与PID不一致。 V114 = 特性与特性值不一致。 @@ -169,6 +170,9 @@ V132 = 配信的初训家亲密度与初始亲密度不一致。 V133 = 配信的初训家牵绊度应为0。 V134 = 当前持有人不能为配信的初训家。 V138 = 华丽大赛状态值应为0。 +V301 = Invalid Console Region. +V302 = Geolocation: Country is not in 3DS region. +V303 = Geolocation: Country is in 3DS region. V137 = 地理位置回忆: 回忆应该存在。 V135 = 地理位置回忆: 间隔/空白存在。 V136 = 地理位置回忆: 地区没有国家。 @@ -183,6 +187,7 @@ V144 = 未交换: 美丽度足够但仍为1级。 V148 = 回忆: 持有人回忆里没有持有人的名字。 V150 = 回忆: 缺失持有人回忆。 V152 = 回忆: 缺失初训家回忆。 +V329 = Memory: Not cleared properly. V149 = 回忆: 蛋不能作为持有人的回忆。 V151 = 回忆: 蛋不能作为初训家的回忆。 V164 = {0} 回忆: 当前种类能在游戏中捕获。 @@ -215,4 +220,29 @@ V186 = 遗传招式检查功能未开发。 V156 = 应该有连接交换持有人的回忆。 V157 = 持有人回忆文本值(某处)。 V158 = 持有人回忆强度值应为(1st)。 -V159 = 持有人回忆感受值应为0-9。 \ No newline at end of file +V159 = 持有人回忆感受值应为0-9。 +V318 = Form is Valid. +V304 = Form Count is out of range. Expected <= {0}, got {1}. +V305 = Cosplay Pikachu cannot have the default form. +V306 = Only Cosplay Pikachu can have this form. +V307 = Event Pikachu cannot have the default form. +V308 = Held item does not match Form. +V309 = Held item matches Form. +V310 = Form cannot exist outside of a battle. +V311 = Event Vivillon pattern on pre-evolution. +V312 = Invalid Vivillon pattern. +V313 = Valid Vivillon pattern. +V314 = Invalid Eternal Flower encounter. +V315 = Valid Eternal Flower encounter. +V316 = Form cannot exist outside of Party. +V317 = Form cannot be obtained for pre-Alola generation games. +V319 = Cannot apply PP Ups to an Egg. +V320 = Cannot increase Contest Stats of an Egg. +V321 = Mystery Gift Fateful Encounter. +V322 = Mystery Gift Fateful Encounter flag missing. +V323 = Special ingame Fateful Encounter. +V324 = Special ingame Fateful Encounter flag missing. +V325 = Fateful Encounter should not be checked. +V326 = Special ingame N's Sparkle flag missing. +V327 = Special ingame N's Sparkle flag should not be checked. +V328 = Version Specific evolution requires a trade to opposite version. A Handling Trainer is required. \ No newline at end of file