Script Hacking

A forum for the translation project of the first title of the Legend of Heroes Gagharv Trilogy: Legend of Heroes III - The White Witch. Also known as Prophecy of the Moonlight Witch.
flamethrower
Programmer
Posts: 995
Joined: Mon Mar 09, 2015 3:03 pm

Script Hacking

Post by flamethrower » Mon May 11, 2015 3:10 pm

I tried looking at the script for this and got nowhere. Any tips?

I searched for the fail message you get when there's no CD inserted and was able to find it. Just search for it (it's in SHIFT-JIS), select on the first byte of it, CTRL+R to find references in OllyDbg. I'm not sure how the program gets to that code, though, so I can't patch it. The reason I was able to find it is that this message is specified in the program code?

I also searched for the text that appears in game when a dialog box was open, but I didn't find it. I don't know how you'd search the stack for something like that. I'm probably doing this wrong. I think I was searching the executable (dump) memory for that, but it wouldn't be there. How do you search memory for a string? How do you memory breakpoint? I want to break when the program gets to a certain point in the script.

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Mon May 11, 2015 5:23 pm

Olly kind of sucks with Japanese. Probably other similar languages too. The easiest way would probably be to do a binary search and type out the hex for the shift jis your looking for. By dialoge box are you talking about this stuff?Image
If so it's easier to find it with a hex editor. If you're talking about the actual script then yeah just figure out the hex and search for it.

Trying to find the script files? Probably be best to set a break on all calls to createfile. The text files load up on screen changes if my memory is correct. If you're wanting to look at the decompression routines I can find it for you real quick once I get home.

For cracking the CD check you can work backwards from the error message or do what is usually called blind stupid patching. Basically load up the exe and start stepping over, F8, Eventually you will step over a call that throws that message. Restart and step into, F7, that call and start stepping over again. Every time you step over a call that throws that message step into it again. Eventually you will be at the code that checks the drive. You will see a check and then a jump. Depending on how the code is written you'll either want to always take the jump or never take it. It'll be pretty obvious once you get close because you start seeing the program setting drive letters and then checking the name of the disc in the drive.

Of course there are other ways. You can search for all intermodular calls and set breaks on things like string compares and set drive letters.

flamethrower
Programmer
Posts: 995
Joined: Mon Mar 09, 2015 3:03 pm

Re: Script Hacking

Post by flamethrower » Mon May 11, 2015 6:11 pm

How do you "Set a break on calls to X"?

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Mon May 11, 2015 6:53 pm

Right click anywhere in the disassembly go to Search for / all intermodular calls. Find createfile and right click on it. Then set breakpoint on all calls to x. While you're at it do the same for Readfile. Turn the breakpoints off and leave the first village. Turn the break points back on and re enter the village. You will start breaking on createfile. Readfile actually reads the file to memory. So the program will go back and forth between create and read.

The script stays in memory until another screen change. If you want to break in the dialogue text then find the text in memory right click it and set a memory breakpoint. Then go talk to whoever triggers that text. It should work just like how I found the word "Old" in the finding bugs thread I made. Just with shift jis instead. I've read that shift jis works fine with Olly but have never experienced that myself. Whenever I've tried to type Japanese in the binary search box I always end up with Unicode.

Edited to fix phone errors and elaborate a bit more.

User avatar
zeromonkey
Hacker, script editor and control freak
Posts: 486
Joined: Thu Mar 05, 2015 3:10 pm
Location: Tennessee

Re: Script Hacking

Post by zeromonkey » Tue May 12, 2015 2:53 am

The dialog in this game uses single and double byte. Unless a custom table is used to extract it, narrowing it down by conventional means is gonna be a real pain in the ass. Trust me, I have tried searching for it. I have located files with dialog in them, but honestly can't tell you where they appear in the game.

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Tue May 12, 2015 3:50 am

Oh yeah Kind of forgot about the half width stuff. That will complicate searching. Here is the first text file after you actually gain control of the character. You can use it to help search for stuff.

Edit: ignore the English names in the file. That was me messing around with stuff. The original file was all Japanese.
Attachments
crap2.zip
(3.2 KiB) Downloaded 190 times

flamethrower
Programmer
Posts: 995
Joined: Mon Mar 09, 2015 3:03 pm

Re: Script Hacking

Post by flamethrower » Tue May 12, 2015 3:22 pm

Script Test: http://pastebin.com/j0kRAeza
The part of the script that decodes between half-width kana, katakana, and hiragana is definitely working.
The part that finds text is definitely not working.

