Incense, doors and the Door of Light
Four ways Legend of Legaia lets a player go where the story is not ready for them: an Incense notice that swallows a cutscene trigger, an Incense effect that outlives its save file, a boss-room door that opens to one button press from beside its guards, and one patch of floor in Nivora Ravine where a Door of Light works. Each is traced to the code and scene data on the USA disc.
0x801CE818) and from the scene files. The Juggernaut Room door is also captured on an emulator, and its section says how each capture was set up; so is one reading in the carry-over section. The rest is static: where those sections say what a debugger shows, that is a prediction from the code. The player's movement lock is bit 0x80000 of player[+0x10], with the player actor at *0x8007C364; a tile is 128 units, and the player's tile is its position shifted right by 7.
Incense trigger bypass
- Reported as
- When the notice that the Incense has worn off appears on the step that would have entered a cutscene trigger or loading zone, the notice wins and the trigger never fires (community report).
- Cause
- The Incense expiry sets the movement lock mid-frame; the player still steps onto the trigger tile, and a locked crossing is recorded without running.
- Where
- Field overlay, PROT 0897:
FUN_801D0B90(walk tick) andFUN_801D1EC4(walk-on dispatcher) - Affects
- Walk-on records and intra-scene teleports that are one tile deep on the line walked; Jette and the three Uru Mais dreams match on the disc
- Status
- explained - read from the disc, not captured on an emulator
The trigger code never looks at the Incense. What the two share is the movement lock, the bit that tells the game a script or window owns the player.
Each frame the game asks once whether the player is free. If so it runs the walk tick, then moves the player, then compares the player's tile with the last one to see whether a trigger tile was entered. When the Incense runs out, the walk tick raises the lock so its notice window can take the pad. That happens after the frame's question and before the move, and the player still moves that frame.
If that move crosses onto a trigger tile, the trigger test finds a new tile and a locked player. Its rule for that case is to write the tile down as handled and do nothing else. Once the notice is dismissed the player is standing on the trigger tile, and only a fresh crossing fires a trigger. The trigger is spent without running.
The Incense drains by time spent moving: one use is 0x40 walk ticks of 0x20 vsyncs each, about 34 seconds of walking, capped at 0x100 ticks (about 137 seconds). That is why a fixed walking route reproduces the skip. This is read from the code; it has not been captured on an emulator.
Mechanism
- 0x801D1694Gate: the per-frame player routine tests the lock once. A free player continues.
- 0x801D0D14Walk tick: the Incense window goes from 1 to 0, the notice record is installed and the movement lock is set.
- 0x801D01F0Mover: its own lock test only skips the menu-button block, so the player still moves and can cross a tile edge.
- 0x801D2158Trigger test: new tile plus locked player takes the exit that stores the tile and performs no lookup.
- 0x8007BDC8After the notice the last tile equals the current tile, so nothing fires until another crossing.
Which triggers the consumed crossing can skip:
| Trigger | Path | Skippable |
|---|---|---|
| Walk-on record: cutscene, walk-on boss fight, named scene exit | crossing arm, FUN_801D5630(1), FUN_8003BDE0 | yes |
| Intra-scene teleport (a map door) | crossing arm, FUN_801D5630(0), timer 0x8007B6B0 | yes, same locked exit |
| A strip more than one tile deep along the path | each further crossing is a new compare | first tile only |
Stand-here-and-press records armed by 2E 13 | unchanged-tile arm | not applicable |
| Landing-tile record after a teleport | timer half, 0x801D2030 | no |
| Scene-entry scripts and position polls | field VM, every tick | no |
| NPC talk, doors opened by body contact | mover touch dispatch | no |
Known skips matched to trigger records on the disc:
| Skip | Scene | Trigger tiles | Record |
|---|---|---|---|
| Jette | chitei2 | (18, 14), one tile | P2[11], gates C1 0x470 / C2 0x4F0, runs 3E FF 0C |
| Vahn's dream | uru | (110..112, 35) | P2[29], no gates, exit to urudre1 |
| Noa's dream | uru | (10..12, 98) | P2[33], no gates, exit to urudre2 |
| Gala's dream | uru | (80..82, 99) | P2[31], no gates, exit to urudre3 |
Instruction-level walkthrough
The Incense part of the walk tick. The lines from 0x801D0D04 on run only on the tick that takes the window from 1 to 0.
801d0cd4 lw v0,-0x4a00(v1) ; 0x8007B600, the window
801d0cdc beq v0,zero,exit ; already 0: nothing to do
801d0ce0 addiu v0,v0,-1
801d0ce4 bne v0,zero,exit
801d0ce8 sw v0,-0x4a00(v1) ; delay slot: store window - 1
801d0d04 sw v0,-0x4bb0(v1) ; 0x8007B450 = 0x801F2278 (notice record)
801d0d08 lw v0,0x10(a0) ; a0 = player
801d0d0c lui v1,0x8
801d0d10 or v0,v0,v1
801d0d14 sw v0,0x10(a0) ; the lock
801d0d20 jal 0x80020de0 ; spawn the notice actor
The mover's lock test skips only 0x801D01F8..0x801D0330, the pause-menu open. 0x801D0334 is the movement body.
801d01e4 lw v0,0x10(v0) ; player[+0x10]
801d01ec and v0,v0,v1 ; & 0x80000
801d01f0 bnez v0,0x801d0334 ; locked: skip the menu-button block only
The dispatcher's tile compare. The locked exit sits before both lookups.
801d2068 tile = player[+0x14] >> 7, player[+0x18] >> 7
801d2110 0x1F800394 &= ~0x80000 ; re-poll bit cleared on every crossing
801d2140 andi v0,v0,0x600 ; grid cell: a trigger tile?
801d2144 beqz v0,0x801d226c ; no: store tile, return
801d2158 bnez v0,0x801d2270 ; LOCKED: store tile, return
801d2168 jal 0x801d5630 ; kind 1 lookup, then jal 0x8003bde0
801d21c8 jal 0x801d5630 ; kind 0 lookup, then timer = 0x26
801d2270 sw s0,-0x4238(v0) ; last tile = this tile
The walk tick itself runs only when the accumulator at 0x801F2274 holds 0x21 or more, and takes 0x20 off it. The mover adds the frame's vsync count (0x1F800393) at 0x801D08EC..0x801D0928 on any frame with non-zero movement.
Addresses
| Address | Image | What | Evidence |
|---|---|---|---|
0x801D1344 | PROT 0897 | Per-frame player routine; gate 0x801D1694, calls at 0x801D16EC, 0x801D16F4, 0x801D1744 | disassembly |
0x801D0B90 | PROT 0897 | Walk tick; Incense drain 0x801D0CD4..0x801D0CE8, lock store 0x801D0D14 | disassembly |
0x801D01B0 | PROT 0897 | Mover; lock branch 0x801D01F0, movement body 0x801D0334, accumulator feed 0x801D08EC | disassembly |
0x801D1BA0 | PROT 0897 | Settle; calls the walk-on dispatcher at 0x801D1D80 | disassembly |
0x801D1EC4 | PROT 0897 | Walk-on dispatcher; tile compare 0x801D2068, locked exit 0x801D2158 | disassembly |
0x801D5630 | PROT 0897 | Per-tile trigger lookup | disassembly |
0x801F1E48 | PROT 0897 | Wear-off notice; record 0x801F2278, kind table 0x801F33A4 | disassembly |
0x801DA174 | PROT 0897 | Encounter roll skips while the window is non-zero | disassembly |
0x80046870 | SCUS | Window top-up: add 0x40, cap 0x100 | disassembly |
0x80046898 | SCUS | Use validator: window below 0xE0 | disassembly |
0x8003BDE0 | SCUS | Record spawn with the C1 / C2 header gates | repo doc |
0x8007B600 | RAM | Incense window, in walk ticks | disassembly |
0x801F2274 | RAM | Walk-tick accumulator, in vsyncs | disassembly |
0x8007BDC8 / 0x8007BDCC | RAM | Last tile seen by the dispatcher | disassembly |
0x8007B450 | RAM | Submode cell the notice record is installed in | disassembly |
chitei2 .PCH (18,14,11,1) | disc | Jette trigger tile | disc data |
uru .PCH records 29 / 33 / 31 | disc | Dream trigger strips | disc data |
Scope
Between the gate and the mover call the only code is the walk tick, and the Incense edge is its only lock write, so Incense is the only source of this on the walking path. The kingdom overworld runs the same routine. The skip lasts one pass: the record never ran, so its one-shot flag is not set and a later crossing of the same tile fires it.
Related pages: field locomotion, the walk-on trigger sidecar, the pause menu.
Verifying it
Break on 0x801D0D14. On the hit, note the player position, run to 0x801D2068 in the same frame and compare the new tile against 0x8007BDC8 / 0x8007BDCC. To force the case, write 1 to 0x8007B600 and 0x21 to 0x801F2274 on the frame before the player's centre crosses into chitei2 tile (18, 14). Prediction: the branch at 0x801D2158 is taken, 0x8003BDE0 is not called from 0x801D2184, and flag 0x470 stays clear.
Open questions
- The community reports that the Jette skip costs the Door of Light for the rest of the game; that is not traced. A capture of 0x1F800394 after the skip, and of whether FUN_801D9E1C still reaches 0x801DA058, would settle it.
- The routine that releases the lock after the notice is not traced.
- The out-of-bounds uses in the community reports are not matched to specific tiles.
Incense carry-over into a new game
- Reported as
- Use Incense, then load a different save or start a New Game without resetting the console, and the no-encounter effect is still running. Speedrunners call the trick the Incense File Transfer and name the categories that use it New Game+ (community report).
- Cause
- The Incense window is one number in the program's own memory, outside the block that is saved, loaded or rebuilt for a new game.
- Where
- RAM
0x8007B600, inside theSCUS_942.54load image - Affects
- The Incense window only, up to
0x100ticks (about 137 seconds of walking) - Status
- explained - read from the disc; the carry-over itself is not captured on an emulator
"New Game+" is the community's name for this glitch, not a carry-over mode of the kind other games ship. The only thing that transfers is the remaining Incense steps. The name stuck because the trick splits the speedrun categories: a run that starts with Incense already burning skips the early random battles, and it also has the trigger bypass available from the first minutes, long before the item can be bought, so the route looks completely different from a run without it.
The window is a single number kept in the game program's own memory rather than in the block that goes to the memory card. Loading a file does not restore it and starting a new game does not clear it, so whatever was left keeps draining as the party walks. Only a reset or power cycle, which reloads the program, returns it to zero.
Two consequences follow. Saving, using Incense and reloading keeps both the effect and the item. And because the wear-off notice still appears, the trigger bypass becomes available in a file that owns no Incense.
Mechanism
- 0x8007B600The window sits inside the program image, which ends at 0x8007B800; its value in the file is zero.
- 0x80084140The save block is a 0x1A18-byte copy of the live window further up in memory.
- 0x80046870Seven instructions on the disc touch the window: the top-up, the validator, the drain and the encounter test. None stores a constant.
- FUN_8001DCF8The mode-entry reset writes a fixed list of globals; the Incense window is not on it.
Addresses
| Address | Image | What | Evidence |
|---|---|---|---|
0x8007B600 | SCUS data | Incense window; value in the file is 0 | disc data |
0x80046870 / 0x8004687C / 0x8004688C | SCUS | Top-up: the only writes besides the drain | disassembly |
0x80046898 | SCUS | Validator read | disassembly |
0x801D0CD4 / 0x801D0CE8 | PROT 0897 | Walk-tick read and decrement | disassembly |
0x801DA174 | PROT 0897 | Encounter test | disassembly |
0x8001DCF8 | SCUS | Mode-entry reset; callers 0x800160AC, 0x8001D7D8, 0x8002577C, 0x80025FD4, 0x80055D5C | disassembly |
0x80034A6C | SCUS | New-game data init, called at 0x8001DED8 | repo doc |
0x80084140 + 0x1A18 | RAM | The window that is saved and reset | repo doc |
0x8007B5FC | SCUS data | Encounter step counter; value in the file is 0x3CE (974), not saved | disc data, capture |
Scope
The most that can be carried is the cap, 0x100 ticks. Any other global kept outside 0x80084140..0x80085B58 and off the reset list behaves the same way.
The encounter step counter 0x8007B5FC is another number outside the saved window. Its value in the program file is 0x3CE (974), and that is what it holds after a power-on and a memory-card load; this one is a capture, on an unmodified played save loaded from a cold boot. The first battle after a cold load in a room with encounter rate 18 therefore comes on step 55, every time. Whether the counter is on the reset list is not checked here.
Related page: the save screen.
Verifying it
Write 0x100 to 0x8007B600, reach the title screen without resetting the console (a Game Over does it), start a New Game and read the address on the first frame of free walking. Prediction: 0x100 less the ticks walked. After a reset it reads zero.
Juggernaut's Room door
- Reported as
- The two guards in front of the Juggernaut Room in Ratayu castle, who stand aside only for a party at level 99, can be beaten early: "you come at it from the side", stand at an exact spot beside one guard, and one press of the interact button opens the door (community report; the method is shown in this community video).
- Cause
- From a strip beside a guard, one interact press lands in his talk box and the door's box at once; he makes it a talk, and the door, later in the actor list, gets it.
- Where
- Scene
retockin(Ratayu interior), door tojagaroom; interact probeFUN_801CF9F4in the field overlay, PROT 0897 - Affects
- This door, in both story states that have the guards, from either side; the same last-hit rule applies wherever an NPC and a prop share an interact point
- Status
- explained - traced in the disassembly and captured on an emulator; the player was placed by poked coordinates and then driven by pad
Nothing gets past the guards. The door has no lock of its own while they stand there; the guards are the lock. Standing beside one of them, a single press of the interact button reaches a point that is inside the guard's talk box and the door's box at the same time. The guard makes the press count as a talk; the door, which comes later in the game's list of actors, is the one that receives it. The door opens and its own script walks the party through.
The spot is narrow. Along the outer side of each guard there is a strip about eight units wide where he does not stop a player walking up. Stand in that strip level with the guard, face diagonally toward the door and press: the game checks one point 64 units across and 64 units up, and from the strip that point is close enough to both the guard and the door.
A little too low and the guard just talks. A little too high and nothing happens. At the very top of the strip, against the wall, the guard talks without any button press, which is the sign players use to know they are in the right column.
The door is unlocked for a story reason. It is the route to the boss on the first trip through the castle, so its script opens on touch, and the room is closed before and after that by standing two guards in front of it. A party that reaches level 99 and talks to Saryu gets the guards removed and a key, and only then does the door ask for the key.
Behind the door, once the Saryu story is done, the chest gives the Evil Talisman and asks for no key. Before that the room is empty. Nothing is duplicated and nothing locks: the room's exit puts the party back in front of the guards, and reaching level 99 later still gives the key, which then opens a room whose chest is already taken.
Mechanism
- retockin P0[0] +0x16Door prop, centre (3584, 7424): flag 0x650 set opens it; flag 0x64F set asks for key item 0xBF; with neither set the script jumps straight to open and leave, and writes no flag.
- 0x801F2254The interact button tests one point 64 units out on a compass of eight. At heading 0xA00 it is (x + 64, z + 64); at 0x600 it is (x - 64, z + 64).
- 0x801CFB40The box test walks the whole actor list with no early exit. Every hit overwrites the player's partner slot; a talk-class actor (within 72 units) adds result bit 1, a static prop (within 80) adds bit 4.
- 0x801D0860The caller tests bit 1 only, then posts the touch event to the partner slot: the last actor hit, not the one that supplied the bit.
- 0x8003B8D4Scene init creates the scripted actors before the placed props and the list is appended at the tail, so the door (list index 46) is after both guards (21, 22).
- (3444, 7288)From x 3442..3448, z 7282..7302 the point is inside the left guard's box and the door's box. The mirror is x 3720..3726 at heading 0x600.
Why a player can stand there at all: a guard does not keep the player out of a square around him. A step is refused only when one of three leading points, 63 or 64 units ahead, comes within 40 units of the guard, and only along the axis of that step.
| Moving | Left guard refuses the step while | Consequence |
|---|---|---|
| Z+ (up) | x in (3448, 3592) and z in (7193, 7273) | at x 3448 or less the player walks straight up past him |
| X+ (right) | x in (3416, 3496) and z in (7224, 7368) | above z 7224 the player cannot drift right, so x stays in the strip |
| Z+ at the wall | wall at z 7360..7423, probe 47 ahead | the climb ends at z 7314 |
The two guards' Z+ bands overlap on x (3576, 3592), so there is no way up between them. The tile behind them, (27, 57), carries an ungated walk-on exit to the room, but an exhaustive flood of every position reachable in 2-unit steps finds none on that tile while the guards are present. It is not how players get in.
The guard's unprompted talk at the top of the strip is the same rule pointing the other way. With right held at z 7314, one leading point is inside the door's box and two are inside the guard, who is hit last; a prop contact auto-posts to the partner slot, and the slot holds the guard.
The door in each story state:
| State | Guards | Door and room |
|---|---|---|
First arrival in Ratayu (0x357 set, 0x502 clear) | standing, with a different line | opens to the trick; room empty |
The story approach (0x502 set, 0x33E clear) | parked off the map | opens on touch |
0x33E set, 0x64F clear | standing | opens to the trick; chest present once 0x33F is set |
Level 99, talked to Saryu (0x64F set) | parked off the map | takes item 0xBF, sets 0x650, opens |
The capture
PCSX-Redux on the retail disc, starting from a memory-card load made in Ratayu town after a cold boot. The player was placed by poking coordinates: onto the castle-front walk-on tile, then onto a map-door tile so that the game's own warp lands the party in the guard hall, then onto open floor below the guard. From that seat everything is pad input, and nothing the mechanism reads is poked.
| Seat | Pad input | Rest position, heading | Result |
|---|---|---|---|
(3412, 7192) | hold UP+RIGHT to z 7280, release, press Cross | (3444, 7288), 0xA00 | partner slot = door; door flags 0x08008880 to 0x08008981; guards untouched; scene is jagaroom 77 vsyncs after the press |
(3396, 7176) | same, stopped lower | (3444, 7272), 0xA00 | below the window: the guard takes the event and his line plays |
(3396, 7176) | same, stopped higher | (3444, 7308), 0xA00 | above the window: partner slot = door, nothing posted |
(3412, 7192) | hold UP+RIGHT, never press | (3444, 7314) | the guard engages with no button: the auto-talk |
(3444, 7232) | hold UP, press Cross | (3444, 7280), 0x800 | facing straight up: nothing |
(3756, 7192) | hold UP+LEFT to z 7280, release, press Cross | (3724, 7288), 0x600 | the mirror: partner slot = door; scene is jagaroom 75 vsyncs after the press |
On every diagonal approach x froze at 3444, inside the computed 3442..3448, and the three outcomes by z bracket the window's edges. After the first run the room loads with the player free, the chest parked off the map and no flag change in 500 vsyncs.
The chest was opened in one further run with story flags 0x33E and 0x33F poked set, so that line is captured on a poked state: the chest is at (4992, 2496), talking to it adds one item 0x76 and sets 0x64C, the key count stays 0 and 0x64F / 0x650 stay clear.
The door script, the probe and the window arithmetic
The door prop's touch script, by record offset. A flag test jumps when the flag is set.
+0x0E 76 50 test flag 0x650 -> +0x5B ; already unlocked: open
+0x12 76 4F test flag 0x64F -> +0x19 ; guards dismissed: insert the key
+0x16 26 jump -> +0x5B ; neither flag: open anyway
+0x19 56 50 set flag 0x650 ; 4C 52 BF ; take item 0xBF
+0x5B door swing ; 31 00 ; C7 F8 9B 3B 32 ; walk the player to (3584, 7616)
+0xAC 3F .. scene change to jagaroom
The interact path. The store at 0x801CFB40 runs on every box hit.
801cfb40 sw t3,0x98(t6) ; partner slot = this actor
801d0854 jal 0x801cf9f4
801d085c andi v0,v0,1
801d0860 beqz v0,0x801d08dc ; no talk-class hit: nothing
801d0868 lw a0,0x98(s2) ; whoever was hit last
801d086c jal 0x801d5b5c ; touch event
The window for the left guard at heading 0xA00: the guard's box needs x + 64 in (3448, 3592) and z + 64 in (7224, 7368); the door's box needs x + 64 in (3504, 3664) and z + 64 in (7344, 7504). Together: x in (3440, 3528), z in (7280, 7304), of which only x up to 3448 is reachable. On the game's even position lattice that is 44 positions, 8 units wide and 22 deep.
Position bytes decode as (b & 0x7F) * 128 + 64, plus 64 when bit 7 is set: the guards' 1B B8 and 1C B8 are (3520, 7296) and (3648, 7296). The bit-4 auto-post is the test at 0x801D0800 and the post at 0x801D0750.
The chest is jagaroom P1[27]: seated only when flag 0x33F is set, it tests its own taken flag 0x64C and gives item 0x76. 0x33F is set by retockin P2[37], the record after the Saryu awakening, and by P1[1]. The room's exit, P2[11], returns to retockin at (3584, 7232).
Addresses
| Address | Image | What | Evidence |
|---|---|---|---|
retockin P0[0], MAN offset 0x172 | disc | Door script; tests at +0x0E and +0x12, jump at +0x16, exit at +0xAC | disc data, capture |
retockin P2[32], MAN offset 0x30E2 | disc | Ungated walk-on exit to jagaroom; unreachable on foot with the guards present | disc data |
retockin P1[20] 0x1424, P1[21] 0x151A | disc | The two guards, world (3520, 7296) and (3648, 7296) | disc data, capture |
retockin P1[29], MAN offset 0x1E17 | disc | Level compares at +0x26C and +0x387; sets 0x64F at +0x503; gives 0xBF at +0x5DA | disc data |
.MAP trigger (28,58,0,0) | disc | Binds the door prop to its tile; prop centre (3584, 7424) | disc data, capture |
.PCH trigger (27,57,32,1) | disc | Walk-on tile behind the guards | disc data |
flags 0x64F, 0x650 | flag bank 0x80085758 | Guards dismissed; door unlocked | disc data |
flags 0x33E, 0x357, 0x502 | flag bank 0x80085758 | Story states that place the guards | disc data |
0x801CF9F4 | PROT 0897 | Interact box test; partner-slot store at 0x801CFB40 on every hit, no early exit | disassembly, capture |
0x801D085C..0x801D086C | PROT 0897 | Bit-1 test, then touch post to player+0x98 | disassembly, capture |
0x801D0800 / 0x801D0750 | PROT 0897 | Bit-4 test and the auto-post, also to player+0x98 | disassembly, capture |
0x801F2254 | PROT 0897 | Interact compass, eight points 64 units out | disc data |
0x801D5B5C | PROT 0897 | Touch event post | repo doc |
0x801CFE4C / 0x801CFC40 | PROT 0897 | Per-step collision and the actor probe | disassembly |
0x801F21B4 | PROT 0897 | Actor probe offsets, file offset 0x2399C | disc data |
0x80020454 | SCUS | Actor list tail append | disassembly |
0x8003B8D4 / 0x8003B908 | SCUS | Scene init: partition-1 actors, then placed props | disassembly |
jagaroom P1[27] | disc | Chest: seated on 0x33F, taken flag 0x64C, gives item 0x76 | disc data; capture on a poked state |
flags 0x33F, 0x64C | flag bank 0x80085758 | Chest present; chest taken | disc data |
Scope
The trick works in both guarded states and on either side of the door. The ending's copy of the scene, edretoin, carries the same door record and walk-on record. The rule behind it is general: an interact press goes to the last actor in the list whose box the point is in, not to the actor that made it count as a talk, and props are always later in the list than NPCs.
Related pages: field locomotion, scene names.
Verifying it
In retockin with the guards present, walk the player to (3444, 7288) facing heading 0xA00 and press the interact button with a breakpoint on 0x801D086C. a0 is the door actor, not the guard, and the scene changes to jagaroom about 77 vsyncs later. From z 7272 a0 is the guard; from z 7308 the breakpoint is not reached. A coordinate poke that skips the map door measures the poke: the guards stay culled against the old region box and the player walks through them.
Open questions
- The chest pickup is captured on poked story flags. The same run from a played save made after the Saryu story would make it a plain capture.
Noa's sigil and the Door of Light in Nivora
- Reported as
- In Nivora Ravine, where the Door of Light is greyed out, standing on the glowing crest on Noa's route makes it usable (community report).
- Cause
- The crest stands inside a nine-by-nine map rectangle marked Door of Light allowed, listed ahead of the tunnel rectangles that forbid it.
- Where
- Scene
nilboaregion table;FUN_801D9E1C(PROT 0897) andFUN_80030628(SCUS) - Affects
- Tiles x
46..54, z60..68of Nivora Ravine; no other scene has such a pocket - Status
- explained - read from the disc, not captured on an emulator
The crest does nothing to the Door. It stands inside a small rectangle of the map that is marked Door of Light allowed, surrounded by tunnels that are marked not allowed.
Every dungeon map is divided into rectangles that set the random encounters for that area. Each rectangle also carries one bit saying whether a Door of Light may be used there. Every time the player steps onto a new tile the game finds the first rectangle that contains it and copies that bit into a flag; the item menu greys the Door when the flag says no.
In Nivora the tunnel rectangles say no. A nine-by-nine box over the ravine's two-level crossing says yes, and it comes earlier in the list, so it wins wherever it overlaps. The crest sits on the east edge of that box. Step onto it and the flag flips; one tile further east it flips back.
Any walkable tile of the box has the same effect; the crest is the landmark that happens to be in it. Leaving this way during the party split skips the prompt that regroups the party; what the game does next in that state is not traced.
Mechanism
- 0x8003093CThe item menu dims the Door of Light when bit 0x100000 of the transient flag word is set.
- 0x801D9FE8On every tile step the region reader takes the first record whose tile box contains the player.
- 0x801DA064It sets both Door bits, then clears the Door of Light bit only if the record's byte +8 has bit 7.
- nilboa region recordsNivora's tunnel records carry +8 = 0x20; records 1 and 20, the box at 46..54, 60..68, carry 0x80 and come first.
- nilboa P1[0] +0x4D4The crest's test area is tiles 53..55, 62..64; columns 53 and 54 are inside the box.
Nivora's region records (both story groups carry the same Door bits):
| Records | Tile box (x, z) | Rate | Byte +8 | Door of Light |
|---|---|---|---|---|
| 0 / 19 | 75..128, 90..128 | 0 | A2 / A1 | allowed |
| 1 / 20 | 46..54, 60..68 | 0 | 80 | allowed |
| 2 / 21 | 55..79, 0..32 | 0 | 80 | allowed |
| 3..6 / 22..25 | strips at x 0..26 | 20 or 0 | 80 / A0 | allowed |
| 7..18 / 26..37 | the twelve tunnel boxes | 20 | 20 | blocked |
Instruction-level walkthrough
The item menu's test:
80030930 addiu v0,zero,0x88
8003093c lui v0,0x1f80 ; lw v0,0x394(v0)
80030944 lui v1,0x10 ; and v0,v0,v1
8003094c bnez v0,0x800309ec ; dimmed row
The only writer of the two Door bits:
801da064 lbu v0,8(s2) ; region byte +8
801da068 lui a0,0x30
801da080 or a0,v1,a0 ; 0x1F800394 |= 0x300000: both Doors blocked
801da090 sltiu v0,v0,0xc ; needs a region stride of 12 or more
801da0b8 andi v0,v0,0x80 ; bit 7: clear 0x100000, Door of Light allowed
801da0d8 andi v0,v0,0x40 ; bit 6: clear 0x200000, Door of Wind allowed
Region record 1 is 2E 3C 36 44 00 81 00 01 80 87 5D 42: box 46, 60, 54, 68; rate 0; byte +8 = 0x80; return to map03 tile (93, 66). Tunnel record 7 is 2E 24 35 55 14 81 07 0D 20 87 5D 42.
Addresses
| Address | Image | What | Evidence |
|---|---|---|---|
0x80030628 | SCUS | Use list builder; Door tests at 0x80030930..0x80030974 | disassembly |
0x801D9E1C | PROT 0897 | Region reader; match 0x801D9FE8..0x801DA050, Door bits 0x801DA064..0x801DA0F0 | disassembly |
0x1F800394 bits 0x100000 / 0x200000 | scratchpad | Door of Light / Door of Wind blocked | disassembly |
0x80084624 / 0x80084628 / 0x8008462C | RAM | Door of Light return point (map03, tile 93, 66 from Nivora) | disassembly |
*0x801C6EA4 +0x28, +0x5F | RAM | Region table pointer and record stride | disassembly |
0x801D8A58 | PROT 0899 | Door of Light confirm; consumes item 0x88 | repo doc |
nilboa region records 1 and 20 | disc | The allowed box, byte +8 = 0x80 | disc data |
nilboa region records 7..18 and 26..37 | disc | Tunnel boxes, byte +8 = 0x20 | disc data |
nilboa P0[24], P0[7] | disc | Crest prop; rotating-road prop at (50, 64) | disc data |
nilboa P1[0] +0x4D4 | disc | Crest box test, tiles 53..55, 62..64 | disc data |
nilboa P2[4..6], P2[28] | disc | Tunnel-mouth prompts; regroup record that clears flag 0x00D | disc data |
Scope
Across every scene's bundle MAN, nilboa is the only scene where a live story group mixes allowed and blocked records so as to leave a walk-in pocket (7 of 19 allowed, in both groups). The one other mixed group is rikuroa's default group, with a single blocked record among eleven. The per-scene variant MANs are not part of this scan. No field script changes the Door bits: ops 2E / 2F appear only with bit numbers 0, 16 to 19, 22 and 24 to 27.
Related pages: encounter and region tables, the field script VM.
Verifying it
In nilboa during the split, watch bit 20 of 0x1F800394. Prediction: it reads 1 in the tunnels and drops to 0 on the step that brings the player's tile to x 46..54, z 60..68. A breakpoint at 0x801DA0C8 stops on the clear, with s2 pointing at the matched record.
Open questions
- Whether the box was left allowed on purpose or kept a default byte nobody restricted.
- Which of the three split characters can reach the box; the community report says Noa.
- What the game does after a lone character leaves with flag 0x00D set.