-
Notifications
You must be signed in to change notification settings - Fork 5
Level records
This documents what we know about the record types found in *.lvl files.
struct db_ref
{
uint16_t index;
uint16_t ???;
string path; // relative to *.lvl file
};
string level_name;
uint32_t max_width;
uint32_t max_height;
uint32_t db_ref_count;
db_ref[db_ref_count] db_refs;
struct color4b
{
uint8_t red;
uint8_t green;
uint8_t blue;
uint8_t dummy = 0;
};
struct layer_def
{
uint32_t id;
uint32_t width; // (#vertices - 1); a layer with width and height of 1 is a square with 1 vertex in each corner
uint32_t height;
uint32_t type; // 0 = floor, 1 = ceiling, 2 = between
uint32_t origin_x; // position of layer's top left corner in the level, where 0/0 is the top left corner of the level
uint32_t origin_z;
float world_height;
string layer_name;
uint32_t flags; // 2 = member of alternate blending group
float light_direction; // in radians. east to west is 0, north to south is 0.5*pi etc.
float light_ascension; // in radians. horizontal is 0, straight down is 0.5*pi, straight up is -0.5*pi
color4b light_color;
color4b ambient_color;
uint32_t light_dropoff_type; // 0 = none; 1 = from north to south; 2 = E->W; 3 = S->N; 4 = W->E
uint32_t visible_layer_count;
uint32_t[visible_layer_count] visible_layers; // this lists layers by their index in the definition block (not the layer's ID!)
};
struct layer_data_block
{
uint32_t compressed_size;
uint8_t[compressed_size] layer_data; // zlib-compressed
};
uint32_t layer_count;
layer_def[layer_count] layer_definitions;
uint32_t ???; // could be compression level of layer data. seems to be always 1
layer_data_block[layer_count] data_blocks;
The layer data block is zlib-compressed. The data is divided into two blocks without length fields. The length of these blocks is determined by the layer dimensions.
First block is vertex data. 4 bytes per vertex. Top left vertex appears first, then filled left to right, top to bottom.
- First byte is type. Type 0 is normal. Values 0-75 are defined. This indicates water etc.
- Second byte is always 0x01. No idea what it does yet.
- Third and fourth byte seems to be height offset divided by two (can't change height in smaller units). Value is biased, so 0x8000 means an offset of 0, 0x7FFF means -2 and 0x8002 means +4 etc.
Second block is cell data. Four vertices make once cell, each cell consists of two triangles. 26 bytes per cell, top left cell appears first, then filled left to right, top to bottom.
First 2 bytes seem to be flags. Low bit is cell division:
+-+ +-+
0= |/| 1= |\|
+-+ +-+
Flags are followed by two 4-byte-words which are database references for the face textures. First is for left triangle, second is right triangle.
The texture references are followed by 16 bytes for texture coordinates. Each coordinate is represented by a uint16_t where 0x0000 means 0.0 in texture space and 0xffff means 1.0. The coordinates are stored as:
Uc Ud Ub Ua Vc Vd Vb Va
with corners defined as such:
a-b
| |
c-d
This probably is an editor thing without relevance for the game.
struct layer_group
{
string group_name;
uint32_t layer_count;
uint32_t[layer_count] layers; // lists IDs of all member layers
};
uint32_t group_count;
layer_group[group_count] groups;
This record does not appear if the level does not contain any objects.
struct object
{
uint32_t id;
uint16_t class_id;
uint16_t class_db_index;
uint32_t lighting_layer_id;
float x_position;
float y_position; // elevation axis, always relative to model origin
float z_position;
uint32_t flags; // 0x01 = visible in-game, 0x100 = scaled
uint16_t initial_event_count;
uint16_t link_count;
uint16_t[link_count] linked_objects; // list of indices in object table, not object IDs!
uint16_t x_rotation; // in degrees
uint16_t y_rotation; // "
uint16_t z_rotation; // "
if(flags & 0x100) // these only appear if scaled flag is set
{
float x_scaling;
float y_scaling;
float z_scaling;
}
uint32_t data_area_size; // in dwords (4 byte blocks)
uint32_t parameter_count; // how many parameters in this object are changed compared to the class
uint32_t[data_area_size] parameter_data; // note that compared to classes, count and data are swapped
uint16_t[~parameter_count] parameter_indices; // location x of this contains the index field x as defined here has in this object's class
field_def[parameter_count] parameter_definitions; // this has the same format as the one of classes
};
uint16_t object_count;
object[~] objects;