Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - OneWingedAngel

Pages: [1]
Welcome! I played around with the TT tools last year and mostly got the hang of them. I can probably answer questions you have.

Thanks!  Oddly, the game takes away / unlearns Serge's elements during the Fort Dragonia scene, but only teaches Lynx's when you get to the Temporal Vortex.

Also good to know that the program that dumped the fieldscript left gaps when it encountered some unknown codes.  I need to look at Danetta's updated version.

I don't know how Gameshark codes are constructed, but for those who do:

- The fieldscript events that remove your "Serge members" don't seem to appear in the Fort Dragonia sequence.  I think this happens when the Temporal Vortex is loaded.

- The fieldscript dump that I'm looking at (CD0-371-Temporal Vortex.txt) has a strange gap between 0x006C and 0x0088. This corresponds to 0x00730 and 0x0074B if you decompress /D1445/0003; I don't know why the fieldscript dump drops all of the header information from its count.  Anyway, this is in a section of fieldscript that is triggered on room initialization when you enter from the Fort Dragonia scene.

- The code in that gap, starting after the unknown opcode FE 6F, is:

00 D9 00 80 31 80 DA FE 79 00 80 9C 82 FE 74 00
80 9D 82 FE 73 00 80 9E 82 6C 64 80

- The page with known opcodes has vanished, so I can't try to work out what might be happening here.

- The only other code that only runs when you enter the Temporal Vortex from Fort Dragonia is the block between 0x0109 and 0x0144 in the fieldscript dump, which looks like it's just the code to make Lynx stand up and look around.

Generally: There isn't any fieldscript that removes a bunch of characters from your roster, nor one that adds Lynx to your roster.  I suspect this happens in a "special script" called with one of the FE XX opcodes.

Also: I don't think you need to label threads as spoilers in this section of the forum.  If you're modifying the game, you've almost certainly played through it.

The list of opcodes that was at seems to have vanished, and the link to "fieldscript" from is now dead.  Does anyone have an archived version of this page, or know to where it got moved?

Here's my plan of attack to get things moving on this front again:

1) Translate the Terminus Traduction tools into English.  I might leave most/all of the actual variables in French, and only translate comments, printed strings, and scripting commands.  I've found their code to be really well organized/structured, and their tools more complete than the other sets.  This also includes removing the French translation that sits in the Textes_Avant folder in the distributed version (so that extracting and reinserting does what you'd expect) and fixing the accent issue with script extraction.  I'll try to write better documentation that provides instructions for the *order* of scripts to run.

2) Move utunnel's fieldscript decompiler (and compiler?) into the TT tools.  That is, have the TT tools run the LZSS decompressor and fieldscript decompiler on file 0003 in each room, as part of its script extraction routine.

3) Rewrite/edit the decompiled fieldscript format to be more human-friendly / editable.  This includes a few things:

     - Remove the hexidecimal indexing at the start of each line, or at least make it optional.

     - Change the format of decompiled IF statements to point to a marker in the code (e.g. LANDING_POINT(2)), not a hex reference.  As is, all IF statements are decompiled literally, indicating the file position marker to jump to if the condition is/not met.  This makes it difficult to add lines (or change a line to an opcode with a different byte length) to the fieldscript, as it requires the user to change *every* file position marker after the added lines.

     - Make the IF statements more consistent.  As others have noted, some of the IF-type opcodes seem to be upside down, or are phrased in the negative (e.g. IF_CHARACTER_NOT_IN_PARTY).  As far as I can tell, all IF opcodes are most directly phrased as IF(condition) CONTINUE, ELSE GOTO(reference).

     - Add metadata files for labeling entities and scripts at decompile time (add comments to individual entities and scripts).  If the metadata file for a room doesn't exist when it is decompiled, the decompiler will make a "blank" or default file with the right number of entities and scripts per entity.  A human can then edit that file to overwrite default names and descriptions, so it decompiles "nicer" next time.

