{ "chunk": "game_main_new_652E", "unit": "game/main_0800", "routines": [ { "addr": "652E", "name": "runRepairWhichMenu", "summary": "Draws and runs the 'REPAIR WHICH:' comcen-system menu of the REPAIR console tab. Opens a 7-column text window at column 3 spanning rows 9..19 (colour $61, fill char 0, centring and raw-code modes off), prints the header string 'REPAIRWHICH:' at $CBD6, records the resulting cursor row as menuFirstRow ($91D6 = 13), appends menu items 13..16 (ENERGY, BATTLE, RADAR, DRONE) and item 12 ((EXIT)) with addMenuItem, then repeatedly runs the menu selector with selectedUnit = $FF (the sentinel that makes toggleMenuRowHighlight blink the matching comcen system marker). Called only from $1860 inside repairTabAction, which has just erased the four markers and set showOkMarkers = 1 so undamaged systems are shown too.", "inputs": "none in registers; reads D_0B9B (film/solo flag) and D_923F (game-over flags) through getSoloOrFlag923F, D_91D5 after each selector pass, comcen state via attemptSystemRepair, text cursor row zp_40 after the header", "outputs": "zp_39=$09, zp_3A=$13, zp_3B=$03, zp_3C=$07, zp_3D=$61 then $60 then $66, zp_3E=0, zp_43=0, D_90EF=0, D_91D4=5 (items), D_91D5=selection, D_91D6=first row 13, D_91CE[0..4]={13,14,15,16,12}, D_90F8=$FF, zp_1C=item-id loop counter; text window painted and, on exit, cleared with colour $66 via a JMP to sub_C06A; may queue the $9A energy-repair command and clear D_9241[y] through attemptSystemRepair", "confidence": "high" } ], "variables": [ {"addr": "39", "scope": "zp", "name": "textWindowTop", "meaning": "Top row of the text window; set to 9 for the REPAIR WHICH panel (sub_C06A copies it into textCursorRow when it clears the window).", "confidence": "high"}, {"addr": "3A", "scope": "zp", "name": "textWindowBottom", "meaning": "Bottom row limit (exclusive) of the text window; computed here as textWindowTop + 10 = $13, so the panel occupies rows 9..18.", "confidence": "high"}, {"addr": "3B", "scope": "zp", "name": "textWindowLeft", "meaning": "Left screen column of the text window; 3 for the REPAIR WHICH panel.", "confidence": "high"}, {"addr": "3C", "scope": "zp", "name": "textWindowWidth", "meaning": "Text window width in characters (7 here); the menu engine also uses it as the number of colour cells EORed for the highlight bar of a menu row.", "confidence": "high"}, {"addr": "3D", "scope": "zp", "name": "textColour", "meaning": "Colour byte used by the $C000 text engine for printed characters and as the EOR mask for the menu highlight: $61 while the header is printed, $60 while the menu runs, $66 for the final window clear.", "confidence": "high"}, {"addr": "3E", "scope": "zp", "name": "textFillChar", "meaning": "Glyph used to blank cells by the window/line clear routines; zeroed (space) before this menu is drawn.", "confidence": "high"}, {"addr": "40", "scope": "zp", "name": "textCursorRow", "meaning": "Absolute text cursor row maintained by the $C000 text engine; read at $655F after the two-CR header so that menuFirstRow gets the row of the first menu item (13).", "confidence": "high"}, {"addr": "43", "scope": "zp", "name": "textRawMode", "meaning": "Text engine flag: bit 7 set prints character codes verbatim instead of translating them through the $987E table. Cleared here so the header and the item names print normally.", "confidence": "medium"}, {"addr": "1C", "scope": "zp", "name": "scratchCounter1C", "meaning": "Scratch byte; in this routine the item-id loop counter that walks 13..16 (ENERGY, BATTLE, RADAR, DRONE) while calling addMenuItem.", "confidence": "high"}, {"addr": "90EF", "scope": "abs", "name": "textCentreWidth", "meaning": "Text engine centring width: when non-zero sub_C137 pads the string to that many columns using the zp_42 colour. Cleared at $6532 so the menu text is printed left-aligned inside the narrow window.", "confidence": "high"}, {"addr": "90F8", "scope": "abs", "name": "selectedUnit", "meaning": "Unit index the menus act on. The value $FF written here is a sentinel meaning 'repair menu': toggleMenuRowHighlight ($60EE) tests for it and, while the selection is 0..3, blinks the comcen system marker with the row (and aborts the menu when the comcen becomes stunned). It is re-stored on every pass because the selector overwrites it via D_91D7.", "confidence": "high"}, {"addr": "91CE", "scope": "abs", "name": "menuItemIdList", "meaning": "Item ids of the current menu in display order, filled by addMenuItem; here {13,14,15,16,12} = ENERGY, BATTLE, RADAR, DRONE, (EXIT).", "confidence": "high"}, {"addr": "91D4", "scope": "abs", "name": "menuItemCount", "meaning": "Number of rows in the current menu; zeroed at $6537 and incremented by each addMenuItem call, ending at 5.", "confidence": "high"}, {"addr": "91D5", "scope": "abs", "name": "menuSelectedItem", "meaning": "Currently highlighted / chosen menu row. In this menu it doubles as the comcen system index 0..3 (ENERGY, BATTLE, RADAR, DRONE) used by toggleSystemMarker and attemptSystemRepair; 4 is the (EXIT) row. Pre-set to 0 at $653A.", "confidence": "high"}, {"addr": "91D6", "scope": "abs", "name": "menuFirstRow", "meaning": "Screen row of menu row 0; taken from textCursorRow after the header is printed (13 here, so the items sit on rows 13..17).", "confidence": "high"}, {"addr": "0B9B", "scope": "abs", "name": "filmPlaybackFlag", "meaning": "Bit 7 = film playback / solo observer mode. Read indirectly through getSoloOrFlag923F at $658B: while it is set the menu still runs but no repair is attempted (a film must not change game state).", "confidence": "medium"}, {"addr": "923F", "scope": "abs", "name": "gameOverFlags", "meaning": "Set to $C0 when the game ends (computeGameResult, the $8C abort command, end of film). Bit 6 is the half tested by getSoloOrFlag923F, so once the game is over the REPAIR menu becomes inert.", "confidence": "medium"}, {"addr": "922A", "scope": "abs", "name": "comcenStunStatus", "meaning": "Comcen stun status; bit 7 set = comcen stunned. Not read by this chunk directly, but toggleMenuRowHighlight checks it on every blink while selectedUnit is $FF and forces this menu to exit if the comcen gets stunned while it is open.", "confidence": "medium"}, {"addr": "9241", "scope": "abs", "name": "comcenSystemStatus", "meaning": "Four-byte comcen system status array indexed by the same 0..3 value this menu leaves in menuSelectedItem ($80 = damaged, 0 = ok); written by attemptSystemRepair on a successful repair.", "confidence": "medium"} ], "dataBlocks": [], "misclassified": [], "insights": [ "REPAIR tab flow: repairTabAction ($17DA) -> at $1860 it erases the four comcen system markers, sets showOkMarkers ($188A) = 1 so even undamaged systems get a marker, JSRs runRepairWhichMenu ($652E), then consumes the SPACE key, restores the standard menu text window and redraws all four markers. runRepairWhichMenu itself only returns after the player picks (EXIT) or the selector aborts.", "Screen layout of the REPAIR WHICH panel: text window at column 3, width 7, rows 9..19, colour $61. sub_C06A clears it, sub_C041 emits one CR (row 9 -> 10), the string at $CBD6 ('REPAIR',CR,'WHICH:',CR,CR|$80) puts the two header words on rows 10 and 11 and leaves the cursor on row 13, which becomes menuFirstRow. Items therefore occupy rows 13 (ENERGY), 14 (BATTLE), 15 (RADAR), 16 (DRONE) and 17 ((EXIT)).", "menuSelectedItem ($91D5) is deliberately a single source of truth here: the same byte is the highlighted row for the menu engine, the comcen system index for toggleSystemMarker ($188B) / drawSystemMarker, and the system index attemptSystemRepair ($193C) uses to index comcenSystemStatus ($9241). That only works because addMenuItem is called with ids 13,14,15,16 in exactly the system order ENERGY, BATTLE, RADAR, DRONE.", "selectedUnit ($90F8) = $FF is a sentinel, not a unit: only toggleMenuRowHighlight ($60EE) looks at it, and only to enable the marker blink. It has to be re-written on every pass of the L_657C loop because runMenuLoopWatchUnit copies it into $91D7 and the repair attempt in between can change it.", "Non-local exit: if the comcen is stunned while the menu is up, toggleMenuRowHighlight pops its own return address ($6103/$6104) and jumps to L_607E inside the selector, which sets menuSelectedItem = menuItemCount-1 = 4. Control comes back to $6584 with Y = 4, so the CPY #$04 test at $6587 takes the (EXIT) path and the window is cleared - the abort is funnelled through the normal exit. The same holds for a game-over or a sub_C451 abort (SPACE / function key).", "getSoloOrFlag923F ($0EE5) gates the repair: repair is attempted only when D_0B9B bit 7 is clear (not a film / solo replay) and D_923F & $40 is clear (game not over). This corrects docs/knowledgeBase.md line 274, which calls $0EE5 an orphan 'not referenced by traced code' - XREF.txt shows exactly one caller, $658B, and it is this routine.", "The exit path is a JMP sub_C06A ($659D), i.e. the routine tail-calls the window clear with colour $66 and returns to repairTabAction from there; there is no RTS at the end of this chunk.", "Earlier notes (knowledgeBase line 639 and annotations/11_survey_notes_game_main_0800.json) still say this routine 'shows as data in the disassembly'. That is stale: main_0800.s now disassembles $652E-$659F correctly as code, and repairTabAction at $17DA is code too." ] }