2016-03-12 17:16:41 +00:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
2016-03-11 04:36:32 +00:00
namespace PKHeX
{
public enum Severity
{
Indeterminate = - 2 ,
Invalid = - 1 ,
Fishy = 0 ,
Valid = 1 ,
NotImplemented = 2 ,
}
public class LegalityCheck
{
2016-03-12 03:43:40 +00:00
public Severity Judgement = Severity . Valid ;
2016-04-07 01:13:43 +00:00
public string Comment = "Valid" ;
2016-03-11 04:36:32 +00:00
public bool Valid = > Judgement > = Severity . Fishy ;
2016-03-25 07:10:11 +00:00
public bool Flag ;
2016-03-11 04:36:32 +00:00
public LegalityCheck ( ) { }
public LegalityCheck ( Severity s , string c )
{
Judgement = s ;
Comment = c ;
}
2016-03-14 03:19:04 +00:00
}
public partial class LegalityAnalysis
{
private LegalityCheck verifyECPID ( )
2016-03-11 04:36:32 +00:00
{
// Secondary Checks
2016-03-14 03:19:04 +00:00
if ( pk6 . EncryptionConstant = = 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "Encryption Constant is not set." ) ;
2016-03-14 03:19:04 +00:00
if ( pk6 . PID = = 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "PID is not set." ) ;
2016-04-22 02:46:33 +00:00
string special = "" ;
2016-03-14 03:19:04 +00:00
if ( pk6 . Gen6 )
2016-04-08 00:56:39 +00:00
{
2016-04-21 07:28:40 +00:00
// Wurmple -> Silcoon/Cascoon
int wIndex = Array . IndexOf ( Legal . WurmpleFamily , pk6 . Species ) ;
if ( wIndex > - 1 )
{
// Check if Wurmple was the origin (only Egg and Wild Encounter)
if ( pk6 . WasEgg | | ( EncounterType = = typeof ( EncounterSlot [ ] ) & & ( EncounterMatch as EncounterSlot [ ] ) . All ( slot = > slot . Species = = 265 ) ) )
if ( ( pk6 . EncryptionConstant > > 16 ) % 10 / 5 ! = wIndex / 2 )
return new LegalityCheck ( Severity . Invalid , "Wurmple evolution Encryption Constant mismatch." ) ;
}
2016-04-22 02:46:33 +00:00
else if ( pk6 . Species = = 265 )
special = "Wurmple Evolution: " + ( ( pk6 . EncryptionConstant > > 16 ) % 10 / 5 = = 0 ? "Silcoon" : "Cascoon" ) ;
2016-04-21 07:28:40 +00:00
2016-04-08 00:56:39 +00:00
if ( pk6 . PID = = pk6 . EncryptionConstant )
return new LegalityCheck ( Severity . Fishy , "Encryption Constant matches PID." ) ;
int xor = pk6 . TSV ^ pk6 . PSV ;
2016-04-22 02:46:33 +00:00
if ( xor < 16 & & xor > = 8 & & ( pk6 . PID ^ 0x80000000 ) = = pk6 . EncryptionConstant )
return new LegalityCheck ( Severity . Fishy , "Encryption Constant matches shinyxored PID." ) ;
return special ! = "" ? new LegalityCheck ( Severity . Valid , special ) : new LegalityCheck ( ) ;
2016-04-08 00:56:39 +00:00
}
2016-03-11 04:36:32 +00:00
// When transferred to Generation 6, the Encryption Constant is copied from the PID.
// The PID is then checked to see if it becomes shiny with the new Shiny rules (>>4 instead of >>3)
// If the PID is nonshiny->shiny, the top bit is flipped.
// Check to see if the PID and EC are properly configured.
2016-03-14 03:19:04 +00:00
bool xorPID = ( ( pk6 . TID ^ pk6 . SID ^ ( int ) ( pk6 . PID & 0xFFFF ) ^ ( int ) ( pk6 . PID > > 16 ) ) & 0x7 ) = = 8 ;
2016-03-11 04:36:32 +00:00
bool valid = xorPID
2016-03-14 03:19:04 +00:00
? pk6 . EncryptionConstant = = ( pk6 . PID ^ 0x8000000 )
: pk6 . EncryptionConstant = = pk6 . PID ;
2016-03-11 04:36:32 +00:00
if ( ! valid )
if ( xorPID )
return new LegalityCheck ( Severity . Invalid , "PID should be equal to EC [with top bit flipped]!" ) ;
else
return new LegalityCheck ( Severity . Invalid , "PID should be equal to EC!" ) ;
return new LegalityCheck ( ) ;
}
2016-03-14 03:19:04 +00:00
private LegalityCheck verifyNickname ( )
2016-03-11 04:36:32 +00:00
{
// If the Pokémon is not nicknamed, it should match one of the language strings.
2016-03-14 03:19:04 +00:00
if ( pk6 . Nickname . Length = = 0 )
2016-03-16 01:56:18 +00:00
return new LegalityCheck ( Severity . Indeterminate , "Nickname is empty." ) ;
if ( pk6 . Species > PKX . SpeciesLang [ 0 ] . Length )
return new LegalityCheck ( Severity . Indeterminate , "Species index invalid for Nickname comparison." ) ;
2016-03-20 01:06:02 +00:00
if ( ! Encounter . Valid )
return new LegalityCheck ( Severity . Valid , "Skipped Nickname check due to other check being invalid." ) ;
2016-03-27 00:23:53 +00:00
if ( pk6 . Language > 8 )
return new LegalityCheck ( Severity . Indeterminate , "Language ID > 8." ) ;
2016-03-28 05:05:51 +00:00
if ( EncounterType = = typeof ( EncounterTrade ) )
2016-03-27 00:23:53 +00:00
{
string [ ] validOT = new string [ 0 ] ;
int index = - 1 ;
if ( pk6 . XY )
{
validOT = Legal . TradeXY [ pk6 . Language ] ;
index = Array . IndexOf ( Legal . TradeGift_XY , EncounterMatch ) ;
}
else if ( pk6 . AO )
{
validOT = Legal . TradeAO [ pk6 . Language ] ;
index = Array . IndexOf ( Legal . TradeGift_AO , EncounterMatch ) ;
}
if ( validOT . Length = = 0 )
return new LegalityCheck ( Severity . Indeterminate , "Ingame Trade invalid version?" ) ;
if ( index = = - 1 | | validOT . Length < index * 2 )
return new LegalityCheck ( Severity . Indeterminate , "Ingame Trade invalid lookup?" ) ;
string nick = validOT [ index ] ;
string OT = validOT [ validOT . Length / 2 + index ] ;
if ( nick ! = pk6 . Nickname )
return new LegalityCheck ( Severity . Fishy , "Ingame Trade nickname has been altered." ) ;
if ( OT ! = pk6 . OT_Name )
return new LegalityCheck ( Severity . Invalid , "Ingame Trade OT has been altered." ) ;
return new LegalityCheck ( Severity . Valid , "Ingame Trade OT/Nickname have not been altered." ) ;
}
2016-03-20 01:06:02 +00:00
2016-03-16 04:15:40 +00:00
if ( pk6 . IsEgg )
{
if ( ! pk6 . IsNicknamed )
return new LegalityCheck ( Severity . Invalid , "Eggs must be nicknamed." ) ;
return PKX . SpeciesLang [ pk6 . Language ] [ 0 ] = = pk6 . Nickname
? new LegalityCheck ( Severity . Valid , "Egg matches language Egg name." )
: new LegalityCheck ( Severity . Invalid , "Egg name does not match language Egg name." ) ;
}
2016-03-16 04:40:11 +00:00
string nickname = pk6 . Nickname . Replace ( "'" , "’ " ) ;
2016-03-16 01:56:18 +00:00
if ( pk6 . IsNicknamed )
2016-03-11 04:36:32 +00:00
{
2016-03-20 01:06:02 +00:00
for ( int i = 0 ; i < PKX . SpeciesLang . Length ; i + + )
{
string [ ] lang = PKX . SpeciesLang [ i ] ;
int index = Array . IndexOf ( lang , nickname ) ;
if ( index < 0 )
continue ;
return index = = pk6 . Species & & i ! = pk6 . Language
? new LegalityCheck ( Severity . Fishy , "Nickname matches another species name (+language)." )
: new LegalityCheck ( Severity . Fishy , "Nickname flagged, matches species name." ) ;
}
return new LegalityCheck ( Severity . Valid , "Nickname does not match another species name." ) ;
2016-03-16 01:56:18 +00:00
}
// else
{
// Can't have another language name if it hasn't evolved.
2016-03-16 04:40:11 +00:00
return Legal . getHasEvolved ( pk6 ) & & PKX . SpeciesLang . Any ( lang = > lang [ pk6 . Species ] = = nickname )
| | PKX . SpeciesLang [ pk6 . Language ] [ pk6 . Species ] = = nickname
2016-03-16 02:06:13 +00:00
? new LegalityCheck ( Severity . Valid , "Nickname matches species name." )
: new LegalityCheck ( Severity . Invalid , "Nickname does not match species name." ) ;
2016-03-11 04:36:32 +00:00
}
}
2016-03-14 03:19:04 +00:00
private LegalityCheck verifyEVs ( )
2016-03-11 04:36:32 +00:00
{
2016-03-14 03:19:04 +00:00
var evs = pk6 . EVs ;
int sum = evs . Sum ( ) ;
2016-04-08 00:56:39 +00:00
if ( sum = = 0 & & pk6 . Stat_Level - pk6 . Met_Level > 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "All EVs are zero, but leveled above Met Level" ) ;
2016-03-14 03:19:04 +00:00
if ( sum = = 508 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "2 EVs remaining." ) ;
2016-03-14 03:19:04 +00:00
if ( sum > 510 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Invalid , "EV total cannot be above 510." ) ;
2016-03-14 03:19:04 +00:00
if ( evs . Any ( ev = > ev > 252 ) )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Invalid , "EVs cannot go above 252." ) ;
2016-03-14 03:19:04 +00:00
if ( evs . All ( ev = > pk6 . EVs [ 0 ] = = ev ) & & evs [ 0 ] ! = 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "EVs are all equal." ) ;
return new LegalityCheck ( ) ;
}
2016-03-14 03:19:04 +00:00
private LegalityCheck verifyIVs ( )
2016-03-11 04:36:32 +00:00
{
2016-05-04 02:36:47 +00:00
if ( EncounterType = = typeof ( EncounterStatic ) & & ( EncounterMatch as EncounterStatic ) ? . IV3 = = true )
if ( pk6 . IVs . Count ( iv = > iv = = 31 ) < 3 )
return new LegalityCheck ( Severity . Invalid , "Should have at least 3 IVs = 31." ) ;
2016-03-14 03:19:04 +00:00
if ( pk6 . IVs . Sum ( ) = = 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "All IVs are zero." ) ;
2016-03-14 03:19:04 +00:00
if ( pk6 . IVs [ 0 ] < 30 & & pk6 . IVs . All ( iv = > pk6 . IVs [ 0 ] = = iv ) )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "All IVs are equal." ) ;
return new LegalityCheck ( ) ;
}
2016-03-14 03:19:04 +00:00
private LegalityCheck verifyID ( )
2016-03-11 04:36:32 +00:00
{
2016-04-08 05:27:36 +00:00
if ( EncounterType = = typeof ( EncounterTrade ) )
return new LegalityCheck ( ) ; // Already matches Encounter Trade information
2016-03-14 03:19:04 +00:00
if ( pk6 . TID = = 0 & & pk6 . SID = = 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "TID and SID are zero." ) ;
2016-04-08 00:56:39 +00:00
if ( pk6 . TID = = pk6 . SID )
return new LegalityCheck ( Severity . Fishy , "TID and SID are equal." ) ;
2016-03-14 03:19:04 +00:00
if ( pk6 . TID = = 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "TID is zero." ) ;
2016-03-14 03:19:04 +00:00
if ( pk6 . SID = = 0 )
2016-03-11 04:36:32 +00:00
return new LegalityCheck ( Severity . Fishy , "SID is zero." ) ;
return new LegalityCheck ( ) ;
}
2016-03-14 03:19:04 +00:00
private LegalityCheck verifyEncounter ( )
2016-03-12 03:43:40 +00:00
{
2016-03-14 03:19:04 +00:00
if ( ! pk6 . Gen6 )
2016-03-12 03:43:40 +00:00
return new LegalityCheck { Judgement = Severity . NotImplemented } ;
2016-03-14 03:19:04 +00:00
if ( pk6 . WasLink )
2016-03-12 03:43:40 +00:00
{
2016-03-16 05:04:04 +00:00
// Should NOT be Fateful, and should be in Database
2016-03-24 00:57:22 +00:00
EncounterLink enc = EncounterMatch as EncounterLink ;
if ( enc = = null )
2016-04-22 02:32:22 +00:00
return new LegalityCheck ( Severity . Invalid , "Invalid Link Gift: unable to find matching gift." ) ;
2016-03-24 00:57:22 +00:00
if ( pk6 . XY & & ! enc . XY )
2016-04-22 02:32:22 +00:00
return new LegalityCheck ( Severity . Invalid , "Invalid Link Gift: can't obtain in XY." ) ;
2016-03-24 00:57:22 +00:00
if ( pk6 . AO & & ! enc . ORAS )
2016-04-22 02:32:22 +00:00
return new LegalityCheck ( Severity . Invalid , "Invalid Link Gift: can't obtain in ORAS." ) ;
2016-04-03 23:56:57 +00:00
if ( enc . Shiny ! = null & & ( bool ) enc . Shiny ^ pk6 . IsShiny )
return new LegalityCheck ( Severity . Invalid , "Shiny Link gift mismatch." ) ;
2016-03-24 00:57:22 +00:00
return pk6 . FatefulEncounter
2016-04-22 02:32:22 +00:00
? new LegalityCheck ( Severity . Invalid , "Invalid Link Gift: should not be Fateful Encounter." )
2016-03-16 05:04:04 +00:00
: new LegalityCheck ( Severity . Valid , "Valid Link gift." ) ;
2016-03-12 03:43:40 +00:00
}
2016-03-14 03:19:04 +00:00
if ( pk6 . WasEvent | | pk6 . WasEventEgg )
2016-03-12 03:43:40 +00:00
{
2016-03-23 05:49:46 +00:00
WC6 MatchedWC6 = EncounterMatch as WC6 ;
2016-03-14 03:19:04 +00:00
return MatchedWC6 ! = null // Matched in RelearnMoves check.
? new LegalityCheck ( Severity . Valid , $"Matches #{MatchedWC6.CardID.ToString(" 0000 ")} ({MatchedWC6.CardTitle})" )
: new LegalityCheck ( Severity . Invalid , "Not a valid Wonder Card gift." ) ;
2016-03-12 03:43:40 +00:00
}
2016-03-23 02:47:13 +00:00
EncounterMatch = null ; // Reset object
2016-03-14 03:19:04 +00:00
if ( pk6 . WasEgg )
2016-03-12 03:43:40 +00:00
{
// Check Hatch Locations
2016-03-14 03:19:04 +00:00
if ( pk6 . Met_Level ! = 1 )
2016-03-12 17:16:41 +00:00
return new LegalityCheck ( Severity . Invalid , "Invalid met level, expected 1." ) ;
2016-04-15 07:39:19 +00:00
// Check species
if ( Legal . NoHatchFromEgg . Contains ( pk6 . Species ) )
return new LegalityCheck ( Severity . Invalid , "Species cannot be hatched from an egg." ) ;
2016-03-14 03:19:04 +00:00
if ( pk6 . IsEgg )
2016-03-12 17:16:41 +00:00
{
2016-03-31 02:07:52 +00:00
if ( pk6 . Egg_Location = = 30002 )
return new LegalityCheck ( Severity . Invalid , "Egg location shouldn't be 'traded' for an un-hatched egg." ) ;
if ( pk6 . Met_Location = = 30002 )
return new LegalityCheck ( Severity . Valid , "Valid traded un-hatched egg." ) ;
2016-03-16 01:56:18 +00:00
return pk6 . Met_Location = = 0
2016-03-12 17:16:41 +00:00
? new LegalityCheck ( Severity . Valid , "Valid un-hatched egg." )
2016-04-07 01:13:43 +00:00
: new LegalityCheck ( Severity . Invalid , "Invalid location for un-hatched egg (expected no met location)." ) ;
2016-03-12 17:16:41 +00:00
}
2016-03-16 02:06:13 +00:00
if ( pk6 . XY )
2016-03-12 03:43:40 +00:00
{
2016-04-23 17:12:52 +00:00
if ( pk6 . Egg_Location = = 318 )
return new LegalityCheck ( Severity . Invalid , "Invalid X/Y egg location." ) ;
2016-03-16 01:56:18 +00:00
return Legal . ValidMet_XY . Contains ( pk6 . Met_Location )
2016-03-12 17:16:41 +00:00
? new LegalityCheck ( Severity . Valid , "Valid X/Y hatched egg." )
: new LegalityCheck ( Severity . Invalid , "Invalid X/Y location for hatched egg." ) ;
2016-03-12 03:43:40 +00:00
}
2016-03-16 02:06:13 +00:00
if ( pk6 . AO )
2016-03-12 03:43:40 +00:00
{
2016-03-16 01:56:18 +00:00
return Legal . ValidMet_AO . Contains ( pk6 . Met_Location )
2016-03-12 17:16:41 +00:00
? new LegalityCheck ( Severity . Valid , "Valid OR/AS hatched egg." )
: new LegalityCheck ( Severity . Invalid , "Invalid OR/AS location for hatched egg." ) ;
2016-03-12 03:43:40 +00:00
}
return new LegalityCheck ( Severity . Invalid , "Invalid location for hatched egg." ) ;
}
2016-03-23 02:47:13 +00:00
EncounterMatch = Legal . getValidStaticEncounter ( pk6 ) ;
if ( EncounterMatch ! = null )
2016-03-13 21:56:23 +00:00
return new LegalityCheck ( Severity . Valid , "Valid gift/static encounter." ) ;
2016-03-17 02:15:49 +00:00
if ( Legal . getIsFossil ( pk6 ) )
{
return pk6 . AbilityNumber ! = 4
? new LegalityCheck ( Severity . Valid , "Valid revived fossil." )
: new LegalityCheck ( Severity . Invalid , "Hidden ability on revived fossil." ) ;
}
2016-03-23 05:31:30 +00:00
EncounterMatch = Legal . getValidFriendSafari ( pk6 ) ;
if ( EncounterMatch ! = null )
2016-03-16 01:35:40 +00:00
{
if ( pk6 . Species = = 670 | | pk6 . Species = = 671 ) // Floette
2016-04-20 03:16:40 +00:00
if ( ! new [ ] { 0 , 1 , 3 } . Contains ( pk6 . AltForm ) ) // 0/1/3 - RBY
2016-03-16 01:35:40 +00:00
return new LegalityCheck ( Severity . Invalid , "Friend Safari: Not valid color." ) ;
else if ( pk6 . Species = = 710 | | pk6 . Species = = 711 ) // Pumpkaboo
if ( pk6 . AltForm ! = 1 ) // Average
return new LegalityCheck ( Severity . Invalid , "Friend Safari: Not average sized." ) ;
else if ( pk6 . Species = = 586 ) // Sawsbuck
if ( pk6 . AltForm ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Friend Safari: Not Spring form." ) ;
2016-03-13 21:56:23 +00:00
return new LegalityCheck ( Severity . Valid , "Valid friend safari encounter." ) ;
2016-03-16 01:35:40 +00:00
}
2016-03-23 02:47:13 +00:00
EncounterMatch = Legal . getValidWildEncounters ( pk6 ) ;
if ( EncounterMatch ! = null )
2016-03-13 23:42:03 +00:00
{
2016-04-21 02:47:40 +00:00
EncounterSlot [ ] enc = ( EncounterSlot [ ] ) EncounterMatch ;
if ( enc . Any ( slot = > slot . Normal ) )
return enc . All ( slot = > slot . Pressure )
? new LegalityCheck ( Severity . Valid , "Valid encounter at location (Pressure/Hustle/Vital Spirit)." )
: new LegalityCheck ( Severity . Valid , "Valid encounter at location." ) ;
// Decreased Level Encounters
if ( enc . Any ( slot = > slot . WhiteFlute ) )
return enc . All ( slot = > slot . Pressure )
? new LegalityCheck ( Severity . Valid , "Valid encounter at location (White Flute & Pressure/Hustle/Vital Spirit)." )
: new LegalityCheck ( Severity . Valid , "Valid encounter at location (White Flute)." ) ;
// Increased Level Encounters
if ( enc . Any ( slot = > slot . BlackFlute ) )
return enc . All ( slot = > slot . Pressure )
? new LegalityCheck ( Severity . Valid , "Valid encounter at location (Black Flute & Pressure/Hustle/Vital Spirit)." )
: new LegalityCheck ( Severity . Valid , "Valid encounter at location (Black Flute)." ) ;
if ( enc . Any ( slot = > slot . Pressure ) )
return new LegalityCheck ( Severity . Valid , "Valid encounter at location (Pressure/Hustle/Vital Spirit)." ) ;
return new LegalityCheck ( Severity . Valid , "Valid encounter at location (DexNav)." ) ;
2016-03-13 23:42:03 +00:00
}
2016-03-23 02:47:13 +00:00
EncounterMatch = Legal . getValidIngameTrade ( pk6 ) ;
if ( EncounterMatch ! = null )
2016-03-18 00:25:21 +00:00
{
return new LegalityCheck ( Severity . Valid , "Valid ingame trade." ) ;
}
2016-03-12 03:43:40 +00:00
return new LegalityCheck ( Severity . Invalid , "Not a valid encounter." ) ;
}
2016-03-19 05:49:21 +00:00
private LegalityCheck verifyLevel ( )
{
2016-03-23 05:49:46 +00:00
WC6 MatchedWC6 = EncounterMatch as WC6 ;
2016-03-22 04:31:06 +00:00
if ( MatchedWC6 ! = null & & MatchedWC6 . Level ! = pk6 . Met_Level )
return new LegalityCheck ( Severity . Invalid , "Met Level does not match Wonder Card level." ) ;
2016-04-08 00:56:39 +00:00
int lvl = pk6 . CurrentLevel ;
if ( lvl < pk6 . Met_Level )
return new LegalityCheck ( Severity . Invalid , "Current level is below met level." ) ;
2016-04-23 15:37:05 +00:00
if ( ( pk6 . WasEgg | | EncounterMatch = = null ) & & ! Legal . getEvolutionValid ( pk6 ) & & pk6 . Species ! = 350 )
2016-04-08 01:19:21 +00:00
return new LegalityCheck ( Severity . Invalid , "Level is below evolution requirements." ) ;
2016-04-08 00:56:39 +00:00
if ( lvl > pk6 . Met_Level & & lvl > 1 & & lvl ! = 100 & & pk6 . EXP = = PKX . getEXP ( pk6 . Stat_Level , pk6 . Species ) )
return new LegalityCheck ( Severity . Fishy , "Current experience matches level threshold." ) ;
return new LegalityCheck ( Severity . Valid , "Current level is not below met level." ) ;
2016-03-19 05:49:21 +00:00
}
2016-03-20 22:20:11 +00:00
private LegalityCheck verifyRibbons ( )
{
if ( ! Encounter . Valid )
return new LegalityCheck ( Severity . Valid , "Skipped Ribbon check due to other check being invalid." ) ;
List < string > missingRibbons = new List < string > ( ) ;
List < string > invalidRibbons = new List < string > ( ) ;
// Check Event Ribbons
bool [ ] EventRib =
{
pk6 . RIB2_6 , pk6 . RIB2_7 , pk6 . RIB3_0 , pk6 . RIB3_1 , pk6 . RIB3_2 ,
pk6 . RIB3_3 , pk6 . RIB3_4 , pk6 . RIB3_5 , pk6 . RIB3_6 , pk6 . RIB3_7 ,
pk6 . RIB4_0 , pk6 . RIB4_1 , pk6 . RIB4_2 , pk6 . RIB4_3 , pk6 . RIB4_4
} ;
2016-03-23 05:49:46 +00:00
WC6 MatchedWC6 = EncounterMatch as WC6 ;
2016-03-21 15:01:08 +00:00
if ( MatchedWC6 ! = null ) // Wonder Card
2016-03-20 22:20:11 +00:00
{
bool [ ] wc6rib =
{
MatchedWC6 . RIB0_3 , MatchedWC6 . RIB0_4 , MatchedWC6 . RIB0_5 , MatchedWC6 . RIB0_6 , MatchedWC6 . RIB1_5 ,
MatchedWC6 . RIB1_6 , MatchedWC6 . RIB0_7 , MatchedWC6 . RIB1_1 , MatchedWC6 . RIB1_2 , MatchedWC6 . RIB1_3 ,
MatchedWC6 . RIB1_4 , MatchedWC6 . RIB0_0 , MatchedWC6 . RIB0_1 , MatchedWC6 . RIB0_2 , MatchedWC6 . RIB1_0
} ;
for ( int i = 0 ; i < EventRib . Length ; i + + )
if ( EventRib [ i ] ^ wc6rib [ i ] ) // Mismatch
( wc6rib [ i ] ? missingRibbons : invalidRibbons ) . Add ( EventRibName [ i ] ) ;
}
2016-03-28 05:05:51 +00:00
else if ( EncounterType = = typeof ( EncounterLink ) )
2016-03-23 02:47:13 +00:00
{
// No Event Ribbons except Classic (unless otherwise specified, ie not for Demo)
for ( int i = 0 ; i < EventRib . Length ; i + + )
if ( i ! = 4 & & EventRib [ i ] )
invalidRibbons . Add ( EventRibName [ i ] ) ;
if ( EventRib [ 4 ] ^ ( ( EncounterLink ) EncounterMatch ) . Classic )
( EventRib [ 4 ] ? invalidRibbons : missingRibbons ) . Add ( EventRibName [ 4 ] ) ;
}
else // No ribbons
2016-03-20 22:20:11 +00:00
{
for ( int i = 0 ; i < EventRib . Length ; i + + )
2016-03-23 02:47:13 +00:00
if ( EventRib [ i ] )
2016-03-20 22:20:11 +00:00
invalidRibbons . Add ( EventRibName [ i ] ) ;
}
// Unobtainable ribbons for Gen6 Origin
if ( pk6 . RIB0_1 )
invalidRibbons . Add ( "GBA Champion" ) ; // RSE HoF
if ( pk6 . RIB0_2 )
invalidRibbons . Add ( "Sinnoh Champ" ) ; // DPPt HoF
2016-03-22 06:43:03 +00:00
if ( pk6 . RIB2_2 )
2016-03-20 22:20:11 +00:00
invalidRibbons . Add ( "Artist" ) ; // RSE Master Rank Portrait
2016-03-22 06:43:03 +00:00
if ( pk6 . RIB2_4 )
2016-03-20 22:20:11 +00:00
invalidRibbons . Add ( "Record" ) ; // Unobtainable
2016-03-22 06:43:03 +00:00
if ( pk6 . RIB2_5 )
2016-03-20 22:20:11 +00:00
invalidRibbons . Add ( "Legend" ) ; // HGSS Defeat Red @ Mt.Silver
if ( pk6 . Memory_ContestCount > 0 )
invalidRibbons . Add ( "Contest Memory" ) ; // Gen3/4 Contest
if ( pk6 . Memory_BattleCount > 0 )
invalidRibbons . Add ( "Battle Memory" ) ; // Gen3/4 Battle
if ( missingRibbons . Count + invalidRibbons . Count = = 0 )
return new LegalityCheck ( Severity . Valid , "All ribbons accounted for." ) ;
string [ ] result = new string [ 2 ] ;
if ( missingRibbons . Count > 0 )
result [ 0 ] = "Missing Ribbons: " + string . Join ( ", " , missingRibbons ) ;
if ( invalidRibbons . Count > 0 )
result [ 1 ] = "Invalid Ribbons: " + string . Join ( ", " , invalidRibbons ) ;
return new LegalityCheck ( Severity . Invalid , string . Join ( Environment . NewLine , result . Where ( s = > ! string . IsNullOrEmpty ( s ) ) ) ) ;
}
2016-03-21 15:01:08 +00:00
private LegalityCheck verifyAbility ( )
{
int index = Legal . PersonalAO [ pk6 . Species ] . FormeIndex ( pk6 . Species , pk6 . AltForm ) ;
byte [ ] abilities = Legal . PersonalAO [ index ] . Abilities ;
int abilval = Array . IndexOf ( abilities , ( byte ) pk6 . Ability ) ;
if ( abilval < 0 )
2016-03-23 02:47:13 +00:00
return new LegalityCheck ( Severity . Invalid , "Ability is not valid for species/form." ) ;
2016-03-21 15:01:08 +00:00
2016-03-23 02:47:13 +00:00
if ( EncounterMatch ! = null )
{
2016-03-28 05:05:51 +00:00
if ( EncounterType = = typeof ( EncounterStatic ) )
2016-03-23 02:47:13 +00:00
if ( pk6 . AbilityNumber = = 4 ^ ( ( EncounterStatic ) EncounterMatch ) . Ability = = 4 )
return new LegalityCheck ( Severity . Invalid , "Hidden Ability mismatch for static encounter." ) ;
2016-03-28 05:05:51 +00:00
if ( EncounterType = = typeof ( EncounterTrade ) )
2016-03-23 02:47:13 +00:00
if ( pk6 . AbilityNumber = = 4 ^ ( ( EncounterTrade ) EncounterMatch ) . Ability = = 4 )
return new LegalityCheck ( Severity . Invalid , "Hidden Ability mismatch for ingame trade." ) ;
2016-03-31 02:55:27 +00:00
if ( EncounterType = = typeof ( EncounterSlot [ ] ) & & pk6 . AbilityNumber = = 4 )
{
var slots = ( EncounterSlot [ ] ) EncounterMatch ;
bool valid = slots . Any ( slot = > slot . DexNav | |
slot . Type = = SlotType . FriendSafari | |
slot . Type = = SlotType . Horde ) ;
if ( ! valid )
2016-03-23 05:31:30 +00:00
return new LegalityCheck ( Severity . Invalid , "Hidden Ability on non-horde/friend safari wild encounter." ) ;
2016-03-31 02:55:27 +00:00
}
2016-03-23 02:47:13 +00:00
}
2016-03-22 04:50:39 +00:00
2016-03-21 15:01:08 +00:00
return abilities [ pk6 . AbilityNumber > > 1 ] ! = pk6 . Ability
? new LegalityCheck ( Severity . Invalid , "Ability does not match ability number." )
: new LegalityCheck ( Severity . Valid , "Ability matches ability number." ) ;
}
private LegalityCheck verifyBall ( )
{
2016-03-29 05:30:23 +00:00
if ( ! pk6 . Gen6 )
return new LegalityCheck ( ) ;
2016-03-23 02:47:13 +00:00
if ( ! Encounter . Valid )
return new LegalityCheck ( Severity . Valid , "Skipped Ball check due to other check being invalid." ) ;
2016-03-29 05:30:23 +00:00
if ( EncounterType = = typeof ( WC6 ) )
return pk6 . Ball ! = ( ( WC6 ) EncounterMatch ) . Pokéball
2016-03-21 15:01:08 +00:00
? new LegalityCheck ( Severity . Invalid , "Ball does not match specified Wonder Card Ball." )
: new LegalityCheck ( Severity . Valid , "Ball matches Wonder Card." ) ;
2016-03-29 05:30:23 +00:00
if ( EncounterType = = typeof ( EncounterLink ) )
return ( ( EncounterLink ) EncounterMatch ) . Ball ! = pk6 . Ball
? new LegalityCheck ( Severity . Invalid , "Incorrect ball on Link gift." )
: new LegalityCheck ( Severity . Valid , "Correct ball on Link gift." ) ;
if ( EncounterType = = typeof ( EncounterTrade ) )
return pk6 . Ball ! = 4 // Pokeball
? new LegalityCheck ( Severity . Invalid , "Incorrect ball on ingame trade encounter." )
: new LegalityCheck ( Severity . Valid , "Correct ball on ingame trade encounter." ) ;
2016-03-29 05:36:01 +00:00
if ( pk6 . Ball = = 0x04 ) // Poké Ball
return new LegalityCheck ( Severity . Valid , "Standard Poké Ball." ) ;
2016-03-29 05:30:23 +00:00
if ( EncounterType = = typeof ( EncounterStatic ) )
2016-04-21 03:46:18 +00:00
{
EncounterStatic enc = EncounterMatch as EncounterStatic ;
if ( enc . Gift )
return enc . Ball ! = pk6 . Ball // Pokéball by default
? new LegalityCheck ( Severity . Invalid , "Incorrect ball on ingame gift." )
: new LegalityCheck ( Severity . Valid , "Correct ball on ingame gift." ) ;
2016-03-29 05:30:23 +00:00
return ! Legal . WildPokeballs . Contains ( pk6 . Ball )
? new LegalityCheck ( Severity . Invalid , "Incorrect ball on ingame static encounter." )
: new LegalityCheck ( Severity . Valid , "Correct ball on ingame static encounter." ) ;
2016-04-21 03:46:18 +00:00
}
2016-03-29 05:30:23 +00:00
if ( EncounterType = = typeof ( EncounterSlot [ ] ) )
return ! Legal . WildPokeballs . Contains ( pk6 . Ball )
? new LegalityCheck ( Severity . Invalid , "Incorrect ball on ingame encounter." )
: new LegalityCheck ( Severity . Valid , "Correct ball on ingame encounter." ) ;
2016-03-21 15:01:08 +00:00
if ( pk6 . WasEgg )
{
2016-03-27 00:12:09 +00:00
if ( pk6 . Ball = = 0x01 ) // Master Ball
return new LegalityCheck ( Severity . Invalid , "Master Ball on egg origin." ) ;
2016-03-28 05:05:51 +00:00
if ( pk6 . Ball = = 0x10 ) // Cherish Ball
2016-03-27 00:12:09 +00:00
return new LegalityCheck ( Severity . Invalid , "Cherish Ball on non-event." ) ;
if ( pk6 . Gender = = 2 ) // Genderless
return pk6 . Ball ! = 0x04 // Must be Pokéball as ball can only pass via mother (not Ditto!)
? new LegalityCheck ( Severity . Invalid , "Non-Pokéball on genderless egg." )
: new LegalityCheck ( Severity . Valid , "Pokéball on genderless egg." ) ;
if ( Legal . BreedMaleOnly . Contains ( pk6 . Species ) )
return pk6 . Ball ! = 0x04 // Must be Pokéball as ball can only pass via mother (not Ditto!)
? new LegalityCheck ( Severity . Invalid , "Non-Pokéball on Male-Only egg." )
: new LegalityCheck ( Severity . Valid , "Pokéball on Male-Only egg." ) ;
2016-03-28 05:05:51 +00:00
if ( pk6 . Ball = = 0x05 ) // Safari Ball
{
if ( Legal . getLineage ( pk6 ) . All ( e = > ! Legal . Inherit_Safari . Contains ( e ) ) )
return new LegalityCheck ( Severity . Invalid , "Safari Ball not possible for species." ) ;
if ( pk6 . AbilityNumber = = 4 )
return new LegalityCheck ( Severity . Invalid , "Safari Ball with Hidden Ability." ) ;
return new LegalityCheck ( Severity . Valid , "Safari Ball possible for species." ) ;
}
if ( 0x10 < pk6 . Ball & & pk6 . Ball < 0x18 ) // Apricorn Ball
{
if ( Legal . getLineage ( pk6 ) . All ( e = > ! Legal . Inherit_Apricorn . Contains ( e ) ) )
return new LegalityCheck ( Severity . Invalid , "Apricorn Ball not possible for species." ) ;
if ( pk6 . AbilityNumber = = 4 )
return new LegalityCheck ( Severity . Invalid , "Apricorn Ball with Hidden Ability." ) ;
return new LegalityCheck ( Severity . Valid , "Apricorn Ball possible for species." ) ;
}
if ( pk6 . Ball = = 0x18 ) // Sport Ball
{
if ( Legal . getLineage ( pk6 ) . All ( e = > ! Legal . Inherit_Sport . Contains ( e ) ) )
return new LegalityCheck ( Severity . Invalid , "Sport Ball not possible for species." ) ;
if ( pk6 . AbilityNumber = = 4 )
return new LegalityCheck ( Severity . Invalid , "Sport Ball with Hidden Ability." ) ;
return new LegalityCheck ( Severity . Valid , "Sport Ball possible for species." ) ;
}
if ( pk6 . Ball = = 0x19 ) // Dream Ball
{
if ( Legal . getLineage ( pk6 ) . All ( e = > ! Legal . Inherit_Dream . Contains ( e ) ) )
return new LegalityCheck ( Severity . Invalid , "Dream Ball not possible for species." ) ;
return new LegalityCheck ( Severity . Valid , "Dream Ball possible for species." ) ;
}
2016-03-27 03:52:06 +00:00
2016-03-23 02:47:13 +00:00
if ( pk6 . Species > 650 & & pk6 . Species ! = 700 ) // Sylveon
2016-03-21 15:01:08 +00:00
return ! Legal . WildPokeballs . Contains ( pk6 . Ball )
? new LegalityCheck ( Severity . Invalid , "Unobtainable ball for Kalos origin." )
: new LegalityCheck ( Severity . Valid , "Obtainable ball for Kalos origin." ) ;
2016-03-28 05:05:51 +00:00
2016-03-29 05:30:23 +00:00
if ( 0x0D < = pk6 . Ball & & pk6 . Ball < = 0x0F )
{
if ( Legal . Ban_Gen4Ball . Contains ( pk6 . Species ) )
return new LegalityCheck ( Severity . Invalid , "Unobtainable capture for Gen4 Ball." ) ;
2016-03-22 04:31:06 +00:00
2016-03-29 05:30:23 +00:00
return new LegalityCheck ( Severity . Valid , "Obtainable capture for Gen4 Ball." ) ;
}
if ( 0x02 < = pk6 . Ball & & pk6 . Ball < = 0x0C ) // Don't worry, Ball # 0x05 was already checked.
{
if ( Legal . Ban_Gen3Ball . Contains ( pk6 . Species ) )
return new LegalityCheck ( Severity . Invalid , "Unobtainable capture for Gen4 Ball." ) ;
2016-03-23 02:47:13 +00:00
2016-03-29 05:30:23 +00:00
return new LegalityCheck ( Severity . Valid , "Obtainable capture for Gen4 Ball." ) ;
}
}
2016-03-21 15:01:08 +00:00
2016-03-29 05:30:23 +00:00
return new LegalityCheck ( Severity . Invalid , "No ball check satisfied, assuming illegal." ) ;
2016-03-21 15:01:08 +00:00
}
2016-05-06 03:05:22 +00:00
private LegalityCheck verifyHistory ( )
2016-03-22 04:31:06 +00:00
{
2016-03-23 02:47:13 +00:00
if ( ! Encounter . Valid )
return new LegalityCheck ( Severity . Valid , "Skipped Memory check due to other check being invalid." ) ;
2016-03-23 05:49:46 +00:00
WC6 MatchedWC6 = EncounterMatch as WC6 ;
2016-03-22 04:31:06 +00:00
if ( MatchedWC6 ? . OT . Length > 0 ) // Has Event OT -- null propagation yields false if MatchedWC6=null
{
if ( pk6 . OT_Friendship ! = PKX . getBaseFriendship ( pk6 . Species ) )
return new LegalityCheck ( Severity . Invalid , "Event OT Friendship does not match base friendship." ) ;
if ( pk6 . OT_Affection ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Event OT Affection should be zero." ) ;
if ( pk6 . CurrentHandler ! = 1 )
return new LegalityCheck ( Severity . Invalid , "Current handler should not be Event OT." ) ;
2016-05-08 21:29:08 +00:00
if ( pk6 . OT_Memory ! = MatchedWC6 . OT_Memory )
return new LegalityCheck ( Severity . Invalid , "Event " + ( MatchedWC6 . OT_Memory = = 0 ? "should not have an OT Memory" : "OT Memory should be index " + MatchedWC6 . OT_Memory ) + "." ) ;
if ( pk6 . OT_Intensity ! = MatchedWC6 . OT_Intensity )
return new LegalityCheck ( Severity . Invalid , "Event " + ( MatchedWC6 . OT_Intensity = = 0 ? "should not have an OT Memory Intensity value" : "OT Memory Intensity should be index " + MatchedWC6 . OT_Intensity ) + "." ) ;
if ( pk6 . OT_TextVar ! = MatchedWC6 . OT_TextVar )
return new LegalityCheck ( Severity . Invalid , "Event " + ( MatchedWC6 . OT_TextVar = = 0 ? "should not have an OT Memory TextVar value" : "OT Memory TextVar should be index " + MatchedWC6 . OT_TextVar ) + "." ) ;
if ( pk6 . OT_Feeling ! = MatchedWC6 . OT_Feeling )
return new LegalityCheck ( Severity . Invalid , "Event " + ( MatchedWC6 . OT_Feeling = = 0 ? "should not have an OT Memory Feeling value" : "OT Memory Feeling should be index " + MatchedWC6 . OT_Feeling ) + "." ) ;
2016-03-22 04:31:06 +00:00
}
2016-05-09 01:11:31 +00:00
if ( ! pk6 . WasEvent & & ! ( pk6 . WasLink & & ( EncounterMatch as EncounterLink ) ? . OT = = false ) & & ( pk6 . HT_Name . Length = = 0 | | pk6 . Geo1_Country = = 0 ) ) // Is not Traded
2016-03-22 04:31:06 +00:00
{
if ( pk6 . HT_Name . Length ! = 0 )
return new LegalityCheck ( Severity . Invalid , "GeoLocation -- HT Name present but has no previous Country." ) ;
if ( pk6 . Geo1_Country ! = 0 )
return new LegalityCheck ( Severity . Invalid , "GeoLocation -- Previous country of residence but no Handling Trainer." ) ;
if ( pk6 . HT_Memory ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Memory -- Handling Trainer memory present but no Handling Trainer." ) ;
if ( pk6 . CurrentHandler ! = 0 ) // Badly edited; PKHeX doesn't trip this.
return new LegalityCheck ( Severity . Invalid , "Untraded -- Current handler should not be the Handling Trainer." ) ;
if ( pk6 . HT_Friendship ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Untraded -- Handling Trainer Friendship should be zero." ) ;
if ( pk6 . HT_Affection ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Untraded -- Handling Trainer Affection should be zero." ) ;
2016-04-04 04:46:05 +00:00
if ( pk6 . XY & & pk6 . CNTs . Any ( stat = > stat > 0 ) )
return new LegalityCheck ( Severity . Invalid , "Untraded -- Contest stats on XY should be zero." ) ;
2016-03-22 04:31:06 +00:00
// We know it is untraded (HT is empty), if it must be trade evolved flag it.
2016-05-10 15:09:36 +00:00
if ( Legal . getHasTradeEvolved ( pk6 ) & & ( EncounterMatch as EncounterSlot [ ] ) ? . Any ( slot = > slot . Species = = pk6 . Species ) ! = true )
2016-03-22 04:31:06 +00:00
{
if ( pk6 . Species ! = 350 ) // Milotic
return new LegalityCheck ( Severity . Invalid , "Untraded -- requires a trade evolution." ) ;
if ( pk6 . CNT_Beauty < 170 ) // Beauty Contest Stat Requirement
return new LegalityCheck ( Severity . Invalid , "Untraded -- Beauty is not high enough for Levelup Evolution." ) ;
2016-04-23 15:37:05 +00:00
if ( pk6 . CurrentLevel = = 1 )
return new LegalityCheck ( Severity . Invalid , "Untraded -- Beauty is high enough but still Level 1." ) ;
2016-03-22 04:31:06 +00:00
}
}
else // Is Traded
{
if ( pk6 . HT_Memory = = 0 )
return new LegalityCheck ( Severity . Invalid , "Memory -- missing Handling Trainer Memory." ) ;
}
2016-03-31 01:53:34 +00:00
// Memory Checks
if ( pk6 . IsEgg )
{
if ( pk6 . HT_Memory ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Memory -- has Handling Trainer Memory." ) ;
if ( pk6 . OT_Memory ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Memory -- has Original Trainer Memory." ) ;
}
else if ( EncounterType ! = typeof ( WC6 ) )
{
if ( pk6 . OT_Memory = = 0 ^ ! pk6 . Gen6 )
return new LegalityCheck ( Severity . Invalid , "Memory -- missing Original Trainer Memory." ) ;
if ( ! pk6 . Gen6 & & pk6 . OT_Affection ! = 0 )
return new LegalityCheck ( Severity . Invalid , "OT Affection should be zero." ) ;
}
2016-03-22 04:31:06 +00:00
// Unimplemented: Ingame Trade Memories
return new LegalityCheck ( Severity . Valid , "History is valid." ) ;
}
2016-05-07 06:16:35 +00:00
private LegalityCheck verifyCommonMemory ( int handler )
{
int m = 0 ;
2016-05-09 23:09:40 +00:00
int t = 0 ;
2016-05-07 06:16:35 +00:00
string resultPrefix = "" ;
switch ( handler )
{
case 0 :
m = pk6 . OT_Memory ;
2016-05-09 23:09:40 +00:00
t = pk6 . OT_TextVar ;
2016-05-07 06:16:35 +00:00
resultPrefix = "OT " ;
break ;
case 1 :
m = pk6 . HT_Memory ;
2016-05-09 23:09:40 +00:00
t = pk6 . HT_TextVar ;
2016-05-07 06:16:35 +00:00
resultPrefix = "HT " ;
break ;
}
int matchingMoveMemory = Array . IndexOf ( Legal . MoveSpecificMemories [ 0 ] , m ) ;
2016-05-10 02:24:18 +00:00
if ( matchingMoveMemory ! = - 1 & & pk6 . Species ! = 235 & & ! Legal . getCanLearnMachineMove ( pk6 , Legal . MoveSpecificMemories [ 1 ] [ matchingMoveMemory ] ) )
2016-05-07 06:16:35 +00:00
{
return new LegalityCheck ( Severity . Invalid , resultPrefix + "Memory: Species cannot learn this move." ) ;
}
2016-05-09 23:09:40 +00:00
if ( m = = 6 & & ! Legal . LocationsWithPKCenter [ 0 ] . Contains ( t ) )
{
return new LegalityCheck ( Severity . Invalid , resultPrefix + "Memory: Location doesn't have a Pokemon Center." ) ;
}
2016-05-10 01:19:31 +00:00
if ( m = = 21 ) // {0} saw {2} carrying {1} on its back. {4} that {3}.
{
2016-05-10 02:24:18 +00:00
if ( ! Legal . getCanLearnMachineMove ( new PK6 { Species = t , EXP = PKX . getEXP ( 100 , t ) } , 19 ) )
2016-05-10 01:19:31 +00:00
return new LegalityCheck ( Severity . Invalid , resultPrefix + "Memory: Argument Species cannot learn Fly." ) ;
}
2016-05-10 16:06:52 +00:00
if ( ( m = = 16 | | m = = 48 ) & & ( t = = 0 | | ! Legal . getCanKnowMove ( pk6 , t , 1 ) ) )
{
return new LegalityCheck ( Severity . Invalid , resultPrefix + "Memory: Species cannot know this move." ) ;
}
2016-05-11 23:37:51 +00:00
if ( m = = 49 & & ( t = = 0 | | ! Legal . getCanRelearnMove ( pk6 , t , 1 ) ) ) // {0} was able to remember {2} at {1}'s instruction. {4} that {3}.
{
return new LegalityCheck ( Severity . Invalid , resultPrefix + "Memory: Species cannot relearn this move." ) ;
}
2016-05-07 06:16:35 +00:00
return new LegalityCheck ( Severity . Valid , resultPrefix + "Memory is valid." ) ;
}
2016-05-06 03:05:22 +00:00
private LegalityCheck verifyOTMemory ( )
{
if ( ! History . Valid )
return new LegalityCheck ( Severity . Valid , "Skipped OT Memory check as History is not valid." ) ;
if ( EncounterType = = typeof ( EncounterTrade ) )
{
return new LegalityCheck ( Severity . Valid , "OT Memory (Ingame Trade) is valid." ) ;
}
if ( EncounterType = = typeof ( WC6 ) )
{
if ( pk6 . OT_Memory ! = 0 )
return new LegalityCheck ( Severity . Invalid , "Event Pokémon should not have an OT memory." ) ;
return new LegalityCheck ( Severity . Valid , "OT Memory (Event) is valid." ) ;
}
switch ( pk6 . OT_Memory )
{
case 4 : // {0} became {1}’ s friend when it arrived via Link Trade at... {2}. {4} that {3}.
return new LegalityCheck ( Severity . Invalid , "OT Memory: Link Trade is not a valid first memory." ) ;
2016-05-09 23:09:40 +00:00
case 6 : // {0} went to the Pokémon Center in {2} with {1} and had its tired body healed there. {4} that {3}.
int matchingOriginGame = Array . IndexOf ( Legal . LocationsWithPKCenter [ 0 ] , pk6 . OT_TextVar ) ;
2016-05-10 00:51:35 +00:00
if ( matchingOriginGame ! = - 1 )
{
int gameID = Legal . LocationsWithPKCenter [ 1 ] [ matchingOriginGame ] ;
if ( pk6 . XY & & gameID ! = 0 | | pk6 . AO & & gameID ! = 1 )
2016-05-09 23:09:40 +00:00
return new LegalityCheck ( Severity . Invalid , "OT Memory: Location doesn't exist on Origin Game region." ) ;
2016-05-10 00:51:35 +00:00
}
2016-05-09 23:09:40 +00:00
return verifyCommonMemory ( 0 ) ;
2016-05-06 03:35:18 +00:00
case 14 :
if ( ! Legal . getCanBeCaptured ( pk6 . OT_TextVar , pk6 . Version ) )
return new LegalityCheck ( Severity . Invalid , "OT Memory: Captured Species can not be captured in game." ) ;
return new LegalityCheck ( Severity . Valid , "OT Memory: Captured Species can be captured in game." ) ;
2016-05-06 03:05:22 +00:00
}
if ( pk6 . XY & & Legal . Memory_NotXY . Contains ( pk6 . OT_Memory ) )
return new LegalityCheck ( Severity . Invalid , "OT Memory: OR/AS exclusive memory on X/Y origin." ) ;
if ( pk6 . AO & & Legal . Memory_NotAO . Contains ( pk6 . OT_Memory ) )
return new LegalityCheck ( Severity . Invalid , "OT Memory: X/Y exclusive memory on OR/AS origin." ) ;
2016-05-07 06:16:35 +00:00
return verifyCommonMemory ( 0 ) ;
2016-05-06 03:05:22 +00:00
}
private LegalityCheck verifyHTMemory ( )
{
if ( ! History . Valid )
return new LegalityCheck ( Severity . Valid , "Skipped OT Memory check as History is not valid." ) ;
switch ( pk6 . HT_Memory )
{
case 1 : // {0} met {1} at... {2}. {1} threw a Poké Ball at it, and they started to travel together. {4} that {3}.
return new LegalityCheck ( Severity . Invalid , "HT Memory: Handling Trainer did not capture this." ) ;
case 2 : // {0} hatched from an Egg and saw {1} for the first time at... {2}. {4} that {3}.
return new LegalityCheck ( Severity . Invalid , "HT Memory: Handling Trainer did not hatch this." ) ;
2016-05-06 03:35:18 +00:00
case 14 :
if ( ! Legal . getCanBeCaptured ( pk6 . HT_TextVar ) )
return new LegalityCheck ( Severity . Invalid , "HT Memory: Captured Species can not be captured in game." ) ;
return new LegalityCheck ( Severity . Valid , "HT Memory: Captured Species can be captured in game." ) ;
2016-05-06 03:05:22 +00:00
}
2016-05-07 06:16:35 +00:00
return verifyCommonMemory ( 1 ) ;
2016-05-06 03:05:22 +00:00
}
2016-05-11 23:20:31 +00:00
private LegalityCheck verifyRegion ( )
{
2016-05-12 04:18:05 +00:00
bool valid = false ;
2016-05-11 23:20:31 +00:00
switch ( pk6 . ConsoleRegion )
{
2016-05-12 04:18:05 +00:00
case 0 : // Japan
valid = pk6 . Country = = 1 ;
2016-05-11 23:20:31 +00:00
break ;
2016-05-12 04:18:05 +00:00
case 1 : // Americas
valid = 8 < = pk6 . Country & & pk6 . Country < = 52 | | new [ ] { 153 , 156 , 168 , 174 , 186 } . Contains ( pk6 . Country ) ;
2016-05-11 23:20:31 +00:00
break ;
2016-05-12 04:18:05 +00:00
case 2 : // Europe
valid = 64 < = pk6 . Country & & pk6 . Country < = 127 | | new [ ] { 169 , 184 , 185 } . Contains ( pk6 . Country ) ;
2016-05-11 23:20:31 +00:00
break ;
2016-05-12 04:18:05 +00:00
case 4 : // China
valid = pk6 . Country = = 144 | | pk6 . Country = = 160 ;
2016-05-11 23:20:31 +00:00
break ;
2016-05-12 04:18:05 +00:00
case 5 : // Korea
valid = pk6 . Country = = 136 ;
2016-05-11 23:20:31 +00:00
break ;
2016-05-12 04:18:05 +00:00
case 6 : // Taiwan
valid = pk6 . Country = = 128 ;
2016-05-11 23:20:31 +00:00
break ;
}
2016-05-12 04:18:05 +00:00
return ! valid
? new LegalityCheck ( Severity . Invalid , "Geolocation: Country is not in 3DS region." )
: new LegalityCheck ( Severity . Valid , "Geolocation: Country is in 3DS region." ) ;
2016-05-11 23:20:31 +00:00
}
2016-04-14 10:17:03 +00:00
private LegalityCheck verifyForm ( )
{
if ( ! Encounter . Valid )
return new LegalityCheck ( Severity . Valid , "Skipped Form check due to other check being invalid." ) ;
switch ( pk6 . Species )
{
2016-04-23 21:16:12 +00:00
case 25 :
if ( pk6 . AltForm ! = 0 ^ EncounterType = = typeof ( EncounterStatic ) )
return EncounterType = = typeof ( EncounterStatic )
? new LegalityCheck ( Severity . Invalid , "Cosplay Pikachu cannot have the default form." )
: new LegalityCheck ( Severity . Invalid , "Only Cosplay Pikachu can have this form." ) ;
break ;
2016-04-14 10:17:03 +00:00
case 664 :
case 665 :
if ( pk6 . AltForm > 17 ) // Fancy & Pokéball
return new LegalityCheck ( Severity . Invalid , "Event Vivillon pattern on pre-evolution." ) ;
break ;
case 666 :
if ( pk6 . AltForm > 17 ) // Fancy & Pokéball
return EncounterType ! = typeof ( WC6 )
? new LegalityCheck ( Severity . Invalid , "Invalid Vivillon pattern." )
: new LegalityCheck ( Severity . Valid , "Valid Vivillon pattern." ) ;
break ;
case 670 :
if ( pk6 . AltForm = = 5 ) // Eternal Flower
return EncounterType ! = typeof ( WC6 )
? new LegalityCheck ( Severity . Invalid , "Invalid Eternal Flower encounter." )
: new LegalityCheck ( Severity . Valid , "Valid Eternal Flower encounter." ) ;
break ;
}
return pk6 . AltForm > 0 & & ( Legal . BattleForms . Contains ( pk6 . Species ) | | Legal . BattleMegas . Contains ( pk6 . Species ) )
? new LegalityCheck ( Severity . Invalid , "Form cannot exist outside of a battle." )
: new LegalityCheck ( ) ;
}
2016-04-22 02:32:22 +00:00
private LegalityCheck verifyMisc ( )
{
if ( pk6 . Gen6 & & Encounter . Valid & & EncounterType = = typeof ( WC6 ) ^ pk6 . FatefulEncounter )
{
if ( EncounterType = = typeof ( EncounterStatic ) & & pk6 . Species = = 386 ) // Deoxys Matched @ Sky Pillar
return new LegalityCheck ( ) ;
2016-04-23 03:08:02 +00:00
return new LegalityCheck ( Severity . Invalid , "Fateful Encounter should " + ( pk6 . FatefulEncounter ? "not " : "" ) + "be checked." ) ;
2016-04-22 02:32:22 +00:00
}
return new LegalityCheck ( ) ;
}
2016-03-14 03:19:04 +00:00
private LegalityCheck [ ] verifyMoves ( )
2016-03-12 17:16:41 +00:00
{
int [ ] Moves = pk6 . Moves ;
LegalityCheck [ ] res = new LegalityCheck [ 4 ] ;
for ( int i = 0 ; i < 4 ; i + + )
res [ i ] = new LegalityCheck ( ) ;
if ( ! pk6 . Gen6 )
return res ;
var validMoves = Legal . getValidMoves ( pk6 ) . ToArray ( ) ;
if ( pk6 . Species = = 235 )
{
for ( int i = 0 ; i < 4 ; i + + )
res [ i ] = Legal . InvalidSketch . Contains ( Moves [ i ] )
? new LegalityCheck ( Severity . Invalid , "Invalid Sketch move." )
: new LegalityCheck ( ) ;
}
2016-04-16 18:35:16 +00:00
else if ( CardMatch ? . Count > 1 ) // Multiple possible WC6 matched
{
int [ ] RelearnMoves = pk6 . RelearnMoves ;
foreach ( var wc in CardMatch )
{
for ( int i = 0 ; i < 4 ; i + + )
{
if ( Moves [ i ] = = Legal . Struggle )
res [ i ] = new LegalityCheck ( Severity . Invalid , "Invalid Move: Struggle." ) ;
else if ( validMoves . Contains ( Moves [ i ] ) )
2016-04-16 19:01:09 +00:00
res [ i ] = new LegalityCheck ( Severity . Valid , Moves [ i ] = = 0 ? "Empty" : "Level-up." ) ;
2016-04-16 18:35:16 +00:00
else if ( RelearnMoves . Contains ( Moves [ i ] ) )
2016-04-16 19:01:09 +00:00
res [ i ] = new LegalityCheck ( Severity . Valid , Moves [ i ] = = 0 ? "Empty" : "Relearn Move." ) { Flag = true } ;
2016-04-16 18:35:16 +00:00
else if ( wc . Moves . Contains ( Moves [ i ] ) )
res [ i ] = new LegalityCheck ( Severity . Valid , "Wonder Card Non-Relearn Move." ) ;
else
res [ i ] = new LegalityCheck ( Severity . Invalid , "Invalid Move." ) ;
}
if ( res . All ( r = > r . Valid ) ) // Card matched
2016-04-16 19:01:09 +00:00
{ EncounterMatch = wc ; RelearnBase = wc . RelearnMoves ; }
2016-04-16 18:35:16 +00:00
}
}
2016-03-12 17:16:41 +00:00
else
{
int [ ] RelearnMoves = pk6 . RelearnMoves ;
2016-03-23 05:49:46 +00:00
WC6 MatchedWC6 = EncounterMatch as WC6 ;
2016-03-14 03:19:04 +00:00
int [ ] WC6Moves = MatchedWC6 ? . Moves ? ? new int [ 0 ] ;
2016-03-12 17:16:41 +00:00
for ( int i = 0 ; i < 4 ; i + + )
{
if ( Moves [ i ] = = Legal . Struggle )
res [ i ] = new LegalityCheck ( Severity . Invalid , "Invalid Move: Struggle." ) ;
else if ( validMoves . Contains ( Moves [ i ] ) )
2016-04-16 19:01:09 +00:00
res [ i ] = new LegalityCheck ( Severity . Valid , Moves [ i ] = = 0 ? "Empty" : "Level-up." ) ;
2016-03-12 17:16:41 +00:00
else if ( RelearnMoves . Contains ( Moves [ i ] ) )
2016-04-16 19:01:09 +00:00
res [ i ] = new LegalityCheck ( Severity . Valid , Moves [ i ] = = 0 ? "Empty" : "Relearn Move." ) { Flag = true } ;
2016-03-14 03:19:04 +00:00
else if ( WC6Moves . Contains ( Moves [ i ] ) )
2016-03-21 15:01:08 +00:00
res [ i ] = new LegalityCheck ( Severity . Valid , "Wonder Card Non-Relearn Move." ) ;
2016-03-12 17:16:41 +00:00
else
res [ i ] = new LegalityCheck ( Severity . Invalid , "Invalid Move." ) ;
}
}
if ( Moves [ 0 ] = = 0 )
res [ 0 ] = new LegalityCheck ( Severity . Invalid , "Invalid Move." ) ;
2016-03-15 06:54:13 +00:00
if ( pk6 . Species = = 647 ) // Keldeo
2016-03-19 14:53:55 +00:00
if ( pk6 . AltForm = = 1 ^ pk6 . Moves . Contains ( 548 ) )
res [ 0 ] = new LegalityCheck ( Severity . Invalid , "Secret Sword / Resolute Keldeo Mismatch." ) ;
2016-03-15 06:54:13 +00:00
2016-03-15 06:26:51 +00:00
// Duplicate Moves Check
for ( int i = 0 ; i < 4 ; i + + )
if ( Moves . Count ( m = > m ! = 0 & & m = = Moves [ i ] ) > 1 )
res [ i ] = new LegalityCheck ( Severity . Invalid , "Duplicate Move." ) ;
2016-03-12 17:16:41 +00:00
return res ;
}
2016-03-14 03:19:04 +00:00
private LegalityCheck [ ] verifyRelearn ( )
2016-03-12 17:16:41 +00:00
{
2016-03-29 05:30:23 +00:00
RelearnBase = null ;
2016-03-12 17:16:41 +00:00
LegalityCheck [ ] res = new LegalityCheck [ 4 ] ;
2016-03-23 02:47:13 +00:00
2016-03-12 17:16:41 +00:00
int [ ] Moves = pk6 . RelearnMoves ;
if ( ! pk6 . Gen6 )
goto noRelearn ;
if ( pk6 . WasLink )
{
2016-03-23 05:49:46 +00:00
var Link = Legal . getValidLinkGifts ( pk6 ) ;
if ( Link = = null )
2016-03-23 02:47:13 +00:00
{
for ( int i = 0 ; i < 4 ; i + + )
res [ i ] = new LegalityCheck ( ) ;
return res ;
}
2016-03-23 05:49:46 +00:00
EncounterMatch = Link ;
2016-03-23 02:47:13 +00:00
int [ ] moves = ( ( EncounterLink ) EncounterMatch ) . RelearnMoves ;
2016-03-25 07:10:11 +00:00
RelearnBase = moves ;
2016-03-12 17:16:41 +00:00
for ( int i = 0 ; i < 4 ; i + + )
res [ i ] = moves [ i ] ! = Moves [ i ]
2016-04-07 01:13:43 +00:00
? new LegalityCheck ( Severity . Invalid , $"Expected: {movelist[moves[i]]}." )
2016-03-12 17:16:41 +00:00
: new LegalityCheck ( ) ;
return res ;
}
if ( pk6 . WasEvent | | pk6 . WasEventEgg )
{
// Get WC6's that match
2016-04-16 18:35:16 +00:00
CardMatch = new List < WC6 > ( Legal . getValidWC6s ( pk6 ) ) ;
2016-04-30 21:23:56 +00:00
foreach ( var wc in CardMatch . ToArray ( ) )
2016-03-12 17:16:41 +00:00
{
int [ ] moves = wc . RelearnMoves ;
for ( int i = 0 ; i < 4 ; i + + )
res [ i ] = moves [ i ] ! = Moves [ i ]
2016-04-07 01:13:43 +00:00
? new LegalityCheck ( Severity . Invalid , $"Expected ID: {movelist[moves[i]]}." )
2016-03-12 17:16:41 +00:00
: new LegalityCheck ( Severity . Valid , $"Matched WC #{wc.CardID.ToString(" 0000 ")}" ) ;
2016-04-16 18:35:16 +00:00
if ( res . Any ( r = > ! r . Valid ) )
CardMatch . Remove ( wc ) ;
2016-03-12 17:16:41 +00:00
}
2016-04-16 18:35:16 +00:00
if ( CardMatch . Count > 1 )
return res ;
if ( CardMatch . Count = = 1 )
2016-04-19 13:37:40 +00:00
{ EncounterMatch = CardMatch [ 0 ] ; RelearnBase = CardMatch [ 0 ] . RelearnMoves ; return res ; }
2016-04-16 18:35:16 +00:00
2016-03-28 05:05:51 +00:00
EncounterMatch = EncounterType = null ;
2016-03-12 17:16:41 +00:00
goto noRelearn ; // No WC match
}
if ( pk6 . WasEgg )
{
const int games = 2 ;
bool checkAllGames = pk6 . WasTradedEgg ;
bool splitBreed = Legal . SplitBreed . Contains ( pk6 . Species ) ;
int iterate = ( checkAllGames ? games : 1 ) * ( splitBreed ? 2 : 1 ) ;
for ( int i = 0 ; i < iterate ; i + + )
{
int gameSource = ! checkAllGames ? - 1 : i % iterate / ( splitBreed ? 2 : 1 ) ;
int skipOption = splitBreed & & iterate / 2 < = i ? 1 : 0 ;
2016-03-12 22:07:57 +00:00
// Obtain level1 moves
2016-03-12 18:35:17 +00:00
List < int > baseMoves = new List < int > ( Legal . getBaseEggMoves ( pk6 , skipOption , gameSource ) ) ;
int baseCt = baseMoves . Count ;
if ( baseCt > 4 ) baseCt = 4 ;
2016-03-12 22:07:57 +00:00
2016-03-12 17:16:41 +00:00
// Obtain Nonstandard moves
2016-03-12 22:07:57 +00:00
var relearnMoves = Legal . getValidRelearn ( pk6 , skipOption ) . ToArray ( ) ;
var relearn = pk6 . RelearnMoves . Where ( move = > move ! = 0
& & ( ! baseMoves . Contains ( move ) | | relearnMoves . Contains ( move ) )
) . ToArray ( ) ;
2016-03-12 17:16:41 +00:00
int relearnCt = relearn . Length ;
2016-03-12 22:07:57 +00:00
2016-03-12 18:35:17 +00:00
// Get Move Window
List < int > window = new List < int > ( baseMoves ) ;
window . AddRange ( relearn ) ;
int [ ] moves = window . Skip ( baseCt + relearnCt - 4 ) . Take ( 4 ) . ToArray ( ) ;
2016-03-12 17:16:41 +00:00
Array . Resize ( ref moves , 4 ) ;
2016-03-12 18:35:17 +00:00
int req ;
if ( relearnCt = = 4 )
req = 0 ;
else if ( baseCt + relearnCt > 4 )
req = 4 - relearnCt ;
else
req = baseCt ;
2016-03-12 17:16:41 +00:00
// Movepool finalized! Check validity.
int [ ] rl = pk6 . RelearnMoves ;
2016-04-07 01:13:43 +00:00
string em = string . Join ( ", " , baseMoves . Select ( r = > r > = movelist . Length ? "ERROR" : movelist [ r ] ) ) ;
2016-03-25 07:10:11 +00:00
RelearnBase = baseMoves . ToArray ( ) ;
2016-03-12 17:16:41 +00:00
// Base Egg Move
for ( int j = 0 ; j < req ; j + + )
2016-04-07 01:13:43 +00:00
{
if ( baseMoves . Contains ( rl [ j ] ) )
res [ j ] = new LegalityCheck ( Severity . Valid , "Base egg move." ) ;
else
{
res [ j ] = new LegalityCheck ( Severity . Invalid , "Base egg move missing." ) ;
for ( int f = j + 1 ; f < req ; f + + )
res [ f ] = new LegalityCheck ( Severity . Invalid , "Base egg move missing." ) ;
res [ req - 1 ] . Comment + = $"{Environment.NewLine}Expected the following Relearn Moves: {em}." ;
break ;
}
}
2016-03-12 17:16:41 +00:00
// Non-Base
2016-03-12 22:07:57 +00:00
if ( Legal . LightBall . Contains ( pk6 . Species ) )
relearnMoves = relearnMoves . Concat ( new [ ] { 344 } ) . ToArray ( ) ;
2016-03-12 17:16:41 +00:00
for ( int j = req ; j < 4 ; j + + )
res [ j ] = ! relearnMoves . Contains ( rl [ j ] )
? new LegalityCheck ( Severity . Invalid , "Not an expected relearn move." )
2016-04-16 19:01:09 +00:00
: new LegalityCheck ( Severity . Valid , rl [ j ] = = 0 ? "Empty" : "Relearn move." ) ;
2016-03-12 17:16:41 +00:00
if ( res . All ( r = > r . Valid ) )
break ;
}
return res ;
}
if ( Moves [ 0 ] ! = 0 ) // DexNav only?
{
// Check DexNav
if ( ! Legal . getDexNavValid ( pk6 ) )
goto noRelearn ;
res [ 0 ] = ! Legal . getValidRelearn ( pk6 , 0 ) . Contains ( Moves [ 0 ] )
? new LegalityCheck ( Severity . Invalid , "Not an expected DexNav move." )
: new LegalityCheck ( ) ;
for ( int i = 1 ; i < 4 ; i + + )
res [ i ] = Moves [ i ] ! = 0
? new LegalityCheck ( Severity . Invalid , "Expected no Relearn Move in slot." )
: new LegalityCheck ( ) ;
2016-03-25 07:10:11 +00:00
if ( res [ 0 ] . Valid )
RelearnBase = new [ ] { Moves [ 0 ] , 0 , 0 , 0 } ;
2016-03-12 17:16:41 +00:00
return res ;
}
// Should have no relearn moves.
noRelearn :
for ( int i = 0 ; i < 4 ; i + + )
res [ i ] = Moves [ i ] ! = 0
? new LegalityCheck ( Severity . Invalid , "Expected no Relearn Moves." )
: new LegalityCheck ( ) ;
return res ;
}
2016-03-23 02:47:13 +00:00
2016-04-07 01:13:43 +00:00
internal static string [ ] movelist = Util . getStringList ( "moves" , "en" ) ;
2016-03-26 03:39:31 +00:00
private static readonly string [ ] EventRibName =
2016-03-23 02:47:13 +00:00
{
"Country" , "National" , "Earth" , "World" , "Classic" ,
"Premier" , "Event" , "Birthday" , "Special" , "Souvenir" ,
"Wishing" , "Battle Champ" , "Regional Champ" , "National Champ" , "World Champ"
} ;
2016-03-11 04:36:32 +00:00
}
}