Skip to content

Getting started with MSC

jam1garner edited this page Jul 17, 2017 · 1 revision

Language Overview

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.

The Stack

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

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]