4) Write a fieldscript compiler that's compatible with the new format, and have the TT tools recompress and insert it when the script is reinserted.

5) Make some sort of database / something of unknown opcodes (frequency, where they occur relative to other operations, etc), as a reference for trying to decipher them.  Yes, this is vague.


I'm going to do all of this in a public GitHub repo, both in order to generate a history of changes from code written by others that's publicly available and to (hopefully) foster collaboration with others.  In particular, just about anyone should be able to contribute to the fieldscript metadata labeling, once those files exist-- no programming, just labeling.

I made a slight edit to the "rescue Riddel" condition above.  The relevant story trigger happens at the end of the escape, when a party member suggests going to Hermit's Hideaway, not right when you beat Hell's Cook.  I don't think there's a way to fight the TD in between those events, so it's sort of moot.

The one thing I haven't fully verified is the "Harle permanently leaves you" condition.  In the fieldscript dump, this is a check that SCENARIO_FLAG (game progress) is at least 176... but I can't find where this is set!  The scene where Harle leaves you (talking about it with Starky if he's on your roster, and just saying "au revoir" if not) happens when SCENARIO_FLAG is 172, and the end of this scene transitions to the world map.  However, the fieldscript does not indicate that SCENARIO_FLAG becomes 176 at the end of the scene, when Harle is removed.  In fact, the script doesn't explicitly say to transition to the world map-- there is no NEXT_ROOM reference for the world map anywhere in the script.  My only guess is that the unknown opcode FE 7D calls some unseen script that sets SCENARIO_FLAG and moves to the world map, but that seems weird.

EDIT: That scene is CD0-271 at 0x0C84.

Anyway, I'm new here, but I'm going to try to make more progress on deciphering fieldscript.  I haven't used utunnels' tools yet, only working with the posted fieldscript dump and the TT tools.  If utunnels' tools don't include source code for a fieldscript decompiler, I'll write one from scratch and add it to the TT tools.

I have no idea how you guys made initial progress on this-- starting from zero must have been maddening.  From here, I think the correct approach is to make a concordance / quasi-database of unknown opcodes, indicating which kinds of scripts they appear in (init, interact, etc) and before/after which other codes.

Here's a translation of the "choose which ending" code from the Opassa Beach fieldscript file.  All endings refer to this page.


IF(You completed Terra Tower all the way to Kid's final line on the boat) {
    IF(You beat the Time Devourer normally) {
        RUN the "Bad" ending
    RUN the "Chrono Cross" ending

IF(You completed Chronopolis all the way to Harle bidding you "adieu") {
    RUN the "Return of the Downtrodden" ending

IF(Harle has permanently left your party) {
    IF(Dario has decided to rebuild Viper manor) {
        RUN "Career change" ending
    RUN "Darkened Fate" ending

IF(You escaped from Viper manor after rescuing Riddel) {
    RUN "Onward Dragoons" ending

IF(Serge has body swapped into Lynx) {
    RUN "New Beginnings" ending

IF(You have decided whether or not to try to heal Kid) {
    IF(You took the Forest Route with Nikki) {
        IF(You chose to try to save Kid) {
            IF(Razzly is in your roster) {
                RUN "Magical Dreamers" ending
    RUN some version of "True Hero" ending

IF(You spoke with Leena at the dock) {
    RUN "General Kid" ending

IF(You recruited Poshul in Home World) {
    RUN "General Kid" ending

Request change to disc 2
RUN "Programmer's" ending


It's not just that you can't cross dimensions to get the developer's ending-- you can't make *any* progress in the game, whether by talking to Leena or recruiting Poshul.

From reading the fieldscript, it looks like there might be *three* versions of the True Hero ending, not just the two listed on that page.  By my reading of the script, it looks like it's possible to cut to the final scene (with Solt, Peppor, and Pierre) after seeing Kid in Viper Manor (if you neither gave her the Hydra Humor nor recruited her with Doc), after Kid says "Bugger! How'd she know about that?", or after the Korcha/Macha scene.  The Korcha scene can be skipped if you *don't* get Korcha's boat by promising that Kid will marry him, but instead go directly to Opassa Beach and fight the TD.

Whoa, did I just find a 13th ending?

This thread has been dead for 9.5 years, but:

Is the list of opcodes the full list of known codes?  I'm reading through the dump of fieldscript, and I think I've figured out a couple that aren't on that list.

I am 99% sure that opAE(0x01) indicates that this entity's script 4 is the "on key item interaction" script.  In every case I've looked at, it appears in script 0 *if and only if* the entity's script 4 has one or more IF checks using USED_KEY_ITEM.

Are others still working on deciphering fieldscript?  I couldn't find a more recent thread discussing it.

Using the TT source (Lzss.cpp) as a reference, I can see three possible errors in the code you posted:

1) In the codeblock for when the first bit indicates a byte literal (if is_val == true {), you write that byte to your temporary buffer buf, but never put that byte in outbuf.  In contrast, the corresponding block of Lzss_Decompression in the TT code (if (type==OCTET)) stores the byte/character in the temporary buffer and writes it to the outfile.

2) In the line that writes a byte/character from buffer to outbuf (outbuf.push(buf[(offs as usize)+(i as usize)])), I think the index of buf needs % BUFFER_SIZE at the end.  As written, it looks like it could ask for an illegal element of buf when offs+i > BUFFER_SIZE.

3) The line in the TT code that reads the buffer offset (offs in your code, position in theirs) strangely *decreases* it by 1 from what the bitreader returned (then modulos by 4096 to fix any -1's that generated).  That seems really weird, but it's there.  Maybe there's something weird about TT's bitreader (Bread_M in Binare.cpp).

But more broadly, something more than these errors must be wrong for your code to generate a 4765 byte file when the header says 2048.  Googling a bit, my guess is that you're writing to outbuf incorrectly.  You initialized it as a vector of zeros of type u8 with dsize elements, the size of the file you want to write (based on the header).  So when you want to write data to it, you should write to an existing element of outbuf; start from element zero, and increment a position counter every time you write to outbuf (whether from a byte literal in the compressed file or from the temporary buffer).  In your code, however, you use push, which *adds* an element on the end of the list / vector / serializer / whatever these things are called in Rust.  So I would expect that your test has all zeros for the first 2048 bytes, then whatever output your code produces.

Caveats: I don't know C++ or Rust, I can barely read French, and I learned about LZSS compression just now.

Chrono Cross Modification / Re: Chrono Cross Lzss compressor
« on: August 25, 2018, 10:56:06 pm »
Sorry to bump a nearly three year old thread with my first post, but I've just begun working with the Terminus Traduction tools, and encountered (seemingly) the same problem.

For me, it turns out that the TT program would crash *after* doing the LZSS compression for *all* of the files.  That is, every single .scn file had been compressed into the corresponding .lzs file according to the file timestamps.

I found one workaround and one solution that works for unknown reasons:

1) Run Rein_Script, let it crash.  Then edit /CD#/60_Scripts/Rein_Script.txt to comment out (with a /) the first three commands (up to Rooms_Lzss_C).  Then run Rein_Script.bat again, and it will pick up with Rooms_Cpt_C.

2) For mysterious reasons, the script doesn't crash if I run Rein_ScriptC before running Rein_Script (obviously you have to do Dump_ScriptC before reinserting it).  I have no idea why this is; my only guess is that some extraneous characters get removed when it copies the script from Textes_Apres into Fichiers_Apres.

If you're still out there and trying to translate CC with these tools, my suggestion is to do all of the translation in Script1_CD1.txt, Script2_CD2.txt and ScriptC_CD1.txt (and copy and rename that for CD2), then Rein_Script# and Rein_ScriptC before Rein_Script.  The "Repartition" tools to break up the dialogue by character to send to different translators seems fiddly to me.

You might also find that the code unpacks accents incorrectly.  I can help with that too, if you want.

Pages: [1]