MAZ File Format

Hover! uses the Microsoft Foundation Classes (MFC) serialization framework to store texture data in TEX files. This documentation describes the binary file structure and explains how to read TEX files without relying on MFC.

All multi-byte integer values are stored in little-endian byte order, meaning the least significant byte comes first. For example, the 16-bit value 0x1234 is stored as 34 12.

General Structure

The structure shows the general layout using 4 entries for each collection to demonstrate counting of the MFC objects. The structure is split into 4 sections for better readability.

CMerlinWorld
CMerlinWorld
CMerlinStatic Collection
CObArray (object_count)
NEW_CLASS_TAG
MFC Class Definition "CMerlinStatic" (MFC object 1)
CMerlinStatic (index 0, MFC object 2)
CLASS_TAG (reference to MFC object 1)
CMerlinStatic (index 1, MFC object 3)
CLASS_TAG (reference to MFC object 1)
CMerlinStatic (index 2, MFC object 4)
CLASS_TAG (reference to MFC object 1)
CMerlinStatic (index 3, MFC object 5)
CMerlinLocation Collection
CObArray (object_count)
NEW_CLASS_TAG
MFC Class Definition "CMerlinLocation" (MFC object 6)
CMerlinLocation (index 0, MFC object 7)
CLASS_TAG (reference to MFC object 6)
CMerlinLocation (index 1, MFC object 8)
CLASS_TAG (reference to MFC object 6)
CMerlinLocation (index 2, MFC object 9)
CLASS_TAG (reference to MFC object 6)
CMerlinLocation (index L, MFC object 10))
CMerlinBSP Collection
CObArray (object_count)
NEW_CLASS_TAG
MFC Class Definition "CMerlinBSP" (MFC object 11)
CMerlinBSP (index 0, MFC object 12)
CLASS_TAG (reference to MFC object 11)
CMerlinBSP (index 1, MFC object 12)
CLASS_TAG (reference to MFC object 11)
CMerlinBSP (index 2, MFC object 13)
CLASS_TAG (reference to MFC object 11)
CMerlinBSP (index 3, MFC object 14)

MFC Data Structure

MFC CObArray

NameDatatypeDescription
object_countuint16Number of elements in the serialized CObArray.

MFC Tags

The CLASS_TAG is formed by performing a bitwise OR operation between 0x8000 and the reference ID of an existing class definition. For example, class ID 1 results in 0x8001.

NameDatatypeDescription
NEW_CLASS_TAGuint160xFFFF – Defines and registers a new class in the MFC reference table.
CLASS_TAGuint160x8000 | class_id – References an existing class definition (e.g., 0x8001 for class definition at ID 1).

MFC Class Definition

NameDatatypeDescription
schema_versionuint160x0100
name_lengthuint16Length of the string in bytes.
nameunit8[name_length]String data (ANSI). The class name of serialized object.

MFC CString

This is a simplified representation of the MFC CString type. The length prefix uses a variable-size encoding depending on the string length. Since all texture names in Hover! are shorter than 255 characters, only the single-byte length prefix is required.

string_lengthuint8Length of the string in bytes (0–254).
stringuint8[string_length]String data (ANSI, not null-terminated).

CMerlin Data Structures

CMerlinWorld

CMerlinWorld is the main container that holds lists of CMerlinStatic, CMerlinLocation and CMerlinBSP. It might also serialize these classes to the CArchive.

These coordinates form a rectangle. The only use case known for now is collision detection. Outside of the boundary, no collision detection is performed.

NameDatatypeDescription
x1uint16Minimum X coordinate of world boundaries.
y1uint16Minimum Y coordinate of world boundaries.
x2uint16Maximum X coordinate of world boundaries.
y2uint16Maximum Y coordinate of world boundaries.

CMerlinStatic

NameDatatypeDescription
object_nameCStringName of the object/section, see Pad Types.
object_extension_dataExtension DataOptional object data, normally empty.
x1uint16X coordinate of the first line endpoint.
y1uint16Y coordinate of the first line endpoint.
x2uint16X coordinate of the second line endpoint.
y2uint16Y coordinate of the second line endpoint.
line_extension_dataExtension DataOptional line data, normally empty.
left_ceiling_textureCStringLeft ceiling texture.
right_ceiling_textureCStringRight ceiling texture.
left_wall_textureCStringLeft wall texture.
right_wall_textureCStringRight wall texture.
left_floor_textureCStringLeft floor texture.
right_floor_textureCStringRight floor texture.
z1int16Z of lower sector.
z2int16Z of higher sector.
unknown_1uint16Unknown, initialized to 0.
unknown_2uint16Unknown, initialized to 0.
left_transparentuint8Transparency flag for the left wall texture.
right_transparentuint8Transparency flag for the right wall texture.
soliduint8Solid/collision flag.
static_extension_dataCMerlinStaticExtensionExtended static data, normally 5 bytes.

CMerlinStaticExtension

