{
 "chunk": "game_main_new_17DA",
 "unit": "game/main_0800",
 "routines": [
  {
   "addr": "17DA",
   "name": "repairTabAction",
   "summary": "Fire-button handler of the REPAIR tab (entry 1 of menuItemHandlerTable at $1535, called through the self-modified JSR at $148D). Does nothing unless the DAMAGE option is on (gameTypeOptions $0BA3 bit 4), the game is not a film playback ($0B9B bit 7 clear) and a game is running ($0BA8 == 0). When the comcen is stunned (comcenStunStatus $922A bit 7) it runs the stun-repair attempt: prints 'ATTEMPTING REPAIR...', plays sound $18, advances the battle 200 frames, clears the message, and - only while the stun counter ($922A & $0F) is below 8 - takes a 1-in-8 random chance to queue the 1-byte command $9E (cmdComcenRepairedOrSetupReady, which clears the comcen stun counter on both machines) with success sound $13, otherwise failure sound $12, then runs 20 more frames. When the comcen is not stunned (L_1823) it first halts the comcen if needed: if unitDisplayFlags[comcen] bit 7 is clear (still moving) or bit 6 is set (group order active) it queues command $80 (cmdMoveUnit) with the comcen's own current column/row, which halts it and drops its group membership. Then it erases all four system markers, sets showOkMarkers and opens the 'REPAIR WHICH:' selection menu (runRepairWhichMenu $652E), and on return consumes a pending space key, restores the menu text window, redraws the four markers and tail-calls snapshotSetupId.",
   "inputs": "D_0BA3 gameTypeOptions bit 4, D_0B9B filmPlaybackFlag, D_0BA8 noGameInProgress, D_922A comcenStunStatus, D_9236 comcenUnit, D_FB54 unitDisplayFlags, D_F640/D_F6A4 unit column/row, RNG nextGameRandom",
   "outputs": "commands $9E (queueCmdBytePending) or $80 (queueCmd4 with zp_73/74/75) queued into the outgoing ring; sounds $12/$13/$18 via sub_C89A; battle advanced by runGameFrames; blinkPhase=1, showOkMarkers toggled, menuFlag1412 used as a 3..0 loop counter; markers redrawn; comcenStatusSnapshot $92D6-$92D9 refreshed",
   "confidence": "high"
  },
  {
   "addr": "188B",
   "name": "toggleSystemMarker",
   "summary": "Blink helper for the REPAIR WHICH menu. Toggles blinkPhase ($1889) and then either draws (phase 0) or erases with colour $16 (phase 1) the marker of the currently highlighted comcen system D_91D5. Called from blinkRepairMarker and from the menu-row highlight toggler at $6108, which invokes it whenever the menu selector runs in repair mode (selectedUnit $90F8 == $FF) and the highlighted row is < 4, so the schematic marker blinks in step with the menu row.",
   "inputs": "D_91D5 selected system 0..3, blinkPhase $1889",
   "outputs": "blinkPhase toggled; falls through to drawSystemMarker or jumps to eraseSystemMarker (X=$16)",
   "confidence": "high"
  },
  {
   "addr": "189D",
   "name": "drawSystemMarker",
   "summary": "Draws the status marker of comcen system Y on the comcen schematic of the REPAIR tab. Saves Y in the self-modified operand at $18A4 (printEnergyValue clobbers Y), refreshes the energy reading and hence comcenSystemStatus[0], then picks the colour byte: $15 (white/green) when comcenSystemStatus[Y]==0, $12 (white/red) when bit 7 is set (damaged), $17 (white/yellow) otherwise ($40 = degraded energy). A healthy system is erased with $16 instead of drawn unless showOkMarkers is set (only true while the REPAIR WHICH menu is open). The marker itself is a plus of five colour cells: origin (row=systemMarkerRowTable[Y], col=systemMarkerColumnTable[Y]), cells (r,c+1), (r+2,c+1), (r+1,c), (r+1,c+1), (r+1,c+2), each painted with a 1x1 fillScreenColourRect.",
   "inputs": "Y = system index 0..3, D_9241 comcenSystemStatus, showOkMarkers $188A, systemMarkerColumnTable/systemMarkerRowTable",
   "outputs": "screen RAM colour cells at $8C00; D_2A2A fill colour, D_2A2D row, D_2A2E column; self-modifies $18A4; energy readout refreshed",
   "confidence": "high"
  },
  {
   "addr": "1919",
   "name": "eraseSystemMarker",
   "summary": "Fills the 3x3 colour-cell block of system Y's marker (origin systemMarkerRowTable[Y] / systemMarkerColumnTable[Y]) with the colour byte in X, which every caller passes as $16 - the schematic background colour used when the REPAIR panel is drawn with text colour $66. Used to blank markers before the REPAIR WHICH menu and as the 'off' phase of the marker blink.",
   "inputs": "Y = system index 0..3, X = colour byte (always $16)",
   "outputs": "D_2A2D/D_2A2E set, 3x3 colour rectangle filled via fillScreenColourRect",
   "confidence": "high"
  },
  {
   "addr": "192D",
   "name": "sendEnergyRepairCommand",
   "summary": "Queues the 3-byte command $9A (cmdAddEnergy) with parameters comcenUnit ($9236) and repairAmount ($17D9) through queueCmd3, so both machines add the repaired energy to the comcen's entry in unitEnergyTable. The only part of a comcen repair that travels over the link; the status of systems 1-3 is purely local.",
   "inputs": "D_9236 comcenUnit, repairAmount $17D9",
   "outputs": "zp_74 = comcen unit, zp_75 = amount; command $9A queued, pendingOwnCmdCount $929F incremented",
   "confidence": "high"
  },
  {
   "addr": "193C",
   "name": "attemptSystemRepair",
   "summary": "One repair attempt on the comcen system selected in D_91D5, called from the REPAIR WHICH menu loop at $6590 (skipped in solo/film mode). Prints 'ATTEMPTING REPAIR...', plays sound $18 and rolls the RNG: the attempt succeeds with probability 1/2 for the energy system (index 0, random & 1) and 1/4 for systems 1-3 (random & 3), and only if the system is not already OK. On success for the energy system it computes repairAmount = (50 - comcenEnergySnapshot)/8 + 1, sends it with sendEnergyRepairCommand and updates the snapshot (capped at 50); for the other systems it simply clears comcenSystemStatus[Y]. Plays sound $13 on success, $12 on failure, with a marker blink before and after the sound, then re-reads the comcen energy into the snapshot, clears zp_6E and blinkPhase and erases the message line.",
   "inputs": "D_91D5 selected system, D_9241 comcenSystemStatus, comcenEnergySnapshot $17D8, D_9236, D_F9C4 unitEnergyTable, nextGameRandom",
   "outputs": "repairAmount $17D9, comcenEnergySnapshot $17D8, D_9241[Y] cleared on success, command $9A queued for the energy system, sounds $12/$13/$18, zp_6E=0, blinkPhase=0, message line cleared",
   "confidence": "high"
  },
  {
   "addr": "19B0",
   "name": "blinkRepairMarker",
   "summary": "Blinks the marker of the selected comcen system for about one second while a repair attempt resolves: sets the IRQ frame countdown zp_6F to 60 and, every 20 game frames (runGameFrames, so the real-time battle keeps running), calls toggleSystemMarker until zp_6F reaches 0. Aborts immediately if the game-over flag D_92C9 is nonzero.",
   "inputs": "D_91D5, D_92C9 gameEndFlag",
   "outputs": "zp_6F counted down by the IRQ, blinkPhase toggled, marker drawn/erased, battle advanced",
   "confidence": "high"
  },
  {
   "addr": "19C9",
   "name": "printAttemptingRepair",
   "summary": "Positions the repair message line (setRepairMessageWindow) and prints the string 'ATTEMPTING REPAIR...' at $CBE5 with sub_C133, then restores the previously saved text window with sub_C40E.",
   "inputs": "none",
   "outputs": "text drawn into the bitmap at column 10, row 20; text window restored from $92B6",
   "confidence": "high"
  },
  {
   "addr": "19D6",
   "name": "clearRepairMessage",
   "summary": "Erases the repair message line: positions the same window and prints 20 copies of the text fill character zp_3E (routine $C0EF in the $C000 overlay; its label bootReceiveSectorData is a stale leftover from the boot loader that used to occupy $C000), then restores the text window.",
   "inputs": "zp_3E fill character (0 while the repair menus are up)",
   "outputs": "20 characters of the message line blanked; text window restored",
   "confidence": "high"
  },
  {
   "addr": "19E1",
   "name": "setRepairMessageWindow",
   "summary": "Saves the current 12-byte text-window state to $92B6 (sub_C41B), sets the menu text colour (setMenuTextColour, $61 or $21 when stunned), applies the menu panel window geometry (setMenuWindowBounds: left column 2, rows 7..$16, width $24) and places the cursor at column 10, row 20 by falling into sub_C097/sub_C099. Shared prologue of printAttemptingRepair and clearRepairMessage.",
   "inputs": "D_922A, D_90F9 (through setMenuTextColour)",
   "outputs": "zp_39-zp_40 window, zp_3D colour, cursor pointer recomputed; previous window saved at $92B6",
   "confidence": "high"
  }
 ],
 "variables": [
  {"addr": "17D8", "scope": "abs", "name": "comcenEnergySnapshot", "meaning": "Local copy of the comcen energy (unitEnergyTable[comcenUnit] & $3F, 0..50) taken when the REPAIR tab is drawn and refreshed after every repair attempt; the energy repair size is computed from it because the queued $9A command has not been executed yet.", "confidence": "high"},
  {"addr": "17D9", "scope": "abs", "name": "repairAmount", "meaning": "Energy points added by the last successful energy repair: (50 - comcenEnergySnapshot)/8 + 1; sent as the second parameter of command $9A.", "confidence": "high"},
  {"addr": "1889", "scope": "abs", "name": "blinkPhase", "meaning": "0/1 blink phase shared by the menu tab blink ($16B7) and the comcen system marker blink; 0 = element visible, 1 = element blanked.", "confidence": "high"},
  {"addr": "188A", "scope": "abs", "name": "showOkMarkers", "meaning": "Nonzero while the REPAIR WHICH menu is open: makes drawSystemMarker paint a green marker for undamaged systems too instead of erasing them.", "confidence": "high"},
  {"addr": "1412", "scope": "abs", "name": "systemMarkerLoopIndex", "meaning": "Scratch byte used by repairTabAction as the 3..0 loop counter of the marker erase/redraw loops. The only other write is the $7F stored by enterMainMenu at $141F, which is never read - dead code. A better name than the current menuFlag1412.", "confidence": "medium"},
  {"addr": "18A4", "scope": "abs", "name": "drawSystemMarkerIndex", "meaning": "Immediate operand of the LDY at $18A3, self-modified by drawSystemMarker so the system index survives the call to printEnergyValue.", "confidence": "high"},
  {"addr": "922A", "scope": "abs", "name": "comcenStunStatus", "meaning": "Own comcen stun state, recomputed at $4549 as (unitStunTable[comcenUnit] & $0F) with bit 7 ORed in when nonzero; $FF triggers the knock-out sequence. repairTabAction only offers the stun repair while the low nibble is below 8.", "confidence": "high"},
  {"addr": "9236", "scope": "abs", "name": "comcenUnit", "meaning": "Index of the local player's COMCEN unit (49 for side 0, 99 for side 1); used to index unitEnergyTable/unitCol/unitRow/unitDisplayFlags and as the unit parameter of the $80 and $9A commands issued here.", "confidence": "high"},
  {"addr": "9241", "scope": "abs", "name": "comcenSystemStatus", "meaning": "Four status bytes shown on the comcen schematic: [0] energy (0 = 100%, $40 = 21..99%, $80 = below 21%, recomputed by printEnergyValue), [1..3] the three comcen systems (0 = ok, $80 = damaged, set only by rollComcenSystemDamage, cleared only by attemptSystemRepair). Values $40 therefore only ever occur for entry 0.", "confidence": "high"},
  {"addr": "91D5", "scope": "abs", "name": "menuSelectedItem", "meaning": "Highlighted/selected menu row; while the REPAIR tab is up it doubles as the comcen system index 0..3 ($04 = the (EXIT) item), which is what drawSystemMarker/toggleSystemMarker/attemptSystemRepair operate on.", "confidence": "high"},
  {"addr": "92C9", "scope": "abs", "name": "gameEndFlag", "meaning": "Nonzero once the game-over sequence is running; blinkRepairMarker and runGameFrames abort their waits on it.", "confidence": "high"},
  {"addr": "0BA3", "scope": "abs", "name": "gameTypeOptions", "meaning": "Game type/option byte; bit 4 = DAMAGE option, the master switch that enables the whole comcen repair feature tested at $17DA.", "confidence": "high"},
  {"addr": "0B9B", "scope": "abs", "name": "filmPlaybackFlag", "meaning": "Bit 7 = film playback / solo observer mode; repairs are refused because commands must not be queued during playback.", "confidence": "high"},
  {"addr": "0BA8", "scope": "abs", "name": "noGameInProgress", "meaning": "0 while a game is running; any nonzero value disables the repair action.", "confidence": "high"},
  {"addr": "F9C4", "scope": "abs", "name": "unitEnergyTable", "meaning": "Per-unit energy array (100 entries): bits 0-5 = 0..50 (displayed as 0..100%), upper bits = spotted/visible flags. Masked with $3F when read for comcenEnergySnapshot.", "confidence": "high"},
  {"addr": "FB54", "scope": "abs", "name": "unitDisplayFlags", "meaning": "Per-unit local flag array; repairTabAction tests bit 7 (unit is stationary / at its destination) and bit 6 (group membership/order active) on the comcen to decide whether it must be halted with a $80 move-to-self command before repairing.", "confidence": "medium"},
  {"addr": "F640", "scope": "abs", "name": "unitCol", "meaning": "Per-unit map column (100 entries); source of the column parameter of the halt command.", "confidence": "high"},
  {"addr": "F6A4", "scope": "abs", "name": "unitRow", "meaning": "Per-unit map row (100 entries); source of the row parameter of the halt command.", "confidence": "high"},
  {"addr": "2A2A", "scope": "abs", "name": "fillColourValue", "meaning": "Colour byte used by fillScreenColourRect; drawSystemMarker parks the marker colour here and re-loads it for each of the five 1x1 fills.", "confidence": "high"},
  {"addr": "2A2D", "scope": "abs", "name": "fillRow", "meaning": "Screen row (0-24) of the fill/window origin used by fillScreenColourRect; stepped by drawSystemMarker to build the plus shape.", "confidence": "high"},
  {"addr": "2A2E", "scope": "abs", "name": "fillColumn", "meaning": "Screen column (0-39) of the fill/window origin used by fillScreenColourRect.", "confidence": "high"},
  {"addr": "6E", "scope": "zp", "name": "menuBlinkTimer", "meaning": "IRQ frame countdown (one of the six timers $6C-$71 decremented at $123D) used for the menu highlight/tab blink; attemptSystemRepair zeroes it so the tab blink restarts immediately after a repair.", "confidence": "high"},
  {"addr": "6F", "scope": "zp", "name": "countdownTimer6F", "meaning": "IRQ frame countdown; blinkRepairMarker loads it with 60 (one second) to time the marker blink.", "confidence": "high"},
  {"addr": "73", "scope": "zp", "name": "cmdParam0", "meaning": "First parameter of an outgoing command; here the comcen unit index for the $80 halt command.", "confidence": "high"},
  {"addr": "74", "scope": "zp", "name": "cmdParam1", "meaning": "Second command parameter: map column for $80, comcen unit index for $9A.", "confidence": "high"},
  {"addr": "75", "scope": "zp", "name": "cmdParam2", "meaning": "Third command parameter: map row for $80, energy amount for $9A.", "confidence": "high"},
  {"addr": "3D", "scope": "zp", "name": "textColour", "meaning": "Colour byte for printed text; set by setMenuTextColour ($61, or $21 when the comcen is stunned) before the repair messages are drawn. Its low nibble also determines the schematic background ($16 normally) that eraseSystemMarker assumes.", "confidence": "high"},
  {"addr": "3E", "scope": "zp", "name": "textFillChar", "meaning": "Fill character used by the clear routines; clearRepairMessage prints 20 of it. It is 0 (blank) while the repair menus are up.", "confidence": "high"},
  {"addr": "3F", "scope": "zp", "name": "textCursorCol", "meaning": "Text cursor column relative to the window left edge; set to 10 for the repair message line.", "confidence": "high"},
  {"addr": "40", "scope": "zp", "name": "textCursorRow", "meaning": "Absolute text cursor row; set to 20 for the repair message line.", "confidence": "high"},
  {"addr": "92B6", "scope": "abs", "name": "savedTextWindow", "meaning": "12-byte save area for zp_39-zp_44 written by sub_C41B and restored by sub_C40E around the repair message printing.", "confidence": "high"},
  {"addr": "929F", "scope": "abs", "name": "pendingOwnCmdCount", "meaning": "Count of own commands queued but not yet executed; incremented by queueCmdBytePending/queueCmd3/queueCmd4 for each command this chunk queues.", "confidence": "high"}
 ],
 "dataBlocks": [
  {"addr": "1881", "length": 4, "type": "byteTable", "name": "systemMarkerColumnTable", "description": "Screen column of the four comcen system markers on the REPAIR schematic: $0D, $10, $14, $19 (energy, then the three systems). Read by drawSystemMarker and eraseSystemMarker."},
  {"addr": "1885", "length": 4, "type": "byteTable", "name": "systemMarkerRowTable", "description": "Screen row of the four comcen system markers: $0E, $0A, $0A, $0C."},
  {"addr": "1889", "length": 1, "type": "byteTable", "name": "blinkPhase", "description": "Shared 0/1 blink phase for the menu tab blink and the comcen system marker blink."},
  {"addr": "188A", "length": 1, "type": "byteTable", "name": "showOkMarkers", "description": "Flag: draw markers for undamaged systems as well (set only while the REPAIR WHICH menu is open)."}
 ],
 "misclassified": [],
 "insights": [
  "The whole chunk implements the REPAIR tab of the in-game console. It is reached only through menuItemHandlerTable ($1535, entry 1 = $17DA) via the self-modified JSR at $148D in mainMenuLoop, so nothing calls repairTabAction directly and it does not appear in XREF.txt as a callee.",
  "Comcen damage model: comcenSystemStatus ($9241) holds four bytes - [0] is a derived display value for the energy (0 = 100%, $40 = 21..99%, $80 = under 21%, recomputed by printEnergyValue), while [1..3] are the three repairable systems, set to $80 only by rollComcenSystemDamage ($3D57) and cleared only by attemptSystemRepair. The three system states are never transmitted: each machine damages and repairs its own comcen locally. Only the energy repair goes over the link, as command $9A (cmdAddEnergy, unit + amount), so that both copies of unitEnergyTable stay in sync.",
  "Repair odds are hard-coded: energy repairs succeed 1 time in 2 (random & 1), the other three systems 1 time in 4 (random & 3), and the comcen stun repair 1 time in 8 (random & 7) - and the stun repair is refused outright while the stun counter ($922A & $0F) is 8 or more. A successful stun repair queues the single-byte command $9E (cmdComcenRepairedOrSetupReady), which zeroes the comcen's stun counter in unitStunTable on both machines. Each energy repair adds (50 - currentEnergy)/8 + 1 points, i.e. repairs get smaller as the comcen recovers.",
  "Before opening the REPAIR WHICH menu, repairTabAction issues command $80 (cmdMoveUnit) with the comcen's own current column and row whenever unitDisplayFlags[comcen] bit 7 is clear (still moving) or bit 6 is set (group order active). Because the $80 handler clears the group-membership bit and sets the destination, this is the game's idiom for 'halt this unit and take it out of its group' - the comcen must stand still while it is being repaired.",
  "Marker geometry and colours: each system marker is a plus of five 1x1 colour cells built by five fillScreenColourRect calls around the origin (systemMarkerRowTable[i], systemMarkerColumnTable[i]); erasing uses a single 3x3 fill. The colour bytes are screen-RAM nibble pairs with a fixed high nibble 1: $15 ok, $17 degraded, $12 damaged, $16 blank. $16 matches the schematic background that drawRepairTab paints as (textColour & $0F) | $10, which is $16 for the normal panel colour $66 - eraseSystemMarker hard-codes $16, which would be wrong for the stunned panel ($12), but markers are never drawn while the comcen is stunned so the case cannot occur.",
  "drawSystemMarker keeps its system index in the self-modified LDY operand at $18A4 across the call to printEnergyValue (which clobbers Y); the same trick is used by runGameFrames at $40B0. Reading $18A4 as data would be wrong - it is an immediate operand.",
  "zp_6C-zp_71 are six general frame countdowns decremented once per frame by the IRQ code at $123D (floor 0). blinkRepairMarker uses zp_6F = 60 frames (one second) and advances the real-time battle 20 frames per blink step with runGameFrames, so a repair attempt keeps the game running for roughly two seconds while the marker flashes.",
  "The menu selector shares its highlight blink with the schematic: when it runs in repair mode (selectedUnit $90F8 = $FF) the toggler at $6108 calls toggleSystemMarker for rows 0-3, and it also aborts the menu entirely ($6103: two PLAs and a jump) the moment the comcen becomes stunned.",
  "Dead code: enterMainMenu stores $7F into $1412 at $141F, but the only reads of $1412 are the two loop-counter reads inside repairTabAction ($1856, $1879), which always follow a store of 3. The initial $7F is never used.",
  "Stale label: clearRepairMessage calls $C0EF in the $C000 overlay under the name bootReceiveSectorData. That address now holds the text routine 'print A copies of the fill character zp_3E' (loop over sub_C0C0); the name is a leftover from the boot loader that occupied $C000 before the runtime overlay replaced it."
 ]
}