1) Make a list of half-width kana
2) Make a list of hiragana corresponding to half-width kana
3) Make a list of katakana corresponding to half-width kana
4) Put together 1, 2 and 3 into a list structure or whatever. Python's zip() actually makes a tuple, which is like a list, but read-only. Python docs call this immutable. But for our purposes we don't care. Tuple must have some advantage over list. If you are a real programmer, you know what it is (but I don't).
5) When we encounter a wild half-width katakana, loop through the list. If the half-width kana matches, we write the full-width kana based on the current flag, increment position counter and then break out of the loop.

Oh yeah, I guess you can use tuple unpacking.
...But you can unpack lists too. I fail to see the benefit.

Good reasons
-You want a write only data structure
-Tuples are faster execution speed

There's still a lot to do.
-Need a way to insert back script files

Within scripts:
-Need to find out opcodes
One I know is definitely wrong is "aiyo" (sorry, can't type Japanese at work) at 0xF41. It's really, "naiyo." I think this opcode really starts at 0xF2D and there's a bunch of opcodes before the text...that I don't understand. Need a way to find the text opcodes.
-Need to find the pointers.

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Tue May 12, 2015 4:03 pm

Not script related per say... But If you want to give the .dat files a look it would be great to have a program that can quickly split and rejoin them. They are very similar to the wanderwonder fld but I don't think there are file names. Its been a while but I could look at it again after work if there is something you can't figure out but I remember it being pretty straight forward.

I should be able to easily hack the routines to allow for uncompressed script files. In fact I did that before but no longer have that exe.

About pointers I recall at least some of them being in the file but there were some I couldn't find. Likely because at the time I wasn't aware of opcodes in the script files. Or probably just didn't look long enough to be aware of them. Before Eidenyaku announced their translation plans for the game.

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Wed May 13, 2015 2:38 am

About the cd check;
Image
So here is the message getting displayed in a message box. If I understand you correctly that's where you were right? Again as a huge plus of hacking in the windows environment we can pretty easily see whats going on. I only took a pic of the end but you can scroll up in olly to see the whole routine. I thought about making one big pic but it was way too long. Anyway we can pretty plainly read what is going on here.

Starting from the top we see we set a drive letter. Then comes the first test. The game checks to make sure the drive is valid. If it passes it checks the volume information. Then we do a few other things I'm not sure of without actually debugging. Then if it passed the volume information it checks the name of the disc with a string compare. If that passes it checks if the ed3_dt22.dat is there. If it passes that test it checks the size of the dat file. If it passes that test it actually sets a pointer and reads a single byte from the file and checks it against known value. We are now in the picture I posted. If it passes that last test it jumps out of the loop , past the mesage box, to 41F4C0. Sets AL and returns.

If it fails any of the above tests it immediately jumps to 41F47F where it checks a counter against 0x5a and Jumps back to the top to do all the tests again with another drive letter. Upon failing any test 0x5a times it continues out of the check loop and runs the message box. After running the message box there is a CALL EDI probably in the event you hit retry so it will run the whole loop again but I havn't actually debugged it yet. When all alternatives are exhausted it jumps out of the loop to 41F4CD where it clears AL and returns.

So you could hack this routine many ways. Or you can do a little bit of back tracking. Scroll up to the top of the routine to 41F2C0. If you highlight it you will see it's only called once at 42002C. And then another call back from there is where we will return and actually check the value of AL that was returned from this routine. So you could probably actually hack it to where it displays the message box if there is no disc but still runs the game if you wanted too. I think I NOPed the whole thing and just set AL and returned.

About the Dat files:

Code: Select all

4C 42 20 44 41 54 1A 00 00 02 00 00 00 00 00 00 
14 08 00 00 2C 15 00 00 37 24 00 00 81 2D 00 00
So this is the first 0x1F bytes of ED3_DT00.DAT. The first 6 bytes is just a name, LB DAT, then I have no clue what byte 6 or 9 are yet . Starting At 0x10 we have dwords for the starting offset for each file in the dat. So the first file starts at 0x0814 the second starts at 0x152C and so on and so forth. The length of the file can either be calculated or read from the individual files. The first four bytes of each file is the file length.

Oh yeah and the first file of the first dat is the file I uploaded earlier but compressed.

flamethrower
Programmer
Posts: 995
Joined: Mon Mar 09, 2015 3:03 pm

Re: Script Hacking

Post by flamethrower » Wed May 13, 2015 4:20 am

Unpacking the .DAT files is the easy part! See? I'm done!
Unpack: Run from game folder (no arguments)
Pack: example usage: python script.py ED3_DT00.DAT

You have to run the unpacker first because
1) It creates a meta data file the packer needs to work
2) It sets up your folder structure to make packing easy

Unpacker: http://pastebin.com/P6rCxYN3
Packer: http://pastebin.com/9Gft37AH
Attachments
ED3_DAT_tools.zip
(1.67 KiB) Downloaded 191 times

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Sat May 16, 2015 1:40 am

