Terminal Velocity
Terminal Velocity stores its data files in .POD containers, which are a simple way of storing an entire directory structure, including paths. Only 2 .POD files are provided, STARTUP.POD and DISK.POD (floppy disk version) or CDROM.POD (CD version). An arbitrary number of PODs can be mounted by creating a file named POD.INI, which contains the number of PODs followed by the filenames. The game can be forced to use only external files by just writing a "0" in the POD.INI file. If a specified file does not exist, the game will crash. Most files are in plain text format (strings). So it's easy to change settings or even create completely new maps/missions. Every other file is mostly a table of 8-bit values (see below). The whole file system is 98% compatible to Fury³, the successor of Terminal Velocity. That means, you can run Terminal Velocity completely in the Fury³ environment, and vice versa. But the Fury³ environment (although a win32 Application) is worse than Terminal Velocity's.
All positions, angles, distances etc. are given in signed 32-bit integers. The terrain is a grid - 256x256 squares in size - defined by a 8-bit heightmap. One terrain square is exactly 1048576 (2^20) units wide - the whole map is 268435456 units wide. But the coordinates are shifted in the range from -134217728 to 134217727. Angles are counted clockwise. 65535 units = 360 degrees. Negative values are possible, of course. Speeds are given in 1048576 units per second.
Contents |
Files
Inside the already mentioned .POD files there are many different file formats:
.LVL
This are the level files - one for each level and tunnel. They contain a list of linked files (which define the level), the level type and a few lighting parameters. LVL has the following format:
level type briefing text (TXT) heightmap (RAW) or tunnel segment file (TNL) texture placement file (CLR) global palette (ACT) level texture list (TEX) QKE file (?) powerup placement file (PUP) texture animation file (ANI) tunnel definition file (TDF) cloud texture (RAW) background gradient palette (ACT) enemy definition + placement file (DEF) navigation file (NAV) background music (MOD) precalculated fog colors (FOG) luminance map (LTE) sun light direction vector ambient light for objects <unknown> <unknown> <unknown> ;New story stuff introduction video (TVI) level end video (TVI) transition video (TVI) mission start text (MIC) mission end text (MIC)
The very first number gives the level type. [4] defines a regular map, [1] defines a tunnel. The 3rd line is either a RAW heightmap (level type 4) or a tunnel segment definition (level type 1).
.TXT
Includes the mission briefing text, showed before entering a new planet. It's more or less compatible to the standard TXT files, with one exception: the first 2 lines indicate 2 files: the planet's model file and the texture filename it should use. The rest is plain text.
.RAW
This format is used for all textures in the game. No other graphic formats are used. The RAWs have no header - so every texture file is assumed to be quadratic and (of course) a power of 2. The only exceptions are the menu background graphics and the cockpit bitmap. They are 320x200. All RAWs are 8-bit. The maximum size for textures is 256^2. When using higher values, the textures simply show the (changing) content of other RAM areas. RAWs are also used as heightmaps for terrain. The color index 0 (black) is often defined as transparent. This is used for tunnel entrances/exits and some effect animations.
.CLR
These files are used in combination with TEX files. The CLRs specify one texture for every terrain square. The TEX files provide a list of textures (indexes) and the CLR map uses these indexes for texture placement. CLRs have the same size as the heightmap. Because CLR files are 8-bit, there is a maximum of 256 textures per terrain - even if the TEX file holds more than 256 textures. If the CLR uses an index, which is not defined in the TEX file, some other RAM data is displayed instead of the texture.
.ACT
This are VGA color palettes. They are exactly 768 bytes long. Every color is defined as RGB vector (3 * 8-bit). All in-game textures only use the first 240 palette entries. The last 16 are reserved for the sky texture. This way, every planet can have different cloud colors, while maintaining the correct colors for all other textures. If the ACT file is specified as "sky palette" in the LVL file, the entries 193...208 define the background gradient - from the sky color to the fog/atmosphere color. If the sky color (entry 193) is black, the stars become visible. These 16 entries are mapped to the last 16 entries of the "global" palette in-game. When the cloud texture uses this 16 color indexes, it can be colored independend of the other textures.
.TEX
TEX files provide a list of RAW textures for 1) the terrain or 2) the tunnels, depending on the level type. The number in the first line indicates the number of textures in the list. These files are used in combination with CLR and TNL files - they take the texture indexes from the TEX file to place the corresponding texture on 1) a terrain square or 2) a tunnel's segment side.
.FOG
The name says it all! Easy concept, hard to explain: The game has 16 "fog steps". These fog steps are pre-calculated for all 256 colors in the palette - using only colors from the same palette. It tries to find colors in the palette, which match a blending between the real color and the fog color as close as possible. This is more an index-remapping than a fog effect. At step 16, all 256 colors have the same index - the fog color. Maybe this image shows the concept:
The crappy look of the blending is no error or compression artifact. It is the correct representation of the FOG file. Because everything is 8-bit, it's impossible to blend smoothly between all colors. FOG files are 4096 bytes long.
.LTE
These files are used to tell the engine, which colors are affected by lighting. 16 "brightness steps" are defined for all 256 colors. Colors affected by light have a gradient to black. This way, specified colors are rendered with full brightness, even if the ambient light is zero. Often used for light textures and explosion sprites. LTE files have the same size and work the same way as FOG files.
.MAP .MIX
MAP files are 15-bit color tables, converted to 8-bit using the vga palette. MIX files are color tables where every color is linearly blended with every other. They're used for semi-transparent effects such as shadow mapping, smoke trails, force fields in tunnels, the red screen when the player is hit and the main menu panel. If a MAP or MIX file is not present, the game generates them when needed.
.PUP
This defines, where powerups are placed on the terrain and in tunnels. Not to be confused with the powerups which appear after blowing stuff up! The first number gives the number of list entries. Every entry has the format:
x_pos, y_pos, z_pos, powerup
12 powerups are available (in the following order):
0 - RTL 1 - PAC 2 - ION 3 - MAM 4 - SAD 5 - SWT 6 - Shields restored 7 - Invisibility 8 - Invincibility 9 - DAM 10 - Afterburner 11 - Power core 12 - Random (not supported in Terminal Velocity, but Fury³)
All powerups re-appear after entering/exiting a tunnel.
.ANI
These files are used to create continuous animation cycles for terrain and tunnel textures - in combination with TEX files. It is never used in Terminal Velocity, but the engine supports it. The first number gives the number of animations. Every animation has the following format:
reference name frames, speed frame#1 frame#2 frame#3 frame#4 ...
The reference name must be identical to the name in the TEX file. It's case sensitive! The speed value controls the frame rate of the animation. 65536 means 1 frame per second. Lower values mean faster animation. Only 8 frames are supported for each animation. When adding more frames, a 9th frame with random RAM data is shown, all other frames are ignored.
.TDF
These files specify, where tunnel entrances and exits are placed on the terrain - along other tunnel properties. The very first number gives the number of tunnels in the level. Each tunnel definition has the following format:
tunnel filename (LVL) entrance_x,entrance_y,entrance_z exit_x,exit_y,exit_z entrance logic <unused line> entrance terrain texture exit logic <unused line> exit terrain texture chamber exit
The entrance and exit vectors are self explanatory. Only the X and Z components needs to be specified, because the engine automatically sets the correct high value (Y-axis) according to the terrain slope. The entrance terrain texture is placed on the terrain square nearest to the entrance vector. It replaces the texture, which was originally underneath it. The same rules apply for the exit. The entrance/exit logic determines the appearance of the tunnel in the map:
[0]: the tunnel is not visible, but can be entered. This is sometimes used for hidden tunnel exits. A hidden tunnel entrance is never used in Terminal Velocity, but the engine supports it. [1]: the tunnel is always visible, and can be entered anytime. [2]: the tunnel is always visible, except when a boss fight takes place. This is used to prevent the player from escaping the boss's chamber, before the fight is over. This can cause some unintended "navigation behavior". See the NAV section below.
If chamber exit is set to 1, the tunnel ends in a chamber. These are internally created by mirroring the heightmap at the cloud plane, so the mirrored terrain appears instead of the sky. The fog effect is not supported while in "chamber mode".
.TNL
The actual look of the tunnel is defined in the TNL files. The first number gives the number of tunnel segments. The tunnel can have up to 90 segments. More segments cause a crash! Each segment has the following format:
start_x, start_y, end_x, end_y, polygons start_angle1, start_angle2, rotation_speed start_width, start_height end_angle1, end_angle2 end_width, end_height ??? light_polygon concave obstacle obstacle_tex_index polygon#1_tex_index polygon#2_tex_index polygon#3_tex_index polygon#4_tex_index polygon#5_tex_index polygon#6_tex_index polygon#7_tex_index polygon#8_tex_index flicker_light_type flicker_light_strength ambient_light
Start_x and start_y are the positions for the front end of the segment, end_x and end_y for the back end. The start position of the next segment should be equal to the end position of the current segment. This is not required for the game, but it prevents graphic errors. The polygons parameter defines the number of polygon per segment in the range from 3 to 8. Although 1 and 2 polygons are supported by the engine, it's not recommended because it makes no sense (A flat plane is no tunnel!). Start_angle1 and start_angle2 are used to rotate the upper and lower half of the pipe independently to create other forms (half-pipes for example). All polygons stay connected, but the first one is stretched depending on the two angles. To create a normal pipe, the 2nd angle must be 360 degrees (65536 units) heigher than the 1st. The same rules apply for end_angle1 and end_angle2. The rotation_speed lets the segment rotate with the defined speed - 65536 units per second. Both directions are possible. Start_width and start_height are the scale for the front end of the segment, end_width and end_height for the back end. The start scale of the next segment should be equal to the end scale of the current segment to prevent graphic errors. The light_polygon specifies the polygon, where the light is coming from, starting at 0. When this parameter is -1, the light is switched off. If concave is set to 1, the first and the last polygon-edges are placed at the center of the segment to form non-convex shapes. Other values are accepted but they make no sense.
Obstacle can be one of the following types (0 = none):
Numbers 4..7 and 12..15 seems to be duplicates. 26..29 are never used in the game. The obstacle is rendered with the texture specified in obstacle_tex_index. This index refers to the TEX file specified in the tunnel's LVL file. If an invalid index is given, the game crashes! The polygon#n_tex_index parameters are the texture indexes for every polygon of the current segment. The number of lines must be equal to the number of polygons. If not, the game crashes! The flicker_light_type can be one of the following patterns:
0 = no light 1 = 1.0 sec ON 1.0 sec OFF 2 = 1.5 sec ON 0.5 sec OFF 3 = 1.5 sec OFF 0.5 sec ON 4 = toggle every frame
When flickering light is activated, the texture is split up in 2 separate sectors. Because all textures need to be quadratic, the texture resolution is limited to 128^2 pixels. The upper left quarter of the texture is used for "light ON" and the upper right for "light OFF". The lower half of the texture is unused. The same rules apply for the obstacles of type 2 and 3. "closed door" takes the upper left sector, "blown open door" takes the upper right. flicker_light_strength and ambient_light are self explanatory. Both are in the range of 0...65536.
.DEF
These files define the properties of all enemies on a per-level-basis. It contains also a list of where all the objects are placed within the map/tunnel. The first number gives the number of object definitions. Every object definition has the following format:
logic, unknown, bbox_radius, cx, cy, cz, complex_model, simple_model thrust_speed, rotation_speed, fire_speed, fire_strength, weapon show_on_briefing, create_randomly, powerup_probability, powerup num_rnd_fire_verts, fire_vert#1, fire_vert#2, fire_vert#3 ... ;NewHit num_new_hboxes, hbox#1_vert, hbox#1_size, hbox#2_vert, hbox#2_size ... !NewAtakRet attack_dist, retreat_dist, object_is_boss, unknown Description line #New2ndweapon fire_spread, 2nd_wpn, 2nd_wpn_dist, fire_velocity %SFX boss_fire_sfx boss_yell_sfx
Logic describes the behavior of the object. 42 types are available:
The bbox_radius should give the size of the bounding box. But changing this parameter has no effect in the game. The next vector (cx, cy, cz) defines a pivot point for off-center rotation. This way, the object can rotate around a different point than it's center. The engine switches between complex_model and simlpe_model depending on the distance to the camera. The thrust_speed parameter gives the object's forward speed - measured in terrain units per second. The rotation_speed is measured in 65536 units per second. Fire_speed is the delay between each shot. 65536 = one second. Lower means faster fire interval. Fire_strength is the damage inflicted to the player - per shot. If this parameter is 65536, the player's ship is destroyed with one hit! Weapon can be one of 19 available weapon types (see table below). If show_on_briefing is set to 1, the object appears in the briefing sequence before the level starts. If create_randomly is set to 1, this object is generated in random spots and in random time intervals around the player (not in easy-mode). At least one object of this type must already be placed in the map, or the game crashes as soon as it tries to spawn the object. Also, when all instances of this object type are destroyed before the game spawned a new one, the complete spawning process is canceled. The powerup_probability parameter is self explanatory. It's in percent. The powerup parameter specifies the powerup (see table below) which appears after the object is destroyed.
Enemies can fire their weapon from more than one point. The num_rnd_fire_verts parameter is used for this. It defines the number of random vertices, directly followed by an array of vertices used for different "muzzle positions". The helicopters for example have 2 vertices defined. One for each missile launcher.
The object's bounding box is usually calculated from the outer most vertices of the model file. But the engine supports an arbitrary number of hit boxes with different sizes. The num_new_hboxes parameter is used for this. It defines the number of hit boxes for the object, directly followed by an array of pairs of numbers. The first number of each pair is the vertex, the second number is the size. This array overrides the object's original bounding box. This way, special hit regions can be specified - often used for bosses. The hit boxes are always cubic.
Attack_dist is the distance, at which the object turns towards the player and attacks with it's primary weapon. Retreat_dist is the distance, at which the object turns away from the player and stops attacking. If object_is_boss is set to 1, the object becomes invisible until it's "activated" by a navigation point of type 5 (see NAV section). The description line is self explanatory. The fire_spread parameter can be set to one of 3 spread patterns (see table below). All values >2 will cause a crash! 2nd_wpn gives the object the ability to fire a second weapon, even when in "retreat mode". 2nd_wpn_dist is the distance at which the weapon is fired. The fire direction of the 2nd weapon is independent of the object's orientation. Fire_velocity is the speed of the bullets/lasers measured in 1048576 units per second. Boss_fire_sfx can be used to replace the sound effect for the primary weapon. boss_yell_sfx works the same way but is pretty useless.
The table shows all possible values for the following parameters:
The 4 lines ;NewHit, !NewAtakRet, #New2ndweapon and %SFX are section markers. The important thing is the first character. These are needed to tell the engine, if the following definition section is part of the current definition block or not. If one or more of these markers are not found, the parser assumes, that the respective section is not included in the current block. As consequence, there are 5 different block formats. Directly after the object definition follows the object placement list. The first number gives the number of objects on the map/in the tunnel. Each entry has the following format:
def_index, strength, X ,Y ,Z , pitch, roll, yaw
Def_index corresponds to a number in the object definition section of the DEF file, beginning at 0. Strength is self explanatory. When this parameter is 65536, it's equal to the strength of the player's ship. When zero, no object is placed. X, Y, Z is the starting vector for the object and pitch, roll, yaw is the starting rotation of the object. Up to 500 objects can be placed in the map. Higher numbers will cause a crash. If an object with invalid index number is placed, the game shows a radar-spot but no actual object.
.NAV
The NAV files include a list of navigation points and their properties. The first number gives the number of navigation points. 7 types are available (in the following order):
0 - TGT - Target (can also be a group of targets) 1 - TUN - Tunnel entrance 2 - CHK - Checkpoint 3 - DUN - Departure Unit (level end) 4 - XIT - Tunnel exit 5 - BOS - Boss 6 - Starting point
Different types have different properties, but all of them have at least identifier, position and description (unused).
Pitch, roll and yaw are the starting angles for the player's ship.
The departure unit is automatically created, when the last navigation point is of type 3. If the last point is a tunnel exit, the level ends immediately after exiting the tunnel. This applies for every other type. When no nav-point is set, the level ends as soon as it starts. The NAV system is poorly integrated. It's possible to simply skip some of the navigation points and - in some cases - the entire list (2 examples):
1) Whenever there's a point of type 1 in the list (tunnel entrance), everything before this point can be skipped. The only exception are targets with more than one sub-target. 2) If the boss fight takes place in a chamber, and you know the position of this chamber on the map, you can simply fly into the boss's tunnel to complete the level without even seeing the boss! But this works only, if the last tunnel is part of the navigation list.
.BIN
These are the model and vertex animation files. A good description of the format can be found here: http://www.viaregio.de/pieper/mtm_binformat.shtml
.MOD
The music in the game uses ProTracker MOD files. The internal player only supports 6 channels. Further channels are ignored. Not even looped samples are supported.
.WAV
The sounds are standard PCM Wave files. The sample rate can go up to 44100 Hz, but only 8-bit streams are supported. 16-bit is simply interpreted as 8-bit. In this case, only loud noise is heared.
.TVI
...are headerless video files with fixed resolution (320x120), framerate (15 fps), sampling frequency (11025 Hz) and bit depth (8-bit). TVI has the following structure:
The entry content_start equals num_frames * 4 + 4. It's the offset to the actual video data. Next is an array of offset-entries for every frame. The audio stream is splitted into chunks of 11026 bytes, except the first chunk, which is 22051 bytes long. Every chunk starts with a length entry which - for some odd reason - is always 1 byte longer then expected, while the first byte is NOT part of the audio data! It has almost always the value of "3". Because the stream is played back with 11 kHz, the audio chunks are exactly one second long (the first chunk is 2 seconds). The audio data is uncompressed PCM (8-bit unsigned).
The video stream is split into 15-frame-chunks, where every 15th frame starts with an audio chunk. In this case, the frame offset is calculated by adding the length of the current audio chunk to the frame offset. Every frame starts with an length entry. The frames are compressed (losless), but unfortunately I haven't figured out the compression algorithm yet. Empty (black) frames are 600 bytes long. The video uses the same palette as the rest of the game.
.DMO
Demo files are short, pre-recorded gameplay sections that are loaded, when the user leaves the main menu open for some time without pressing any key. The option "demos: on" must be activated for this to work. DMO has the following format:
num_entries level_file key_event, time_offset x, y, z pitch, roll, yaw, unknown //if a key is pressed or released: key_event, time_offset key_number
As long as no key is pressed, key_event is 0, otherwise it's 1 - no matter if a key is pressed or released. The key_number represents the scancode of the key that was pressed/released, starting at 0. The [x,y,z] vector is the position and the [pitch,roll,yaw] vector is the orientation of the player's ship at any given moment. Demo files can also be recorded by the user by pressing ctrl+B in the main menu...
.NDX
There's just one file of this type in the whole game (FONT.NDX) which defines the width of every character in the file "FONT.BIN" found in the startup directory. All characters are 23 pixels height. The file FONT.BIN contains the actual pixel data of the character set used in the game for the main menu and the messages in the screen center. Not to be confused with the font for the briefing text or the sector/objective/status display. That font is directly embedded into the GAME.EXE.
.VOX
These are the files that define a complete mission (level order). The format is as follows:
num_entries mission_name level_num, stage_num, lvl_file level_num, stage_num, lvl_file level_num, stage_num, lvl_file ...
The mission_name is ignored by the game. It's not displayed anywhere (the mission names are hardcoded). level_num and stage_num also have no real meaning. They're only displayed at the beginning of the level (as loading screen). The only thing that really matters is the lvl_file which, of course, is the map to load. There is another VOX file in the ART folder named STARS.VOX but it is redundant and can savely be ignored (and even deleted) because the distribution of the stars in the background is hardcoded anyway.
.QKE
I have no idea what these files are used for. Every QKE file in Terminal Velocity and Fury³ contains just a zero (as character, not binary). With one exception: The 3 QKE files for the 3rd planet of Fury³ (Ares) contain 6 blocks of data. Each entry has a identifier and two pairs of coordinates...
--WDLmaster 17:37, 14 June 2010 (CEST)
