{ "chunk": "game_ovl_6F00_B_7891", "unit": "game/ovl_6F00_B", "routines": [ {"addr": "7894", "name": "updateRadarSweep", "summary": "Per-frame driver of the radar sweep animation on screen 1 (the RADAR/MISSILE screen at $7587). When frameTick92FB reaches the self-modified threshold at $7898 it advances the threshold by 2 and performs one step: the step number radarSweepStep ($7891) is the grid row that gets lit (rows 0-16 via paintRadarSweepRow) and row step-14 (when 0..16) is repainted dark, so a 14-row light band wipes down the 21x17 radar window. Steps 0-30 take about 62 frames; at step 31 the sweep is restarted by restartRadarSweep. Called from the screen-1 main loop ($75F7) and from the missile flight animation ($77F9).", "inputs": "frameTick92FB ($92FB), radarSweepStep ($7891), radarSweepNextTick ($7898 immediate operand)", "outputs": "$7891 incremented (or reset), $7892 = row being painted, $7898 += 2, screen RAM colour cells of the radar window rows; A/X/Y clobbered", "confidence": "high"}, {"addr": "78CB", "name": "restartRadarSweep", "summary": "Restarts the radar sweep: clears radarSweepStep, radarSweepDarkFlag, frameTick92FB and the tick threshold at $7898. If the comcen radar system is damaged (comcenRadarStatus $9243 nonzero) a random draw (nextGameRandom bit 7) makes the whole next sweep dark (radarSweepDarkFlag = $FF), i.e. the damaged radar fails to show anything on about half of its sweeps. Called when screen 1 is built ($75B3) and at the end of every sweep.", "inputs": "$9243 comcenRadarStatus, RNG $57-$59", "outputs": "$7891 = 0, $7893 = 0 or $FF, $92FB = 0, $7898 = 0; X clobbered", "confidence": "high"}, {"addr": "78E7", "name": "paintRadarSweepRow", "summary": "Repaints the screen-RAM colour bytes of the 21 cells of radar grid row A (0-16, screen row A+3, columns 3-23): computes the screen RAM ($8C00, via the row tables D_9385/D_939E whose index 0 is row 3) and colour RAM ($D800) pointers, then for each cell writes $F0 (multicolour %01 pixels light grey = visible) when the cell's colour RAM nibble is 1 (a spotted enemy unit) and the radar is intact, or when this row is the current sweep row (radarSweepRow == radarSweepStep) and the sweep is not dark; otherwise writes $00 (pixels black = hidden). This is how the sweep band reveals and re-hides the radar blips.", "inputs": "A = grid row 0-16, $7891 radarSweepStep, $7892 radarSweepRow, $7893 radarSweepDarkFlag, $9243 comcenRadarStatus, colour RAM row", "outputs": "21 screen RAM bytes at $8C00+(row+3)*40+3 set to $F0/$00; zp_B6/B7 = colour RAM pointer, zp_B8/B9 = screen RAM pointer; A/X/Y clobbered", "confidence": "medium"}, {"addr": "7926", "name": "redrawEnemyUnitsOnRadar", "summary": "Re-randomises the 16 noise masks at $9210 (sub_727A) and redraws every unit of the opposing side on the radar window: starts at unit comcenUnit EOR $52 (99 for comcen 49, 49 for comcen 99) and walks 50 units downwards, passing cell value $80|unit (alive) or the terrain byte saved under a dead unit (skipped when $FF = not on the map) with the unit's column/row in $54-$56 to drawScreen1Cell ($5D7F). Called from the screen-1 refresh sub_7688 (at screen build and whenever statsNeedRefresh $920E is set after a turn), so enemy blips move and their noise pattern changes every turn.", "inputs": "$9236 comcenUnit, unit arrays $F640/$F6A4/$F76C/$FAF0", "outputs": "cells redrawn on screen 1; $9210-$921F new masks; zp_18 = unit index, zp_19 = counter, $54-$56", "confidence": "high"}, {"addr": "7959", "name": "scrollRadarOnComcenMove", "summary": "Entered by JMP from drawScreen1Cell ($5D8A) when the cell being redrawn is the player's comcen. Computes the radar grid origin from the comcen position (getRadarGridOrigin); if it equals the current view origin zp_A5/A6 nothing happens. Otherwise the comcen has moved: unless the target cursor sits on the comcen cell (10,8) it is shifted by (old origin - new origin) through $76EC so that it keeps pointing at the same map cell (left unchanged if that would leave the grid), then the whole radar map is redrawn (drawRadarMap) and the sweep row restarts at 0.", "inputs": "$9236 comcenUnit, zp_A5/A6 view origin, zp_67/68 radar cursor", "outputs": "zp_A5/A6 = new origin, zp_67/68 and sprite 2 position possibly updated, radar window redrawn, $7891 = 0", "confidence": "medium"}, {"addr": "7987", "name": "isRadarCursorOnComcen", "summary": "Compares the radar target cursor (zp_67 column, zp_68 row) with the comcen's fixed grid cell (10,8), the centre of the 21x17 radar window. Returns Z=1 when the cursor is on the comcen.", "inputs": "zp_67, zp_68", "outputs": "Z flag (set = cursor on comcen cell); A clobbered", "confidence": "high"}, {"addr": "7992", "name": "radarCursorToMapCoords", "summary": "Converts the radar cursor grid position into map coordinates for an outgoing command: cmdParam1 (zp_74) = zp_67 + view origin column, cmdParam2 (zp_75) = zp_68 + view origin row. Used before queueing the missile strike command $90 ($7667) and by checkStrikeHitsDrone.", "inputs": "zp_67/68 radar cursor, zp_A5/A6 view origin", "outputs": "zp_74 = map column, zp_75 = map row; A clobbered", "confidence": "high"}, {"addr": "79A1", "name": "checkStrikeHitsDrone", "summary": "After a missile strike is fired: if a drone is active (droneStateFlags $920D nonzero) and still in flight (droneFlags $92F9 == 0), converts the strike cursor to map coordinates and tests whether the target cell is one of the 2x2 cells occupied by the drone (droneCol - col and droneRow - row both in {-1,0}). If so it queues the 1-byte command $92 (drone destroyed/finished) and sets droneFlags bit 0. Called from the fire handler at $767E.", "inputs": "$920D, $92F9, $92F6 droneCol, $92F7 droneRow, zp_67/68, zp_A5/A6", "outputs": "command $92 queued (queueCmdBytePending), $92F9 |= 1, zp_74/75", "confidence": "medium"}, {"addr": "79D8", "name": "showDroneKillBurst", "summary": "Visual/sound effect on the radar screen when the local $92 command has been executed (droneFlags bit 4 set by cmdDroneArrived): not in solo/film mode ($0B9B bit 7). Moves droneFlags bit 4 to bit 5, clears droneStateFlags, plays sounds $17 and $09, positions sprite 1 on the drone's cell centre (getUnitSpriteCentreOnGrid) and plays an 11-step ring burst there. Called from the screen-1 loop when statsNeedRefresh is set ($75F4).", "inputs": "$0B9B, $92F9, $92F6/$92F7 drone position", "outputs": "$92F9 bit4 cleared/bit5 set, $920D = 0, $9011/$9019 sprite 1 position, sprite 1 animation, sounds", "confidence": "medium"}, {"addr": "7A13", "name": "mapCellToRadarGrid", "summary": "Converts map coordinates (X = column, Y = row) into radar grid coordinates relative to the comcen: X = col + 10 - comcenCol, Y = row + 8 - comcenRow, then falls into isRadarGridCellInRange. Called by the main program's getUnitSpriteCentreOnGrid ($340B) and by the communications module ($EE7C in build 1, $EEE1 in the $EE00 sub-overlay) to place sprites on screen 1.", "inputs": "X = map column, Y = map row, $9236 comcenUnit, $F640/$F6A4", "outputs": "X = grid column, Y = grid row, C = 0 inside the 21x17 grid, C = 1 outside", "confidence": "high"}, {"addr": "7A2B", "name": "isRadarGridCellInRange", "summary": "Range test for a radar grid cell: C = 0 when Y < 17 and X < 21 (unsigned, so negative values count as outside), C = 1 otherwise. Also called directly from $33A0, $76FC and $77B9.", "inputs": "X = grid column, Y = grid row", "outputs": "C flag", "confidence": "high"}, {"addr": "7A32", "name": "initRadarScreen", "summary": "Builds screen 1 (RADAR/MISSILE screen, game screen id 1 entered at $7587): clears the text draw parameters $2A29-$2A2C, sets border and background colour shadows to $0C, clears $9226, sets zp_41 = 1, then draws the MISSILES panel (drawMissilePanel), the missile count (drawMissileCount), the FIRE button (drawFireButton), the DRONE ALERT panel (drawDroneAlertPanel), the framed radar map window (redrawRadarMapWindow) and the main frame (drawMainWindowFrame), and finally jumps to the $C000 overlay's message-line redraw at L_C5D7.", "inputs": "$9232 missiles left, game state", "outputs": "whole screen drawn; $9003/$9004 = $0C, $9226 = 0, zp_41 = 1, $2A29-$2A2C = 0", "confidence": "high"}, {"addr": "7A6B", "name": "redrawRadarMapWindow", "summary": "Draws the two nested frames of the radar window (window 5: 25x21 at (1,1); window 6: 23x19 at (2,2)) and then the 21x17 radar map itself (drawRadarMap). Also the target of clearCurrentScreenWindows ($2DFA) when screen 1 is active.", "inputs": "comcen position, map", "outputs": "frames and map drawn", "confidence": "high"}, {"addr": "7A78", "name": "drawMissilePanel", "summary": "Draws the MISSILES panel at the bottom right: resets the text window to the full screen, draws window 7 (12x7 at (27,15)) with inner corners and window 8 (4x4 at (31,16)), fills the 2x2 count box at row 17 column 32 with colour $30, selects OR bitmap mode, text colour $CF, and prints the string 'MISSILES' ($CC9E) at column 29 row 19, then resets the draw modes.", "inputs": "-", "outputs": "panel drawn; zp_3D, zp_3F, zp_40, $2A2D/$2A2E changed", "confidence": "high"}, {"addr": "7ABA", "name": "drawMissileCount", "summary": "Displays the number of missiles left ($9232) as two tall (2-row) digits at row 17, columns 32 and 33: sub_C428 splits the value into tens ($C44F) and ones ($C450), the fixed draw colour $30 is selected (and remembered in missileCountColour) and drawTallGlyph is called twice. Called at screen build, after each launch ($7647) and from the refresh routine.", "inputs": "$9232", "outputs": "digits drawn; $7AB9 = $30; $2A29/$2A2A restored to 0; zp_18/zp_19 = row/column", "confidence": "high"}, {"addr": "7AEC", "name": "blinkMissileCount", "summary": "Toggles missileCountColour between $30 and $03 and fills the 2x2 colour cells of the count box (row 17, column 32) with it, which swaps foreground and background of the digits. Called every 9 frames by the screen-1 loop ($75E4) while fewer than 2 missiles are left.", "inputs": "$7AB9", "outputs": "$7AB9 toggled, screen RAM colour cells; $2A2D/$2A2E = 17/32", "confidence": "high"}, {"addr": "7B05", "name": "drawFireButton", "summary": "Draws the FIRE button panel: window 9 (8x7 at (29,8)) with inner corners, the 2x2 character picture at $9804 at row 10 column 32 filled with colour 5, text colour $CD and the word 'FIRE' ($869D) at column 31 row 12, then resets the draw modes. The screen-1 loop blinks the button by XORing colour 8 into the same 2x2 cells every 9 frames ($75DA).", "inputs": "-", "outputs": "panel drawn; zp_3D, zp_3F, zp_40, text window reset", "confidence": "high"}, {"addr": "7B44", "name": "drawDroneAlertPanel", "summary": "Draws the top-right DRONE ALERT panel made of three nested frames (windows $0A 11x8 at (28,0), $0B 9x6 at (29,1), $0C 7x4 at (30,2)) and falls into resetDroneAlertPanel which prints the text in its inactive colour.", "inputs": "-", "outputs": "panel drawn", "confidence": "high"}, {"addr": "7B59", "name": "resetDroneAlertPanel", "summary": "Prints 'DRONE' / 'ALERT' ($86A1, two lines) at column 31 row 3 in colour $0B (replace colour mode), sets droneAlertColour ($7B43) back to 2, stores 11 in zp_70 (never read) and fills the 7x4 panel interior at (2,30) with colour $0B, i.e. the panel is shown dark/inactive. Entered by JMP from the refresh routine sub_7688 when no drone is active ($920D bit 0 clear) and at the end of drawDroneAlertPanel.", "inputs": "-", "outputs": "text and colour cells; $7B43 = 2, zp_3B = 31, zp_3D = $0B, zp_3F = 0, zp_40 = 3, zp_70 = 11", "confidence": "high"}, {"addr": "7B86", "name": "flashDroneAlertPanel", "summary": "Resets the draw modes, toggles droneAlertColour between $02 and $20 (EOR $22) and repaints the 7x4 panel interior with it, making the DRONE ALERT text flash red. Entered by JMP from sub_7688 on every refresh while a drone is active ($920D bit 0 set).", "inputs": "$7B43", "outputs": "$7B43 toggled, 7x4 colour cells at (2,30)", "confidence": "high"}, {"addr": "7B91", "name": "fillDroneAlertPanel", "summary": "Tail shared by the two panel states: fills the 7 column x 4 row colour rectangle at row 2, column 30 with the colour byte in A (fillScreenColourRect).", "inputs": "A = colour byte", "outputs": "$2A2D = 2, $2A2E = 30, 28 colour cells written", "confidence": "high"}, {"addr": "7BA2", "name": "drawRadarMap", "summary": "Draws the 21x17 radar map centred on the comcen at screen rows 3-19, columns 3-23, one character per map cell: re-randomises the noise masks (sub_727A), sets the cell colour parameters $9237/$9239 = $0B and $9238 = 1, clears the window's colour cells to 0, sets the view origin zp_A5/A6 = comcen - (10,8) (saved in $90F6/$90F7), gets the map pointer with getViewportOriginPointer and for every row/column computes the bitmap address (row/column tables with the +3 offset) and the colour RAM address ($D800 based), then calls the cell classifier sub_74C3 and glyph plotter sub_7396 of this overlay. Restores zp_A5/A6 and clears useFixedColourFlag at the end.", "inputs": "$9236 comcenUnit, map $F000, unit arrays", "outputs": "radar window drawn; zp_A5/A6 = grid origin, $90F6/$90F7, zp_48/49 map pointer, zp_B4/B5 bitmap pointer, zp_B6/B7 colour RAM pointer, $9237-$9239, $2A29 = 0", "confidence": "high"}, {"addr": "7C5C", "name": "getRadarGridOrigin", "summary": "Returns the map coordinates of the top-left cell of the radar grid: X = comcenCol - 10, Y = comcenRow - 8 (may be negative / wrap when the comcen is near the map edge; the drawing code handles that through getViewportOriginPointer).", "inputs": "$9236 comcenUnit, $F640/$F6A4", "outputs": "X = origin column, Y = origin row; A clobbered", "confidence": "high"} ], "variables": [ {"addr": "7891", "scope": "abs", "name": "radarSweepStep", "meaning": "current step (0-30) of the radar sweep on screen 1; for steps 0-16 it is the grid row being lit, rows step-14 are darkened; 31 restarts the sweep", "confidence": "high"}, {"addr": "7892", "scope": "abs", "name": "radarSweepRow", "meaning": "grid row currently handed to paintRadarSweepRow; equal to radarSweepStep for the lit row, step-14 for the row being darkened", "confidence": "high"}, {"addr": "7893", "scope": "abs", "name": "radarSweepDarkFlag", "meaning": "$FF = the current sweep shows nothing (set randomly at sweep restart while the radar system $9243 is damaged), 0 = normal", "confidence": "high"}, {"addr": "7898", "scope": "abs", "name": "radarSweepNextTick", "meaning": "self-modified immediate operand of the CMP at $7897: value of frameTick92FB at which the next sweep step is due (advanced by 2 per step, reset to 0 with the tick)", "confidence": "high"}, {"addr": "7AB9", "scope": "abs", "name": "missileCountColour", "meaning": "colour byte of the 2x2 missile count box: $30 normal, $03 inverted; toggled by blinkMissileCount when fewer than 2 missiles are left", "confidence": "high"}, {"addr": "7B43", "scope": "abs", "name": "droneAlertColour", "meaning": "colour byte of the DRONE ALERT panel interior while flashing: toggles between $02 and $20 (EOR $22); reset to 2 when the panel is inactive", "confidence": "high"}, {"addr": "9232", "scope": "abs", "name": "radarMissilesLeft", "meaning": "screen-1 working copy of the player's missiles left (loaded from missilesLeft[0] $92B0 at $758C, decremented when FIRE is used, shown by drawMissileCount, blinks below 2)", "confidence": "high"}, {"addr": "9243", "scope": "abs", "name": "comcenRadarStatus", "meaning": "comcenSystemStatus[2] = RADAR system of the comcen (0 ok, nonzero damaged): a damaged radar randomly blanks whole sweeps and no longer keeps spotted enemy cells lit; only ever cleared by the main program ($3FED), damage is presumably written through the indexed base $9241", "confidence": "medium"}, {"addr": "9237", "scope": "abs", "name": "screen1OwnUnitColour", "meaning": "colour RAM value (set to $0B) used by the screen-1 cell classifier sub_74C3 for units of the player's side", "confidence": "medium"}, {"addr": "9238", "scope": "abs", "name": "screen1SpottedEnemyColour", "meaning": "colour RAM value (set to 1 = white) used by sub_74C3 for spotted enemy units; paintRadarSweepRow keeps cells with this nibble lit while the radar is intact", "confidence": "medium"}, {"addr": "9239", "scope": "abs", "name": "screen1TerrainColour", "meaning": "colour RAM value (set to $0B) used by sub_74C3 for terrain cells and for unspotted (noise-drawn) enemy units", "confidence": "medium"}, {"addr": "9210", "scope": "abs", "name": "radarNoiseMaskTable", "meaning": "16 random AND masks ($FF with four random bits cleared, built by sub_727A) used to draw unspotted enemy units as noisy radar blips", "confidence": "high"}, {"addr": "92FB", "scope": "abs", "name": "frameTick92FB", "meaning": "free-running frame counter; reset to 0 by restartRadarSweep and compared with radarSweepNextTick to pace the sweep (2 frames per step)", "confidence": "high"}, {"addr": "920D", "scope": "abs", "name": "droneStateFlags", "meaning": "drone control flags; bit 0 set = a drone is active (DRONE ALERT panel flashes); cleared to 0 by showDroneKillBurst", "confidence": "medium"}, {"addr": "920E", "scope": "abs", "name": "statsNeedRefresh", "meaning": "nonzero requests a screen refresh after a command slice; the screen-1 loop then calls sub_7688 (which clears it) and showDroneKillBurst", "confidence": "high"}, {"addr": "92F9", "scope": "abs", "name": "droneFlags", "meaning": "drone lifecycle flags: 0 while in flight; bit 0 set by checkStrikeHitsDrone when a missile hits the drone; bit 4 (own $92 executed) consumed and turned into bit 5 by showDroneKillBurst", "confidence": "medium"}, {"addr": "92F6", "scope": "abs", "name": "droneCol", "meaning": "map column of the drone (top-left of its 2x2 cells), from command $8D", "confidence": "high"}, {"addr": "92F7", "scope": "abs", "name": "droneRow", "meaning": "map row of the drone (top-left of its 2x2 cells)", "confidence": "high"}, {"addr": "9236", "scope": "abs", "name": "comcenUnit", "meaning": "index of the player's comcen (49 or 99); the radar grid is centred on it at grid cell (10,8)", "confidence": "high"}, {"addr": "90F6", "scope": "abs", "name": "viewOriginColSave", "meaning": "radar grid origin column saved while drawRadarMap walks zp_A5 through the cells; restored at the end", "confidence": "high"}, {"addr": "90F7", "scope": "abs", "name": "viewOriginRowSave", "meaning": "radar grid origin row saved by drawRadarMap", "confidence": "high"}, {"addr": "9003", "scope": "abs", "name": "borderColorShadow", "meaning": "shadow of $D020; set to $0C for the radar screen", "confidence": "high"}, {"addr": "9004", "scope": "abs", "name": "bgColorShadow", "meaning": "shadow of $D021; set to $0C for the radar screen", "confidence": "high"}, {"addr": "9011", "scope": "abs", "name": "sprite1XShadow", "meaning": "sprite 1 X position (ring burst sprite); set to the drone cell centre by showDroneKillBurst", "confidence": "high"}, {"addr": "9019", "scope": "abs", "name": "sprite1YShadow", "meaning": "sprite 1 Y position", "confidence": "high"}, {"addr": "9012", "scope": "abs", "name": "sprite2XShadow", "meaning": "sprite 2 X position = radar target cursor (cross marker) on screen 1", "confidence": "high"}, {"addr": "901A", "scope": "abs", "name": "sprite2YShadow", "meaning": "sprite 2 Y position = radar target cursor", "confidence": "high"}, {"addr": "9226", "scope": "abs", "name": "screenStateFlag9226", "meaning": "cleared by initRadarScreen; read only by overlay code ($740F)", "confidence": "low"}, {"addr": "0B9B", "scope": "abs", "name": "soloModeFlag", "meaning": "bit 7 = solo/film playback mode: showDroneKillBurst does nothing", "confidence": "high"}, {"addr": "2A29", "scope": "abs", "name": "useFixedColourFlag", "meaning": "nonzero: glyph plotters use the fixed colour $2A2A; set to $FF around drawTallGlyph in drawMissileCount", "confidence": "high"}, {"addr": "2A2A", "scope": "abs", "name": "fillColourValue", "meaning": "fixed colour byte for glyph/fill drawing ($30 for the missile digits)", "confidence": "high"}, {"addr": "2A2D", "scope": "abs", "name": "windowRow", "meaning": "screen row of the window / fill origin for fillScreenColourRect and drawCharBlock", "confidence": "high"}, {"addr": "2A2E", "scope": "abs", "name": "windowCol", "meaning": "screen column of the window / fill origin", "confidence": "high"}, {"addr": "C44F", "scope": "abs", "name": "decimalTensDigit", "meaning": "tens digit produced by sub_C428 (binary to two decimal digits)", "confidence": "high"}, {"addr": "C450", "scope": "abs", "name": "decimalOnesDigit", "meaning": "ones digit produced by sub_C428", "confidence": "high"}, {"addr": "67", "scope": "zp", "name": "radarCursorCol", "meaning": "grid column (0-20) of the missile target cursor on the radar screen; starts on the comcen cell (10)", "confidence": "high"}, {"addr": "68", "scope": "zp", "name": "radarCursorRow", "meaning": "grid row (0-16) of the missile target cursor; starts on the comcen cell (8)", "confidence": "high"}, {"addr": "A5", "scope": "zp", "name": "viewOriginCol", "meaning": "map column of the left edge of the current view; on screen 1 = comcenCol - 10 (radar grid origin)", "confidence": "high"}, {"addr": "A6", "scope": "zp", "name": "viewOriginRow", "meaning": "map row of the top edge of the current view; on screen 1 = comcenRow - 8", "confidence": "high"}, {"addr": "74", "scope": "zp", "name": "cmdParam1", "meaning": "second byte of an outgoing command: strike column", "confidence": "high"}, {"addr": "75", "scope": "zp", "name": "cmdParam2", "meaning": "third byte of an outgoing command: strike row", "confidence": "high"}, {"addr": "48", "scope": "zp", "name": "mapCellPtr", "meaning": "pointer (lo) into the $F000 map, set by getViewportOriginPointer and advanced by 40 per radar row", "confidence": "high"}, {"addr": "49", "scope": "zp", "name": "mapCellPtrHi", "meaning": "pointer (hi) into the map", "confidence": "high"}, {"addr": "B4", "scope": "zp", "name": "bitmapPtr", "meaning": "pointer (lo) to the 8x8 bitmap block of the cell being drawn ($A000 bitmap, from the row/column tables)", "confidence": "high"}, {"addr": "B5", "scope": "zp", "name": "bitmapPtrHi", "meaning": "pointer (hi) to the bitmap block", "confidence": "high"}, {"addr": "B6", "scope": "zp", "name": "colourRamPtr", "meaning": "in this chunk: pointer (lo) into colour RAM $D800 for the cell row (screen row table hi byte + $4C)", "confidence": "high"}, {"addr": "B7", "scope": "zp", "name": "colourRamPtrHi", "meaning": "pointer (hi) into colour RAM", "confidence": "high"}, {"addr": "B8", "scope": "zp", "name": "screenRamPtr", "meaning": "in paintRadarSweepRow: pointer (lo) into screen RAM $8C00 (multicolour colour cells) for the sweep row", "confidence": "high"}, {"addr": "B9", "scope": "zp", "name": "screenRamPtrHi", "meaning": "pointer (hi) into screen RAM", "confidence": "high"}, {"addr": "3B", "scope": "zp", "name": "textWindowLeft", "meaning": "left column of the text window (31 for the DRONE ALERT text)", "confidence": "high"}, {"addr": "3D", "scope": "zp", "name": "textColour", "meaning": "colour byte for printed text ($CF MISSILES, $CD FIRE, $0B DRONE ALERT)", "confidence": "high"}, {"addr": "3F", "scope": "zp", "name": "textCursorCol", "meaning": "text cursor column relative to the window left edge", "confidence": "high"}, {"addr": "40", "scope": "zp", "name": "textCursorRow", "meaning": "text cursor row", "confidence": "high"}, {"addr": "41", "scope": "zp", "name": "flag41", "meaning": "set to 1 by initRadarScreen (menu-vs-battle / screen-built flag, write-mostly)", "confidence": "low"}, {"addr": "70", "scope": "zp", "name": "unusedTimer70", "meaning": "one of the IRQ-decremented frame countdowns zp_6C-zp_71; written with 11 by resetDroneAlertPanel and never read anywhere (dead store)", "confidence": "medium"}, {"addr": "18", "scope": "zp", "name": "scratch18", "meaning": "scratch: unit index in redrawEnemyUnitsOnRadar, glyph row for drawTallGlyph", "confidence": "high"}, {"addr": "19", "scope": "zp", "name": "scratch19", "meaning": "scratch: loop counter (50) in redrawEnemyUnitsOnRadar, glyph column for drawTallGlyph", "confidence": "high"}, {"addr": "54", "scope": "zp", "name": "mapCellValue", "meaning": "cell byte passed to drawScreen1Cell ($80|unit or terrain)", "confidence": "high"}, {"addr": "55", "scope": "zp", "name": "mapCellX", "meaning": "column of the cell passed to drawScreen1Cell", "confidence": "high"}, {"addr": "56", "scope": "zp", "name": "mapCellY", "meaning": "row of the cell passed to drawScreen1Cell", "confidence": "high"} ], "dataBlocks": [ {"addr": "7891", "length": 3, "type": "byteTable", "name": "radarSweepState", "description": "three state bytes of the radar sweep: radarSweepStep, radarSweepRow, radarSweepDarkFlag (all initialised to 0 on disk)"}, {"addr": "7A12", "length": 1, "type": "unknown", "name": "padding7A12", "description": "unreferenced $00 byte between the RTS of showDroneKillBurst and mapCellToRadarGrid (alignment filler)"}, {"addr": "7AB9", "length": 1, "type": "byteTable", "name": "missileCountColour", "description": "colour byte of the missile count box ($30 / $03)"}, {"addr": "7B43", "length": 1, "type": "byteTable", "name": "droneAlertColour", "description": "flash colour of the DRONE ALERT panel ($02 / $20)"} ], "misclassified": [], "insights": [ "Screen 1 of the game (entered at $7587, selected with the function key giving screen id 1) is the comcen's RADAR / MISSILE screen in overlay variant B: a 21x17-cell map window at screen (3,3) centred on the player's comcen (grid cell (10,8), one 8x8 character per map cell), a DRONE ALERT panel (windows $0A-$0C, top right), a FIRE button (window 9, 2x2 picture $9804 at (10,32) + 'FIRE') and a MISSILES panel (windows 7/8) showing the missiles left ($9232, copied from missilesLeft[0] $92B0) as two tall digits at (17,32). Border and background are $0C.", "Radar sweep mechanics: a 14-row light band wipes down the 17 rows every ~62 frames (2 frames per step, 31 steps). It works by writing $F0 or $00 into the screen RAM colour cells (multicolour %01 pixels light grey or black) of one row at a time, so radar blips drawn with %01 pixels appear only while the band passes. Cells with colour RAM nibble 1 (spotted enemy units, $9238) stay lit while the radar system is intact. If the comcen RADAR system is damaged ($9243 = comcenSystemStatus[2]) about half of the sweeps are blank.", "Enemy units are re-drawn on the radar (redrawEnemyUnitsOnRadar) every time statsNeedRefresh $920E is set, i.e. once per processed turn, with freshly randomised noise masks ($9210-$921F from sub_727A) so unspotted enemy blips shimmer.", "The missile target cursor is sprite 2 (the cross shape built by showComcenCrossMarker $3383); its grid position is zp_67/zp_68 and is moved by the joystick handler sub_76B2 (outside this chunk). FIRE ($763F/$764A) decrements $9232, queues command $90 col,row (radarCursorToMapCoords -> zp_74/75), animates the missile flight along a line in sprite 3 (sub_7713) and a 3-step ring burst on sprite 1 at the target, then checkStrikeHitsDrone queues $92 if the strike cell is inside the drone's 2x2 footprint - this is the only sender of command $92, which therefore means 'drone destroyed by a missile' rather than 'drone arrived'. showDroneKillBurst then shows an 11-step ring burst at the drone when the own $92 has been executed.", "When the comcen moves, drawScreen1Cell ($5D7F) jumps to scrollRadarOnComcenMove ($7959), which recomputes the grid origin (comcen - (10,8)), shifts the cursor so it keeps its map cell and redraws the whole window.", "The $9300 address tables are used with a +3 bias in this overlay: D_9303/D_931C = bitmap row address lo/hi for row 3 onwards (real tables start at $9300/$9319), D_9335/D_935D = bitmap column offset for column 3 onwards (real tables $9332/$935A), D_9385/D_939E = screen RAM ($8C00) row address for row 3 onwards (real tables $9382/$939B); adding $4C to the high byte turns a screen RAM address into the colour RAM address.", "mapCellToRadarGrid ($7A13) / isRadarGridCellInRange ($7A2B) / getRadarGridOrigin ($7C5C) are the shared coordinate helpers of the radar grid; $7A13 is an entry point used by the main program ($340B) and by both communications-module variants ($EE7C in build 1, $EEE1 in the $EE00 sub-overlay), so its address must stay fixed across overlay builds.", "Window table entries used here (left,top,width,height): 5=(1,1,25,21) 6=(2,2,23,19) radar frame; 7=(27,15,12,7) 8=(31,16,4,4) missiles panel; 9=(29,8,8,7) fire button; $0A=(28,0,11,8) $0B=(29,1,9,6) $0C=(30,2,7,4) drone alert panel.", "Strings in overlay B used by this chunk: $869D 'FIRE', $86A1 'DRONEALERT' (bit-7 terminated; $868C 'DRONE', $8691 'LAUNCH', $8697 'STRIKE' precede them and belong to screen 2); 'MISSILES' lives in the $C000 overlay at $CC9E.", "sub_C428 in the $C000 overlay converts A to two decimal digits stored at $C44F (tens) and $C450 (ones) (and a hundreds/leading flag at $C44E); drawTallGlyph ($2BB7) then draws each digit as a 2-row glyph." ] }