The CMerlinStaticExtension block contains five known bytes and supports optional additional data. Hover! reads the first five bytes when the block length is at least 5 and skips any remaining bytes. The original format uses a length of 5 bytes, but larger blocks are supported and have been successfully tested.

NameDatatypeDescription
lengthuint16Length of the extension data in bytes, normally 5.
unknown_3uint8Unknown, initialized to 0.
left_texture_offsetuint16Horizontal texture offset for the left wall.
right_texture_offsetuint16Horizontal texture offset for the right wall.
extra_datauint8[length - 5]Optional additional bytes, ignored by Hover!.

CMerlinLocation

NameDatatypeDescription
object_nameCStringName of the object, see Location Types.
object_extension_dataExtension DataOptional object data, normally empty.
xuint16X position of the object.
yuint16Y position of the object.
angleuint16Orientation of the location in a 512-unit angular system (512 units = 360°).
zuint16Z position of the object (height).
location_extension_dataExtension DataOptional object data, normally empty.

CMerlinBSP

NameDatatypeDescription
object_nameCStringName of the object, normally empty (0x00).
object_extension_dataExtension DataOptional object data, normally empty.
x1uint16X coordinate of the first line endpoint.
y1uint16Y coordinate of the first line endpoint.
x2uint16X coordinate of the second line endpoint.
y2uint16Y coordinate of the second line endpoint.
line_extension_dataExtension DataOptional line data, normally empty.
static_iduint16Index of the associated CMerlinStatic object.
unknown_iduint16A BSP node reference. Not clear yet how it is used by Hover!
left_iduint16Index of the left child BSP node.
right_iduint16Index of the right child BSP node.
unknown_1uint16Unknown BSP property.
unknown_2float64Unknown floating-point value.
unknown_3float64Unknown floating-point value.
bsp_extension_dataExtension DataOptional BSP-specific extension data.

Extension Data

A length-prefixed data block containing additional object-specific information. Its exact purpose is currently unknown. It is read by Hover! but the bytes are discarded. The only class that is using some kind of extension or meta-data is CMerlinStatic.

NameDatatypeDescription
lengthuint16Number of additional bytes to read.
datauint8[length]Optional data, ignored by Hover!

Additional Notes

Angle Representation of Locations

Hover! uses a 512-unit angular system, where 512 units represent a full rotation of 360 degrees.

The angle can be converted to degrees using:
degrees = angle * 360.0 / 512.0 and angle = degrees * 512.0 / 360.0

Angle valueDegrees
00
12890
256180
384270
512360, equivalent to 0

Location Types

Each location has a unique name that follows the pattern <TYPE>_<INDEX>, where TYPE identifies the location type and INDEX is a zero-based, two-digit number. For example, three locations of type HUMAN are named HUMAN_00, HUMAN_01, and HUMAN_02. The location type is determined by extracting the prefix from its name. The numeric suffix distinguishes locations of the same type.

Name / PrefixDescription
HUMAN_Player position.
ROBOT_Robot position.
FLAG_ROBOT_Robot flag position.
FLAG_HUMAN_Player flag position.
POD_RANDOM_Random pod (green bubbles).
BEACON_Waypoint for robot navigation.

Pad Types

Pads follow a naming convention similar to locations, but use an additional index to group multiple static line segments into a single pad. The naming pattern is <TYPE>_<INDEX>_<SEGMENT_INDEX>.

For example, a sled pad consisting of four static line segments uses the following names:

PAD_SLED_01_00
PAD_SLED_01_01
PAD_SLED_01_02
PAD_SLED_01_03

All four segments belong to sled pad 01, with line indices ranging from 00 to 03. Similarly, PAD_HOLD_04_02 identifies line segment 02 of hold pad 04.

Pads must form a closed, convex shape, with their line segments following the correct winding order. When viewed from above, the segments must connect sequentially, starting at 00, with the interior of the pad always lying to the left of each directed segment. The final segment must connect back to the starting point of the first segment. A pad may consist of any number of segments, provided these requirements are met.

NameDescription
PAD_RAZEDRazed floor pad. The player height is z2 of the area (upper boundary).
PAD_LOWEREDLowered floor pad. The player height is z1 of the area (lower boundary).
PAD_HOLDHold pad. The player freezes for some time and can't move.
PAD_SLED_RSled pad. The player is pushed with higher speed in positive x direction.
PAD_SLED_LSled pad. The player is pushed with higher speed in negative x direction.
PAD_SLED_BSled pad. The player is pushed with higher speed in positive y direction.
PAD_SLED_TSled pad. The player is pushed with higher speed in negative y direction.
PAD_FLAG_REMOVERFlag remover pad. One flag is taken from the player.

CMerlinObject

CMerlinStatic and CMerlinBSP extends from CMerlinLine. CMerlinLine and CMerlinLocation extends from CMerlinObject. Each of the classes have their own reserved data. This is the reason why all 3 serialized classes start reading a CString, followed by the reserved data. Additional CMerlinLine defines the line segment and then the reserved data.

The class CMerlinStatic is the only class that really uses the reserved data as extension to provide additional data.