Again you're the man Flame! Your program works like a charm and I have now successfully loaded uncompressed script files in the game. I've uploaded a hacked exe to the private ftp server if any one wants to mess around with it. It has the CD check completely removed and the ability to read uncompressed or compressed script files.

To use uncompressed script files first use Pokan's falcom tool to decompress them. Then you will have to add the uncompressed files length plus 4 bytes to the start of the file followed by two bytes of 0xFF. So for example the file I uploaded earlier is 0x117E bytes long plus 4 is 0x1182. So you would have 0x8211FFFF added to the front of the file. Then just use Flame's script to glue the dat file back together.

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Sat May 16, 2015 10:10 pm

flamethrower wrote: Within scripts:
-Need to find out opcodes
One I know is definitely wrong is "aiyo" (sorry, can't type Japanese at work) at 0xF41. It's really, "naiyo." I think this opcode really starts at 0xF2D and there's a bunch of opcodes before the text...that I don't understand. Need a way to find the text opcodes.
-Need to find the pointers.
I starting looking into this a bit today and I realized I've actually already done alot of this. I wrote alot of my findings down in a notebook. If I can find it I'll post everything I learned back then. But trying to figure out the Naiyo thing you were talking about I can tell you that this is buried down in the item shop text routines which starts at 0xE8E.

As far as the aiyo part I haven't triggered that text yet but if you were counting on the half width na at 0xF3E being part of that don't. It is part of the Speaker name at the top of the box. At 0xF3D We have 0x12C5040F. The 12 is call a name from file the C504 is the location of the name, in this case Teluno's shop, and the 0F ends it.

Found that text.
Image

flamethrower
Programmer
Posts: 995
Joined: Mon Mar 09, 2015 3:03 pm

Re: Script Hacking

Post by flamethrower » Sat May 16, 2015 11:22 pm

Alright, thanks for the reply. Now we need some help from the Japanese-reading people on our team :)
Is it this? http://jisho.org/word/%E3%81%82%E3%81%84
There's a huge number of homonyms for あい

flamethrower
Programmer
Posts: 995
Joined: Mon Mar 09, 2015 3:03 pm

Re: Script Hacking

Post by flamethrower » Sun May 17, 2015 1:23 am

OK. Getting there. Slowly. Need some help with the 01 opcode.
I'm getting ahead of myself. I have done real, actual work today on this.
ED3 Script Test 2: http://pastebin.com/3NeqZCE8
I only have that file you posted earlier to work with right now.
Current output is both screen and file. I posted the output to Google Sheets also: ED3 First Script File

Where it is messing up:
Wherever you see the output and it is blank, this is because it didn't pass the program's check:
0xF opcode 3 bytes after 0x12 opcode or 0xF opcode 2 bytes after 0x13 opcode.
However, some of these actually do contain text. I'll need to know more about the opcodes in between the 0x12 / 0x13 and the 0xF (that marks the start of the text.

Looking at the first two, 0x91C doesn't appear to be a "real" 0x12 opcode. It seems like it's an operand for the 0xB opcode before it.
0x91E does appear to be a real one. There is opcode 01 after it which I don't know how to decode (or skip over).

Opcode 02 appears to also be a jump. At 0xD74 you can see it jumps to 0xD98. This is an absolute pointer style.
Opcode 04 in a text string appears to be an item string.
Opcode 05 in a text string appears to be a price.

Also, my program is missing a bunch of text because it uses searching. We'll have to decompile the whole file to make sure we've got it all, I'm afraid.

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Sun May 17, 2015 3:53 am

Yeah I think we'll end up decoding the whole file before we're through.

Yeah the 0x91C does indeed look to not be real. There is no pointer to any of those bytes.
There is a pointer to 0x91E though. I verified it by changing Julio's dads text to point to it instead. As for the rest of the opcodes that follow I only know some of it. This is an instance of a character saying more the first time you talk to them then on subsequent talks. The first time it reads all the text the second time it skips down to 0x941. So the whole set of opcodes start at 0x91E 0x12A404011261666041090B120F and the pointer for subsequent speaking is at 0x926. I'm guessing between the box name pointer and the subsequent speaking pointer is some sort of flag setting/checking. I'll know more after some debugging.

Ok did a little debugging. 01 takes us to some case switches, 12 gets read and stored, 61 66 and 60 select different cases. 12 gets used in the 61 case. 60 bails out of the case switching routine and determines if the text is first time or not. If it's the first time it skips over to the 0b12 which sets a flag then starts printing text. The second time when we bail out with the 60 opcode we read the next two bytes to determine where to start printing the text.

Still a little rough at this point.

12 is the name of the flag basically so like 0112 check flag 12. 0b12 set flag 12. Really though 12 is just used to locate a certain place on the stack. and 6166 is really what does the checking and 60 does one of two things based on the results.

