Skip to main content

Documentation 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.

Every EVT script is a flat Bytecode array interpreted by the EVT virtual machine. Each instruction begins with an opcode constant from the EVT_OP_* enum (defined in include/evt.h), followed by an argument count and then the argument values. You never write these low-level arrays by hand — the high-level macros in include/script_api/macros.h generate them — but understanding the opcode set helps you read decompiled scripts and diagnose unexpected behavior.
EVT_OP_INTERNAL_FETCH (value 0) is used internally by the VM to prefetch the next instruction. You will never write it in a script, and the assembler macros never emit it directly.

Control flow

These opcodes govern branching, looping, and early exit from a script.
OpcodeMacroArgsDescription
EVT_OP_ENDEndSignals the end of script data. Every script must terminate with this; a missing End will likely crash on load.
EVT_OP_RETURNReturnKills the current thread. A script missing Return will remain alive but do nothing until something else (e.g. leaving the map) kills it.
EVT_OP_LABELLabel(id)idMarks a jump target. Valid label IDs are 0–22.
EVT_OP_GOTOGoto(id)idMoves execution to the label with the given ID.
EVT_OP_LOOPLoop(times)timesBegins a loop. The counter is decremented after each iteration. Loop(0) loops infinitely. Up to 8 loops may be nested.
EVT_OP_END_LOOPEndLoopMarks the end of a loop body.
EVT_OP_BREAK_LOOPBreakLoopExits the innermost loop immediately.
EVT_OP_WAIT_FRAMESWait(n)nBlocks the thread for n frames. This is one of the four blocking instructions.
EVT_OP_WAIT_SECSWaitSecs(n)nBlocks the thread for n seconds.
EVT_OP_IF_EQIfEq(a, b)a, bBegins an if block that executes only when a == b.
EVT_OP_IF_NEIfNe(a, b)a, bExecutes when a != b.
EVT_OP_IF_LTIfLt(a, b)a, bExecutes when a < b.
EVT_OP_IF_GTIfGt(a, b)a, bExecutes when a > b.
EVT_OP_IF_LEIfLe(a, b)a, bExecutes when a <= b.
EVT_OP_IF_GEIfGe(a, b)a, bExecutes when a >= b.
EVT_OP_IF_FLAGIfFlag(a, b)a, bExecutes when (a & b) != 0.
EVT_OP_IF_NOT_FLAGIfNotFlag(a, b)a, bExecutes when (a & b) == 0.
EVT_OP_ELSEElseBegins the else branch of an if block.
EVT_OP_END_IFEndIfCloses an if or else block.
EVT_OP_JUMPJump(script)EvtScript*Jumps unconditionally to another script pointer, resetting the timescale. Labels and other state are loaded from the target source.

Switch statements

EVT switch statements do not have implicit fallthrough; use CaseOrEq when you need it.
OpcodeMacroArgsDescription
EVT_OP_SWITCHSwitch(expr)exprBegins a switch over an expression resolved through evt_get_variable. Up to 8 switches may be nested.
EVT_OP_SWITCH_CONSTSwitchConst(val)valBegins a switch where the value is used as-is, without variable lookup.
EVT_OP_CASE_EQCaseEq(val)valMatches when the switch expression equals val.
EVT_OP_CASE_NECaseNe(val)valMatches when not equal.
EVT_OP_CASE_LTCaseLt(val)valMatches when less than.
EVT_OP_CASE_GTCaseGt(val)valMatches when greater than.
EVT_OP_CASE_LECaseLe(val)valMatches when less than or equal.
EVT_OP_CASE_GECaseGe(val)valMatches when greater than or equal.
EVT_OP_CASE_DEFAULTCaseDefaultMatches unconditionally; used as the default case.
EVT_OP_CASE_OR_EQCaseOrEq(val)valLike CaseEq, but falls through to the next case until EndCaseGroup.
EVT_OP_CASE_AND_EQCaseAndEq(val)valFalls through only if expr == val; skips the group body otherwise.
EVT_OP_CASE_FLAGCaseFlag(val)valMatches when the flag bit val is set on the switch expression.
EVT_OP_END_CASE_GROUPEndCaseGroupCloses a CaseOrEq / CaseAndEq fallthrough group.
EVT_OP_CASE_RANGECaseRange(min, max)min, maxMatches when min <= expr <= max (inclusive).
EVT_OP_BREAK_SWITCHBreakSwitchExits the current switch block.
EVT_OP_END_SWITCHEndSwitchCloses the switch statement.

