Every interactive element in Paper Mario’s world — doors, NPCs, cutscenes, shops — runs as an EVT script. You write scripts asDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/pmret/papermario/llms.txt
Use this file to discover all available pages before exploring further.
const Bytecode[] arrays in C, but you never write raw opcodes by hand. The macro layer in include/script_api/macros.h gives you a readable, structured syntax that compiles down to the bytecode the VM expects. This page walks you through the core patterns so you can read existing scripts and contribute new ones.
Script structure
A script is declared asEvtScript (a typedef for Bytecode[]) and terminated with End. Without End, the interpreter will walk past the end of the array and almost certainly crash.
N() is a name-mangling macro used by the map overlay system to avoid symbol collisions between areas. Every script defined inside a map overlay should use it. Scripts in src/evt/ (shared scripts) do not.
Every instruction macro places a trailing comma after its bytecode, so lines in a script body do not need extra separators. The C array initializer syntax treats the entire block as comma-separated values.
Script variables
EVT encodes different variable classes as large negative integers, allowing the interpreter to distinguish them from literal values at runtime. The macros ininclude/script_api/macros.h do this encoding for you.
Local variables
Local Words (LVar0–LVarF, i.e. LocalVar(0)–LocalVar(15)) are per-thread integer variables. They are copied into any child thread spawned by Exec, ExecWait, Thread, or ChildThread. ExecWait also copies them back when the child finishes.
LFlag0–LFlagF, i.e. LocalFlag(0)–LocalFlag(15)) are boolean variants with the same lifetime and copy semantics.
Map variables and flags
Map Words (MapVar(0)–MapVar(15)) are global across all threads in a map and are cleared when you leave. Map Flags (MapFlag(0)–MapFlag(95)) are the boolean equivalent.
Persistent variables
| Macro | Storage | Description |
|---|---|---|
GameFlag(n) | Save file | Persistent boolean, 0–2047. Used for story progress, item collection. |
AreaFlag(n) | Save file, area-scoped | Persistent boolean, 0–255. Cleared when you move to a different world area. Used for respawnable coins, Goomnuts, etc. |
GameByte(n) | Save file | Persistent integer. Used for almost all savefile state. |
AreaByte(n) | Save file, area-scoped | Persistent integer, 0–15. Cleared with a new area. |
Float literals
Floats in EVT are encoded as fixed-point values (1024 units = 1.0). Use theFloat() macro when passing float literals and SetF / AddF / etc. when operating on float variables:
Array variables
UseMallocArray or UseArray to attach an s32 array to the thread, then access elements with ArrayVar(index):
Control flow
Conditionals
Else block is optional. Comparisons available: IfEq, IfNe, IfLt, IfGt, IfLe, IfGe, IfFlag, IfNotFlag.
The shorthand macros IfTrue(b) and IfFalse(b) expand to IfNe(b, 0) and IfEq(b, 0) respectively.
Switch statements
EVT switch statements do not fall through by default. UseCaseOrEq for intentional fallthrough.
Loops
Labels and Goto
UseLabel and Goto for simple jumps without the overhead of a loop construct:
Calling API functions
Call invokes any API_CALLABLE function and passes arguments after the function pointer. Arguments are resolved as EVT expressions, so you can pass literals, variable references (LVar0), float literals (Float(1.5)), and pointer constants (Ref(myArray)).
Call targets a blocking function (one that returns ApiStatus_BLOCK), the script thread suspends until the function returns ApiStatus_DONE1 or ApiStatus_DONE2.
Inline thread blocks
You can fork a thread inline without a separateEvtScript array:
ChildThread / EndChildThread creates a thread that is automatically killed when the parent dies:
Spawning and waiting on scripts
Binding triggers
BindTrigger registers a script to run when the player interacts with a collider or entity:
Unbind inside the triggered script to remove the binding after it fires.
A complete example
The following script is drawn fromsrc/world/area_kmr/kmr_02/main.c. It opens a gate by animating a rotation lerp, then modifies collider flags so the player can pass through:
MakeLerpinitializes a lerp;UpdateLerpadvances it each frame, writing the current value intoLVar0and a “still running” flag intoLVar1.Wait(1)inside the label loop prevents a freeze.IfEq(LVar1, 1) / Goto(0)loops back while the lerp is active.
Defining a local callable
You can define anAPI_CALLABLE function directly in a map file and call it from a script in the same file. Use the N() macro to avoid symbol conflicts:
INCLUDE_ASM for unmatched scripts
Scripts that have not yet been matched to C source are kept in hand-written MIPS assembly and pulled in withINCLUDE_ASM:
INCLUDE_ASM line with the equivalent C definition using the EVT macros described on this page.
