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
This commit is contained in:
javierhimura 2017-04-13 17:48:13 +02:00 committed by Kurt
parent 2f59710eee
commit 0af983547d
2 changed files with 40 additions and 19 deletions

View file

@ -1242,8 +1242,9 @@ namespace PKHeX.Core
return; 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 // Check Ability Mismatches
int? EncounterAbility = (EncounterMatch as EncounterStatic)?.Ability ?? int? EncounterAbility = (EncounterMatch as EncounterStatic)?.Ability ??
(EncounterMatch as EncounterTrade)?.Ability ?? (EncounterMatch as EncounterTrade)?.Ability ??
@ -1262,23 +1263,24 @@ namespace PKHeX.Core
case 7: verifyAbility7(abilities); break; case 7: verifyAbility7(abilities); break;
} }
} }
var AbilityMatchPID = true;
if (3 <= pkm.Format && pkm.Format <= 5) // 3-5 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) if (3 <= pkm.GenNumber && pkm.GenNumber <= 4 && pkm.AbilityNumber == 4)
AddLine(Severity.Invalid, V112, CheckIdentifier.Ability); 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); AddLine(Severity.Invalid, V114, CheckIdentifier.Ability);
else else
AddLine(Severity.Valid, V115, CheckIdentifier.Ability); 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) if (pkm.Version == (int)GameVersion.CXD)
{ {
// TODO for GameCube analysis // TODO for GameCube analysis
AddLine(Severity.Valid, V115, CheckIdentifier.Ability); AddLine(Severity.Valid, V115, CheckIdentifier.Ability);
return; return false;
} }
var abilities_count = abilities.Distinct().Count(); 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" // 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, // 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 // 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) if (gen3Species > 0)
AbilityMatchPID = verifyAbilityGen3Transfer(abilities, abilval, gen3Species, abilities_count); 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 // Gen 4,5 pokemon or gen 3 pokemon evolved in gen 4,5 games, ability must match PID
if (AbilityMatchPID && pkm.AbilityNumber != 1 << abilval) if (AbilityMatchPID && pkm.AbilityNumber != 1 << abilval)
AddLine(Severity.Invalid, V113, CheckIdentifier.Ability); AddLine(Severity.Invalid, V113, CheckIdentifier.Ability);
return AbilityMatchPID;
} }
private bool verifyAbilityGen3Transfer(int[] abilities, int abilval, int Species_g3, int abilities_count) 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(); var abilities_g3 = PersonalTable.E.getAbilities(Species_g3, pkm.AltForm).Where(a => a != 0).Distinct().ToArray();
if (abilities_g3.Length == 2) 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 // 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 // For non-GC, it has 2 abilities in gen 3, must match PID
return pkm.Version != (int)GameVersion.CXD; 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) if (Species_g45 > Species_g3)
// it have evolved in gen 4 or 5 games, ability must match PID // it have evolved in gen 4 or 5 games, ability must match PID
return true; return true;
@ -2402,7 +2411,9 @@ namespace PKHeX.Core
encounters.AddRange(EventGiftMatch.Where(x => (x as IMoveset)?.Moves != null)); encounters.AddRange(EventGiftMatch.Where(x => (x as IMoveset)?.Moves != null));
if (null != EncounterStaticMatch) if (null != EncounterStaticMatch)
encounters.AddRange(EncounterStaticMatch.Where(x => (x as IMoveset)?.Moves != null)); 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); encounters.Add(EncounterMatch);
if (!pkm.IsEgg) if (!pkm.IsEgg)
@ -2576,7 +2587,7 @@ namespace PKHeX.Core
{ {
for (int i = 0; i <= splitctr; i++) for (int i = 0; i <= splitctr; i++)
{ {
var baseSpecies = Legal.getBaseSpecies(pkm, i); var baseSpecies = Legal.getBaseEggSpecies(pkm, i);
if (baseSpecies != pkm.Species) if (baseSpecies != pkm.Species)
continue; continue;

View file

@ -958,7 +958,7 @@ namespace PKHeX.Core
} }
internal static IEnumerable<int> getBaseEggMoves(PKM pkm, int skipOption, GameVersion gameSource, int lvl) internal static IEnumerable<int> getBaseEggMoves(PKM pkm, int skipOption, GameVersion gameSource, int lvl)
{ {
int species = getBaseSpecies(pkm, skipOption); int species = getBaseEggSpecies(pkm, skipOption);
if (gameSource == GameVersion.Any) if (gameSource == GameVersion.Any)
gameSource = (GameVersion) pkm.Version; gameSource = (GameVersion) pkm.Version;
@ -1049,7 +1049,7 @@ namespace PKHeX.Core
} }
internal static IEnumerable<int> getEggMoves(PKM pkm, int skipOption, GameVersion Version) internal static IEnumerable<int> 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<EncounterStatic> getG3SpecialEggEncounter(PKM pkm) internal static IEnumerable<EncounterStatic> getG3SpecialEggEncounter(PKM pkm)
{ {
@ -1606,7 +1606,7 @@ namespace PKHeX.Core
if (t != null && t.TID != 0) if (t != null && t.TID != 0)
return new GBEncounterData(pkm, 2, t); // gen2 trade return new GBEncounterData(pkm, 2, t); // gen2 trade
if (WasEgg && new[] { sm, em, tm }.Min(a => a) >= 5) 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) if (em <= sm && em <= tm)
return new GBEncounterData(pkm, gen, e.Where(slot => slot.Species == em).OrderBy(slot => slot.LevelMin).First()); 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 // Generation Specific Fetching
private static EvolutionTree getEvolutionTable(PKM pkm) private static EvolutionTree getEvolutionTable(PKM pkm)
{ {
switch (pkm.Format) return getEvolutionTable(pkm.Format);
}
private static EvolutionTree getEvolutionTable(int generation)
{
switch (generation)
{ {
case 1: case 1:
return Evolves1; return Evolves1;
@ -2283,15 +2287,21 @@ namespace PKHeX.Core
return true; return true;
return getValidMoves(pkm, version, getValidPreEvolutions(pkm).ToArray(), generation, LVL: true, Relearn: true, Tutor: true, Machine: true).Contains(move); return getValidMoves(pkm, version, getValidPreEvolutions(pkm).ToArray(), generation, LVL: true, Relearn: true, Tutor: true, Machine: true).Contains(move);
} }
internal static int getBaseEggSpecies(PKM pkm, int skipOption = 0)
internal static int getBaseSpecies(PKM pkm, int skipOption = 0, int maxSpeciesOrigin = -1) {
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) if (pkm.Species == 292)
return 290; return 290;
if (pkm.Species == 242 && pkm.CurrentLevel < 3) // Never Cleffa if (pkm.Species == 242 && pkm.CurrentLevel < 3) // Never Cleffa
return 113; 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(); var evos = table.getValidPreEvolutions(pkm, 100, maxSpeciesOrigin: maxSpeciesOrigin, skipChecks:true).ToArray();
switch (skipOption) switch (skipOption)
@ -2350,7 +2360,7 @@ namespace PKHeX.Core
if (pkm.Format <= 2) if (pkm.Format <= 2)
return 2; return 2;
if (!pkm.HasOriginalMetLocation) if (!pkm.HasOriginalMetLocation && generation != pkm.GenNumber)
return pkm.Met_Level; return pkm.Met_Level;
if (pkm.GenNumber <= 3) if (pkm.GenNumber <= 3)
@ -2392,7 +2402,7 @@ namespace PKHeX.Core
continue; continue;
if ((pkm.Gen2 || pkm.VC2) && 3 <= gen && gen <= 6) if ((pkm.Gen2 || pkm.VC2) && 3 <= gen && gen <= 6)
continue; 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 // 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; lvl = pkm.Met_Level;
@ -2430,7 +2440,7 @@ namespace PKHeX.Core
//Remove previous evolutions bellow transfer level //Remove previous evolutions bellow transfer level
//For example a gen3 charizar in format 7 with current level 36 and met level 36 //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 //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; return GensEvoChains;
} }