mirror of
https://github.com/kwsch/PKHeX.git
synced 2026-08-28 03:06:24 -05:00
New legallity checks (#1196)
* Add move source to the check result for current moves, it will be used for analysis of evolution with move to determine how many egg moves had the pokemon and determine if the evolution move could be a egg move that was forgotten * Verify evolution for species that evolved leveling up with an specific move learned, the evolution must be at least one level after the pokemon could legally learn the move or one level after transfer to the first generation where it can evolve * Check to detect traded unevolved Kadabra based in catch rate and moves exclusive from yellow or red/blue If pokemon have data exclusive from one version but is in another version that means it should be evolved * Check no tradeback moves for preevolutions, like Pichu exclusive non tradeback moves for a Pikachu, that Pikachu could not have at the same time Pichu gen 2 moves and gen 1 moves because move reminder do not allow to relearn Pichu moves and gen 2 moves must be forgotten to trade into generation 1 games * Legallity strings for non tradeback checks * https://bulbapedia.bulbagarden.net/wiki/Pok%C3%A9mon_breeding#Passing_moves_down Eggs only inherit a level up move if both parents know the move, that means genderless and male only moves could not have any level up move as an egg except the base egg moves because Ditto is one parent Nidoran male and Volbeat excluded because they can breed with Nidoran female and Illusime * Small check to not search for egg moves in genderless pokemon, generation 2 data include egg moves for Starmie * Fix female only species * Stomp is not a possible egg moves of Stanee * Fix Steenee evolution move, it cant be inherited as an egg
This commit is contained in:
@@ -44,7 +44,10 @@ private IEnumerable<int> AllSuggestedRelearnMoves
|
||||
if (Error)
|
||||
return new int[4];
|
||||
if (_allSuggestedRelearnMoves == null)
|
||||
return _allSuggestedRelearnMoves = pkm == null || !pkm.IsOriginValid ? new int[4] : Legal.getValidRelearn(pkm, info.EncounterMatch.Species).ToArray();
|
||||
{
|
||||
var inheritLvlMoves = pkm.PersonalInfo.Gender > 0 && pkm.PersonalInfo.Gender < 255 || Legal.MixedGenderBreeding.Contains(info.EncounterMatch.Species);
|
||||
return _allSuggestedRelearnMoves = pkm == null || !pkm.IsOriginValid ? new int[4] : Legal.getValidRelearn(pkm, info.EncounterMatch.Species, inheritLvlMoves).ToArray();
|
||||
}
|
||||
return _allSuggestedRelearnMoves;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,7 +626,7 @@ private void verifyLevel()
|
||||
}
|
||||
private void verifyG1TradeEvo()
|
||||
{
|
||||
var mustevolve = pkm.TradebackStatus == TradebackType.WasTradeback || (pkm.Format == 1 && Legal.IsOutsider(pkm));
|
||||
var mustevolve = pkm.TradebackStatus == TradebackType.WasTradeback || (pkm.Format == 1 && Legal.IsOutsider(pkm)) || Legal.IsTradedKadabraG1(pkm);
|
||||
if (!mustevolve)
|
||||
return;
|
||||
// Pokemon have been traded but it is not evolved, trade evos are sequential dex numbers
|
||||
@@ -1792,7 +1792,7 @@ private void verifyForm()
|
||||
int index = Array.IndexOf(pkm.Moves, 548); // Secret Sword
|
||||
bool noSword = index < 0;
|
||||
if (pkm.AltForm == 0 ^ noSword) // mismatch
|
||||
info.vMoves[noSword ? 0 : index] = new CheckResult(Severity.Invalid, V169, CheckIdentifier.Move);
|
||||
info.vMoves[noSword ? 0 : index] = new CheckMoveResult(info.vMoves[noSword ? 0 : index], Severity.Invalid, V169, CheckIdentifier.Move);
|
||||
break;
|
||||
}
|
||||
case 649: // Genesect
|
||||
|
||||
@@ -1206,7 +1206,7 @@ internal static IEnumerable<int> getValidMoves(PKM pkm, DexLevel[] evoChain, int
|
||||
version = GameVersion.Any;
|
||||
return getValidMoves(pkm, version, evoChain, generation, minLvLG1: minLvLG1, LVL: LVL, Relearn: false, Tutor: Tutor, Machine: Machine, MoveReminder: MoveReminder, RemoveTransferHM: RemoveTransferHM);
|
||||
}
|
||||
internal static IEnumerable<int> getValidRelearn(PKM pkm, int species)
|
||||
internal static IEnumerable<int> getValidRelearn(PKM pkm, int species, bool inheritlvlmoves)
|
||||
{
|
||||
List<int> r = new List<int> { 0 };
|
||||
if (pkm.GenNumber < 6 || pkm.VC)
|
||||
@@ -1219,7 +1219,7 @@ internal static IEnumerable<int> getValidRelearn(PKM pkm, int species)
|
||||
form = 0;
|
||||
|
||||
r.AddRange(getEggMoves(pkm, species, form));
|
||||
if (pkm.Species != 489)
|
||||
if (inheritlvlmoves)
|
||||
r.AddRange(getRelearnLVLMoves(pkm, species, 100, pkm.AltForm));
|
||||
return r.Distinct();
|
||||
}
|
||||
@@ -1997,6 +1997,63 @@ internal static bool getEvolutionValid(PKM pkm, int minSpecies = -1)
|
||||
return curr.Count() >= poss.Count() - 1;
|
||||
return curr.Count() >= poss.Count();
|
||||
}
|
||||
internal static bool getEvolutionWithMoveValid(PKM pkm, LegalInfo info)
|
||||
{
|
||||
// Exclude species that do not evolve leveling with a move
|
||||
// Exclude gen 1-3 games
|
||||
// Exclude Mr Mime and Snorlax for gen 1-3 games
|
||||
if (!SpeciesEvolutionWithMove.Contains(pkm.Species) || pkm.Format <= 3 || (BabyEvolutionWithMove.Contains(pkm.Species) && pkm.GenNumber <= 3))
|
||||
return true;
|
||||
|
||||
var index = Array.FindIndex(SpeciesEvolutionWithMove, p => p == pkm.Species);
|
||||
var levels = MinLevelEvolutionWithMove[index];
|
||||
var moves = MoveEvolutionWithMove[index];
|
||||
var allowegg = EggMoveEvolutionWithMove[index][pkm.GenNumber];
|
||||
|
||||
// Get the minimun level in any generation when the pokemon could learn the evolve move
|
||||
var LearnLevel = 101;
|
||||
for(int g = pkm.GenNumber; g <= pkm.Format; g++)
|
||||
if(pkm.InhabitedGeneration(g) && levels[g] > 0)
|
||||
LearnLevel = Math.Min(LearnLevel, levels[g]);
|
||||
|
||||
// Check also if the current encounter include the evolve move as an special move
|
||||
// That means the pokemon have the move from the encounter level
|
||||
int[] SpecialMoves = (info.EncounterMatch as IMoveset)?.Moves ?? new int[0];
|
||||
if (SpecialMoves.Any(m => moves.Contains(m)))
|
||||
LearnLevel = Math.Min(LearnLevel, info.EncounterMatch.LevelMin);
|
||||
|
||||
// If the encounter is a player hatched egg check if the move could be an egg move or inherited level up move
|
||||
if (info.EncounterMatch.EggEncounter && !pkm.WasGiftEgg && !pkm.WasEventEgg && allowegg)
|
||||
{
|
||||
var inheritmove = false;
|
||||
if (pkm.GenNumber >= 6)
|
||||
// 3DS games, if the move is not a relearn move that means the pokemon was hatched without the move
|
||||
inheritmove = pkm.RelearnMoves.Any(m => moves.Contains(m));
|
||||
else if (pkm.Moves.Any(m => moves.Contains(m)))
|
||||
// Pre-3DS games, if the pokemon was an egg and it have the move and also and egg from this species could hatch with the move
|
||||
// that means is a valid egg move
|
||||
inheritmove = true;
|
||||
else
|
||||
{
|
||||
// If the pokemon does not have the move it still could be an egg move that was forgotten
|
||||
// But that requires for the pokemon to do not have 4 other moves identified as egg moves or inherited level up moves
|
||||
var eggmoves = info.vMoves.Count(m => m.Source == MoveSource.EggMove || m.Source == MoveSource.InheritLevelUp);
|
||||
inheritmove = eggmoves < 4;
|
||||
}
|
||||
if (inheritmove)
|
||||
LearnLevel = Math.Min(LearnLevel, pkm.GenNumber < 4 ? 5 : 1);
|
||||
}
|
||||
|
||||
// If has original met location the minimun evolution level is one level after met level
|
||||
// Gen 3 pokemon in gen 4 games minimun level is one level after transfer to generation 4
|
||||
// VC pokemon minimun level is one leve after transfer to generation 7
|
||||
// Sylveon always one level after met level, for gen 4 and 5 eevees in gen 6 games minimun for evolution is one leve after transfer to generation 5
|
||||
if (pkm.HasOriginalMetLocation || pkm.Format == 4 && pkm.Gen3 || pkm.VC || pkm.Species == 700)
|
||||
LearnLevel = Math.Max(pkm.Met_Level, LearnLevel);
|
||||
|
||||
// Current level must be at leats one level after the minimun learn level
|
||||
return pkm.CurrentLevel > LearnLevel;
|
||||
}
|
||||
internal static bool getCanFormChange(PKM pkm, int species)
|
||||
{
|
||||
if (FormChange.Contains(species))
|
||||
@@ -2642,7 +2699,7 @@ private static IEnumerable<int> getMoves(PKM pkm, int species, int minlvlG1, int
|
||||
|
||||
internal static int[] getEggMoves(PKM pkm, int species, int formnum, GameVersion Version = GameVersion.Any)
|
||||
{
|
||||
if (!pkm.InhabitedGeneration(pkm.GenNumber, species))
|
||||
if (!pkm.InhabitedGeneration(pkm.GenNumber, species) || pkm.PersonalInfo.Gender == 255)
|
||||
return new int[0];
|
||||
|
||||
switch (pkm.GenNumber)
|
||||
@@ -2872,6 +2929,34 @@ internal static List<int>[] GetEmptyMovesList(DexLevel[][] EvoChainsAllGens)
|
||||
empty[i] = new List<int>();
|
||||
return empty;
|
||||
}
|
||||
internal static bool IsTradedKadabraG1(PKM pkm)
|
||||
{
|
||||
if (pkm.SpecForm != 64 || pkm.Format > 1)
|
||||
return false;
|
||||
if (pkm.TradebackStatus == TradebackType.WasTradeback)
|
||||
return true;
|
||||
var IsYellow = Savegame_Version == GameVersion.Y;
|
||||
if (pkm.TradebackStatus == TradebackType.Gen1_NotTradeback)
|
||||
{
|
||||
// If catch rate is abra catch rate it wont trigger as invalid trade without evolution, it could be traded as Abra
|
||||
var catch_rate = (pkm as PK1).Catch_Rate;
|
||||
// Yellow Kadabra catch rate in Red/Blue game, must be Allakazham
|
||||
if (catch_rate == PersonalTable.Y[64].CatchRate && !IsYellow)
|
||||
return true;
|
||||
// Red/Blue Kadabra catch rate in Yellow game, must be Allakazham
|
||||
if (catch_rate == PersonalTable.RB[64].CatchRate && IsYellow)
|
||||
return true;
|
||||
}
|
||||
if (IsYellow)
|
||||
return false;
|
||||
// Yellow only moves in Red/Blue game, must be Allakazham
|
||||
if (pkm.Moves.Contains(134)) // Kinesis, yellow only move
|
||||
return true;
|
||||
if (pkm.CurrentLevel < 20 && pkm.Moves.Contains(50)) // Disable bellow level 20, yellow only move
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
internal static bool IsOutsider(PKM pkm)
|
||||
{
|
||||
var Outsider = Savegame_TID != pkm.TID || Savegame_OT != pkm.OT_Name;
|
||||
|
||||
@@ -41,7 +41,7 @@ public static LegalInfo verifyEncounter(PKM pkm)
|
||||
if (info.vMoves.Any(z => !z.Valid) && encounter.PeekIsNext())
|
||||
continue;
|
||||
|
||||
var evo = VerifyEvolution.verifyEvolution(pkm, EncounterMatch);
|
||||
var evo = VerifyEvolution.verifyEvolution(pkm, info);
|
||||
if (!evo.Valid && encounter.PeekIsNext())
|
||||
continue;
|
||||
info.Parse.Add(evo);
|
||||
|
||||
@@ -31,7 +31,7 @@ public IEncounterable EncounterMatch
|
||||
public readonly List<CheckResult> Parse = new List<CheckResult>();
|
||||
|
||||
public CheckResult[] vRelearn = new CheckResult[4];
|
||||
public CheckResult[] vMoves = new CheckResult[4];
|
||||
public CheckMoveResult[] vMoves = new CheckMoveResult[4];
|
||||
|
||||
public DexLevel[][] EvoChainsAllGens => _evochains ?? (_evochains = Legal.getEvolutionChainsAllGens(pkm, EncounterMatch));
|
||||
public ValidEncounterMoves EncounterMoves { get; set; }
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace PKHeX.Core
|
||||
{
|
||||
public static class VerifyCurrentMoves
|
||||
{
|
||||
public static CheckResult[] verifyMoves(PKM pkm, LegalInfo info, GameVersion game = GameVersion.Any)
|
||||
public static CheckMoveResult[] verifyMoves(PKM pkm, LegalInfo info, GameVersion game = GameVersion.Any)
|
||||
{
|
||||
int[] Moves = pkm.Moves;
|
||||
var res = parseMovesForEncounters(pkm, info, game, Moves);
|
||||
@@ -16,12 +16,12 @@ public static CheckResult[] verifyMoves(PKM pkm, LegalInfo info, GameVersion gam
|
||||
// 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);
|
||||
res[0] = new CheckMoveResult(res[0], Severity.Invalid, V167, CheckIdentifier.Move);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static CheckResult[] parseMovesForEncounters(PKM pkm, LegalInfo info, GameVersion game, int[] Moves)
|
||||
private static CheckMoveResult[] parseMovesForEncounters(PKM pkm, LegalInfo info, GameVersion game, int[] Moves)
|
||||
{
|
||||
if (pkm.Species == 235) // special handling for Smeargle
|
||||
return parseMovesForSmeargle(pkm, Moves, info); // Smeargle can have any moves except a few
|
||||
@@ -55,10 +55,10 @@ private static CheckResult[] parseMovesForEncounters(PKM pkm, LegalInfo info, Ga
|
||||
pkm.TradebackStatus = defaultTradeback;
|
||||
return res;
|
||||
}
|
||||
private static CheckResult[] parseMovesForSmeargle(PKM pkm, int[] Moves, LegalInfo info)
|
||||
private static CheckMoveResult[] parseMovesForSmeargle(PKM pkm, int[] Moves, LegalInfo info)
|
||||
{
|
||||
if (!pkm.IsEgg)
|
||||
return parseMovesSketch(Moves);
|
||||
return parseMovesSketch(pkm, Moves);
|
||||
|
||||
// can only know sketch as egg
|
||||
var empty = ValidEncounterMoves.Empty;
|
||||
@@ -66,15 +66,18 @@ private static CheckResult[] parseMovesForSmeargle(PKM pkm, int[] Moves, LegalIn
|
||||
{
|
||||
validLevelUpMoves = Legal.getValidMovesAllGens(pkm, info.EvoChainsAllGens, minLvLG1: 1, Tutor: false, Machine: false, RemoveTransferHM: false)
|
||||
};
|
||||
return parseMoves(pkm, pkm.Moves, new int[0], new int[0], new int[0], empty, new int[0], new int[0], false, info);
|
||||
return parseMoves(pkm, pkm.Moves, new int[0], new int[0], new int[0], new int[0], new int[0], new int[0], false, info);
|
||||
}
|
||||
private static CheckResult[] parseMovesIsEggPreRelearn(PKM pkm, int[] Moves, int[] SpecialMoves, bool allowinherited, EncounterEgg e)
|
||||
private static CheckMoveResult[] parseMovesIsEggPreRelearn(PKM pkm, int[] Moves, int[] SpecialMoves, bool allowinherited, EncounterEgg e)
|
||||
{
|
||||
CheckResult[] res = new CheckResult[4];
|
||||
CheckMoveResult[] res = new CheckMoveResult[4];
|
||||
var ValidSpecialMoves = SpecialMoves.Where(m => m != 0).ToList();
|
||||
|
||||
var baseEggMoves = Legal.getBaseEggMoves(pkm, e.Species, e.Game, pkm.GenNumber < 4 ? 5 : 1)?.ToList() ?? new List<int>();
|
||||
var InheritedLvlMoves = Legal.getBaseEggMoves(pkm, e.Species, e.Game, 100)?.ToList() ?? new List<int>();
|
||||
// Level up moves could not be inherited if Ditto is parent,
|
||||
// that means genderless species and male only species except Nidoran and Volbet (they breed with female nidoran and illumise) could not have level up moves as an egg
|
||||
var AllowLvlMoves = pkm.PersonalInfo.Gender > 0 && pkm.PersonalInfo.Gender < 255 || Legal.MixedGenderBreeding.Contains(e.Species);
|
||||
var InheritedLvlMoves = !AllowLvlMoves? new List<int>() : Legal.getBaseEggMoves(pkm, e.Species, e.Game, 100)?.ToList() ?? new List<int>();
|
||||
var EggMoves = Legal.getEggMoves(pkm, e.Species, pkm.AltForm)?.ToList() ?? new List<int>();
|
||||
var InheritedTutorMoves = e.Game == GameVersion.C ? Legal.getTutorMoves(pkm, pkm.Species, pkm.AltForm, false, 2)?.ToList() : new List<int>();
|
||||
// Only TM Hm moves from the source game of the egg, not any other games from the same generation
|
||||
@@ -94,30 +97,35 @@ private static CheckResult[] parseMovesIsEggPreRelearn(PKM pkm, int[] Moves, int
|
||||
|
||||
return res;
|
||||
}
|
||||
private static CheckResult[] parseMovesWasEggPreRelearn(PKM pkm, int[] Moves, LegalInfo info, EncounterEgg e)
|
||||
private static CheckMoveResult[] parseMovesWasEggPreRelearn(PKM pkm, int[] Moves, LegalInfo info, EncounterEgg e)
|
||||
{
|
||||
var EventEggMoves = (info.EncounterMatch as IMoveset)?.Moves ?? new int[0];
|
||||
int BaseLvlMoves = 489 <= pkm.Species && pkm.Species <= 490 ? 1 : 100;
|
||||
// Level up moves could not be inherited if Ditto is parent,
|
||||
// that means genderless species and male only species except Nidoran and Volbet (they breed with female nidoran and illumise) could not have level up moves as an egg
|
||||
var inheritLvlMoves = pkm.PersonalInfo.Gender > 0 && pkm.PersonalInfo.Gender < 255 || Legal.MixedGenderBreeding.Contains(e.Species);
|
||||
int BaseLvlMoves = inheritLvlMoves ? 100 : pkm.GenNumber <= 3 ? 5 : 1;
|
||||
var LvlupEggMoves = Legal.getBaseEggMoves(pkm, e.Species, e.Game, BaseLvlMoves);
|
||||
// Level up, TMHM or tutor moves exclusive to the incense egg species, like Azurill, incompatible with the non-incense species egg moves
|
||||
var ExclusiveIncenseMoves = e.SplitBreed ? Legal.getExclusivePreEvolutionMoves(pkm, Legal.getBaseEggSpecies(pkm), info.EvoChainsAllGens, e.Game) : null;
|
||||
var TradebackPreevo = pkm.Format == 2 && info.EncounterMatch.Species > 151;
|
||||
var NonTradebackLvlMoves = new int[0];
|
||||
if (TradebackPreevo)
|
||||
NonTradebackLvlMoves = Legal.getExclusivePreEvolutionMoves(pkm, info.EncounterMatch.Species, info.EvoChainsAllGens[2], 2, e.Game).Where(m => m > Legal.MaxMoveID_1).ToArray();
|
||||
var EggMoves = Legal.getEggMoves(pkm, e.Species, pkm.AltForm);
|
||||
|
||||
bool volt = (pkm.GenNumber > 3 || e.Game == GameVersion.E) && Legal.LightBall.Contains(pkm.Species);
|
||||
var SpecialMoves = volt && EventEggMoves.Length == 0 ? new[] { 344 } : new int[0]; // Volt Tackle for bred Pichu line
|
||||
|
||||
return parseMoves(pkm, Moves, SpecialMoves, LvlupEggMoves, EggMoves, ExclusiveIncenseMoves, EventEggMoves, new int[0], e.SplitBreed, info);
|
||||
return parseMoves(pkm, Moves, SpecialMoves, LvlupEggMoves, EggMoves, NonTradebackLvlMoves, EventEggMoves, new int[0], e.SplitBreed, info);
|
||||
}
|
||||
private static CheckResult[] parseMovesSketch(int[] Moves)
|
||||
private static CheckMoveResult[] parseMovesSketch(PKM pkm, int[] Moves)
|
||||
{
|
||||
CheckResult[] res = new CheckResult[4];
|
||||
CheckMoveResult[] res = new CheckMoveResult[4];
|
||||
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);
|
||||
? new CheckMoveResult(MoveSource.Unknown, pkm.Format, Severity.Invalid, V166, CheckIdentifier.Move)
|
||||
: new CheckMoveResult(MoveSource.Sketch, pkm.Format, CheckIdentifier.Move);
|
||||
return res;
|
||||
}
|
||||
private static CheckResult[] parseMoves3DS(PKM pkm, GameVersion game, int[] Moves, LegalInfo info)
|
||||
private static CheckMoveResult[] parseMoves3DS(PKM pkm, GameVersion game, int[] Moves, LegalInfo info)
|
||||
{
|
||||
info.EncounterMoves.Relearn = pkm.GenNumber >= 6 ? pkm.RelearnMoves : new int[0];
|
||||
if (info.EncounterMatch is IMoveset)
|
||||
@@ -126,7 +134,7 @@ private static CheckResult[] parseMoves3DS(PKM pkm, GameVersion game, int[] Move
|
||||
// Everything else
|
||||
return parseMovesRelearn(pkm, Moves, info);
|
||||
}
|
||||
private static CheckResult[] parseMovesPre3DS(PKM pkm, int[] Moves, LegalInfo info)
|
||||
private static CheckMoveResult[] parseMovesPre3DS(PKM pkm, int[] Moves, LegalInfo info)
|
||||
{
|
||||
if (pkm.IsEgg && info.EncounterMatch is EncounterEgg egg)
|
||||
{
|
||||
@@ -142,66 +150,65 @@ private static CheckResult[] parseMovesPre3DS(PKM pkm, int[] Moves, LegalInfo in
|
||||
|
||||
return parseMovesSpecialMoveset(pkm, Moves, info);
|
||||
}
|
||||
private static CheckResult[] parseMovesGen1(PKM pkm, int[] Moves, LegalInfo info)
|
||||
private static CheckMoveResult[] parseMovesGen1(PKM pkm, int[] Moves, LegalInfo info)
|
||||
{
|
||||
GameVersion[] games = Legal.getGen1GameEncounter(pkm);
|
||||
CheckResult[] res = new CheckResult[4];
|
||||
CheckMoveResult[] res = new CheckMoveResult[4];
|
||||
var G1Encounter = info.EncounterMatch;
|
||||
if (G1Encounter == null)
|
||||
return parseMovesSpecialMoveset(pkm, Moves, info);
|
||||
var InitialMoves = new int[0];
|
||||
int[] SpecialMoves = (info.EncounterMatch as IMoveset)?.Moves ?? new int[0];
|
||||
var empty = Legal.GetEmptyMovesList(info.EvoChainsAllGens);
|
||||
var emptyegg = new int[0];
|
||||
foreach (GameVersion ver in games)
|
||||
{
|
||||
var VerInitialMoves = Legal.getInitialMovesGBEncounter(G1Encounter.Species, G1Encounter.LevelMin, ver).ToArray();
|
||||
if (VerInitialMoves.SequenceEqual(InitialMoves))
|
||||
return res;
|
||||
res = parseMoves(pkm, Moves, SpecialMoves, emptyegg, emptyegg, empty, new int[0], VerInitialMoves, false, info);
|
||||
res = parseMoves(pkm, Moves, SpecialMoves, emptyegg, emptyegg, emptyegg, new int[0], VerInitialMoves, false, info);
|
||||
if (res.All(r => r.Valid))
|
||||
return res;
|
||||
InitialMoves = VerInitialMoves;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
private static CheckResult[] parseMovesSpecialMoveset(PKM pkm, int[] Moves, LegalInfo info)
|
||||
private static CheckMoveResult[] parseMovesSpecialMoveset(PKM pkm, int[] Moves, LegalInfo info)
|
||||
{
|
||||
var mg = info.EncounterMatch as IMoveset;
|
||||
int[] SpecialMoves = mg?.Moves ?? new int[0];
|
||||
var empty = Legal.GetEmptyMovesList(info.EvoChainsAllGens);
|
||||
var emptyegg = new int[0];
|
||||
CheckResult[] res = parseMoves(pkm, Moves, SpecialMoves, emptyegg, emptyegg, empty, new int[0], new int[0], false, info);
|
||||
CheckMoveResult[] res = parseMoves(pkm, Moves, SpecialMoves, emptyegg, emptyegg, emptyegg, new int[0], new int[0], false, info);
|
||||
if (res.Any(r => !r.Valid))
|
||||
return res;
|
||||
|
||||
return res;
|
||||
}
|
||||
private static CheckResult[] parseMovesRelearn(PKM pkm, int[] Moves, LegalInfo info)
|
||||
private static CheckMoveResult[] parseMovesRelearn(PKM pkm, int[] Moves, LegalInfo info)
|
||||
{
|
||||
var emptyegg = new int[0];
|
||||
|
||||
var issplitbreed = pkm.WasEgg && Legal.SplitBreed.Contains(pkm.Species);
|
||||
var e = info.EncounterMatch as EncounterEgg;
|
||||
var EggMoves = e != null ? Legal.getEggMoves(pkm, e.Species, pkm.AltForm, e.Game) : emptyegg;
|
||||
// Level up, TMHM or tutor moves exclusive to the incense egg species, like Azurill, incompatible with the non-incense species egg moves
|
||||
var ExclusiveIncenseMoves = issplitbreed ? Legal.getExclusivePreEvolutionMoves(pkm, Legal.getBaseEggSpecies(pkm), info.EvoChainsAllGens, e.Game) : Legal.GetEmptyMovesList(info.EvoChainsAllGens);
|
||||
|
||||
var TradebackPreevo = pkm.Format == 2 && info.EncounterMatch.Species > 151 && pkm.InhabitedGeneration(1);
|
||||
var NonTradebackLvlMoves = TradebackPreevo ? Legal.getExclusivePreEvolutionMoves(pkm, info.EncounterMatch.Species, info.EvoChainsAllGens[2], 2, e.Game).Where(m => m > Legal.MaxMoveID_1).ToArray() : new int[0];
|
||||
|
||||
int[] RelearnMoves = pkm.RelearnMoves;
|
||||
int[] SpecialMoves = (info.EncounterMatch as IMoveset)?.Moves ?? new int[0];
|
||||
|
||||
CheckResult[] res = parseMoves(pkm, Moves, SpecialMoves, new int[0], EggMoves, ExclusiveIncenseMoves, new int[0], new int[0], issplitbreed, info);
|
||||
CheckMoveResult[] res = parseMoves(pkm, Moves, SpecialMoves, new int[0], EggMoves, NonTradebackLvlMoves, new int[0], new int[0], issplitbreed, info);
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
if ((pkm.IsEgg || res[i].Flag) && !RelearnMoves.Contains(Moves[i]))
|
||||
res[i] = new CheckResult(Severity.Invalid, string.Format(V170, res[i].Comment), res[i].Identifier);
|
||||
res[i] = new CheckMoveResult(res[i], Severity.Invalid, string.Format(V170, res[i].Comment), res[i].Identifier);
|
||||
|
||||
return res;
|
||||
}
|
||||
private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int[] lvlupegg, int[] egg, List<int>[] IncenseExclusiveMoves, int[] eventegg, int[] initialmoves, bool issplitbreed, LegalInfo info)
|
||||
private static CheckMoveResult[] parseMoves(PKM pkm, int[] moves, int[] special, int[] lvlupegg, int[] egg, int[] NonTradebackLvlMoves, int[] eventegg, int[] initialmoves, bool issplitbreed, LegalInfo info)
|
||||
{
|
||||
CheckResult[] res = new CheckResult[4];
|
||||
CheckMoveResult[] res = new CheckMoveResult[4];
|
||||
var Gen1MovesLearned = new List<int>();
|
||||
var Gen2PreevoMovesLearned = new List<int>();
|
||||
var EggMovesLearned = new List<int>();
|
||||
var LvlupEggMovesLearned = new List<int>();
|
||||
var EventEggMovesLearned = new List<int>();
|
||||
@@ -213,9 +220,9 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (moves[m] == 0)
|
||||
res[m] = new CheckResult(m < required ? Severity.Invalid : Severity.Valid, V167, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.None, pkm.Format, m < required ? Severity.Invalid : Severity.Valid, V167, CheckIdentifier.Move);
|
||||
else if (info.EncounterMoves.Relearn.Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Valid, V172, CheckIdentifier.Move) { Flag = true };
|
||||
res[m] = new CheckMoveResult(MoveSource.Relearn, pkm.GenNumber, Severity.Valid, V172, CheckIdentifier.Move) { Flag = true };
|
||||
}
|
||||
|
||||
if (res.All(r => r != null))
|
||||
@@ -251,21 +258,28 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
continue;
|
||||
|
||||
if (gen == 1 && initialmoves.Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Valid, native ? V361 : string.Format(V362, gen), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.Initial, gen, Severity.Valid, native ? V361 : string.Format(V362, gen), CheckIdentifier.Move);
|
||||
else if (info.EncounterMoves.validLevelUpMoves[gen].Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Valid, native ? V177 : string.Format(V330, gen), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.LevelUp, gen, Severity.Valid, native ? V177 : string.Format(V330, gen), CheckIdentifier.Move);
|
||||
else if (info.EncounterMoves.validTMHMMoves[gen].Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Valid, native ? V173 : string.Format(V331, gen), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.TMHM, gen, Severity.Valid, native ? V173 : string.Format(V331, gen), CheckIdentifier.Move);
|
||||
else if (info.EncounterMoves.validTutorMoves[gen].Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Valid, native ? V174 : string.Format(V332, gen), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.Tutor, gen, Severity.Valid, native ? V174 : string.Format(V332, gen), CheckIdentifier.Move);
|
||||
else if (gen == pkm.GenNumber && special.Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Valid, V175, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.Special, gen, Severity.Valid, V175, CheckIdentifier.Move);
|
||||
|
||||
if (res[m] == null || gen < 3)
|
||||
continue;
|
||||
|
||||
if (res[m].Valid && gen == 2 && NonTradebackLvlMoves.Contains(m))
|
||||
Gen2PreevoMovesLearned.Add(m);
|
||||
if (res[m].Valid && gen == 1)
|
||||
{
|
||||
Gen1MovesLearned.Add(m);
|
||||
if (Gen2PreevoMovesLearned.Any())
|
||||
MixedGen1NonTradebackGen2 = true;
|
||||
}
|
||||
|
||||
if (res[m].Valid && gen <= 2 && pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber != gen)
|
||||
pkm.TradebackStatus = TradebackType.WasTradeback;
|
||||
}
|
||||
@@ -285,11 +299,11 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
|
||||
if (IsGen2Pkm && Gen1MovesLearned.Any() && moves[m] > Legal.MaxMoveID_1)
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Invalid, V334, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.InheritLevelUp, gen, Severity.Invalid, V334, CheckIdentifier.Move);
|
||||
MixedGen1NonTradebackGen2 = true;
|
||||
}
|
||||
else
|
||||
res[m] = new CheckResult(Severity.Valid, V345, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.InheritLevelUp, gen, Severity.Valid, V345, CheckIdentifier.Move);
|
||||
LvlupEggMovesLearned.Add(m);
|
||||
if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1)
|
||||
pkm.TradebackStatus = TradebackType.WasTradeback;
|
||||
@@ -310,11 +324,11 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
{
|
||||
// To learn exclusive generation 1 moves the pokemon was tradeback, but it can't be trade to generation 1
|
||||
// without removing moves above MaxMoveID_1, egg moves above MaxMoveID_1 and gen 1 moves are incompatible
|
||||
res[m] = new CheckResult(Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true };
|
||||
res[m] = new CheckMoveResult(MoveSource.EggMove, gen, Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true };
|
||||
MixedGen1NonTradebackGen2 = true;
|
||||
}
|
||||
else
|
||||
res[m] = new CheckResult(Severity.Valid, V171, CheckIdentifier.Move) { Flag = true };
|
||||
res[m] = new CheckMoveResult(MoveSource.EggMove, gen, Severity.Valid, V171, CheckIdentifier.Move) { Flag = true };
|
||||
|
||||
EggMovesLearned.Add(m);
|
||||
if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1)
|
||||
@@ -327,11 +341,11 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
{
|
||||
if (IsGen2Pkm && Gen1MovesLearned.Any() && moves[m] > Legal.MaxMoveID_1)
|
||||
{
|
||||
res[m] = new CheckResult(Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true };
|
||||
res[m] = new CheckMoveResult(MoveSource.SpecialEgg, gen, Severity.Invalid, V334, CheckIdentifier.Move) { Flag = true };
|
||||
MixedGen1NonTradebackGen2 = true;
|
||||
}
|
||||
else
|
||||
res[m] = new CheckResult(Severity.Valid, V333, CheckIdentifier.Move) { Flag = true };
|
||||
res[m] = new CheckMoveResult(MoveSource.SpecialEgg, gen, Severity.Valid, V333, CheckIdentifier.Move) { Flag = true };
|
||||
}
|
||||
if (pkm.TradebackStatus == TradebackType.Any && pkm.GenNumber == 1)
|
||||
pkm.TradebackStatus = TradebackType.WasTradeback;
|
||||
@@ -350,11 +364,11 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
foreach (int m in IncompatibleEggMoves)
|
||||
{
|
||||
if (EventEggMovesLearned.Contains(m) && !EggMovesLearned.Contains(m))
|
||||
res[m] = new CheckResult(Severity.Invalid, V337, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V337, CheckIdentifier.Move);
|
||||
else if (!EventEggMovesLearned.Contains(m) && EggMovesLearned.Contains(m))
|
||||
res[m] = new CheckResult(Severity.Invalid, V336, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V336, CheckIdentifier.Move);
|
||||
else if (!EventEggMovesLearned.Contains(m) && LvlupEggMovesLearned.Contains(m))
|
||||
res[m] = new CheckResult(Severity.Invalid, V358, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V358, CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,9 +378,9 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
foreach (int m in RegularEggMovesLearned)
|
||||
{
|
||||
if (EggMovesLearned.Contains(m))
|
||||
res[m] = new CheckResult(Severity.Invalid, pkm.WasGiftEgg ? V377 : V341, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, pkm.WasGiftEgg ? V377 : V341, CheckIdentifier.Move);
|
||||
else if (LvlupEggMovesLearned.Contains(m))
|
||||
res[m] = new CheckResult(Severity.Invalid, pkm.WasGiftEgg ? V378 : V347, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, pkm.WasGiftEgg ? V378 : V347, CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -383,18 +397,23 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
if (invalidCount == 2) // can't know both at the same time
|
||||
for (int i = 0; i < 4; i++) // flag both moves
|
||||
if (moves[i] == 250 || moves[i] == 432)
|
||||
res[i] = new CheckResult(Severity.Invalid, V338, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(res[i], Severity.Invalid, V338, CheckIdentifier.Move);
|
||||
}
|
||||
|
||||
for (int i = 0; i < HMLearned.Length; i++)
|
||||
if (res[i]?.Valid ?? false)
|
||||
res[i] = new CheckResult(Severity.Invalid, string.Format(V339, gen, gen + 1), CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(res[i], Severity.Invalid, string.Format(V339, gen, gen + 1), CheckIdentifier.Move);
|
||||
}
|
||||
|
||||
// Mark the gen 1 exclusive moves as illegal because the pokemon also have Non tradeback egg moves.
|
||||
if (MixedGen1NonTradebackGen2)
|
||||
{
|
||||
foreach (int m in Gen1MovesLearned)
|
||||
res[m] = new CheckResult(Severity.Invalid, V335, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V335, CheckIdentifier.Move);
|
||||
|
||||
foreach (int m in Gen2PreevoMovesLearned)
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V412, CheckIdentifier.Move);
|
||||
}
|
||||
|
||||
if (gen == 1 && pkm.Format == 1 && pkm.Gen1_NotTradeback)
|
||||
{
|
||||
@@ -405,7 +424,7 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
ParseEvolutionsIncompatibleMoves(pkm, moves, info.EncounterMoves.validTMHMMoves[1], ref res);
|
||||
}
|
||||
|
||||
if (Legal.EvolutionWithMove.Contains(pkm.Species))
|
||||
if (Legal.SpeciesEvolutionWithMove.Contains(pkm.Species))
|
||||
{
|
||||
// Pokemon that evolved by leveling up while learning a specific move
|
||||
// This pokemon could only have 3 moves from preevolutions that are not the move used to evolved
|
||||
@@ -428,12 +447,12 @@ private static CheckResult[] parseMoves(PKM pkm, int[] moves, int[] special, int
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (res[m] == null)
|
||||
res[m] = new CheckResult(Severity.Invalid, V176, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.Unknown, pkm.GenNumber, Severity.Invalid, V176, CheckIdentifier.Move);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private static void ParseRedYellowIncompatibleMoves(PKM pkm, int[] moves, ref CheckResult[] res)
|
||||
private static void ParseRedYellowIncompatibleMoves(PKM pkm, int[] moves, ref CheckMoveResult[] res)
|
||||
{
|
||||
var incompatible = new List<int>();
|
||||
if (pkm.Species == 134 && pkm.CurrentLevel < 47 && moves.Contains(151))
|
||||
@@ -457,10 +476,10 @@ private static void ParseRedYellowIncompatibleMoves(PKM pkm, int[] moves, ref Ch
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (incompatible.Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Invalid, V363, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V363, CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
private static void ParseEvolutionsIncompatibleMoves(PKM pkm, int[] moves, List<int> tmhm, ref CheckResult[] res)
|
||||
private static void ParseEvolutionsIncompatibleMoves(PKM pkm, int[] moves, List<int> tmhm, ref CheckMoveResult[] res)
|
||||
{
|
||||
var species = specieslist;
|
||||
var currentspecies = species[pkm.Species];
|
||||
@@ -508,12 +527,12 @@ private static void ParseEvolutionsIncompatibleMoves(PKM pkm, int[] moves, List<
|
||||
for (int m = 0; m < 4; m++)
|
||||
{
|
||||
if (incompatible_current.Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Invalid, string.Format(V365, currentspecies, previousspecies), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, string.Format(V365, currentspecies, previousspecies), CheckIdentifier.Move);
|
||||
if (incompatible_previous.Contains(moves[m]))
|
||||
res[m] = new CheckResult(Severity.Invalid, string.Format(V366, currentspecies, previousspecies), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, string.Format(V366, currentspecies, previousspecies), CheckIdentifier.Move);
|
||||
}
|
||||
}
|
||||
private static void ParseShedinjaEvolveMoves(PKM pkm, int[] moves, ref CheckResult[] res)
|
||||
private static void ParseShedinjaEvolveMoves(PKM pkm, int[] moves, ref CheckMoveResult[] res)
|
||||
{
|
||||
List<int>[] ShedinjaEvoMoves = Legal.getShedinjaEvolveMoves(pkm);
|
||||
var ShedinjaEvoMovesLearned = new List<int>();
|
||||
@@ -528,7 +547,7 @@ private static void ParseShedinjaEvolveMoves(PKM pkm, int[] moves, ref CheckResu
|
||||
if (!ShedinjaEvoMoves[gen].Contains(moves[m]))
|
||||
continue;
|
||||
|
||||
res[m] = new CheckResult(Severity.Valid, native ? V355 : string.Format(V356, gen), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(MoveSource.ShedinjaEvo, gen, Severity.Valid, native ? V355 : string.Format(V356, gen), CheckIdentifier.Move);
|
||||
ShedinjaEvoMovesLearned.Add(m);
|
||||
}
|
||||
}
|
||||
@@ -537,9 +556,9 @@ private static void ParseShedinjaEvolveMoves(PKM pkm, int[] moves, ref CheckResu
|
||||
return;
|
||||
|
||||
foreach (int m in ShedinjaEvoMovesLearned)
|
||||
res[m] = new CheckResult(Severity.Invalid, V357, CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, V357, CheckIdentifier.Move);
|
||||
}
|
||||
private static void ParseEvolutionLevelupMove(PKM pkm, int[] moves, List<int> IncenseMovesLearned, ref CheckResult[] res, LegalInfo info)
|
||||
private static void ParseEvolutionLevelupMove(PKM pkm, int[] moves, List<int> IncenseMovesLearned, ref CheckMoveResult[] res, LegalInfo info)
|
||||
{
|
||||
// Ignore if there is an invalid move or an empty move, this validation is only for 4 non-empty moves that are all valid, but invalid as a 4 combination
|
||||
// Ignore Mr. Mime and Sudowodoo from generations 1 to 3, they cant be evolved from Bonsly or Munchlax
|
||||
@@ -549,11 +568,6 @@ private static void ParseEvolutionLevelupMove(PKM pkm, int[] moves, List<int> In
|
||||
info.EncounterMatch.Species == pkm.Species)
|
||||
return;
|
||||
|
||||
// Mr.Mime and Sodowodoo from eggs that does not have any exclusive egg move or level up move from Mime Jr or Bonsly.
|
||||
// The egg can be assumed to be a non-incense egg if the pokemon was not evolved by the player
|
||||
if (info.EncounterMatch.EggEncounter && Legal.BabyEvolutionWithMove.Contains(pkm.Species) && !IncenseMovesLearned.Any())
|
||||
return;
|
||||
|
||||
var ValidMoves = Legal.getValidPostEvolutionMoves(pkm, pkm.Species, info.EvoChainsAllGens, GameVersion.Any);
|
||||
// Add the evolution moves to valid moves in case some of this moves could not be learned after evolving
|
||||
switch (pkm.Species)
|
||||
@@ -586,14 +600,14 @@ private static void ParseEvolutionLevelupMove(PKM pkm, int[] moves, List<int> In
|
||||
return;
|
||||
|
||||
for (int m = 0; m < 4; m++)
|
||||
res[m] = new CheckResult(Severity.Invalid, string.Format(V385, specieslist[pkm.Species]), CheckIdentifier.Move);
|
||||
res[m] = new CheckMoveResult(res[m], Severity.Invalid, string.Format(V385, specieslist[pkm.Species]), CheckIdentifier.Move);
|
||||
}
|
||||
|
||||
/* Similar to verifyRelearnEgg but in pre relearn generation is the moves what should match the expected order but only if the pokemon is inside an egg */
|
||||
private static CheckResult[] verifyPreRelearnEggBase(PKM pkm, int[] Moves, List<int> baseMoves, List<int> eggmoves, List<int> lvlmoves, List<int> tmhmmoves, List<int> tutormoves, List<int> specialmoves, bool AllowInherited, GameVersion ver)
|
||||
private static CheckMoveResult[] verifyPreRelearnEggBase(PKM pkm, int[] Moves, List<int> baseMoves, List<int> eggmoves, List<int> lvlmoves, List<int> tmhmmoves, List<int> tutormoves, List<int> specialmoves, bool AllowInherited, GameVersion ver)
|
||||
{
|
||||
CheckResult[] res = new CheckResult[4];
|
||||
|
||||
CheckMoveResult[] res = new CheckMoveResult[4];
|
||||
var gen = pkm.GenNumber;
|
||||
// Obtain level1 moves
|
||||
int baseCt = baseMoves.Count;
|
||||
if (baseCt > 4) baseCt = 4;
|
||||
@@ -614,12 +628,12 @@ private static CheckResult[] verifyPreRelearnEggBase(PKM pkm, int[] Moves, List<
|
||||
for (int i = moveoffset; i < reqBase; i++)
|
||||
{
|
||||
if (baseMoves.Contains(Moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V179, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.Initial, gen, Severity.Valid, V179, CheckIdentifier.Move);
|
||||
else
|
||||
{
|
||||
// mark remaining base egg moves missing
|
||||
for (int z = i; z < reqBase; z++)
|
||||
res[z] = new CheckResult(Severity.Invalid, V180, CheckIdentifier.Move);
|
||||
res[z] = new CheckMoveResult(MoveSource.Initial, gen, Severity.Invalid, V180, CheckIdentifier.Move);
|
||||
|
||||
// provide the list of suggested base moves for the last required slot
|
||||
em = string.Join(", ", baseMoves.Select(m => m >= movelist.Length ? V190 : movelist[m]));
|
||||
@@ -633,12 +647,12 @@ private static CheckResult[] verifyPreRelearnEggBase(PKM pkm, int[] Moves, List<
|
||||
for (int i = moveoffset; i < moveoffset + specialmoves.Count; i++)
|
||||
{
|
||||
if (specialmoves.Contains(Moves[i]))
|
||||
res[i] = new CheckResult(Severity.Valid, V333, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.SpecialEgg, gen, Severity.Valid, V333, CheckIdentifier.Move);
|
||||
else
|
||||
{
|
||||
// mark remaining special egg moves missing
|
||||
for (int z = i; z < moveoffset + specialmoves.Count; z++)
|
||||
res[z] = new CheckResult(Severity.Invalid, V342, CheckIdentifier.Move);
|
||||
res[z] = new CheckMoveResult(MoveSource.SpecialEgg, gen, Severity.Invalid, V342, CheckIdentifier.Move);
|
||||
|
||||
// provide the list of suggested base moves and species moves for the last required slot
|
||||
if (!string.IsNullOrEmpty(em)) em += ", ";
|
||||
@@ -660,23 +674,23 @@ private static CheckResult[] verifyPreRelearnEggBase(PKM pkm, int[] Moves, List<
|
||||
for (int i = reqBase + specialmoves.Count; i < 4; i++)
|
||||
{
|
||||
if (Moves[i] == 0) // empty
|
||||
res[i] = new CheckResult(Severity.Valid, V167, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.None, gen, Severity.Valid, V167, CheckIdentifier.Move);
|
||||
else if (eggmoves.Contains(Moves[i])) // inherited egg move
|
||||
res[i] = new CheckResult(AllowInheritedSeverity, AllowInherited ? V344 : V341, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.EggMove, gen, AllowInheritedSeverity, AllowInherited ? V344 : V341, CheckIdentifier.Move);
|
||||
else if (lvlmoves.Contains(Moves[i])) // inherited lvl moves
|
||||
res[i] = new CheckResult(AllowInheritedSeverity, AllowInherited ? V345 : V347, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.InheritLevelUp, gen, AllowInheritedSeverity, AllowInherited ? V345 : V347, CheckIdentifier.Move);
|
||||
else if (tmhmmoves.Contains(Moves[i])) // inherited TMHM moves
|
||||
res[i] = new CheckResult(AllowInheritedSeverity, AllowInherited ? V349 : V350, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.TMHM, gen, AllowInheritedSeverity, AllowInherited ? V349 : V350, CheckIdentifier.Move);
|
||||
else if (tutormoves.Contains(Moves[i])) // inherited tutor moves
|
||||
res[i] = new CheckResult(AllowInheritedSeverity, AllowInherited ? V346 : V348, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.Tutor, gen, AllowInheritedSeverity, AllowInherited ? V346 : V348, CheckIdentifier.Move);
|
||||
else // not inheritable, flag
|
||||
res[i] = new CheckResult(Severity.Invalid, V340, CheckIdentifier.Move);
|
||||
res[i] = new CheckMoveResult(MoveSource.Unknown, gen, Severity.Invalid, V340, CheckIdentifier.Move);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
private static void verifyNoEmptyDuplicates(int[] Moves, CheckResult[] res)
|
||||
private static void verifyNoEmptyDuplicates(int[] Moves, CheckMoveResult[] res)
|
||||
{
|
||||
bool emptySlot = false;
|
||||
for (int i = 0; i < 4; i++)
|
||||
@@ -684,9 +698,9 @@ private static void verifyNoEmptyDuplicates(int[] Moves, CheckResult[] res)
|
||||
if (Moves[i] == 0)
|
||||
emptySlot = true;
|
||||
else if (emptySlot)
|
||||
res[i] = new CheckResult(Severity.Invalid, V167, res[i].Identifier);
|
||||
res[i] = new CheckMoveResult(res[i], 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);
|
||||
res[i] = new CheckMoveResult(res[i], Severity.Invalid, V168, res[i].Identifier);
|
||||
}
|
||||
}
|
||||
private static void UptateGen1LevelUpMoves(PKM pkm, ValidEncounterMoves EncounterMoves, int defaultLvlG1, int generation, LegalInfo info)
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
using static PKHeX.Core.LegalityCheckStrings;
|
||||
|
||||
using System.Linq;
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public static class VerifyEvolution
|
||||
{
|
||||
// Evolutions
|
||||
public static CheckResult verifyEvolution(PKM pkm, IEncounterable EncounterMatch)
|
||||
public static CheckResult verifyEvolution(PKM pkm, LegalInfo info)
|
||||
{
|
||||
return isValidEvolution(pkm, EncounterMatch)
|
||||
return isValidEvolution(pkm, info)
|
||||
? new CheckResult(CheckIdentifier.Evolution)
|
||||
: new CheckResult(Severity.Invalid, V86, CheckIdentifier.Evolution);
|
||||
}
|
||||
private static bool isValidEvolution(PKM pkm, IEncounterable EncounterMatch)
|
||||
private static bool isValidEvolution(PKM pkm, LegalInfo info)
|
||||
{
|
||||
int species = pkm.Species;
|
||||
if (EncounterMatch.Species == species)
|
||||
if (info.EncounterMatch.Species == species)
|
||||
return true;
|
||||
if (EncounterMatch.EggEncounter && species == 350)
|
||||
if (info.EncounterMatch.EggEncounter && species == 350)
|
||||
return true;
|
||||
return Legal.getEvolutionValid(pkm, EncounterMatch.Species);
|
||||
if(!Legal.getEvolutionValid(pkm, info.EncounterMatch.Species))
|
||||
return false;
|
||||
// If current species evolved with a move evolution and encounter species is not current species check if the evolution by move is valid
|
||||
// Only the evolution by move is checked, if there is another evolution before the evolution by move is covered in getEvolutionValid
|
||||
if (Legal.SpeciesEvolutionWithMove.Contains(pkm.Species))
|
||||
return Legal.getEvolutionWithMoveValid(pkm, info);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,7 @@ private static CheckResult[] verifyRelearnDexNav(PKM pkm, LegalInfo info)
|
||||
int[] RelearnMoves = pkm.RelearnMoves;
|
||||
|
||||
// DexNav Pokémon can have 1 random egg move as a relearn move.
|
||||
res[0] = !Legal.getValidRelearn(pkm, Legal.getBaseEggSpecies(pkm)).Contains(RelearnMoves[0])
|
||||
res[0] = !Legal.getValidRelearn(pkm, Legal.getBaseEggSpecies(pkm),true).Contains(RelearnMoves[0])
|
||||
? new CheckResult(Severity.Invalid, V183, CheckIdentifier.RelearnMove)
|
||||
: new CheckResult(CheckIdentifier.RelearnMove);
|
||||
|
||||
@@ -85,6 +85,9 @@ private static CheckResult[] verifyRelearnEggBase(PKM pkm, LegalInfo info, Encou
|
||||
int[] RelearnMoves = pkm.RelearnMoves;
|
||||
info.RelearnBase = new int[4];
|
||||
CheckResult[] res = new CheckResult[4];
|
||||
// Level up moves could not be inherited if Ditto is parent,
|
||||
// that means genderless species and male only species except Nidoran and Volbet (they breed with female nidoran and illumise) could not have level up moves as an egg
|
||||
var inheritLvlMoves = pkm.PersonalInfo.Gender > 0 && pkm.PersonalInfo.Gender < 255 || Legal.MixedGenderBreeding.Contains(e.Species);
|
||||
|
||||
// Obtain level1 moves
|
||||
List<int> baseMoves = new List<int>(Legal.getBaseEggMoves(pkm, e.Species, e.Game, 1));
|
||||
@@ -92,7 +95,7 @@ private static CheckResult[] verifyRelearnEggBase(PKM pkm, LegalInfo info, Encou
|
||||
if (baseCt > 4) baseCt = 4;
|
||||
|
||||
// Obtain Inherited moves
|
||||
var inheritMoves = Legal.getValidRelearn(pkm, e.Species).ToList();
|
||||
var inheritMoves = Legal.getValidRelearn(pkm, e.Species, inheritLvlMoves).ToList();
|
||||
var inherited = RelearnMoves.Where(m => m != 0 && (!baseMoves.Contains(m) || inheritMoves.Contains(m))).ToList();
|
||||
int inheritCt = inherited.Count;
|
||||
|
||||
@@ -129,7 +132,7 @@ private static CheckResult[] verifyRelearnEggBase(PKM pkm, LegalInfo info, Encou
|
||||
|
||||
// If any splitbreed moves are invalid, flag accordingly
|
||||
var splitInvalid = false;
|
||||
var splitMoves = e.SplitBreed ? Legal.getValidRelearn(pkm, Legal.getBaseEggSpecies(pkm)).ToList() : new List<int>();
|
||||
var splitMoves = e.SplitBreed ? Legal.getValidRelearn(pkm, Legal.getBaseEggSpecies(pkm), inheritLvlMoves).ToList() : new List<int>();
|
||||
|
||||
// Inherited moves appear after the required base moves.
|
||||
for (int i = reqBase; i < 4; i++)
|
||||
|
||||
@@ -347,7 +347,7 @@ public static class LegalityCheckStrings
|
||||
public static string V328 {get; set;} = "Version Specific evolution requires a trade to opposite version. A Handling Trainer is required.";
|
||||
|
||||
public static string V334 {get; set;} = "Non-tradeback egg move. Incompatible with generation 1 exclusive moves.";
|
||||
public static string V335 {get; set;} = "Generation 1 exclusive move. Incompatible with Non-tradeback egg moves.";
|
||||
public static string V335 {get; set;} = "Generation 1 exclusive move. Incompatible with Non-tradeback moves.";
|
||||
public static string V336 {get; set;} = "Egg Move. Incompatible with event egg moves.";
|
||||
public static string V337 {get; set;} = "Event Egg Move. Incompatible with normal egg moves.";
|
||||
public static string V338 {get; set;} = "Defog and whirpool. One of the two moves should have been removed before transfered to generation 5.";
|
||||
@@ -405,6 +405,7 @@ public static class LegalityCheckStrings
|
||||
public static string V409 {get; set;} = "Mystery Gift shiny mismatch.";
|
||||
public static string V410 {get; set;} = "Mystery Gift fixed PID mismatch.";
|
||||
public static string V411 {get; set;} = "Encounter Type PID mismatch.";
|
||||
public static string V412 {get; set;} = "Non-tradeback pre evolution move. Incompatible with generation 1 exclusive moves.";
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
44
PKHeX.Core/Legality/Structures/CheckMoveResult.cs
Normal file
44
PKHeX.Core/Legality/Structures/CheckMoveResult.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
namespace PKHeX.Core
|
||||
{
|
||||
public enum MoveSource
|
||||
{
|
||||
Unknown,
|
||||
None,
|
||||
Relearn,
|
||||
Initial,
|
||||
LevelUp,
|
||||
TMHM,
|
||||
Tutor,
|
||||
EggMove,
|
||||
InheritLevelUp,
|
||||
Special,
|
||||
SpecialEgg,
|
||||
ShedinjaEvo,
|
||||
Sketch,
|
||||
}
|
||||
|
||||
public class CheckMoveResult : CheckResult
|
||||
{
|
||||
public readonly MoveSource Source;
|
||||
public readonly int Generation;
|
||||
|
||||
internal CheckMoveResult(MoveSource m, int g, CheckIdentifier i)
|
||||
: base(i)
|
||||
{
|
||||
Source = m;
|
||||
Generation = g;
|
||||
}
|
||||
internal CheckMoveResult(MoveSource m, int g, Severity s, string c, CheckIdentifier i)
|
||||
: base(s, c, i)
|
||||
{
|
||||
Source = m;
|
||||
Generation = g;
|
||||
}
|
||||
internal CheckMoveResult(CheckMoveResult Org, Severity s, string c, CheckIdentifier i)
|
||||
: base(s, c, i)
|
||||
{
|
||||
Source = Org?.Source ?? MoveSource.Unknown;
|
||||
Generation = Org?.Generation ?? 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -224,8 +224,9 @@ public static partial class Legal
|
||||
122, // Mr. Mime (Mime Jr with Mimic)
|
||||
185, // Sudowoodo (Bonsly with Mimic)
|
||||
};
|
||||
|
||||
internal static readonly int[] EvolutionWithMove =
|
||||
|
||||
// List of species that evolve from a previous species having a move while leveling up
|
||||
internal static readonly int[] SpeciesEvolutionWithMove =
|
||||
{
|
||||
122, // Mr. Mime (Mime Jr with Mimic)
|
||||
185, // Sudowoodo (Bonsly with Mimic)
|
||||
@@ -237,6 +238,64 @@ public static partial class Legal
|
||||
700, // Sylveon (Eevee with Fairy Move)
|
||||
763, // Tsareena (Steenee with Stomp)
|
||||
};
|
||||
// Moves that trigger the evolution by move
|
||||
internal static readonly int[][] MoveEvolutionWithMove =
|
||||
{
|
||||
new [] { 102 }, // Mr. Mime (Mime Jr with Mimic)
|
||||
new [] { 102 }, // Sudowoodo (Bonsly with Mimic)
|
||||
new [] { 458 }, // Ambipom (Aipom with Double Hit)
|
||||
new [] { 205 }, // Lickilicky (Lickitung with Rollout)
|
||||
new [] { 246 }, // Tangrowth (Tangela with Ancient Power)
|
||||
new [] { 246 }, // Yanmega (Yamma with Ancient Power)
|
||||
new [] { 246 }, // Mamoswine (Piloswine with Ancient Power)
|
||||
FairyMoves, // Sylveon (Eevee with Fairy Move)
|
||||
new [] { 023 }, // Tsareena (Steenee with Stomp)
|
||||
};
|
||||
// Min level for any species for every generation to learn the move for evolution by move
|
||||
// 0 means it cant be learned in that generation
|
||||
internal static readonly int[][] MinLevelEvolutionWithMove =
|
||||
{
|
||||
// Mr. Mime (Mime Jr with Mimic)
|
||||
new [] { 0, 0, 0, 0, 18, 15, 15, 15 },
|
||||
// Sudowoodo (Bonsly with Mimic)
|
||||
new [] { 0, 0, 0, 0, 17, 17, 15, 15 },
|
||||
// Ambipom (Aipom with Double Hit)
|
||||
new [] { 0, 0, 0, 0, 32, 32, 32, 32 },
|
||||
// Lickilicky (Lickitung with Rollout)
|
||||
new [] { 0, 0, 1, 0, 1, 33, 33, 33 },
|
||||
// Tangrowth (Tangela with Ancient Power)
|
||||
new [] { 0, 0, 0, 0, 1, 36, 38, 38 },
|
||||
// Yanmega (Yanma with Ancient Power)
|
||||
new [] { 0, 0, 0, 0, 1, 33, 33, 33 },
|
||||
// Mamoswine (Piloswine with Ancient Power)
|
||||
new [] { 0, 0, 0, 0, 1, 1, 1, 1 },
|
||||
// Sylveon (Eevee with Fairy Move)
|
||||
new [] { 0, 0, 0, 0, 0, 29, 9, 9 },
|
||||
// Tsareena (Steenee with Stomp)
|
||||
new [] { 0, 0, 0, 0, 0, 0, 0, 29 },
|
||||
};
|
||||
// True -> the pokemon could hatch from an egg with the move for evolution as an egg move
|
||||
internal static readonly bool[][] EggMoveEvolutionWithMove =
|
||||
{
|
||||
// Mr. Mime (Mime Jr with Mimic)
|
||||
new [] { false, false, false, false, true, true, true, true },
|
||||
// Sudowoodo (Bonsly with Mimic)
|
||||
new [] { false, false, false, false, true, true, true, true },
|
||||
// Ambipom (Aipom with Double Hit)
|
||||
new [] { false, false, false, false, true, true, true, true },
|
||||
// Lickilicky (Lickitung with Rollout)
|
||||
new [] { false, false, true, false, true, true, true, true },
|
||||
// Tangrowth (Tangela with Ancient Power)
|
||||
new [] { false, false, false, false, true, true, true, true },
|
||||
// Yanmega (Yanma with Ancient Power)
|
||||
new [] { false, false, false, false, true, true, true, true },
|
||||
// Mamoswine (Piloswine with Ancient Power)
|
||||
new [] { false, false, true, true, true, true, true, true },
|
||||
// Sylveon (Eevee with Fairy Move)
|
||||
new [] { false, false, true, true, true, true, true, true },
|
||||
// Tsareena (Steenee with Stomp)
|
||||
new [] { false, false, false, false, false, false, false, false },
|
||||
};
|
||||
|
||||
internal static readonly int[] FairyMoves =
|
||||
{
|
||||
@@ -264,7 +323,13 @@ public static partial class Legal
|
||||
705, //Fleur Cannon
|
||||
717, //Nature's Madness
|
||||
};
|
||||
|
||||
internal static readonly int[] MixedGenderBreeding =
|
||||
{
|
||||
29, // Nidoran♀
|
||||
32, // Nidoran♂
|
||||
314, // Volbeat
|
||||
314, // Illumise
|
||||
};
|
||||
#region Games
|
||||
|
||||
public static readonly int[] Games_7vc2 = { 39, 40, 41 }; // Gold, Silver, Crystal
|
||||
|
||||
@@ -284,7 +284,7 @@ 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.
|
||||
V334 = Non-tradeback egg move. Incompatible with generation 1 exclusive moves.
|
||||
V335 = Generation 1 exclusive move. Incompatible with Non-tradeback egg moves.
|
||||
V335 = Generation 1 exclusive move. Incompatible with Non-tradeback moves.
|
||||
V336 = Egg Move. Incompatible with event egg moves.
|
||||
V337 = Event Egg Move. Incompatible with normal egg moves.
|
||||
V338 = Defog and whirpool. One of the two moves should have been removed before transfered to generation 5.
|
||||
@@ -339,4 +339,7 @@ V405 = Outsider {0} should have evolved into {1}.
|
||||
V406 = Non Japanese Shadow E-reader Pokémon. Unreleased encounter.
|
||||
V407 = OT from Colosseum/XD cannot be female.
|
||||
V408 = Female OT from Generation 1/2 is invalid.
|
||||
V409 = Mystery Gift shiny mismatch.
|
||||
V409 = Mystery Gift shiny mismatch.
|
||||
V410 = Mystery Gift fixed PID mismatch.
|
||||
V411 = Encounter Type PID mismatch.
|
||||
V412 = Non-tradeback pre evolution move. Incompatible with generation 1 exclusive moves.
|
||||
@@ -340,4 +340,7 @@ V405 = Outsider {0} should have evolved into {1}.
|
||||
V406 = Non Japanese Shadow E-reader Pokémon. Unreleased encounter.
|
||||
V407 = OT from Colosseum/XD cannot be female.
|
||||
V408 = Female OT from Generation 1/2 is invalid.
|
||||
V409 = Mystery Gift shiny mismatch.
|
||||
V409 = Mystery Gift shiny mismatch.
|
||||
V410 = Mystery Gift fixed PID mismatch.
|
||||
V411 = Encounter Type PID mismatch.
|
||||
V412 = Non-tradeback pre evolution move. Incompatible with generation 1 exclusive moves.
|
||||
@@ -339,4 +339,7 @@ V405 = 外来的{0}应当进化为{1}.
|
||||
V406 = 非日版黑暗E-reader宝可梦。未解禁遇见方式。
|
||||
V407 = OT from Colosseum/XD cannot be female.
|
||||
V408 = Female OT from Generation 1/2 is invalid.
|
||||
V409 = Mystery Gift shiny mismatch.
|
||||
V409 = Mystery Gift shiny mismatch.
|
||||
V410 = Mystery Gift fixed PID mismatch.
|
||||
V411 = Encounter Type PID mismatch.
|
||||
V412 = Non-tradeback pre evolution move. Incompatible with generation 1 exclusive moves.
|
||||
Reference in New Issue
Block a user