How to read this page
Everything here is read from the disassembly of the game program and its field overlay (PROT entry 0897, load base 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) and FUN_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.

The frame the Incense runs out - FUN_801D1344, in call order1 Gate0x801D1694lock clear: carry on2 Walk tick0x801D0D141 to 0: LOCK SET3 Mover0x801D0334player still moves4 Trigger test0x801D2158locked: tile storedmovement lock set from here to the end of the frametile beforetrigger tiletile aftereach tile is128 units wideplayer crossesthe tile edgelast tile = trigger tile, FUN_8003BDE0 never called: the trigger is spent
The frame the Incense runs out, in call order. The lock is set after the gate has already let the frame through and before the trigger test, so the move happens and the trigger does not. Predicted from the disassembly; not an emulator capture.

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.

An ordinary frame - FUN_801D1344, in call order1 Gate0x801D1694lock clear: carry on2 Walk tick0x801D0CDCno expiry: no lock3 Mover0x801D0334moves the player4 Trigger test0x801D2184record spawnsmovement lock stays cleartile beforetrigger tiletile aftereach tile is128 units wideplayer crossesthe tile edgenew tile and player free: FUN_8003BDE0 spawns the tile's record
For comparison, an ordinary frame: the lock stays clear and the trigger test spawns the record of the tile just entered.

Mechanism

  1. 0x801D1694Gate: the per-frame player routine tests the lock once. A free player continues.
  2. 0x801D0D14Walk tick: the Incense window goes from 1 to 0, the notice record is installed and the movement lock is set.
  3. 0x801D01F0Mover: its own lock test only skips the menu-button block, so the player still moves and can cross a tile edge.
  4. 0x801D2158Trigger test: new tile plus locked player takes the exit that stores the tile and performs no lookup.
  5. 0x8007BDC8After the notice the last tile equals the current tile, so nothing fires until another crossing.

Which triggers the consumed crossing can skip:

TriggerPathSkippable
Walk-on record: cutscene, walk-on boss fight, named scene exitcrossing arm, FUN_801D5630(1), FUN_8003BDE0yes
Intra-scene teleport (a map door)crossing arm, FUN_801D5630(0), timer 0x8007B6B0yes, same locked exit
A strip more than one tile deep along the patheach further crossing is a new comparefirst tile only
Stand-here-and-press records armed by 2E 13unchanged-tile armnot applicable
Landing-tile record after a teleporttimer half, 0x801D2030no
Scene-entry scripts and position pollsfield VM, every tickno
NPC talk, doors opened by body contactmover touch dispatchno

Known skips matched to trigger records on the disc:

SkipSceneTrigger tilesRecord
Jettechitei2(18, 14), one tileP2[11], gates C1 0x470 / C2 0x4F0, runs 3E FF 0C
Vahn's dreamuru(110..112, 35)P2[29], no gates, exit to urudre1
Noa's dreamuru(10..12, 98)P2[33], no gates, exit to urudre2
Gala's dreamuru(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

