Patch Files
See Writing a Patch for a basic walkthrough. This page collects the exact local and global patch forms.
Common Syntax
Section titled “Common Syntax”| Syntax | Description |
|---|---|
% comment | Single-line comment. |
/%...%/ | Multi-line comment. Everything between the delimiters is replaced with a single space. |
@ $Pointer {...} | Patch the named structure. |
@ $Pointer {[40]...} | Begin writing at an offset within the structure. |
@ $Pointer {[40] ...[60] ...} | Write at several offsets. Each offset must begin on a new line. |
@ $Pointer [40] {[10] ...[20] ...} | Set a base offset. The writes begin at $Pointer[50] and $Pointer[60]. |
.Constant | Local or global constant, enum value, or structure-specific constant. |
*ScriptVariable | Encoded script variable. |
~Expression | Value or data generated by a Star Rod expression. |
#directive | Import, declaration, alias, export, or another compiler instruction. |
Function patches contain MIPS assembly. Script patches contain event-script commands. Strings use message markup. Other structures interpret their contents according to their registered type.
Local Directives
Section titled “Local Directives”#new:StructType $StructName
Section titled “#new:StructType $StructName”Creates a structure and begins reading its body. The structure may be patched again by name later in the file.
#import OtherFile.mpat
Section titled “#import OtherFile.mpat”Imports every patch from a file in the relevant import/ directory. Battle imports may also use the import/enemy/ directory. Imports are valid in map, battle, move, and similar overlay patches, not in global patches.
An optional namespace qualifies every imported name:
#import MyFile.bpat FileNamespaceThe imported structures have names such as $FileNamespace:PointerName. Nested imports produce nested names such as $Outer:Inner:OriginalName.
An import may pass named options to the imported file. Add a body containing one Name=Value assignment per line:
#import Configurable.mpat Shared { Mode=Hard IncludeExtraData=true TableVal=20}Option names and comparisons are case-insensitive. Each value must be a single token. A constant may be supplied as a value and is resolved before it is passed to the imported file.
The imported file may use the following preprocessor directives:
| Directive | Description |
|---|---|
##[IF:Name] | Include the following branch when the option is defined. |
##[IF:Name:Value] | Include the following branch when the option has the specified value. |
##[IFNOT:Name] | Include the following branch when the option is not defined. |
##[IFNOT:Name:Value] | Include the following branch when the option does not have the specified value. An undefined option also satisfies this condition. |
##[ELSEIF:Name] | Begin another branch selected when the option is defined and no earlier branch matched. |
##[ELSEIF:Name:Value] | Begin another branch selected when the option has the specified value and no earlier branch matched. |
##[ELSEIFNOT:Name] | Begin another branch selected when the option is not defined and no earlier branch matched. |
##[ELSEIFNOT:Name:Value] | Begin another branch selected when the option does not have the specified value and no earlier branch matched. |
##[ELSE] | Begin the fallback branch. |
##[ENDIF] | End the conditional. |
##[VALUE:Name] | Replace the directive with the option value. |
Conditionals may be nested. Every IF or IFNOT must have a matching ENDIF, and ELSEIF, ELSEIFNOT, and ELSE apply to the nearest open conditional. VALUE may appear within a declaration or body line; using an undefined value in an active branch is an error.
For example, Configurable.mpat could select a structure and substitute a value passed by the importing patch:
##[IF:Mode:Hard]#new:Data $ModeData { 2}##[ELSE]#new:Data $ModeData { 1}##[ENDIF]
#new:Data $Table { ##[VALUE:TableVal]}Options are scoped to a single import. A nested import receives its own option body; values can be forwarded explicitly with ##[VALUE:Name].
#define .Name Value
Section titled “#define .Name Value”Creates a constant for the current patch. Global constants must be defined in a global patch or enum file.
#alias $ExistingName $Alias
Section titled “#alias $ExistingName $Alias”Adds another name for an existing structure.
#delete $StructName
Section titled “#delete $StructName”Clears the region occupied by an existing local structure so the space may be reused.
#reserve StartAddress EndAddress
Section titled “#reserve StartAddress EndAddress”Reserves a region of RAM in a local overlay. New structures will not be placed there. Only one region may be reserved in a patch file.
Global Patches
Section titled “Global Patches”Files under $mod/globals/patch/ are applied directly to the ROM and compiled into every build.
Existing data is addressed with a type and ROM address:
@Data XXXX@Function XXXX@Hook XXXX@Script:Global XXXX@Script:Map XXXX@Script:Battle XXXX@Fill repeats its body from the first address to the second, truncating the last repetition if necessary:
@Fill XXXX YYYYNew global structures use the same typed declaration model:
#new:Data $Name#new:Function $Name#new:Script:Global $Name#new:Script:Map $Name#new:Script:Battle $Name#reserve XXXX $Name reserves XXXX bytes of RAM and stores the resulting address in $Name.
| Directive | Description |
|---|---|
#export:Function $GlobalFunction | Create and export a global structure. |
#export .NewConstName XXXX | Create and export a global constant. |
#export $GlobalPointer | Export an existing structure. |
#export .ExistingConstName | Export an existing constant. |
For structures, #export: is a shorthand for creating a globally visible #new: declaration.