-
Notifications
You must be signed in to change notification settings - Fork 3
Getting started with MSC
MSC (specifically raw MSC) is a custom bytecode used in Super Smash Brothers for Wii U. It is based around the concept of commands that push values onto a stack and popping them back off in order to have any operation use the result of any other operation as a parameter allowing for things such as advanced arithmetic, logic and control flow operations.
For those unfamiliar with what a stack is, a stack is a data structure in memory that follows a FILO (First in, last out) method of storing a set of values. There are two operations in a stack, pushing and popping. Pushing something onto a stack puts it on the top of the stack, popping something takes something off the top of the stack. Think of it like a stack of books, if I have a red book on the bottom, a blue book in the middle and a green book on top and I put a yellow book on the top I am "pushing" it onto the stack. If I proceed to take the yellow book off and then the green book, I am popping both of them off. For further reading see the wikipedia page, youtube also is a great source for graphical explanations of the concept of a stack.
Pymsc ASM syntax is pretty simple for the most part. It involves an opcode, an optional push indicator and parameters. For example:
pushInt. 0x30
is command "pushInt", the .
is telling it to push it onto the stack, and the 0x30 is the parameter being pushed onto the stack. When multiple parameters are used for a command they should be separated by a comma. Some commands require referencing specific locations within the same script. For these you use labels, which are a name followed by a colon at the location you want that name to reference. For example:
begin 0x1, 0x1
pushVar. 0x0, 0x0
pushInt. 0x0
notEqual.
if test
pushInt. 0x19
pushInt. 0x1f000009
sys 0x2, 0x16
else loc_33
test:
pushInt. 0x1a
pushInt. 0x1f000009
sys 0x2, 0x16
"test" is a label that is used by the if
command in order to reference the position right before the
push. 0x1a
command. This can also be done with script positions, for any command if you use "script_#" (where # is a number) as a parameter it will be treated as the offset to the script in question. The # is the index of the script in the Scripts
file (see repo README for more info about Scripts
files). If we have a Scripts file like
test1.txt
test2.txt
:startingPoint.txt
then test1.txt is script_0, test2.txt is script_1 and startingPoint.txt is script_2. It isn't just positions that you can make easier to read. If you have a value that you use that you want to have a name (for example if you want to name your variable ids) then you can use aliases. Here's an example:
.alias 3,stockCount
pushInt. 4
setVar 0,stockCount
This is the same as
pushInt. 4
setVar 0,3
but with improved readability. It is suggested you use the alias feature of pymsc in order to make the source of your modifications easy to read by others and easy to figure out if you return to it, as well as if you make the source public (open source character mods are certainly encouraged!). You can also make global aliases. For example if you want every script to use localVar
instead of 0
as the variable type for commands like setVar
you can use a globals file in order to apply an alias globally.
Scripts file
>globals.txt
script_0.txt
:script_1.txt
globals.txt
.alias 0,localVar
.alias 1,globalVar
script_0.txt
begin
pushInt. 0xFFFFFFFF
setVar. globalVar,0
end
The global files are also used for storing strings, which are referenced by index from printf commands. The syntax for declaring a string is:
.string [string]