yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
ZSM File Format Specification

ZSpriteMaker Project File format (.zsm) - used by ZSpriteMaker for ALttP custom sprites.

Source: ~/Documents/Zelda/Editors/ZSpriteMaker-1/

Format Overview

Binary file format using .NET BinaryWriter/BinaryReader conventions:

  • Strings: Length-prefixed (7-bit encoded length + UTF-8 bytes)
  • Integers: Little-endian 32-bit
  • Booleans: Single byte (0x00 = false, 0x01 = true)

File Structure

┌─────────────────────────────────────────────────┐
│ ANIMATIONS SECTION │
├─────────────────────────────────────────────────┤
│ int32 animationCount │
│ for each animation: │
│ string name (length-prefixed) │
│ byte frameStart │
│ byte frameEnd │
│ byte frameSpeed │
├─────────────────────────────────────────────────┤
│ FRAMES SECTION │
├─────────────────────────────────────────────────┤
│ int32 frameCount │
│ for each frame: │
│ int32 tileCount │
│ for each tile: │
│ uint16 id (tile index in sheet) │
│ byte palette (0-7) │
│ bool mirrorX │
│ bool mirrorY │
│ byte priority (0-3, default 3) │
│ bool size (false=8x8, true=16x16) │
│ byte x (0-251) │
│ byte y (0-219) │
│ byte z (depth/layer) │
├─────────────────────────────────────────────────┤
│ SPRITE PROPERTIES (20 booleans) │
├─────────────────────────────────────────────────┤
│ bool blockable │
│ bool canFall │
│ bool collisionLayer │
│ bool customDeath │
│ bool damageSound │
│ bool deflectArrows │
│ bool deflectProjectiles │
│ bool fast │
│ bool harmless │
│ bool impervious │
│ bool imperviousArrow │
│ bool imperviousMelee │
│ bool interaction │
│ bool isBoss │
│ bool persist │
│ bool shadow │
│ bool smallShadow │
│ statis (stasis) │
│ bool statue │
│ bool waterSprite │
├─────────────────────────────────────────────────┤
│ SPRITE STATS (6 bytes) │
├─────────────────────────────────────────────────┤
│ byte prize (drop item ID) │
│ byte palette (sprite palette) │
│ byte oamNbr (OAM slot count) │
│ byte hitbox (collision box ID) │
│ byte health │
│ byte damage │
├─────────────────────────────────────────────────┤
│ USER ROUTINES SECTION (optional) │
├─────────────────────────────────────────────────┤
│ string spriteName (length-prefixed) │
│ int32 routineCount │
│ for each routine: │
│ string name (e.g., "Long Main") │
│ string code (ASM code) │
├─────────────────────────────────────────────────┤
│ SPRITE ID (optional) │
├─────────────────────────────────────────────────┤
│ string spriteId (hex string) │
└─────────────────────────────────────────────────┘

Data Types

OamTile

struct OamTile {
uint16_t id; // Tile index in sprite sheet (0-511)
uint8_t palette; // Palette index (0-7)
bool mirrorX; // Horizontal flip
bool mirrorY; // Vertical flip
uint8_t priority; // BG priority (0-3)
bool size; // false=8x8, true=16x16
uint8_t x; // X position (0-251)
uint8_t y; // Y position (0-219)
uint8_t z; // Z depth for sorting
};
// Tile sheet position from ID:
// sheet_x = (id % 16) * 8
// sheet_y = (id / 16) * 8

AnimationGroup

struct AnimationGroup {
std::string name; // Animation name
uint8_t frameStart; // First frame index
uint8_t frameEnd; // Last frame index
uint8_t frameSpeed; // Frames per tick
};

Frame

struct Frame {
std::vector<OamTile> tiles;
};

Sprite Properties Bitfield (Alternative)

The 20 boolean properties could be packed as bitfield:

enum SpriteFlags : uint32_t {
BLOCKABLE = 1 << 0,
CAN_FALL = 1 << 1,
COLLISION_LAYER = 1 << 2,
CUSTOM_DEATH = 1 << 3,
DAMAGE_SOUND = 1 << 4,
DEFLECT_ARROWS = 1 << 5,
DEFLECT_PROJECTILES = 1 << 6,
FAST = 1 << 7,
HARMLESS = 1 << 8,
IMPERVIOUS = 1 << 9,
IMPERVIOUS_ARROW = 1 << 10,
IMPERVIOUS_MELEE = 1 << 11,
INTERACTION = 1 << 12,
IS_BOSS = 1 << 13,
PERSIST = 1 << 14,
SHADOW = 1 << 15,
SMALL_SHADOW = 1 << 16,
STASIS = 1 << 17,
STATUE = 1 << 18,
WATER_SPRITE = 1 << 19,
};

Default User Routines

New projects include three template routines:

  1. Long Main - Main sprite loop (TemplateLongMain.asm)
  2. Sprite Prep - Initialization (TemplatePrep.asm)
  3. Sprite Draw - Rendering (TemplateDraw.asm)

Related Formats

ZSPR (ALttP Randomizer Format)

Different format used by ALttP Randomizer for Link sprite replacements.

ZSM vs ZSPR

Feature ZSM ZSPR
Purpose Custom enemy/NPC sprites Link sprite replacement
Contains ASM Yes (routines) No
Animation data Yes No (uses ROM animations)
Properties Sprite behavior flags Metadata only
Editor ZSpriteMaker SpriteSomething, others

Implementation Notes

Reading ZSM in C++

// .NET BinaryReader string format:
std::string read_dotnet_string(std::istream& is) {
uint32_t length = 0;
uint8_t byte;
int shift = 0;
do {
is.read(reinterpret_cast<char*>(&byte), 1);
length |= (byte & 0x7F) << shift;
shift += 7;
} while (byte & 0x80);
std::string result(length, '\0');
is.read(&result[0], length);
return result;
}

Validation

  • Frame count typically 0-255 (byte range in UI)
  • Tile positions clamped: x < 252, y < 220
  • Palette 0-7
  • Priority 0-3

Source Files

From ~/Documents/Zelda/Editors/ZSpriteMaker-1/ZSpriteMaker/:

  • MainWindow.xaml.cs:323-419 - Save_Command (write format)
  • MainWindow.xaml.cs:209-319 - Open_Command (read format)
  • OamTile.cs - Tile data structure
  • Frame.cs - Frame container
  • AnimationGroup.cs - Animation definition