Actor sprites file

From Boktai Hacking Wiki
Revision as of 20:47, 22 October 2024 by Raphi (talk | contribs) (Raphi moved page Animation file to Actor sprites file without leaving a redirect)

Animations are similar to sprite sets, but they are (slightly) simpler in structure. Animations are used for "small" enemies (like boks or mummies), while sprite sets are used for "large" enemies (bosses and minibosses). Both animations and sprite sets can store static and animated sprites as well.

Differences compared to sprite sets

  • Each object in a sprite set sprite can have a different palette, whereas each animation frame must use the same palette for each object.
  • Each game has multiple sprite set files, but only one animation file. However, the animation file has an internal structure instead that allows one to reference specific animations in the file.
  • Sprites use 2D character mapping, animations use 1D character mapping (for sprite objects, consecutive rows of tiles are always stored 16 tiles apart, whereas for animations consecutive rows follow immediately after the preceding row).

File format

The animation file stores multiple animations, and each animation can have multiple frames (a frame is similar to a sprite in a sprite set file). Each frame can be made up of multiple GBA objects.

struct AnimationFile {
  /* offset 0x00 */ u32 unknown_0x00;
  /* offset 0x04 */ u32 animationCount;  // Number of animations in the animations[] array
  /* offset 0x08 */ u32 unknown_0x08;

  // Byte offset from start of the file to the tiles[] array
  /* offset 0x0c */ u32 offsetToTiles;

  // Byte offset from start of the file to the frames[] array
  /* offset 0x10 */ u32 offsetToFrames;

  // Byte offset from start of the file to the objects[] array
  /* offset 0x14 */ u32 offsetToObjects;

  Animation animations[animationCount];
  GBA_Tile tiles[];
  AnimationFrame frames[];
  AnimationObject objects[];
};

struct Animation {
  /* offset 0x00 */ u16 id;       // ID of this animation, used for loading it
  /* offset 0x02 */ u16 unknown_0x02;
  /* offset 0x04 */ u8 widthPx;   // Width of every animation frame in pixels
  /* offset 0x05 */ u8 heightPx;  // Height of every animation frame in pixels
  /* offset 0x06 */ i8 offsetX;   // X pixel offset of the animation, relative to the position provided by the game
  /* offset 0x07 */ i8 offsetY;   // Y pixel offset of the animation, relative to the position provided by the game

  // Byte offset from start of the frames[] array to the first frame of the animation
  /* offset 0x08 */ u32 frameOffset;
};

struct AnimationFrame {
  /* offset 0x00 */ u8 objectCount;   // Number of objects in this frame
  /* offset 0x01 */ u8 unknown_0x01;

  // Palette index, same as https://boktaihacking.net/wiki/Sprite_set_file#Palettes
  /* offset 0x02 */ u16 palette;

  // Byte offset from start of the tiles[] array to the first tile of this frame
  /* offset 0x04 */ u16 tileOffset;

  // Byte offset from start of the objects[] array to the first object of this frame
  // The objectCount field determines how many objects should be drawn
  /* offset 0x06 */ u16 objectOffset;
};

struct AnimationObject {
  // Same as the shape field in https://boktaihacking.net/wiki/Sprite_set_file
  /* offset 0x00 */ u8 shape;
  /* offset 0x01 */ u8 unknown_0x01;
  /* offset 0x02 */ i8 x; // X offset of this object in pixels
  /* offset 0x03 */ i8 y; // Y offset of this object in pixels
};

Tiles

Each animation frame only stores the first tile that should be drawn for this frame. The remaining tiles follow the first tile, in order, and using 1D character mapping. Example: Assume that we have an AnimationFrame with two objects, one 16x16 px object, followed by one 8x16 px object:

  • Tile 0: Top-left tile of first object
  • Tile 1: Top-right tile of first object
  • Tile 2: Bottom-left tile of first object
  • Tile 3: Bottom-right tile of first object
  • Tile 4: Top tile of second object
  • Tile 5: Bottom tile of second object