PKHeX’s legality checking system validates whether a Pokémon could legitimately exist in the games. It analyzes hundreds of data points including encounter data, moves, abilities, IVs, ribbons, and more to determine if a Pokémon is legal.
The LegalityAnalysis class is the entry point for all legality checks. It orchestrates the entire validation process:
using PKHeX.Core;// Load a Pokémon filevar pk = PKMConverter.GetPKMfromBytes(File.ReadAllBytes("pokemon.pk9"));// Perform legality analysisvar analysis = new LegalityAnalysis(pk);// Check if the Pokémon is legalif (analysis.Valid){ Console.WriteLine("This Pokémon is legal!");}else{ Console.WriteLine("This Pokémon has legality issues.");}
Each validation produces a CheckResult containing:
Judgement - Severity level (Valid, Fishy, or Invalid)
Identifier - Which property was checked (Ability, Moves, IVs, etc.)
Result - Specific result code (AbilityMismatch, MovePPTooHigh, etc.)
Value - Optional numeric argument for detailed messages
var analysis = new LegalityAnalysis(pk);// Access all check resultsforeach (var result in analysis.Results){ Console.WriteLine($"{result.Identifier}: {result.Judgement}"); Console.WriteLine($" Code: {result.Result}"); Console.WriteLine($" Valid: {result.Valid}");}
The system attempts to match the Pokémon to a possible encounter:
var analysis = new LegalityAnalysis(pk);// Get the matched encountervar encounter = analysis.EncounterMatch;Console.WriteLine($"Encounter Type: {encounter.GetType().Name}");Console.WriteLine($"Species: {encounter.Species}");Console.WriteLine($"Level: {encounter.LevelMin}-{encounter.LevelMax}");Console.WriteLine($"Location: {encounter.Location}");// For Gen1/2 transfers, there may be an original encounterif (analysis.EncounterOriginal != analysis.EncounterMatch){ Console.WriteLine($"Original: {analysis.EncounterOriginal.GetType().Name}");}
var analysis = new LegalityAnalysis(pk);// Parsed: All checks completed without errorsif (analysis.Parsed){ Console.WriteLine("Analysis completed successfully");}// Valid: All checks returned Valid severityif (analysis.Valid){ Console.WriteLine("Pokémon is completely legal");}// A Pokémon can be parsed but not validif (analysis.Parsed && !analysis.Valid){ Console.WriteLine("Analysis completed, but found legality issues");}
If Parsed is false, an error occurred during analysis. The Valid property is only meaningful when Parsed is true.
You can provide save file context for more accurate validation:
using PKHeX.Core;// Load save filevar sav = SaveUtil.GetVariantSAV(File.ReadAllBytes("save.sav"));if (sav == null) return;// Load Pokémonvar pk = sav.GetBoxSlotAtIndex(0, 0);// Use save file's personal table for accurate form datavar analysis = new LegalityAnalysis(pk, sav.Personal, StorageSlotType.Box);// The third parameter indicates where the Pokémon came from// This helps validate certain restrictions
Different generations have different validation rules:
var analysis = new LegalityAnalysis(pk);var info = analysis.Info;Console.WriteLine($"Generation: {info.Generation}");Console.WriteLine($"Context: {pk.Context}");// The system automatically applies generation-specific rulesswitch (pk.Generation){ case 1: case 2: // Gen 1/2: Checks catch rate, DVs, no abilities break; case 3: // Gen 3: PID-based ability, gender, shininess break; case 4: case 5: // Gen 4/5: Transition to new ability system break; case 6: case 7: case 8: case 9: // Modern gens: Full ability numbers, memories, etc. break;}
The LegalityCheckResultCode enum contains over 400 specific result codes:
var analysis = new LegalityAnalysis(pk);foreach (var result in analysis.Results){ switch (result.Result) { case LegalityCheckResultCode.Valid: // Generic valid result break; case LegalityCheckResultCode.AbilityMismatch: // Ability doesn't match encounter break; case LegalityCheckResultCode.MovePPTooHigh_01: // Move has too many PP Ups break; case LegalityCheckResultCode.IVFlawlessCountGEQ_0: // Minimum flawless IV count not met break; // ... and many more }}