{
 "_comment": "generated by tools/mergeSurvey.py from survey/*.json - do not edit by hand",
 "notes": {
  "FC50": {
   "unit": "game/highMemoryFBB8",
   "block": [
    "multicolorFillPatterns: byteTable, 4 bytes. $00,$55,$AA,$FF: colour index 0-3 replicated into all four pixel pairs of a bitmap byte; indexed by plotColorIndex"
   ]
  },
  "FC54": {
   "unit": "game/highMemoryFBB8",
   "block": [
    "multicolorPixelMasks: byteTable, 4 bytes. $C0,$30,$0C,$03: bit mask of multicolour pixel pair (X & 3) within a bitmap byte"
   ]
  },
  "FD70": {
   "unit": "game/highMemoryFBB8",
   "block": [
    "arrowGlyphTable: sprite, 177 bytes. Leading byte $01 followed by eight 22-byte records: a 2-byte header ($01,$16 for the first, $01,$2D for the rest) and seven 3-byte rows holding an 8x7 arrow glyph in the middle byte (last row only 2 bytes). Glyphs are arrows for the 8 compass directions in clockwise order: N ($08,$1C,$7F,$08,$08,$08,$1C), NE, E, SE, S, SW, W, NW. No static reference to this table exists anywhere in the disassembly (no $FD7x/$FE/$FF pointers); it may be unused leftover data."
   ]
  },
  "FE24": {
   "unit": "game/highMemoryFBB8",
   "block": [
    "droneShapesRle: sprite, 367 bytes. RLE-compressed set of eight 24x21 sprites, first byte $05 = the escape marker. enterDroneScreen ($7FE6, overlay variant B) does LDA #$24 / LDY #$FE / JSR unpackRleTo0200, giving eight 64-byte shapes at $0200-$03FF that loadDirectionShapeSprite copies into the sprite data. The shapes are a top-down aeroplane silhouette (the drone) in the eight compass headings N, NE, E, SE, S, SW, W, NW. The stream ends with the run $05,$0E,$00 at $FF90-$FF92, which pads the buffer out to 512 bytes."
   ]
  },
  "FF93": {
   "unit": "game/highMemoryFBB8",
   "block": [
    "targetingReticleSprite: sprite, 63 bytes. One complete uncompressed 24x21 sprite: four corner brackets with a centre cross - the drone screen's targeting reticle. Copied into sprite 2 by overlay B at $80EB (LDA $FF93,Y) when the drone screen is built, so the drone starts over the comcen with this frame drawn around it. It ends exactly at $FFD1, the last byte of the relocated high-memory block."
   ]
  },
  "FBB8": {
   "routine": [
    "initLineStepper - Bresenham/DDA line set-up between the current cell ($93,$92) = (col,row) and the target cell ($95,$94). Computes |dRow| -> $8F, |dCol| -> $90, the step signs $96/$97 (+1 or -1), the major-axis length -> $8E and $91 (steps left), clears both error accumulators ($8C/$8D) and preloads the minor-axis accumulator with major/2. Used by the unit movement / path code in the main program ($1D57, $2512, $306F, $3771, $3A82, $42EC, $4559), by the comm module ($E80E, $E96F) and by overlay B to draw a shot/route line in the zoom window ($83A4).",
    "In:  $92 = start row, $93 = start column, $94 = end row, $95 = end column",
    "Out: A = $91 = number of steps (major axis length, Z set if zero); $8C,$8D = 0 / major/2; $8E = major length; $8F,$90 = |dRow|,|dCol|; $96,$97 = row/col step (+1/-1)"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FBFA": {
   "routine": [
    "stepLine - Advances the line started by initLineStepper by one cell: adds |dRow| to $8C and |dCol| to $8D, and whenever an accumulator reaches the major length it wraps it and moves $92 (row) / $93 (col) by the step sign, recording the applied delta in $90F4 / $90F5. $A9 ends up 0 for an orthogonal step and 1 for a diagonal step (the major axis always advances); if no steps are left nothing moves and $A9 = 0. Returns the remaining step count so callers loop with BEQ.",
    "In:  line state $8C-$8E,$8F,$90,$91,$92,$93,$96,$97",
    "Out: A = $91 (steps remaining, Z = line finished); $92/$93 advanced; $90F4 = row delta applied (-1/0/+1), $90F5 = column delta applied; $A9 = 1 if diagonal step, 0 otherwise"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FC58": {
   "routine": [
    "plotFatPixel - Plots a 'fat' multicolour pixel (one 2x2 hires block) of colour A (0-3) at X = 0..159, Y = 0..95 into the $A000 bitmap by drawing bitmap rows 2Y and 2Y+1 via plotBitmapPixelRow. X and Y are saved in self-modifying code and restored before returning. Only called from overlay B ($83E6 and the 2x2 marker at sub_84F1) to draw a shot/route line in the zoom window. The clip test is wrong: it returns early only when X >= 160 AND Y >= 96 (two BCCs into the plot path), so an out-of-range Y with a valid X is not rejected.",
    "In:  A = colour index 0-3, X = fat pixel column 0-159, Y = fat pixel row 0-95",
    "Out: bitmap byte(s) modified; X and Y preserved; $FC4D-$FC4F, $B4/$B5 clobbered"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FC74": {
   "routine": [
    "plotBitmapPixelRow - Inner routine of plotFatPixel: for bitmap row Y (0-191) and multicolour column X (0-159) computes the byte address bitmapRowAddr[Y>>3] + (Y&7) + colOffset[X>>2] using the tables at $9300/$9319 (row lo/hi, 25 entries, $A000 + 320*row) and $9332/$935A (8*column lo/hi, 40 entries), then merges the 2-bit colour ($FC50[colour] & $FC54[X&3]) into the byte. Colour index must already be in $FC4D.",
    "In:  X = pixel column 0-159, Y = bitmap row 0-191, $FC4D = colour index",
    "Out: one bitmap byte updated; $B4/$B5 = byte address; $FC4E = colour bits, $FC4F = keep mask; A,Y clobbered, X preserved"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FCCD": {
   "routine": [
    "multiply8x8 - Unsigned 8x8 -> 16 bit multiply by shift-and-add (8 iterations). Used by overlay A ($814A, $846B: value * Y for the option/limit editor) and the $EC00 sub-overlay ($ECD4: A * $96).",
    "In:  A = multiplicand, Y = multiplier",
    "Out: A = Y = product high byte, $18 = product low byte, $19 = product high byte, $1A clobbered, X = 0"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FCEC": {
   "routine": [
    "divideSigned16by8 - Divides the signed 16-bit value Y:A (Y = high byte) by the unsigned 8-bit divisor X. A negative dividend is negated first, the quotient is negated afterwards (the remainder is that of the absolute value). Callers: $41E4 (timer mod 10/50 test), the comm module ($E8EA-$E90D) and the $EE00 sub-overlay ($EE86-$EEB6).",
    "In:  X = divisor, A = dividend low, Y = dividend high (sign)",
    "Out: A = quotient (low 8 bits, sign restored), Y = remainder (of |dividend|), $18 = divisor, $19 clobbered"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FD0A": {
   "routine": [
    "divideUnsigned16by8 - Unsigned 16/8 restoring division, 8 iterations: dividend high byte in A, low byte in $19, divisor in $18. Entered directly from divideSigned16by8 for non-negative dividends. Quotient bits beyond 8 are lost.",
    "In:  A = dividend high byte, $19 = dividend low byte, $18 = divisor",
    "Out: A = quotient (low byte), Y = remainder, $19 = quotient, X = 0"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FD1E": {
   "routine": [
    "addRandomJitter - Returns base value A plus a random offset +/- 2*k, where k is the number of consecutive 1 bits at the bottom of a scenario random byte (geometric distribution) capped at Y, and the sign comes from bit 7 of $5B. Y = 0 returns A unchanged. A negative (bit 7 set) result is clamped to 0. Overlay A's scenario generator uses it to scatter unit/terrain positions around a centre (callers $7036, $738B, $7398, which retry while the result is >= 40).",
    "In:  A = base value, Y = maximum offset count; uses scenario RNG $5A-$5C",
    "Out: A = jittered value (0..127); $18, $19 clobbered; RNG state advanced",
    "(confidence: medium)"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FD4A": {
   "routine": [
    "nextScenarioRandom - 24-bit shift-register pseudo random generator on $5A/$5B/$5C, returns $5A EOR $5B. This generator is the scenario/map seed: it is zeroed at $7731, seeded from the game RNG at $77E7 or from the typed 5-character MAP ID code (5 bits per character via the 32-entry alphabet at $890C, $77F7-$7821), and consumed only by overlay A's battlefield/unit generator and $4805. Same algorithm as nextGameRandom.",
    "In:  $5A-$5C RNG state",
    "Out: A = random byte, $5A-$5C advanced, C = 0"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FD5D": {
   "routine": [
    "nextGameRandom - 24-bit shift-register pseudo random generator on $57/$58/$59, returns $57 EOR $58. Seeded with the constants $49,$19,$02 by the start-up code at $0309-$0313, so both machines of a modem game run the same deterministic sequence; used throughout the main program, overlays, the sound code ($C862) and the comm module. NOTE: this is not an IRQ handler (docs/overview.md calls $FD5D-$FD6F the IRQ handler region; the IRQ vector actually points to $1298 and later $10F1).",
    "In:  $57-$59 RNG state",
    "Out: A = random byte, $57-$59 advanced, C = 0"
   ],
   "unit": "game/highMemoryFBB8"
  },
  "FE21": {
   "unit": "game/highMemoryFBB8",
   "block": [
    "aircraftShapeTable: sprite, 367 bytes. Eight records, each a 2-3 byte header ($01,$17,$00,$05,$05,$0A / $05,$15 / $05,$18 / $05,$18 / $05,$15 / $05,$18 / $05,$11,$00 / $05,$12) followed by 14-15 rows of 3 bytes (24 px wide) that draw a top-down aeroplane/drone silhouette in 8 orientations (up, diagonal, left, diagonal, down, diagonal, right, diagonal); e.g. rows $02,$38,$80 / $0F,$FF,$E0 x3 / $08,$7C,$20 are the wings. The record framing is not fully resolved (header length and row alignment differ between records) and nothing references the table; probably stale data from the mastering system or an unused earlier unit graphic."
   ]
  },
  "FF90": {
   "unit": "game/highMemoryFBB8",
   "block": [
    "unknownShapeTail: unknown, 66 bytes. Starts with the same $05,$xx header pattern ($05,$0E) but the following bytes ($08,$78,$08,$08,..,$49,$00,$49) look like 8-pixel-wide character rows rather than 24-px rows; the sector continues past $FFD1 with stale bytes that resemble the end of the $8800 message block (track 29 s9-10) and were not moved by the loader, so this block is most likely unused leftover memory."
   ]
  }
 }
}