Hacking [PSP] La Pucelle Ragnarok Translation

Cyberdrive

Well-Known Member
Member
Joined
Aug 6, 2013
Messages
141
Trophies
0
XP
181
Country
Serbia, Republic of
START_JP.LZS has some fonts. The thing is, it's compressed with some variant of LZSS, and I don't know any tools made to handle this specific one. We can take the uncompressed file from PSP RAM though. Search for "anim0000.dat" in the RAM dump made by Jpcsp or PPSSPP emulators. I have it at 0x450300 with its size (11629612 bytes) prepended as a DWORD. It has a file table of 1168 bytes containing 36 entries, each entry consisting of starting ending offset of the file in the START_JP container and file name, offsets are relative to the end of the file table.
Edit: the first file starts immediately after the file table (at 1168) and all other files immediately follow each other without any padding.

FontB0000.txp FontB0001.txp is the pictured font file, it's located at (0xAF1CC0 + 1168) = 0xAF2150 and ends at the start of the next file, taking up 132112 bytes. It has 16-byte header, followed by 256-color 32-bit palette (256*4=1024 bytes) and raw image data.
LZSS recompression is not necessary. Edit: because of the method used by the game to decompress the file, recompression is required until a way to avoid it is found.
There's an empty 250MB DUMMY_DATA file in the ISO which can be used as a container for all modified files (leaving original files untouched) by cross-linking its parts with them, I don't think that the game uses LBA addressing.

The main text is stored in SCRIPTPACK.DAT container. The very first message on the beginning of the new game (line 1: "あ〜、クソッ!", line 2: " ムカツクっ!!") is located in talk01_jp.dat file inside the SCRIPTPACK container (.dat is at 0x247800 of .DAT, see the last entry of DAT file table), at 0x1B727.
Every character's message can contain up to 3 lines, they are stored as 64-byte long null-padded text strings in Shift-JIS encoding at (PSP RAM addressing) 0x1FC158, 0x1FC199 and 0x1FC1DA respectively. This can be used to hook this text and translate it on the fly.
 

Attachments

  • FontB0000.png
    FontB0000.png
    96.5 KB · Views: 894

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I have a tool that can decompress that file START_JP.LZS. It is called NISDecmp.exe It works but the issue I may have is that I have no idea how to compress it back into a format that the game can read.

I also finally got an PSP emulator working so that I do not have to keep loading the iso onto my PSP to troubleshoot my hex edits. I am using PPSSPP.

I have made some more progress on the menus. Here are some more screenshots:

ltwm.jpg

-ChepChep
 

Cyberdrive

Well-Known Member
Member
Joined
Aug 6, 2013
Messages
141
Trophies
0
XP
181
Country
Serbia, Republic of
It is called NISDecmp.exe It works but the issue I may have is that I have no idea how to compress it back into a format that the game can read.
As I have already said, recompression is not needed. Edit: currently it is needed. LZSS has control bytes which indicate whether the following bytes are compressed or not; just set them all to "literal" aka uncompressed. For traditional LZSS implementation it means that you insert 0xFF control byte every 18 bytes of source data to make it look "compressed" to decompression algorithm, that's all. This implementation is a bit different, but principle should be the same.
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I am still struggling to get the start_jp.dat file back into LZS format that will not crash PSP emulator or PSP. Any ideas?

-Steve
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I tried to "compress" the file by adding a new line at the top of the START_JP.dat
64 61 74 00 10 74 B1 00 0C 74 B1 00 FF 00 00

- bytes 0x0 to 0x2: the expected extension of the decompressed file
- byte 0x3: should be '\0'
- bytes 0x4 to 0x7 (little endian uint32): decompressed file size
- bytes 0x8 to 0xb (little endian uint32): (compressed file size) - 4
- bytes 0xc to 0xf (little endian uint32): flag value; must be less than 255, which means that bytes 0xd to 0xf are always "\0\0\0"

I set 0xC to 0XFF to make it look compressed and it works fine for the emulator but when I drop the iso on the psp it crashes on the loading screen.

Any ideas?


