Ship of Harkinian · agentic playtest · step 19
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.
1 · the problem
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
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
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.
| what | table says | Link stands on | what stands there |
|---|---|---|---|
| Natural | 181 | 181.00 | 0.00 up — on his floor |
| roost A | 120 | 120.00 | 45.00 up — exactly ROOST_HANG |
| roost B | 340 | 359.01 (+19.01) | 385, so 25.99 up, not 45 |
| roost C | 189 | 189.00 | 45.00 up |
| the tear | 181 | 192.45 (+11.45) | — measured at stage 3; step 9 owns the tear itself |
| the grave opening | −140 | 201.64 (+341.64) | — nothing is placed there, and this is why |
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.
4 · the mechanism
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.
Same actor, same call, same coordinate, different frame (scenarios/measure_dynapoly_timing.py).
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
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.
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
“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
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.
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.
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.
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.