Author Topic: CHRONO CROSS ROOM SCRIPT INVESTIGATION THREAD (formerly event script thread)  (Read 22159 times)

halkun

  • Architect of Kajar
  • Earthbound (+15)
  • *
  • Posts: 50
  • Ayumi Hamasaki Fanboy
    • View Profile
IN FF7, rooms were loaded using a door lookup table in the header, and the JUMPMAP() opcode. Rooms were referenced by number.

Agent 12

  • Zurvan Surfer (+2500)
  • *
  • Posts: 2572
    • View Profile
Just so you know making the tech editor was INFINITELY more times useful once I figured out what bytes were arguments and which bytes were um....functions?  CL was able to use Geigers Debugger to figure it out I'm sure there's some sort of similar tool for playstation...as an example the hex

70  03 70 70

Before CL came a long I didn't know if this would be

70 -- Play Weapon Sound
03 -- Unkonwn one byte command
70 -- Play weapons Sound
70 -- Play weapons Sound
or

70 -- Play weapons Sound
03 70 -- An unknown command with 7D as the argument
70 -- Play weapons Sound

Turns out it was the second one (03 7D means load animation 7D).  I'm pretty sure the way you figure out is there was a pointer to the next command that would just skip arguments so he would see it was pointing to 70...then 03...then skip 70 and go to the final 70.  This means the byte after 03 was an argument and not a new command.

Phew sorry if that was long winded but it honestly was key to deciphering the code.

--JP

halkun

  • Architect of Kajar
  • Earthbound (+15)
  • *
  • Posts: 50
  • Ayumi Hamasaki Fanboy
    • View Profile
Here is an old fieldscript dump from ff7's debug room (It's gotten much better)

Code: [Select]
****** Section n°0 (dic) Script n° 0 ******
000 : PRTYP ( 00 )
002 : RET
003 : RET
                                                                               
****** Section n°0 (dic) Script n° 1 ******
000 : RET
                                                                               
****** Section n°1 (cloud) Script n° 0 ******
000 : CHAR ( 00 )
002 : PC ( 00 )
004 : RET
005 : XYZI ( 00, 00, 00, 00, 00, 00, 00, 00, 01, 00 )
010 : RET
                                                                               
****** Section n°1 (cloud) Script n° 1 ******
000 : RET
                                                                               
****** Section n°2 (tifa) Script n° 0 ******
000 : CHAR ( 01 )
002 : PC ( 02 )
004 : RET
005 : RET
                                                                               
****** Section n°2 (tifa) Script n° 1 ******
000 : RET
                                                                               
****** Section n°3 (cid) Script n° 0 ******
000 : CHAR ( 02 )
002 : PC ( 08 )
004 : RET
005 : RET
                                                                               
****** Section n°3 (cid) Script n° 1 ******
000 : RET
                                                                               
****** Section n°4 (yufi) Script n° 0 ******
000 : CHAR ( 03 )
002 : XYZI ( 00, 00, B6, FF, 7E, FF, 00, 00, 64, 00 )
00D : DIR ( 00, 60 )
010 : SLIDR ( 00, 01 )
013 : RET
014 : RET
                                                                               
