MPD Map/Cell Format

Documentation of the map and cell data format used in DOKAPON! Sword of Fury.

Table of contents

  1. Overview
  2. File Types
  3. Header Structure
    1. Cell Header Format
    2. Example Header (CREDIT.mpd)
  4. Index Section
    1. Index Record Format
    2. Example Index Data
  5. Data Section
    1. Cell Data Organization
    2. Data Characteristics
  6. S_TIT Format Variant
    1. S_TIT Header
    2. S_TIT Field Layout
    3. Palette Information
  7. Data Alignment
  8. Extraction Strategy
    1. Header Parsing
    2. Index Parsing
    3. Data Extraction
  9. Image Processing
    1. Planar vs Linear Format
      1. Planar Format
      2. Linear Format
    2. Color Conversion
  10. File Format Comparison
    1. CREDIT.mpd vs S_TIT Files
  11. Practical Examples
    1. Extracting CREDIT.mpd
    2. Extracting S_TIT Sprite
  12. Known Issues
    1. Sparse Data
    2. Format Variations
  13. Tool Support
  14. Research Status
  15. See Also

Overview

MPD files contain map data and cell-based graphics used for game environments, UI elements, and other grid-based content. The format features:

  • Cell-based organization
  • Index and data sections
  • Support for both compressed and uncompressed data
  • Dimension and alignment metadata

File Types

MPD files serve different purposes:

TypeDescriptionExample
Resource IndexTable of resource referencesCREDIT.mpd
Sprite ContainerCell-based sprite dataS_TIT00_00.mpd
Map DataGame map informationVarious map files

Header Structure

Cell Header Format

struct MPDHeader {
    char magic[16];      // "Cell" + padding
    uint32_t data_size;  // Size of data section
    uint32_t width;      // Image/grid width
    uint32_t height;     // Image/grid height
    uint32_t cell_width; // Width of each cell
    uint32_t cell_height;// Height of each cell
};

Example Header (CREDIT.mpd)