AddressImageWhatEvidence
0x801D1344PROT 0897Per-frame player routine; gate 0x801D1694, calls at 0x801D16EC, 0x801D16F4, 0x801D1744disassembly
0x801D0B90PROT 0897Walk tick; Incense drain 0x801D0CD4..0x801D0CE8, lock store 0x801D0D14disassembly
0x801D01B0PROT 0897Mover; lock branch 0x801D01F0, movement body 0x801D0334, accumulator feed 0x801D08ECdisassembly
0x801D1BA0PROT 0897Settle; calls the walk-on dispatcher at 0x801D1D80disassembly
0x801D1EC4PROT 0897Walk-on dispatcher; tile compare 0x801D2068, locked exit 0x801D2158disassembly
0x801D5630PROT 0897Per-tile trigger lookupdisassembly
0x801F1E48PROT 0897Wear-off notice; record 0x801F2278, kind table 0x801F33A4disassembly
0x801DA174PROT 0897Encounter roll skips while the window is non-zerodisassembly
0x80046870SCUSWindow top-up: add 0x40, cap 0x100disassembly
0x80046898SCUSUse validator: window below 0xE0disassembly
0x8003BDE0SCUSRecord spawn with the C1 / C2 header gatesrepo doc
0x8007B600RAMIncense window, in walk ticksdisassembly
0x801F2274RAMWalk-tick accumulator, in vsyncsdisassembly
0x8007BDC8 / 0x8007BDCCRAMLast tile seen by the dispatcherdisassembly
0x8007B450RAMSubmode cell the notice record is installed indisassembly
chitei2 .PCH (18,14,11,1)discJette trigger tiledisc data
uru .PCH records 29 / 33 / 31discDream trigger stripsdisc 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 the SCUS_942.54 load image
Affects
The Incense window only, up to 0x100 ticks (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.

Main RAM from 0x80010000 to 0x80086000, to scaleSCUS_942.54 load image, 0x80010000..0x8007B800Incense window, 0x8007B600saved window, 0x80084140 + 0x1A18Memory card load: restores the saved window onlyNew Game: rebuilds the saved window onlyMode-entry reset FUN_8001DCF8: a fixed list, the Incense window is not on itSeven instructions touch 0x8007B600: add 0x40, clamp, compare, read, subtract 1, test.None stores a constant, so only reloading the program returns it to zero.
Main RAM to scale. The Incense window sits just inside the top of the program image; saving, loading and New Game all act on the block further up.

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

  1. 0x8007B600The window sits inside the program image, which ends at 0x8007B800; its value in the file is zero.
  2. 0x80084140The save block is a 0x1A18-byte copy of the live window further up in memory.
  3. 0x80046870Seven instructions on the disc touch the window: the top-up, the validator, the drain and the encounter test. None stores a constant.
  4. FUN_8001DCF8The mode-entry reset writes a fixed list of globals; the Incense window is not on it.

Addresses

AddressImageWhatEvidence
0x8007B600SCUS dataIncense window; value in the file is 0disc data
0x80046870 / 0x8004687C / 0x8004688CSCUSTop-up: the only writes besides the draindisassembly
0x80046898SCUSValidator readdisassembly
0x801D0CD4 / 0x801D0CE8PROT 0897Walk-tick read and decrementdisassembly
0x801DA174PROT 0897Encounter testdisassembly
0x8001DCF8SCUSMode-entry reset; callers 0x800160AC, 0x8001D7D8, 0x8002577C, 0x80025FD4, 0x80055D5Cdisassembly
0x80034A6CSCUSNew-game data init, called at 0x8001DED8repo doc
0x80084140 + 0x1A18RAMThe window that is saved and resetrepo doc
0x8007B5FCSCUS dataEncounter step counter; value in the file is 0x3CE (974), not saveddisc 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 to jagaroom; interact probe FUN_801CF9F4 in 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.

wallwallguardguarddoor(3584, 7424)x 3456x 3584x 3712z 7296z 7424Door propits box: 80 units each wayTwo guards, 128 apart(3520, 7296) and (3648, 7296)outline: talk box, 72 each wayInside both boxesthe press counts as a talk,and the door receives itWhere to standx 3442..3448 or 3720..3726z 7282..7302The interact point64 across and 64 up: from(3444, 7288) it is (3508, 7352)Walk-on tile (27, 57)not reachable on footWallwalking stops at z = 7314
The door, both guards and the two standing strips, to scale at one pixel per world unit (a floor tile is 128 units). The arrows are the interact point of a player facing diagonally at the door; each ends inside the door's box and a guard's talk box at once. The dashed lines are the captured approach. A community screenshot of the method shows Vahn immediately to the right of the right-hand guard, which is the right-hand strip.

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

  1. 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.
  2. 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).
  3. 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.
  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.
  5. 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).
  6. (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.

MovingLeft guard refuses the step whileConsequence
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 wallwall at z 7360..7423, probe 47 aheadthe 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:

StateGuardsDoor and room
First arrival in Ratayu (0x357 set, 0x502 clear)standing, with a different lineopens to the trick; room empty
The story approach (0x502 set, 0x33E clear)parked off the mapopens on touch
0x33E set, 0x64F clearstandingopens to the trick; chest present once 0x33F is set
Level 99, talked to Saryu (0x64F set)parked off the maptakes 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.

SeatPad inputRest position, headingResult
(3412, 7192)hold UP+RIGHT to z 7280, release, press Cross(3444, 7288), 0xA00partner slot = door; door flags 0x08008880 to 0x08008981; guards untouched; scene is jagaroom 77 vsyncs after the press
(3396, 7176)same, stopped lower(3444, 7272), 0xA00below the window: the guard takes the event and his line plays
(3396, 7176)same, stopped higher(3444, 7308), 0xA00above 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), 0x800facing straight up: nothing
(3756, 7192)hold UP+LEFT to z 7280, release, press Cross(3724, 7288), 0x600the 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

