Skip to main content

Overview

PKHeX provides comprehensive support for Mystery Gift files across all Pokémon generations. Mystery Gifts are special distributions that can contain Pokémon, items, or other rewards. Each generation uses different file formats with varying extensions and structures.

Supported Formats

PKHeX supports the following Mystery Gift formats:
FormatExtensionGenerationDescription
PGT.pgtGen 4Gift Template (inner data only)
PCD.pcd, .wc4Gen 4Pokémon Card with gift data
PGF.pgfGen 5Gen 5 Gift Format
WC6.wc6, .wc6fullGen 6Wonder Card for X/Y/OR/AS
WC7.wc7, .wc7fullGen 7Wonder Card for Sun/Moon/US/UM
WB7.wb7Gen 7Wonder Box (Let’s Go)
WC8.wc8Gen 8Wonder Card (Sword/Shield)
WB8.wb8Gen 8Wonder Box (BD/SP)
WA8.wa8Gen 8Wonder Album (Legends Arceus)
WC9.wc9Gen 9Wonder Card (Scarlet/Violet)
WA9.wa9Gen 9Wonder Album (Gen 9)

Loading Mystery Gifts

From File

using PKHeX.Core;

// Load a Mystery Gift file
var data = File.ReadAllBytes("event.wc8");
var ext = Path.GetExtension("event.wc8");

// Parse the gift data
var gift = MysteryGift.GetMysteryGift(data, ext);

if (gift != null)
{
    Console.WriteLine($"Gift Type: {gift.Type}");
    Console.WriteLine($"Card Title: {gift.CardTitle}");
    Console.WriteLine($"Card ID: {gift.CardID}");
}

Auto-Detection

PKHeX can automatically detect the format based on file size:
// Auto-detect format from data length only
var data = File.ReadAllBytes("mystery_gift.bin");
var gift = MysteryGift.GetMysteryGift(data);

if (gift is WC8 wc8)
{
    Console.WriteLine($"Sword/Shield Wonder Card detected");
    Console.WriteLine($"Repeatable: {wc8.GiftRepeatable}");
}
else if (gift is WC9 wc9)
{
    Console.WriteLine($"Scarlet/Violet Wonder Card detected");
}

From Folder

Load all valid Mystery Gift files from a directory:
using PKHeX.Core;

// Recursively load all gifts from a folder
var gifts = MysteryUtil.GetGiftsFromFolder(@"C:\Events");

foreach (var gift in gifts)
{
    Console.WriteLine($"{gift.FileName} - {gift.CardTitle}");
    
    if (gift.IsEntity)
    {
        Console.WriteLine($"  Species: {gift.Species}");
        Console.WriteLine($"  Level: {gift.Level}");
    }
    else if (gift.IsItem)
    {
        Console.WriteLine($"  Item ID: {gift.ItemID}");
        Console.WriteLine($"  Quantity: {gift.Quantity}");
    }
}

Working with Gift Properties

Checking Gift Type

if (gift.IsEntity)
{
    // This gift contains a Pokémon
    Console.WriteLine($"Pokémon: {gift.Species}");
    Console.WriteLine($"Form: {gift.Form}");
    Console.WriteLine($"Level: {gift.Level}");
    Console.WriteLine($"Ball: {gift.Ball}");
    Console.WriteLine($"OT: {gift.OriginalTrainerName}");
    Console.WriteLine($"TID: {gift.TID16}");
    
    // Check moves
    var moves = gift.Moves;
    Console.WriteLine($"Move 1: {moves.Move1}");
    Console.WriteLine($"Move 2: {moves.Move2}");
    Console.WriteLine($"Move 3: {moves.Move3}");
    Console.WriteLine($"Move 4: {moves.Move4}");
}
else if (gift.IsItem)
{
    // This gift contains an item
    Console.WriteLine($"Item: {gift.ItemID} x{gift.Quantity}");
}

Generation 8+ Specific Features

