Ship of Harkinian · agentic playtest · step 19

The Floor the Table Cannot See

A Lua quest in this engine places its actors at coordinates that came out of a tool, not out of the running game. dump_scene_actors.py opens oot.o2r, finds the scene's collision mesh, and answers “what is the floor at (x, z)” in a second and without booting anything. Six positions in the Third Brother quest were computed that way and none of them had ever been stood on.

All six turn out to be real, and all six turn out to be reachable. Three of them are not at the height the table gives, and the reason is the same in all three cases: they stand on collision that belongs to an actor rather than to the scene, and nothing that reads oot.o2r can see it. The quest’s own self-check cannot see it either — for an entirely different reason, which is the interesting half.

Metric
18 → 19of 23 playtest steps written
Full suite
17 PASS2 FAIL (9, 20 — known), 4 not written
Sabotage
BITone claim earlier than aimed
Coordinates
63 sit on dynapoly

1 · the problem

A floor reading is not a place to stand

docs/SCRIPTING_PLACES.md says outright what its own table cannot answer: whether “there is floor at (x, z)” means “you can walk there and swing at what is hanging over it”. Three separate things could be wrong behind a correct-looking number — the thing could be half-buried, it could be floating out of a child’s reach, or it could be behind something you cannot get to — and an offline mesh query distinguishes none of them.

The six: Natural at (660, 181, 20), the three hive-sac roosts, the tear the song opens at (718, 181, 80), and the grave opening at (762, 180, 80) whose pit is at −140.

2 · the instrument

Drop Link, and read where he stops

The player has the engine’s own collision and no opinion about it. So the step moves Link over each point at y = 1200 (above every wall in both scenes), releases him 60 units up, steps 50 frames, and reads probe. Sixty and not four hundred, because this step drops him 36 times and a fall long enough to trigger the engine’s landing damage would have killed him around the fourth place — and a Game Over is a twenty-second wall-clock wait, since a press is an edge and cannot be stepped.

Then a path, not a teleport. goto_actor reaches a walled-off ledge by going over the wall, which answers nothing about whether a player can get there. Link is stood on four doorsteps 100 units out — +x, −x, +z, −z — and walks in on the analog stick, re-aimed every two frames because the camera swings as he runs.

3 · what came back

Three of the six are somewhere else

Natural, roost A and roost C land on exactly the number in the table. The other three do not, and every one of them is higher than the table says — which is the signature of collision sitting on top of the scene rather than missing from it.

whattable saysLink stands onwhat stands there
Natural181181.000.00 up — on his floor
roost A120120.0045.00 up — exactly ROOST_HANG
roost B340359.01 (+19.01)385, so 25.99 up, not 45
roost C189189.0045.00 up
the tear181192.45 (+11.45)— measured at stage 3; step 9 owns the tear itself
the grave opening−140201.64 (+341.64)— nothing is placed there, and this is why
roost B — (1240, 20) the tear — (718, 80) static mesh 340 dynapoly → 359.01 sac at 385 45 over the table 26 over the ground static 181 stone apron → 192.45 tear spawned at MAW_FLOOR = 181 — 11.45 UNDER the stone it is drawn on

The same arithmetic twice, with the sign against it once. Both placements compute their y from the table’s number; at roost B that puts the sac closer to a sword, at the tear it puts the tear under the floor.

step19_roost_b.png Roost B, and the 19 units, drawn. Link is standing on the pale grey platform with the cyan Shadow Medallion device on it — the Nocturne of Shadow warp pad. That is the dynapoly. The sac is around his head rather than above it. ground 359.01 · static 340 · sac 385
step19_tear.png The apron the tear is under. The raised carved slab Link stands on is the 11.45. The grass beside it is the 181 the table gives and the quest places on. Stage 3, so the terrace is empty and the ground is the only subject. ground 192.45 · static 181
step19_grave.png The pit that is not a pit. The table reads −140 here, which is the hole. Link comes to rest at 201.64 on the monument standing in it, and slides about nine units off the crown — it is a gravestone, not a lid. ground 201.64 · static −140
step19_roost_a.png The control. Roost A’s table entry is exactly right and the sac hangs the full 45. From where walking leaves Link — about eleven units — that still puts him inside its body, which is section 6. ground 120.00 · static 120 · sac 165

4 · the mechanism

A raycast that looks one frame too early

Each roost checks its own floor. roost_measure calls ship.actor.update_bg_check_info(self, 0,0,0, 4) and logs what it got against the table, shouting *** THE FLOOR IS NOT WHERE THE TABLE SAYS when they differ. At roost B it has never shouted. It logs floor under me is 340, which agrees with the table and disagrees with the ground Link is standing on.

