Tomba!/Technical information
Understanding Tomba
File:Tombaexplain.pngSchematic explanation of FLA, LDAR, GAM files by vervalkon
This is an eternally unfinished document that tries its best to explain how Tomba and its various file formats work. There might be mistakes, there might be misinformation, but all of the things written have been verified to be true in a sense that exporters and converters based off this info work and produce legitimate output.
There might be things we've missed and there might be things we just don't know, so if you're a PSX hacker and/or know r3000 well, please join our Discord group: https://discord.gg/RXgDnkv
The ISO
There are four retail versions of the game and a varying amount of demos per region.
SLPS-01144for the JP version SCUS-94236for the US version SCES-01330and `SCES-01331for the PAL versions
The notable visual differences between these are obviously the languages, but also the fact that the Japanese version uses few to no polygons with vertex coloring (gouraud shading, vertex shading, shaded polygons, gradated polygons, whatever you want to call it) on.
Structurally the JP version is very different to the US and PAL releases, but more on that later. Unless otherwise noted, I will be talking about the US retail version.
The Contents
Unpacking the ISO will give you the following:
AREA00 to AREA19
These are the folders corresponding to the areas in the game, with the exception of the empty folders found in the JP version and the AREA15 folder found in all versions. When you see a loading screen in-game, the game is looking up files from one of these folders.
The numbers correspond to the AREAS found in the Areas and sections chapter.
These folders contain all the files used for creating an area, including images to put into VRAM, area dialogue, collision, models, assets and their placement.
MOVIE
Contains all the FMV sequences in the game. Standard STR files, nothing special.
SCUS_942.36
The executable itself. This file runs when the game is booted and besides critical code, it contains important arrays related to file linkage and camera coordinates, among others. The executable in the Japanese version has much more data in it, including the LDAR data. For the rest of the doc, this file will be referred to as the Executable.
SOUND
Contains standard SEQ and WVD data - sequenced music and wavetables. Nothing special.
SYS
Contains the LDARs. See the LDAR section for more information. Note: this folder is not in the JP version of the game.
SYSTEM
Contains all kinds of miscellaneous stuff, including graphics, models and Xfiles. These don't particularly fit into any single area folder, as there are things like the Game Over models and the Map models (and textures) here.
Additionally, there are several unused graphics to be found.
SYSTEM.CNF
This small 68 byte file contains the following ASCII:
// BOOT = cdrom:\SCUS_942.36;1 // TCB = 4 // EVENT = 10 // STACK = 80200000
Likely just boot information for the game, guessing that this is the first file the PSX reads.
ZZZ
Contains a file called DUMMY.DAT, filled with $1A5E000zeroes. There is probably an anti-piracy or file lookup efficiency related reason for why this file exists, but generally it's useless and of no concern.
Understanding LDARs
The SYS folder's LDAR files are as follows:
LDAR00.BIN, LDAR01.BIN, LDAR02.BIN, LDAR03.BIN, LDAR04.BIN, LDAR05.BIN, LDAR06.BIN, LDAR07.BIN, LDAR08.BIN, LDAR09.BIN, LDAR10.BIN, LDAR11.BIN, LDAR12.BIN, LDAR13.BIN, LDAR14.BIN, LDAR16.BIN, LDAR17.BIN, LDAR18.BIN, LDAR19.BIN, LDSYS.BIN
Essentially, this folder contains an LDAR file for every AREA, excluding the AREA15. The LDAR files contain instructions that tell the game to fetch files and either split them into smaller pieces to push into RAM or just take and draw into the VRAM. Once the data is decompressed or written into (V)RAM,
An LDAR is a "bill of materials", if you will.
Reading the LDAR files is relatively straightforward: you read Entries that consist of byte groups of size $14bytes until you encounter an group of exactly:
FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00
The following bytes are an excerpt from LDAR00. I've annotated the columns on the top, and a legend is provided after the bytes. Some bytes have been grouped to little endian longs for readability's sake.
xxxxxxxx fidx ftpe ram-info fs-or-xy wdth hght`_ `00000006 0149 10FF 80141000 00800000 0040 0080 00000001 014A 10FF 80141000 010000C0 0040 0100 00000001 014B 10FF 80141000 00000240 01C0 0100 00000001 014C 10FF 80141000 01000000 00C0 0100 00000001 014D F0FF 00000000 00053F38 0000 0000 00000002 014E 60FF 80140000 0002E008 0000 0000 00000004 0000 62FF 00000000 00014CDC 0000 0000 FFFFFFFF 014F 63FF 00000000 000018C8 0000 0000 00000003 0000 30FF 00000000 00003248 0000 0000 FFFFFFFF 0000 35FF 00000000 0000067C 0000 0000 FFFFFFFF 0000 31FF 00000000 0000008C 0000 0000 FFFFFFFF 0000 3FFF 00000000 000003C0 0000 0000 FFFFFFFF 0000 32FF 00000000 00001C98 0000 0000 FFFFFFFF 0000 33FF 00000000 00002488 0000 0000 FFFFFFFF 0000 34FF 00000000 00004CDC 0000 0000 FFFFFFFF 0000 37FF 00000000 000002BC 0000 0000 FFFFFFFF 0000 39FF 00000000 00001EBC 0000 0000 FFFFFFFF 0000 53FF 00000000 000001F4 0000 0000 FFFFFFFF 0000 71FF 00000000 00005980 0000 0000 FFFFFFFF 0000 52FF 00000000 00000978 0000 0000 FFFFFFFF 0000 54FF 00000000 00001694 0000 0000 FFFFFFFF 0000 B2FF 00000000 00000528 0000 0000 FFFFFFFF 0000 B3FF 00000000 000003D0 0000 0000 FFFFFFFF 0000 D1FF 00000000 0000412C 0000 0000 FFFFFFFF 0000 86FF 00000000 00000400 0000 0000 FFFFFFFF FFFF 0000 00000000 00000000 0000 0000 etc...
Legend:
- xxxxxxxx: These bytes can be ignored.
- fidx: The file index. If nonzero,this tells what file to load into memory, either into the address that's in the group's `ram-info`, or in the case of `wdthand`hghtbeing nonzero, into the VRAM to the coordinates that the`fs-or-xy describes. If `fidx itself is zero, the 'keep reading' flag is set, and the next byte group won't load a new file for reading,but instead keeps reading the same file's data from where it left off. First such instance can be found in the sixth row in thee xample above. You first write $0002E008bytes from file index$14E`, then start a new file where you keep reading file $14Efor$00014CDCadditional bytes.
- ftpe: File type. If nonzero, thistells the game what type of data we're dealing with. For more information see the file types section.
- ram-info: If nonzero, contains aRAM address where the game pushes the data for decompression or simply for storage. To-be-decompressed data usually goes to$80141000`, while static data into $80140000`(?). If the value iszero, the file is a raw file so no decompression is involved.
- fs-or-xy: If `wdthand `hghtarezero, read as a 4-byte word for file size. Essentially, how many bytes to decompress (or read if it's a raw file). If `wdthand`hghtare nonzero, read as two 2-byte words for X and Y coordinatesfor the spot where to start writing the data in VRAM.
- wwww: If nonzero, the width of thegraphic to write in VRAM.
- hhhh: If nonzero, the height of the graphic to write in VRAM.
The LDARtool does exactly this; it takes an LDAR file as input, makes a folder for the entry, reads the byte groups and acts accordingly; reading files and decompressing them into the folder until a terminator is found, after which a new folder is created and the next set of byte groups is scoured through. This repeats until a `00 00 00 00 AC 7F 09 80occurs. This is an unconventional and probably incorrect, but it works.
The LDARtool's output naming convention is as follows: The first folder is always called 'base' as it's the baseline files you _need_ to first get before you can do anything, really. After that, the following folders are indexed from 0 upwards in decimal. These numbers correspond to the SECTIONS found in the Areas and sections chapter.
Understanding File Links
The LDARs don't refer to filenames or use some kind of pointers, but file indexes. What that means is that whenever, say, file index $0149is called, the game looks up the entry of index $0149(or in decimal, 329) in the **File Link Array.**
- In the US version, the File Link Array is located in **the Executable** at address $699A0and contains $41Eentries. - In the JP version, it's at $634CCand contains $33Centries.
For the sake of brevity, here are the File Link Array's indexes 0 to 3. The legend is below:
mm ss SS nn fs......`_ `21 23 10 00 00001E18 21 22 59 00 00000890 21 22 61 00 0000079C 21 22 62 00 0000087C
mm: Minute
ss: Second
SS: Sector
nn: Unused
fs: File size. Essentially, how many bytes to read.
Now, the minute, second and sector alone don't tell you very much, so you must look at the ISO file itself. It would be wise to open the ISO (or BIN) in a hex editor now.
The ISO is built from exactly 119130 chunks of $930(2352 in decimal) bytes. A single chunk is called a **Sector** and consists of seven parts:
`Sync: $0C bytes Header: $04 bytes Sub-Header: $04 bytes Copy of Sub-Header: $04 bytes Data: $800 bytes EDC: $04 bytes ECC: $114 bytes
The only thing that interests us about any of the sectors is the **Header**. The header consists of four bytes: Minute, Second, Sector and Mode. While Mode can be ignored, the triplet of bytes the Sector Header's values form _is the sector the File Link Array is looking for.
So let's recap one more time:
1. LDAR calls File Index $01492. In the File Link Array, the "mm ss SStriplet" of index $0149is 00 05 733. If you were to skip through the entire ISO, one sector at a time, you would eventually find a sector that's **Header** is _also_ `00 05 73`. 4. This sector is _the_ sector that's **Data** the game reads to get what the LDAR asks for.
Notes:
- There might be (and probably is) a method of calculating the address/sector in the ISO just by the "mm ss SStriplet" alone. That's just math I never looked into.
- You can't simply go to the Data section of the sector and start reading the `fsamount of bytes, as you will hit the EDC after $800bytes. Please refer to the nocash docs if you wish to look into the issue deeper.
- You will lose filename context if you just dump yourself a list of binaries based on whatever the File Link Array tells you.
This is a convoluted process to do manually, so ISOtool helps with this a bit, by generating a plaintext file that pairs up the filenames with their file indexes automatically, albeit only for the US version for the time being.
GAMs
Most of the files in the game are compressed with the GAM compression. You can use the Japanese Ungammer to decompress any number of GAMs, but the specification is below for educational and inspirational purposes:
47 41 4D 00 / cccc / magicnumber, $00-terminated "GAM" in ASCII 00 80 00 00 / i4le / outputfilesize, ($800 here) C0 00 / i2le / commandword
must be read as binary:
0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0
(data...)
The decompression is relatively straightforward.
Shift the command word right:
- If overflowing bit is `0`, read one byte from the GAM and print it to output file. Repeat step 1 (unless it's EOF) - If overflowing bit is `1`, read _two bytes_ from the GAM as `distand `amnt`. In the output file, seek backwards `distbytes and read `amntbytes. Write them into the output. Go back to step 1 (unless it's EOF) - If all 16 bits have been shifted, read another two bytes as a commandword (unless it's EOF)
Notes:
- While a GAM decompressor has been programmed, a GAM compressor is yet to be done.
- EOF (End-Of-File) condition is true immediately when either `outputfilesizebytes have been written to output or there is no bytes in the GAM left to read.
What the LDARs give us
Using the LDARtool, we get a folders filled with several kinds of files. Although the only hint of their file _type_ is the ftpevalue in the LDAR bytegroups, research has shown us what kind of files these values represent. Some original filetype extensions could also be determined. Below is a non-exhaustive list of all known filetypes and their `ftpevalues:
Areas and Sections
AREAs are what the game indexes the AREA folders by, and they correspond to the following areas in the game. Every AREA has a varying amount of SECTIONs, and you can access them with the level select debug mode. SECTIONs are also what the LDAR entries correspond to.
00: Village of All Beginnings
00: Village of All Beginnings 01: Forest of All Beginnings 02: Forest of All Beginnings (hut entrance) 03: 100 Year Old Man's Hut 04: Behind the Hut 05: Ol' Pond
01: Dwarf Forest
00: Forest of 100 Flowers 01: Forest of 100 Flowers (right entrance) 02: Wobbly Wharf 03: Watch Tower 04: Charity Square
02: Dwarf village
00: Dwarf village 01: Dwarf Elder's Hut 02: Underground Prison 03: Underground Maze 04: Million Year Old Man's Room 05: The Strange Small Room
03: Phoenix mountain
00: Stormy Mountain 01: Stormy Mountain (second part) 02: Lava Caves 03: Phoenix's nest 04: Stormy Mountain (purified) 05: Stormy Mountain (purified, second part)
04: Haunted Mansion
00: North Side of Mansion 01: West Side of Mansion 02: South Side of Mansion 03: East Side of Mansion 04: Sunny Room 05: Thief's Room One 06: Swimming Room 07: Keyhole Room 08: Hiding Room 09: Room of Tribulation 10: Laughing Room 11: Civilization Room 12: Trap Room 13: Trick Room 14: Sun Torch Stand 15: 1,000 Year Old Man's Room 16: Shadow Room 17: Thief's Room Two 18: Thief's Room Three 19: Crying Room
05: Baccus Village
00: Baccus Village 01: Central Park 02: Baccus Village 03: Central Park
06: Motocross segment
00: Dirt Motocross 01: The Mermaid's Singing Rock (beach) 02: The Mermaid's Singing Rock (mermaid)
07: Dwarf Forest (purified)
00: Forest of 100 Flowers 01: Forest of 100 Flowers (right entrance) 02: Wobbly Wharf 03: Watch Tower 04: Charity Square
08: Baccus Lake
00: Baccus Pier 01: Baccus Lake 02: Baccus Pier 03: Baccus Lake
09: Mushroom village
00: Mushroom Forest 01: Lake 02: Mansion (Grandfather clock room) 03: Mansion (Chandelier room) 04: Mansion (descending stairs) 05: Mansion (ascending stairs) 06: Leaf Slider
10: Deep Jungle
00: Masakari Jungle 01: Masakari River 02: Old Tree Hill 03: Trick Village 04: Masakari Jungle (purified) 05: Masakari River (purified) 06: Old Tree Hill (purified) 07: Trick Village (purified) 08: 10,000 Year Old Man's Room
11: Village of Civilization
00: Lumberjack Town (crashes/soft locks the game) 01: Lumberjack Factory 02: Dried Wishing Well
12: Haunted Mansion (purified)
00: North Side of Mansion 01: West Side of Mansion 02: South Side of Mansion 03: East Side of Mansion 04: Sunny Room 05: Thief's Room One 06: Swimming Room 07: Keyhole Room 08: Hiding Room 09: Room of Tribulation 10: Laughing Room 11: Civilization Room 12: Trap Room 13: Trick Room 14: Sun Torch Stand 15: 1,000 Year Old Man's Room 16: Shadow Room 17: Thief's Room Two 18: Thief's Room Three 19: Crying Room
13: Pig Island
00: Outer Walls of Pig Island (Flower Tower) 01: x Year Old Men Ending
14: Evil Pigs
00: Evil Pig Area One 01: Evil Pig Area Two 02: Evil Pig Area Three 03: Evil Pig Area Four 04: Evil Pig Area Five 05: Evil Pig Area Six 06: Evil Pig Area Seven 07: Evil Pig Area Eight
16: Village of Civilization (Clock Tower)
00: Stonestown (soft locks the game) 01: Clock Tower (soft locks the game) 02: Clock Tower (crash) 03: Clock Tower (Engine room) 04: Clock Tower (Entrance) 05: Clock Tower (Halfway up) 06: Clock Tower (Engine room, no exit)
17: Village of Civilization (Iron Tower)
00: Iron Town (crashes the game) 01: Iron Castle (entrance) 02: Iron Castle (main room) 03: Iron Castle (left room) 04: Iron Castle (right room) 05: Iron Castle (engine room) 06: Iron Castle (soft lock) 06: Iron Castle (soft lock) 07: Iron Castle (soft lock) 08: Iron Castle (crashes the game) 09: Iron Castle (soft lock, "Y Crossing" music plays) 10: Iron Castle (soft lock, "Witch's Hut" music plays)
18: Village of Civilization (Y Crossing)
00: Village of Civilization (crash/soft lock) 01: Y crossing 02: Witch's Hut
19: Village of Civilization (Purified Dwarf village / Hidden Village)
00: Dwarf Elder's Hut 01: Dwarf Elder's Hut 02: Hidden Village