{ "chunk": "game_main_0800_163A", "unit": "game/main_0800", "routines": [ { "addr": "1643", "name": "drawMenuTabBar", "summary": "Draws the header of the in-game STATS / REPAIR / MISC screen (screen id 3): full-screen text window, prints 'STATS' (colour $CD), 'REPAIR' ($C6) and 'MISC' ($C2) on row 3 from column 10, then colours the three tab boxes with setTabNormalColour for X=2..0 and tail-calls sub_2A56 (frame/shape draw). Called once from sub_153B when the menu screen is entered.", "inputs": "none", "outputs": "screen updated; zp_21 used as loop counter; zp_39-zp_40, zp_3D, zp_3F clobbered", "confidence": "high" }, { "addr": "168C", "name": "setTabHighlightColour", "summary": "Colours tab X with its bright colour from tabHighlightColourTable (falls into setTabNormalColour if the entry is 0). Used by the tab-bar loop when a tab becomes selected and by blinkSelectedTab.", "inputs": "X = tab index 0..2", "outputs": "fills a 2x2 colour rectangle at row 1, column tabColumnTable[X] via sub_2A64 after drawing the tab shape ($9804) with sub_2B18; self-modifies L_16AC/L_16AE operands", "confidence": "high" }, { "addr": "1691", "name": "setTabNormalColour", "summary": "Colours tab X with its normal colour from tabColourTable: sets D_2A2D=1 (row) and D_2A2E=tabColumnTable[X] (column), draws the tab shape at $9804 with sub_2B18 and fills 2x2 colour cells with sub_2A64.", "inputs": "X = tab index 0..2", "outputs": "screen colour RAM updated; D_2A2D/D_2A2E set", "confidence": "high" }, { "addr": "16B7", "name": "blinkSelectedTab", "summary": "Called every pass of the menu-screen main loop (L_1439). When countdown zp_6E reaches 0 it reloads it with 10 and toggles blinkPhase (D_1889), recolouring the selected tab (D_90F9) bright or normal so it blinks.", "inputs": "zp_6E countdown, D_90F9 selected tab, D_1889", "outputs": "zp_6E=10, D_1889 toggled, tab recoloured", "confidence": "high" }, { "addr": "16D6", "name": "printEnergyLabel", "summary": "Prints the string 'ENERGY' ($CBB8) at column $1C, row 8 of the REPAIR tab using the menu text colour.", "inputs": "none", "outputs": "zp_3D, zp_3F, zp_40 set; text printed", "confidence": "high" }, { "addr": "16EB", "name": "setMenuTextColour", "summary": "Sets the text colour byte zp_3D for the menu screen: $61 normally, $21 when the REPAIR tab (D_90F9==1) is shown and the comcen is stunned (D_922A bit 7).", "inputs": "D_922A, D_90F9", "outputs": "zp_3D", "confidence": "high" }, { "addr": "16FF", "name": "printEnergyValue", "summary": "Prints the comcen energy as a percentage at column $22 row 9: reads unitEnergyTable[comcenUnit] & $3F, doubles it (0..100), right-aligns with leading spaces and prints it with sub_C17D only if it changed since lastEnergyShown. Then classifies it into comcenSystemStatus[0]: 0 when 100%, $40 when >= 21%, $80 (critical) below.", "inputs": "D_9236 comcen unit index, D_F9C4 energy table, D_16FE", "outputs": "D_16FE updated, D_9241 (energy status) updated, text printed; saves/restores the text window (sub_C41B/sub_C40E)", "confidence": "high" }, { "addr": "175A", "name": "drawRepairTab", "summary": "Draws the REPAIR tab contents: background colour $66 (or $22 when stunned), clears the window, draws the comcen schematic (sub_8632 in overlay B), paints a 20x10 colour block at row 10 column 13, resets the blink state and energy snapshot, then draws the four system status markers (unless stunned), prints the ENERGY label/value and, when stunned, 'COMCEN STUNNED!' at column 5. Remembers the stun flag in D_1413 so the main loop can redraw on change.", "inputs": "D_922A stun status, D_9236, D_F9C4", "outputs": "D_1413, zp_6E=0, D_188A=0, D_1889, D_16FE=$FF, D_17D8 energy snapshot, D_91D5 (=4 when markers drawn), screen updated", "confidence": "high" }, { "addr": "17DA", "name": "repairTabAction", "summary": "Fire-button action of the REPAIR tab (entered through the address table D_1535, index 1; the disassembly shows it as data). Only works when the DAMAGE option ($0BA3 bit 4) is on, not in film playback ($0B9B bit 7) and a game is running ($0BA8==0). If the comcen is stunned it prints 'ATTEMPTING REPAIR...', plays sound $18, waits 200 frames and, with a 1-in-8 chance while the stun counter is below 8, queues command byte $9E and plays sound $13 (else $12). Otherwise (L_1823) it queues a 3-byte command $80,unit,x,y for the comcen if its flag byte allows, blanks the markers, shows the 'REPAIR WHICH:' selection screen (sub_652E, also mis-typed as data), redraws the markers and snapshots the statuses (sub_14F0).", "inputs": "D_0BA3, D_0B9B, D_0BA8, D_922A, D_9236, D_FB54, D_F640/D_F6A4", "outputs": "command bytes queued via sub_55EC/sub_560A, sounds, screen; D_1889, D_188A, D_1412 loop counter, zp_73-zp_75", "confidence": "medium" }, { "addr": "188B", "name": "toggleSystemMarker", "summary": "Blink helper used by the repair selection menu (called from $6108 and blinkRepairMarker): toggles blinkPhase and either draws the status marker of system D_91D5 (drawSystemMarker) or erases it (eraseSystemMarker with colour $16).", "inputs": "D_91D5 selected system 0..3, D_1889", "outputs": "D_1889 toggled; marker drawn/erased", "confidence": "high" }, { "addr": "189D", "name": "drawSystemMarker", "summary": "Draws the status marker of comcen system Y on the schematic as a plus-shaped group of five colour cells at column systemMarkerColumnTable[Y], row systemMarkerRowTable[Y]: colour $15 (green) when comcenSystemStatus[Y]==0, $12 (red) when bit 7 set (damaged), $17 (yellow) when $40. An OK system is erased instead (3x3 of $16) unless showOkMarkers (D_188A) is set. Refreshes the energy reading first.", "inputs": "Y = system index 0..3, D_9241, D_188A", "outputs": "screen colour cells; D_2A2A, D_2A2D, D_2A2E; self-modifies L_18A3", "confidence": "high" }, { "addr": "1919", "name": "eraseSystemMarker", "summary": "Fills the 3x3 colour block of system Y's marker with colour X (normally $16 = blank) via sub_2A64.", "inputs": "Y = system index, X = colour byte", "outputs": "D_2A2D/D_2A2E set, rectangle filled", "confidence": "high" }, { "addr": "192D", "name": "sendEnergyRepairCommand", "summary": "Queues the 3-byte command $9A, comcenUnit, repairAmount (D_17D9) to the opponent/game engine via sub_560F. Shown as data in the disassembly; called from attemptSystemRepair.", "inputs": "D_9236, D_17D9", "outputs": "zp_74, zp_75 set; command queued", "confidence": "medium" }, { "addr": "193C", "name": "attemptSystemRepair", "summary": "Called from the 'REPAIR WHICH:' menu code at $6590 (also mis-typed as data) with the chosen system in D_91D5. Prints 'ATTEMPTING REPAIR...', sound $18, then succeeds when (random & 3)==0 ((random & 1) for the energy system) and the system is damaged: energy gets (50-energy)/8+1 added (capped at 50) through sendEnergyRepairCommand, other systems have comcenSystemStatus[Y] cleared; plays sound $13 on success, $12 on failure, blinking the marker for about 60 ticks each time. Finally resets the energy snapshot, zp_6E, blinkPhase and clears the message line.", "inputs": "D_91D5, D_9241, D_17D8, RNG sub_FD5D", "outputs": "D_17D8, D_17D9, D_9241[Y], zp_6E=0, D_1889=0; sounds, command queued", "confidence": "medium" }, { "addr": "19B0", "name": "blinkRepairMarker", "summary": "Blinks the selected system marker: zp_6F = 60 ticks; every 20 frames (sub_4094) calls toggleSystemMarker until zp_6F expires or the game-end flag D_92C9 is set.", "inputs": "D_91D5, D_92C9", "outputs": "zp_6F, marker toggled", "confidence": "high" }, { "addr": "19C9", "name": "printAttemptingRepair", "summary": "Sets the repair message window and prints 'ATTEMPTING REPAIR...' ($CBE5), then restores the previous text window (sub_C40E).", "inputs": "none", "outputs": "text printed", "confidence": "high" }, { "addr": "19D6", "name": "clearRepairMessage", "summary": "Sets the repair message window and prints 20 spaces (the runtime routine at $C0EF prints A copies of the fill character; the label bootReceiveSectorData is stale), then restores the window.", "inputs": "none", "outputs": "message line cleared", "confidence": "high" }, { "addr": "19E1", "name": "setRepairMessageWindow", "summary": "Saves the current text window (sub_C41B), sets the menu text colour, the stats window geometry (sub_1578: left 2, rows 7..$16, width $24) and positions the cursor at column 10, row 20.", "inputs": "none", "outputs": "zp_39-zp_40, zp_3D set, window saved at $92B6", "confidence": "high" }, { "addr": "19F3", "name": "printOptionsList", "summary": "Prints the MISC tab: window at column 6 rows 9..$1D, colour $61, ' OPTIONS'. While a game is running ($0BA8==0 and D_92C9==0) it lists 'ABORT GAME', 'VOICE PAUSE' (only when not in film playback and the modem build flag $0BA5 is clear) and ' (EXIT)'. Otherwise it lists the main menu: COMPETE WITH MODEM OPPONENT / PRACTICE WITH SOLO TRAINER / WATCH GAME FILM / SAVE GAME FILM / LOAD GAME FILM and, when the comm link is active (D_E03B), DISCONNECT/SET VOICE.", "inputs": "D_0BA8, D_92C9, D_0B9B, D_0BA5, D_E03B", "outputs": "text printed; zp_39-zp_3F set", "confidence": "high" }, { "addr": "1A49", "name": "miscTabAction", "summary": "Fire-button action of the MISC tab (D_1535 entry 2). With a game running it runs the options menu (sub_65A0 with 2 or 3 items); item 0 ABORT GAME sends command $8C (reason 0) to a connected opponent, waits up to $26 ticks for the transmitter, hangs up (hangUpModem) and redisplays the status message. Then, and whenever no game is running, it loops: clear window, restoreSettingsAfterFilm, printOptionsList, runMainMenu.", "inputs": "D_92C9, D_0BA8, D_0B9B, D_0BA5, D_E03B, D_0B9C, D_E030, D_92A1", "outputs": "D_91D4/D_91D5/D_91D6 menu state, D_92A1, zp_73, D_9163, zp_7F; may end the game via endGameToMainMenu", "confidence": "medium" }, { "addr": "1ADC", "name": "endGameToMainMenu", "summary": "Resets game-session state when a game ends (also jumped to from sub_C86D when D_92C9 is negative): clears D_92C9, zp_BE, the outgoing command ring indices $908D/$908E and D_92FD; reloads the runtime overlays unless D_67C8 is $0D/$0E; for comm build 1 (D_E030 bit 7) clears the link flag and makes PRACTICE the default item; marks no game in progress ($0BA8=1); when not in setup/film mode calls sub_57F2 and makes WATCH GAME FILM the default; finally sets commSessionState $0B9C to $80 if the link is active (flushing it with sub_56F1 if needed) or 0.", "inputs": "D_67C8, D_E030, D_E03B, zp_B1, D_0B9B, D_0B9C", "outputs": "D_92C9=0, zp_BE=0, D_908D/D_908E=0, D_92FD, D_0BA8, D_0B9C, D_E03B", "confidence": "medium" }, { "addr": "1B33", "name": "hangUpModem", "summary": "Entry that hangs up with a resulting commSessionState of 0 (falls into hangUpModemSetState with A=0).", "inputs": "none", "outputs": "see hangUpModemSetState", "confidence": "high" }, { "addr": "1B35", "name": "hangUpModemSetState", "summary": "If the link is active and this is the modem build (D_E030 bit 7 clear) shows message $18 'PRESS SPACE, WAIT, HANGUP PHONE.' and waits for space, then waits up to $26 ticks for D_E03C bit 7 to clear; calls the comm module sub_E003 with X=3 (link down) and stores A into $0B9C.", "inputs": "A = new value for D_0B9C, D_E03B, D_E030, D_E03C", "outputs": "D_0B9C, comm flags cleared by sub_E003, zp_7F; self-modifies L_1B59", "confidence": "high" }, { "addr": "1B5F", "name": "openCommLink", "summary": "If no link is active: on the modem build ($0BA5 bit 7 clear) shows message $17 'PICK UP PHONE THEN PRESS SPACE.' and waits for space, then calls sub_E003 with X=0 which sets the comm flags D_E03B/D_E03C/D_E03D to $FF.", "inputs": "D_E03B, D_0BA5", "outputs": "comm link flags set", "confidence": "high" }, { "addr": "1B74", "name": "openLinkAndWaitForConnection", "summary": "openCommLink followed by waitForConnection.", "inputs": "none", "outputs": "see callees", "confidence": "high" }, { "addr": "1B77", "name": "waitForConnection", "summary": "On the modem build: shows persistent message $10 'WAITING FOR CONNECTION...', runs waitForCarrier (zp_18 preset to $FF), clears bit 7 of zp_BE, clears the message and restores the status area (sub_C39F).", "inputs": "D_0BA5", "outputs": "D_92A1, zp_18, zp_BE", "confidence": "high" }, { "addr": "1B9A", "name": "waitForCarrier", "summary": "Polling loop: services the message/status system (sub_C4EF), handles comm status code zp_B1==$FF via sub_5A14, waits 2 frames and decrements zp_18 while D_E03D bit 6 is clear (held at 1 instead of wrapping), until D_E03C bit 6 (connected) is set; then silences sound (sub_C89A 0). The stray $60 at $1BC0 is an unreachable RTS.", "inputs": "zp_B1, D_E03C, D_E03D, zp_18", "outputs": "zp_18, sound off", "confidence": "medium" }, { "addr": "1BC1", "name": "showMessageWaitForSpace", "summary": "Shows status message A (stored in D_92A1 as the persistent message), clears D_9277/D_929C/D_0B7D, then loops servicing sub_C4EF and stirring the RNG until lastKeyPressed (D_9248) == $A0 (space); clears the message (sub_C6EF), sets D_0B7D=$1E and D_9248=$FF.", "inputs": "A = message id", "outputs": "D_92A1, D_9277, D_929C, D_0B7D, D_9248", "confidence": "high" }, { "addr": "1BF7", "name": "voicePauseReconnect", "summary": "Voice pause: hangUpAndPause, then openLinkAndWaitForConnection; stores A in zp_7B and clears bit 7 of D_91D5. Called from the VOICE PAUSE menu item (sub_65A0), sub_5A14 and the $C000 overlay ($C768).", "inputs": "D_0B9C", "outputs": "zp_7B, D_91D5", "confidence": "medium" }, { "addr": "1C08", "name": "hangUpAndPause", "summary": "hangUpModemSetState with A = current $0B9C (or 0 if it is negative), then waits 250 frames (sub_C37F).", "inputs": "D_0B9C", "outputs": "D_0B9C", "confidence": "high" }, { "addr": "1C17", "name": "disconnectFromOpponent", "summary": "If a session is active ($0B9C bit 7): queues command $8C with reason byte 5 (zp_73), flushes the outgoing queue (sub_562B) and hangs up (hangUpModem). Used for DISCONNECT/SET VOICE and before starting a solo practice game.", "inputs": "D_0B9C", "outputs": "zp_73=5, command queued, link closed, D_0B9C=0", "confidence": "medium" }, { "addr": "1C2C", "name": "runMainMenu", "summary": "Runs the main menu drawn by printOptionsList: 5 items (6 = DISCONNECT/SET VOICE when $0B9C bit 7), initial item D_92FD, first row $0B; sets D_90F8 and zp_B1 to $F0, colour $60, and calls the menu selector sub_5FD1. Item 5 -> disconnectFromOpponent and return. Otherwise waits 15 frames, disconnects first for item 1 (PRACTICE WITH SOLO TRAINER), reloads the $6F00 overlay/strings (sub_1030 with $0BA7 bumped) and jumps to L_7DE3 in the overlay to act on the choice.", "inputs": "D_0B9C, D_92FD, zp_3B", "outputs": "D_91D4, D_91D5, D_91D6, D_90F8=$F0, zp_B1=$F0, zp_3D/zp_42=$60, D_0BA7", "confidence": "medium" }, { "addr": "1C7B", "name": "isAsymmetricGameType", "summary": "Tests the game type (D_0BA3 & 7): returns Z=1 when it is 1 (QB SNEAK) or 6 (DEFENDER), the scenarios where '1ST PLAY'/'2ND PLAY' is shown on the STATS tab.", "inputs": "D_0BA3", "outputs": "Z flag, A = type", "confidence": "medium" }, { "addr": "1C87", "name": "restoreSettingsAfterFilm", "summary": "When the film-playback flag $0B9B bit 7 is set: clears it and, if pendingGameType $0BA4 != $FF, copies the pending settings back into the current ones: $0BAF-$0BB4 -> $0BA9-$0BAE, $0B98-$0B9A -> $0B95-$0B97, $0BA2 -> $0BA1, $0B9E -> $0B9D, $0BA4 -> $0BA3.", "inputs": "D_0B9B, D_0BA4, D_0BAF.., D_0B98.., D_0BA2, D_0B9E", "outputs": "D_0B9B=0, D_0BA9.., D_0B95.., D_0BA1, D_0B9D, D_0BA3", "confidence": "medium" }, { "addr": "1CC1", "name": "setViewVerticalLimit", "summary": "Sets zp_F8, the exclusive limit for the view centre row: 40 normally, 20 when zp_B1 (setup/film phase) is nonzero, in which case the incoming row delta Y is also biased by -20 (the caller adds it back).", "inputs": "Y = row delta, zp_B1", "outputs": "zp_F8, Y adjusted", "confidence": "medium" }, { "addr": "1CD3", "name": "scrollViewBy", "summary": "Scrolls the battlefield view by X columns and Y rows (-1/0/+1): keeps the view centre (zp_A5+3, zp_A6+2) and, when a group box is active (D_920A bit 7), the box offsets D_922E-D_9231 inside the 40x40 map; the actually applied deltas go to zp_F0/zp_F1 (0 if clamped), zp_A5/zp_A6 are updated, D_91CC cleared, sub_3049 refreshes the cursor cell, then it continues into scrollViewBitmap.", "inputs": "X = dx, Y = dy, zp_A5, zp_A6, zp_B1, D_920A, D_922E-D_9231", "outputs": "zp_A5, zp_A6, zp_F0, zp_F1, zp_F8, D_91CC=0; screen scrolled", "confidence": "high" }, { "addr": "1D4E", "name": "scrollViewToUnit", "summary": "Scrolls the view step by step along a Bresenham line from the current cursor cell (zp_92 row, zp_93 column) to unit X's position until the unit is centred. A nonzero A animates: each step waits for countdown zp_6E (reloaded with A) while polling input (sub_40B2) and aborts as soon as the joystick leaves centre (zp_5D != $0F). Callers: $25B3 (A=1, selected unit D_90F8) and $485C (A=0).", "inputs": "A = ticks per step (0 = immediate), X = unit index, zp_92/zp_93 current cell", "outputs": "D_1D4C, D_1D4D, zp_6E, zp_92-zp_97, zp_8C-zp_91, zp_A5/zp_A6, screen", "confidence": "high" }, { "addr": "1D97", "name": "setLineTargetToUnit", "summary": "Loads the Bresenham target from the unit position tables: zp_95 = unitXTable[X], zp_94 = unitYTable[X].", "inputs": "X = unit index", "outputs": "zp_94, zp_95", "confidence": "high" }, { "addr": "1DE4", "name": "scrollViewBitmap", "summary": "Shifts the 7x5-cell battlefield view (16x16-pixel cells at screen column 25, row 1: bitmap $A208, screen RAM $8C41, colour RAM +$4C00) by one cell in the direction given by zp_F0/zp_F1 (0/1/2 = -1/0/+1) using two self-modified copy loops parameterised from the tables at $1DA2-$1DE3, then redraws the newly exposed column (5 cells) and/or row (7 cells) from the map with sub_25FA/sub_5D1A. Entered only by jmp from scrollViewBy.", "inputs": "zp_F0, zp_F1, zp_A5, zp_A6", "outputs": "zp_F2-zp_F7, zp_54-zp_56, bitmap/screen/colour RAM; self-modifies L_1E81-L_1EBF and D_1E89/D_1EBE opcodes", "confidence": "high" }, { "addr": "1F4E", "name": "keepGroupBoxInsideMap", "summary": "Nudges the view origin zp_A5/zp_A6 one cell at a time until the group box (centre + D_922E..D_9231 offsets) fits inside the map (width 40, height zp_F8), then redraws the whole view (sub_26C1) if anything moved. Called from $319D after a group box is set up.", "inputs": "zp_A5, zp_A6, D_922E-D_9231, zp_B1", "outputs": "zp_A5, zp_A6, zp_18, zp_19, zp_F8; view redrawn", "confidence": "high" } ], "variables": [ { "addr": "39", "scope": "zp", "name": "textWindowTop", "meaning": "text window first row", "confidence": "high" }, { "addr": "3A", "scope": "zp", "name": "textWindowBottom", "meaning": "text window last row + 1", "confidence": "high" }, { "addr": "3B", "scope": "zp", "name": "textWindowLeft", "meaning": "text window left column", "confidence": "high" }, { "addr": "3C", "scope": "zp", "name": "textWindowWidth", "meaning": "text window width in characters", "confidence": "high" }, { "addr": "3D", "scope": "zp", "name": "textColour", "meaning": "colour byte used for printed text (foreground/background nibbles of the bitmap colour cell)", "confidence": "high" }, { "addr": "3E", "scope": "zp", "name": "textFillChar", "meaning": "character used by the clear/space routines ($C06A, $C0EF)", "confidence": "medium" }, { "addr": "3F", "scope": "zp", "name": "textColumn", "meaning": "text cursor column relative to the window", "confidence": "high" }, { "addr": "40", "scope": "zp", "name": "textRow", "meaning": "text cursor row", "confidence": "high" }, { "addr": "42", "scope": "zp", "name": "textPadColour", "meaning": "colour used for the padding spaces of centred text ($C13F)", "confidence": "medium" }, { "addr": "18", "scope": "zp", "name": "tempByte18", "meaning": "scratch; carrier wait counter in waitForCarrier, moved flag / temp in keepGroupBoxInsideMap", "confidence": "medium" }, { "addr": "19", "scope": "zp", "name": "tempByte19", "meaning": "scratch; 'view moved' flag in keepGroupBoxInsideMap", "confidence": "medium" }, { "addr": "21", "scope": "zp", "name": "loopCounter21", "meaning": "loop counter (tab index loop in drawMenuTabBar)", "confidence": "high" }, { "addr": "54", "scope": "zp", "name": "mapCellValue", "meaning": "map byte of the cell being drawn by sub_5D1A", "confidence": "high" }, { "addr": "55", "scope": "zp", "name": "mapCellX", "meaning": "map column of the cell being drawn", "confidence": "high" }, { "addr": "56", "scope": "zp", "name": "mapCellY", "meaning": "map row of the cell being drawn", "confidence": "high" }, { "addr": "57", "scope": "zp", "name": "rngState0", "meaning": "random number generator state (sub_FD5D), 3 bytes $57-$59", "confidence": "high" }, { "addr": "5D", "scope": "zp", "name": "joystickState", "meaning": "joystick direction bits (active low, $0F = centred; bit 2 left, bit 3 right)", "confidence": "high" }, { "addr": "66", "scope": "zp", "name": "requestedScreenId", "meaning": "screen to switch to (bit 7 = none); compared with currentScreenId by sub_06BA", "confidence": "medium" }, { "addr": "6C", "scope": "zp", "name": "joystickRepeatDelay", "meaning": "countdown during which joystick directions are ignored (set to $14 after a move)", "confidence": "high" }, { "addr": "6E", "scope": "zp", "name": "countdownTimer6E", "meaning": "general frame countdown (tab blink period = 10, per-step delay of scrollViewToUnit)", "confidence": "high" }, { "addr": "6F", "scope": "zp", "name": "countdownTimer6F", "meaning": "frame countdown used for the repair marker blink duration (60)", "confidence": "medium" }, { "addr": "73", "scope": "zp", "name": "cmdParam0", "meaning": "first parameter byte of an outgoing command (unit index or reason code)", "confidence": "high" }, { "addr": "74", "scope": "zp", "name": "cmdParam1", "meaning": "second parameter byte of an outgoing command (unit x / unit index)", "confidence": "high" }, { "addr": "75", "scope": "zp", "name": "cmdParam2", "meaning": "third parameter byte of an outgoing command (unit y / amount)", "confidence": "high" }, { "addr": "7B", "scope": "zp", "name": "currentMessageId", "meaning": "id of the status-line message currently shown (bit 7 = none)", "confidence": "medium" }, { "addr": "7F", "scope": "zp", "name": "timeoutTicks", "meaning": "tick countdown used as timeout while waiting for the comm module ($26 or $4B)", "confidence": "medium" }, { "addr": "8C", "scope": "zp", "name": "lineErrY", "meaning": "Bresenham error accumulator (row axis), sub_FBB8/sub_FBFA", "confidence": "high" }, { "addr": "8D", "scope": "zp", "name": "lineErrX", "meaning": "Bresenham error accumulator (column axis)", "confidence": "high" }, { "addr": "8E", "scope": "zp", "name": "lineLength", "meaning": "Bresenham major-axis length", "confidence": "high" }, { "addr": "8F", "scope": "zp", "name": "lineDeltaY", "meaning": "|target row - current row|", "confidence": "high" }, { "addr": "90", "scope": "zp", "name": "lineDeltaX", "meaning": "|target column - current column|", "confidence": "high" }, { "addr": "91", "scope": "zp", "name": "lineStepsLeft", "meaning": "remaining Bresenham steps", "confidence": "high" }, { "addr": "92", "scope": "zp", "name": "cursorRow", "meaning": "current map row of the view centre / line start (= zp_A6 + 2)", "confidence": "high" }, { "addr": "93", "scope": "zp", "name": "cursorCol", "meaning": "current map column of the view centre / line start (= zp_A5 + 3)", "confidence": "high" }, { "addr": "94", "scope": "zp", "name": "lineTargetRow", "meaning": "Bresenham target row", "confidence": "high" }, { "addr": "95", "scope": "zp", "name": "lineTargetCol", "meaning": "Bresenham target column", "confidence": "high" }, { "addr": "96", "scope": "zp", "name": "lineStepY", "meaning": "row step direction (+1/-1)", "confidence": "high" }, { "addr": "97", "scope": "zp", "name": "lineStepX", "meaning": "column step direction (+1/-1)", "confidence": "high" }, { "addr": "A2", "scope": "zp", "name": "stringPtr", "meaning": "pointer to the bit-7-terminated string being printed by $C133/$C137 (lo), $A3 hi", "confidence": "high" }, { "addr": "A5", "scope": "zp", "name": "viewLeftCol", "meaning": "map column of the left edge of the 7x5 battlefield view", "confidence": "high" }, { "addr": "A6", "scope": "zp", "name": "viewTopRow", "meaning": "map row of the top edge of the battlefield view (biased +20 when zp_B1 is nonzero)", "confidence": "high" }, { "addr": "B1", "scope": "zp", "name": "gamePhase", "meaning": "0 during battle; nonzero ($F0 menu, $FE/$FF) in setup/menu phases where the view is limited to a 20-row half of the map; $FF also triggers special comm handling", "confidence": "low" }, { "addr": "B6", "scope": "zp", "name": "screenPtr", "meaning": "pointer into screen RAM ($8C00 based) computed from row/column tables (lo), $B7 hi", "confidence": "high" }, { "addr": "BE", "scope": "zp", "name": "commPauseFlags", "meaning": "comm/pause related flag byte (bit 7 cleared after connecting, bit 0 toggled by $C70A)", "confidence": "low" }, { "addr": "F0", "scope": "zp", "name": "scrollDeltaX", "meaning": "applied horizontal scroll delta (0/1/2 = -1/0/+1 after the +1 in scrollViewBitmap)", "confidence": "high" }, { "addr": "F1", "scope": "zp", "name": "scrollDeltaY", "meaning": "applied vertical scroll delta (0/1/2 = -1/0/+1)", "confidence": "high" }, { "addr": "F2", "scope": "zp", "name": "bitmapRowStride", "meaning": "signed 16-bit stride added between bitmap rows while scrolling (lo), $F3 hi (+320 or -320)", "confidence": "high" }, { "addr": "F4", "scope": "zp", "name": "screenRowStride", "meaning": "signed 16-bit stride between screen rows while scrolling (lo), $F5 hi (+40/-40)", "confidence": "high" }, { "addr": "F6", "scope": "zp", "name": "scrollRowCount", "meaning": "number of character rows to copy while scrolling (8 or 10)", "confidence": "high" }, { "addr": "F7", "scope": "zp", "name": "redrawCellCount", "meaning": "cells left to redraw after a scroll (5 or 7)", "confidence": "high" }, { "addr": "F8", "scope": "zp", "name": "viewRowLimit", "meaning": "exclusive map-row limit for the view centre (40, or 20 in setup phase)", "confidence": "high" }, { "addr": "0B7D", "scope": "abs", "name": "uiDelayTimer", "meaning": "key/menu delay countdown (set $14 by the menu selector, $1E after a keypress wait)", "confidence": "low" }, { "addr": "0B9B", "scope": "abs", "name": "filmPlaybackFlag", "meaning": "bit 7 set while a game film is being played back (commands are not queued, number keys set the replay speed)", "confidence": "medium" }, { "addr": "0B9C", "scope": "abs", "name": "commSessionState", "meaning": "0 = no session, $80 = linked session, $FF = link lost; also sent to the comm module by sub_56F1", "confidence": "low" }, { "addr": "0BA1", "scope": "abs", "name": "playsFirstFlag", "meaning": "nonzero: this side has '1ST PLAY' in asymmetric scenarios, else '2ND PLAY'", "confidence": "medium" }, { "addr": "0BA2", "scope": "abs", "name": "pendingPlaysFirstFlag", "meaning": "copy of playsFirstFlag restored after film playback", "confidence": "medium" }, { "addr": "0BA3", "scope": "abs", "name": "gameTypeOptions", "meaning": "bits 0-2 game type (0 SCRIMAGE,1 QB SNEAK,2 THE BOMB,3 FACE-OFF,4 SLUGGERS,5 FULL WAR,6 DEFENDER,7 M...), bit 4 DAMAGE option on, bit 6 CUSTOM rules", "confidence": "medium" }, { "addr": "0BA4", "scope": "abs", "name": "pendingGameTypeOptions", "meaning": "pending copy of gameTypeOptions, $FF = none", "confidence": "medium" }, { "addr": "0BA5", "scope": "abs", "name": "commBuildFlag", "meaning": "copy of D_E030; bit 7 set = comm build 1 (T35): no phone pick-up/hang-up prompts, no VOICE PAUSE item", "confidence": "medium" }, { "addr": "0BA7", "scope": "abs", "name": "diskLoadNestCount", "meaning": "incremented around overlay reloads (sub_1030)", "confidence": "low" }, { "addr": "0BA8", "scope": "abs", "name": "noGameInProgress", "meaning": "nonzero when no game is running (menus); 0 during a game", "confidence": "medium" }, { "addr": "0BA9", "scope": "abs", "name": "currentSettingsText", "meaning": "6-byte text field ($A0 padded) of the current game settings, restored from $0BAF after a film", "confidence": "low" }, { "addr": "0BAF", "scope": "abs", "name": "pendingSettingsText", "meaning": "6-byte pending copy of currentSettingsText", "confidence": "low" }, { "addr": "1412", "scope": "abs", "name": "loopCounter1412", "meaning": "loop counter used by repairTabAction (marker loops)", "confidence": "high" }, { "addr": "1413", "scope": "abs", "name": "lastStunFlagShown", "meaning": "copy of D_922A taken when the REPAIR tab was drawn; bit 7 compared to detect stun changes", "confidence": "high" }, { "addr": "1535", "scope": "abs", "name": "tabActionTable", "meaning": "3 JSR addresses for the fire action of tabs 0..2: $158F (STATS), $17DA (REPAIR), $1A49 (MISC)", "confidence": "high" }, { "addr": "2A2A", "scope": "abs", "name": "fillColourValue", "meaning": "colour byte written by the rectangle fill sub_2A64", "confidence": "high" }, { "addr": "2A2D", "scope": "abs", "name": "fillRow", "meaning": "screen row for sub_2A64 / sub_2B18", "confidence": "high" }, { "addr": "2A2E", "scope": "abs", "name": "fillColumn", "meaning": "screen column for sub_2A64 / sub_2B18", "confidence": "high" }, { "addr": "9065", "scope": "abs", "name": "outgoingCmdRing", "meaning": "40-byte ring buffer of outgoing command bytes (sub_55EF)", "confidence": "medium" }, { "addr": "908D", "scope": "abs", "name": "outgoingCmdWriteIdx", "meaning": "write index into outgoingCmdRing", "confidence": "medium" }, { "addr": "908E", "scope": "abs", "name": "outgoingCmdReadIdx", "meaning": "read index into outgoingCmdRing", "confidence": "medium" }, { "addr": "90EF", "scope": "abs", "name": "textCentreWidth", "meaning": "nonzero: next string is centred in this many columns ($C137)", "confidence": "medium" }, { "addr": "90F4", "scope": "abs", "name": "lineLastStepY", "meaning": "row step (-1/0/+1) taken by the last sub_FBFA call", "confidence": "high" }, { "addr": "90F5", "scope": "abs", "name": "lineLastStepX", "meaning": "column step taken by the last sub_FBFA call", "confidence": "high" }, { "addr": "90F8", "scope": "abs", "name": "selectedUnit", "meaning": "index of the currently selected unit ($F0/$FE/$FF = none)", "confidence": "medium" }, { "addr": "90F9", "scope": "abs", "name": "menuTabIndex", "meaning": "selected tab of the in-game menu screen: 0 STATS, 1 REPAIR, 2 MISC", "confidence": "high" }, { "addr": "90FB", "scope": "abs", "name": "currentScreenId", "meaning": "active screen: 0 battlefield, 1 ($7587), 2 ($7FE6), 3 STATS/REPAIR/MISC menu", "confidence": "medium" }, { "addr": "91D4", "scope": "abs", "name": "menuItemCount", "meaning": "number of items for the menu selector sub_5FD1/sub_65A0", "confidence": "high" }, { "addr": "91D5", "scope": "abs", "name": "menuSelectedItem", "meaning": "current/selected menu item (also the repair system index 0..3)", "confidence": "high" }, { "addr": "91D6", "scope": "abs", "name": "menuFirstRow", "meaning": "screen row of the first menu item", "confidence": "high" }, { "addr": "920A", "scope": "abs", "name": "groupBoxActive", "meaning": "bit 7 set while a group/formation box around the cursor is active", "confidence": "medium" }, { "addr": "920E", "scope": "abs", "name": "statsNeedRefresh", "meaning": "nonzero: STATS tab must be redrawn (sub_8518)", "confidence": "low" }, { "addr": "922A", "scope": "abs", "name": "comcenStunStatus", "meaning": "bits 0-3 stun counter of the comcen (from D_F960), bit 7 set = stunned; bit 6 set during the knock-out sequence", "confidence": "medium" }, { "addr": "922E", "scope": "abs", "name": "groupBoxLeftOffset", "meaning": "signed column offset of the group box left edge from the cursor", "confidence": "medium" }, { "addr": "922F", "scope": "abs", "name": "groupBoxRightOffset", "meaning": "signed column offset of the group box right edge", "confidence": "medium" }, { "addr": "9230", "scope": "abs", "name": "groupBoxTopOffset", "meaning": "signed row offset of the group box top edge", "confidence": "medium" }, { "addr": "9231", "scope": "abs", "name": "groupBoxBottomOffset", "meaning": "signed row offset of the group box bottom edge", "confidence": "medium" }, { "addr": "9236", "scope": "abs", "name": "comcenUnit", "meaning": "index of the player's COMCEN unit (indexes the unit tables)", "confidence": "high" }, { "addr": "9241", "scope": "abs", "name": "comcenSystemStatus", "meaning": "4 bytes: status of the comcen energy (0) and three systems (1-3); 0 ok, $40 degraded, $80 damaged", "confidence": "high" }, { "addr": "9248", "scope": "abs", "name": "lastKeyPressed", "meaning": "last key as ASCII | $80 ($A0 = space, $B1-$B9 digits), $FF = none", "confidence": "high" }, { "addr": "92A1", "scope": "abs", "name": "persistentMessageId", "meaning": "id of the status message kept on screen (0 = none)", "confidence": "low" }, { "addr": "92B6", "scope": "abs", "name": "savedTextWindow", "meaning": "12-byte save area for zp_39-zp_44 (sub_C41B/sub_C40E)", "confidence": "high" }, { "addr": "92C9", "scope": "abs", "name": "gameEndFlag", "meaning": "nonzero once the game is over/aborted (bit 7 = return to menu pending); aborts waits", "confidence": "medium" }, { "addr": "92D6", "scope": "abs", "name": "comcenStatusSnapshot", "meaning": "4-byte copy of comcenSystemStatus (energy in [0]) taken when the REPAIR tab was last used; differences auto-select the REPAIR tab", "confidence": "high" }, { "addr": "92FD", "scope": "abs", "name": "defaultMainMenuItem", "meaning": "initial main-menu item (0 COMPETE, 1 PRACTICE, 2 WATCH FILM)", "confidence": "medium" }, { "addr": "E01D", "scope": "abs", "name": "commTxState", "meaning": "comm module transmit state byte (0 = nothing pending; $C0 set by sub_E003 default path)", "confidence": "low" }, { "addr": "E030", "scope": "abs", "name": "commModuleFlags", "meaning": "comm module capability byte, bit 7 set in build 1 (T35) = no modem handshake prompts", "confidence": "medium" }, { "addr": "E03B", "scope": "abs", "name": "commLinkActive", "meaning": "$FF while the link is open (set by sub_E003 X=0, cleared by X>=1)", "confidence": "medium" }, { "addr": "E03C", "scope": "abs", "name": "commLineStatus", "meaning": "bit 6 = connected (carrier), bit 7 = line busy; $FF after link open", "confidence": "low" }, { "addr": "E03D", "scope": "abs", "name": "commStatusFlags2", "meaning": "bit 6 polled while waiting for a carrier; $FF after link open", "confidence": "low" }, { "addr": "F640", "scope": "abs", "name": "unitXTable", "meaning": "map column of each unit (100 entries)", "confidence": "high" }, { "addr": "F6A4", "scope": "abs", "name": "unitYTable", "meaning": "map row of each unit (100 entries)", "confidence": "high" }, { "addr": "F960", "scope": "abs", "name": "unitStunTable", "meaning": "per-unit byte whose low nibble is the stun counter (used for the comcen)", "confidence": "low" }, { "addr": "F9C4", "scope": "abs", "name": "unitEnergyTable", "meaning": "per-unit energy, bits 0-5 = 0..50 (shown x2 as a percentage)", "confidence": "high" }, { "addr": "FB54", "scope": "abs", "name": "unitFlagsTable", "meaning": "per-unit flag byte (bits 2-6 group/type, bit 6/7 tested before ordering the comcen)", "confidence": "low" } ], "dataBlocks": [ { "addr": "163A", "length": 3, "type": "byteTable", "name": "tabColumnTable", "description": "screen column of tab 0..2 boxes ($0B,$13,$1B)" }, { "addr": "163D", "length": 3, "type": "byteTable", "name": "tabColourTable", "description": "normal colour byte of tabs (green $05, blue $06, red $02)" }, { "addr": "1640", "length": 3, "type": "byteTable", "name": "tabHighlightColourTable", "description": "bright colour byte of tabs ($0D,$0E,$0A)" }, { "addr": "16FE", "length": 1, "type": "byteTable", "name": "lastEnergyShown", "description": "energy value last printed ($FF forces a reprint)" }, { "addr": "17D8", "length": 1, "type": "byteTable", "name": "comcenEnergySnapshot", "description": "comcen energy (0..50) when the REPAIR tab was drawn / after a repair" }, { "addr": "17D9", "length": 1, "type": "byteTable", "name": "repairAmount", "description": "energy added by the last repair attempt" }, { "addr": "1881", "length": 4, "type": "byteTable", "name": "systemMarkerColumnTable", "description": "screen column of the four comcen system markers ($0D,$10,$14,$19)" }, { "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": "0/1 blink phase shared by the tab blink and the marker blink" }, { "addr": "188A", "length": 1, "type": "byteTable", "name": "showOkMarkers", "description": "nonzero: draw markers for undamaged systems too (during the REPAIR WHICH screen)" }, { "addr": "1BC0", "length": 1, "type": "unknown", "name": "orphanRts1BC0", "description": "unreachable $60 (RTS) between waitForCarrier and showMessageWaitForSpace" }, { "addr": "1D4C", "length": 1, "type": "byteTable", "name": "scrollTargetUnit", "description": "unit index parameter of scrollViewToUnit" }, { "addr": "1D4D", "length": 1, "type": "byteTable", "name": "scrollStepDelay", "description": "ticks per step parameter of scrollViewToUnit (0 = immediate)" }, { "addr": "1DA2", "length": 3, "type": "byteTable", "name": "scrollXStartIndex", "description": "per horizontal direction (0=-1,1=0,2=+1): start Y index of the bitmap byte copy ($5F,$00,$00)" }, { "addr": "1DA5", "length": 3, "type": "byteTable", "name": "scrollXEndIndex", "description": "end Y index of the bitmap byte copy ($FF,$70,$60)" }, { "addr": "1DA8", "length": 3, "type": "byteTable", "name": "scrollXStepOpcode", "description": "DEY ($88) or INY ($C8) opcode patched into both copy loops" }, { "addr": "1DAB", "length": 3, "type": "byteTable", "name": "scrollXBitmapSrcOffset", "description": "byte offset added to the bitmap source address (0,0,$10)" }, { "addr": "1DAE", "length": 3, "type": "byteTable", "name": "scrollXBitmapDstOffset", "description": "byte offset added to the bitmap destination address ($10,0,0)" }, { "addr": "1DB1", "length": 3, "type": "byteTable", "name": "scrollYBitmapSrcLo", "description": "per vertical direction: bitmap source address lo ($AAC8,$A208,$A488)" }, { "addr": "1DB4", "length": 3, "type": "byteTable", "name": "scrollYBitmapSrcHi", "description": "bitmap source address hi" }, { "addr": "1DB7", "length": 3, "type": "byteTable", "name": "scrollYBitmapDstLo", "description": "bitmap destination address lo ($AD48,$A208,$A208)" }, { "addr": "1DBA", "length": 3, "type": "byteTable", "name": "scrollYBitmapDstHi", "description": "bitmap destination address hi" }, { "addr": "1DBD", "length": 3, "type": "byteTable", "name": "scrollYBitmapStrideLo", "description": "bitmap row stride lo ($FEC0 = -320 when scrolling up, $0140 = +320 otherwise)" }, { "addr": "1DC0", "length": 3, "type": "byteTable", "name": "scrollYBitmapStrideHi", "description": "bitmap row stride hi" }, { "addr": "1DC3", "length": 3, "type": "byteTable", "name": "scrollYRowCount", "description": "character rows to copy (8,10,8)" }, { "addr": "1DC6", "length": 3, "type": "byteTable", "name": "scrollXScreenStartIndex", "description": "start Y index of the screen/colour copy ($0B,0,0)" }, { "addr": "1DC9", "length": 3, "type": "byteTable", "name": "scrollXScreenEndIndex", "description": "end Y index of the screen/colour copy ($FF,$0E,$0C)" }, { "addr": "1DCC", "length": 3, "type": "byteTable", "name": "scrollXScreenSrcOffset", "description": "column offset of the screen source (0,0,2)" }, { "addr": "1DCF", "length": 3, "type": "byteTable", "name": "scrollXScreenDstOffset", "description": "column offset of the screen destination (2,0,0)" }, { "addr": "1DD2", "length": 3, "type": "byteTable", "name": "scrollYScreenSrcLo", "description": "screen RAM source address lo ($8D59 row 8, $8C41 row 1, $8C91 row 3; column 25)" }, { "addr": "1DD5", "length": 3, "type": "byteTable", "name": "scrollYScreenSrcHi", "description": "screen RAM source address hi (colour RAM = +$4C00)" }, { "addr": "1DD8", "length": 3, "type": "byteTable", "name": "scrollYScreenDstLo", "description": "screen RAM destination address lo ($8DA9, $8C41, $8C41)" }, { "addr": "1DDB", "length": 3, "type": "byteTable", "name": "scrollYScreenDstHi", "description": "screen RAM destination address hi" }, { "addr": "1DDE", "length": 3, "type": "byteTable", "name": "scrollYScreenStrideLo", "description": "screen row stride lo ($FFD8 = -40 up, $0028 = +40)" }, { "addr": "1DE1", "length": 3, "type": "byteTable", "name": "scrollYScreenStrideHi", "description": "screen row stride hi" } ], "misclassified": [ { "addr": "17DA", "length": 167, "actual": "code", "evidence": "$17DA-$1880 disassembles cleanly (lda $0BA3 / and #$10 / beq ...; ends with jmp $14F0); $17DA is the second entry of the JSR address table D_1535 used at $1480-$148D, and the block references $1889/$188A/$1412 and calls $19C9/$19D6/$1919/$189D/$652E. Only $17D8/$17D9 are data." }, { "addr": "192D", "length": 198, "actual": "code", "evidence": "$192D-$19F2 disassembles cleanly into six routines ($192D, $193C, $19B0, $19C9, $19D6, $19E1); $193C is called by 'jsr $193C' at $6590 (inside another mis-typed block $652E-$659F), $19C9/$19D6 are called from $17F0/$17FD, $19B0 and $192D from $193C." }, { "addr": "652E", "length": 114, "actual": "code", "evidence": "outside this chunk but called from $1860 (jsr $652E) and containing jsr $193C at $6590; it is the 'REPAIR WHICH:' screen (prints $CBD6, runs the menu selector sub_5FD7)." } ], "insights": [ "The in-game menu screen (screen id 3, entered via sub_06BA -> L_141D when zp_66 requests it) has three tabs STATS / REPAIR / MISC selected with joystick left/right and activated with fire; the main loop is L_1439 and the fire action is dispatched through the JSR address table D_1535 = {$158F, $17DA, $1A49}. sub_1507 picks the initial tab: MISC when no game is running, REPAIR when the comcen is stunned or any comcen status changed since the last visit (snapshot at $92D6), else STATS.", "The display is a VIC bank 2 bitmap: bitmap $A000, screen (colour) RAM $8C00, colour RAM $D800 (offset $4C00 from screen RAM). 'Text' is drawn into the bitmap by the $C000 overlay (font at $987E) and all colour operations (tabs, markers) write colour bytes with sub_2A64(A=colour, X=width, Y=height at row D_2A2D, column D_2A2E). The row address tables live at $9300/$9319 (bitmap) and $9382/$939B (screen RAM), column x8 at $9332/$935A.", "The battlefield view is 7x5 map cells of 16x16 pixels at screen column 25, row 1 (bitmap $A208, screen $8C41). zp_A5/zp_A6 are the map column/row of its top-left cell, the cursor/centre cell is (zp_A5+3, zp_A6+2) and is mirrored in zp_93/zp_92. scrollViewBitmap ($1DE4) shifts the bitmap and both RAMs by one cell using self-modified loops parameterised by the 22 three-byte tables at $1DA2-$1DE3, then redraws the exposed column/row via sub_25FA (map cell read, row pointers $BFB0/$BFD8) and sub_5D1A (draw cell).", "$C000 overlay text API as used here: zp_39/zp_3A/zp_3B/zp_3C = window top/bottom/left/width, zp_3F/zp_40 = cursor column/row, zp_3D = colour byte; sub_C099 = set cursor, sub_C097 = set row then cursor, sub_C06A = clear window, sub_C0D7 = full-screen window, sub_C041 = newline, sub_C01A = print char, sub_C133(A/Y=string) = print bit-7-terminated string, sub_C137 = print the string following the last one, sub_C100(A/Y=table,X) = print 8-byte table entry X, sub_C17D(A/Y) = print decimal, $C0EF (stale label bootReceiveSectorData) = print A fill characters, sub_C41B/sub_C40E = save/restore the window to $92B6, sub_C37F = wait A frames, sub_C89A = play sound A, sub_C6FF = show status message A (table at $0500/$0524), sub_C853 = show 'WORKING...'.", "Status message ids used by the comm code: $10 'WAITING FOR CONNECTION...', $17 'PICK UP PHONE THEN PRESS SPACE.', $18 'PRESS SPACE, WAIT, HANGUP PHONE.', $0C 'COMCEN STUNNED!', $01 'WORKING...'. Game-type names are an 8-byte-per-entry table at $CCC8 (SCRIMAGE, QB SNEAK, THE BOMB, FACE-OFF, SLUGGERS, FULL WAR, DEFENDER, ...) indexed by $0BA3 & 7; $CC11 holds STANDARD/CUSTOM selected by $0BA3 bit 6.", "Outgoing commands to the opponent/engine are queued byte-wise by sub_55EF into the 40-byte ring at $9065 (indices $908D/$908E, pending count $929F) and suppressed during film playback ($0B9B bit 7). Commands seen here: $80 unit x y (comcen order before repair), $8C reason (abort/disconnect, reason 0 = abort game, 5 = disconnect), $9A unit amount (energy repair), $9E (repair attempt while stunned).", "Comm module jump table entry sub_E003: X=0 opens the link (D_E03B/D_E03C/D_E03D := $FF), X>=1 closes it (:= 0, D_E01F := 0). The modem prompts are skipped when $0BA5/D_E030 bit 7 is set (comm build 1 = T35), suggesting build 1 is the direct/null-modem variant and build 2 (T34) the Hayes modem variant.", "Comcen damage model: D_9241[0..3] hold energy/system statuses (0 ok, $40 degraded, $80 damaged); sub_3D57 randomly damages systems 1-3 when the DAMAGE option ($0BA3 bit 4) is on; repairs succeed with probability 1/4 (1/2 for energy) and energy repairs add (50-energy)/8+1. Energy lives in unitEnergyTable $F9C4 bits 0-5 (0..50, displayed x2 as %). D_922A mirrors the comcen stun counter from $F960 with bit 7 = stunned.", "The file's line numbering does not match the chunk spec (lines 1607-2668 are $13C0-$1D4C); this survey covers the address range $163A-$1FA5 (file lines 1903-3019)." ] }