-ChepChep
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I made a tool using python to "compress" the .dat files to LZS. I am close to having it working. I just need to figure out the header and spacing of the control byte.

I will post source once I have it completed and working.

-ChepChep
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
So I am about ready to start going at this from a different angle. I am first going to write a program to decompress the LZS format and then try to write a program that will compress it based on the things I learn from decompressing. It should not be too hard to write the decompressor but the compressor will be more difficult.

I have posted up some of the code I have already written. It can be found here:
http://www.tarranoth.com/LPR/LZS_Compress_v1.py

I am using Python 2.7.

I do not want to continue translating in the eboot.bin or in SCRIPTPACK.dat unless I have a way to package everything back up and get it running on a PSP. Cracking this format for LPR is really the only major hurtle I see for translating this game beside putting in time to actually translate the game.

If anyone has any insight on LZS please let me know.

Thanks,
-ChepChep
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I got the LZS decompressor working and compared the output to NISDecmp.exe
http://www.tarranoth.com/LPR/NISDecmp.exe

The byte to byte comparison between the output of START_JP.dat from START_JP.LZS is bye identical between the two decompressors.

Here is the python code I wrote. I used python 2.7

http://www.tarranoth.com/LPR/LZS_Decompress_v2.py

I am going to start now trying to write a compressor but I expect it to take significant time.
-ChepChep

Code in Spoiler

#################################################################
# LZS_Decompress_v2.py
#################################################################
# Built to decompress LZS format for La Pucelle: Ragnaraok [JPN]
# Run with python 2.7
# Last Update: 09/05/2013
#################################################################

import math
import struct
import time
import copy

fileName = "START_JP.LZS"
fileName1 = "START_JP.dat"

dTestTime = 0.0
dStartTime = time.clock()

# Open file to convert
f = open(fileName, 'rb')
f1 = open(fileName1, 'wb')

slideWindow =[]
f.seek(12)
delimiter = hex(ord(f.read(1)))
f.seek(16)
byte = f.read(1)

print delimiter
print byte

while byte != "":
try:
if hex(ord(byte)) == delimiter:
byte1 = f.read(1)
if hex(ord(byte1)) == delimiter:
f1.write(byte)
slideWindow.append(byte)
if len(slideWindow) > 254:
slideWindow.pop(0)
else:
byte2 = f.read(1)
location = ord(byte1)
if location > 213:
location = location - 1
ran = ord(byte2)

slideWindowTemp = copy.copy(slideWindow)

for i in range(ran):
value = slideWindowTemp[len(slideWindowTemp)-location+i]
f1.write(value)
slideWindow.append(value)
if len(slideWindow) > 254:
slideWindow.pop(0)
else:
f1.write(byte)
slideWindow.append(byte)
if len(slideWindow) > 254:
slideWindow.pop(0)
byte = f.read(1)

except:
pass
f.close()
f1.close()

dTestTime = time.clock() - dStartTime
print
print "Total Test Time = %.3f sec" % dTestTime
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
If anyone want to try the translation follow these instructions:

LPR_translation_v0.0.1 (Menu and Names)

1) Acquire PSP La Pucelle Ragnarok ISO
2) Download EBOOT.BIN - www.tarranoth.com/LPR/EBOOT.BIN
3) Download START_JP.LZS - www.tarranoth.com/LPR/START_JP.LZS
4) Backup ISO, EBOOT.BIN and START_JP.LZS
5) Extract files from LPR ISO using UMDGen
6) Replace EBOOT.BIN in \PSP_GAME\SYSDIR\ with the downloaded EBOOT.BIN
7) Replace START_JP.LZS in \PSP_GAME\USRDIR\ with the downloaded START_JP.LZS
8) Create a new LPR ISO with UMDGen
9) Either use a PSP emulator or download to PSP and enjoy

Note: You must have CFW in order to play the translated ISO on a PSP
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I have some good new and bad news about the LZS compressor. I got it working and can compress files into LZS format used by LPR. The bad news is that right now the code is not very efficient and will take about 800 hours to compress START_JP.LZS. I obviously need to make it more efficient. Also right now I am running it on a crappy Intel Atom CPU. The compression time should significantly decrease if I run it on a computer with a "real" CPU. The part of the code that takes so long is where I search a list for arrays of numbers to compress. I may be able to speed it up by converting everything to strings and then searching that way.