****** Section n°4 (yufi) Script n° 1 ******
000 : window( id=01, X=0000, Y=0000, W=008A, H=00A9 )
00A : ASK ( 05, 01, 00, 00, 09, 00 )
011 : gotoNext +15
013 : window( id=01, X=0000, Y=0000, W=0081, H=0059 )
01D : ASK ( 05, 01, 01, 00, 04, 00 )
024 : gotoNextLong +009D
027 : if UByteL(50)[00] != 00 then(00) gotoLong +0007
02E : gotoPrev -1B
030 : gotoNextLong +0090
033 : if UByteL(50)[00] != 01 then(00) gotoLong +000A
03A : SET-WORD ( 20, 1E, 00, 00 )
03F : gotoNextLong +0081
042 : if UByteL(50)[00] != 02 then(00) gotoLong +0008
049 : SPECIAL ( FB )
04B : REQ ( 11, 74 )
04E : RET
04F : if UByteL(50)[00] != 03 then(00) gotoLong +0008
056 : SPECIAL ( FB )
058 : RET
059 : gotoNextLong +0067
05C : if UByteL(50)[00] != 04 then(00) gotoLong +0008
063 : SPECIAL ( FC )
065 : REQ ( 11, 5A )
068 : RET
069 : if UByteL(50)[00] != 05 then(00) gotoLong +0008
070 : SPECIAL ( FC )
072 : RET
073 : gotoNextLong +004D
076 : if UByteL(50)[00] != 06 then(00) gotoLong +0007
07D : SPECIAL ( FE )
07F : gotoNextLong +0041
082 : if UByteL(50)[00] != 07 then(00) gotoLong +0029
089 : SPECIAL ( FD )
08B : RET
08C : REQSW ( 0F, FD )
08F : REQ ( 03, 0F )
092 : CMUSC ( 02, 04, 0F, FD, 03 )
098 : PRQSW ( 0F, FD )
09B : PRQSW ( 06, 0F )
09E : CMUSC ( 06, 07, 0F, FD, 08 )
0A4 : JOIN ( 0F )
0A6 : CMUSC ( 04, 0A, 0F, FD, 07 )
0AC : SPLIT ( 11, 13, 00, 15, 50, 00, 08, 00, 0C, 00, 60, 74, 00, 00 )
0BB : RET
0BC : RET
0BD : RET
0BE : RET
0BF : RET
0C0 : RET
0C1 : RET
0C2 : if UByteL(50)[00] != 00 then(00) gotoLong +0008
0C9 : gotoPrevLong -00C9
0CC : gotoNextLong +0102
0CF : if UByteL(50)[00] != 01 then(00) gotoLong +00DF
0D6 : AKAO ( 00, 00, 00, C0, 7F, 00, 00, 00, 00, 00, 00, 00, 00 )
0E4 : AKAO ( 00, 00, 00, A0, 7F, 00, 00, 00, 00, 00, 00, 00, 00 )
0F2 : AKAO ( 00, 00, 00, A1, 7F, 00, 00, 00, 00, 00, 00, 00, 00 )
100 : AKAO ( 00, 00, 00, A2, 7F, 00, 00, 00, 00, 00, 00, 00, 00 )
10E : AKAO ( 00, 00, 00, A3, 7F, 00, 00, 00, 00, 00, 00, 00, 00 )
11C : AKAO2 ( 00, 00, 00, C8, FF, 7F, 00, 00, 00, 00, 00, 00, 00, 00 )
12B : AKAO2 ( 00, 00, 00, E4, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 )
13A : AKAO2 ( 00, 00, 00, B0, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 )
149 : AKAO2 ( 00, 00, 00, B1, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 )
158 : AKAO2 ( 00, 00, 00, B2, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 )
167 : AKAO2 ( 00, 00, 00, B3, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00 )
176 : MUSIC ( 00 )
178 : AKAO ( 00, 00, 00, 28, 3F, 00, 00, 00, 00, 00, 00, 00, 00 )
186 : AKAO ( 00, 00, 00, 29, 3F, 00, 00, 00, 00, 00, 00, 00, 00 )
194 : AKAO ( 00, 00, 00, 2A, 3F, 00, 00, 00, 00, 00, 00, 00, 00 )
1A2 : AKAO ( 00, 00, 00, 2B, 3F, 00, 00, 00, 00, 00, 00, 00, 00 )
1B0 : gotoNextLong +001E
1B3 : if UByteL(50)[00] != 02 then(00) gotoLong +000B
1BA : SPECIAL ( F9 )
1BC : SPECIAL ( F9 )
1BE : SPECIAL ( F9 )
1C0 : gotoNextLong +000E
1C3 : if UByteL(50)[00] != 03 then(00) gotoLong +0007
1CA : battle ( 00, E7, 03 )
1CE : MHMMX
                                                                               
****** Section n°4 (yufi) Script n° 2 ******
000 : RET



Here's how it works. Each entity has a a few scripts. Depending on how you interact with the script determines which script is ran.