Variables and assignment

EVT encodes variable references as large negative integers so they are distinguishable from literal values. The evt_get_variable and evt_set_variable functions decode the encoding at runtime.
OpcodeMacroArgsDescription
EVT_OP_SETSet(var, val)var, valSets var to the integer result of evaluating val through evt_get_variable.
EVT_OP_SET_CONSTSetConst(var, const)var, constSets var to const as-is, skipping variable lookup.
EVT_OP_SETFSetF(var, val)var, valSets var to a fixed-point float value via evt_get_float_variable.

Integer arithmetic

All arithmetic opcodes read from and write back to a variable container.
OpcodeMacroArgsDescription
EVT_OP_ADDAdd(var, val)var, valvar += val
EVT_OP_SUBSub(var, val)var, valvar -= val
EVT_OP_MULMul(var, val)var, valvar *= val
EVT_OP_DIVDiv(var, val)var, valInteger division: var /= val
EVT_OP_MODMod(var, val)var, valvar %= val

Floating-point arithmetic

These operate on fixed-point floats using the same encoding as Float() and SetF.
OpcodeMacroArgsDescription
EVT_OP_ADDFAddF(var, val)var, valvar += val (float)
EVT_OP_SUBFSubF(var, val)var, valvar -= val (float)
EVT_OP_MULFMulF(var, val)var, valvar *= val (float)
EVT_OP_DIVFDivF(var, val)var, valvar /= val (float)

Bitwise operations

OpcodeMacroArgsDescription
EVT_OP_BITWISE_ANDBitwiseAnd(var, val)var, valvar &= valval is resolved through evt_get_variable.
EVT_OP_BITWISE_AND_CONSTBitwiseAndConst(var, const)var, constvar &= constconst is used as-is.
EVT_OP_BITWISE_ORBitwiseOr(var, val)var, valvar |= val
EVT_OP_BITWISE_OR_CONSTBitwiseOrConst(var, const)var, constvar |= constconst is used as-is.

Buffers and arrays

Scripts can read sequential data from a C pointer via buffer opcodes, or access named elements via array opcodes.
OpcodeMacroArgsDescription
EVT_OP_USE_BUFUseBuf(ptr)s32*Sets the integer buffer pointer for subsequent BufRead calls.
EVT_OP_BUF_READ1BufRead1(v)containerReads one s32 from the buffer and advances the read position.
EVT_OP_BUF_READ2BufRead2(v1, v2)container, containerReads two s32 values.
EVT_OP_BUF_READ3BufRead3(v1, v2, v3)3 containersReads three s32 values.
EVT_OP_BUF_READ4BufRead4(v1, v2, v3, v4)4 containersReads four s32 values.
EVT_OP_BUF_PEEKBufPeek(idx, v)index, containerReads the s32 at idx without advancing the position.
EVT_OP_USE_FBUFUseFBuf(ptr)f32*Identical to UseBuf for float buffers (same underlying pointer).
EVT_OP_FBUF_READ1FBufRead1(v)containerReads one f32.
EVT_OP_FBUF_READ2FBufRead2(v1, v2)2 containersReads two f32 values.
EVT_OP_FBUF_READ3FBufRead3(v1, v2, v3)3 containersReads three f32 values.
EVT_OP_FBUF_READ4FBufRead4(v1, v2, v3, v4)4 containersReads four f32 values.
EVT_OP_FBUF_PEEKFBufPeek(idx, v)index, containerReads the f32 at idx without advancing.
EVT_OP_USE_ARRAYUseArray(ptr)s32*Loads an s32 array for use with ArrayVar(index).
EVT_OP_USE_FLAGSUseFlagArray(ptr)s32*Loads a packed flag array for use with ArrayFlag(index).
EVT_OP_MALLOC_ARRAYMallocArray(size, outVar)length, s32*Allocates a new array of size elements. Scripts do not free this memory.

