{
 "chunk": "game_ovl_6F00_A_844F",
 "unit": "game/ovl_6F00_A",
 "routines": [
  {
   "addr": "8451",
   "name": "editValueWithJoystick",
   "summary": "Generic numeric option editor used by the custom-scenario setup. A = exclusive upper limit (patched into the CMP at $8492), Y = display multiplier (patched into $8469). Loops: un-highlights the one-row menu, prints editValue*Y in decimal at column 1 of the value window (multiply8x8 $FCCD -> A=lo/Y=hi, then $C17D), clears the rest of the line, services the link (serviceCommandExchange), blinks the row, and applies joystick up/down as +1/-1 (rejecting values >= limit or below 0, playing sound 2 on a change, auto-repeat via setJoystickRepeatDelay). Returns when the fire button is pressed (checkFirePressed).",
   "inputs": "A = limit (value must stay < A), Y = multiplier for display, D_844F initial value, zp_5D joystick, zp_6C repeat timer, zp_6E blink timer, menu window set up by beginValueEdit",
   "outputs": "D_844F = edited value; D_92C5 = 1; text printed in the info panel; sounds 2",
   "confidence": "high"
  },
  {
   "addr": "84AA",
   "name": "applyHandicapPoints",
   "summary": "Tail of runGameStartOptions (reached by JMP from $85B9). Computes the default handicap for the asymmetric scenarios: game type 1 (QB SNEAK) gives side 0 a handicap of 2 (20 points), game type 6 (DEFENDER) gives side 1 a handicap of $14 (200 points), everything else 0. When the custom toggle (D_92F3 bit 7) is set the player edits the value instead ('HANDICAP', 0..50 shown x10) starting from that default. A nonzero result is sent as command $A5 kind 0 (value*10 points for the sender's side, cmdSetupOption); zero is not sent.",
   "inputs": "D_0BA3 bits 0-2 game type, D_0B9F playerSide, D_92F3 bit 7 custom flag",
   "outputs": "command $A5 00 value queued via queueCmd3 (zp_74 = 0, zp_75 = value); info panel used",
   "confidence": "high"
  },
  {
   "addr": "84EC",
   "name": "editTerrainPoints",
   "summary": "Custom option 'TERRAIN PTS': starts from D_92AC[opponent side] (points awarded for entering the enemy zone), lets the player pick 0..2 with editValueWithJoystick and sends command $A5 kind 1 (cmdSetupOption stores it in $92AC of the other side).",
   "inputs": "D_0B9F playerSide, D_92AC",
   "outputs": "command $A5 01 value queued (zp_74 = 1, zp_75 = value)",
   "confidence": "medium"
  },
  {
   "addr": "84F1",
   "name": "editTerrainPointsForSide",
   "summary": "Entry into editTerrainPoints with the side index already in A (A -> Y, X = D_92AC[Y]). In variant A nothing calls it; the XREF caller at $83DE belongs to overlay variant B, where $84F1 is a different routine.",
   "inputs": "A = side index 0/1",
   "outputs": "as editTerrainPoints",
   "confidence": "medium"
  },
  {
   "addr": "8511",
   "name": "editDronesAndMissiles",
   "summary": "Custom options 'DRONES' (0..9, from D_92AE) and 'MISSILES' (label $CC9E, 0..36, from D_92B0), each edited with beginValueEdit + editValueWithJoystick. The two results are sent as one command $90 x=drones y=missiles; in the setup phase cmdMissileStrike ($53C0) stores them as dronesLeft/missilesLeft for the sender.",
   "inputs": "D_92AE dronesLeft, D_92B0 missilesLeft",
   "outputs": "command $90 drones missiles queued (zp_74 = drones, zp_75 = missiles)",
   "confidence": "medium"
  },
  {
   "addr": "8518",
   "name": "editDronesAndMissilesBody",
   "summary": "Not a real entry point in variant A: it is the JSR beginValueEdit inside editDronesAndMissiles (A/Y/X must already hold the label and value). The label exists because the main program calls $8518 at $1460/$14D3, which is a routine of overlay variant B (menu screen).",
   "inputs": "A/Y = label, X = value (must be preset)",
   "outputs": "as editDronesAndMissiles",
   "confidence": "high"
  },
  {
   "addr": "8547",
   "name": "runGameStartOptions",
   "summary": "Called once from the new-game start sequence ($7AF7) after the setup has been saved and before unit placement. Sets gamePhase $7F, hides the viewport (sub_8364), draws the overview (side 0: drawOverviewMap, side 1: clearScreenAndRedrawGameScreen), shows the 'STANDARD/CUSTOM <type> SCENARIO - PRESS BUTTON WHEN READY.' banner (showScenarioBannerAndWaitForButton), copies gameTypeOptions bit 6 into D_8450 and (shifted to bit 7) into D_92F3. If CUSTOM rules are on it shows the custom summary message, prints the game type name and a 2-item STANDARD/CUSTOM menu (rows at column 28, width 10, runMenuLoopWithFlag); choosing CUSTOM (D_8450 = 1) runs editComcenSpeed, editTerrainPoints and editDronesAndMissiles. Then, for game types 4-6 (SLUGGERS, FULL WAR, DEFENDER), sub_8378 sets up the recycler, and finally it jumps to applyHandicapPoints.",
   "inputs": "D_0BA3 gameTypeOptions, D_0B9F playerSide, menu/text engine state",
   "outputs": "zp_B1 = $7F, D_8450, D_92F3, setup commands $A5/$90/$9C queued, screen redrawn",
   "confidence": "medium"
  },
  {
   "addr": "85BC",
   "name": "editComcenSpeed",
   "summary": "Custom option 'COMCEN SPEED': starts from D_92B4 (own comcen speed setting 0..3), edits it with editValueWithJoystick (limit 4) and sends command $A5 kind 3 (cmdSetupOption writes $92B4 of the sender's side; $7B6E later maps the setting through the table at $78BF).",
   "inputs": "D_92B4",
   "outputs": "command $A5 03 value queued (zp_74 = 3, zp_75 = value)",
   "confidence": "medium"
  },
  {
   "addr": "85DB",
   "name": "beginValueEdit",
   "summary": "Common prologue of the value editors: stores the label pointer (patched into $85EA/$85EC), sets editValue = X, clears the info panel in colour 8 and sets row 15 (sub_8441), prints the label centred, moves the text window left edge to column 29, starts a new line and records that row as menuFirstRow with menuSelectedItem = 0. Falls into the tail at $8601 which sets selectedUnit = $FE (plain menu, no unit) and the window width to 5 for the highlight bar.",
   "inputs": "A/Y = label string (bit-7 terminated), X = initial value",
   "outputs": "D_844F = X, D_91D5 = 0, D_91D6 = row, D_90F8 = $FE, zp_3B = $1D, zp_3C = 5, label printed",
   "confidence": "high"
  },
  {
   "addr": "8601",
   "name": "setValueEditWindow",
   "summary": "Tail of beginValueEdit: selectedUnit = $FE and textWindowWidth = 5. The sub_ label only exists because $8601 is a routine entry in overlay variant B; in A it is only reached by fall-through.",
   "inputs": "-",
   "outputs": "D_90F8 = $FE, zp_3C = 5",
   "confidence": "high"
  },
  {
   "addr": "860B",
   "name": "editOptionBitOnOff",
   "summary": "Two-row OFF/ON menu for one bit of gameTypeOptions, used by the scenario setup screen for 'UNIT MENUS' (mask $08, $82B3) and 'DAMAGE' (mask $10, $82BC). Stores the label pointer and mask in self-modifying operands, hides the viewport, clears the panel to row 14, prints the label centred with the current state pre-selected (row 0 = OFF from $064D, row 1 = ON via sub_C137), runs runMenuLoopWithFlag with width 5 at column 27 and then clears or sets the mask bit in D_0BA3 according to the chosen row.",
   "inputs": "A/Y = label string, X = bit mask, D_0BA3",
   "outputs": "D_0BA3 bit updated; D_91D4 = 2, D_91D5 = choice",
   "confidence": "high"
  },
  {
   "addr": "862D",
   "name": "runOnOffMenuAndApplyBit",
   "summary": "Tail of editOptionBitOnOff (menuItemCount = 2, print OFF/ON, run the menu, apply the mask at $8621+1). Only an entry point in overlay variant B.",
   "inputs": "label already printed, mask operand at $8622",
   "outputs": "D_0BA3 updated",
   "confidence": "high"
  },
  {
   "addr": "8632",
   "name": "printOnOffMenuAndApplyBit",
   "summary": "Inner tail of editOptionBitOnOff starting at the OFF/ON printing. The main program's JSR $8632 at $176B targets overlay variant B's routine of the same address, not this code.",
   "inputs": "menu state, mask operand at $8622",
   "outputs": "D_0BA3 updated",
   "confidence": "high"
  },
  {
   "addr": "8658",
   "name": "handleStarKeyToggle",
   "summary": "Per-frame hook called while overlay A is resident in non-battle phases (battlefield loop via the trampoline $25C4 when zp_B1 != 0, and runMenuLoop at $6002 when zp_B1 == $FF). If no chat entry is pending (D_929C bit 7 clear) and the last key is '*' ($AA) it consumes the key, toggles bit 7 of D_92F3 and falls into showToggleStateMessage (returns C = 1). Otherwise returns C = 0. During unit placement the flag means DESTROY mode (clicking an own unit sends $91 self destruct, $209F); on the scenario setup screen it means CUSTOM rules.",
   "inputs": "D_929C chatState, D_9248 lastKeyCode, D_92F3",
   "outputs": "C = 1 and D_92F3 bit 7 toggled when '*' was pressed (D_9248 = $FF), else C = 0",
   "confidence": "high"
  },
  {
   "addr": "8673",
   "name": "showToggleStateMessage",
   "summary": "Shows the state of the '*' toggle: empties the message queue (tail = head), patches the word 'ON' ($0650) or 'OFF' ($064D) into the message text (3 bytes copied to the address patched at $869A/$869B: $EFDF inside 'CUSTOM OFF' or $EFEA inside 'DESTROY OFF'), sets persistentMessageId to $1E while the mode is on (or to the operand at $868D when off: 0 on the setup screen, 10 = 'SETUP UNITS...' during placement), clears the message timer and queues message $1E. Returns C = 1. Also called directly from the setup screen ($8253) to show 'CUSTOM ON' initially.",
   "inputs": "D_92F3 bit 7, operands patched by $820B/$821F or setDestroyModeMessage",
   "outputs": "D_9252 = D_9251, D_92A1, zp_72 = 0, message $1E queued, C = 1, zp_48/49 = word pointer",
   "confidence": "high"
  },
  {
   "addr": "86AA",
   "name": "setDestroyModeMessage",
   "summary": "Prepares the '*' toggle for the unit-placement phase (called at $7B4B before the placement loop): off-state persistent message = 10 ('SETUP UNITS. PRESS F 1 WHEN DONE.'), message slot $1E -> 'DESTROY OFF' ($EFE2 in the T34 $EC00 sub-overlay), and the ON/OFF patch address = $EFEA (the 'OFF' inside that string). The setup-screen code at $820B/$821F does the same with 'CUSTOM OFF' ($EFD8/$EFDF) and off-message 0.",
   "inputs": "-",
   "outputs": "$868D = $0A, message slot $1E (D_0500/D_0524 index $1E) = $EFE2, $869A/$869B = $EFEA",
   "confidence": "high"
  },
  {
   "addr": "86C3",
   "name": "showCustomSummaryMessage",
   "summary": "Builds the status line 'CUSTOM:' [+ 'MAP,' when D_0BA3 bit 7 is set] + ' MENUS OFF,/ON,  DAMAGE OFF./ON.' into the buffer at $0332 (prefix from $CC19 'CUSTOM' and $EF77 'MAP TYPE'; the option part is filled into the template at $0636 ' MENUS XXXX DAMAGE XXX.' by appendOnOffWord with bits 3 and 4 of gameTypeOptions) and registers it as the persistent message $1E (setPersistentMessage). Called when a game starts or resumes with CUSTOM rules ($7D4B, $856D).",
   "inputs": "D_0BA3 bits 3, 4, 7; templates at $0636 and $064D; strings $CC19, $EF77",
   "outputs": "$0332.. text, $0636 template overwritten, message slot $1E = $0332, D_92A1 = $1E, message queued",
   "confidence": "high"
  },
  {
   "addr": "8722",
   "name": "setPersistentMessage",
   "summary": "Registers the string A/Y as message slot $1E (sub_C924 writes the pointer tables at $0500/$0524), makes $1E the persistent status message (D_92A1) and queues it with sub_C566. Used for 'PRESS BUTTON WHEN READY.' and the custom summary; the entry at $8722 is also the tail of showCustomSummaryMessage.",
   "inputs": "A/Y = string pointer",
   "outputs": "D_0500[$1E]/D_0524[$1E], D_92A1 = $1E, message queued, X = $1E",
   "confidence": "high"
  },
  {
   "addr": "872E",
   "name": "appendOnOffWord",
   "summary": "Writes 'OFF,' (A = 0) or 'ON, ' (A != 0) into the template at $0636 starting at index X: copies the bit-7 terminated word from $064D (OFF) or $0650 (ON), adds a comma, and for ON adds a trailing space so both forms are 4 characters; returns X pointing at the comma.",
   "inputs": "A = option state (0 = off), X = destination index in $0636",
   "outputs": "$0636+X.. written, X = index of the comma",
   "confidence": "high"
  },
  {
   "addr": "8756",
   "name": "showScenarioBannerAndWaitForButton",
   "summary": "Clears the info panel (row 15) and prints, centred in 13 columns, 'STANDARD' or 'CUSTOM' (table $CC11, chosen by D_0BA3 bit 6), the game type name (table $CCC8, bits 0-2) and the string '  SCENARIO' ($CC04). Sets 'PRESS BUTTON WHEN READY.' ($CBBE) as persistent message $1E, then loops on serviceCommandExchange until checkFirePressed reports a click, and finally clears the status line (sub_C39F).",
   "inputs": "D_0BA3, fire button, link",
   "outputs": "info panel text, D_92A1 = $1E, status line cleared",
   "confidence": "high"
  },
  {
   "addr": "8795",
   "name": "printCentredTableEntry",
   "summary": "Sets textCentreWidth (D_90EF) to 13 and prints entry X of a table of 8-byte bit-7 terminated strings at A/Y through sub_C100 (used for the STANDARD/CUSTOM words and the game type names).",
   "inputs": "A/Y = table base, X = entry index",
   "outputs": "text printed, D_90EF = $0D",
   "confidence": "high"
  }
 ],
 "variables": [
  {
   "addr": "844F",
   "scope": "abs",
   "name": "editValue",
   "meaning": "value being edited by editValueWithJoystick (initialised by beginValueEdit from X, read back by the option editors)",
   "confidence": "high"
  },
  {
   "addr": "8450",
   "scope": "abs",
   "name": "customSetupChosen",
   "meaning": "nonzero while custom options are being set at game start: first D_0BA3 & $40, then the STANDARD(0)/CUSTOM(1) menu choice; sub_8378 only offers the recycler mode menu when it is set",
   "confidence": "high"
  },
  {
   "addr": "87FF",
   "scope": "abs",
   "name": "overlayVariantFlag",
   "meaning": "last byte of the $6F00 overlay: $00 in variant A, $FF in variant B; bit 7 is tested by the main program ($1036, $1080) to decide whether variant B must be (re)loaded",
   "confidence": "high"
  },
  {
   "addr": "92F3",
   "scope": "abs",
   "name": "setupToggleFlag",
   "meaning": "bit 7 = state of the '*' key toggle handled by handleStarKeyToggle: CUSTOM rules on the scenario setup screen (mirrors D_0BA3 bit 6 << 1), DESTROY mode during unit placement (clicking an own unit sends $91 and clears it)",
   "confidence": "high"
  },
  {
   "addr": "0BA3",
   "scope": "abs",
   "name": "gameTypeOptions",
   "meaning": "bits 0-2 game type (0 SCRIMAGE .. 6 DEFENDER, names at $CCC8), bit 3 UNIT MENUS, bit 4 DAMAGE (both edited by editOptionBitOnOff), bit 6 CUSTOM rules, bit 7 custom MAP (adds 'MAP,' to the custom summary)",
   "confidence": "medium"
  },
  {
   "addr": "0B9F",
   "scope": "abs",
   "name": "playerSide",
   "meaning": "local side 0/1; EOR 1 = opponent (index into the per-side tables $92A6/$92AC)",
   "confidence": "high"
  },
  {
   "addr": "0BA5",
   "scope": "abs",
   "name": "commBuildFlag",
   "meaning": "bit 7 = comm build 1 (T35, solo trainer) resident: sub_8378 then forces recycler mode NONE for both sides",
   "confidence": "medium"
  },
  {
   "addr": "92A1",
   "scope": "abs",
   "name": "persistentMessageId",
   "meaning": "id of the status-line message that stays/returns after transient messages (0 none, $0A 'SETUP UNITS...', $1E the dynamic slot used by this code)",
   "confidence": "high"
  },
  {
   "addr": "92A6",
   "scope": "abs",
   "name": "recyclerModeBySide",
   "meaning": "2 bytes: recycler setting per side, 0 FULL, 1 HALF, 2 NONE (words at $0652); chosen in sub_8378 and sent with command $9C",
   "confidence": "high"
  },
  {
   "addr": "92AC",
   "scope": "abs",
   "name": "terrainPointsBySide",
   "meaning": "2 bytes: 'TERRAIN PTS' (0..2) per side, edited by editTerrainPoints for the opponent index and sent as $A5 kind 1",
   "confidence": "medium"
  },
  {
   "addr": "92AE",
   "scope": "abs",
   "name": "dronesLeft",
   "meaning": "2 bytes (own, opponent): number of drones, 'DRONES' custom option 0..9, sent as the x byte of command $90 during setup",
   "confidence": "high"
  },
  {
   "addr": "92B0",
   "scope": "abs",
   "name": "missilesLeft",
   "meaning": "2 bytes: number of missiles, 'MISSILES' custom option 0..36, sent as the y byte of command $90 during setup",
   "confidence": "high"
  },
  {
   "addr": "92B4",
   "scope": "abs",
   "name": "comcenSpeedSetting",
   "meaning": "2 bytes per side: 'COMCEN SPEED' option 0..3 at setup time (sent as $A5 kind 3), later replaced by the speed class looked up at $7B6E",
   "confidence": "medium"
  },
  {
   "addr": "91D4",
   "scope": "abs",
   "name": "menuItemCount",
   "meaning": "number of rows of the current menu (2 for OFF/ON and STANDARD/CUSTOM, 3 for the recycler mode menu)",
   "confidence": "high"
  },
  {
   "addr": "91D5",
   "scope": "abs",
   "name": "menuSelectedItem",
   "meaning": "highlighted/chosen menu row; the value editors keep it at 0 (single row)",
   "confidence": "high"
  },
  {
   "addr": "91D6",
   "scope": "abs",
   "name": "menuFirstRow",
   "meaning": "screen row of menu row 0 (the value editors use the row below the label)",
   "confidence": "high"
  },
  {
   "addr": "91D8",
   "scope": "abs",
   "name": "pickedCellX",
   "meaning": "map column returned by runTargetCursorLoop in free-pick mode (recycler location)",
   "confidence": "high"
  },
  {
   "addr": "91D9",
   "scope": "abs",
   "name": "pickedCellY",
   "meaning": "map row returned by runTargetCursorLoop in free-pick mode",
   "confidence": "high"
  },
  {
   "addr": "92C5",
   "scope": "abs",
   "name": "menuBlinkState",
   "meaning": "0 while the menu row is drawn highlighted, 1 normal; editValueWithJoystick sets 1 before redrawing the value",
   "confidence": "high"
  },
  {
   "addr": "9248",
   "scope": "abs",
   "name": "lastKeyCode",
   "meaning": "last typed key with bit 7 set ($AA = '*'), $FF = none; consumed by handleStarKeyToggle",
   "confidence": "high"
  },
  {
   "addr": "929C",
   "scope": "abs",
   "name": "chatState",
   "meaning": "bit 7 set = chat text entry in progress; handleStarKeyToggle ignores keys then",
   "confidence": "medium"
  },
  {
   "addr": "9251",
   "scope": "abs",
   "name": "messageQueueHead",
   "meaning": "message queue index; showToggleStateMessage copies it to the tail to flush the queue",
   "confidence": "medium"
  },
  {
   "addr": "9252",
   "scope": "abs",
   "name": "messageQueueTail",
   "meaning": "message queue index (8-entry queue at $9249)",
   "confidence": "medium"
  },
  {
   "addr": "9242",
   "scope": "abs",
   "name": "unitDrawOverride",
   "meaning": "set to $FE by sub_8364 together with selectedUnit while the viewport is hidden",
   "confidence": "low"
  },
  {
   "addr": "90F8",
   "scope": "abs",
   "name": "selectedUnit",
   "meaning": "unit the menus act on; $FE = plain menu without a unit (set by beginValueEdit and sub_8364)",
   "confidence": "high"
  },
  {
   "addr": "90FB",
   "scope": "abs",
   "name": "currentScreen",
   "meaning": "0 = battlefield screen; sub_8364 forces it to 0",
   "confidence": "high"
  },
  {
   "addr": "90EF",
   "scope": "abs",
   "name": "textCentreWidth",
   "meaning": "nonzero = the next string is centred in this many columns (13 for the banner words, zp_3C via sub_C121)",
   "confidence": "high"
  },
  {
   "addr": "9022",
   "scope": "abs",
   "name": "spriteEnableShadow",
   "meaning": "shadow of $D015; cleared after the recycler has been located",
   "confidence": "high"
  },
  {
   "addr": "FA70",
   "scope": "abs",
   "name": "unitUnderCellAlias",
   "meaning": "terrain under a unit indexed by the raw map byte ($80|unit); sub_8378 uses it so a cell occupied by a unit counts as its underlying terrain when checking for a plain ($40) recycler site",
   "confidence": "high"
  },
  {
   "addr": "0332",
   "scope": "abs",
   "name": "customSummaryText",
   "meaning": "text buffer (in the $0200 setup block area) that receives 'CUSTOM:[MAP,] MENUS xxx, DAMAGE xxx.' built by showCustomSummaryMessage; registered as message slot $1E",
   "confidence": "high"
  },
  {
   "addr": "0636",
   "scope": "abs",
   "name": "optionSummaryTemplate",
   "meaning": "23-byte template ' MENUS XXXX DAMAGE XXX.' (bit-7 terminated) whose XXXX/XXX fields are filled with OFF,/ON, by appendOnOffWord",
   "confidence": "high"
  },
  {
   "addr": "064D",
   "scope": "abs",
   "name": "wordOff",
   "meaning": "'OFF' (bit-7 terminated), followed by 'ON' at $0650 and the option words FULL/HALF/NONE at $0652",
   "confidence": "high"
  },
  {
   "addr": "0650",
   "scope": "abs",
   "name": "wordOn",
   "meaning": "'ON' (bit-7 terminated); 3 bytes from here (O, N|$80, F) are copied over the OFF in the CUSTOM/DESTROY message",
   "confidence": "high"
  },
  {
   "addr": "0500",
   "scope": "abs",
   "name": "messagePtrLo",
   "meaning": "low bytes of the status message pointer table indexed by message id (high bytes at $0524); slot $1E is rewritten at run time by sub_C924 from this overlay",
   "confidence": "high"
  },
  {
   "addr": "EFDF",
   "scope": "abs",
   "name": "customOnOffWord",
   "meaning": "the 'OFF' inside 'CUSTOM OFF' ($EFD8, T34 $EC00 sub-overlay), overwritten with ON/OFF by showToggleStateMessage while the setup screen uses it",
   "confidence": "high"
  },
  {
   "addr": "EFEA",
   "scope": "abs",
   "name": "destroyOnOffWord",
   "meaning": "the 'OFF' inside 'DESTROY OFF' ($EFE2), overwritten with ON/OFF by showToggleStateMessage during unit placement",
   "confidence": "high"
  },
  {
   "addr": "3B",
   "scope": "zp",
   "name": "textWindowLeft",
   "meaning": "text window left column (28 for the OFF/ON and STANDARD/CUSTOM menus, 29 for the value editors, 30 for the recycler menu; decremented once more before the menu loop)",
   "confidence": "high"
  },
  {
   "addr": "3C",
   "scope": "zp",
   "name": "textWindowWidth",
   "meaning": "text window width = width of the menu highlight bar (5 value editor / OFF-ON, 10 STANDARD/CUSTOM, 6 recycler) and centring width for sub_C121",
   "confidence": "high"
  },
  {
   "addr": "3D",
   "scope": "zp",
   "name": "textColour",
   "meaning": "text colour byte (8 for all panels drawn by this code)",
   "confidence": "high"
  },
  {
   "addr": "3F",
   "scope": "zp",
   "name": "textCursorCol",
   "meaning": "text cursor column relative to the window (1 for the value)",
   "confidence": "high"
  },
  {
   "addr": "40",
   "scope": "zp",
   "name": "textCursorRow",
   "meaning": "text cursor row; copied into menuFirstRow",
   "confidence": "high"
  },
  {
   "addr": "42",
   "scope": "zp",
   "name": "textPadColour",
   "meaning": "colour of centring padding, kept equal to textColour (8)",
   "confidence": "high"
  },
  {
   "addr": "48",
   "scope": "zp",
   "name": "wordPtr",
   "meaning": "in this chunk: pointer (lo) to the ON/OFF word copied by showToggleStateMessage (general fill/map pointer elsewhere)",
   "confidence": "high"
  },
  {
   "addr": "49",
   "scope": "zp",
   "name": "wordPtrHi",
   "meaning": "high byte of wordPtr",
   "confidence": "high"
  },
  {
   "addr": "5D",
   "scope": "zp",
   "name": "joyDirection",
   "meaning": "joystick direction bits, active low, $0F centred; the value editor ORs with $0C and maps up/down to +1/-1",
   "confidence": "high"
  },
  {
   "addr": "6C",
   "scope": "zp",
   "name": "joyRepeatTimer",
   "meaning": "frame countdown gating joystick auto-repeat in the value editor",
   "confidence": "high"
  },
  {
   "addr": "6E",
   "scope": "zp",
   "name": "menuBlinkTimer",
   "meaning": "frame countdown; when 0 the value editor toggles the row highlight",
   "confidence": "high"
  },
  {
   "addr": "72",
   "scope": "zp",
   "name": "messageTimer",
   "meaning": "status message countdown, cleared by showToggleStateMessage so the new message appears at once",
   "confidence": "medium"
  },
  {
   "addr": "73",
   "scope": "zp",
   "name": "cmdParam0",
   "meaning": "first parameter of an outgoing command (recycler mode for $9C)",
   "confidence": "high"
  },
  {
   "addr": "74",
   "scope": "zp",
   "name": "cmdParam1",
   "meaning": "second command parameter (option kind for $A5, drones for $90, x for $9C)",
   "confidence": "high"
  },
  {
   "addr": "75",
   "scope": "zp",
   "name": "cmdParam2",
   "meaning": "third command parameter (option value for $A5, missiles for $90, y for $9C)",
   "confidence": "high"
  },
  {
   "addr": "A5",
   "scope": "zp",
   "name": "viewOriginCol",
   "meaning": "map column of the viewport's left edge; sub_8364 parks it at 45 (off the map) to blank the viewport",
   "confidence": "high"
  },
  {
   "addr": "A6",
   "scope": "zp",
   "name": "viewOriginRow",
   "meaning": "map row of the viewport's top edge; 45 = viewport blanked",
   "confidence": "high"
  },
  {
   "addr": "B1",
   "scope": "zp",
   "name": "gamePhase",
   "meaning": "0 battle; $7F during the game-start option dialogs (runGameStartOptions), $3F/$FF during unit placement where handleStarKeyToggle is polled",
   "confidence": "high"
  },
  {
   "addr": "BB",
   "scope": "zp",
   "name": "cursorTargetMode",
   "meaning": "$FF = free cell pick for runTargetCursorLoop (recycler location)",
   "confidence": "high"
  },
  {
   "addr": "18",
   "scope": "zp",
   "name": "productLo",
   "meaning": "low byte of the multiply8x8 product (unused here; A already holds it)",
   "confidence": "medium"
  }
 ],
 "dataBlocks": [
  {
   "addr": "844F",
   "length": 1,
   "type": "byteTable",
   "name": "editValue",
   "description": "current value of the joystick value editor"
  },
  {
   "addr": "8450",
   "length": 1,
   "type": "byteTable",
   "name": "customSetupChosen",
   "description": "nonzero = CUSTOM options chosen at game start"
  },
  {
   "addr": "879F",
   "length": 13,
   "type": "text",
   "name": "msgWonOnPointsTail",
   "description": "'ON ON POINTS!' - the tail of message $12 'WE WON ON POINTS!' whose first four bytes ($879B-$879E) are overlaid by code in variant A (pla / jmp sub_C100); overlay variant B holds the complete string at $879B. Message pointer table slots $11-$16 ($0500/$0524) point to $8789, $879B, $87AC, $87BA, $87CE, $87E3 and are only valid with variant B resident."
  },
  {
   "addr": "87AC",
   "length": 14,
   "type": "text",
   "name": "msgItWasADraw",
   "description": "'IT WAS A DRAW.' = message $13 (game result)"
  },
  {
   "addr": "87BA",
   "length": 20,
   "type": "text",
   "name": "msgWeWereKnockedOut",
   "description": "'WE WERE KNOCKED OUT!' = message $14"
  },
  {
   "addr": "87CE",
   "length": 21,
   "type": "text",
   "name": "msgWeWonByKnockout",
   "description": "'WE WON BY A KNOCKOUT!' = message $15. Comm build 1 (T35, solo trainer) reuses $87CE+unit as a per-unit work table ($EB29/$EB53 store the game clock there), so with the trainer resident these strings are clobbered."
  },
  {
   "addr": "87E3",
   "length": 10,
   "type": "text",
   "name": "msgGameOver",
   "description": "'GAME OVER.' = message $16"
  },
  {
   "addr": "87ED",
   "length": 12,
   "type": "text",
   "name": "msgDroneAlert",
   "description": "'DRONE ALERT!' - installed as message slot $20 by overlay A at $7BA6 (sub_C924 X=$20)"
  },
  {
   "addr": "87F9",
   "length": 6,
   "type": "unknown",
   "name": "overlayTailPadding",
   "description": "six zero bytes of padding before the variant flag"
  },
  {
   "addr": "87FF",
   "length": 1,
   "type": "byteTable",
   "name": "overlayVariantFlag",
   "description": "$00 = variant A, $FF = variant B (bit 7 tested by the main program at $1036/$1080)"
  }
 ],
 "misclassified": [],
 "insights": [
  "Chunk location: the task quoted file lines 2896-3677 but in disassembly/game/ovl_6F00_A.s the address range $844F-$87FF is at lines 3198-3676 (lines 2896-3197 hold $820B-$844E); this survey covers the address range.",
  "This chunk is the custom-scenario option dialog of overlay A, run once per new game from $7AF7 (runGameStartOptions). Dialog order: banner 'STANDARD/CUSTOM <game type> SCENARIO' + 'PRESS BUTTON WHEN READY.'; if CUSTOM rules are on: STANDARD/CUSTOM menu, then COMCEN SPEED (0-3), TERRAIN PTS (0-2), DRONES (0-9) and MISSILES (0-36); for game types 4-6 the recycler (mode FULL/HALF/NONE only in custom mode, then 'LOCATING RECYCLER' free cell pick on a plain cell, command $9C mode x y); finally the handicap (default 2 = 20 points for side 0 in QB SNEAK, 20 = 200 points for side 1 in DEFENDER, or custom 0-500 step 10) as command $A5 kind 0. The values reach both machines only through the lock-step commands $A5 kind/value, $90 drones/missiles and $9C.",
  "Value editor pattern: beginValueEdit(A/Y label, X start) + editValueWithJoystick(A limit, Y display multiplier) -> D_844F. The editor is a one-row 'menu' (width 5 at column 29) so it reuses the menu highlight/blink code (sub_60E5/sub_60EA, D_92C5, zp_6E). The display multiplies with multiply8x8 ($FCCD), which returns A = product low byte and Y = high byte (the game_high_FBB8 survey's description 'A = Y = high byte' is inverted) and prints via sub_C17D(A=lo, Y=hi).",
  "The '*' key toggle (handleStarKeyToggle, $8658) is the overlay-A hook behind the main program's trampoline sub_25C4 and the runMenuLoop call at $6002. D_92F3 bit 7 is reused for two meanings: CUSTOM rules on the scenario setup screen ($821F initialises it from D_0BA3 bit 6 and message text 'CUSTOM OFF' $EFD8) and DESTROY mode during unit placement (setDestroyModeMessage $86AA selects 'DESTROY OFF' $EFE2; with the flag set a click on an own unit sends $91 self destruct at $209F). The ON/OFF word is patched directly into the string in the T34 $EC00 sub-overlay ($EFDF / $EFEA) using the words at $064D/$0650, and the message is always slot $1E, which is a run-time slot (pointer $FFFF on disk) rewritten with sub_C924; persistentMessageId D_92A1 decides what the status line falls back to.",
  "Message slot $1E is the overlay's scratch message: 'PRESS BUTTON WHEN READY.' ($CBBE), the 'CUSTOM:MAP, MENUS ON,  DAMAGE OFF.' summary built at $0332 from the template at $0636, 'CUSTOM ON/OFF' or 'DESTROY ON/OFF'. Slot $20 is set to 'DRONE ALERT!' ($87ED) at $7BA6.",
  "gameTypeOptions D_0BA3 bit map as used here: bits 0-2 game type, bit 3 UNIT MENUS (editOptionBitOnOff with label $EF9B), bit 4 DAMAGE (label $EFA7), bit 6 CUSTOM rules (banner word, D_8450, D_92F3), bit 7 custom MAP (adds 'MAP,' to the summary; corresponds to the $A6 custom map seed command / D_0B9D).",
  "Labels sub_84F1, sub_8518, sub_8601, sub_862D and sub_8632 are entry points of overlay variant B only (the main program's JSR $8518 at $1460/$14D3 and JSR $8632 at $176B target variant B code); in variant A they fall in the middle of editTerrainPoints, editDronesAndMissiles, beginValueEdit and editOptionBitOnOff. Likewise the XREF callers 83A1/83DE listed for $84B2/$84F1 are variant-B call sites.",
  "The game-result strings at $879B-$87EC (message ids $11-$16 via the pointer table at $0500/$0524) and the variant flag $87FF are the shared tail of both overlay variants; variant A's code runs through $879E, so message $11 ($8789) and the first four bytes of message $12 are code in A. They are only displayed during battle when variant B is resident, so no visible corruption results. The $0332 buffer used for the custom summary lives in the $0200-$03FF setup block area and is not referenced by anything else (XREF)."
 ]
}