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
{
2017-10-24 06:12:58 +00:00
/// <summary>
/// Logic to verify the current <see cref="PKM.Moves"/>.
/// </summary>
2017-05-28 04:17:53 +00:00
public static class VerifyCurrentMoves
{
2017-12-12 00:01:24 +00:00
public static CheckMoveResult [ ] VerifyMoves ( PKM pkm , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
int [ ] Moves = pkm . Moves ;
2017-12-12 00:01:24 +00:00
var res = ParseMovesForEncounters ( pkm , info , Moves ) ;
2017-05-28 04:17:53 +00:00
// Duplicate Moves Check
2017-06-18 01:37:19 +00:00
VerifyNoEmptyDuplicates ( Moves , res ) ;
2017-05-28 04:17:53 +00:00
if ( Moves [ 0 ] = = 0 ) // Can't have an empty moveslot for the first move.
2018-09-01 21:11:12 +00:00
res [ 0 ] = new CheckMoveResult ( res [ 0 ] , Severity . Invalid , LMoveSourceEmpty , CheckIdentifier . Move ) ;
2017-05-28 04:17:53 +00:00
return res ;
}
2017-12-12 00:01:24 +00:00
private static CheckMoveResult [ ] ParseMovesForEncounters ( PKM pkm , LegalInfo info , int [ ] Moves )
2017-05-28 04:17:53 +00:00
{
if ( pkm . Species = = 235 ) // special handling for Smeargle
2017-06-18 01:37:19 +00:00
return ParseMovesForSmeargle ( pkm , Moves , info ) ; // Smeargle can have any moves except a few
2017-05-28 04:17:53 +00:00
// gather valid moves for encounter species
2018-10-07 02:44:50 +00:00
var restrict = new LevelUpRestriction ( pkm , info ) ;
info . EncounterMoves = new ValidEncounterMoves ( pkm , restrict ) ;
2017-05-28 04:17:53 +00:00
2017-09-04 02:51:29 +00:00
if ( info . Generation < = 3 )
2017-05-28 04:17:53 +00:00
pkm . WasEgg = info . EncounterMatch . EggEncounter ;
2018-10-07 02:44:50 +00:00
List < int > defaultG1LevelMoves = null ;
List < int > defaultG2LevelMoves = null ;
2017-05-28 04:17:53 +00:00
var defaultTradeback = pkm . TradebackStatus ;
2018-10-07 02:44:50 +00:00
bool gb = false ;
if ( info . EncounterMatch is IGeneration g & & g . Generation < = 2 )
2017-06-07 23:15:13 +00:00
{
2018-10-07 02:44:50 +00:00
gb = true ;
defaultG1LevelMoves = info . EncounterMoves . LevelUpMoves [ 1 ] ;
defaultG2LevelMoves = pkm . InhabitedGeneration ( 2 ) ? info . EncounterMoves . LevelUpMoves [ 2 ] : null ;
2017-05-28 04:17:53 +00:00
// Generation 1 can have different minimum level in different encounter of the same species; update valid level moves
2018-10-07 02:44:50 +00:00
UpdateGen1LevelUpMoves ( pkm , info . EncounterMoves , restrict . MinimumLevelGen1 , g . Generation , info ) ;
2017-09-02 06:45:47 +00:00
// The same for Generation 2; if move reminder from Stadium 2 is not allowed
2018-10-06 02:58:30 +00:00
if ( ! ParseSettings . AllowGen2MoveReminder ( pkm ) & & pkm . InhabitedGeneration ( 2 ) )
2018-10-07 02:44:50 +00:00
UpdateGen2LevelUpMoves ( pkm , info . EncounterMoves , restrict . MinimumLevelGen2 , g . Generation , info ) ;
2017-06-07 23:15:13 +00:00
}
2017-05-28 04:17:53 +00:00
2017-12-12 00:01:24 +00:00
var res = info . Generation < 6
2017-06-18 01:37:19 +00:00
? ParseMovesPre3DS ( pkm , Moves , info )
2017-09-02 06:15:57 +00:00
: ParseMoves3DS ( pkm , Moves , info ) ;
2017-05-28 04:17:53 +00:00
if ( res . All ( x = > x . Valid ) )
return res ;
2017-12-12 00:01:24 +00:00
// not valid
2018-10-07 02:44:50 +00:00
if ( gb ) // restore generation 1 and 2 moves
2017-06-07 23:15:13 +00:00
{
2017-06-18 01:37:19 +00:00
info . EncounterMoves . LevelUpMoves [ 1 ] = defaultG1LevelMoves ;
2017-06-07 23:15:13 +00:00
if ( pkm . InhabitedGeneration ( 2 ) )
2017-06-18 01:37:19 +00:00
info . EncounterMoves . LevelUpMoves [ 2 ] = defaultG2LevelMoves ;
2017-06-07 23:15:13 +00:00
}
2017-05-28 04:17:53 +00:00
pkm . TradebackStatus = defaultTradeback ;
return res ;
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static CheckMoveResult [ ] ParseMovesForSmeargle ( PKM pkm , int [ ] Moves , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
if ( ! pkm . IsEgg )
2017-06-18 01:37:19 +00:00
return ParseMovesSketch ( pkm , Moves ) ;
2017-05-28 04:17:53 +00:00
// can only know sketch as egg
2018-06-11 15:03:10 +00:00
var levelup = new List < int > [ info . EvoChainsAllGens . Length ] ;
levelup [ pkm . Format ] = new List < int > ( 1 ) { 166 } ;
2017-09-02 06:15:57 +00:00
info . EncounterMoves = new ValidEncounterMoves ( levelup ) ;
var source = new MoveParseSource { CurrentMoves = pkm . Moves , } ;
return ParseMoves ( pkm , source , info ) ;
2017-06-18 01:37:19 +00:00
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static CheckMoveResult [ ] ParseMovesIsEggPreRelearn ( PKM pkm , int [ ] Moves , int [ ] SpecialMoves , EncounterEgg e )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
EggInfoSource infoset = new EggInfoSource ( pkm , SpecialMoves , e ) ;
return VerifyPreRelearnEggBase ( pkm , Moves , infoset ) ;
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static CheckMoveResult [ ] ParseMovesWasEggPreRelearn ( PKM pkm , int [ ] Moves , LegalInfo info , EncounterEgg e )
2017-05-28 04:17:53 +00:00
{
2017-08-01 00:09:16 +00:00
var EventEggMoves = GetSpecialMoves ( info . EncounterMatch ) ;
2018-06-09 03:36:52 +00:00
// Level up moves could not be inherited if Ditto is parent,
2017-09-02 06:15:57 +00:00
// that means genderless species and male only species except Nidoran and Volbeat (they breed with female nidoran and illumise) could not have level up moves as an egg
2018-08-03 03:11:42 +00:00
var AllowLevelUp = ( pkm . PersonalInfo . Gender > 0 & & pkm . PersonalInfo . Gender < 255 ) | | Legal . MixedGenderBreeding . Contains ( e . Species ) ;
2017-09-02 06:15:57 +00:00
int BaseLevel = AllowLevelUp ? 100 : e . LevelMin ;
2018-03-31 05:11:24 +00:00
var LevelUp = Legal . GetBaseEggMoves ( pkm , e . Species , e . Version , BaseLevel ) ;
2017-11-18 06:19:23 +00:00
2017-06-07 03:10:05 +00:00
var TradebackPreevo = pkm . Format = = 2 & & info . EncounterMatch . Species > 151 ;
2018-05-12 15:13:39 +00:00
var NonTradebackLvlMoves = TradebackPreevo
? Legal . GetExclusivePreEvolutionMoves ( pkm , info . EncounterMatch . Species , info . EvoChainsAllGens [ 2 ] , 2 , e . Version ) . Where ( m = > m > Legal . MaxMoveID_1 ) . ToArray ( )
2018-08-02 01:30:51 +00:00
: Array . Empty < int > ( ) ;
2017-11-18 06:19:23 +00:00
2018-06-19 04:56:30 +00:00
var Egg = MoveEgg . GetEggMoves ( pkm , e . Species , pkm . AltForm , e . Version ) ;
2017-10-17 00:24:19 +00:00
if ( info . Generation < 3 & & pkm . Format > = 7 & & pkm . VC1 )
Egg = Egg . Where ( m = > m < = Legal . MaxMoveID_1 ) . ToArray ( ) ;
2017-05-28 04:17:53 +00:00
2018-03-31 05:11:24 +00:00
bool volt = ( info . Generation > 3 | | e . Version = = GameVersion . E ) & & Legal . LightBall . Contains ( pkm . Species ) ;
2018-08-02 01:30:51 +00:00
var Special = volt & & EventEggMoves . Length = = 0 ? new [ ] { 344 } : Array . Empty < int > ( ) ; // Volt Tackle for bred Pichu line
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
var source = new MoveParseSource
{
CurrentMoves = Moves ,
SpecialSource = Special ,
NonTradeBackLevelUpMoves = NonTradebackLvlMoves ,
EggLevelUpSource = LevelUp ,
EggMoveSource = Egg ,
EggEventSource = EventEggMoves ,
} ;
return ParseMoves ( pkm , source , info ) ;
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static CheckMoveResult [ ] ParseMovesSketch ( PKM pkm , int [ ] Moves )
2017-05-28 04:17:53 +00:00
{
2018-08-03 03:11:42 +00:00
var res = new CheckMoveResult [ 4 ] ;
2017-05-28 04:17:53 +00:00
for ( int i = 0 ; i < 4 ; i + + )
2018-08-03 03:11:42 +00:00
{
2017-05-28 04:17:53 +00:00
res [ i ] = Legal . InvalidSketch . Contains ( Moves [ i ] )
2018-09-01 21:11:12 +00:00
? new CheckMoveResult ( MoveSource . Unknown , pkm . Format , Severity . Invalid , LMoveSourceInvalidSketch , CheckIdentifier . Move )
2017-06-07 03:10:05 +00:00
: new CheckMoveResult ( MoveSource . Sketch , pkm . Format , CheckIdentifier . Move ) ;
2018-08-03 03:11:42 +00:00
}
2017-05-28 04:17:53 +00:00
return res ;
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static CheckMoveResult [ ] ParseMoves3DS ( PKM pkm , int [ ] Moves , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
2018-08-02 01:30:51 +00:00
info . EncounterMoves . Relearn = info . Generation > = 6 ? pkm . RelearnMoves : Array . Empty < int > ( ) ;
2017-05-28 04:17:53 +00:00
if ( info . EncounterMatch is IMoveset )
2017-06-18 01:37:19 +00:00
return ParseMovesSpecialMoveset ( pkm , Moves , info ) ;
2017-05-28 04:17:53 +00:00
// Everything else
2017-06-18 01:37:19 +00:00
return ParseMovesRelearn ( pkm , Moves , info ) ;
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static CheckMoveResult [ ] ParseMovesPre3DS ( PKM pkm , int [ ] Moves , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
2017-06-04 07:12:35 +00:00
if ( pkm . IsEgg & & info . EncounterMatch is EncounterEgg egg )
2017-05-28 04:17:53 +00:00
{
2017-08-01 00:09:16 +00:00
int [ ] SpecialMoves = GetSpecialMoves ( info . EncounterMatch ) ;
2017-09-02 06:15:57 +00:00
return ParseMovesIsEggPreRelearn ( pkm , Moves , SpecialMoves , egg ) ;
2017-05-28 04:17:53 +00:00
}
2018-04-01 22:04:53 +00:00
if ( info . EncounterMatch is EncounterEgg e )
return ParseMovesWasEggPreRelearn ( pkm , Moves , info , e ) ;
2018-10-06 02:58:30 +00:00
if ( info . Generation < = 2 & & info . EncounterMatch is IGeneration g & & ( g . Generation = = 1 | | ( g . Generation = = 2 & & ! ParseSettings . AllowGen2MoveReminder ( pkm ) ) ) ) // fixed encounter moves without relearning
2017-06-18 01:37:19 +00:00
return ParseMovesGenGB ( pkm , Moves , info ) ;
2017-05-28 04:17:53 +00:00
2017-06-18 01:37:19 +00:00
return ParseMovesSpecialMoveset ( pkm , Moves , info ) ;
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static CheckMoveResult [ ] ParseMovesGenGB ( PKM pkm , int [ ] Moves , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
2017-06-07 03:10:05 +00:00
CheckMoveResult [ ] res = new CheckMoveResult [ 4 ] ;
2017-05-28 04:17:53 +00:00
var G1Encounter = info . EncounterMatch ;
if ( G1Encounter = = null )
2017-06-18 01:37:19 +00:00
return ParseMovesSpecialMoveset ( pkm , Moves , info ) ;
2018-08-02 01:30:51 +00:00
var InitialMoves = Array . Empty < int > ( ) ;
2017-08-01 00:09:16 +00:00
int [ ] SpecialMoves = GetSpecialMoves ( info . EncounterMatch ) ;
2018-10-10 04:07:13 +00:00
var games = info . EncounterMatch is IGeneration g & & g . Generation = = 1 ? GBRestrictions . GetGen1Versions ( info ) : GBRestrictions . GetGen2Versions ( info ) ;
2018-06-19 02:57:32 +00:00
foreach ( var ver in games )
2017-05-28 04:17:53 +00:00
{
2018-06-19 02:57:32 +00:00
var VerInitialMoves = MoveLevelUp . GetEncounterMoves ( G1Encounter . Species , 0 , G1Encounter . LevelMin , ver ) ;
if ( VerInitialMoves . Intersect ( InitialMoves ) . Count ( ) = = VerInitialMoves . Length )
2017-05-28 04:17:53 +00:00
return res ;
2017-09-02 06:15:57 +00:00
var source = new MoveParseSource
{
CurrentMoves = Moves ,
SpecialSource = SpecialMoves ,
Base = VerInitialMoves ,
} ;
res = ParseMoves ( pkm , source , info ) ;
2017-05-28 04:17:53 +00:00
if ( res . All ( r = > r . Valid ) )
return res ;
InitialMoves = VerInitialMoves ;
}
return res ;
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static CheckMoveResult [ ] ParseMovesSpecialMoveset ( PKM pkm , int [ ] Moves , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
var source = new MoveParseSource
{
CurrentMoves = Moves ,
SpecialSource = GetSpecialMoves ( info . EncounterMatch ) ,
} ;
return ParseMoves ( pkm , source , info ) ;
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2017-07-26 00:35:07 +00:00
private static int [ ] GetSpecialMoves ( IEncounterable EncounterMatch )
{
2018-09-02 02:55:08 +00:00
if ( EncounterMatch is IMoveset mg & & mg . Moves ! = null )
return mg . Moves ;
2018-08-02 01:30:51 +00:00
return Array . Empty < int > ( ) ;
2017-07-26 00:35:07 +00:00
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static CheckMoveResult [ ] ParseMovesRelearn ( PKM pkm , int [ ] Moves , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
var source = new MoveParseSource
{
CurrentMoves = Moves ,
SpecialSource = GetSpecialMoves ( info . EncounterMatch ) ,
} ;
2017-05-28 04:17:53 +00:00
2017-09-04 20:48:10 +00:00
if ( info . EncounterMatch is EncounterEgg e )
2018-06-19 04:56:30 +00:00
source . EggMoveSource = MoveEgg . GetEggMoves ( pkm , e . Species , pkm . AltForm , e . Version ) ;
2017-10-17 00:24:19 +00:00
2017-09-02 06:15:57 +00:00
CheckMoveResult [ ] res = ParseMoves ( pkm , source , info ) ;
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
int [ ] RelearnMoves = pkm . RelearnMoves ;
2017-05-28 04:17:53 +00:00
for ( int i = 0 ; i < 4 ; i + + )
2018-08-03 03:11:42 +00:00
{
2017-05-28 04:17:53 +00:00
if ( ( pkm . IsEgg | | res [ i ] . Flag ) & & ! RelearnMoves . Contains ( Moves [ i ] ) )
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( res [ i ] , Severity . Invalid , string . Format ( LMoveRelearnFMiss_0 , res [ i ] . Comment ) , res [ i ] . Identifier ) ;
2018-08-03 03:11:42 +00:00
}
2017-05-28 04:17:53 +00:00
return res ;
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static CheckMoveResult [ ] ParseMoves ( PKM pkm , MoveParseSource source , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
2017-06-07 03:10:05 +00:00
CheckMoveResult [ ] res = new CheckMoveResult [ 4 ] ;
2017-09-02 06:15:57 +00:00
bool AllParsed ( ) = > res . All ( r = > r ! = null ) ;
2018-10-10 04:07:13 +00:00
var required = pkm . Format ! = 1 ? 1 : GBRestrictions . GetRequiredMoveCount ( pkm , source . CurrentMoves , info , source . Base ) ;
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
// Check empty moves and relearn moves before generation specific moves
2017-05-28 04:17:53 +00:00
for ( int m = 0 ; m < 4 ; m + + )
{
2017-09-02 06:15:57 +00:00
if ( source . CurrentMoves [ m ] = = 0 )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . None , pkm . Format , m < required ? Severity . Fishy : Severity . Valid , LMoveSourceEmpty , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( info . EncounterMoves . Relearn . Contains ( source . CurrentMoves [ m ] ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . Relearn , info . Generation , Severity . Valid , LMoveSourceRelearn , CheckIdentifier . Move ) { Flag = true } ;
2017-05-28 04:17:53 +00:00
}
2017-09-02 06:15:57 +00:00
if ( AllParsed ( ) )
2017-05-28 04:17:53 +00:00
return res ;
2017-09-02 06:15:57 +00:00
// Encapsulate arguments to simplify method calls
var moveInfo = new LearnInfo ( pkm ) { Source = source } ;
2017-05-28 04:17:53 +00:00
// Check moves going backwards, marking the move valid in the most current generation when it can be learned
2017-06-18 01:37:19 +00:00
int [ ] generations = GetGenMovesCheckOrder ( pkm ) ;
2017-07-18 23:21:31 +00:00
if ( pkm . Format < = 2 )
generations = generations . Where ( z = > z < info . EncounterMoves . LevelUpMoves . Length ) . ToArray ( ) ;
2017-09-02 06:15:57 +00:00
2017-09-20 16:04:30 +00:00
int lastgen = generations . LastOrDefault ( ) ;
2017-05-28 04:17:53 +00:00
foreach ( var gen in generations )
{
2017-09-02 06:15:57 +00:00
ParseMovesByGeneration ( pkm , res , gen , info , moveInfo , lastgen ) ;
if ( AllParsed ( ) )
return res ;
}
2017-05-28 04:17:53 +00:00
2018-04-11 00:00:28 +00:00
if ( pkm . Species = = 292 & & info . Generation < = 4 )
2017-09-02 06:15:57 +00:00
ParseShedinjaEvolveMoves ( pkm , res , source . CurrentMoves ) ;
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
for ( int m = 0 ; m < 4 ; m + + )
{
if ( res [ m ] = = null )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . Unknown , info . Generation , Severity . Invalid , LMoveSourceInvalid , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
}
return res ;
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static void ParseMovesByGeneration ( PKM pkm , CheckMoveResult [ ] res , int gen , LegalInfo info , LearnInfo learnInfo , int last )
{
2017-12-15 00:16:47 +00:00
GetHMCompatibility ( pkm , res , gen , learnInfo . Source . CurrentMoves , out bool [ ] HMLearned , out bool KnowDefogWhirlpool ) ;
2017-09-02 06:15:57 +00:00
ParseMovesByGeneration ( pkm , res , gen , info , learnInfo ) ;
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
if ( gen = = last )
ParseMovesByGenerationLast ( pkm , res , gen , learnInfo ) ;
2017-06-07 03:10:05 +00:00
2017-09-02 06:15:57 +00:00
switch ( gen )
{
case 3 :
case 4 :
if ( pkm . Format > gen )
FlagIncompatibleTransferHMs ( res , learnInfo . Source . CurrentMoves , gen , HMLearned , KnowDefogWhirlpool ) ;
break ;
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
case 1 :
case 2 :
ParseMovesByGeneration12 ( pkm , res , learnInfo . Source . CurrentMoves , gen , info , learnInfo ) ;
break ;
}
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
// 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
if ( Legal . SpeciesEvolutionWithMove . Contains ( pkm . Species ) )
2018-09-15 05:37:47 +00:00
ParseEvolutionLevelupMove ( pkm , res , learnInfo . Source . CurrentMoves , info ) ;
2017-09-02 06:15:57 +00:00
}
2018-08-03 03:11:42 +00:00
2017-12-15 00:16:47 +00:00
private static void ParseMovesByGeneration ( PKM pkm , IList < CheckMoveResult > res , int gen , LegalInfo info , LearnInfo learnInfo )
2017-09-02 06:15:57 +00:00
{
var moves = learnInfo . Source . CurrentMoves ;
bool native = gen = = pkm . Format ;
for ( int m = 0 ; m < 4 ; m + + )
{
if ( IsCheckValid ( res [ m ] ) ) // already validated with another generation
continue ;
2017-09-20 23:19:50 +00:00
int move = moves [ m ] ;
if ( move = = 0 )
2017-09-02 06:15:57 +00:00
continue ;
2017-05-28 04:17:53 +00:00
2018-04-01 22:04:53 +00:00
if ( gen < = 2 )
{
if ( gen = = 2 & & ! native & & move > Legal . MaxMoveID_1 & & pkm . VC1 )
2018-04-01 22:51:55 +00:00
{
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . Unknown , gen , Severity . Invalid , LMoveSourceInvalid , CheckIdentifier . Move ) ;
2018-04-01 22:51:55 +00:00
continue ;
}
if ( gen = = 2 & & learnInfo . Source . EggMoveSource . Contains ( move ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . EggMove , gen , Severity . Valid , LMoveSourceEgg , CheckIdentifier . Move ) ;
2018-04-01 22:04:53 +00:00
else if ( learnInfo . Source . Base . Contains ( move ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . Initial , gen , Severity . Valid , native ? LMoveSourceDefault : string . Format ( LMoveFDefault_0 , gen ) , CheckIdentifier . Move ) ;
2018-04-01 22:04:53 +00:00
}
2018-04-01 22:51:55 +00:00
if ( info . EncounterMoves . LevelUpMoves [ gen ] . Contains ( move ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . LevelUp , gen , Severity . Valid , native ? LMoveSourceLevelUp : string . Format ( LMoveFLevelUp_0 , gen ) , CheckIdentifier . Move ) ;
2017-09-20 23:19:50 +00:00
else if ( info . EncounterMoves . TMHMMoves [ gen ] . Contains ( move ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . TMHM , gen , Severity . Valid , native ? LMoveSourceTMHM : string . Format ( LMoveFTMHM_0 , gen ) , CheckIdentifier . Move ) ;
2017-09-20 23:19:50 +00:00
else if ( info . EncounterMoves . TutorMoves [ gen ] . Contains ( move ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . Tutor , gen , Severity . Valid , native ? LMoveSourceTutor : string . Format ( LMoveFTutor_0 , gen ) , CheckIdentifier . Move ) ;
2017-09-20 23:19:50 +00:00
else if ( gen = = info . Generation & & learnInfo . Source . SpecialSource . Contains ( move ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . Special , gen , Severity . Valid , LMoveSourceSpecial , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
if ( res [ m ] = = null | | gen > = 3 )
continue ;
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
if ( res [ m ] . Valid & & gen = = 2 & & learnInfo . Source . NonTradeBackLevelUpMoves . Contains ( m ) )
learnInfo . Gen2PreevoMoves . Add ( m ) ;
if ( res [ m ] . Valid & & gen = = 1 )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
learnInfo . Gen1Moves . Add ( m ) ;
2017-12-05 04:16:54 +00:00
if ( learnInfo . Gen2PreevoMoves . Count ! = 0 )
2017-09-02 06:15:57 +00:00
learnInfo . MixedGen12NonTradeback = true ;
2017-05-28 04:17:53 +00:00
}
2017-09-04 02:51:29 +00:00
if ( res [ m ] . Valid & & gen < = 2 & & pkm . TradebackStatus = = TradebackType . Any & & info . Generation ! = gen )
2017-09-02 06:15:57 +00:00
pkm . TradebackStatus = TradebackType . WasTradeback ;
}
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static void ParseMovesByGeneration12 ( PKM pkm , CheckMoveResult [ ] res , int [ ] moves , int gen , LegalInfo info , LearnInfo learnInfo )
{
// Mark the gen 1 exclusive moves as illegal because the pokemon also have Non tradeback egg moves.
if ( learnInfo . MixedGen12NonTradeback )
{
foreach ( int m in learnInfo . Gen1Moves )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , LG1MoveExclusive , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
foreach ( int m in learnInfo . Gen2PreevoMoves )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , LG1TradebackPreEvoMove , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
}
2017-06-07 03:10:05 +00:00
2017-09-02 06:15:57 +00:00
if ( gen = = 1 & & pkm . Format = = 1 & & pkm . Gen1_NotTradeback )
{
ParseRedYellowIncompatibleMoves ( pkm , res , moves ) ;
ParseEvolutionsIncompatibleMoves ( pkm , res , moves , info . EncounterMoves . TMHMMoves [ 1 ] ) ;
}
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static void ParseMovesByGenerationLast ( PKM pkm , CheckMoveResult [ ] res , int gen , LearnInfo learnInfo )
{
ParseEggMovesInherited ( pkm , res , gen , learnInfo ) ;
ParseEggMoves ( pkm , res , gen , learnInfo ) ;
ParseEggMovesRemaining ( pkm , res , learnInfo ) ;
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static void ParseEggMovesInherited ( PKM pkm , CheckMoveResult [ ] res , int gen , LearnInfo learnInfo )
{
var moves = learnInfo . Source . CurrentMoves ;
// 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 + + )
{
2017-12-15 00:16:47 +00:00
if ( IsCheckValid ( res [ m ] ) ) // already validated
2017-09-02 06:15:57 +00:00
continue ;
if ( moves [ m ] = = 0 )
continue ;
if ( ! learnInfo . Source . EggLevelUpSource . Contains ( moves [ m ] ) ) // Check if contains level-up egg moves from parents
continue ;
2017-12-05 04:16:54 +00:00
if ( learnInfo . IsGen2Pkm & & learnInfo . Gen1Moves . Count ! = 0 & & moves [ m ] > Legal . MaxMoveID_1 )
2017-09-02 06:15:57 +00:00
{
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . InheritLevelUp , gen , Severity . Invalid , LG1MoveTradeback , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
learnInfo . MixedGen12NonTradeback = true ;
2017-06-07 03:10:05 +00:00
}
2017-09-02 06:15:57 +00:00
else
2018-08-03 03:11:42 +00:00
{
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . InheritLevelUp , gen , Severity . Valid , LMoveEggLevelUp , CheckIdentifier . Move ) ;
2018-08-03 03:11:42 +00:00
}
2017-09-02 06:15:57 +00:00
learnInfo . LevelUpEggMoves . Add ( m ) ;
if ( pkm . TradebackStatus = = TradebackType . Any & & pkm . GenNumber = = 1 )
pkm . TradebackStatus = TradebackType . WasTradeback ;
}
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static void ParseEggMoves ( PKM pkm , CheckMoveResult [ ] res , int gen , LearnInfo learnInfo )
{
var moves = learnInfo . Source . CurrentMoves ;
// 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 ( IsCheckValid ( res [ m ] ) )
continue ;
if ( moves [ m ] = = 0 )
continue ;
2017-05-28 04:17:53 +00:00
2018-07-02 04:34:17 +00:00
bool wasEggMove = learnInfo . Source . EggMoveSource . Contains ( moves [ m ] ) ;
if ( wasEggMove )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
// 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
2017-12-05 04:16:54 +00:00
if ( learnInfo . IsGen2Pkm & & learnInfo . Gen1Moves . Count ! = 0 & & moves [ m ] > Legal . MaxMoveID_1 )
2017-09-02 06:15:57 +00:00
{
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . EggMove , gen , Severity . Invalid , LG1MoveTradeback , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
learnInfo . MixedGen12NonTradeback = true ;
}
else
2018-08-03 03:11:42 +00:00
{
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . EggMove , gen , Severity . Valid , LMoveSourceEgg , CheckIdentifier . Move ) { Flag = true } ;
2018-08-03 03:11:42 +00:00
}
2017-05-28 04:17:53 +00:00
2017-09-02 06:15:57 +00:00
learnInfo . EggMovesLearned . Add ( m ) ;
if ( pkm . TradebackStatus = = TradebackType . Any & & pkm . GenNumber = = 1 )
pkm . TradebackStatus = TradebackType . WasTradeback ;
2017-05-28 04:17:53 +00:00
}
2017-09-02 06:15:57 +00:00
if ( ! learnInfo . Source . EggEventSource . Contains ( moves [ m ] ) )
continue ;
2017-05-28 04:17:53 +00:00
2018-07-02 04:34:17 +00:00
if ( ! wasEggMove )
2017-05-28 04:17:53 +00:00
{
2017-12-05 04:16:54 +00:00
if ( learnInfo . IsGen2Pkm & & learnInfo . Gen1Moves . Count ! = 0 & & moves [ m ] > Legal . MaxMoveID_1 )
2017-09-02 06:15:57 +00:00
{
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . SpecialEgg , gen , Severity . Invalid , LG1MoveTradeback , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
learnInfo . MixedGen12NonTradeback = true ;
}
else
2018-08-03 03:11:42 +00:00
{
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( MoveSource . SpecialEgg , gen , Severity . Valid , LMoveSourceEggEvent , CheckIdentifier . Move ) ;
2018-08-03 03:11:42 +00:00
}
2017-05-28 04:17:53 +00:00
}
2017-09-02 06:15:57 +00:00
if ( pkm . TradebackStatus = = TradebackType . Any & & pkm . GenNumber = = 1 )
pkm . TradebackStatus = TradebackType . WasTradeback ;
learnInfo . EventEggMoves . Add ( m ) ;
2017-05-28 04:17:53 +00:00
}
2017-09-02 06:15:57 +00:00
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static void ParseEggMovesRemaining ( PKM pkm , CheckMoveResult [ ] res , LearnInfo learnInfo )
{
// 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 = learnInfo . EggMovesLearned . Union ( learnInfo . LevelUpEggMoves ) . ToList ( ) ;
2017-12-05 04:16:54 +00:00
if ( RegularEggMovesLearned . Count ! = 0 & & learnInfo . EventEggMoves . Count ! = 0 )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
// Moves that are egg moves or event egg moves but not both
var IncompatibleEggMoves = RegularEggMovesLearned . Except ( learnInfo . EventEggMoves ) . Union ( learnInfo . EventEggMoves . Except ( RegularEggMovesLearned ) ) . ToList ( ) ;
2017-12-05 04:16:54 +00:00
if ( IncompatibleEggMoves . Count = = 0 )
2017-09-02 06:15:57 +00:00
return ;
foreach ( int m in IncompatibleEggMoves )
{
if ( learnInfo . EventEggMoves . Contains ( m ) & & ! learnInfo . EggMovesLearned . Contains ( m ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , LMoveEggIncompatibleEvent , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( ! learnInfo . EventEggMoves . Contains ( m ) & & learnInfo . EggMovesLearned . Contains ( m ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , LMoveEggIncompatible , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( ! learnInfo . EventEggMoves . Contains ( m ) & & learnInfo . LevelUpEggMoves . Contains ( m ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , LMoveEventEggLevelUp , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
}
2017-05-28 04:17:53 +00:00
}
2017-09-02 06:15:57 +00:00
// If there is no incompatibility with event egg check that there is no inherited move in gift eggs and event eggs
2017-12-05 04:16:54 +00:00
else if ( RegularEggMovesLearned . Count ! = 0 & & ( pkm . WasGiftEgg | | pkm . WasEventEgg ) )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
foreach ( int m in RegularEggMovesLearned )
{
if ( learnInfo . EggMovesLearned . Contains ( m ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , pkm . WasGiftEgg ? LMoveEggMoveGift : LMoveEggInvalidEvent , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( learnInfo . LevelUpEggMoves . Contains ( m ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , pkm . WasGiftEgg ? LMoveEggInvalidEventLevelUpGift : LMoveEggInvalidEventLevelUp , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
}
2017-05-28 04:17:53 +00:00
}
}
2018-08-03 03:11:42 +00:00
2017-06-18 01:37:19 +00:00
private static void ParseRedYellowIncompatibleMoves ( PKM pkm , IList < CheckMoveResult > res , int [ ] moves )
2018-07-02 04:34:17 +00:00
{
var incompatible = GetIncompatibleRBYMoves ( pkm , moves ) ;
if ( incompatible . Count = = 0 )
return ;
for ( int m = 0 ; m < 4 ; m + + )
2018-08-03 03:11:42 +00:00
{
2018-07-02 04:34:17 +00:00
if ( incompatible . Contains ( moves [ m ] ) )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , LG1MoveLearnSameLevel , CheckIdentifier . Move ) ;
2018-08-03 03:11:42 +00:00
}
2018-07-02 04:34:17 +00:00
}
2018-10-07 22:36:32 +00:00
private static IList < int > GetIncompatibleRBYMoves ( PKM pkm , int [ ] moves )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
// Check moves that are learned at the same level in red/blue and yellow, these are illegal because there is no move reminder
// There are only two incompatibilites; there is no illegal combination in generation 2+.
switch ( pkm . Species )
2017-05-28 04:17:53 +00:00
{
2018-07-02 04:34:17 +00:00
// Vaporeon in Yellow learns Mist and Haze at level 42, Mist can only be learned if it leveled up in the daycare
2017-09-02 06:15:57 +00:00
// Vaporeon in Red/Blue learns Acid Armor at level 42 and level 47 in Yellow
case 134 when pkm . CurrentLevel < 47 & & moves . Contains ( 151 ) :
2018-10-07 22:36:32 +00:00
{
var incompatible = new List < int > ( 3 ) ;
2017-09-02 06:15:57 +00:00
if ( moves . Contains ( 54 ) )
incompatible . Add ( 54 ) ;
if ( moves . Contains ( 114 ) )
incompatible . Add ( 114 ) ;
2017-12-05 04:16:54 +00:00
if ( incompatible . Count ! = 0 )
2017-09-02 06:15:57 +00:00
incompatible . Add ( 151 ) ;
2018-10-07 22:36:32 +00:00
return incompatible ;
}
2017-09-02 06:15:57 +00:00
// Flareon in Yellow learns Smog at level 42
// Flareon in Red Blue learns Leer at level 42 and level 47 in Yellow
case 136 when pkm . CurrentLevel < 47 & & moves . Contains ( 43 ) & & moves . Contains ( 123 ) :
2018-10-07 22:36:32 +00:00
return new [ ] { 43 , 123 } ;
2017-05-28 04:17:53 +00:00
}
2017-09-02 06:15:57 +00:00
2018-10-07 22:36:32 +00:00
return Array . Empty < int > ( ) ;
2017-05-28 04:17:53 +00:00
}
2018-07-02 04:34:17 +00:00
2017-06-18 01:37:19 +00:00
private static void ParseEvolutionsIncompatibleMoves ( PKM pkm , IList < CheckMoveResult > res , int [ ] moves , List < int > tmhm )
2017-05-28 04:17:53 +00:00
{
2018-10-10 04:07:13 +00:00
GBRestrictions . GetIncompatibleEvolutionMoves ( pkm , moves , tmhm ,
out var prevSpeciesID ,
out var incompatPrev ,
out var incompatCurr ) ;
2017-05-28 04:17:53 +00:00
2018-10-10 04:07:13 +00:00
if ( prevSpeciesID = = 0 )
return ;
2018-08-03 03:11:42 +00:00
2018-10-10 04:07:13 +00:00
var prev = SpeciesStrings [ prevSpeciesID ] ;
var curr = SpeciesStrings [ pkm . Species ] ;
for ( int m = 0 ; m < 4 ; m + + )
2018-10-07 22:36:32 +00:00
{
2018-10-10 04:07:13 +00:00
if ( incompatCurr . Contains ( moves [ m ] ) )
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , string . Format ( LMoveEvoFLower , curr , prev ) , CheckIdentifier . Move ) ;
if ( incompatPrev . Contains ( moves [ m ] ) )
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , string . Format ( LMoveEvoFHigher , curr , prev ) , CheckIdentifier . Move ) ;
2018-10-07 22:36:32 +00:00
}
}
2017-06-18 01:37:19 +00:00
private static void ParseShedinjaEvolveMoves ( PKM pkm , IList < CheckMoveResult > res , int [ ] moves )
2017-05-28 04:17:53 +00:00
{
var ShedinjaEvoMovesLearned = new List < int > ( ) ;
for ( int gen = Math . Min ( pkm . Format , 4 ) ; gen > = 3 ; gen - - )
{
2018-08-28 03:44:26 +00:00
var ninjaskMoves = Legal . GetShedinjaEvolveMoves ( pkm , gen ) ;
2017-05-28 04:17:53 +00:00
bool native = gen = = pkm . Format ;
for ( int m = 0 ; m < 4 ; m + + )
{
2017-12-15 00:16:47 +00:00
if ( IsCheckValid ( res [ m ] ) ) // already validated
2017-05-28 04:17:53 +00:00
continue ;
2018-02-02 03:57:02 +00:00
if ( ! ninjaskMoves . Contains ( moves [ m ] ) )
2017-05-28 04:17:53 +00:00
continue ;
2018-10-07 22:36:32 +00:00
var msg = native ? LMoveNincadaEvo : string . Format ( LMoveNincadaEvoF_0 , gen ) ;
res [ m ] = new CheckMoveResult ( MoveSource . ShedinjaEvo , gen , Severity . Valid , msg , CheckIdentifier . Move ) ;
2017-05-28 04:17:53 +00:00
ShedinjaEvoMovesLearned . Add ( m ) ;
}
}
2018-06-09 23:04:06 +00:00
if ( ShedinjaEvoMovesLearned . Count = = 0 )
return ;
2018-02-02 03:57:02 +00:00
if ( ShedinjaEvoMovesLearned . Count > 1 )
{
// Can't have more than one Ninjask exclusive move on Shedinja
foreach ( int m in ShedinjaEvoMovesLearned )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , LMoveNincada , CheckIdentifier . Move ) ;
2017-05-28 04:17:53 +00:00
return ;
2018-02-02 03:57:02 +00:00
}
// Double check that the Ninjask move level isn't less than any Nincada move level
int move = ShedinjaEvoMovesLearned [ 0 ] ;
int g = res [ move ] . Generation ;
int levelJ = Legal . GetShedinjaMoveLevel ( 291 , moves [ move ] , g ) ;
for ( int m = 0 ; m < 4 ; m + + )
{
2018-03-18 22:30:19 +00:00
if ( m ! = move )
2018-02-02 03:57:02 +00:00
continue ;
if ( res [ m ] . Source ! = MoveSource . LevelUp )
continue ;
int levelS = Legal . GetShedinjaMoveLevel ( 292 , moves [ m ] , res [ m ] . Generation ) ;
if ( levelS > 0 )
continue ;
2017-05-28 04:17:53 +00:00
2018-02-02 03:57:02 +00:00
int levelN = Legal . GetShedinjaMoveLevel ( 290 , moves [ m ] , res [ m ] . Generation ) ;
if ( levelN > levelJ )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , string . Format ( LMoveEvoFHigher , SpeciesStrings [ 290 ] , SpeciesStrings [ 291 ] ) , CheckIdentifier . Move ) ;
2018-02-02 03:57:02 +00:00
}
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2018-09-15 05:37:47 +00:00
private static void ParseEvolutionLevelupMove ( PKM pkm , IList < CheckMoveResult > res , int [ ] moves , 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
2018-09-15 23:13:17 +00:00
if ( info . EncounterMatch . Species = = pkm . Species )
return ;
if ( ! res . All ( r = > r ? . Valid ? ? false ) | | moves . Any ( m = > m = = 0 ) | | ( Legal . BabyEvolutionWithMove . Contains ( pkm . Species ) & & info . Generation < = 3 ) )
2017-05-28 04:17:53 +00:00
return ;
2017-06-18 01:37:19 +00:00
var ValidMoves = Legal . GetValidPostEvolutionMoves ( pkm , pkm . Species , info . EvoChainsAllGens , GameVersion . Any ) ;
2018-08-03 03:11:42 +00:00
2017-09-02 06:45:47 +00:00
// Add the evolution moves to valid moves in case some of these moves could not be learned after evolving
2017-05-28 04:17:53 +00:00
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 + + )
2018-09-01 21:11:12 +00:00
res [ m ] = new CheckMoveResult ( res [ m ] , Severity . Invalid , string . Format ( LMoveEvoFCombination_0 , SpeciesStrings [ pkm . Species ] ) , CheckIdentifier . Move ) ;
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2017-12-15 00:16:47 +00:00
private static void GetHMCompatibility ( PKM pkm , IReadOnlyList < CheckResult > res , int gen , IReadOnlyList < int > moves , out bool [ ] HMLearned , out bool KnowDefogWhirlpool )
2017-09-02 06:15:57 +00:00
{
HMLearned = new bool [ 4 ] ;
// 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
if ( gen = = 4 & & pkm . Format > 4 )
{
2017-12-15 00:16:47 +00:00
IsHMSource ( HMLearned , Legal . HM_4_RemovePokeTransfer ) ;
2017-09-02 06:15:57 +00:00
KnowDefogWhirlpool = moves . Where ( ( m , i ) = > IsDefogWhirl ( m ) & & IsCheckInvalid ( res [ i ] ) ) . Count ( ) = = 2 ;
return ;
}
KnowDefogWhirlpool = false ;
if ( gen = = 3 & & pkm . Format > 3 )
2017-12-15 00:16:47 +00:00
IsHMSource ( HMLearned , Legal . HM_3 ) ;
2017-09-02 06:15:57 +00:00
2017-12-15 00:16:47 +00:00
void IsHMSource ( IList < bool > flags , ICollection < int > source )
2017-09-02 06:15:57 +00:00
{
for ( int i = 0 ; i < 4 ; i + + )
flags [ i ] = IsCheckInvalid ( res [ i ] ) & & source . Contains ( moves [ i ] ) ;
}
}
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static bool IsDefogWhirl ( int move ) = > move = = 250 | | move = = 432 ;
private static bool IsCheckInvalid ( CheckResult chk ) = > ! ( chk ? . Valid ? ? false ) ;
private static bool IsCheckValid ( CheckResult chk ) = > chk ? . Valid ? ? false ;
2018-08-03 03:11:42 +00:00
2017-09-02 06:15:57 +00:00
private static void FlagIncompatibleTransferHMs ( CheckMoveResult [ ] res , int [ ] moves , int gen , bool [ ] HMLearned , bool KnowDefogWhirlpool )
{
2018-06-09 03:36:52 +00:00
// After all the moves from the generations 3 and 4,
2017-09-02 06:15:57 +00:00
// including egg moves if is the origin generation because some hidden moves are also special egg moves in gen 3
2018-06-09 03:36:52 +00:00
// Check if the marked hidden moves that were invalid at the start are now marked as valid, that means
2017-09-02 06:15:57 +00:00
// 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 ) = > IsDefogWhirl ( m ) & & IsCheckValid ( res [ i ] ) ) . Count ( ) ;
if ( invalidCount = = 2 ) // can't know both at the same time
2018-08-03 03:11:42 +00:00
{
2017-09-02 06:15:57 +00:00
for ( int i = 0 ; i < 4 ; i + + ) // flag both moves
2018-08-03 03:11:42 +00:00
{
2017-09-02 06:15:57 +00:00
if ( IsDefogWhirl ( moves [ i ] ) )
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( res [ i ] , Severity . Invalid , LTransferMoveG4HM , CheckIdentifier . Move ) ;
2018-08-03 03:11:42 +00:00
}
}
2017-09-02 06:15:57 +00:00
}
// Flag moves that are only legal when learned from a past-gen HM source
for ( int i = 0 ; i < HMLearned . Length ; i + + )
2018-08-03 03:11:42 +00:00
{
2017-09-02 06:15:57 +00:00
if ( HMLearned [ i ] & & IsCheckValid ( res [ i ] ) )
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( res [ i ] , Severity . Invalid , string . Format ( LTransferMoveHM , gen , gen + 1 ) , CheckIdentifier . Move ) ;
2018-08-03 03:11:42 +00:00
}
2017-09-02 06:15:57 +00:00
}
2017-05-28 04:17:53 +00:00
/* 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 */
2017-09-02 06:15:57 +00:00
private static CheckMoveResult [ ] VerifyPreRelearnEggBase ( PKM pkm , int [ ] Moves , EggInfoSource infoset )
2017-05-28 04:17:53 +00:00
{
2017-06-07 03:10:05 +00:00
CheckMoveResult [ ] res = new CheckMoveResult [ 4 ] ;
var gen = pkm . GenNumber ;
2017-05-28 04:17:53 +00:00
// Obtain level1 moves
2017-09-04 20:48:10 +00:00
var reqBase = GetRequiredBaseMoveCount ( Moves , infoset ) ;
2017-05-28 04:17:53 +00:00
2018-09-02 02:55:08 +00:00
var sb = new System . Text . StringBuilder ( ) ;
2017-05-28 04:17:53 +00:00
// Check if the required amount of Base Egg Moves are present.
2017-06-18 01:37:19 +00:00
for ( int i = 0 ; i < reqBase ; i + + )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
if ( infoset . Base . Contains ( Moves [ i ] ) )
2017-05-28 04:17:53 +00:00
{
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . Initial , gen , Severity . Valid , LMoveRelearnEgg , CheckIdentifier . Move ) ;
2017-06-18 01:37:19 +00:00
continue ;
2017-05-28 04:17:53 +00:00
}
2017-06-18 01:37:19 +00:00
// mark remaining base egg moves missing
for ( int z = i ; z < reqBase ; z + + )
2018-09-01 21:11:12 +00:00
res [ z ] = new CheckMoveResult ( MoveSource . Initial , gen , Severity . Invalid , LMoveRelearnEggMissing , CheckIdentifier . Move ) ;
2017-05-28 04:17:53 +00:00
2017-06-18 01:37:19 +00:00
// provide the list of suggested base moves for the last required slot
2018-09-02 02:55:08 +00:00
sb . Append ( string . Join ( ", " , GetMoveNames ( infoset . Base ) ) ) ;
2017-06-18 01:37:19 +00:00
break ;
}
int moveoffset = reqBase ;
2017-09-02 06:15:57 +00:00
int endSpecial = moveoffset + infoset . Special . Count ;
2017-05-28 04:17:53 +00:00
// Check also if the required amount of Special Egg Moves are present, ir are after base moves
2017-06-18 01:37:19 +00:00
for ( int i = moveoffset ; i < endSpecial ; i + + )
2017-05-28 04:17:53 +00:00
{
2017-09-02 06:15:57 +00:00
if ( infoset . Special . Contains ( Moves [ i ] ) )
2017-05-28 04:17:53 +00:00
{
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . SpecialEgg , gen , Severity . Valid , LMoveSourceEggEvent , CheckIdentifier . Move ) ;
2017-06-18 01:37:19 +00:00
continue ;
2017-05-28 04:17:53 +00:00
}
2017-06-18 01:37:19 +00:00
// Not in special moves, mark remaining special egg moves missing
for ( int z = i ; z < endSpecial ; z + + )
2018-09-01 21:11:12 +00:00
res [ z ] = new CheckMoveResult ( MoveSource . SpecialEgg , gen , Severity . Invalid , LMoveEggMissing , CheckIdentifier . Move ) ;
2017-06-18 01:37:19 +00:00
// provide the list of suggested base moves and species moves for the last required slot
2018-09-02 02:55:08 +00:00
if ( sb . Length = = 0 )
sb . Append ( string . Join ( ", " , GetMoveNames ( infoset . Base ) ) ) ;
sb . Append ( ", " ) ;
sb . Append ( string . Join ( ", " , GetMoveNames ( infoset . Special ) ) ) ;
2017-06-18 01:37:19 +00:00
break ;
2017-05-28 04:17:53 +00:00
}
2018-09-02 02:55:08 +00:00
if ( sb . Length ! = 0 )
2018-10-07 02:44:50 +00:00
res [ reqBase > 0 ? reqBase - 1 : 0 ] . Comment = string . Format ( Environment . NewLine + LMoveFExpect_0 , sb ) ;
2017-05-28 04:17:53 +00:00
// Inherited moves appear after the required base moves.
2017-06-18 01:37:19 +00:00
var AllowInheritedSeverity = infoset . AllowInherited ? Severity . Valid : Severity . Invalid ;
2017-09-02 06:15:57 +00:00
for ( int i = reqBase + infoset . Special . Count ; i < 4 ; i + + )
2017-05-28 04:17:53 +00:00
{
if ( Moves [ i ] = = 0 ) // empty
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . None , gen , Severity . Valid , LMoveSourceEmpty , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( infoset . Egg . Contains ( Moves [ i ] ) ) // inherited egg move
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . EggMove , gen , AllowInheritedSeverity , infoset . AllowInherited ? LMoveEggInherited : LMoveEggInvalidEvent , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( infoset . LevelUp . Contains ( Moves [ i ] ) ) // inherited lvl moves
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . InheritLevelUp , gen , AllowInheritedSeverity , infoset . AllowInherited ? LMoveEggLevelUp : LMoveEggInvalidEventLevelUp , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( infoset . TMHM . Contains ( Moves [ i ] ) ) // inherited TMHM moves
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . TMHM , gen , AllowInheritedSeverity , infoset . AllowInherited ? LMoveEggTMHM : LMoveEggInvalidEventTMHM , CheckIdentifier . Move ) ;
2017-09-02 06:15:57 +00:00
else if ( infoset . Tutor . Contains ( Moves [ i ] ) ) // inherited tutor moves
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . Tutor , gen , AllowInheritedSeverity , infoset . AllowInherited ? LMoveEggInheritedTutor : LMoveEggInvalidEventTutor , CheckIdentifier . Move ) ;
2017-05-28 04:17:53 +00:00
else // not inheritable, flag
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( MoveSource . Unknown , gen , Severity . Invalid , LMoveEggInvalid , CheckIdentifier . Move ) ;
2017-05-28 04:17:53 +00:00
}
return res ;
}
2018-08-03 03:11:42 +00:00
2017-09-04 20:48:10 +00:00
private static int GetRequiredBaseMoveCount ( int [ ] Moves , EggInfoSource infoset )
{
int baseCt = infoset . Base . Count ;
if ( baseCt > 4 ) baseCt = 4 ;
// Obtain Inherited moves
var inherited = Moves . Where ( m = > m ! = 0 & & infoset . IsInherited ( m ) ) . ToList ( ) ;
int inheritCt = inherited . Count ;
// Get required amount of base moves
2017-10-07 04:03:23 +00:00
int unique = infoset . Base . Union ( inherited ) . Count ( ) ;
2017-09-04 20:48:10 +00:00
int reqBase = inheritCt = = 4 | | baseCt + inheritCt > 4 ? 4 - inheritCt : baseCt ;
if ( Moves . Count ( m = > m ! = 0 ) < Math . Min ( 4 , infoset . Base . Count ) )
reqBase = Math . Min ( 4 , unique ) ;
return reqBase ;
}
2017-05-28 04:17:53 +00:00
2017-06-18 01:37:19 +00:00
private static void VerifyNoEmptyDuplicates ( int [ ] Moves , CheckMoveResult [ ] res )
2017-05-28 04:17:53 +00:00
{
bool emptySlot = false ;
for ( int i = 0 ; i < 4 ; i + + )
{
if ( Moves [ i ] = = 0 )
emptySlot = true ;
else if ( emptySlot )
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( res [ i ] , Severity . Invalid , LMoveSourceEmpty , res [ i ] . Identifier ) ;
2017-05-28 04:17:53 +00:00
else if ( Moves . Count ( m = > m = = Moves [ i ] ) > 1 )
2018-09-01 21:11:12 +00:00
res [ i ] = new CheckMoveResult ( res [ i ] , Severity . Invalid , LMoveSourceDuplicate , res [ i ] . Identifier ) ;
2017-05-28 04:17:53 +00:00
}
}
2018-08-03 03:11:42 +00:00
2018-06-09 15:04:40 +00:00
private static void UpdateGen1LevelUpMoves ( PKM pkm , ValidEncounterMoves EncounterMoves , int defaultLvlG1 , int generation , LegalInfo info )
2017-05-28 04:17:53 +00:00
{
2018-09-02 02:55:08 +00:00
if ( generation > = 3 )
return ;
var lvlG1 = info . EncounterMatch ? . LevelMin + 1 ? ? 6 ;
if ( lvlG1 = = defaultLvlG1 )
return ;
EncounterMoves . LevelUpMoves [ 1 ] = Legal . GetValidMoves ( pkm , info . EvoChainsAllGens [ 1 ] , generation : 1 , minLvLG1 : lvlG1 , LVL : true , Tutor : false , Machine : false , MoveReminder : false ) . ToList ( ) ;
2017-06-07 23:15:13 +00:00
}
2018-08-03 03:11:42 +00:00
2018-06-09 15:04:40 +00:00
private static void UpdateGen2LevelUpMoves ( PKM pkm , ValidEncounterMoves EncounterMoves , int defaultLvlG2 , int generation , LegalInfo info )
2017-06-07 23:15:13 +00:00
{
2018-09-02 02:55:08 +00:00
if ( generation > = 3 )
return ;
var lvlG2 = info . EncounterMatch ? . LevelMin + 1 ? ? 6 ;
if ( lvlG2 = = defaultLvlG2 )
return ;
EncounterMoves . LevelUpMoves [ 2 ] = Legal . GetValidMoves ( pkm , info . EvoChainsAllGens [ 2 ] , generation : 2 , minLvLG2 : defaultLvlG2 , LVL : true , Tutor : false , Machine : false , MoveReminder : false ) . ToList ( ) ;
2017-05-28 04:17:53 +00:00
}
2018-08-03 03:11:42 +00:00
2018-03-26 05:50:32 +00:00
public static int [ ] GetGenMovesCheckOrder ( PKM pkm )
2017-05-28 04:17:53 +00:00
{
2017-09-24 17:52:39 +00:00
if ( pkm . Format < 3 )
return GetGenMovesCheckOrderGB ( pkm , pkm . Format ) ;
if ( pkm . VC )
return GetGenMovesOrderVC ( pkm ) ;
2017-05-28 04:17:53 +00:00
2017-09-24 17:52:39 +00:00
return GetGenMovesOrder ( pkm . Format , pkm . GenNumber ) ;
}
2018-08-03 03:11:42 +00:00
2017-09-24 17:52:39 +00:00
private static int [ ] GetGenMovesOrderVC ( PKM pkm )
{
// VC case: check transfer games in reverse order (8, 7..) then past games.
2018-03-28 02:45:22 +00:00
int [ ] xfer = GetGenMovesOrder ( pkm . Format , 7 ) ;
2017-09-24 17:52:39 +00:00
int [ ] past = GetGenMovesCheckOrderGB ( pkm , pkm . GenNumber ) ;
int end = xfer . Length ;
Array . Resize ( ref xfer , xfer . Length + past . Length ) ;
past . CopyTo ( xfer , end ) ;
return xfer ;
}
2018-08-03 03:11:42 +00:00
2018-09-02 02:55:08 +00:00
private static readonly int [ ] G2 = { 2 } ;
private static readonly int [ ] G12 = { 1 , 2 } ;
2018-09-15 05:37:47 +00:00
2017-09-24 17:52:39 +00:00
private static int [ ] GetGenMovesCheckOrderGB ( PKM pkm , int originalGeneration )
{
if ( originalGeneration = = 2 )
2018-09-02 02:55:08 +00:00
return pkm . Korean ? G2 : G12 ;
2017-09-24 17:52:39 +00:00
return new [ ] { 1 , 2 } ; // RBY
}
2018-08-03 03:11:42 +00:00
2017-09-24 17:52:39 +00:00
private static int [ ] GetGenMovesOrder ( int start , int end )
{
2018-06-09 03:36:52 +00:00
if ( end < 0 )
2018-08-02 01:30:51 +00:00
return Array . Empty < int > ( ) ;
2017-11-16 02:13:04 +00:00
if ( start < = end )
return new [ ] { start } ;
2017-09-24 17:52:39 +00:00
var order = new int [ start - end + 1 ] ;
2017-05-28 04:17:53 +00:00
for ( int i = 0 ; i < order . Length ; i + + )
2017-09-24 17:52:39 +00:00
order [ i ] = start - i ;
2017-05-28 04:17:53 +00:00
return order ;
}
}
}