-ChepChep
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I got the compression time down to about 10 hours from 800 hours. Still trying to figure out ways to speed the encoding up. I am sure there are other ways to get it below an hour.

-ChepChep
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I got the encoding time reduced even more. I got it down now to about 20 minutes. I still need to "package" the header part of the LZS file but hopefully tonight I will post code for a LZS compressor for LPR.

-ChepChep
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
So I got the LZS compressor working and it will encode an LZS file in about 22 minutes. I have compressed START_JP.dat and confirmed the file works on the PSP. I will now try making a change to START_JP.dat, compress the files to LZS and try running it on the PSP.

Once I am done with that I am going to try to find the file with all the characters names and translate them and also some on the skills and items. Pretty sure they are in the START_JP.dat.

Here is the code I used:
http://www.tarranoth.com/LPR/LZS_Compress_v4.py

Code in spoiler:

######################################################################
# LZS_Compress_v4.py
######################################################################
# Built to compress files into LZS format for La Pucelle: Ragnaraok [JPN]
# Run with python 2.7
# Last Update: 09/09/2013
######################################################################

import math
import struct
import time
import copy
import os

fileName = "START_JP.dat"
fileName1 = "START_JP.LZS"

dTestTime = 0.0
dStartTime = time.time()
bytesCompressed = 0
fileSizeUncompressed = 0

# Open file to convert
f = open(fileName, 'rb')
f1 = open(fileName1, 'wb')

delimiter = 213
minCompress = 4
writerPointer = 0
slideBuffer = []

# Write Header Bits for LZS file format

##- bytes 0x0 to 0x2: the expected extension of the decompressed file
f1.write('d') # byte 0x0
f1.write('a') # byte 0x1
f1.write('t') # byte 0x2

##- byte 0x3: should be '\0'
f1.write(chr(0)) # byte 0x3

##- bytes 0x4 to 0x7 (little endian uint32): decompressed file size
# Calculate length of uncompressed file and put into litle endian uint32
fileSizeUncompressed = os.path.getsize(fileName)
fileSize = struct.pack('<I',fileSizeUncompressed).encode('hex')

f1.write(chr(int(fileSize[0:2],16))) # byte 0x4
f1.write(chr(int(fileSize[2:4],16))) # byte 0x5
f1.write(chr(int(fileSize[4:6],16))) # byte 0x6
f1.write(chr(int(fileSize[6:8],16))) # byte 0x7

##- bytes 0x8 to 0xB (little endian uint32): (compressed file size) - 4
# Dummy values to be overwritten later
f1.write(chr(0)) # byte 0x8
f1.write(chr(0)) # byte 0x9
f1.write(chr(0)) # byte 0xA
f1.write(chr(0)) # byte 0xB

##- bytes 0xC to 0xF (little endian uint32): flag value; must be less than 255, which means that bytes 0xd to 0xf are always "\0\0\0"
f1.write(chr(213)) # byte 0xC
f1.write(chr(0)) # byte 0xD
f1.write(chr(0)) # byte 0xE
f1.write(chr(0)) # byte 0xF

bytesCompressed = 4

# End of Header bits


# Read into slideBuffer first 4 bytes
for i in range(4):
byte=f.read(1)
slideBuffer.append(ord(byte))

# Read and write first four bits since thet can never be compressed
f1.write(chr(slideBuffer[0]))
f1.write(chr(slideBuffer[1]))
f1.write(chr(slideBuffer[2]))
f1.write(chr(slideBuffer[3]))

writerPointer = 4

while byte != "":

byte = f.read(1)

if byte == "":
break
slideBuffer.append(ord(byte))

while writerPointer > 254:
slideBuffer.pop(0)
writerPointer = writerPointer - 1

sub_lists = []

for j in range(minCompress-1):
byte1 = f.read(1)
if byte1 == "":
break
slideBuffer.append(ord(byte1))

