From 0af983547d01888df38fbf7bd510a41fdd2bc61e Mon Sep 17 00:00:00 2001 From: javierhimura Date: Thu, 13 Apr 2017 17:48:13 +0200 Subject: [PATCH] Fix legality issues (#1055) * Added method getBaseEggSpecies to get the base species when the pokemon was an egg, is needed because for format 1 pokemon with egg origin every time getBaseSpecies is called is returning the gen 1 base species obtaining invalid eggmoves and base egg moves Also getBaseEggSpecies was using Evolves1 when format = 1 even when asking for a gen2 egg base species, returning Pikachu egg moves (empty list) instead of Pichu egg moves * Fix ability checking for generation 3 pokemon, likea de Seadra from Issue #1011 pkm.AbilityNumber have a value assuming PID match ability like a generation 4 pokemon but the validation should be ignored if is a generation 3 pokemon with only one ability in generation 3 Also changed the validation for ingame trades with fixed abilities to check only with generation 3 abilities in the case the species has two abilities generation 3, if only one was possible any PID should be valid with the generation 3 ability Encounter Trades Also the check for evolution was wrong, the most evolved species is the first in the evochain, not the last * Fix evolution chains for gen 3 pokemon in format 4 * Fix ability for generation 3 trades. Ability could not change if there were 2 abilities in generation 3, that means it is irrelevant if the pokemon evolved in gen 4-5, the ability number must match the encounter --- PKHeX/Legality/Checks.cs | 29 ++++++++++++++++++++--------- PKHeX/Legality/Core.cs | 30 ++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/PKHeX/Legality/Checks.cs b/PKHeX/Legality/Checks.cs index 83122a599..b2c5e0207 100644 --- a/PKHeX/Legality/Checks.cs +++ b/PKHeX/Legality/Checks.cs @@ -1242,8 +1242,9 @@ namespace PKHeX.Core return; } - if (EncounterMatch != null) + if (EncounterMatch != null && (!pkm.Gen3 || pkm.Format ==3)) { + // Gen 3 transfered to 4 could change ability, defer to verifyAbilityPreCapsule // Check Ability Mismatches int? EncounterAbility = (EncounterMatch as EncounterStatic)?.Ability ?? (EncounterMatch as EncounterTrade)?.Ability ?? @@ -1262,23 +1263,24 @@ namespace PKHeX.Core case 7: verifyAbility7(abilities); break; } } + var AbilityMatchPID = true; if (3 <= pkm.Format && pkm.Format <= 5) // 3-5 - verifyAbilityPreCapsule(abilities, abilval); + AbilityMatchPID = verifyAbilityPreCapsule(abilities, abilval); if (3 <= pkm.GenNumber && pkm.GenNumber <= 4 && pkm.AbilityNumber == 4) AddLine(Severity.Invalid, V112, CheckIdentifier.Ability); - else if (abilities[pkm.AbilityNumber >> 1] != pkm.Ability) + else if (AbilityMatchPID && abilities[pkm.AbilityNumber >> 1] != pkm.Ability) AddLine(Severity.Invalid, V114, CheckIdentifier.Ability); else AddLine(Severity.Valid, V115, CheckIdentifier.Ability); } - private void verifyAbilityPreCapsule(int[] abilities, int abilval) + private bool verifyAbilityPreCapsule(int[] abilities, int abilval) { if (pkm.Version == (int)GameVersion.CXD) { // TODO for GameCube analysis AddLine(Severity.Valid, V115, CheckIdentifier.Ability); - return; + return false; } var abilities_count = abilities.Distinct().Count(); @@ -1288,7 +1290,7 @@ namespace PKHeX.Core // gen3Species will be zero for pokemon with illegal gen 3 encounters, like Infernape with gen 3 "origin" // Do not check for gen 3 pokemon that has evolved into gen 4 species, // those have evolved in generation 4 or 5 and ability must match PID, not need to check gen 3 data - var gen3Species = EvoChainsAllGens[3].LastOrDefault()?.Species ?? 0; + var gen3Species = EvoChainsAllGens[3].FirstOrDefault()?.Species ?? 0; if (gen3Species > 0) AbilityMatchPID = verifyAbilityGen3Transfer(abilities, abilval, gen3Species, abilities_count); } @@ -1296,6 +1298,7 @@ namespace PKHeX.Core // Gen 4,5 pokemon or gen 3 pokemon evolved in gen 4,5 games, ability must match PID if (AbilityMatchPID && pkm.AbilityNumber != 1 << abilval) AddLine(Severity.Invalid, V113, CheckIdentifier.Ability); + return AbilityMatchPID; } private bool verifyAbilityGen3Transfer(int[] abilities, int abilval, int Species_g3, int abilities_count) { @@ -1305,11 +1308,17 @@ namespace PKHeX.Core var abilities_g3 = PersonalTable.E.getAbilities(Species_g3, pkm.AltForm).Where(a => a != 0).Distinct().ToArray(); if (abilities_g3.Length == 2) { + int? EncounterAbility = (EncounterMatch as EncounterTrade)?.Ability ?? null; + // If there were two abilities in generation 3 then ability match PID in gen 3 (is impossible not to do it) and will be the same ability if evolved in gen 4-5 + if (EncounterAbility != null && EncounterAbility != 0 && pkm.AbilityNumber != EncounterAbility) + { + AddLine(Severity.Invalid, V223, CheckIdentifier.Ability); + } // Shadow Colloseum pokemon could habe any PID without maching PID if has 2 abilities in generation 3 // For non-GC, it has 2 abilities in gen 3, must match PID return pkm.Version != (int)GameVersion.CXD; } - var Species_g45 = Math.Max(EvoChainsAllGens[4].LastOrDefault()?.Species ?? 0, pkm.Format == 5 ? EvoChainsAllGens[5].LastOrDefault()?.Species ?? 0 : 0); + var Species_g45 = Math.Max(EvoChainsAllGens[4].FirstOrDefault()?.Species ?? 0, pkm.Format == 5 ? EvoChainsAllGens[5].FirstOrDefault()?.Species ?? 0 : 0); if (Species_g45 > Species_g3) // it have evolved in gen 4 or 5 games, ability must match PID return true; @@ -2402,7 +2411,9 @@ namespace PKHeX.Core encounters.AddRange(EventGiftMatch.Where(x => (x as IMoveset)?.Moves != null)); if (null != EncounterStaticMatch) encounters.AddRange(EncounterStaticMatch.Where(x => (x as IMoveset)?.Moves != null)); - if (null != (EncounterMatch as IMoveset)?.Moves) + if (null != (EncounterMatch as EncounterTrade)) + encounters.Add(EncounterMatch); + else if (null != (EncounterMatch as IMoveset)?.Moves) encounters.Add(EncounterMatch); if (!pkm.IsEgg) @@ -2576,7 +2587,7 @@ namespace PKHeX.Core { for (int i = 0; i <= splitctr; i++) { - var baseSpecies = Legal.getBaseSpecies(pkm, i); + var baseSpecies = Legal.getBaseEggSpecies(pkm, i); if (baseSpecies != pkm.Species) continue; diff --git a/PKHeX/Legality/Core.cs b/PKHeX/Legality/Core.cs index ddb708a3c..cb2d509ff 100644 --- a/PKHeX/Legality/Core.cs +++ b/PKHeX/Legality/Core.cs @@ -958,7 +958,7 @@ namespace PKHeX.Core } internal static IEnumerable getBaseEggMoves(PKM pkm, int skipOption, GameVersion gameSource, int lvl) { - int species = getBaseSpecies(pkm, skipOption); + int species = getBaseEggSpecies(pkm, skipOption); if (gameSource == GameVersion.Any) gameSource = (GameVersion) pkm.Version; @@ -1049,7 +1049,7 @@ namespace PKHeX.Core } internal static IEnumerable getEggMoves(PKM pkm, int skipOption, GameVersion Version) { - return getEggMoves(pkm, getBaseSpecies(pkm, skipOption), 0, Version); + return getEggMoves(pkm, getBaseEggSpecies(pkm, skipOption), 0, Version); } internal static IEnumerable getG3SpecialEggEncounter(PKM pkm) { @@ -1606,7 +1606,7 @@ namespace PKHeX.Core if (t != null && t.TID != 0) return new GBEncounterData(pkm, 2, t); // gen2 trade if (WasEgg && new[] { sm, em, tm }.Min(a => a) >= 5) - return new GBEncounterData(getBaseSpecies(pkm, maxSpeciesOrigin: MaxSpeciesID_2)); // gen2 egg + return new GBEncounterData(getBaseEggSpecies(pkm)); // gen2 egg } if (em <= sm && em <= tm) return new GBEncounterData(pkm, gen, e.Where(slot => slot.Species == em).OrderBy(slot => slot.LevelMin).First()); @@ -1697,7 +1697,11 @@ namespace PKHeX.Core // Generation Specific Fetching private static EvolutionTree getEvolutionTable(PKM pkm) { - switch (pkm.Format) + return getEvolutionTable(pkm.Format); + } + private static EvolutionTree getEvolutionTable(int generation) + { + switch (generation) { case 1: return Evolves1; @@ -2283,15 +2287,21 @@ namespace PKHeX.Core return true; return getValidMoves(pkm, version, getValidPreEvolutions(pkm).ToArray(), generation, LVL: true, Relearn: true, Tutor: true, Machine: true).Contains(move); } - - internal static int getBaseSpecies(PKM pkm, int skipOption = 0, int maxSpeciesOrigin = -1) + internal static int getBaseEggSpecies(PKM pkm, int skipOption = 0) + { + if (pkm.Format == 1) + return getBaseSpecies(pkm, skipOption : skipOption, generation : 2); + return getBaseSpecies(pkm, skipOption); + } + internal static int getBaseSpecies(PKM pkm, int skipOption = 0, int generation = -1) { if (pkm.Species == 292) return 290; if (pkm.Species == 242 && pkm.CurrentLevel < 3) // Never Cleffa return 113; - var table = getEvolutionTable(pkm); + var table = generation != -1 ? getEvolutionTable(generation): getEvolutionTable(pkm); + int maxSpeciesOrigin = generation != -1 ? getMaxSpeciesOrigin(generation) : - 1; var evos = table.getValidPreEvolutions(pkm, 100, maxSpeciesOrigin: maxSpeciesOrigin, skipChecks:true).ToArray(); switch (skipOption) @@ -2350,7 +2360,7 @@ namespace PKHeX.Core if (pkm.Format <= 2) return 2; - if (!pkm.HasOriginalMetLocation) + if (!pkm.HasOriginalMetLocation && generation != pkm.GenNumber) return pkm.Met_Level; if (pkm.GenNumber <= 3) @@ -2392,7 +2402,7 @@ namespace PKHeX.Core continue; if ((pkm.Gen2 || pkm.VC2) && 3 <= gen && gen <= 6) continue; - if (!pkm.HasOriginalMetLocation && pkm.Format > 2 && gen <= 4 && lvl > pkm.Met_Level) + if (!pkm.HasOriginalMetLocation && pkm.Format > 2 && gen < pkm.Format && gen <= 4 && lvl > pkm.Met_Level) { // Met location was lost at this point but it also means the pokemon existed in generations 1 to 4 with maximum level equals to met level lvl = pkm.Met_Level; @@ -2430,7 +2440,7 @@ namespace PKHeX.Core //Remove previous evolutions bellow transfer level //For example a gen3 charizar in format 7 with current level 36 and met level 36 //chain level for charmander is 35, is bellow met level - GensEvoChains[gen] = GensEvoChains[gen].Where(e => e.Level >= lvl).ToArray(); + GensEvoChains[gen] = GensEvoChains[gen].Where(e => e.Level >= getMinLevelGeneration(pkm,gen)).ToArray(); } return GensEvoChains; }