2017-05-28 04:17:53 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using static PKHeX . Core . LegalityCheckStrings ;
using static PKHeX . Core . LegalityAnalysis ;
namespace PKHeX.Core
{
public static class VerifyCurrentMoves
{
public static CheckResult [ ] verifyMoves ( PKM pkm , LegalInfo info , GameVersion game = GameVersion . Any )
{
int [ ] Moves = pkm . Moves ;
var res = parseMovesForEncounters ( pkm , info , game , Moves ) ;
// 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 static CheckResult [ ] 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
// Iterate over encounters
bool pre3DS = pkm . GenNumber < 6 ;
// gather valid moves for encounter species
info . EncounterMoves = getEncounterValidMoves ( pkm , info ) ;
if ( pkm . GenNumber < = 3 )
pkm . WasEgg = info . EncounterMatch . EggEncounter ;
var EncounterMatchGen = info . EncounterMatch as IGeneration ;
var defaultG1LevelMoves = info . EncounterMoves . validLevelUpMoves [ 1 ] ;
var defaultTradeback = pkm . TradebackStatus ;
if ( EncounterMatchGen ! = null )
// Generation 1 can have different minimum level in different encounter of the same species; update valid level moves
UptateGen1LevelUpMoves ( pkm , info . EncounterMoves , info . EncounterMoves . minLvlG1 , EncounterMatchGen . Generation , info ) ;
var res = pre3DS
? parseMovesPre3DS ( pkm , Moves , info )
: parseMoves3DS ( pkm , game , Moves , info ) ;
if ( res . All ( x = > x . Valid ) )
return res ;
if ( EncounterMatchGen ? . Generation = = 1 ) // not valid, restore generation 1 moves
info . EncounterMoves . validLevelUpMoves [ 1 ] = defaultG1LevelMoves ;
pkm . TradebackStatus = defaultTradeback ;
return res ;
}
private static CheckResult [ ] parseMovesForSmeargle ( PKM pkm , int [ ] Moves , LegalInfo info )
{
if ( ! pkm . IsEgg )
return parseMovesSketch ( Moves ) ;
// can only know sketch as egg
var empty = ValidEncounterMoves . Empty ;
info . EncounterMoves = new ValidEncounterMoves
{
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 ) ;
}
private static CheckResult [ ] parseMovesIsEggPreRelearn ( PKM pkm , int [ ] Moves , int [ ] SpecialMoves , bool allowinherited , EncounterEgg e )
{
CheckResult [ ] res = new CheckResult [ 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 > ( ) ;
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
var InheritedTMHMMoves = Legal . getTMHM ( pkm , pkm . Species , pkm . AltForm , pkm . GenNumber , e . Game , false ) ? . ToList ( ) ;
InheritedLvlMoves . RemoveAll ( x = > baseEggMoves . Contains ( x ) ) ;
if ( pkm . Format > 2 | | SpecialMoves . Any ( ) )
{
// For gen 2 is not possible to difference normal eggs from event eggs
// If there is no special moves assume normal egg
res = verifyPreRelearnEggBase ( pkm , Moves , baseEggMoves , EggMoves , InheritedLvlMoves , InheritedTMHMMoves , InheritedTutorMoves , ValidSpecialMoves , allowinherited , e . Game ) ;
}
else if ( pkm . Format = = 2 )
{
res = verifyPreRelearnEggBase ( pkm , Moves , baseEggMoves , EggMoves , InheritedLvlMoves , InheritedTMHMMoves , InheritedTutorMoves , new List < int > ( ) , true , e . Game ) ;
}
return res ;
}
private static CheckResult [ ] 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 ;
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 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 ) ;
}
private static CheckResult [ ] parseMovesSketch ( int [ ] Moves )
{
CheckResult [ ] res = new CheckResult [ 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 ) ;
return res ;
}
private static CheckResult [ ] 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 )
return parseMovesSpecialMoveset ( pkm , Moves , info ) ;
// Everything else
return parseMovesRelearn ( pkm , Moves , info ) ;
}
private static CheckResult [ ] parseMovesPre3DS ( PKM pkm , int [ ] Moves , LegalInfo info )
{
if ( pkm . IsEgg )
{
int [ ] SpecialMoves = ( info . EncounterMatch as IMoveset ) ? . Moves ;
// Gift do not have special moves but also should not have normal egg moves
var allowinherited = SpecialMoves = = null & & ! pkm . WasGiftEgg & & pkm . Species ! = 489 & & pkm . Species ! = 490 ;
return parseMovesIsEggPreRelearn ( pkm , Moves , SpecialMoves ? ? new int [ 0 ] , allowinherited , info . EncounterMatch as EncounterEgg ) ;
}
if ( pkm . GenNumber < = 2 & & ( info . EncounterMatch as IGeneration ) ? . Generation = = 1 )
return parseMovesGen1 ( pkm , Moves , info ) ;
if ( info . EncounterMatch is EncounterEgg e )
return parseMovesWasEggPreRelearn ( pkm , Moves , info , e ) ;
return parseMovesSpecialMoveset ( pkm , Moves , info ) ;
}
private static CheckResult [ ] parseMovesGen1 ( PKM pkm , int [ ] Moves , LegalInfo info )
{
GameVersion [ ] games = Legal . getGen1GameEncounter ( pkm ) ;
CheckResult [ ] res = new CheckResult [ 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 ) ;
if ( res . All ( r = > r . Valid ) )
return res ;
InitialMoves = VerInitialMoves ;
}
return res ;
}
private static CheckResult [ ] 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 ) ;
if ( res . Any ( r = > ! r . Valid ) )
return res ;
return res ;
}
private static CheckResult [ ] 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 ) ;
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 ) ;
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 ) ;
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 )
{
CheckResult [ ] res = new CheckResult [ 4 ] ;
var Gen1MovesLearned = new List < int > ( ) ;
var EggMovesLearned = new List < int > ( ) ;
var LvlupEggMovesLearned = new List < int > ( ) ;
var EventEggMovesLearned = new List < int > ( ) ;
var IsGen2Pkm = pkm . Format = = 2 | | pkm . VC2 ;
var required = Legal . getRequiredMoveCount ( pkm , moves , info , initialmoves ) ;
var IncenseMovesLearned = new List < int > ( ) ;
// Check none moves and relearn moves before generation moves
for ( int m = 0 ; m < 4 ; m + + )
{
if ( moves [ m ] = = 0 )
res [ m ] = new CheckResult ( 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 } ;
}
if ( res . All ( r = > r ! = null ) )
return res ;
bool MixedGen1NonTradebackGen2 = false ;
// Check moves going backwards, marking the move valid in the most current generation when it can be learned
int [ ] generations = getGenMovesCheckOrder ( pkm ) ;
foreach ( var gen in generations )
{
if ( ! pkm . InhabitedGeneration ( gen ) )
continue ;
var HMLearned = new int [ 0 ] ;
// Check if pokemon knows HM moves from generation 3 and 4 but are not valid yet, that means it cant learn the HMs in future generations
bool KnowDefogWhirlpool = false ;
if ( gen = = 4 & & pkm . Format > 4 )
{
// Copy to array the hm found or else the list will be emptied when the legal status of moves changes in the current generation
HMLearned = moves . Where ( ( m , i ) = > ! ( res [ i ] ? . Valid ? ? false ) & & Legal . HM_4_RemovePokeTransfer . Any ( l = > l = = m ) ) . Select ( ( m , i ) = > i ) . ToArray ( ) ;
// Defog and Whirlpool at the same time, also both can't be learned in future generations or else they will be valid
KnowDefogWhirlpool = moves . Where ( ( m , i ) = > ( m = = 250 | | m = = 432 ) & & ! ( res [ i ] ? . Valid ? ? false ) ) . Count ( ) = = 2 ;
}
else if ( gen = = 3 & & pkm . Format > 3 )
HMLearned = moves . Select ( ( m , i ) = > i ) . Where ( i = > ! ( res [ i ] ? . Valid ? ? false ) & & Legal . HM_3 . Any ( l = > l = = moves [ i ] ) ) . ToArray ( ) ;
bool native = gen = = pkm . Format ;
for ( int m = 0 ; m < 4 ; m + + )
{
if ( res [ m ] ? . Valid ? ? false )
continue ;
if ( moves [ m ] = = 0 )
continue ;
if ( gen = = 1 & & initialmoves . Contains ( moves [ m ] ) )
res [ m ] = new CheckResult ( 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 ) ;
else if ( info . EncounterMoves . validTMHMMoves [ gen ] . Contains ( moves [ m ] ) )
res [ m ] = new CheckResult ( 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 ) ;
else if ( gen = = pkm . GenNumber & & special . Contains ( moves [ m ] ) )
res [ m ] = new CheckResult ( Severity . Valid , V175 , CheckIdentifier . Move ) ;
if ( res [ m ] = = null | | gen < 3 )
continue ;
if ( res [ m ] . Valid & & gen = = 1 )
Gen1MovesLearned . Add ( m ) ;
if ( res [ m ] . Valid & & gen < = 2 & & pkm . TradebackStatus = = TradebackType . Any & & pkm . GenNumber ! = gen )
pkm . TradebackStatus = TradebackType . WasTradeback ;
}
if ( gen = = generations . Last ( ) )
{
// Check higher-level moves after all the moves but just before egg moves to differentiate it from normal level up moves
// Also check if the base egg moves is a non tradeback move
for ( int m = 0 ; m < 4 ; m + + )
{
if ( res [ m ] ? . Valid ? ? false ) // Skip valid move
continue ;
if ( moves [ m ] = = 0 )
continue ;
if ( ! lvlupegg . Contains ( moves [ m ] ) ) // Check if contains level-up egg moves from parents
continue ;
if ( IsGen2Pkm & & Gen1MovesLearned . Any ( ) & & moves [ m ] > Legal . MaxMoveID_1 )
{
res [ m ] = new CheckResult ( Severity . Invalid , V334 , CheckIdentifier . Move ) ;
MixedGen1NonTradebackGen2 = true ;
}
else
res [ m ] = new CheckResult ( Severity . Valid , V345 , CheckIdentifier . Move ) ;
LvlupEggMovesLearned . Add ( m ) ;
if ( pkm . TradebackStatus = = TradebackType . Any & & pkm . GenNumber = = 1 )
pkm . TradebackStatus = TradebackType . WasTradeback ;
}
// Check egg moves after all the generations and all the moves, every move that can't be learned in another source should have preference
// the moves that can only be learned from egg moves should in the future check if the move combinations can be breed in gens 2 to 5
for ( int m = 0 ; m < 4 ; m + + )
{
if ( res [ m ] ? . Valid ? ? false )
continue ;
if ( moves [ m ] = = 0 )
continue ;
if ( egg . Contains ( moves [ m ] ) )
{
if ( IsGen2Pkm & & Gen1MovesLearned . Any ( ) & & moves [ m ] > Legal . MaxMoveID_1 )
{
// 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 } ;
MixedGen1NonTradebackGen2 = true ;
}
else
res [ m ] = new CheckResult ( Severity . Valid , V171 , CheckIdentifier . Move ) { Flag = true } ;
EggMovesLearned . Add ( m ) ;
if ( pkm . TradebackStatus = = TradebackType . Any & & pkm . GenNumber = = 1 )
pkm . TradebackStatus = TradebackType . WasTradeback ;
}
if ( ! eventegg . Contains ( moves [ m ] ) )
continue ;
if ( ! egg . Contains ( moves [ m ] ) )
{
if ( IsGen2Pkm & & Gen1MovesLearned . Any ( ) & & moves [ m ] > Legal . MaxMoveID_1 )
{
res [ m ] = new CheckResult ( Severity . Invalid , V334 , CheckIdentifier . Move ) { Flag = true } ;
MixedGen1NonTradebackGen2 = true ;
}
else
res [ m ] = new CheckResult ( Severity . Valid , V333 , CheckIdentifier . Move ) { Flag = true } ;
}
if ( pkm . TradebackStatus = = TradebackType . Any & & pkm . GenNumber = = 1 )
pkm . TradebackStatus = TradebackType . WasTradeback ;
EventEggMovesLearned . Add ( m ) ;
}
// A pokemon could have normal egg moves and regular egg moves
// Only if all regular egg moves are event egg moves or all event egg moves are regular egg moves
var RegularEggMovesLearned = EggMovesLearned . Union ( LvlupEggMovesLearned ) . ToList ( ) ;
if ( RegularEggMovesLearned . Any ( ) & & EventEggMovesLearned . Any ( ) )
{
// Moves that are egg moves or event egg moves but not both
var IncompatibleEggMoves = RegularEggMovesLearned . Except ( EventEggMovesLearned ) . Union ( EventEggMovesLearned . Except ( RegularEggMovesLearned ) ) . ToList ( ) ;
if ( IncompatibleEggMoves . Any ( ) )
{
foreach ( int m in IncompatibleEggMoves )
{
if ( EventEggMovesLearned . Contains ( m ) & & ! EggMovesLearned . Contains ( m ) )
res [ m ] = new CheckResult ( Severity . Invalid , V337 , CheckIdentifier . Move ) ;
else if ( ! EventEggMovesLearned . Contains ( m ) & & EggMovesLearned . Contains ( m ) )
res [ m ] = new CheckResult ( Severity . Invalid , V336 , CheckIdentifier . Move ) ;
else if ( ! EventEggMovesLearned . Contains ( m ) & & LvlupEggMovesLearned . Contains ( m ) )
res [ m ] = new CheckResult ( Severity . Invalid , V358 , CheckIdentifier . Move ) ;
}
}
}
// If there is no incompatibility with event egg check that there is no inherited move in gift eggs and event eggs
else if ( RegularEggMovesLearned . Any ( ) & & ( pkm . WasGiftEgg | | pkm . WasEventEgg ) )
{
foreach ( int m in RegularEggMovesLearned )
{
if ( EggMovesLearned . Contains ( m ) )
res [ m ] = new CheckResult ( 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 ) ;
}
}
}
if ( 3 < = gen & & gen < = 4 & & pkm . Format > gen )
{
// After all the moves from the generations 3 and 4,
// including egg moves if is the origin generation because some hidden moves are also special egg moves in gen 3
// Check if the marked hidden moves that were invalid at the start are now marked as valid, that means
// the hidden move was learned in gen 3 or 4 but was not removed when transfer to 4 or 5
if ( KnowDefogWhirlpool )
{
int invalidCount = moves . Where ( ( m , i ) = > ( m = = 250 | | m = = 432 ) & & ( res [ i ] ? . Valid ? ? false ) ) . Count ( ) ;
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 ) ;
}
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 ) ;
}
// 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 ) ;
if ( gen = = 1 & & pkm . Format = = 1 & & pkm . Gen1_NotTradeback )
{
// Check moves learned at the same level in red/blue and yellow, illegal because there is no move reminder
// Only two incompatibilites and only there are no illegal combination if generation 2 or 7 are included in the analysis
ParseRedYellowIncompatibleMoves ( pkm , moves , ref res ) ;
ParseEvolutionsIncompatibleMoves ( pkm , moves , info . EncounterMoves . validTMHMMoves [ 1 ] , ref res ) ;
}
if ( Legal . EvolutionWithMove . 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
// including special and eggs moves before realearn generations
2017-05-29 22:21:39 +00:00
ParseEvolutionLevelupMove ( pkm , moves , IncenseMovesLearned , ref res , info ) ;
2017-05-28 04:17:53 +00:00
}
if ( res . All ( r = > r ! = null ) )
return res ;
}
if ( pkm . Species = = 292 & & info . EncounterMatch . Species ! = 292 )
{
// Ignore Shedinja if the Encounter was also a Shedinja, assume null Encounter as a Nincada egg
// Check Shedinja evolved moves from Ninjask after egg moves
// Those moves could also be inherited egg moves
ParseShedinjaEvolveMoves ( pkm , moves , ref res ) ;
}
for ( int m = 0 ; m < 4 ; m + + )
{
if ( res [ m ] = = null )
res [ m ] = new CheckResult ( Severity . Invalid , V176 , CheckIdentifier . Move ) ;
}
return res ;
}
private static void ParseRedYellowIncompatibleMoves ( PKM pkm , int [ ] moves , ref CheckResult [ ] res )
{
var incompatible = new List < int > ( ) ;
if ( pkm . Species = = 134 & & pkm . CurrentLevel < 47 & & moves . Contains ( 151 ) )
{
// Vaporeon in Yellow learn Mist and Haze at level 42, Mist only if level up in day-care
// Vaporeon in Red Blue learn Acid Armor at level 42 and level 47 in Yellow
if ( moves . Contains ( 54 ) )
incompatible . Add ( 54 ) ;
if ( moves . Contains ( 114 ) )
incompatible . Add ( 114 ) ;
if ( incompatible . Any ( ) )
incompatible . Add ( 151 ) ;
}
if ( pkm . Species = = 136 & & pkm . CurrentLevel < 47 & & moves . Contains ( 43 ) & & moves . Contains ( 123 ) )
{
// Flareon in Yellow learn Smog at level 42
// Flareon in Red Blue learn Leer at level 42 and level 47 in Yellow
incompatible . Add ( 43 ) ;
incompatible . Add ( 123 ) ;
}
for ( int m = 0 ; m < 4 ; m + + )
{
if ( incompatible . Contains ( moves [ m ] ) )
res [ m ] = new CheckResult ( Severity . Invalid , V363 , CheckIdentifier . Move ) ;
}
}
private static void ParseEvolutionsIncompatibleMoves ( PKM pkm , int [ ] moves , List < int > tmhm , ref CheckResult [ ] res )
{
var species = specieslist ;
var currentspecies = species [ pkm . Species ] ;
var previousspecies = string . Empty ;
var incompatible_previous = new List < int > ( ) ;
var incompatible_current = new List < int > ( ) ;
if ( pkm . Species = = 34 & & moves . Contains ( 31 ) & & moves . Contains ( 37 ) )
{
// Nidoking learns Thrash at level 23
// Nidorino learns Fury Attack at level 36, Nidoran♂ at level 30
// Other moves are either learned by Nidoran♂ up to level 23 or by TM
incompatible_current . Add ( 31 ) ;
incompatible_previous . Add ( 37 ) ;
previousspecies = species [ 33 ] ;
}
if ( pkm . Species = = 103 & & moves . Contains ( 23 ) & & moves . Any ( m = > Legal . G1Exeggcute_IncompatibleMoves . Contains ( moves [ m ] ) ) )
{
// Exeggutor learns stomp at level 28
// Exeggcute learns Stun Spore at 32, PoisonPowder at 37 and Sleep Powder at 48
incompatible_current . Add ( 23 ) ;
incompatible_previous . AddRange ( Legal . G1Exeggcute_IncompatibleMoves ) ;
previousspecies = species [ 103 ] ;
}
if ( 134 < = pkm . Species & & pkm . Species < = 136 )
{
previousspecies = species [ 133 ] ;
var ExclusiveMoves = Legal . getExclusiveMoves ( 133 , pkm . Species , 1 , tmhm , moves ) ;
var EeveeLevels = Legal . getMinLevelLearnMove ( 133 , 1 , ExclusiveMoves [ 0 ] ) ;
var EvoLevels = Legal . getMaxLevelLearnMove ( pkm . Species , 1 , ExclusiveMoves [ 1 ] ) ;
for ( int i = 0 ; i < ExclusiveMoves [ 0 ] . Count ; i + + )
{
// There is a evolution move with a lower level that current eevee move
if ( EvoLevels . Any ( ev = > ev < EeveeLevels [ i ] ) )
incompatible_previous . Add ( ExclusiveMoves [ 0 ] [ i ] ) ;
}
for ( int i = 0 ; i < ExclusiveMoves [ 1 ] . Count ; i + + )
{
// There is a eevee move with a greather level that current evolution move
if ( EeveeLevels . Any ( ev = > ev > EvoLevels [ i ] ) )
incompatible_current . Add ( ExclusiveMoves [ 1 ] [ i ] ) ;
}
}
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 ) ;
if ( incompatible_previous . Contains ( moves [ m ] ) )
res [ m ] = new CheckResult ( Severity . Invalid , string . Format ( V366 , currentspecies , previousspecies ) , CheckIdentifier . Move ) ;
}
}
private static void ParseShedinjaEvolveMoves ( PKM pkm , int [ ] moves , ref CheckResult [ ] res )
{
List < int > [ ] ShedinjaEvoMoves = Legal . getShedinjaEvolveMoves ( pkm ) ;
var ShedinjaEvoMovesLearned = new List < int > ( ) ;
for ( int gen = Math . Min ( pkm . Format , 4 ) ; gen > = 3 ; gen - - )
{
bool native = gen = = pkm . Format ;
for ( int m = 0 ; m < 4 ; m + + )
{
if ( res [ m ] ? . Valid ? ? false )
continue ;
if ( ! ShedinjaEvoMoves [ gen ] . Contains ( moves [ m ] ) )
continue ;
res [ m ] = new CheckResult ( Severity . Valid , native ? V355 : string . Format ( V356 , gen ) , CheckIdentifier . Move ) ;
ShedinjaEvoMovesLearned . Add ( m ) ;
}
}
if ( ShedinjaEvoMovesLearned . Count < = 1 )
return ;
foreach ( int m in ShedinjaEvoMovesLearned )
res [ m ] = new CheckResult ( Severity . Invalid , V357 , CheckIdentifier . Move ) ;
}
2017-05-29 22:21:39 +00:00
private static void ParseEvolutionLevelupMove ( PKM pkm , int [ ] moves , List < int > IncenseMovesLearned , ref CheckResult [ ] res , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
// 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
// Ignore if encounter species is the evolution species, the pokemon was not evolved by the player
if ( ! res . All ( r = > r ? . Valid ? ? false ) | | moves . Any ( m = > m = = 0 ) | |
( Legal . BabyEvolutionWithMove . Contains ( pkm . Species ) & & pkm . GenNumber < = 3 ) | |
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
2017-05-29 22:21:39 +00:00
if ( info . EncounterMatch . EggEncounter & & Legal . BabyEvolutionWithMove . Contains ( pkm . Species ) & & ! IncenseMovesLearned . Any ( ) )
2017-05-28 04:17:53 +00:00
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 )
{
case 122 : // Mr. Mime (Mime Jr with Mimic)
case 185 : // Sudowoodo (Bonsly with Mimic)
ValidMoves . Add ( 102 ) ;
break ;
case 424 : // Ambipom (Aipom with Double Hit)
ValidMoves . Add ( 458 ) ;
break ;
case 463 : // Lickilicky (Lickitung with Rollout)
ValidMoves . Add ( 205 ) ;
break ;
case 465 : // Tangrowth (Tangela with Ancient Power)
case 469 : // Yanmega (Yamma with Ancient Power)
case 473 : // Mamoswine (Piloswine with Ancient Power)
ValidMoves . Add ( 246 ) ;
break ;
case 700 : // Sylveon (Eevee with Fairy Move)
// Add every fairy moves without cheking if eevee learn it or not, pokemon moves are determined legal before this function
ValidMoves . AddRange ( Legal . FairyMoves ) ;
break ;
case 763 : // Tsareena (Steenee with Stomp)
ValidMoves . Add ( 023 ) ;
break ;
}
if ( moves . Any ( m = > ValidMoves . Contains ( m ) ) )
return ;
for ( int m = 0 ; m < 4 ; m + + )
res [ m ] = new CheckResult ( 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 )
{
CheckResult [ ] res = new CheckResult [ 4 ] ;
// Obtain level1 moves
int baseCt = baseMoves . Count ;
if ( baseCt > 4 ) baseCt = 4 ;
// Obtain Inherited moves
var inherited = Moves . Where ( m = > m ! = 0 & & ( ! baseMoves . Contains ( m ) | | specialmoves . Contains ( m ) | | eggmoves . Contains ( m ) | | lvlmoves . Contains ( m ) | | tmhmmoves . Contains ( m ) | | tutormoves . Contains ( m ) ) ) . ToList ( ) ;
int inheritCt = inherited . Count ;
// Get required amount of base moves
int unique = baseMoves . Concat ( inherited ) . Distinct ( ) . Count ( ) ;
int reqBase = inheritCt = = 4 | | baseCt + inheritCt > 4 ? 4 - inheritCt : baseCt ;
if ( Moves . Where ( m = > m ! = 0 ) . Count ( ) < Math . Min ( 4 , baseMoves . Count ) )
reqBase = Math . Min ( 4 , unique ) ;
var em = string . Empty ;
var moveoffset = 0 ;
// Check if the required amount of Base Egg Moves are present.
for ( int i = moveoffset ; i < reqBase ; i + + )
{
if ( baseMoves . Contains ( Moves [ i ] ) )
res [ i ] = new CheckResult ( 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 ) ;
// provide the list of suggested base moves for the last required slot
em = string . Join ( ", " , baseMoves . Select ( m = > m > = movelist . Length ? V190 : movelist [ m ] ) ) ;
break ;
}
}
moveoffset + = reqBase ;
// Check also if the required amount of Special Egg Moves are present, ir are after base moves
for ( int i = moveoffset ; i < moveoffset + specialmoves . Count ; i + + )
{
if ( specialmoves . Contains ( Moves [ i ] ) )
res [ i ] = new CheckResult ( 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 ) ;
// provide the list of suggested base moves and species moves for the last required slot
if ( ! string . IsNullOrEmpty ( em ) ) em + = ", " ;
else
em = string . Join ( ", " , baseMoves . Select ( m = > m > = movelist . Length ? V190 : movelist [ m ] ) ) + ", " ;
em + = string . Join ( ", " , specialmoves . Select ( m = > m > = movelist . Length ? V190 : movelist [ m ] ) ) ;
break ;
}
}
if ( ! string . IsNullOrEmpty ( em ) )
res [ reqBase > 0 ? reqBase - 1 : 0 ] . Comment = string . Format ( Environment . NewLine + V343 , em ) ;
// Non-Base moves that can magically appear in the regular movepool
if ( pkm . GenNumber > = 3 & & Legal . LightBall . Contains ( pkm . Species ) )
eggmoves . Add ( 344 ) ;
// Inherited moves appear after the required base moves.
var AllowInheritedSeverity = AllowInherited ? Severity . Valid : Severity . Invalid ;
for ( int i = reqBase + specialmoves . Count ; i < 4 ; i + + )
{
if ( Moves [ i ] = = 0 ) // empty
res [ i ] = new CheckResult ( Severity . Valid , V167 , CheckIdentifier . Move ) ;
else if ( eggmoves . Contains ( Moves [ i ] ) ) // inherited egg move
res [ i ] = new CheckResult ( 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 ) ;
else if ( tmhmmoves . Contains ( Moves [ i ] ) ) // inherited TMHM moves
res [ i ] = new CheckResult ( 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 ) ;
else // not inheritable, flag
res [ i ] = new CheckResult ( Severity . Invalid , V340 , CheckIdentifier . Move ) ;
}
return res ;
}
private static 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 static void UptateGen1LevelUpMoves ( PKM pkm , ValidEncounterMoves EncounterMoves , int defaultLvlG1 , int generation , LegalInfo info )
{
switch ( generation )
{
case 1 :
case 2 :
var lvlG1 = info . EncounterMatch ? . LevelMin + 1 ? ? 6 ;
if ( lvlG1 ! = defaultLvlG1 )
EncounterMoves . validLevelUpMoves [ 1 ] = Legal . getValidMoves ( pkm , info . EvoChainsAllGens [ 1 ] , generation : 1 , minLvLG1 : lvlG1 , LVL : true , Tutor : false , Machine : false , MoveReminder : false ) . ToList ( ) ;
break ;
}
}
private static int [ ] getGenMovesCheckOrder ( PKM pkm )
{
if ( pkm . Format = = 1 )
return new [ ] { 1 , 2 } ;
if ( pkm . Format = = 2 )
return new [ ] { 2 , 1 } ;
if ( pkm . Format = = 7 & & pkm . VC1 )
return new [ ] { 7 , 1 } ;
if ( pkm . Format = = 7 & & pkm . VC2 )
return new [ ] { 7 , 2 , 1 } ;
var order = new int [ pkm . Format - pkm . GenNumber + 1 ] ;
for ( int i = 0 ; i < order . Length ; i + + )
order [ i ] = pkm . Format - i ;
return order ;
}
private static ValidEncounterMoves getEncounterValidMoves ( PKM pkm , LegalInfo info )
{
var minLvLG1 = pkm . GenNumber < = 2 ? info . EncounterMatch . LevelMin + 1 : 0 ;
var encounterspecies = info . EncounterMatch . Species ;
var EvoChainsAllGens = info . EvoChainsAllGens ;
// If encounter species is the same species from the first match, the one in variable EncounterMatch, its evolution chains is already in EvoChainsAllGens
var LevelMoves = Legal . getValidMovesAllGens ( pkm , EvoChainsAllGens , minLvLG1 : minLvLG1 , Tutor : false , Machine : false , RemoveTransferHM : false ) ;
var TMHMMoves = Legal . getValidMovesAllGens ( pkm , EvoChainsAllGens , LVL : false , Tutor : false , MoveReminder : false , RemoveTransferHM : false ) ;
var TutorMoves = Legal . getValidMovesAllGens ( pkm , EvoChainsAllGens , LVL : false , Machine : false , MoveReminder : false , RemoveTransferHM : false ) ;
return new ValidEncounterMoves
{
EncounterSpecies = encounterspecies ,
validLevelUpMoves = LevelMoves ,
validTMHMMoves = TMHMMoves ,
validTutorMoves = TutorMoves ,
EvolutionChains = EvoChainsAllGens ,
minLvlG1 = minLvLG1
} ;
}
}
}