Overview
ThePKM class is the abstract base class representing individual Pokémon data structures. Each generation has specific implementations (PK1, PK2, PK3, etc.) that inherit from PKM and implement generation-specific features.
Core Architecture
Memory-Based Design
PKM uses a memory buffer to store raw Pokémon data:protected readonly Memory<byte> Raw;
public Span<byte> Data => Raw.Span;
Entity Context
Every PKM has a context that determines its format and rules:public abstract EntityContext Context { get; }
public byte Format => Context.Generation;
Basic Properties
Species and Forms
PKM pokemon = GetPokemon();
// Species information
ushort species = pokemon.Species; // National Dex number
byte form = pokemon.Form; // Alternate form index
PersonalInfo info = pokemon.PersonalInfo; // Base stats and info
// Nickname
string nickname = pokemon.Nickname;
bool isNicknamed = pokemon.IsNicknamed;
Trainer Information
// Original Trainer
string ot = pokemon.OriginalTrainerName;
byte otGender = pokemon.OriginalTrainerGender;
// Trainer IDs
uint tid = pokemon.DisplayTID; // Visible TID
uint sid = pokemon.DisplaySID; // Visible SID
uint id32 = pokemon.ID32; // Combined 32-bit ID
// Handler information (Gen 6+)
string htName = pokemon.HandlingTrainerName;
byte htGender = pokemon.HandlingTrainerGender;
Battle Stats
// Level and experience
byte level = pokemon.CurrentLevel;
uint exp = pokemon.EXP;
// Nature
Nature nature = pokemon.Nature; // Affects stat growth
Nature statNature = pokemon.StatNature; // Gen 8+ mints
// Ability
int ability = pokemon.Ability;
int abilityNumber = pokemon.AbilityNumber; // Which ability slot (0/1/2)
// Gender
byte gender = pokemon.Gender; // 0=Male, 1=Female, 2=Genderless
Stats and Training
Individual Values (IVs)
// Access individual IVs
int hpIV = pokemon.IV_HP;
int atkIV = pokemon.IV_ATK;
int defIV = pokemon.IV_DEF;
int speIV = pokemon.IV_SPE;
int spaIV = pokemon.IV_SPA;
int spdIV = pokemon.IV_SPD;
// Get all IVs at once
Span<int> ivs = stackalloc int[6];
pokemon.GetIVs(ivs);
// Set all IVs
ReadOnlySpan<int> newIVs = stackalloc int[] { 31, 31, 31, 31, 31, 31 };
pokemon.SetIVs(newIVs);
// IV statistics
int totalIVs = pokemon.IVTotal;
int maxIV = pokemon.MaximumIV;
int flawlessCount = pokemon.FlawlessIVCount;
// Set random IVs with guaranteed perfect stats
pokemon.SetRandomIVs(minFlawless: 3); // 3 guaranteed 31 IVs
Effort Values (EVs)
// Access individual EVs
int hpEV = pokemon.EV_HP;
int atkEV = pokemon.EV_ATK;
int defEV = pokemon.EV_DEF;
int speEV = pokemon.EV_SPE;
int spaEV = pokemon.EV_SPA;
int spdEV = pokemon.EV_SPD;
// Get/Set all EVs
Span<int> evs = stackalloc int[6];
pokemon.GetEVs(evs);
ReadOnlySpan<int> newEVs = stackalloc int[] { 252, 252, 0, 4, 0, 0 };
pokemon.SetEVs(newEVs);
// EV total
int totalEVs = pokemon.EVTotal; // Max 510
Calculated Stats
// Battle stats (calculated from IVs, EVs, nature)
int currentHP = pokemon.Stat_HPCurrent;
int maxHP = pokemon.Stat_HPMax;
int atk = pokemon.Stat_ATK;
int def = pokemon.Stat_DEF;
int spa = pokemon.Stat_SPA;
int spd = pokemon.Stat_SPD;
int spe = pokemon.Stat_SPE;
// Get all stats at once
int[] stats = pokemon.Stats;
// Recalculate stats
pokemon.ResetPartyStats();
// Heal to full HP and fix status
pokemon.Heal();
Moves and Attacks
Current Moves
// Individual move access
ushort move1 = pokemon.Move1;
ushort move2 = pokemon.Move2;
ushort move3 = pokemon.Move3;
ushort move4 = pokemon.Move4;
// PP (Power Points)
int move1PP = pokemon.Move1_PP;
int move1PPUps = pokemon.Move1_PPUps;
// Get all moves
ushort[] moves = pokemon.Moves;
// Set moves
ReadOnlySpan<ushort> newMoves = stackalloc ushort[] { 1, 2, 3, 4 };
pokemon.SetMoves(newMoves);
// Move utilities
bool hasMove = pokemon.HasMove(25); // Has Thunder Shock?
int moveIndex = pokemon.GetMoveIndex(25);
int moveCount = pokemon.MoveCount;
// Add a move
bool added = pokemon.AddMove(25, pushOut: true);
// Fix move ordering and PP
pokemon.FixMoves();
// Heal PP to maximum
pokemon.HealPP();
Relearn Moves (Gen 6+)
// Individual relearn moves
ushort relearn1 = pokemon.RelearnMove1;
ushort relearn2 = pokemon.RelearnMove2;
ushort relearn3 = pokemon.RelearnMove3;
ushort relearn4 = pokemon.RelearnMove4;
// Get all relearn moves
ushort[] relearnMoves = pokemon.RelearnMoves;
// Set relearn moves
ReadOnlySpan<ushort> newRelearnMoves = stackalloc ushort[] { 1, 2, 0, 0 };
pokemon.SetRelearnMoves(newRelearnMoves);
// Check if has relearn move
bool hasRelearn = pokemon.HasRelearnMove(1);
Identification
Unique Identifiers
// PID (Personality Value)
uint pid = pokemon.PID;
// Encryption Constant (Gen 6+)
uint ec = pokemon.EncryptionConstant;
// Shiny calculation
uint tsv = pokemon.TSV; // Trainer Shiny Value
uint psv = pokemon.PSV; // Pokémon Shiny Value
bool isShiny = pokemon.IsShiny;
ushort shinyXor = pokemon.ShinyXor;
// Make shiny
pokemon.SetShiny();
// Set specific shiny type
pokemon.SetShinySID(Shiny.AlwaysSquare);
Characteristic
// IV Judge characteristic
int characteristic = pokemon.Characteristic;
int potentialRating = pokemon.PotentialRating; // 0-3 (worst to best)
Origin Information
Game Version
// Origin game
GameVersion version = pokemon.Version;
// Generation shortcuts
byte generation = pokemon.Generation;
bool isGen8 = pokemon.Gen8;
bool isSwSh = pokemon.SWSH;
bool isBDSP = pokemon.BDSP;
bool isSV = pokemon.SV;
// Virtual Console
bool isVC = pokemon.VC;
bool isVC1 = pokemon.VC1; // Gen 1 VC
bool isVC2 = pokemon.VC2; // Gen 2 VC
Met Information
// Met location
ushort metLocation = pokemon.MetLocation;
byte metLevel = pokemon.MetLevel;
// Met date (Gen 4+)
DateOnly? metDate = pokemon.MetDate;
if (metDate.HasValue)
{
Console.WriteLine($"Met on {metDate.Value}");
}
// Set met date
pokemon.MetDate = new DateOnly(2024, 1, 15);
// Individual date components
byte metYear = pokemon.MetYear; // Years since 2000
byte metMonth = pokemon.MetMonth;
byte metDay = pokemon.MetDay;
Egg Information
// Egg status
bool isEgg = pokemon.IsEgg;
bool wasEgg = pokemon.WasEgg;
// Egg location
ushort eggLocation = pokemon.EggLocation;
bool wasTradedEgg = pokemon.WasTradedEgg;
bool isTradedEgg = pokemon.IsTradedEgg;
// Egg met date
DateOnly? eggMetDate = pokemon.EggMetDate;
pokemon.EggMetDate = new DateOnly(2024, 1, 1);
Special Attributes
Ball and Item
// Poké Ball
byte ball = pokemon.Ball;
// Held item
int heldItem = pokemon.HeldItem;
bool canHold = pokemon.CanHoldItem(legalItems);
Friendship and Affection
// Current friendship
byte friendship = pokemon.CurrentFriendship;
// Original friendship
byte otFriendship = pokemon.OriginalTrainerFriendship;
// Handler friendship (Gen 6+)
byte htFriendship = pokemon.HandlingTrainerFriendship;
Language
int language = pokemon.Language;
bool isJapanese = pokemon.Japanese;
bool isKorean = pokemon.Korean;
Fateful Encounter
bool isFateful = pokemon.FatefulEncounter;
Pokérus
// Pokérus status
int strain = pokemon.PokerusStrain;
int days = pokemon.PokerusDays;
bool isInfected = pokemon.IsPokerusInfected;
bool isCured = pokemon.IsPokerusCured;
// Infect with Pokérus
pokemon.IsPokerusInfected = true;
// Cure Pokérus
pokemon.IsPokerusCured = true;
Hidden Power
// Hidden Power type (based on IVs)
int hpType = pokemon.HPType; // 0-15 (type index)
int hpPower = pokemon.HPPower; // Base power
// Set Hidden Power type (adjusts IVs)
pokemon.HPType = 1; // Fighting
Data Export and Cloning
File Operations
// File name
string fileName = pokemon.FileName; // "025 - Pikachu - 123456.pk8"
string fileNameNoExt = pokemon.FileNameWithoutExtension;
string extension = pokemon.Extension; // "pk8"
// Export formats
byte[] encryptedBoxData = pokemon.EncryptedBoxData;
byte[] encryptedPartyData = pokemon.EncryptedPartyData;
byte[] decryptedBoxData = pokemon.DecryptedBoxData;
byte[] decryptedPartyData = pokemon.DecryptedPartyData;
Cloning
// Deep clone a Pokémon
PKM clone = pokemon.Clone();
// Clone maintains all properties but is a separate instance
clone.Nickname = "Cloned";
Console.WriteLine(pokemon.Nickname); // Original unchanged
Format Conversion
// Transfer properties between formats
PK7 pk7 = new PK7();
PK8 pk8 = new PK8();
// Copy all compatible properties
pk7.TransferPropertiesWithReflection(pk8);
Validation
Checksum
// Verify checksum
bool isValid = pokemon.ChecksumValid;
// Recalculate checksum
pokemon.RefreshChecksum();
// Validity flag
bool valid = pokemon.Valid;
Gender Validation
bool genderValid = pokemon.IsGenderValid();
Origin Validation
bool originValid = pokemon.IsOriginValid; // Species <= MaxSpeciesID
bool hasOriginalMet = pokemon.HasOriginalMetLocation;
bool isUntraded = pokemon.IsUntraded;
Generation-Specific Features
Generation 8 Example (PK8)
if (pokemon is PK8 pk8)
{
// Dynamax type
int dynamaxType = pk8.DynamaxType;
pk8.DynamaxType = 1;
// Fix memories for Gen 8
pk8.FixMemories();
// Check if belongs to trainer
bool belongsToTrainer = pk8.BelongsTo(trainerInfo);
// Update handler info
pk8.UpdateHandler(trainerInfo);
}
Hyper Training (Gen 7+)
if (pokemon is IHyperTrain ht)
{
// Check/set hyper trained stats
bool htHP = ht.HT_HP;
bool htATK = ht.HT_ATK;
bool htDEF = ht.HT_DEF;
bool htSPA = ht.HT_SPA;
bool htSPD = ht.HT_SPD;
bool htSPE = ht.HT_SPE;
// Hyper train all stats
ht.HT_HP = ht.HT_ATK = ht.HT_DEF = true;
ht.HT_SPA = ht.HT_SPD = ht.HT_SPE = true;
}
Working with Status
// Battle status condition
int status = pokemon.Status_Condition;
pokemon.Status_Condition = 0; // Clear status
// Current level (calculated from EXP)
byte currentLevel = pokemon.CurrentLevel;
// Set level (updates EXP)
pokemon.CurrentLevel = 100;
Best Practices
Always refresh checksums before exporting:
pokemon.RefreshChecksum();
byte[] data = pokemon.EncryptedBoxData;
Use
ResetPartyStats() after modifying stats, IVs, EVs, or level:pokemon.SetIVs(newIVs);
pokemon.SetEVs(newEVs);
pokemon.ResetPartyStats(); // Recalculates battle stats
Generation limits vary by format. Check maximums:
ushort maxMove = pokemon.MaxMoveID;
ushort maxSpecies = pokemon.MaxSpeciesID;
int maxItem = pokemon.MaxItemID;
int maxAbility = pokemon.MaxAbilityID;
int maxIV = pokemon.MaxIV; // Usually 31
int maxEV = pokemon.MaxEV; // Usually 252
Related Resources
- Save Files - Managing save file data
- Legality Analysis - Validating Pokémon
- Game Versions - Version identification