if (gift is WC8 wc8)
{
    // Check gift type
    switch (wc8.CardType)
    {
        case WC8.GiftType.Pokemon:
            Console.WriteLine("Contains a Pokémon");
            break;
        case WC8.GiftType.Item:
            Console.WriteLine("Contains items");
            // Can have multiple items
            for (int i = 0; i < 4; i++)
            {
                var itemId = wc8.GetItem(i);
                if (itemId > 0)
                {
                    var qty = wc8.GetQuantity(i);
                    Console.WriteLine($"  Item {i}: {itemId} x{qty}");
                }
            }
            break;
        case WC8.GiftType.BP:
            Console.WriteLine("Contains Battle Points");
            break;
        case WC8.GiftType.Clothing:
            Console.WriteLine("Contains clothing items");
            break;
    }
    
    // Check version restrictions
    Console.WriteLine($"Can receive in Sword: {wc8.CanBeReceivedByVersion(GameVersion.SW)}");
    Console.WriteLine($"Can receive in Shield: {wc8.CanBeReceivedByVersion(GameVersion.SH)}");
    
    // Check if repeatable
    Console.WriteLine($"Repeatable: {wc8.GiftRepeatable}");
}

Converting to Pokémon

Convert a Mystery Gift to a PKM object:
// Create trainer info
var trainer = new SimpleTrainerInfo
{
    OT = "Player",
    TID16 = 12345,
    SID16 = 54321,
    Gender = 0,
    Language = 2, // English
    Generation = 8
};

// Convert gift to PKM
var pk = gift.ConvertToPKM(trainer);

if (pk is PK8 pk8)
{
    Console.WriteLine($"Created {pk8.Species} at level {pk8.CurrentLevel}");
    Console.WriteLine($"Nature: {pk8.Nature}");
    Console.WriteLine($"Ability: {pk8.Ability}");
    
    // The PKM is ready to be added to a save file
}

Compatibility Checking

Verify if a gift is compatible with a save file:
var sav = SaveUtil.GetVariantSAV(File.ReadAllBytes("save.bin"));

if (gift.IsCardCompatible(sav, out string message))
{
    Console.WriteLine("Gift is compatible with this save file!");
    
    // Check if save can receive the specific values
    if (sav.CanReceiveGift(gift))
    {
        Console.WriteLine("All gift values are valid for this game.");
    }
}
else
{
    Console.WriteLine($"Incompatible: {message}");
}

Generation 4 Special Cases

PGT Files

Gen 4 PGT files contain various gift types:
if (gift is PGT pgt)
{
    switch (pgt.GiftType)
    {
        case GiftType4.Pokémon:
            Console.WriteLine("Contains a Pokémon");
            var pk4 = pgt.PK;
            Console.WriteLine($"PID: {pk4.PID:X8}");
            break;
            
        case GiftType4.PokémonEgg:
        case GiftType4.ManaphyEgg:
            Console.WriteLine("Contains an egg");
            break;
            
        case GiftType4.Item:
            Console.WriteLine($"Contains item: {pgt.ItemID}");
            break;
            
        case GiftType4.Goods:
            Console.WriteLine("Contains Underground goods");
            break;
            
        case GiftType4.PokétchApp:
            Console.WriteLine($"Pokétch App: {pgt.PoketchApp}");
            break;
            
        case GiftType4.PokéwalkerCourse:
            Console.WriteLine($"Pokéwalker Course: {pgt.PokewalkerCourseID}");
            break;
            
        case GiftType4.HasSubType:
            // Check subtype for seals, accessories, backdrops
            switch (pgt.GiftSubType)
            {
                case GiftSubType4.Seal:
                    Console.WriteLine($"Seal: {pgt.Seal}");
                    break;
                case GiftSubType4.Accessory:
                    Console.WriteLine($"Accessory: {pgt.Accessory}");
                    break;
                case GiftSubType4.Backdrop:
                    Console.WriteLine($"Backdrop: {pgt.Backdrop}");
                    break;
            }
            break;
    }
}

Getting Gift Descriptions

using PKHeX.Core;

// Get formatted title
var title = gift.GetTitleFromIndex();
Console.WriteLine($"Title: {title}");

// Get full description
var description = gift.GetDescription();
foreach (var line in description)
{
    Console.WriteLine(line);
}

Best Practices

Always validate Mystery Gift compatibility before adding to a save file. Generation and game version mismatches can cause issues.
Some gifts have version restrictions (e.g., Sword-only or Shield-only). Always check RestrictVersion for Gen 8+ gifts.

Build docs developers (and LLMs) love