So it looks like I've found out where the raw assembly of each of the PSA commands are stored. Moreover, I've also found where inside the character module files the 0C series commands are stored.
A long time ago, I mentioned that I'd found out that the first byte of each PSA command represented one or more module inside Brawl. This was the list that I posted at the time:
I'm not sure why, but I never took this bit of information any further at the time. Anyways, it turns out that these modules are stored inside the the Common2 module (
module id 1B). Moreover, each of these modules implement a specific interface soAnimCmdEventObserver. This interface is what allows the module to communicate with the instruction set used by PSA.
In order to find the methods used by the soAnimCmdEventObserver interface I needed to update the old Module Viewer 2. As it turns out, a small quirk in the method table which I was previously ignoring actually corresponded to which interfaces they belong to. It was just a dirty fix, so it's not anything fancy, but you'll need it if you want to find any of the PSA assembly code.
[Download]I guess I should warn everyone ahead of time, that in order to find the assembly of a specific PSA action, you'll need a really good understanding of assembly and a lot of patience - it also helps if you decide on what you're looking for beforehand.
For this example, I'll be looking for the Basic Variable Increment command - given by the PSA id 12030100.
Using the list up above, the first byte of this command (0x12) corresponds to soWorkManageModuleImpl. Start by opening up the common2 module in the new Module Viewer 2. Navigating through the object list to the soWorkManageModuleImpl object and opening up it's inheritance hierarchy, you'll spot the soAnimCmdEventObserver as well as its base; the soEventObserver<soAnimCmdEventObserver>. Observe that the Unknown value of both of them are 16. I'm not sure exactly what this value means, but what's important right now is that it seems to indicate the objects position in the inheritance hierarchy.
The method list has been reorganized so that the first index sorts the methods by inheritance and the second index distinguishes the individual methods. The higher the Unknown value of the inherited object, the higher the first index is for its corresponding methods. In this case, the soAnimCmdEventOberver's events are Method[1][0] to Method[1][5] (
just remember that it will likely be different for each module).
The soAnimCmdEventObserver methods usually have a pretty consistent layout. soAnimCmdEventObserver.Method[0] (
Method[1][0] in this case) seems to be some sort of initializer or hook function, but it isn't really all that interesting - the interesting ones are the two after it. soAnimCmdEventObserver.Method[1] is an identifier function which returns a boolean value depending on whether the first byte of the PSA command passed to it is equal to 12. If that function returns true, then the soAnimCmdEventObserver.Method[2] is called. This is the function that handles the rest of the PSA command.
As it turns out, Method[1] and Method[2] actually call Method[3] and Method[4] in this case so to get at the actual assembly, you'll have to look at those two instead. Just remember that it isn't always this way as things will vary wildly depending on what module you are looking at.
Anyways, if you open up Method[4] (Method[1][4]) - the main handler for the PSA commands starting with 0x12 - you'll be confronted with a ton of assembly you'll need to wade through. You're pretty much on your own here. However, it may help to know that the lines:
lwz r12,16(r12)
mtspr ctr,r12
bctr
extsb r0,r3
will put the second byte of the PSA command into r0. From here, you can follow the code through until you find the handler you're looking for - in this case we would be looking for a branch when r0 = 0x03.
Hey, I didn't say it was simple, and I can't really say it's all that useable for most people either. But this sort of knowledge could lead to a lot of potential. Mainly that using this could allow custom assembly scripts to be ran during gameplay whenever a certain PSA command is triggered.
A few other notes:
Some command set series draw upon multiple modules - such as the 06 series commands (
hitboxes and such). In particular, the 0C series draws upon not only the ft<character>.rel, but also a bunch of other unidentified modules.
When it comes to finding the character specific 0C series commands, you'll need to open the character's .rel file and navigate to the ft<FighterName> object. The main handlers there are actually Method[3][14] and Method[3][15].
Inside the Common2 module there's an object call soAnimCommandInterpreter or something. If I had to venture a guess, I'd say that's what is responsible for parsing PSA commands during gameplay.
That's about it for now. I haven't done any testing on it, so it's all pretty much theory until someone decides to try something with it and proves it - but for now, it seems pretty sound.