Jump to content

Recommended Posts

I've figured out how scripts work in Pokémon xD, and therefore wrote a script disassembler (in Python 3.x). Sorry if it's a mess.

There are basically two scripts run at the same time: the "common" script, used for a lot of things, loaded after the "Health and safety" screen, and the current map's own script.

I don't know where the common script is stored, so I've dumped it from RAM (you can find it in in the link below, along with the disassembler). This common script seems to do strange things anyways. For everything else, refer to the disassembler various docstrings.

I consider the Daycare's script (M3_houseD_1F.fsys/1) to be a good script to begin with. The test script (in Script_test.fsys) is interesting too.

Download link (download the source code, since it's Python): https://github.com/TuxSH/XDscriptTools/releases/tag/v0.1

Share this post


Link to post
Share on other sites
I've figured out how scripts work in Pokémon xD, and therefore wrote a script disassembler (in Python 3.x). Sorry if it's a mess.

There are basically two scripts run at the same time: the "common" script, used for a lot of things, loaded after the "Health and safety" screen, and the current map's own script.

I don't know where the common script is stored, so I've dumped it from RAM (you can find it in in the link below, along with the disassembler). This common script seems to do strange things anyways. For everything else, refer to the disassembler various docstrings.

I consider the Daycare's script (M3_houseD_1F.fsys/1) to be a good script to begin with. The test script (in Script_test.fsys) is interesting too.

Download link (download the source code, since it's Python): https://github.com/TuxSH/XDscriptTools/releases/tag/v0.1

So excited to play around with this! Can it reassemble the scripts as well?

Share this post


Link to post
Share on other sites

No, it can just disassemble.

If you want to modify the script, you will have to do this by hand. Since all code offsets (in FTBL, HEAD, jumps and calls) are absolute, the easiest way to add code to an existing function, though a little bit hackish, is to add the code at the end of the CODE section, jump to this portion, and jump back (as well as updating the script total size (offset 4), and the CODE section size (CODE offset 4)).

Share this post


Link to post
Share on other sites
No, it can just disassemble.

If you want to modify the script, you will have to do this by hand. Since all code offsets (in FTBL, HEAD, jumps and calls) are absolute, the easiest way to add code to an existing function, though a little bit hackish, is to add the code at the end of the CODE section, jump to this portion, and jump back (as well as updating the script total size (offset 4), and the CODE section size (CODE offset 4)).

Did you manage to figure out what the sections at the bottom are for, i.e. GVAR, STRG, VECT, GIRI, ARRY. Also do you know any ways to decrease the compressed file sizes? For example, redundant data or unnecessary data.

Share this post


Link to post
Share on other sites

There are basically two scripts run at the same time: the "common" script, used for a lot of things, loaded after the "Health and safety" screen, and the current map's own script.

I don't know where the common script is stored, so I've dumped it from RAM (you can find it in in the link below, along with the disassembler). This common script seems to do strange things anyways. For everything else, refer to the disassembler various docstrings.

Download link (download the source code, since it's Python): https://github.com/TuxSH/XDscriptTools/releases/tag/v0.1

I'm not sure how I never noticed this before but the "common" script is in common_rel from common.fsys starting at offset 0x5BEE4.

Share this post


Link to post
Share on other sites
I'm not sure how I never noticed this before but the "common" script is in common_rel from common.fsys starting at offset 0x5BEE4.

Thank you ;). I've looked at this file, but I have not bothered searching for "TCOD" xD

Share this post


Link to post
Share on other sites
Thank you ;). I've looked at this file, but I have not bothered searching for "TCOD" xD

hahaha I'm always surprised by how much is in common_rel. When I look for things I find them there like 80% of the time.

btw, have you managed to do anything cool by editing the scripts?

Share this post


Link to post
Share on other sites

I've not tried to modify anything ... but looking at the code, you can lift the restriction on Shadow Pkms in the Daycare (w/o adding any instruction, just by modifiying the existing ones), and I'm sure you can change the Pokémon given by Duking (+ Elekid, + the Johto starters) (again w/o adding anything), refer to Party::recieveGiftOrEventPkm(id)

Share this post


Link to post
Share on other sites
I've not tried to modify anything ... but looking at the code, you can lift the restriction on Shadow Pkms in the Daycare (w/o adding any instruction, just by modifiying the existing ones), and I'm sure you can change the Pokémon given by Duking (+ Elekid, + the Johto starters) (again w/o adding anything), refer to Party::recieveGiftOrEventPkm(id)

Sounds good. So I've been looking at some of the disassembled scripts and I think I'm starting to get a feel for how it all works. For class methods like Party::recieveGiftOrEventPkm(id) or Character::setVisibility did you find out what they do by trial and error and did you name them yourself?

Share this post


Link to post
Share on other sites
Sounds good. So I've been looking at some of the disassembled scripts and I think I'm starting to get a feel for how it all works. For class methods like Party::recieveGiftOrEventPkm(id) or Character::setVisibility did you find out what they do by trial and error and did you name them yourself?

Named them myself (see FunctionInfo for the "whole" list).

For Party::recieveGiftOrEvent I already knew the function that was used to generate never-shiny-if-shadow/can-be-shiny-if-not Pokémon, and for Character::setVisibility it was indeed by trial and error when debugging.

Share this post


Link to post
Share on other sites
Named them myself (see FunctionInfo for the "whole" list).

For Party::recieveGiftOrEvent I already knew the function that was used to generate never-shiny-if-shadow/can-be-shiny-if-not Pokémon, and for Character::setVisibility it was indeed by trial and error when debugging.

Yeah I'm looking through your code now. Impressive work ;).

Share this post


Link to post
Share on other sites

Looks like there is a buffer overflow vulnerability in the implementation of the script version of printf:

ROM:801BE670 # int __fastcall scriptPrintf(void *format, void *args)
ROM:801BE670 scriptPrintf:                           # CODE XREF: scriptStdFunctions2Handler+270p
ROM:801BE670
ROM:801BE670 .set var_12C, -0x12C
ROM:801BE670 .set sprintf_buffer, -0x128
ROM:801BE670 .set var_28, -0x28
ROM:801BE670 .set var_1C, -0x1C
ROM:801BE670 .set lr,  4
ROM:801BE670
ROM:801BE670                 stwu      r1, -0x130(r1)
ROM:801BE674                 mflr      r0
ROM:801BE678                 stw       r0, 0x130+lr(r1)
ROM:801BE67C                 stmw      r25, 0x130+var_1C(r1)
ROM:801BE680                 mr        r26, r3
ROM:801BE684                 mr        r29, r4

# ... NOTE: this function refers to "script error line[%d] : printf argument %d error \n"

ROM:801BE840 loc_801BE840:                           # CODE XREF: scriptPrintf+1C4j
ROM:801BE840                 add       r3, r29, r27  # var
ROM:801BE844                 lha       r0, 0(r3)
ROM:801BE848                 cmpwi     r0, 3
ROM:801BE84C                 bne       loc_801BE884
ROM:801BE850                 lwz       r4, 0x954(r26) # dst
ROM:801BE854                 bne       loc_801BE860
ROM:801BE858                 lwz       r6, 4(r3)
ROM:801BE85C                 b         loc_801BE868
ROM:801BE860 # ---------------------------------------------------------------------------
ROM:801BE860
ROM:801BE860 loc_801BE860:                           # CODE XREF: scriptPrintf+1E4j
ROM:801BE860                 bl        scriptConvertToString
ROM:801BE864                 mr        r6, r3
ROM:801BE868
ROM:801BE868 loc_801BE868:                           # CODE XREF: scriptPrintf+1ECj
ROM:801BE868                 addi      r3, r1, 0x130+sprintf_buffer # str
ROM:801BE86C                 addi      r4, r2, -0x56E8 # aSS # format
ROM:801BE870                 mr        r5, r3
ROM:801BE874                 crclr     4*cr1+eq
ROM:801BE878                 bl        sprintf       # "%s%s" # BOOOOOOOOOOOOOOOOOOOOOOOOOOOOOM
ROM:801BE87C                 mr        r25, r3
ROM:801BE880                 b         loc_801BEA20

# ...
# the buffer is cleared IFF '\\n' is encountered
ROM:801BEA2C # ---------------------------------------------------------------------------
ROM:801BEA2C
ROM:801BEA2C loc_801BEA2C:                           # CODE XREF: scriptPrintf+80j
ROM:801BEA2C                 cmpwi     r0, 0x5C      # '\'
ROM:801BEA30                 bne       loc_801BEAB8
ROM:801BEA34                 addi      r30, r30, 1
ROM:801BEA38                 lbz       r0, 0(r30)
ROM:801BEA3C                 extsb     r0, r0
ROM:801BEA40                 cmpwi     r0, 'n'       # '\n'
ROM:801BEA44                 bne       loc_801BEA94
ROM:801BEA48                 addi      r3, r1, 0x130+sprintf_buffer # str
ROM:801BEA4C                 addi      r4, r2, -0x56D8 # aS_0 # format
ROM:801BEA50                 mr        r5, r3
ROM:801BEA54                 crclr     4*cr1+eq
ROM:801BEA58                 bl        sprintf
ROM:801BEA5C                 addi      r3, r1, 0x130+sprintf_buffer # msg
ROM:801BEA60                 crclr     4*cr1+eq
ROM:801BEA64                 bl        sendToLog     # '%s\n'
ROM:801BEA68                 li        r5, 0
ROM:801BEA6C                 li        r0, 0x100
ROM:801BEA70                 addi      r3, r1, 0x130+sprintf_buffer
ROM:801BEA74                 li        r4, 0
ROM:801BEA78                 mtctr     r0
ROM:801BEA7C
ROM:801BEA7C loc_801BEA7C:                           # CODE XREF: scriptPrintf+418j
ROM:801BEA7C                 stb       r4, 0(r3)     # clear temporary buffer
ROM:801BEA80                 addi      r5, r5, 1
ROM:801BEA84                 addi      r3, r3, 1
ROM:801BEA88                 bdnz      loc_801BEA7C
ROM:801BEA8C                 li        r25, 0
ROM:801BEA90                 b         loc_801BEAC4

# ...

ROM:801BEAB8
ROM:801BEAB8 loc_801BEAB8:                           # CODE XREF: scriptPrintf+3C0j
ROM:801BEAB8                 addi      r3, r1, 0x130+sprintf_buffer
ROM:801BEABC                 stbx      r0, r3, r25
ROM:801BEAC0                 addi      r25, r25, 1
ROM:801BEAC4
ROM:801BEAC4 loc_801BEAC4:                           # CODE XREF: scriptPrintf+3B8j
ROM:801BEAC4                                         # scriptPrintf+420j ...
ROM:801BEAC4                 addi      r30, r30, 1
ROM:801BEAC8
ROM:801BEAC8 loc_801BEAC8:                           # CODE XREF: scriptPrintf+74j
ROM:801BEAC8                 lbz       r3, 0(r30)
ROM:801BEACC                 extsb     r0, r3
ROM:801BEAD0                 cmpwi     r0, 0
ROM:801BEAD4                 bne       loc_801BE6E8
ROM:801BEAD8                 addi      r3, r1, 0x130+sprintf_buffer # msg
ROM:801BEADC                 lbzx      r0, r3, r25
ROM:801BEAE0                 extsb     r0, r0
ROM:801BEAE4                 cmpwi     r0, 0xA       # '\n'
ROM:801BEAE8                 beq       loc_801BEB04
ROM:801BEAEC                 cmpwi     r25, 0
ROM:801BEAF0                 beq       loc_801BEB04
ROM:801BEAF4                 li        r0, 0xA
ROM:801BEAF8                 stbx      r0, r3, r25   # msg
ROM:801BEAFC                 crclr     4*cr1+eq
ROM:801BEB00                 bl        sendToLog
ROM:801BEB04
ROM:801BEB04 loc_801BEB04:                           # CODE XREF: scriptPrintf+478j
ROM:801BEB04                                         # scriptPrintf+480j
ROM:801BEB04                 li        r3, 0         # empty string
ROM:801BEB08
ROM:801BEB08 loc_801BEB08:                           # CODE XREF: scriptPrintf+11Cj
ROM:801BEB08                                         # scriptPrintf+1BCj ...
ROM:801BEB08                 lmw       r25, 0x130+var_1C(r1)
ROM:801BEB0C                 lwz       r0, 0x130+lr(r1)
ROM:801BEB10                 mtlr      r0
ROM:801BEB14                 addi      r1, r1, 0x130
ROM:801BEB18                 blr
ROM:801BEB18 # End of function scriptPrintf

Share this post


Link to post
Share on other sites

Hey, do you think you could add to the script disassembler so that each instruction has it's offset in the script file next to it? It will make it a bit easier to figure out where to go to manually change instructions. Thanks

Share this post


Link to post
Share on other sites

Hey, are you still working on this and have you looked into the scripts any further? I spent a lot of time looking at a bunch of the scripts recently and it's really started to make sense to me. I even tested out a few minor changes which I made manually and it all works as one would expect.

In particular have you discovered any more classes/class functions? I've identified a handful more from what was in the repo last time I checked (like giving the player items and triggering battles) and thought I could help add to the list if you haven't discovered them yet.

I was also wondering if you knew the significance of the "setline" that appears throughout the scripts because it's just about the only thing I don't understand at this point.

Share this post


Link to post
Share on other sites

Sorry for not reponding ^^'

In particular have you discovered any more classes/class functions? I've identified a handful more from what was in the repo last time I checked (like giving the player items and triggering battles) and thought I could help add to the list if you haven't discovered them yet.

I didn't made any research on xD for some time; however I've identified some other classes (Shadow Pokémon handling, party handling) but the problem is that I'm missing the significance of many of their methods... feel free to PR though.

I was also wondering if you knew the significance of the "setline" that appears throughout the scripts because it's just about the only thing I don't understand at this point.

It's debugging information, and it's most likely a remnant of a higher-level language being assembled.

Share this post


Link to post
Share on other sites
Sorry for not reponding ^^'

I didn't made any research on xD for some time; however I've identified some other classes (Shadow Pokémon handling, party handling) but the problem is that I'm missing the significance of many of their methods... feel free to PR though.

It's debugging information, and it's most likely a remnant of a higher-level language being assembled.

That's okay :)

So do you know what happens if the setlines are overwritten? Also, does that mean that you never need to use them when writing your own scripts?

Share this post


Link to post
Share on other sites
That's okay :)

So do you know what happens if the setlines are overwritten? Also, does that mean that you never need to use them when writing your own scripts?

It's only debugging info iirc.

Pokémon xD has a debugging menu disabled on retail. I've made a code to make it appear a while ago, but it was PAL only and doesn't work on latest Dolphin releases.

Basically it just displays timers, currently running functions on each task with the lines, and the free stack space for each task.

Share this post


Link to post
Share on other sites
It's only debugging info iirc.

Pokémon xD has a debugging menu disabled on retail. I've made a code to make it appear a while ago, but it was PAL only and doesn't work on latest Dolphin releases.

Basically it just displays timers, currently running functions on each task with the lines, and the free stack space for each task.

Oh that's cool. It might be possible to shrink the scripts by removing all the debugging lines. Would make it a lot easier to add new functions without having to worry about the compression sizes!

Share this post


Link to post
Share on other sites

Why is compression size an issue?

Be careful as you'll need to move all branches since they are absolute.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...