22 September 2026: the tech and item lists, and the command menu is closed
The input handling for the tech list and the item list is matched, the last two submenus still holding stubs. Every input handler in the battle command menu is now matched code. 637 bytes in 15 routines, the last two increments of session 41.
The tech list: one cursor, two coordinate systems
BattleMenu_TechListInput ($C1:1320, 73 bytes) runs every frame the tech list is open. It works out which entry is highlighted (scroll position plus cursor row), then checks the pad for confirm, cancel or a direction. BattleMenu_TechConfirm ($C1:1369, 38 bytes) hands over to targeting, like BattleMenu_ChooseAttack does for Attack. BattleMenu_TechListCancel ($C1:138F, 30 bytes) restores the cursor and scroll saved before the list opened and goes back to the main menu.
Not every tech in the list is selectable. A character may not have learned it, or may not have the MP. Those entries carry an availability flag, and the cursor must skip them. But two things are being tracked: the tech's index in the underlying list, and where the cursor sits on screen (a row 0–2 plus a scroll offset). Press up when the previous entry is unavailable, and the cursor has to move to the next available entry, which may be two or three list slots away.
BattleMenu_TechListPrev ($C1:13AD, 71 bytes) and BattleMenu_TechListNext ($C1:13F4, 73 bytes) solve it by counting. Each walks the list index one step at a time, checking the flag, until it reaches a selectable entry, and counts the steps. Then it replays that count on the screen position (row and scroll), scrolling the window by a row whenever the cursor would leave the visible part. Two loops, same shape, same count, applied to two representations of "where you are". The list walk finds out how far you moved; the screen replay trusts the number without needing to know why. The availability flags are only checked once.
An example with placeholder entries: from entry 1, DOWN walks past two unavailable entries to entry 4, counting 3 steps, then replays the 3 steps on the window as one row and two scrolls.
The item list: almost the tech list, but simpler
BattleMenu_ItemListInput ($C1:143D, 91 bytes) has the same confirm/cancel/up/down checks plus two branches the tech list lacks: page the list up or down three rows at once, and a check of a flag ($A0D0) that forces a full re-render when something elsewhere has marked the display stale.
Cursor movement is where it differs most. Items don't need skipping: an unusable item still gets a cursor position and just renders greyed out. So BattleMenu_ItemCursorUp ($C1:14EC, 22 bytes) and BattleMenu_ItemCursorDown ($C1:1502, 26 bytes) move the row by one and only call a scroll helper at the top or bottom edge of the window. Same UI pattern, different implementation, because the two lists have different rules for where the cursor may stop.
Borrowing another routine's ending. BattleMenu_ItemListPageDown ($C1:151C, 27 bytes) and BattleMenu_ItemListPageUp ($C1:1537, 20 bytes) don't call the renderer themselves. They set the scroll position and JSR into the middle of BattleMenu_ItemListScrollDown ($C1:17BF, 30 bytes) / BattleMenu_ItemListScrollUp ($C1:17A1, 30 bytes), right at the instruction that calls the renderer, so that routine's tail (render, then flag the scroll arrows for a refresh) does double duty. Bank $C0's Sub_1BA7 does the same, entering Sub_1B90 partway to reuse its tail. On the matching side, that internal entry point had to be a real global label instead of a private .dot label: in asar a new global label resets the local scope, so a label jumped to from outside must be global.
A branch that can't happen. BattleMenu_ItemListScrollUp opens with two BEQs in a row on the same flag, with nothing in between that changes it. The first is a normal check. The second asks a question already answered: if the flag were set, the first branch would have fired. This is a different kind of "does nothing" from the dead block in BattleMenu_TargetSelectInput three days ago. That was code nothing can execute; this runs every time and always gets "no". Both are reproduced exactly.
BattleMenu_ItemConfirm ($C1:1498, 67 bytes), BattleMenu_ItemListCancel ($C1:14DB, 17 bytes) and BattleMenu_ItemListRefresh ($C1:154B, 22 bytes) complete the set.
Fixing an old label
Working out an item record for ItemConfirm (id, target mode, flags, quantity, in that order, five bytes apart) showed that BattleMenu_RenderItemRow, matched on 14 August, had two field comments backwards: it called the quantity field "item ID" and the id field an "unconfirmed-animation flag". That routine only reads the fields; ItemConfirm's branches reveal what they mean. The old comments are corrected. No bytes changed.
What this closes
Every submenu the command window can open, the main Attack/Tech/Item menu, the tech list, the item list and target selection, now has matched input handling and confirm logic, and the tech and item lists have matched navigation. Together with the confirm dispatch and command commit from 19 September, the whole path from "the menu needs a redraw" to "a battle command has been built and queued" is byte-exact end to end.
The day in numbers
| Increment | Routine | Address | Bytes |
|---|---|---|---|
| 9 | BattleMenu_TechListInput |
$C1:1320 |
73 |
| 9 | BattleMenu_TechConfirm |
$C1:1369 |
38 |
| 9 | BattleMenu_TechListCancel |
$C1:138F |
30 |
| 9 | BattleMenu_TechListPrev |
$C1:13AD |
71 |
| 9 | BattleMenu_TechListNext |
$C1:13F4 |
73 |
| 10 | BattleMenu_ItemListInput |
$C1:143D |
91 |
| 10 | BattleMenu_ItemConfirm |
$C1:1498 |
67 |
| 10 | BattleMenu_ItemListCancel |
$C1:14DB |
17 |
| 10 | BattleMenu_ItemCursorUp |
$C1:14EC |
22 |
| 10 | BattleMenu_ItemCursorDown |
$C1:1502 |
26 |
| 10 | BattleMenu_ItemListPageDown |
$C1:151C |
27 |
| 10 | BattleMenu_ItemListPageUp |
$C1:1537 |
20 |
| 10 | BattleMenu_ItemListRefresh |
$C1:154B |
22 |
| 10 | BattleMenu_ItemListScrollUp |
$C1:17A1 |
30 |
| 10 | BattleMenu_ItemListScrollDown |
$C1:17BF |
30 |
| Total | 637 |
Increment totals: 285 and 352 bytes. Bank $C1: 5,848 (9.15%, up from 8.71%) after the tech list, then 6,200 of 63,904 (9.70%, up from 6.39% at the start of session 41). Project-wide: 25,817 bytes (7.19% of all game code), then 26,169 (7.28%). make diff confirms 4,194,304 bytes identical.
Next
BattleMenu_UpdateCursorOverlay at $C1:17DD, the last single-routine stub in this neighborhood. After that, the target-mode handlers behind $C1:1FF8, and the much larger territory past $C1:1C4A: enemy logic, battle animation and most of the 481 routines scouted when the bank opened.