00000000  43 65 6C 6C 20 20 20 20 20 20 20 20 20 20 20 20  Cell            
00000010  20 20 20 20 A0 04 00 00 60 00 00 00 60 00 60 00      ...`...`.`.

Interpretation:

  • Magic: "Cell" (padded to 16 bytes)
  • Data size: 0x04A0 (1184 bytes)
  • Width: 0x60 (96 pixels)
  • Height: 0x60 (96 pixels)

Index Section

Following the header, an index table defines entries:

Index Record Format

struct IndexRecord {
    uint16_t marker;     // 0xFFFF separator
    uint16_t id;         // Entry ID
    uint8_t type;        // Record type (usually 0x01)
    uint8_t reserved[7]; // Padding
};

Example Index Data

00 00 FF FF 01 00 00 00 00 00 00 00
00 00 FF FF 02 00 00 00 00 00 00 00
00 00 FF FF 03 00 00 00 00 00 00 00

Pattern:

  • FF FF markers between entries
  • Sequential IDs
  • Fixed 12-byte record stride

Data Section

Cell Data Organization

Cell data follows the index section:

[Index Section End]
    ↓
[Cell Data Block 0]
[Cell Data Block 1]
[Cell Data Block 2]
    ...
[Cell Data Block N]

Data Characteristics

  • High entropy (compressed/encoded content)
  • No FF FF markers in data section
  • Binary data (possibly texture or tilemap)

S_TIT Format Variant

Sprite title files (S_TIT*) use a different structure:

S_TIT Header

00000000  00 00 00 00 00 00 00 00 00 00 35 55 55 55 55 55  ..........5UUUUU
00000010  55 00 00 00 00 03 00 00 00 00 00 00 00 44 00 00  U............D..
OffsetSizeDescription
0x0010Zero padding
0x0A7Magic: 35 55 55 55 55 55 55
0x124Version/type (e.g., 03 00 00 00)
0x1D4Data offset (e.g., 44 00 00)

S_TIT Field Layout

struct STITHeader {
    uint8_t padding[10];      // Zero padding
    uint8_t magic[7];         // 35 55 55... magic
    uint32_t version;         // Format version
    uint32_t data_offset;     // Offset to data section
    uint32_t width;           // Width or block size
    uint16_t height;          // Height or count
    uint16_t stride;          // Stride or alignment
    uint32_t palette_offset;  // Palette data offset
};

Palette Information

16-color palette example:

Color 0:  Black (0,0,0) - Background
Color 2:  Dark Blue (0,0,136)
Color 5:  Red (128,0,0)
Color 8:  Very Dark Blue (0,0,16)
Color 9:  Blue (0,0,56)
Color 12: Bright Red (192,0,0)
Color 13: Brown (32,8,0)

Data Alignment

MPD files use specific alignment patterns:

AlignmentPurpose
4 bytesStandard integer data
16 bytesBlock boundaries
Power of 2Memory/cache optimization

Extraction Strategy

Header Parsing

class MPDHeader:
    def __init__(self, data: bytes):
        self.magic = data[0:16].rstrip(b' \x00')
        self.data_size = struct.unpack('<I', data[16:20])[0]
        self.width = struct.unpack('<I', data[20:24])[0]
        self.height = struct.unpack('<I', data[24:28])[0]
        
        if len(data) >= 32:
            self.cell_width = struct.unpack('<I', data[28:32])[0]
            self.cell_height = struct.unpack('<I', data[32:36])[0]

Index Parsing

def parse_index_records(data: bytes, start: int) -> list:
    """Parse index records from MPD file."""
    records = []
    pos = start
    
    while pos + 12 <= len(data):
        marker = struct.unpack('<H', data[pos:pos+2])[0]
        if marker == 0:
            # Check for FF FF marker
            if data[pos+2:pos+4] == b'\xFF\xFF':
                record_id = struct.unpack('<H', data[pos+4:pos+6])[0]
                record_type = data[pos+6]
                records.append({
                    'id': record_id,
                    'type': record_type,
                    'offset': pos
                })
        pos += 12
    
    return records

Data Extraction

def extract_cell_data(data: bytes, header: MPDHeader, index: list) -> list:
    """Extract individual cell data blocks."""
    cells = []
    data_start = header_size + (len(index) * 12)
    
    for i, record in enumerate(index):
        # Calculate cell boundaries
        cell_size = header.cell_width * header.cell_height
        cell_start = data_start + (i * cell_size)
        cell_end = cell_start + cell_size
        
        cells.append(data[cell_start:cell_end])
    
    return cells

Image Processing

Planar vs Linear Format

Some MPD files use different pixel organizations:

Planar Format

def decode_planar(data: bytes, width: int, height: int) -> bytes:
    """Decode planar pixel data."""
    output = bytearray(width * height)
    plane_size = (width * height) // 8
    
    for plane in range(8):
        for i in range(plane_size):
            byte = data[plane * plane_size + i]
            for bit in range(8):
                if byte & (1 << (7 - bit)):
                    pixel_idx = i * 8 + bit
                    output[pixel_idx] |= (1 << plane)
    
    return bytes(output)

Linear Format

def decode_linear(data: bytes, width: int, height: int) -> bytes:
    """Decode linear pixel data."""
    return data[:width * height]

Color Conversion

def apply_palette(pixel_data: bytes, palette: list) -> bytes:
    """Convert indexed pixels to RGB."""
    rgb_data = bytearray()
    
    for pixel in pixel_data:
        if pixel < len(palette):
            r, g, b = palette[pixel]
        else:
            r, g, b = 0, 0, 0
        rgb_data.extend([r, g, b])
    
    return bytes(rgb_data)

File Format Comparison

CREDIT.mpd vs S_TIT Files

FeatureCREDIT.mpdS_TIT Files
Magic“Cell”“5UUUUU”
PurposeResource indexSprite data
StructureRecords + markersHeader + data
DataReferencesActual pixels
OrganizationTable formatContainer format

Practical Examples

Extracting CREDIT.mpd

def extract_credit_mpd(filepath: str) -> dict:
    """Extract CREDIT.mpd resource index."""
    with open(filepath, 'rb') as f:
        data = f.read()
    
    header = MPDHeader(data)
    records = parse_index_records(data, 32)
    
    return {
        'header': {
            'magic': header.magic.decode('ascii'),
            'dimensions': f'{header.width}x{header.height}',
            'data_size': header.data_size
        },
        'records': records
    }

Extracting S_TIT Sprite

def extract_stit_sprite(filepath: str, output_dir: str):
    """Extract sprite from S_TIT file."""
    with open(filepath, 'rb') as f:
        data = f.read()
    
    header = parse_stit_header(data)
    
    # Extract palette
    palette = extract_palette(data, header.palette_offset)
    
    # Extract pixel data
    pixels = decode_planar(
        data[header.data_offset:],
        header.width,
        header.height
    )
    
    # Apply palette and save
    rgb_data = apply_palette(pixels, palette)
    save_as_png(rgb_data, header.width, header.height, output_dir)

Known Issues

Sparse Data

S_TIT files contain significant sparse data:

  • ~88% of pixels may be value 0 (background)
  • Remaining pixels distributed across few values
  • Suggests indexed color with transparency

Format Variations

Different MPD files may have:

  • Different header sizes
  • Varying alignment requirements
  • Optional sections

Tool Support

The following tools work with MPD files:

ToolPurpose
Dokapon ExtractExtract MPD cell data
sprite_extractor.pyExtract sprites from MPD
stit_extract.pyExtract S_TIT format files

Research Status

MPD format documentation is based on analysis of limited sample files. Additional research needed:

  • Complete format specification for all variants
  • Compression detection for newer files
  • Animation/sequence data if present
  • Relationship with other asset formats

See Also