User avatar
zeromonkey
Hacker, script editor and control freak
Posts: 486
Joined: Thu Mar 05, 2015 3:10 pm
Location: Tennessee

Re: Script Hacking

Post by zeromonkey » Tue Jun 16, 2015 6:08 pm

Might want to reference this for actual names

Falcom ED3 Character Page

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Sat Jun 20, 2015 6:50 am

zeromonkey wrote:Might want to reference this for actual names

Falcom ED3 Character Page
I'll certainly take it into account but Falcom sucks at English names. Dalk Fukt? I know thats from Ys but some of their Gagharv transliterations are pretty questionable too. Shirla, Goes, and Jurio do not appropriate the sound of the original Japanese nor are they really any good for English.

User avatar
zeromonkey
Hacker, script editor and control freak
Posts: 486
Joined: Thu Mar 05, 2015 3:10 pm
Location: Tennessee

Re: Script Hacking

Post by zeromonkey » Sat Jun 20, 2015 6:46 pm

Xalphenos wrote:
zeromonkey wrote:Might want to reference this for actual names

Falcom ED3 Character Page
I'll certainly take it into account but Falcom sucks at English names. Dalk Fukt? I know thats from Ys but some of their Gagharv transliterations are pretty questionable too. Shirla, Goes, and Jurio do not appropriate the sound of the original Japanese nor are they really any good for English.
Yeah. Some names don't translate well between languages. I was mostly posting that for the spreadsheet that Flame had with Jurio being Julio. I like Jurio much better than Julio. The Dalk Fukt was probably playing it safe instead of calling him Dark Fucked (because he did that to me for over 20 years till last year when I finally beat Ys I). Blasted falling floors and game reaction time.

User avatar
SkyeWelse
Graphics & Web Design
Posts: 490
Joined: Thu Mar 05, 2015 4:32 am
Location: Georgia
Contact:

Re: Script Hacking

Post by SkyeWelse » Sat Jun 20, 2015 7:24 pm

I also agree that the English used in certain Falcom games for names isn't always the best, so I think we have some flexibility there with choosing ones that we can be happy with.

I believe that at least at present Xalphenos and I have decided to go with Julio (pronounced Jewel-ee-oh) for the spelling of his name. I liked Jurio better at first, but Julio has started to grow on me more. The main reason being that Jurio is not a real name, while Julio is a real name and it fits much better with the other main character, Chris.

Ultimately though, I was going to leave the names up to Xalphenos to decide on as far as choices like this go since White Witch in particular has been a project he started awhile back and has vowed to finish (before he dies even in his own words), so I think that for this project especially I would consider him to be the project lead on this one. We're all more or less project leads on our respective games that are the most dear to us.

-Thomas

User avatar
Xalphenos
Wanderer
Posts: 89
Joined: Fri Mar 06, 2015 12:24 am
Location: Texas

Re: Script Hacking

Post by Xalphenos » Sun Jun 21, 2015 12:47 am

zeromonkey wrote:
Xalphenos wrote:
zeromonkey wrote:Might want to reference this for actual names

Falcom ED3 Character Page
I'll certainly take it into account but Falcom sucks at English names. Dalk Fukt? I know thats from Ys but some of their Gagharv transliterations are pretty questionable too. Shirla, Goes, and Jurio do not appropriate the sound of the original Japanese nor are they really any good for English.
Yeah. Some names don't translate well between languages. I was mostly posting that for the spreadsheet that Flame had with Jurio being Julio. I like Jurio much better than Julio. The Dalk Fukt was probably playing it safe instead of calling him Dark Fucked (because he did that to me for over 20 years till last year when I finally beat Ys I). Blasted falling floors and game reaction time.
My main issue with Jurio has always been that there is really only one way to pronounce it with an American English tongue. "Jury-Oh" And I just never liked the sound of that.

IMHO to translate a name you should first try to determine if the name already exists in the new target language and act accordingly. Failing that you should appropriate the sound as closely as possible. IMO "Jury-Oh" doesn't match ジュリオ as well as "Jewlio" Julio. Finally Failing anything good from the previous two then go with the official Japanese translation. And whether Falcom went with Jurio or Julio really wouldn't matter to Japanese gamers because they would still pronounce it ジュリオ.

I guess my point is the Japanese companies don't always know the best English appropriate translation. So in general I give them less credence then well thought out localizations by native speakers of the target language.

One example is the Japanese PC Engine game Sindibad. The name in Japanese is シンドバッド. Which is the character as-Sindibād al-Baḥri. So the transliteration Sindibad certainly isn't wrong. However We commonly know this character to be Sinbad the Sailor in the English versions of the story. So while Sindibad isn't wrong Sinbad is a better localization choice. Even though the official translation is Sindibad.

Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest