There are currently two patches available with this repository:
This is a complete Undub of Tales of Legendia with the original Japanese voices restored for the second half of the game
This is the Partial Undub of Tales of Legendia with the original Japanese voices restored for the second half of the game while retaining the English Dub for the first half of the game, in cutscenes and during combat.
Credits:
- somebody special (for the original Undub)
- Julian
- Trixarian
- Ethanol
Swapping out voice files from English to Japanese is easy. Find the corresponding AFS archive, move it over, copy the corresponding MBS (contains decompressed file sizes), and update the corresponding record in PTN_INFO.BIN. (contains number of files inside AFS archive)
So, why does the game still not play Character Quest voices when you do that and restore everything?
The answer, this time, is pretty simple. First, we start by looking at the game script files, loaded into memory:
That 0x05 at the start here indicates the voice clip index.
The first thing to check - does the script for character quests contain the voice clip id?
The answer, with a huge sigh of relief, is-- yes. That 0x2716 is the voice clip id for that line.
The voice clip id is in the script. Why doesn't it play?
Knowing where the id is being read from, it's super easy to trace and see when the game loads the id, and what it does with it.
We immediately get a hit, and we see it being read, and then written into memory.
Setting a breakpoint at the address being written to, we find something interesting.
The id is loaded once, it calls a function, if that function returns 0 it skips the second function and goes to the end, not playing anything. This is the behavior seen when playing character quest lines. So that first function call is likely doing something that tells the game there's nothing to play. Let's investigate.
Two functions to look at. The first one:
And the second:
The first one we can tell pretty easily it's getting some value from a table. The voice clip id is taken, shifted left twice (multiply by 4, as each entry in the table is 4 bytes), and added to some value in memory, aka the start of the table, and then add 0x10 for I suppose a header. Lastly the value from the table is shifted right twice. (Divide by 4)
The second function is straight forward, the decompiled function says it all:
return a1 != 0x2023e
So.. a value of 0x2023e seems to indicate an invalid value that is skipped.
When we look at the table accessed from the first function, we find it full of 0x0808F9:
0x0808F9 shifted right twice = 0x2023e. A-ha!
So... what happens when we edit the table to use the one loaded by the Japanese version? It works! But now, the last remaining challenge is finding this table in the game files so we can replace it.
Setting a write breakpoint at the start of the table, we find a function that is writing it. A closer look, we see it takes two parameters, a0 and a1. a1 is the destination where the file was written to, and a0 looked like the original compressed file. A quick search for it, and we find it's the first file in the SYS_REG.AFS archive.
The question now is decompressing and re-compressing it. With a ton of help from Ethanol, we determined it was a zeroed buffer LZSS. We decompress the file, and the content matched what we saw in the game. Decompress both NA and JP, find the table, replace NA table with JP table. Re-compress, add CPS header back, rebuild the AFS, rebuild the game, and mission accomplished. 😎
(Note: There is a... probably a somewhat decent chance, that the NA script might have moved voice id's around? Maybe? If anyone notices something wrong please report so we can look into it.)