Script Format/Tool Notes

A forum for a tentative translation project of Legend of Heroes Ao no Kiseki.
Post Reply
flamethrower
Programmer
Posts: 995
Joined: Mon Mar 09, 2015 3:03 pm

Script Format/Tool Notes

Post by flamethrower » Mon Jun 26, 2017 5:21 pm

Virtually all this stuff is the same between Zero and Ao.

The right term is "microcode." I, and other, have incorrectly called them opcodes before. You can read about what microcodes are here: https://en.wikipedia.org/wiki/Microcode

The tl;dr version: a microcode is an instruction that makes something happen in-game.

Script files are mostly made of microcodes. There are a lot of parameters at the top, and then the microcodes themselves are arranged into functions. A function is just a bunch of microcodes that together produce a scene in the game, or otherwise perform some function.

Zero/Ao use single-byte microcodes so when I say "code 01", that's the first byte of the microcodes. Most of the microcodes have parameters that immediately follow the code byte. Each microcode has different parameters, and a lot of them have variable length and parameters, too.

The tools I wrote do basically:
1) Get the functions table
2) Step through each function by microcode, and make a note of the location of:
a) any microcodes that have jumps
b) any microcodes that have user text (will display on the screen during the game)

And that's basically it. For the dumping tool, it doesn't need to care about jumps. The dumping tool tries to produce a human readable, nicely formatted version of each user text microcode. I found:

55 - Dialogue box used for system text & NPCs without a face.
5c - Dialogue box used for NPCs with a face
5d - NPCs with a face, except the name is specified as a parameter (rather than by character code)
61 - Specifies a character name. Other than that, I'm not quite sure how they work

So focusing on 5c now, which is the most common opcode.

5c starts off with a character code. 00 XX means the name is taken from the name list at the bottom of the script. 01 XX means the name is taken from t_name._dt.

Then alternating display codes and pages. Pages after the first without codes assume the same code as the previous page. Common codes:
#NNNNNF specifies display of a certain face.
#NNNNV specifies play of a certain voice file
07 XX (hex bytes) specify text color change
1F XX XX (hex bytes) specify display of a certain item icon

There's also:
01 (hex byte): linebreak
02 03 (hex bytes): pagebreak
02 00 (hex bytes): end of microcode

First, the display routine goes through the entire opcode. It needs to:
1) Find the address of the next opcode, so the program knows where to continue when you're finished reading it
2) Find the length of the longest single line in the entire opcode (across all pages)

The box that displays is based on the longest single line in the entire opcode.

So to address this, the following pseudocode, I think:
1) Even out the lines, so that, as close as possible, the same amount of text is present on each line of each page
2) Find max width, the length of the longest single line in the entire opcode (across all pages)
2A) If max width of any page is too long (TM), we should add lines to the page and repeat (2) to make max width smaller
3) Wrap all the pages to max width.

We'll have to see what it looks like in-game.

How long it can be:
If any single line is more than 63 characters, the buffer will overflow, and the game will crash.

Boxes without a face can fit 60 characters on screen
Boxes with a face can fit 48
Boxes with a portrait can fit 38

You can have up to 5 lines on a single page. More than 3 will look weird, but they will still display. It looks weird because the face is 3 lines tall. More than 5 won't crash the game, but the extra lines won't display.

Boxes with a face always render in boxes that are 3 lines tall, minimum. Boxes without a face render according to maximum number of lines out of any page in the microcode.

We have to manually ID the portrait lines because I'm not sure how to do them automatically.


The wrench is: some pages in-game we will want to wrap manually. So we'll need to come up with some sort of flag for that. Here's an example:

Code: Select all

フン……	
絶対に逃がさんぞ!	
Hmph... 
I won't let them get away!
Hmph... I won't
let them get away!
If it's important to match how the original line appeared, we'll need to flag lines like this to make sure the algorithm leaves them alone. Otherwise, their text will get evened out and it will look like the last set.

For the inserting algorithm, the jumps have to be cared about because our text is a different size than the original text. If our new text is off by even one byte, all the jumps after that point will be off and that will cause the game to not work. As long as you know where all the jumps are, you can write an algorithm to keep track of where they are and where they point to, and this is the technique my script tool uses.

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 2 guests