match = -1
matchLen = 0
slideBufferTemp = copy.copy(slideBuffer[0:writerPointer])

for k in range(writerPointer-minCompress+1):
if len(slideBuffer)-1 < writerPointer+minCompress+k:
byte1 = f.read(1)
if byte1 == "":
break
slideBuffer.append(ord(byte1))
try:
index_find=sub_lists.index(slideBuffer[writerPointer:writerPointer+minCompress+k])
except ValueError:
li = slideBuffer[writerPointer:writerPointer+minCompress+k]
sub_lists.append(slideBuffer[writerPointer:writerPointer+minCompress+k])
length = len(li)
matchFlag = 0
for j in range(len(slideBufferTemp)):
if slideBufferTemp[j:j+length] == li:
matchFlag = 1
if length >= matchLen:
match = j
matchLen = len(li)
if matchFlag == 0:
break

if match > -1:
indexWriter = writerPointer - match
if indexWriter > 212:
indexWriter = indexWriter + 1
rangeWriter = matchLen
writerPointer = writerPointer+rangeWriter
f1.write(chr(delimiter))
f1.write(chr(indexWriter))
f1.write(chr(rangeWriter))
bytesCompressed = bytesCompressed + rangeWriter
else:

if ord(byte) == delimiter:
f1.write(byte)
f1.write(byte)
else:
f1.write(byte)
writerPointer = writerPointer + 1
bytesCompressed = bytesCompressed + 1

while len(slideBuffer) > writerPointer:
slideBuffer.pop()
f.seek(-1,1)


if bytesCompressed%10000 == 0:
dTestTime = time.time() - dStartTime
print "%i of %i Bytes Compressed; Test Time = %.3f sec" % (bytesCompressed,fileSizeUncompressed,dTestTime)

f.close()
f1.close()

## bytes 0x8 to 0xB (little endian uint32): (compressed file size) - 4
# Calculate length of uncompressed file and put into litle endian uint32

fileSizeCompressed = os.path.getsize(fileName1)
f1 = open(fileName1, 'r+b')
f1.seek(8)

sizeComp = struct.pack('<I',fileSizeCompressed-4).encode('hex')
f1.write(chr(int(sizeComp[0:2],16))) # byte 0x8
f1.write(chr(int(sizeComp[2:4],16))) # byte 0x9
f1.write(chr(int(sizeComp[4:6],16))) # byte 0xA
f1.write(chr(int(sizeComp[6:8],16))) # byte 0xB
f1.close()

dTestTime = time.time() - dStartTime
print
print "Total Test Time = %.3f sec" % dTestTime
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I have some more good news. I was able to modify char.dat inside START_JP.dat and compress it to START_JP.LZS. I created a new LPR ISO and was able to run it on the PSP. No crashing on the load screen. It appears I have reversed engineered the algorithm used for LPR for LZS.
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I have been trying to figure out how to view the font characters. How were you able to view these fonts? I tried using the same tool on FontB0000.txp and I get nothing any hints?

I really would like to fix the font so that I do not have to use a mix of single byte and double byte characters.
 

Cyberdrive

Well-Known Member
Member
Joined
Aug 6, 2013
Messages
141
Trophies
0
XP
181
Country
Serbia, Republic of
I have been trying to figure out how to view the font characters. How were you able to view these fonts? I tried using the same tool on FontB0000.txp and I get nothing any hints?
If you followed everything I said above to the last letter and still got nothing, we're probably working with different files, because I've just repeated those steps and got the same result. Here's what I'm working with:
START_JP.LZS from Ragnarok's UMDISO: 5 045 929 bytes long, CRC32 = 1CBA28EB
START_JP.DAT that I get by using NISDecmp.exe with that .LZS: 11 629 584 bytes long, CRC32 = BCED0DFC
If you have the same .DAT as above, copy-paste the following into a new text file, and save it as START_JP.INI in the same folder with .DAT file, Texture Explorer will autoload it when you open .DAT file in it.
[items_count]
count=15
[item_0]
name=item.txp
platform=PSP
offset=11118960
width=128
height=128
BPP=4
mipmaps=-1
palette_offset=11117936
swizzling=Enabled
[item_1]
name=sys2.txp
platform=PSP
offset=11127232
width=128
height=128
BPP=4
mipmaps=-1
palette_offset=11127168
swizzling=Enabled
[item_2]
name=sys3.txp
platform=PSP
offset=11136464
width=256
height=256
BPP=4
mipmaps=-1
palette_offset=11135440
swizzling=Enabled
[item_3]
name=sys4.txp
platform=PSP
offset=11170272
width=256
height=256
BPP=4
mipmaps=-1
palette_offset=11169248
swizzling=Enabled
[item_4]
name=sys5.txp
platform=PSP
offset=11204080
width=256
height=256
BPP=4
mipmaps=-1
palette_offset=11203056
swizzling=Enabled
[item_5]
name=sys6.txp
platform=PSP
offset=11237888
width=256
height=256
BPP=8
mipmaps=-1
palette_offset=11236864
swizzling=Enabled
[item_6]
name=sys7.txp
platform=PSP
offset=11303504
width=128
height=64
BPP=4
mipmaps=-1
palette_offset=11303440
swizzling=Enabled
[item_7]
name=waku.txp
platform=PSP
offset=11307680
width=64
height=32
BPP=4
mipmaps=-1
palette_offset=11307616
swizzling=Enabled
[item_8]
name=wbg01.txp(320x224)
platform=PSP
offset=11308784
width=64
height=64
BPP=4
mipmaps=-1
palette_offset=11308720
swizzling=Enabled
[item_9]
name=wbg.txp
platform=PSP
offset=11344704
width=32
height=32
BPP=4
mipmaps=-1
palette_offset=11344640
swizzling=Enabled
[item_10]
name=FontB0000.txp
platform=PSP
offset=11346256
width=512
height=512
BPP=4
mipmaps=-1
palette_offset=11345232
swizzling=Enabled
[item_11]
name=FontB0001.txp
platform=PSP
offset=11478368
width=512
height=512
BPP=4
mipmaps=-1
palette_offset=11477344
swizzling=Enabled
[item_12]
name=panel.txp
platform=PSP
offset=11610480
width=128
height=128
BPP=8
mipmaps=-1
palette_offset=11609456
swizzling=Enabled
[item_13]
name=waku2.txp
platform=PSP
offset=11626944
width=64
height=64
BPP=4
mipmaps=-1
palette_offset=11626880
swizzling=Enabled
[item_14]
name=waku2bg.txp
platform=PSP
offset=11629072
width=32
height=32
BPP=4
mipmaps=-1
palette_offset=11629008
swizzling=Enabled
If the image doesn't look fine, switch usage of alpha channel (Settings - Alpha mode, Ctrl+A). Unfortunately, the tool doesn't save alpha channel state per texture and doesn't allow non-power-of-2 resolutions, so it can't show wbg01.txp (320x224) properly. You'll want to edit pic related anyway.
Note that .DAT's header contains offsets of files' ends, not their starting offsets as I thought, so my previous post actually has FontB0001.txp.
RealFontB0000.png

Also, regarding the crash if you replace .LZS with "compressed" one: the game copies the whole .LZS to memory and then tries to uncompress it to another memory region, which works fine with 5MB LZS -> 10MB DAT (15MB in use), but fails with 10MB ->10MB (20MB is too much). I'll look into the possibility of disabling the decompression of START_JP.LZS altogether (since it doesn't serve any meaningful purpose and simply slows down the game loading) and make the game read and use uncompressed file.

By the way, there's no need to remake the whole ISO on every modification, there are other options to replace a single file, see http://gbatemp.net/threads/what-would-it-take-to-mod-an-iso.352353/
In our case we have a whole 250MB of empty space at our disposal, it's called DUMMY_DATA. Relink START_JP.LZS to that file using Apache2 by Sonix or other ISO manipulation tool and then replace it with modified one. Original START_JP.LZS will stay unmodified in its own LBA, new one will be placed in DUMMY_DATA's LBA and all access to START_JP.LZS will be redirected to the new location, which was occupied by DUMMY_DATA before.
 

Linka

Well-Known Member
Member
Joined
Sep 13, 2013
Messages
248
Trophies
0
Age
34
XP
189
Country
United States
Haha, this is linka13, the one who made the guide linked above. I'm a little flattered actually that I was asked about it, and that my menu translation WAS used for this! But I will admit, I'm probably not the best sort to help in this. I don't know Japanese and much of what I /do/ know is because I remember a lot of things about the original game and can generally understand what menu does what in terms of that, and have gotten help from a friend (note that I credit one named NeoArkadia when it came to clarification and those store questions. He's not fluent either but he's used to hobby translation work for an entirely different area, and he did it mainly as a favor.) I think the one thing that'd be a killer to do is the shop inventory. I know there apparently used to be a big massive game script on GameFAQs, but I guess the person took it down.

I'm very impressed though that someone is trying to translate La Pucelle Ragnarok, and has managed to plow through some impressive technical bits! It's a game that I really really enjoy and find to be such a staggering improvement to the original that it's... Honestly rather hard to play the original anymore.

As a note, while the main bits of the LJ link are unchanged, I did later repost it to my Dreamwidth journal when I made the jump, and added on more skills and did some organization concerning it. It's the most updated to when I last played.

http://linka13.dreamwidth.org/572.html?style=site

Maybe with this, I might go ahead and pick up the game again after I finish with Meruru Plus.

Oh yes, also, here! Here's a list of La Pucelle skills in Japanese, which is what I used to cross-reference. Very helpful for recognizing team skills, too.

http://www.geocities.co.jp/playtown-Dice/1349/lp/special.html

The main problem would be determining port-exclusive stuff. I know the Disgaea characters show up in the game, and that you get brand new skills with the Demon Lord chapters. It's all stuff that'd be hammered out with a bit more difficulty, but having the basic character skill list helps a lot.
 

ChepChep

Well-Known Member
Member
Joined
Feb 9, 2011
Messages
611
Trophies
0
XP
876
Country
United States
I have another major update as well. I found out that the NISUnpack.jar file was not correctly unpacking the dat files used by LPR. I ended up writing my own ones and I can confirm that they work to unpack and pack dat files in LPR.

Here are the links to the files:

www.tarranoth.com/LPR/DAT_Pack_v1.py
www.tarranoth.com/LPR/DAT_Unpack_v1.py

I also found the file where many of the character's names are hidden. Attach.dat and also name.dat for NPC. I was able to translate the main character and get Prier throughput the entire game. I have also found the Ps2 file that has the same info so I am going to try to insert most of the PS2 names this weekend. I will post some new screen soon with many of the characters translated. The nice things about it is that the PS2 game is in Shift-JIS format which makes easy copying.

I only have two more technical challenges I can see. First I need to make a program for packing and unpacking NISPACK files in dat. I have a ruby version that works for unpack but it does not pack it back up correctly. The dat with the NISPACK is the container for all the game dialog and NPC talking.
The second is fixing the fonts. I really hate the default font using SHift-JIS for latin characters. There is ascii characters but for some reason it is missing many letters.

I should be fine for most of the game as far as translation except for the extra contect above the PS2 version. I have heard that the EUR version many have some of the extra content so I may need to track down a copy of it at some point.

The nice thing about the code I am writing is that I am finding that the other NIS games for psp use similar format which mostly likely means they are using the same tools for all their games. I have been figuring out many things about LPR by looking at the english Disgaea 2 for PSP.

Anyways I will give another update this weekend with some more screenshoot once I have a nice battle screen with player characters translated.

-ChepChep

PS. I am going to post all code on the board to document and so other can use my code. Feel free to use it toward other games if other people are interested.

Code in Spoiler:
######################################################################
# DAT_Unpack_v1.py
######################################################################
# Built to unpack files in dat format for La Pucelle: Ragnaraok [JPN]
# Run with python 2.7
# Last Update: 09/12/2013
######################################################################

import math
import struct
import time
import copy
import os

