Romhacking in Tales of Destiny 2
So once again I open a romhacking thread surprised after finding absolutely no interest by the fanbase in a game translation project that has been requested quite a lot of time ¿"?...
I'm talking about Tales of Destiny 2 (available for both PSP and PS2). Several weeks ago I hacked it (again) and tweeted to see how good reception would be for the project. Believe or not it was pretty bad: only a few people answered and I even lost many followers right after tweeting xDD.
That being said, I'm posting some romhacking stuff here, mostly so everything done wasn't a waste of time.
Just like with Type-0, this is not a recruitment thread, but if someone forms a translation team they can count with my help. As of now, there are no plans of going forward with the translation (at least into English, there are some people interested in translating the game into Spanish), so I'm pretty much leaving the last chance in the hands of the fans, once again.
So, getting started: Both versions of the game works exactly the same way, regardless of the content (that was updated in the PSP version) so unless stated otherwise, everything said here applies for both PSP and PS2 versions.
The first thing is, of course, having a look at the game's files. Right after opening the disc (or a disc image) we can see:
-The game's executable file (the ELF)
-A big file, "file.fbp" containing most of the game ressources
As you can guess, video files are just pre rendered scenes, with voice over and no subtitles at all.
They are pretty easy to edit so inserting subtitles is perfectly possible.
Then we have the big FBP file. This one does not include information to unpack the files inside. Instead, we need to check the executable for it. Inside the ELF there is a pointer table that specifies all file offsets in the FBP file, along with some flags:
Each entry of the able consist in:
- A 21 bit offset -> the file offset inside the FBP
- 11 bits for flags -> Compression, file type, etc...
In order to extract the big file, one would calculate each file size based on the next file's offset. That is enough to extract the whole FBP. Reverting the process it would be easy to repack it.
Once extracted all files we can see the game's raw resources in some custom formats.
The very first file in the package follows the basic data structure used for compressed files in ToD2:
- 1 byte -> compression ID
*** 0x00 For uncompressed files
*** 0x01 For LZSS
*** 0x03 For LZSS + RLE
*** 0x04 For ZLIB (PSP Only)
- 4 bytes -> compressed size
- 4 bytes -> uncompressed size
- Rest of the data -> File data
Does that ring a bell? This is very similar to many other old school JRPG's, where LZSS and RLE are mixed (many SNES, N64, and pretty much all Tri-Ace game do this, we are only missing huffman in ToD2 ).
One peculiarity is that the data is not 32-bit aligned. How could a 32 bit MIPS processor read this? Believe it or not, the game's ASM code shows that it read byte per byte, storing them in the stack in aligned positions, and then read the 32 bit integer from the stack. This shows that the game was coded keeping memory optimization in mind.
After decompressing the file, we obtain some raw data that appears to follow the pattern of a 8 bit graphic.
We can try giving it X and Y sizes, and a grayscale palette, we then unswizzle it and... VOILA! IT'S THE FONT!
It incudes a TON of characters, but no lowercase letter except for some at the bottom (does the PS2 version have eyetoy functionality? If it doesn't it was clearly planned at some point).
The second file in the FBP is a raw shift-jis buffer, easy to decode:
It enumerates all charecters present in the font, so it's most likelly a conversion table used in development stages of the game, to convert the text into the game's custom text encoding. It will come in handy.
In many other project (such as Type-0, Valkyrie Profile, FF4, Star Ocean 1&2, etc...), we didn't have this, and it was necessary to transcribe the font to have it as text (which is some crazy job btw...)
This is everything we need to edit the font. It's actually a must, since we have to add lowercase letters xD.
But what about the rest of the files? Where is the game's script?. In order to find it, we need to dig into some other files, the so-called SCPK files.
SCPK's are "game rooms": individual compiled scripts written in a custom language that manage the game's logic.
I call it rooms because they are are stored in a per-place basis, so you'll always find a SPCK file per game location.
One SCPK will have the code for all events in a given, regardless of the game timeline, as well as all assets present in that place. Again, this "room scheme" is pretty common in old school JRPG games.
Having a look at the data structure, each SCPK file consists on:
- A 4 byte signature "SCPK"
- Two 2 byte integers: Major and minor version numbers (always 0x01 and 0x07).
- A 4 byte integer: number of files packed in the SCPK
- 32 bit padding.
- An integer array: packed files sizes, so it's size is always <number_of_packed_files * 4>
- Packed files, with specified sizes
*** The first file contains the BG graphic data + BG animation data + BG animation code, for example:
*** The second file is always a set of ID's one per remaining file*** The rest of files, except for the last one contain sprite data (character + effects) and animation code.
*** The last file includes the room logic + text script. As I said, it uses a custom language, that the game's interpreter runs. Once again, this happens in many classic JRPG's. In fact, in some cases, fans have been able to understand the custom language and create a fan sequel using the original engine (This is the case of Chrono Trigger: Crimson Echoes).
This last code file (being compiled code) has a complex structure, but since it includes text, there is no choice but to disassemble it; it has:
- 4 bytes: the signature: "SCED"
- A 32 bit value that points to the start of the code section
- Another 32 bit value, this time pointing to the text section
- More pointers until getting to the code section
- The code section itself, it ranges from its pointer to the text sextion pointer
- The text section itself, it ranges from its pointer to the end of the file
A couple of problems here:
-The text uses an incomprehensible encoding, that mixes 8 and 16 bit characters (-_-").
-There are no actual text pointers, but size is limited and not constant... That's because the text position is specified by compiled pointers in the code section... LOL, this hobby can be a pain sometimes xD.
Okay the way to do this is to isolate both the code and the text sections. We case see that the text seems to be separated by byte 0x00, so that would be the end of an intervention (and right after it, the start of the next one):
Knowing where all text interventions start and end, we can look for their offsets in the code sections and... TADA!!
We can find text offsets in the code section of the SCED! Always preceded by byte 0xf8. This is because the code section is an array of "commands".
Each command has:
- A 1 byte opcode
- Several bytes: the operand(s)
For example, opcode 0xf8 means "Open text window" and it uses a 2 byte operand: the text pointer. If we managed to understand all opcodes we could use the game engine to build our own sequel, for example ()"
Still a couple of issues, though
1 - Since opcodes have different size operands, how can we parse the code section to find pointers?
***Possible answer A (dirty one): We just look for the 0xf8 byte in the code section, that's followed by a valid intervention in the text section (e.g. is preceeded by byte 0x00).
***Possible answer B (clean one): We disassemble the SCED interpreter's native MIPS code and write down all possible opcode and operand sizes.
*In the above image, the opcode is located in registry $v1, the code jumps to different places deppending on it's value. In this case $v1 contains the value 0xf8 so it will jump to 0x8951de0, where it'll read two bytes as operand. watching the rest of possible jumps we can know the operand size for each opcode ^^.
As a matter of fact there are several opcodes that configure text appearance, so it's possible to change the text's colors (there are 8 palettes available), it's oppacity, it's x/y offset within the window, it's whith/height, and a long etc... As for window sizes and shapes, they are automatic based on the text to appear on them.
2 - We still don't have a clue about the custom text encoding, how the heck could we edit it?
***Possible answer A (dirty one): We build a table having a look at the raw data and the game's result
***Possible answer B (clean one): We disassemble the tex-decoding routine and implement it. Just like in Type-0 (and many other JRPG games) the result is the position of the character in the font, and since we already have its transcription, we can decode the custom encoding.
*** BTW, the text decoding routine supports ASCII, so upper case letters can be written directly, as for lowercase, the easiest method would be replacing some one-byte hiras in the font
I did several tests of everything after recreating a lowercase font (based on the original typography) and updating the encoding descriptor file:
And that's pretty much it... There are some other interesting files in the game that I already decoded. For example, sound is coded in a pretty simple way, so the game could be dubbed... But since this is already a long post, and it kinda covers the interesting aspects of a possible project, I think I'm just gonna hit that "Create Thread" button and call it a day.