EBLAN_ENGINE/editor/src/level_format.h
Artvasil09 a1d1baa869 feat: complete engine and editor subsystems (Stages 1-5 from TODO_ARTEM)
- Stage 1: Eliminate fish-eye distortion with precomputed tangential ray offset table and fractional DDA depth
- Stage 2: Full asset management in EblanStudio (stb_image/stb_image_write, 128x128 BGRA texture packaging, WAV sound manager)
- Stage 3: Multi-level room streaming, LevelTransition/CELL_PORTAL trigger system, 16-frame screen fade to black
- Stage 4: 60Hz cutscene engine in pure x86 ASM (v4 binary track, waypoint camera motion, shortest-arc pan, CP1251 Russian subtitles, letterbox overlay, audio)
- Stage 5: EblanStudio cutscene timeline (F6) and windowless Live ASM Viewport over shared-memory IPC directly rendered into DX11
- Tooling & Tests: comprehensive regression test suite (94 editor + 107 engine tests), IPC tests, and cutscene demo
2026-10-22 16:24:22 +03:00

96 lines
4 KiB
C++

#pragma once
#include <cstdint>
// ==============================================================================
// EBLAN ENGINE - Binary Level Format Specification (assets/map.dat)
// ==============================================================================
constexpr uint32_t MAP_MAGIC = 0x4E4C4245; // 'EBLN'
constexpr uint16_t MAP_FORMAT_VERSION = 4; // v4 adds a cutscene track and CP1251 string pool
constexpr int MAP_GRID_W = 32;
constexpr int MAP_GRID_H = 32;
constexpr int MAP_TOTAL_CELLS = MAP_GRID_W * MAP_GRID_H; // 1024 bytes
constexpr int MAX_LEVEL_SPRITES = 32;
// Cell Types
enum CellType : uint8_t {
CELL_EMPTY = 0,
CELL_BRICK = 1,
CELL_WOOD = 2,
CELL_STONE = 3,
CELL_METAL = 4,
CELL_DOOR = 5,
CELL_DOOR_OPEN = 6,
CELL_PILLAR = 7,
CELL_GLASS = 8,
CELL_MARBLE = 9,
CELL_PORTAL = 10,
CELL_COUNT = 11
};
constexpr int MAX_LEVEL_TRANSITIONS = 16;
constexpr int MAX_CUTSCENE_EVENTS = 128;
constexpr int MAX_CUTSCENE_STRINGS = 32;
constexpr int CUTSCENE_STRING_BYTES = 96;
constexpr int CUTSCENE_MAX_DURATION = 3600;
constexpr uint16_t CUTSCENE_AUTOPLAY = 1;
enum CutsceneOpCode : uint8_t {
OP_END, OP_WAIT, OP_MOVE_CAM_TO, OP_PAN_CAM_TO, OP_SHOW_SUBTITLE,
OP_HIDE_SUBTITLE, OP_PLAY_SOUND, OP_FADE_SCREEN, OP_CHANGE_SUBLEVEL
};
#pragma pack(push, 1)
struct LevelTransition {
uint8_t triggerCellX; // Trigger cell coordinate X (0..31)
uint8_t triggerCellY; // Trigger cell coordinate Y (0..31)
char targetMap[32]; // Target sublevel filename (e.g. "sublevel_02.dat")
uint16_t targetSpawnX; // Spawn cell X in destination map (0..31)
uint16_t targetSpawnY; // Spawn cell Y in destination map (0..31)
uint16_t targetAngle; // Player orientation (0..511)
uint8_t fadeEffect; // 1 = smooth fade to black, 0 = instant cut
uint8_t reserved; // Padding (total 42 bytes)
};
struct MapHeader {
uint32_t magic; // 'EBLN'
uint16_t version; // Current writer: 4; reader also accepts v1/v2/v3
uint16_t mapWidth; // 32
uint16_t mapHeight; // 32
uint16_t playerStartX; // Cell coordinate (0..31)
uint16_t playerStartY; // Cell coordinate (0..31)
uint16_t playerStartAngle; // 0..511 (0=East, 128=South, 256=West, 384=North)
uint16_t spriteCount; // Number of active sprites
uint32_t ceilingColor; // 00RRGGBBh
uint32_t floorColor; // 00RRGGBBh
uint16_t transitionCount; // Number of sublevel transitions
uint16_t cutsceneCount; // v4 only; old versions ignore the remaining header fields
uint16_t cutsceneStringCount;
uint16_t cutsceneFlags; // bit 0 = start automatically after entering this map
uint8_t reserved[4]; // Total header remains 38 bytes
};
struct CutsceneEvent {
uint16_t tickTimestamp; // Absolute 60 Hz timeline timestamp, 0..65535
uint8_t opCode;
uint8_t param8; // PLAY_SOUND bit 0 = loop; other operations require 0
int32_t paramA; // X, angle, text/sound index, fade level or transition index
int32_t paramB; // Y, duration (PAN/FADE/SUBTITLE) or unused
int32_t dataId; // MOVE duration; never a serialized memory pointer
};
// Engine world units: 1 cell = 64 units (raw integers, NOT fixed point).
struct SpriteEntry {
int32_t x; // Raw world units (cell * 64 + 32)
int32_t y; // Raw world units
uint32_t textureId; // Texture slot 1..15 (0 = solid marker color)
int32_t scale; // 16.16 fixed point (65536 = 1.0)
uint32_t dist; // Runtime calculation (can be 0)
uint32_t flags; // Flags / type
};
#pragma pack(pop)
static_assert(sizeof(MapHeader) == 38, "EBLN header layout changed");
static_assert(sizeof(SpriteEntry) == 24, "EBLN sprite layout changed");
static_assert(sizeof(LevelTransition) == 42, "EBLN transition layout changed");
static_assert(sizeof(CutsceneEvent) == 16, "EBLN cutscene event layout changed");