The "Main script" is the one at the top (Dic). That script sets up the room and gets all the other entities going.

Code: [Select]
#****** Section n°0 (dic) Script n° 0:setup ******
000 : PRTYP ( 00 )     #Adds character 0 (Cloud) to the party.
002 : RET                  #return

#****** Section n°0 (dic) Script n° 0:loop ******
003 : RET                  #return every frame (do nothing)
                                                                               
#****** Section n°0 (dic) Script n° 1:"O" button******
000 : RET                #if "O" button is pressed... return (do nothing)
 


It gets more complex when you talk to people.

Code: [Select]
#****** Section n°4 (yufi) Script n° 0:setup ******
000 : CHAR ( 03 )                                                    #This entity is char #3
002 : XYZI ( 00, 00, B6, FF, 7E, FF, 00, 00, 64, 00 )     #This is the initial X,Y, and Z location of the character
00D : DIR ( 00, 60 )                                                 #This is the direction the character is facing
010 : SLIDR ( 00, 01 )                                              #Set solid range (Bounding box) of this character to 1
013 : RET                                                                #return

#****** Section n°4 (yufi) Script n° 0:loop ******
014 : RET          #every loop return (do nothing)
                                                                               
#****** Section n°4 (yufi) Script n° 1:"O" button ******
000 : window( id=01, X=0000, Y=0000, W=008A, H=00A9 )  #set up a window
00A : ASK ( 05, 01, 00, 00, 09, 00 )  #ask a question with text found in bank 9


See how it works?

FaustWolf

  • Guru of Time Emeritus
  • Arbiter (+8000)
  • *
  • Posts: 8972
  • Fan Power Advocate
    • View Profile
Whoa, thanks for that halkun and jsondag2!

This really helps my understanding of what to expect once the goodies are decompressed. BTW halkun, should the fieldscript be viewable in a text editor, i.e., would it show up just as you've posted, complete with the shorthand for the various commands (CHAR, RET, PC, AKAO, etc)? There's some stuff in the room folders that is not compressed, but it doesn't seem to be viewable in a text editor at all. I suspect walkmeshes and sounds, and I can confirm the latter at least by the AKAO tags present in the file.

halkun

  • Architect of Kajar
  • Earthbound (+15)
  • *
  • Posts: 50
  • Ayumi Hamasaki Fanboy
    • View Profile
No, it's just a sequence of hex codes. In the example dump above, the hex codes representing the commnd have been changed to names, and the number of arguments written down.

The only thing that is text in the fieldscript is the entity name. (Dic, Yufi, cloud) and these are in a seperite lookup table. 
« Last Edit: April 24, 2008, 03:52:39 pm by halkun »

FaustWolf

  • Guru of Time Emeritus
  • Arbiter (+8000)
  • *
  • Posts: 8972
  • Fan Power Advocate
    • View Profile
Alrighty, thanks. That being the case, I'll have to examine some of the uncompressed files as well for pretty patterns. I can't rule out any of the files in the room folders except the ones I know contain sounds (AKAO tags).

halkun

  • Architect of Kajar
  • Earthbound (+15)
  • *
  • Posts: 50
  • Ayumi Hamasaki Fanboy
    • View Profile
The AKAO blocks are not part of the field script and are actually subsections of the field file itself. The Akao field command calls the AKAO block for music/sound playback.

Akari

  • Iokan (+1)
  • *
  • Posts: 11
    • View Profile
I'll tell you a bit of knowledge:

1) You will need learn disasm no mater what, otherwise you will never compleatly understand what fieldscript actualy do.
2) Easiest way to find fieldscript block is to find 200-256 consequental adreses in loaded game memory (cause field script this addreses are actually functions called by each opcode)
3) Most likely you never find actual names for functions (ffvii was great exeption and luck)
4) Easiest way to see something changed in field script - change dialog id called by message displaying opcode.
5) Most likely fieldscript will be entity based. In ffvii and xenogears has 32 fieldscript per entity. First script usually initializing script that called when field loaded, others called by some events or by some opcodes.
6) Easiest opcode to disasm is script flow opcode like conditional/unconditional jump.
7) Some opcodes will pause script execution until some requirements met, like animation stop playing or model finish movement.
8) If you won't be lucky you encount field script lke in FFIX. As I was told it's not entity based and has different paradigm from FFVII.

