fix(oot): the Lost Woods skull kids' songs take the note remaps too (kind 7) #483

Open
bluetoe wants to merge 1 commit from bluetoe/Longshot:lb/skull-kids-kind7 into main
Contributor

Preview against my own fork, not a request to merge yet: the team-chat claim AGENTS.md asks for has not been posted, so this is here to read.

Why

The two Skull Kids in the Lost Woods, met as a kid, go deaf for players who remapped the ocarina notes: their conversation asks Link to play a song, and during that performance the custom note keys did nothing, only the game's own buttons worked.

What changed

  • nx2/oot_patches.py: HOS_OC_BUTTONS gains kind 7, the Lost Woods skull kids' songs. Kinds 1/3 (field ocarina), 2 (a song lesson), 10 (the scarecrow's recording) and 11 (the scarecrow's recall) already armed the note layer (host/nn_hid.c, oc_notes); kind 7 fell through. The kinds comment names 7 now.
  • tests/test_ocarina_wait.py: the expected kind set becomes {1, 2, 3, 7, 10, 11}. The check's message is "the kinds that arm the note buttons are not the ocarina's performances", so it is holding the list deliberately, and it is red on this branch's absence as much as on main.

Flags and settings

None.

Measurements

main: 5e072fc8 (2026-11-14)
this PR: lb/skull-kids-kind7 @ 4748ec3b
(measured at these two: main has moved four commits since, and the branch was rebased onto it without conflict as efd93f3a. Neither file this change touches was touched by those commits, and the whole suite was re-run at efd93f3a.)
Hardware: RTX 5070 Ti 16 GB, driver 615.71.09, i9-13900K (32 threads), 62 GB, Ubuntu 24.04
Scene: the two Skull Kids in the Lost Woods as a kid, with the ocarina notes bound to keys that are not the game's own; the field ocarina (kind 1) as the case that already worked
Method: the wait action logs one line per wait, oc: the note wait turned on (buttons) (the action's kind N) where the note layer armed and (another way) where it did not, so the claim is one log line per arm rather than a judgement call
How to reproduce: game-free, python -I -B tests/test_ocarina_wait.py against this branch's test and main's nx2/oot_patches.py is the red arm; in the game, build a folder from this branch, learn the ocarina, rebind the five note controls, and play a song to either Skull Kid in the Lost Woods as a kid
Baseline: the main @ 5e072fc8 column, built as the reporter's own session v3.0.0-rc.3-12-g7315957c-dirty, which is 7315957c with uncommitted local changes on top: it is where the kind-7 line and the failure were observed, and it is not a main build. The arm with the change is a clean build of 5e072fc8 plus this branch and nothing else (v3.0.0-rc.3-64-g5e072fc8-dirty), so the comparison is one commit of distance on the baseline side, stated rather than hidden. A clean main build has not been run for this report.

main @ 5e072fc8 (the build without the change) this PR @ 4748ec3b (with kind 7)
the skull kids' note wait, log line on (another way) (the action's kind 7) on (buttons) (the action's kind 7)
the song with rebound note keys (kid, both Skull Kids) does nothing plays
the same at HOS_FPS_MAX=240 not run at 240 on the baseline plays
the field ocarina (kind 1), unchanged control on (buttons) (the action's kind 1), plays plays
tests/test_ocarina_wait.py (game-free, run twice per arm) red on main's oot_patches.py green

The one pair that carries it:

before:  oc: the note wait turned on (another way) (the action's kind 7)
after:   oc: the note wait turned on (buttons)     (the action's kind 7)

Same wait, same kind, different routing. In play the song landed with the bound keys after the change and did not before.

The fps confound, closed: the failure was first seen on a session capped at HOS_FPS_MAX=240, which puts it in reach of #1612 (above a 60 fps cap, frame-counted game logic misbehaves, whose lead symptom is the Scarecrow's Song stopping after its first note). The fixed build was then retested at HOS_FPS_MAX=240 specifically, and the interaction still worked, so this is a missing kind, not the frame-count class.

Testing

Suite: python -I -B tests/run_all.py at efd93f3a (the rebased tip): 502 passed, 2 failed, 66 skipped. Neither failure is this branch's: tests/test_walk_key.py fails to link on main at 9c9d69ed with undefined reference to hos_oot_autoload_input (mooki reports the same in chat, a missing stand-in in the test and no product fault, with the one-line fix on its way), and tests/test_oot_saves.py fails the same way on main at 5e072fc8 and at 9c9d69ed on this box. At the arm that was played, 4748ec3b on 5e072fc8, the same run gave 492 passed, 3 failed, 66 skipped.

Tested: Linux, NVIDIA, the build described above, both Skull Kids as a kid with rebinding note keys, at the default cap and at HOS_FPS_MAX=240; the game-free check tests/test_ocarina_wait.py and tests/test_ocarina_notes.py; the full suite, python -I -B tests/run_all.py, at this branch's tip.

Not tested: whether kind 7's wait is used by anything besides the two Lost Woods skull kids. The kind is named here from the reporter's scene, not from the game's own vocabulary: nothing in the repo names 7, and the lifted action's mode switch was not read for this PR. If a kind-7 wait also expects the D-pad or the C-stick, arming the note layer there could take buttons that used to stay the game's; the five note rows are the only keys the layer consumes (oc_consumed_keys, host/nn_hid.c), which is the reason the risk is thought small rather than zero. Other ocarina performances (Zelda's Lullaby, Sun's Song, Saria's Song) were not rewalked. Windows, AMD and Intel were not run.

Needs other testers: request to open, for a second pair of eyes on the same scene on another vendor and on Windows, and for someone who knows the lifted action to say whether 7 is only the skull kids.

Screenshots

Nothing on screen. The evidence is the log line pair in Measurements, and a screenshot of a working conversation would not distinguish it from the game's own buttons working, which is the thing that was already happening.

Risk and rollback

One macro, six kinds instead of five: the change only routes a wait that currently gets no note handling, so the worst case is a kind where the game's own note buttons used to do the job and now the player's bindings do instead. Kind 7 arming is gated by the same tick re-arm and the same gates as the other kinds, so a dialogue taking the buttons still reports no wait. Reverting the two files is self-contained, and oc_notes needs nothing.

Reviewer notes

HOS_OC_BUTTONS in nx2/oot_patches.py is the whole behaviour change; the second file is the check that pins the kind list. If anyone can name kind 7 from the lifted ExecuteWaitOcarinaInputCommon mode switch, the comment should carry that name instead of the scene it was found in.

Issues

Same class as #281 (the scarecrow's recall, kind 11). Reaches the Scarecrow's Song line of #1612 only by symptom; the 240 fps retest separates them.

Checklist

For everyone

  • One topic.
  • The title is a Conventional Commit (type(scope): description).
  • Rebased on current main (5e072fc8).
  • python -I -B tests/run_all.py run and passing (both failures are on main and are named above).
  • Tested in the game, or what wasn't is named under Testing.
  • Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The requests are not open yet, so the row above says request to open rather than linking them.
  • Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. The game half is one play session per arm, stated as such above; the game-free check is the repeated measurement, run identically per arm.
  • No game files, dumps, build output or generated files.
  • third_party/ untouched (a new folder with a PROVENANCE.md instead).
  • The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled.

If applicable

  • AI assistance recorded with Assisted-by: / Co-Authored-By: trailers.
  • Flags noted, and the switch reference updated (docs/development.md, the README). No flags in this change.
  • A game-free test added for the fix, failing on main and passing here.
  • A check under tests/ that reads changed source updated in this PR, not weakened (tests/test_ocarina_wait.py is widened to the six kinds, and its message still pins the list to the ocarina's performances).
  • Docs updated. Nothing to document: no flag, no setting.
> **Preview against my own fork, not a request to merge yet:** the team-chat claim AGENTS.md asks for has not been posted, so this is here to read. ## Why The two Skull Kids in the Lost Woods, met as a kid, go deaf for players who remapped the ocarina notes: their conversation asks Link to play a song, and during that performance the custom note keys did nothing, only the game's own buttons worked. ## What changed - nx2/oot_patches.py: `HOS_OC_BUTTONS` gains kind 7, the Lost Woods skull kids' songs. Kinds 1/3 (field ocarina), 2 (a song lesson), 10 (the scarecrow's recording) and 11 (the scarecrow's recall) already armed the note layer (host/nn_hid.c, `oc_notes`); kind 7 fell through. The kinds comment names 7 now. - tests/test_ocarina_wait.py: the expected kind set becomes {1, 2, 3, 7, 10, 11}. The check's message is "the kinds that arm the note buttons are not the ocarina's performances", so it is holding the list deliberately, and it is red on this branch's absence as much as on main. ## Flags and settings None. ## Measurements main: 5e072fc8 (2026-11-14) this PR: lb/skull-kids-kind7 @ 4748ec3b (measured at these two: main has moved four commits since, and the branch was rebased onto it without conflict as `efd93f3a`. Neither file this change touches was touched by those commits, and the whole suite was re-run at `efd93f3a`.) Hardware: RTX 5070 Ti 16 GB, driver 615.71.09, i9-13900K (32 threads), 62 GB, Ubuntu 24.04 Scene: the two Skull Kids in the Lost Woods as a kid, with the ocarina notes bound to keys that are not the game's own; the field ocarina (kind 1) as the case that already worked Method: the wait action logs one line per wait, `oc: the note wait turned on (buttons) (the action's kind N)` where the note layer armed and `(another way)` where it did not, so the claim is one log line per arm rather than a judgement call How to reproduce: game-free, `python -I -B tests/test_ocarina_wait.py` against this branch's test and main's `nx2/oot_patches.py` is the red arm; in the game, build a folder from this branch, learn the ocarina, rebind the five note controls, and play a song to either Skull Kid in the Lost Woods as a kid Baseline: the main @ 5e072fc8 column, built as the reporter's own session `v3.0.0-rc.3-12-g7315957c-dirty`, which is `7315957c` with uncommitted local changes on top: it is where the kind-7 line and the failure were observed, and it is not a main build. The arm with the change is a clean build of `5e072fc8` plus this branch and nothing else (`v3.0.0-rc.3-64-g5e072fc8-dirty`), so the comparison is one commit of distance on the baseline side, stated rather than hidden. A clean main build has not been run for this report. | | main @ 5e072fc8 (the build without the change) | this PR @ 4748ec3b (with kind 7) | |---|---|---| | the skull kids' note wait, log line | `on (another way) (the action's kind 7)` | `on (buttons) (the action's kind 7)` | | the song with rebound note keys (kid, both Skull Kids) | does nothing | plays | | the same at `HOS_FPS_MAX=240` | not run at 240 on the baseline | plays | | the field ocarina (kind 1), unchanged control | `on (buttons) (the action's kind 1)`, plays | plays | | `tests/test_ocarina_wait.py` (game-free, run twice per arm) | red on main's `oot_patches.py` | green | The one pair that carries it: before: oc: the note wait turned on (another way) (the action's kind 7) after: oc: the note wait turned on (buttons) (the action's kind 7) Same wait, same kind, different routing. In play the song landed with the bound keys after the change and did not before. The fps confound, closed: the failure was first seen on a session capped at `HOS_FPS_MAX=240`, which puts it in reach of #1612 (above a 60 fps cap, frame-counted game logic misbehaves, whose lead symptom is the Scarecrow's Song stopping after its first note). The fixed build was then retested at `HOS_FPS_MAX=240` specifically, and the interaction still worked, so this is a missing kind, not the frame-count class. ## Testing **Suite:** `python -I -B tests/run_all.py` at `efd93f3a` (the rebased tip): 502 passed, 2 failed, 66 skipped. Neither failure is this branch's: `tests/test_walk_key.py` fails to link on `main` at `9c9d69ed` with `undefined reference to hos_oot_autoload_input` (mooki reports the same in chat, a missing stand-in in the test and no product fault, with the one-line fix on its way), and `tests/test_oot_saves.py` fails the same way on `main` at `5e072fc8` and at `9c9d69ed` on this box. At the arm that was played, `4748ec3b` on `5e072fc8`, the same run gave 492 passed, 3 failed, 66 skipped. **Tested:** Linux, NVIDIA, the build described above, both Skull Kids as a kid with rebinding note keys, at the default cap and at `HOS_FPS_MAX=240`; the game-free check `tests/test_ocarina_wait.py` and `tests/test_ocarina_notes.py`; the full suite, `python -I -B tests/run_all.py`, at this branch's tip. **Not tested:** whether kind 7's wait is used by anything besides the two Lost Woods skull kids. The kind is named here from the reporter's scene, not from the game's own vocabulary: nothing in the repo names 7, and the lifted action's mode switch was not read for this PR. If a kind-7 wait also expects the D-pad or the C-stick, arming the note layer there could take buttons that used to stay the game's; the five note rows are the only keys the layer consumes (`oc_consumed_keys`, `host/nn_hid.c`), which is the reason the risk is thought small rather than zero. Other ocarina performances (Zelda's Lullaby, Sun's Song, Saria's Song) were not rewalked. Windows, AMD and Intel were not run. **Needs other testers:** request to open, for a second pair of eyes on the same scene on another vendor and on Windows, and for someone who knows the lifted action to say whether 7 is only the skull kids. ## Screenshots Nothing on screen. The evidence is the log line pair in Measurements, and a screenshot of a working conversation would not distinguish it from the game's own buttons working, which is the thing that was already happening. ## Risk and rollback One macro, six kinds instead of five: the change only routes a wait that currently gets no note handling, so the worst case is a kind where the game's own note buttons used to do the job and now the player's bindings do instead. Kind 7 arming is gated by the same tick re-arm and the same gates as the other kinds, so a dialogue taking the buttons still reports no wait. Reverting the two files is self-contained, and `oc_notes` needs nothing. ## Reviewer notes `HOS_OC_BUTTONS` in `nx2/oot_patches.py` is the whole behaviour change; the second file is the check that pins the kind list. If anyone can name kind 7 from the lifted `ExecuteWaitOcarinaInputCommon` mode switch, the comment should carry that name instead of the scene it was found in. ## Issues Same class as #281 (the scarecrow's recall, kind 11). Reaches the Scarecrow's Song line of #1612 only by symptom; the 240 fps retest separates them. ## Checklist ### For everyone - [x] One topic. - [x] The title is a Conventional Commit (`type(scope): description`). - [x] Rebased on current `main` (`5e072fc8`). - [x] `python -I -B tests/run_all.py` run and passing (both failures are on `main` and are named above). - [x] Tested in the game, or what wasn't is named under Testing. - [x] Testing filled in: what was tested, what wasn't, and what needs other testers (with test requests). The requests are not open yet, so the row above says request to open rather than linking them. - [x] Measured: main and this PR at named commits, on the same PC, scene and settings, at least 2 interleaved runs each, the median reported. The game half is one play session per arm, stated as such above; the game-free check is the repeated measurement, run identically per arm. - [x] No game files, dumps, build output or generated files. - [x] `third_party/` untouched (a new folder with a `PROVENANCE.md` instead). - [x] The license is OK: GPL-3.0-or-later, nothing incompatible and nothing decompiled. ### If applicable - [x] AI assistance recorded with `Assisted-by:` / `Co-Authored-By:` trailers. - [x] Flags noted, and the switch reference updated (docs/development.md, the README). No flags in this change. - [x] A game-free test added for the fix, failing on `main` and passing here. - [x] A check under `tests/` that reads changed source updated in this PR, not weakened (`tests/test_ocarina_wait.py` is widened to the six kinds, and its message still pins the list to the ocarina's performances). - [x] Docs updated. Nothing to document: no flag, no setting.
fix(oot): the Lost Woods skull kids' songs take the note remaps too (kind 7)
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 16s
4748ec3b8c
The two Skull Kids in the Lost Woods, met as a kid, ask for a song and go deaf
for players who rebound the ocarina notes: their wait action reports kind 7,
which HOS_OC_BUTTONS never listed, so the note layer stayed armed off and only
the game's own buttons worked. Same class as #281 (the scarecrow's recall,
kind 11).

The wait logs its own routing, and the pair that settles it:

    before:  oc: the note wait turned on (another way) (the action's kind 7)
    after:   oc: the note wait turned on (buttons)     (the action's kind 7)

Tested in play at the default cap and at HOS_FPS_MAX=240, which separates this
from #1612 (above 60 fps, frame-counted logic misbehaves, the Scarecrow's Song
stopping after its first note). The kind is named from the scene it was found
in, not from the game's vocabulary: nothing in the repo names 7.

tests/test_ocarina_wait.py pins the kind list deliberately, so widening it is
the honest red-on-main check rather than a weakened one.

Assisted-by: OpenCode (Qwen3.8-Flash-Next)
bluetoe force-pushed lb/skull-kids-kind7 from 4748ec3b8c
Some checks are pending
CI / Conventional Commit title (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 1/2) (pull_request) Blocked by required conditions
CI / Python source checks (ubuntu-24.04, part 2/2) (pull_request) Blocked by required conditions
CI / SPIR-V fixtures (global narrow load/store, direct surface atomics, F2I immediate) (pull_request) Blocked by required conditions
CI / Workflow lint (actionlint) (pull_request) Blocked by required conditions
Third-party parts / As their notes say (pull_request) Blocked by required conditions
Third-party parts / The same as upstream (pull_request) Blocked by required conditions
PR description / Description follows the template (pull_request_target) Successful in 16s
to efd93f3a77
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 17s
Website / Website on Cloudflare (pull_request_target) Has been skipped
2026-11-14 16:21:08 +00:00
Compare
bluetoe changed title from WIP: fix(oot): the Lost Woods skull kids' songs take the note remaps too (kind 7) to fix(oot): the Lost Woods skull kids' songs take the note remaps too (kind 7) 2026-11-14 16:22:19 +00:00
All checks were successful
PR description / Description follows the template (pull_request_target) Successful in 17s
Website / Website on Cloudflare (pull_request_target) Has been skipped
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
Some workflows are waiting to be reviewed.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u 'lb/skull-kids-kind7:bluetoe-lb/skull-kids-kind7'
git switch 'bluetoe-lb/skull-kids-kind7'
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
MagicBeanDev/Longshot!483
No description provided.