SkillAgentSearch skills...

MMSprite

Magic & Mayhem sprite reader (.spr files). Information about other files (.ani, .map, .evt, .mps).

Install / Use

/learn @sapphire-bt/MMSprite
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Magic & Mayhem Sprite Reader

<img src="https://www.bunnytrack.net/images/github/mm/sprites.png" />

JavaScript and Python plugins to read image data from sprite files used in the video game Magic & Mayhem, aka Duel: The Mage Wars.

These are ports of a C routine posted on the OpenXcom forums. The original C files are included in the "c" folder. With thanks to user Nikita_Sadkov, the author, for sharing his work and findings.

Be sure to check out the map formats writeup if you're interested in how maps are structured.

How to Use

Python

A script is included to dump a sprite to PNG; this requires pypng:

pip install pypng

Then, use export_image.py as follows:

py export_image.py --input RedCap.spr --dir .

This will export all sprite frames into the current directory.

If you don't care about the pypng dependency and just want to parse a sprite and do something with it:

from mm_files import SpriteFile

fh = open("RedCap.spr", mode="rb")
sprite = SpriteFile(fh)

print(sprite.frames[0])

Output:

Frame(offset=2192, size=1460, width=33, height=46, centre_x=-1, centre_y=-2, name='RALA0001', palette_index=0, delta_offsets=[408, 411, 414, 417, 420, 423, 426, 429, 432, 435, 438, 441, 444, 447, 450, 453, 458, 465, 472, 479, 484, 490, 495, 500, 505, 508, 515, 520, 527, 534, 539, 542, 545, 548, 551, 554, 557, 560, 563, 566, 569, 572, 575, 578, 581, 584], pixel_offsets=[587, 591, 598, 607, 617, 628, 641, 654, 667, 681, 697, 715, 734, 752, 770, 791, 810, 828, 848, 868, 887, 908, 934, 956, 983, 1010, 1029, 1048, 1063, 1078, 1092, 1104, 1116, 1129, 1142, 1155, 1170, 1187, 1204, 1221, 1236, 1249, 1262, 1274, 1287, 1300])

JavaScript

After including the JavaScript file in a page, pass an ArrayBuffer of the sprite file to the global MMSprite function. A minimal example is shown below:

<input type="file" id="file-input" />

<script src="./mm-reader.js"></script>
<script>
    document.getElementById("file-input").addEventListener("input", function() {
        for (const file of this.files) {
            const fileReader = new FileReader();

            fileReader.onload = function() {
                // Get a sprite reader instance
                const reader = new MMReader();

                // Read sprite data
                const sprite = reader.readSprite(this.result);

                // Unpack frame data
                for (let i = 0; i < sprite.frames.length; i++) {
                    const frame = sprite.frames[i];

                    // Render frame to canvas
                    const canvas = sprite.frameToCanvas(i);

                    // Do something with the canvas
                    document.getElementById("canvas-container").appendChild(canvas);
                }
            }

            fileReader.readAsArrayBuffer(file);
        }
    })
</script>

Properties

sprite.header : Object

The sprite file header.

// RedCap.spr
{
    "id"        : "SPR\u0000",
    "size"      : 528540,
    "unknown_1" : 4,
    "frames"    : 350,
    "palettes"  : 1,
    "unknown_2" : 1
}

sprite.palettes : Array

All colour palettes used in the file. palettes is an array containing arrays of RGB pixel value objects.

// RedCap.spr

// sprite.palettes[0][0]
{
    "r": 0,
    "g": 0,
    "b": 0
}

// sprite.palettes[0][1]
{
    "r": 191,
    "g": 0,
    "b": 0
}

sprite.frames : Array

Frame metadata. A frame object contains the following properties:

| Name | Type | Description | --- | --- | --- | begin_offset | Number | Offset in file. | size | Number | Frame size, in bytes. | width | Number | Frame width, in pixels. | height | Number | Frame height, in pixels. | centre_x | Number | Frame centre, X axis. | centre_y | Number | Frame centre, Y axis. | name | String | Frame name. | palette_index | Number | Frame colour palette index. | unknown_1 | Number | Unknown meaning. Only present if file header's unknown_1 value is 2. | unknown_2 | Number | Unknown meaning. Only present if file header's unknown_1 value is 2. | delta_offsets | Array | Delta value offsets. Use for reading pixel data. | pixel_offsets | Array | As above.

Methods

sprite.frameToCanvas(int frameIndex) returns Canvas

Renders a sprite's frame object to a Canvas element. Frames are specified by index. See example in "How to Use" section.

Notes

Certain sprite files ostensibly have no colour palette. timer.spr, for example, has a palette value of 0. Currently the plugin will generate a greyscale palette when encountering such values.

View on GitHub
GitHub Stars8
CategoryDevelopment
Updated24d ago
Forks2

Languages

Python

Security Score

75/100

Audited on Mar 3, 2026

No findings