AddressImageWhatEvidence
retockin P0[0], MAN offset 0x172discDoor script; tests at +0x0E and +0x12, jump at +0x16, exit at +0xACdisc data, capture
retockin P2[32], MAN offset 0x30E2discUngated walk-on exit to jagaroom; unreachable on foot with the guards presentdisc data
retockin P1[20] 0x1424, P1[21] 0x151AdiscThe two guards, world (3520, 7296) and (3648, 7296)disc data, capture
retockin P1[29], MAN offset 0x1E17discLevel compares at +0x26C and +0x387; sets 0x64F at +0x503; gives 0xBF at +0x5DAdisc data
.MAP trigger (28,58,0,0)discBinds the door prop to its tile; prop centre (3584, 7424)disc data, capture
.PCH trigger (27,57,32,1)discWalk-on tile behind the guardsdisc data
flags 0x64F, 0x650flag bank 0x80085758Guards dismissed; door unlockeddisc data
flags 0x33E, 0x357, 0x502flag bank 0x80085758Story states that place the guardsdisc data
0x801CF9F4PROT 0897Interact box test; partner-slot store at 0x801CFB40 on every hit, no early exitdisassembly, capture
0x801D085C..0x801D086CPROT 0897Bit-1 test, then touch post to player+0x98disassembly, capture
0x801D0800 / 0x801D0750PROT 0897Bit-4 test and the auto-post, also to player+0x98disassembly, capture
0x801F2254PROT 0897Interact compass, eight points 64 units outdisc data
0x801D5B5CPROT 0897Touch event postrepo doc
0x801CFE4C / 0x801CFC40PROT 0897Per-step collision and the actor probedisassembly
0x801F21B4PROT 0897Actor probe offsets, file offset 0x2399Cdisc data
0x80020454SCUSActor list tail appenddisassembly
0x8003B8D4 / 0x8003B908SCUSScene init: partition-1 actors, then placed propsdisassembly
jagaroom P1[27]discChest: seated on 0x33F, taken flag 0x64C, gives item 0x76disc data; capture on a poked state
flags 0x33F, 0x64Cflag bank 0x80085758Chest present; chest takendisc 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 nilboa region table; FUN_801D9E1C (PROT 0897) and FUN_80030628 (SCUS)
Affects
Tiles x 46..54, z 60..68 of 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.

Nivora Ravine, 128 x 128 tilesDoor of Light allowedblockedthe crossing, enlargedtiles x 42..58, z 56..72tunnel: +8 = 0x20+8 = 0x80crestroadbox: x 46..54, z 60..68crest test: x 53..55, z 62..64column 55 is outside the box
Nivora's region rectangles at two pixels per tile (z increases downward in this drawing), with the crossing enlarged. The crest's test area overlaps the east edge of the allowed box.

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

  1. 0x8003093CThe item menu dims the Door of Light when bit 0x100000 of the transient flag word is set.
  2. 0x801D9FE8On every tile step the region reader takes the first record whose tile box contains the player.
  3. 0x801DA064It sets both Door bits, then clears the Door of Light bit only if the record's byte +8 has bit 7.
  4. 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.
  5. 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):

RecordsTile box (x, z)RateByte +8Door of Light
0 / 1975..128, 90..1280A2 / A1allowed
1 / 2046..54, 60..68080allowed
2 / 2155..79, 0..32080allowed
3..6 / 22..25strips at x 0..2620 or 080 / A0allowed
7..18 / 26..37the twelve tunnel boxes2020blocked
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

AddressImageWhatEvidence
0x80030628SCUSUse list builder; Door tests at 0x80030930..0x80030974disassembly
0x801D9E1CPROT 0897Region reader; match 0x801D9FE8..0x801DA050, Door bits 0x801DA064..0x801DA0F0disassembly
0x1F800394 bits 0x100000 / 0x200000scratchpadDoor of Light / Door of Wind blockeddisassembly
0x80084624 / 0x80084628 / 0x8008462CRAMDoor of Light return point (map03, tile 93, 66 from Nivora)disassembly
*0x801C6EA4 +0x28, +0x5FRAMRegion table pointer and record stridedisassembly
0x801D8A58PROT 0899Door of Light confirm; consumes item 0x88repo doc
nilboa region records 1 and 20discThe allowed box, byte +8 = 0x80disc data
nilboa region records 7..18 and 26..37discTunnel boxes, byte +8 = 0x20disc data
nilboa P0[24], P0[7]discCrest prop; rotating-road prop at (50, 64)disc data
nilboa P1[0] +0x4D4discCrest box test, tiles 53..55, 62..64disc data
nilboa P2[4..6], P2[28]discTunnel-mouth prompts; regroup record that clears flag 0x00Ddisc 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.