It is not that the raycast is blind to dynapoly. Flag 4 is Actor_UpdateBgCheckInfo’s floor branch → func_8002E2AC → BgCheck_EntityRaycastFloor5, and Floor5 does include dynapoly — docs/SCRIPTING_PLACES.md already says so, about the Hive Queen’s heart container landing on the grave lid rather than falling in the hole.

It is when it is called. roost_measure runs on the actor’s first update, the frame after the room loaded, and on that frame the scene’s dyna actors have not put their collision in yet.

room load frame 1 frame ~360 PLACED roost measures floor under me is 340 SPAWNED roost measures floor under me is 359 dyna actors have not registered dyna registered — Floor5 sees it

Same actor, same call, same coordinate, different frame (scenarios/measure_dynapoly_timing.py).

En_HiveRoost[B]: floor under me is 340 (SCRIPTING_PLACES.md says 340), so I hang 45 up <- placed, first update En_HiveRoost[B]: floor under me is 359 (SCRIPTING_PLACES.md says 340), so I hang 0 up <- spawned, 300 frames later
So the check agrees with the table in exactly the cases where the table is incomplete. It reads the same mesh the table was generated from. And MAW_FLOOR = 181 in examples/third_brother/main.lua is that mistake already made: the tear is spawned on the number the first-update raycast returned, and the apron that registers a few frames later is 11.45 above it. That is playtest step 9’s standing FAIL, and the fix is when the floor is measured — not a new constant.

5 · the walk

One place opens from a single side

Every one of the six is walked in to. Most have two doorsteps that work and two with no ground under them — roost C’s ledge is 160 by 110 and the ground a step west of it rises 200 units, which is a shape, not a defect.

The grave opening is the one that answers the card’s third question. It walks in from −x in twelve frames. From +x and from −z Link wall-slides for a hundred and twenty frames at a full stick deflection — from (762, −20) he creeps along a face at z = −14.3, and from (862, 80) he does not move at all — while the static mesh reads a flat 180–181 across both. The same collision as the floors above, met edge-on instead of from above.

the hole: x 745–791, z 55–105 (762, 80) −x WALKED IN 11.3 short, 12 frames +x BLOCKED 0 units in 120 frames −z BLOCKED wall-slide at z = −14.3 +z no doorstep

Measured aim by aim in scenarios/measure_grave_walk.py, with input state read back on every sample so “he is blocked” could be told from “the stick never reached him”.

6 · judgement call #3

The slash that lands twice

“Can a child standing on the floor reach a sac hanging ROOST_HANG up?” is the one question in this quest that can make it unfinishable, and steps 5, 6 and 8 already answer it — from the stand goto_actor picks, forty units out on z. There the sac goes 4 hp → 2: one hit, every time.

Step 19 swings from wherever walking stopped, which is about 11 units — underneath it, as the roost A frame above shows. From there one press of B takes it 4 → 0 and opens it outright, at all three roosts. The slash lands twice. Walking in is the easier version, not the harder one.

So the step asserts that the slash connects and reports the hit count, rather than asserting a number that belongs to one stand. Its first draft asserted 4 → 2 and failed the quest for being more generous than the document assumed.

7 · drift

What this page has not established

The measurements above are all real and all repeatable. The explanations are not all equally firm, and the difference matters more than the page reads.

Which actor owns the dynapoly was not confirmed by handle. The roost B frame shows Link standing on the Nocturne of Shadow warp pad, and Bg_Mjin is at (1145, 340, 85) in the room’s actor list, which makes it the obvious owner of the nineteen units. “Obvious” is not “checked”. The same goes for whatever Link wall-slides against east and south of the grave: something is there, the static mesh does not have it, and it was not identified.
“Dyna registration” is the best fit, not a proof. What was measured is a difference between a placed actor measuring on its first update and a spawned one measuring three hundred frames later. Registration timing explains it and is consistent with Floor5 seeing dynapoly elsewhere — but the frame at which it flips was not bisected, and placed-versus-spawned was not separated from early-versus-late.
The tear and the grave were measured at stage 3, on an empty terrace. At stage 2 an En_OpenGrave stands on that ground and brings a Hive Queen up out of it, and a boss fight underneath a walk test measures the boss. Whether the tear is on that ground is step 9’s assertion, which already reports FAIL.
Nothing here is fixed. MAW_FLOOR is still 181, step 9 is still red, and no card was filed for it — step 9 is written and already reports it, so it blocks no playtest step. It is written into docs/PLAYTEST.md and docs/SCRIPTING_PLACES.md instead.
The six pictures carry a question, not a verdict. “Is anything half-buried, floating, or behind something you cannot get to?” is printed beside each frame the step files. The numbers say a thing is on its floor; only a person can say whether that floor is somewhere anyone would stand.