Jump to content

Tokimeki Memorial 3 ATP files


Recommended Posts

I'm currently in the early steps of a translation project for Tokimeki Memorial 3: Yakusoku No Ano Basho De. Right now I am making a tool for extracting the game's script.

I have extracted the file system from the .iso. It has five .BIN files which contain all of the game's assets. At first I extracted text from Data5.BIN, as it contained uncompressed text that simply needed to be filtered from the other data. This text is almost exclusively for menus, which means the dialogue must be stored in the other .BIN files.

When viewed in a hex editor, it becomes clear that the other data files (Data1.BIN - Data4.BIN) contain a large amount of compressed files with the header ATP. I know some of these contain dialog, because I can see scattered bits of Shift-JIS strings, some of which line up with dialogue I've seen in-game.

Using a combination of the PCSX2 debugger and Ghidra I was able to identify where the compressed files are stored in memory when they are loaded off the disk and the function that is responsible for decompressing them. I've recreated this function in my toolset and it runs/exits without crashing but I don't think the decompression is working. It seems to have the following issues:

  • Sometimes there are no changes between the compressed and "decompressed" ATP file (it's possible that this means the file's content was never actually compressed to begin with)
  • Oftentimes the strings appear more jumped in the "decompressed" version than the compressed version.
  • It doesn't stop when it needs to, running into the next ATP file and stopping halfway through "decompressing" that.

 

Here's the assembly function taken from the PCSX2 disassembler:

lbu a3,0x0(a0)
addiu a0,a0,0x1
daddu t1,a1,zero
addiu t0,zero,0x8
bne t0,zero,0x001E93F8
andi v0,a3,0x0001
lbu a3,0x0(a0)
addiu a0,a0,0x1
addiu t0,zero,0x8
andi v0,a3,0x0001
bne v0,zero,0x001E9418
addiu t0,t0,-0x1
lbu v0,0x0(a0)
addiu a0,a0,0x1
srl a3,a3,0x01
sb v0,0x0(a1)
beq zero,zero,0x001E93E0
addiu a1,a1,0x1
bne t0,zero,0x001E942C
srl a3,a3,0x01
lbu a3,0x0(a0)
addiu a0,a0,0x1
addiu t0,zero,0x8
andi v0,a3,0x0001
beql v0,zero,0x001E9498
lbu v0,0x0(a0)
addiu t0,t0,-0x1
bne t0,zero,0x001E9450
srl a3,a3,0x01
lbu a3,0x0(a0)
addiu a0,a0,0x1
addiu t0,zero,0x8
andi v0,a3,0x0001
srl a3,a3,0x01
addiu t0,t0,-0x1
bne t0,zero,0x001E9470
sll a2,v0,0x01
lbu a3,0x0(a0)
addiu a0,a0,0x1
addiu t0,zero,0x8
andi v0,a3,0x0001
srl a3,a3,0x01
lbu v1,0x0(a0)
addiu a0,a0,0x1
addu v0,a2,v0
addiu t0,t0,-0x1
bne v1,zero,0x001E94E0
addiu a2,v0,0x2
beq zero,zero,0x001E94E0
addiu v1,zero,0x100
addiu a0,a0,0x1
lbu v1,0x0(a0)
addiu a0,a0,0x1
sll v0,v0,0x08
srl a3,a3,0x01
or v1,v0,v1
beq v1,zero,0x001E9510
addiu t0,t0,-0x1
andi a2,v1,0x000F
beq a2,zero,0x001E94D0
addiu a2,a2,0x2
beq zero,zero,0x001E94E0
srl v1,v1,0x04
nop 
lbu v0,0x0(a0)
addiu a0,a0,0x1
srl v1,v1,0x04
addiu a2,v0,0x1
beq a2,zero,0x001E93E0
subu v1,a1,v1
lbu v0,0x0(v1)
addiu v1,v1,0x1
addiu a2,a2,-0x1
sb v0,0x0(a1)
nop 
bne a2,zero,0x001E94E8
addiu a1,a1,0x1
beq zero,zero,0x001E93E0
nop 
nop 
jr ra
subu v0,a1,t1

 

and here's my attempt to recreate it for my tool set . I apologize in advance for the poor readability

public static void DecodeATP(int startAddress, byte[] byteArray, String outputPath)
        {
            //Note to self: when implementing this, use integers that refer to indexes on the array as "pointers"
            //Use labels and gotos for the parts
            byte[] destination = new byte[byteArray.Length];
            

            uint sourcePointer = (uint) startAddress + 8; //a0 in the assembly, skips 8 to avoid the ATP file header
            

            //set up a few variables to take the place of some registers in the original assembly
            
           
            uint v0 = 0x0;
            uint v1 = 0x0;
            
            uint a2 = 0x0;
            

            byte previousByte = byteArray[sourcePointer];
            sourcePointer++;
            uint destinationPointer = 0;
            uint counter = 8;
            byte buffer;

            Part1:
            	//Part1
           		v0 = (byte)(previousByte & 0x1);
            	if (counter == 0)
            	{
                
                	previousByte = byteArray[sourcePointer];
                	sourcePointer++;
                	counter = 8;
            	}
            	else
            	{
            	    goto Part2;
            	}

            Part2:
            //Part2
            	counter--;
            	if (v0 == 0x0)
            	{
                

                	buffer = byteArray[sourcePointer];
                	sourcePointer++;
                	previousByte = (byte)(previousByte >> 0x1);
                	destination[destinationPointer] = buffer;
                	destinationPointer++;
                	goto Part1;
            	}
            	else
            	{
                	goto Part3;
            	}

            Part3:
            //Part3
            	previousByte = (byte)(previousByte >> 0x1);
            	if (counter == 0)
            	{
                
                	previousByte = byteArray[sourcePointer];
                	sourcePointer++;
                	counter = 8;
            	}
            	else
            	{
                	goto Part4;
            	}

            Part4:
            //Part4
            	v0 = (byte)(previousByte & 0x1);
            	v0 = byteArray[sourcePointer]; 
            	if (v0 == 0x0)
            	{
                	goto Part7;
            	}
            	else
            	{
                
                	counter--;
                	previousByte = (byte)(previousByte >> 0x1); 
                	if (counter != 0){
                    	goto Part5;
                	}
                
                	previousByte = byteArray[sourcePointer];
                	sourcePointer++;
                	counter = 8;
                	goto Part5;

            	}

            Part5:
            //Part5
            	v0 = (byte)(previousByte & 0x1);
            	previousByte = (byte)(previousByte >> 0x1);
            	counter--;
            	a2 = (byte)(v0 << 0x1);
            	if (counter != 0)
            	{
                	goto Part6;
            	}
            	else
            	{
               
                	previousByte = byteArray[sourcePointer];
                	sourcePointer++;
                	counter = 8;
                	goto Part6;

            	}

            Part6:
            //Part6
            	v0 = (byte)(previousByte & 0x1);
            	previousByte = (byte)(previousByte >> 0x1);
            	v1 = byteArray[sourcePointer];
            	sourcePointer++;
            	v0 = (byte)(a2 + v0);
            	counter--;

            	a2 = (byte)(v0 + 0x2);
            	if (v1 == 0)
            	{
                
                	v1 = 0x100;
                
            	}
            	goto Part9;

        Part7:
            //Part7
            	sourcePointer++;
            	v1 = byteArray[sourcePointer];
            	sourcePointer++;
            	v0 = (byte)(v0 << 8);
            	previousByte = (byte)(previousByte >> 0x1);
            	v1 = (byte)(v0 | v1);
            	counter--;
            	if (v1 == 0x0)
            	{
                	goto Part11;
            	}
            	else
            	{
                
                	a2 = (byte)(v1 & 0xf);
                	a2 = a2 + 0x2;
                	if(a2 == 0x0)
                	{
                    	goto Part8;
                	}
                	else
                	{
                    	v1  = (v1 >> 0x4);
                    	goto Part9;
                	}
                
            	}


            Part8:
            //Part8
            	v0 = byteArray[sourcePointer];
            	sourcePointer++;
            	v1 = (byte)(v1 >> 4);
            	a2 = (byte)(v0 + 1);
            	goto Part9;
            
            Part9:
            //Part9
            	v1 = (byte)(destinationPointer - v1);
            	if (a2 == 0)
            	{
                	goto Part1;
            	}
            	else
            	{
                
                	goto Part10;
            	}

            Part10:
            //Part10
            	v0 = byteArray[v1];
            	v1++;
            	a2--;
            	destination[destinationPointer] = (byte)v0;
            	destinationPointer++;
            	if (a2 != 0x0)
            	{
                	goto Part10;
            	}
            	else
            	{
                
                	goto Part1;
            	}



        Part11:

            destination = SubArray(0, (int)destinationPointer, byteArray);
            File.WriteAllBytes(outputPath, destination);
            return;

        }

Could anyone help me identify where the problem is?

Edited by ShortenedName
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...