-
Notifications
You must be signed in to change notification settings - Fork 0
Zenkai Example Scripts
Every script is a flat stream of bytes. To decode it, read the first byte and look it up in the Main Dispatch Table — this tells you what kind of node you're dealing with. Each node type then consumes however many following bytes it needs, and execution moves to the next node.
The two most important things to know before reading any script:
-
Numbers are ZigZag encoded. A value like
0x81, 0x70is not two separate bytes — it is a single multi-byte integer. The high bit of each byte signals whether another byte follows. Once assembled, the raw value is zigzag-decoded: even values become positive, odd values become negative. So2is1,6becomes3,0x81 0x70is120,0x81 0x50is104. -
Opcodes are looked up separately. When a
Stepnode is encountered, the next byte is an index into the Opcode Table, not the dispatch table.0x02, 0x23means "Step, then execute opcode index 35 (0-based)" — which resolves toLoadMapWithEntities.
Arguments are passed via a stack. Nodes like PushByte and PushMultiVarint push values onto it.
Opcodes then pop what they need from the top, so arguments are pushed before the opcode that consumes them.
ROM Address: 0x083B827B
Raw bytes:
0x1D, 5, 2, 6, 2, 0x81, 0x70, 0x81, 0x50, 2, 0x23, 0, 0xB4, 2, 0x45, 0, 0xF0, 2, 0x28, 2, 0x2D, 0, 0x17, 2, 0x31, 0x11, 0, 0, 0
A world transition sequence, it pushes the destination map arguments onto the stack, loads the map with entities, waits a specific number of frames, fades out, swaps the sprite palette, and starts a music track.
| Bytes | Node | Resolves To | Notes |
|---|---|---|---|
0x1D, 5, 2, 6, 2, 0x81 0x70, 0x81 0x50, 2 |
PushMultiVarint(5) | [1, 3, 120, 104, 1] |
Pushes 5 zigzag-encoded varints — world 1, area 3, spawn X 120, spawn Y 104, variation 1
|
0x02, 0x23 |
Step(0x23) | LoadMapWithEntities | Pops all 5 stack values — loads world 1 area 3 at position 120, 104 with variation 1
|
0x00, 0xB4 |
PushByte | 180 |
Raw byte, no encoding |
0x02, 0x45 |
Step(0x45) | WaitFrames | Pops 180 — waits 180 frames before continuing |
0x00, 0xF0 |
PushByte | 240 |
Raw byte, no encoding |
0x02, 0x28 |
Step(0x28) | FadeOut | Pops 240 — fades out over 240 frames |
0x02, 0x2D |
Step(0x2D) | UploadSpritePalette | No args. Copies sprite palette to VRAM via DMA |
0x00, 0x17 |
PushByte | 23 |
Raw byte, no encoding |
0x02, 0x31 |
Step(0x31) | PlayMusic | Pops 23 — starts music track 23 |
0x11, 0, 0, 0 |
— | Terminator | Standard script end marker |
ROM Address: 0x083B831B
Raw bytes:
0, 2, 2, 0x18, 0, 0x78, 2, 0x2A, 0x1D, 2, 6, 0xC, 2, 0x62, 0, 3, 2, 0x46, 0x1D, 5, 2, 2, 2, 0x83, 0x10, 0x8A, 0x30, 2, 0x27, 0, 0x78, 2, 0x2B, 0x11, 0, 0, 0
A level up transition sequence. Disables a display layer, fades to white, sets the specified character to level 6, then warps to zone 1 area 1.
| Bytes | Node | Resolves To | Notes |
|---|---|---|---|
0x00, 0x02 |
PushByte | 2 |
Raw byte, no encoding |
0x02, 0x18 |
Step(0x18) | DisableLayer | Pops 2 — disables display layer 2 |
0x00, 0x78 |
PushByte | 120 |
Raw byte, no encoding |
0x02, 0x2A |
Step(0x2A) | FadeToWhite | Pops 120 — fades to white over 120 frames |
0x1D, 2, 6, 0x0C |
PushMultiVarint(2) | [3, 6] |
Pushes 2 zigzag-encoded varints — char index 3, level 6
|
0x02, 0x62 |
Step(0x62) | SetCharacterLevel | Pops 3 (char index), 6 (level) |
0x00, 0x03 |
PushByte | 3 |
Raw byte, no encoding |
0x02, 0x46 |
Step(0x46) | SetActiveCharacter | Pops 3 — sets character 3 as active |
0x1D, 5, 2, 2, 2, 0x83 0x10, 0x8A 0x30, 2 |
PushMultiVarint(5) | [1, 1, 1, 200, 664] |
Pushes 5 zigzag-encoded varints — zone 1, area 1, variation 1, spawn X 200, spawn Y 664
|
0x02, 0x27 |
Step(0x27) | WarpToMapNoEntities | Pops all 5 stack values — warps to zone 1 area 1 at position 200, 664 with variation 1
|
0x00, 0x78 |
PushByte | 120 |
Raw byte, no encoding |
0x02, 0x2B |
Step(0x2B) | sub_8009B94 | Pops 120 — unknown, likely a fade or wait |
0x11, 0, 0, 0 |
— | Terminator | Standard script end marker |