Script execution

OpcodeMacroArgsDescription
EVT_OP_EXECExec(script)EvtScript*Spawns a new independent thread. The parent continues immediately.
EVT_OP_EXEC_GET_TIDExecGetTID(script, outVar)EvtScript*, containerSpawns a thread and stores its thread ID for later use with KillThread, SuspendThread, etc.
EVT_OP_EXEC_WAITExecWait(script)EvtScript*Spawns a child thread and blocks until it returns. Local variables and flags are copied back on completion. This is a blocking instruction.
EVT_OP_CALLCall(func, ...)*function, ...Calls a C API_CALLABLE function with optional arguments. Blocking if the function returns ApiStatus_BLOCK.

Thread management

OpcodeMacroArgsDescription
EVT_OP_BIND_TRIGGERBindTrigger(script, trigger, colliderID, unkA3, outVar)5 argsRegisters a script to run when a trigger fires (e.g. TRIGGER_FLOOR_TOUCH). Only one thread runs per trigger at a time.
EVT_OP_BIND_PADLOCKBindPadlock(script, trigger, colliderID, itemList, unkA3, outVar)6 argsLike BindTrigger, but also specifies an item list for padlock interactions.
EVT_OP_UNBINDUnbindRemoves the current thread’s trigger binding.
EVT_OP_KILL_THREADKillThread(tid)ScriptIDTerminates the thread with the given ID.
EVT_OP_SUSPEND_GROUPSuspendGroup(group)groupPauses all threads belonging to group.
EVT_OP_RESUME_GROUPResumeGroup(group)groupResumes all threads in group.
EVT_OP_SUSPEND_OTHERSSuspendOthers(group)groupPauses all threads in group except the current one.
EVT_OP_RESUME_OTHERSResumeOthers(group)groupResumes all threads in group except the current one.
EVT_OP_SUSPEND_THREADSuspendThread(tid)ScriptIDPauses a specific thread by ID.
EVT_OP_RESUME_THREADResumeThread(tid)ScriptIDResumes a specific thread by ID.
EVT_OP_IS_THREAD_RUNNINGIsThreadRunning(tid, outVar)ScriptID, containerSets outVar to true if a thread with the given ID is still alive.
EVT_OP_SET_PRIORITYSetPriority(priority)prioritySets the current thread’s execution priority. Higher values run first.
EVT_OP_SET_TIMESCALESetTimescale(scale)timescaleSets a multiplier applied to Wait and WaitSecs durations.
EVT_OP_SET_GROUPSetGroup(group)groupAssigns the current thread to a group. See EventGroupFlags in include/evt.h.

Inline threads

These opcodes create threads inline within a script body rather than from an external EvtScript array.
OpcodeMacroDescription
EVT_OP_THREADThreadBegins an inline thread block. The enclosed commands run as a new, independent thread.
EVT_OP_END_THREADEndThreadCloses an inline thread block.
EVT_OP_CHILD_THREADChildThreadBegins an inline child thread block. The child is killed automatically when the parent dies.
EVT_OP_END_CHILD_THREADEndChildThreadCloses an inline child thread block.

Debug

These opcodes are stripped or become no-ops in the release build.
OpcodeMacroArgsDescription
EVT_OP_DEBUG_LOGEVT_DEBUG_LOG(str)stringLogs a string. Does nothing in the release build.
EVT_OP_DEBUG_PRINT_VARDebugPrintVar(var)expressionPrints the name and value of a variable.

Reserved opcodes

Opcodes EVT_OP_92, EVT_OP_93, and EVT_OP_94 appear in the enum but are not yet documented in the decompilation.

Build docs developers (and LLMs) love