VGFM Level Format

From ModdingWiki
Jump to navigation Jump to search
VGFM Level Format
VGFM Level Format.png
Format typeMap/level
Map type2D tile-based
Layer count2
Tile size (pixels)16×16
Viewport (pixels)320×159
Games

In VGFM there are two types of levels: regular levels (*.M) and "Map" levels (*.MAP) - a world map where you travel between levels. They both use the same file format and structure, but some data fields are used for different purpose in Map levels.

Signature

The file contains no signature. Identification can only be done by parsing the file and checking that valid (in-range) data is at the expected locations.

File format

Data type Name Description
UINT16LE height Height of level, in tiles
UINT16LE width Width of level, in tiles
UINT16LE[width * height] background Background layer, width × height × 2 bytes long
UINT8[width * height] foreground Foreground layer, width × height bytes long
UINT16LE platformTiles Number of tiles from the start of the tileset that can be stood upon (and can be passed through from left, right and bottom direction).
UINT16LE solidTiles Number of tiles from the start of the tileset that are impassable. The value is always less or equal to platformTiles, meaning that solid tiles are located always in the beginning of tileset, followed by 0 or more platform tiles.
TAnimationEntry[15] tileAnimations Animated tile information
UINT16LE numTileAnimations Number of tile animations that are used
UINT16LE noAnimationTiles Number of tiles from the start of the tileset that should not be animated. That means animated tiles are always in the end of tileset. Lowering the value makes all tiles with index >= value animate, and eventually stay animated within the first defined animation.
UINT8[500] safeTiles 0=tile hurts player, 1=tile safe, one byte for each tile in the tileset. In Map level this means whether a tile is passable or not: 0 = impassable, 1 = passable.
UINT16LE capsuleCount Number of capsules (red orbs) in level (displayed on stats screen after level exit)
UINT16LE tileFirstItem Tile index of first item tile. These tiles can be picked up - when touched by player they disappear and a twinkle animation is shown.
UINT16LE tileLastItem Tile index of last item tile
UINT16LE tileFirstClimb Tile index of first climbable tile (vine, chain, stick)
UINT16LE tileLastClimb Tile index of last climbable tile
UINT16LE tileFirstLadder Tile index of first ladder tile
UINT16LE tileLastLadder Tile index of last ladder tile
UINT16LE tileFirstRail Tile index of first overhead climbing rail tile
UINT16LE tileLastRail Tile index of last overhead climbing rail tile
UINT16LE scrollBorderLeft X-tile-coordinate which camera will never exceed when scrolling in left direction. The level will scroll normally as the player moves to the right, but it will only scroll back until tiles at this X-coordinate are visible. No tiles where X is less than this value will appear. If the player continues to walk off the screen to the left, graphical glitches will occur.
UINT16LE scrollBorderTop Y-tile-coordinate which camera should never exceed when scrolling in up direction. Not working - probably not or wrongly implemented in the game.
UINT16LE scrollBorderRight X-tile-coordinate which camera will never exceed when scrolling in right direction. As the player moves right, the level will only scroll this far. The tile at this X coordinate will never be seen, only the one at X-1. Normally this is set close to the width of the level, so that it is not possible to scroll past the edge of the level. If the player is not blocked and continues to walk off the screen to the right, graphical glitches will occur.
UINT16LE scrollBorderBottom Y-tile-coordinate which camera will never exceed when scrolling in down direction. As the player moves down/looks down, the level will only scroll this far. The tile at this Y coordinate will never be seen, only the one at Y-1. Normally this is set to the height of the level of the level, so that it is not possible to scroll past the edge of the level. If the player is not blocked and can move past this point, graphical glitches will occur.
TDoorEntry[10] doors Definitions of walk-through doors, allowing the player move from one place in a map to another. One door allows one-way movement, that means always 2 doors are used for two-way movement. So there can be only 5 two-way doors in a level.
TSwitchEntry[25] switches Definitions of switches, which can be activated by the player to perform some change in a level (activate platform, remove blocking tiles).
TLockEntry[15] locks Definitions of locks (keyhole tiles), which are unlocked by the player by touching them while holding the respective key. Usually blocking tiles are removed when unlocking a lock. In Map level locks are used to define entrance to a regular level.
UINT16LE numDoors Number of doors used in level
UINT16LE numSwitches Number of switches used in level
UINT16LE numLocks Number of locks used in level
UINT16LE tileFirstTransparent Tile index of first transparent tile rendered in front of sprites, partially covering them. This is used on barred windows, trees and some other decorations. Other tiles are rendered behind sprites.
UINT16LE tileLastTransparent Tile index of last transparent tile rendered in front of sprites
BYTE[26] * Unused, contains garbage/leftover data. Editing did not change anything in the level.
CHAR[13] tilesetFilename Filename of tileset to use in this level, NULL terminated
CHAR[13] paletteFilename Filename of palette for this level, NULL terminated
UINT16LE tileFirstBoundary Tile index of first solid (impassable) tile which is used as a boundary of hidden passages. These tiles are always inside tileFirstFront - tileLastFront range, so they cover all sprites (specifically splashes and explosions).
UINT16LE tileLastBoundary Tile index of last solid (impassable) tile which is used as a boundary of hidden passages.
BYTE[1140] * Unused, contains garbage/leftover data. Editing did not change anything in the level.
UINT16LE mapFinishPixelX X-coordinate in pixels (1 tile = 16 pixels) where you appear on Map level after you finish the level. This is for example used to move the player to different place after finishing level 4 in the first episode.
UINT16LE mapFinishPixelY Y-coordinate in pixels (1 tile = 16 pixels) where you appear on Map level after you finish the level.
UINT16LE * Unused, contains garbage/leftover data. Editing did not change anything in the level. It appears to store a number of used structures in the preceding unused data fields. There is place for 25 48-byte structures which seem to be related to locks and switches as they store coordinates to tiles which are removed by unlocking the lock.
TAnimationEntry[5] itemAnimations Defines animations of item tiles - capsule, 100 points, 250 points, 500 points and 1000 points (never used).
UINT16LE tileFirstItemAnim Tile index of first item tile which should be animated
UINT16LE tileLastItemAnim Tile index of last item tile which should be animated
TPaletteAnimationEntry[5] paletteAnimations Defines palette animations - palette continuously "rotates" within this range. This is used to animate falling/flowing water in several levels (most notably egyptian-themed levels in episode 3) as well as blue-circle-shaped level markers in Map level.
UINT16LE numPaletteAnimations Number of palette animations that are used
INT8[5] tileFirstItemType Tile index of first item tile for particular item type - capsule, 100 points, 250 points, 500 points and 1000 points (never used).
INT8[5] tileLastItemType Tile index of last item tile for particular item type
UINT16LE tileFirstFront Tile index of first opaque tile rendered in front of sprites, fully covering them. This is used to make hidden (secret) passages.
UINT16LE tileLastFront Tile index of last opaque tile rendered in front of sprites, fully covering them.
TSpriteDefinition[30] usedSprites Definitions of sprites ("object types") used in the level
TObjectEntry[150] objects Definitions of objects in the level (monsters, weapons, healing potions, keys, moving platforms etc...)
UINT16LE numTransformationBlocks Number of transformation blocks used in level
TTransformationBlock
[numTransformationBlocks]
transformationBlocks Definitions of blocks, which replace a block in a map after unlocking a lock or pressing a switch. This is almost always used to remove blocking tiles or open a door, but can be used for generally anything, like inserting a platform (as it is in E2L7).