that's it for now )

FaustWolf

  • Guru of Time Emeritus
  • Arbiter (+8000)
  • *
  • Posts: 8972
  • Fan Power Advocate
    • View Profile
Ah, a date with R3000 assembly awaits me then. When you say "diasm," akari, are you referring to this open source disassembler, or to knowledge of assembly language in general? I've snooped around in the game executable with ps2dis just to see what assembly looks like, so I respect the daunting challenges that await therein. I always read that IDA Pro is the best thing to go with for reverse engineering though. I'd have to save up for that one.

First, my game plan is to identify which file is the fieldscript for a given room by overwriting one room's suspected fieldscript with another room's suspected fieldscript. If characters start doing things they aren't supposed to in that room, then I'll hopefully have identified which file it is at least. Game freezing will be a near certainty probably, but I'm hoping some event action might be executed according to the foreign fieldscript, and that will be the major clue.

Akari

  • Iokan (+1)
  • *
  • Posts: 11
    • View Profile
Ah, a date with R3000 assembly awaits me then. When you say "diasm," akari, are you referring to this open source disassembler, or to knowledge of assembly language in general?

I was reffered to disassembling and reverse enginearing in total.
I use Agemo Debugger (http://www.enixfans.com/html/agemo/) and it tools as disasm/debugger. It's enough to find all info you need.

If you didn't find script yet here the steps.

1) Find 200-256 consequental adreses in loaded game memory (cause field script this addreses are actually functions called by each opcode). You can do it by writing simple programm in any language that search 200-256 4-bytes values which starts from 0x80xxxxxx.
2) Set break by read from this memory range in agemo debugger and find where this value used.
3) Look at disassembled memory and find from where opcode reads (game executable read opcode - find value with opcode as inde and jump by that address). This is fieldscript. And this is good place to start disasming fieldscript.

Another way to find fieldscript is to analize field data file. This way we used to find script in FFIX, but it very depends on your experience.

Vehek

  • Errare Explorer (+1500)
  • *
  • Posts: 1756
    • View Profile
Now that we can decompress the files, we can research fieldscript! OUT 3 seems to be the file with the fieldscript. I haven't figured out the actual starting points of the scripts yet.

FaustWolf

  • Guru of Time Emeritus
  • Arbiter (+8000)
  • *
  • Posts: 8972
  • Fan Power Advocate
    • View Profile
Oh, definitely! For in-game testing I'd normally target a room, open up the entire ISO in my hex editor, find the original compressed fieldscript, then insert the altered re-compressed fieldscript over that, then save and see what happens in-game. If you guys have a more efficient means of testing involving savestates, by all means go for it.

I'll be sidelined with my job and I still have to figure out why I'm getting a debug assertion (fseek.c, line 146) error when I launch Dump_Main.bat in the Translation Tools package, so It'll be awhile before I can get my hands dirty in fieldscript.

Vehek

  • Errare Explorer (+1500)
  • *
  • Posts: 1756
    • View Profile
I've been testing things with the decompressed data in memory.

edit:
Some guesses at commands.
E0 XX YY ZZ?- Dialog message
BB XX YY ZZ?- Give Element. (XX YY is Element)
« Last Edit: July 15, 2008, 01:52:16 pm by Vehek »

FaustWolf

  • Guru of Time Emeritus
  • Arbiter (+8000)
  • *
  • Posts: 8972
  • Fan Power Advocate
    • View Profile
Excellent, excellent! Wow. Are you using pSX Vehek, or ePSXe for memory dumps?

Vehek

  • Errare Explorer (+1500)
  • *
  • Posts: 1756
    • View Profile
I'm using pSX.

How can I figure out where the scripts begin? I think I have the pointers, but I don't know where they're going.

edit:
I think I have the pointers for the opcodes. They're at E18D0 in my memory dumps.
« Last Edit: July 17, 2008, 11:06:31 pm by Vehek »