fileName = 'START_JP.dat'
fileName1 = '../START_JP_Test/START_JP_header.dat'
filePath = '../START_JP_Test/'

fileSize = os.path.getsize(fileName)

dTestTime = 0.0
dStartTime = time.time()

dir_exists = os.path.exists(filePath)
if dir_exists == False:
os.mkdir(filePath)

# Open file to convert
f = open(fileName, 'rb')
f1 = open(fileName1, 'w+b')

fileCounter = 0
headerLength = 1168
locationBuffer = []
tableFile = []

# Read header data
for i in range(16):
byte = f.read(1)
fileCounter += 1
f1.write(byte)

# Create lcoation file name table
for i in range(36):
location = []
for j in range(3):
byte = f.read(1)
f1.write(byte)
fileCounter += 1
location.append(byte)
locationTemp = str(location[2]) + str(location[1]) + str(location[0])
locationBuffer.append(locationTemp.encode("hex"))

fileNameTemp = ""
for j in range(29):
byte = f.read(1)
f1.write(byte)
fileCounter += 1
if byte != chr(00):
fileNameTemp = fileNameTemp + byte

tableFile.append([int(locationBuffer,16),fileNameTemp])



for i in range(35):
tableFile.append(tableFile[i+1][0]-1)

tableFile[35].append(int(fileSize))

print "Creating packing header file"

while fileCounter < tableFile[0][0]+headerLength:
byte = f.read(1)
f1.write(byte)
fileCounter += 1

f1.close()

for i in range(len(tableFile)):
outputFileName = filePath + tableFile[1]
print
print "Unpacking: " + outputFileName
f2 = open(outputFileName, 'w+b')
print hex(fileCounter)
while fileCounter <= tableFile[2]+headerLength:
byte = f.read(1)
f2.write(byte)
fileCounter += 1
f2.close()

print
print fileCounter
print hex(fileCounter)
f.close()

dTestTime = time.time() - dStartTime
print
print "Total Test Time = %.3f sec" % dTestTime

######################################################################
# DAT_Pack_v1.py
######################################################################
# Built to Pack files in dat format for La Pucelle: Ragnaraok [JPN]
# Run with python 2.7
# Last Update: 09/12/2013
######################################################################

import math
import struct
import time
import copy
import os


fileName = '../START_JP_Test/START_JP_header.dat'
fileName1 = '../START_JP_Test/START_JP.dat'
filePath = '../START_JP_Test/'


dTestTime = 0.0
dStartTime = time.time()

dir_exists = os.path.exists(filePath)
if dir_exists == False:
os.mkdir(filePath)

# Open file to convert
f = open(fileName, 'rb')
f1 = open(fileName1, 'w+b')

headerLength = 1168
locationBuffer = []
tableFile = []

# Read header data
for i in range(16):
byte = f.read(1)
f1.write(byte)

# Create lcoation file name table
for i in range(36):
location = []
for j in range(3):
byte = f.read(1)
f1.write(byte)
location.append(byte)
locationTemp = str(location[2]) + str(location[1]) + str(location[0])
locationBuffer.append(locationTemp.encode("hex"))

fileNameTemp = ""
for j in range(29):
byte = f.read(1)
f1.write(byte)
if byte != chr(00):
fileNameTemp = fileNameTemp + byte

tableFile.append([int(locationBuffer,16),fileNameTemp])

print
print "Packing DAT Header"

while byte != "":
byte = f.read(1)
f1.write(byte)

for i in range(len(tableFile)):
inputFileName = filePath + tableFile[1]
print
print "Packing: " + inputFileName
byte = "1"
f2 = open(inputFileName, 'rb')
while byte != "":
byte = f2.read(1)
f1.write(byte)
f2.close()

f.close()
f1.close()

dTestTime = time.time() - dStartTime
print
print "Total Test Time = %.3f sec" % dTestTime
 
  • Like
Reactions: xhai and Linka

Site & Scene News

Popular threads in this forum

General chit-chat
Help Users
    Psionic Roshambo @ Psionic Roshambo: https://www.youtube.com/watch?v=A0FyqCEfD0E