01-24-2024, 07:37 AM
I can see why this game trip you up. I don't think I saw this kind of compression algorithm before. But I have a good understanding of it now.
Let's use an example for a start, you want to duplicate 0xC9 for 0x40 times. First you use method 6 for 0x1f+2 bytes, so you'll get "DF C9". For the remaining 0x1f bytes, you repeat the last command, or method 0, but with length 0x1d+2 instead, so you'll get "1D".
Hence, the compressed data to duplicate 0xC9 for 0x40 times is "DF C9 1D".
And the game keep the last 6 commands as history, or method 0 to 5.
The whole decompression goes:
read one byte for METHOD and LEN
if the METHOD is 6, read next byte as BYTE, and then duplicate it for LEN + 2 times to output.
if the METHOD is 7, read the next LEN + 1 bytes as STRING and output it.
For both, add it to HISTORY[0] and push the queue down.
For METHOD 0 to 5, set that as current, and re-queue everything before it. For example, METHOD 3 would
If the repeat METHOD is 6, duplicate the same BYTE but with new LEN + 2 times.
If the repeat METHOD is 7, then get SUB_POS and SUB_LEN from LEN
referring to the same STRING, output SUB_LEN + 1 bytes, starting from position SUB_POS.
That's about it.
The code has already uploaded to my github. You can run them by follow the Setup section of tutorial on my signature.
Then run
I also noticed there are 3 Zero no Tsukaima games from the same company on PS2, and they are all using the same SCENEDAT hd+bin set. So I updated the script to support all 3 of them.
Sample
Have fun!
- Rufas
Let's use an example for a start, you want to duplicate 0xC9 for 0x40 times. First you use method 6 for 0x1f+2 bytes, so you'll get "DF C9". For the remaining 0x1f bytes, you repeat the last command, or method 0, but with length 0x1d+2 instead, so you'll get "1D".
Hence, the compressed data to duplicate 0xC9 for 0x40 times is "DF C9 1D".
And the game keep the last 6 commands as history, or method 0 to 5.
The whole decompression goes:
read one byte for METHOD and LEN
Code:
METHOD = BYTE >> 5
LEN = BYTE & 0x1f
if the METHOD is 6, read next byte as BYTE, and then duplicate it for LEN + 2 times to output.
if the METHOD is 7, read the next LEN + 1 bytes as STRING and output it.
For both, add it to HISTORY[0] and push the queue down.
Code:
HISTORY[5] = HISTORY[4]
HISTORY[4] = HISTORY[3]
HISTORY[3] = HISTORY[2]
HISTORY[2] = HISTORY[1]
HISTORY[1] = HISTORY[0]
HISTORY[0] = current
For METHOD 0 to 5, set that as current, and re-queue everything before it. For example, METHOD 3 would
Code:
HISTORY[5] // do nothing
HISTORY[4] // do nothing
current = HISTORY[3]
HISTORY[3] = HISTORY[2] // re-queue
HISTORY[2] = HISTORY[1] // re-queue
HISTORY[1] = HISTORY[0] // re-queue
HISTORY[0] = current // re-queue
If the repeat METHOD is 6, duplicate the same BYTE but with new LEN + 2 times.
If the repeat METHOD is 7, then get SUB_POS and SUB_LEN from LEN
Code:
SUB_POS = LEN >> 2
SUB_LEN = LEN & 3
That's about it.
The code has already uploaded to my github. You can run them by follow the Setup section of tutorial on my signature.
Then run
Code:
php psxtools/ps2_zero_hd-bin.php SCENEDAT.hd
I also noticed there are 3 Zero no Tsukaima games from the same company on PS2, and they are all using the same SCENEDAT hd+bin set. So I updated the script to support all 3 of them.
Sample
Have fun!
- Rufas