TAnimationEntry structure

Data type Name Description
UINT16LE * Unknown. Mostly, but not always it is 0.
UINT16LE lastTile Tile index of last tile in animation sequence
UINT16LE firstTile Tile index of first tile in animation sequence

TPaletteAnimationEntry structure

Data type Name Description
UINT16LE firstIndex Index of first color in animation sequence
UINT16LE lastIndex Index of last color in animation sequence
UINT16LE startIndex Should be set to same value as firstIndex. Setting to a value out of range causes strange graphical effects.
UINT16LE * Unknown, always 0. Editing did not change anything.

TDoorEntry structure

Data type Name Description
UINT16LE minX Defines the door entrance area
UINT16LE maxX
UINT16LE minY
UINT16LE maxY
UINT16LE destPixelX Destination coordinates (where player's sprite appears after entering the door) in pixels (1 tile = 16 pixels)
UINT16LE destPixelY
UINT16LE scrollBorderLeft Behave in same way as scrollBorder values defined in level data, but these values apply in the area reached by entering the door. That means, once player enters any door, the values defined in level data are never valid again (only after player's death)
UINT16LE scrollBorderRight
UINT16LE scrollBorderTop
UINT16LE scrollBorderBottom

TSwitchEntry structure

Data type Name Description
UINT16LE posX Coordinates of the switch in tiles
UINT16LE posY
UINT16LE initialState 0 = Down, 1 = Up. The switch action is performed only when it is flipped from Up state to Down state, so that it is always (and should be) set to 1.
UINT16LE switchType Type of switch action: 1 = Activate object, 3 = Transform tiles, 4 = Remove tiles from foreground layer, 5 = Remove objects.
UINT16LE var1 Various meaning, depends on the switch type.
UINT16LE var2
UINT16LE var3
UINT16LE var4
UINT16LE[5] * Unknown, editing did not change anything.

For type 1 (Activate object) var1 is the object number to activate. Note: Technically a switch of this type sets the "var1" property on an object to "1". For most object/behavior types this value means whether the object is active. But a vertical platform uses "var2" property to determine whether it is active, that's why vertical platform unfortunately cannot be activated with a switch.

For type 3 (Transform tiles) var1 is the number of transformation block which is applied.

For type 4 (Remove tiles from foreground layer) var1 and var2 are X/Y coordinates of the target area and var3/var4 are width/height of the target area (in tiles). Note: At most 24 tiles can be removed this way.

For type 5 (Remove objects) var1 and var2 are first/last object numbers to remove. The numbers are not absolute, but are counted from 0 through only valid objects, so if there is for example free space of 5 objects in the object array, the following objects have number less than 5 than their index. Note: The removed objects must be out of the viewport. If you remove objects which are on-screen they won't disappear completely but become flickering. They will eventually disappear after leaving the viewport.

The switch action is irreversible once the switch is activated. When the switch state is changed, the tile in background layer is changed to the respective adjacent tile in the tileset.

TLockEntry structure

Data type Name Description
UINT16LE keyX Coordinates of the corresponding key in tiles. This is not used by the game (editing these values does not change anything) because keys are defined as objects.
UINT16LE keyY
UINT16LE posX Coordinates of the lock (keyhole tile) in tiles
UINT16LE posY
UINT16LE * Unknown, editing did not change anything.
UINT16LE transblockNumber Number of transformation block which is applied when unlocking the lock.
INT16LE messageNumber Number of message which is displayed when touching the lock without the corresponding key. 0 = "You need a gold key", 1 = red, 2 = green, 3 = blue. Any other value (including negative values) will display some other message from the game's list.
UINT16LE showMessage 0 = Message is shown, nonzero value = Message is not shown
UINT16LE * Unknown, editing did not change anything.
UINT16LE * Unknown, editing did not change anything.

In Map level locks define entrances to levels. In this case keyX/keyY/posX/posY define coordinates of the level entrance area (always posX = keyX + 1, posY = keyY + 1).

TSpriteDefinition structure

Data type Name Description
CHAR[16] name File name of the sprite (always including .cmp extension), null-terminated.
UINT16LE width Sprite width
UINT16LE height Sprite height
INT8 behavior This is the same as behavior value defined for each object separately but this "global" value is applied when the object is spawned during gameplay (a projectile is shot). The value means how the sprite moves and how animates.
INT8 kind Defines the type of object - whether hurts player or not, whether can be stood upon etc: 2 = monster, 3,4 = hazard/projectile (hurts), 5 = pick-up item, 6 = exit, 10 = decoration, 11 = can be stood upon
INT8 numSprites Number of sprites in the cmp file
INT8 itemType Type of the item: 0 = weapon, 1 = healing, 3 = key, 5 = checkpoint
INT8 fullHealth 1 = if healing item, restores full health
INT8 * Unknown, always 0
UINT16LE firstSpriteIndex It is sum of numSprites value of all preceding sprite definitions
UINT16LE childSprite Sprite (sprite definition number) which is spawned by this sprite (fired projectlile, pick-up animation)
BYTE[92] * ! Not known yet, seems to be more details about behavior, sprite offsets etc.

The sprite definition with index 0 has always empty name and it is the player sprite (used as starting point)

TObjectEntry structure

Data type Name Description
INT16LE objType Object type - index of sprite definition. -1 = object is not used.
UINT16LE pixelX X-coordinate in pixels (1 tile = 16 pixels)
UINT16LE pixelY Y-coordinate in pixels (1 tile = 16 pixels)
INT8 var1 Various meaning, depending on object type and behavior (whether monster or platform is active, weapon type, item animaiton speed)
INT8 var2 Various meaning, depending on object type and behavior (key number)
UINT16LE * Unknown, always 0
UINT16LE phase Used on in-out platforms in E2L2, also works on spikes
BYTE[6] * Unknown, always 0
UINT16LE var3 Various meaning, depending on object type and behavior (platform speed, swing/circling radius)
UINT16LE * Unknown
BYTE[20] * Unknown, always 0
UINT16LE behavior Means how the sprite moves and how animates: 1, 2 = Move horizontally (moving platform), 4 = Walking and shooting (monster), 8 = Move vertically (moving platform), 12 = Continuous animation (item), 16 = Jump (jumping spike ball), 23 = Swing, 38 = Move in circle, and many more values

The object with index 0 is always the starting point (and is of type 0).

TTransformationBlock structure

Data type Name Description
UINT16LE posX Target coordinates of the block in tiles
UINT16LE posY
UINT16LE width Block size
UINT16LE height
UINT16LE numBytes Size of tiles array in bytes, equal to width×height×2
UINT16LE * Unknown, editing did not change anything
UINT16LE * Unknown, editing did not change anything
UINT16LE[numBytes/2] tiles Tiles (tile indexes) in the block

Note: Only up to 25 tiles can be transformed at once, so this is a limitation of transformation block size. If a transformation block has more tiles, the tiles above 25 (counted up-to-down, left-to-right) will not be visually redrawn, but still will be internally changed and redrawn respectively if going off-screen and then on-screen. This limit includes also the switch tile so you can use a block of at most 24 tiles if it is triggered with a switch.

Tile mapping

Each tile code in both the foreground and background layer is an index into the tileset. Since the foreground layer only uses one byte for each tile, it can only store tiles up to index 255. The background layer's maximum of 65,535 is well within the 500 tiles in the tileset.

In the foreground layer, a code of 0 is used for an empty tile which is not drawn. In the background layer there is no value reserved for an empty tile, so 0 is valid tile index there.

The background layer can only consist of opaque tiles (tiles not having any transparent pixels) and the foreground layer can only contain transparent tiles (tiles which have transparent pixels). Both types of tiles are stored in different format in the tileset and if a tile is used in the background layer the game treats it as if it was stored in the opaque tile format and vice versa. Using tiles improperly results in wrongly rendered tiles.

Unclear information

  • It is not known how the game determines the player's position on the Map level when saving game inside a regular level. When you restore this saved game you appear on the Map level standing just before the marker of the level you saved in, and the position is part of the saved game. The position is neither stored in the regular level nor the Map level (editing all unknown/unused data didn't change it). It is possible that this information is stored in a different file or is hard-coded in the executable.
  • It is not clearly known how the "locked doors" work (the walk-through doors you cannot pass until unlocked, they appear only in E3L1). It was discovered that the game checks for tiles which are in the door entrance area and for some particular tiles it won't let the player pass (namely the tiles which contain iron bars). But it is not known how these tiles are determined - it is possible that the game checks the pixels in the tiles and for some particular colors it treats the tile as "locking" the doors.

Credits

This file format was reverse engineered by Malvineous and Hisymak. If you find this information helpful in a project you're working on, please give credit where credit is due. (A link back to this wiki would be nice too!)