{
 "chunk": "data_table_0400",
 "unit": "game/table_0400",
 "routines": [],
 "variables": [],
 "dataBlocks": [
  {
   "addr": "0400",
   "length": 1,
   "type": "byteTable",
   "name": "checksumXorConstant",
   "description": "$B0. The constant verifyProgramChecksum ($0461) EORs into the final sum before storing it in programChecksum $0B7E. It sits one byte below the start of the checksummed range ($0402), so it can never influence itself."
  },
  {
   "addr": "0401",
   "length": 96,
   "type": "byteTable",
   "name": "mapNameSeedTable",
   "description": "32 entries of 3 bytes for the manual look-up protection at $09A6: randomSeed ($09C3) AND $1F picks an entry, the triple is copied to $0B95-$0B97 and used as the 24-bit map seed, the generated map is shown with 'IDENTIFY THIS MAP (SEE MANUAL)' ($0A48) and the five-character name the player types is packed through mapNameAlphabet ($890C) into zp_5A-zp_5C and compared with the same triple. Three failures wipe memory ($0A1E). Note $0401 (entry 0's first byte) is the only table byte outside the checksummed range."
  },
  {
   "addr": "04AE",
   "length": 82,
   "type": "unknown",
   "name": "scratchPageTail",
   "description": "$00 on disk. At run time this is shared scratch: the 2x2 tile buffer $04C8-$04E7 filled by the terrain drawing code at $279F/$27CD, statistics accumulators, and the map generator's blob stacks. The trainer's playbook load (track 29 s6-8 -> $0200-$04FF) also overwrites it."
  },
  {
   "addr": "0500",
   "length": 36,
   "type": "byteTable",
   "name": "messagePtrLoTable",
   "description": "Low bytes of the 36 status-message pointers, indexed by message id $00-$23; read by the message system at $C536/$C5E5 and patched at run time by setMessageSlot ($C924). Ids $1E, $20 and $21 are $FFFF placeholders on disk: $20/$21 are filled with $8800/$881C by mainProgram $0B1D/$0B26, with $895E/$8837 by showModemSetupPrompt ($0C8C), and with the modem driver's own $EFxx strings by $EED6/$EEFF."
  },
  {
   "addr": "0524",
   "length": 36,
   "type": "byteTable",
   "name": "messagePtrHiTable",
   "description": "High bytes of the same 36 pointers. $05/$06 = strings in this block, $87 = strings in the $6F00 overlay variant B, $88 = strings in the loaded $8800 message block, $FF = unset placeholder."
  },
  {
   "addr": "0548",
   "length": 36,
   "type": "text",
   "name": "chatMessageLine",
   "description": "Message id $00, the chat / typed line. $0548 is a leading marker glyph ($1E = cursor, or $9E written by sub_C62A to terminate at once = blank line) and $0549-$056B hold up to 35 characters mirrored from $9253 with bit 7 set on the last. On disk it is 35 spaces followed by $A0."
  },
  {
   "addr": "056C",
   "length": 10,
   "type": "text",
   "name": "msgWorking",
   "description": "Message id $01 \"WORKING...\" (bit-7 terminated), sound $80 = silent."
  },
  {
   "addr": "0576",
   "length": 13,
   "type": "text",
   "name": "msgGameAborted",
   "description": "Message id $03 \"GAME ABORTED.\", sound $03."
  },
  {
   "addr": "0583",
   "length": 16,
   "type": "text",
   "name": "msgNotAGameFilm",
   "description": "Message id $09 \"NOT A GAME FILM!\", sound $03 - a film load was rejected."
  },
  {
   "addr": "0593",
   "length": 33,
   "type": "text",
   "name": "msgSetupUnitsPressF1WhenDone",
   "description": "Message id $0A \"SETUP UNITS. PRESS F 1 WHEN DONE.\", silent - the unit setup phase prompt."
  },
  {
   "addr": "05B4",
   "length": 28,
   "type": "text",
   "name": "msgTimeoutRunStopToResume",
   "description": "Message id $19 \"TIMEOUT. RUN/STOP TO RESUME.\", sound $19."
  },
  {
   "addr": "05D0",
   "length": 7,
   "type": "text",
   "name": "msgResumed",
   "description": "Message id $1B \"RESUMED\", sound $19."
  },
  {
   "addr": "05D7",
   "length": 18,
   "type": "text",
   "name": "msgTheBattleBegins",
   "description": "Message id $1C \"THE BATTLE BEGINS!\", sound $03."
  },
  {
   "addr": "05E9",
   "length": 17,
   "type": "text",
   "name": "msgLastQtrWarning",
   "description": "Message id $1D \"LAST QTR WARNING!\", sound $19 - the game is played in quarters."
  },
  {
   "addr": "05FA",
   "length": 14,
   "type": "text",
   "name": "msgPhoneTrouble",
   "description": "Message id $22 \"PHONE TROUBLE.\", sound $15 - modem link failure."
  },
  {
   "addr": "0608",
   "length": 10,
   "type": "text",
   "name": "msgTryAgain",
   "description": "Message id $23 \"TRY AGAIN.\", sound $03."
  },
  {
   "addr": "0612",
   "length": 36,
   "type": "byteTable",
   "name": "messageSoundTable",
   "description": "Sound effect number played when message id X is shown (read at $C557, played through sub_C89A); $80 = silent. $0E for the two 'we lost' messages, $0D for the two 'we won' messages, $19 for GAME OVER / TIMEOUT / RESUMED / LAST QTR WARNING, $15 for PHONE TROUBLE, $06 for the two phone prompts."
  },
  {
   "addr": "0636",
   "length": 23,
   "type": "text",
   "name": "optionSummaryTemplate",
   "description": "\" MENUS XXXX DAMAGE XXX.\" (bit-7 terminated) - a rules summary line whose XXXX and XXX fields are overwritten in place by the $6F00 overlays ($870C, $8739-$8751) with OFF,/ON, and FULL/HALF/NONE before it is printed."
  },
  {
   "addr": "064D",
   "length": 17,
   "type": "text",
   "name": "optionWordTable",
   "description": "Five bit-7 terminated words at fixed offsets, copied into optionSummaryTemplate: +0 \"OFF\", +3 \"ON\", +5 \"FULL\", +9 \"HALF\", +13 \"NONE\". XREF.txt calls this label eaCopyrightMessage, which is wrong (that name belongs to the boot-time `ea` file that once occupied $02A8-$030B)."
  },
  {
   "addr": "065E",
   "length": 10,
   "type": "text",
   "name": "msgClicks",
   "description": "\"   CLICKS:\" - the score header printed by $C6BC (LDA #$5E / LDY #$06 / JSR $C133). \"Clicks\" are Modem Wars' score unit."
  },
  {
   "addr": "0668",
   "length": 7,
   "type": "text",
   "name": "msgUs",
   "description": "\"    US:\" - printed straight after msgClicks, followed by the local player's 16-bit score from $92A2/$92A4."
  },
  {
   "addr": "066F",
   "length": 8,
   "type": "text",
   "name": "msgThem",
   "description": "\"   THEM:\" - the opponent's score label, printed by the same $C6B6 routine."
  },
  {
   "addr": "0677",
   "length": 40,
   "type": "text",
   "name": "msgTypeMapName",
   "description": "Three lines separated by $0D: \"TYPE MAP NAME\" / \" (F7 RANDOM)\" / \" (F5 SYM/RND)\" - the prompt of the map name editor in overlay A, also used by the manual look-up protection at $09EF."
  },
  {
   "addr": "069F",
   "length": 27,
   "type": "text",
   "name": "msgBtnToAccept",
   "description": "Two lines separated by $0D: \"BTN TO ACCEPT\" / \"(F 1 TO FLIP)\" - shown while the generated map is offered for acceptance."
  },
  {
   "addr": "0770",
   "length": 40,
   "type": "byteTable",
   "name": "tileVariantMaskTable",
   "description": "Indexed by map cell value minus $40 (cells below $40 use cell-$20), covering cells $40-$67. The value is ANDed with a scenario random number and added to the base tile by randomTileVariant ($7872, overlay A): cells $49, $4B and $65 -> mask 1; cells $4D, $51, $59, $5D, $61 -> mask 3; everything else 0."
  },
  {
   "addr": "0798",
   "length": 1,
   "type": "unknown",
   "name": "tileVariantPad",
   "description": "$00 pad between tileVariantMaskTable and unitGlyphBaseTable."
  },
  {
   "addr": "0799",
   "length": 6,
   "type": "byteTable",
   "name": "unitGlyphBaseTable",
   "description": "Base glyph index of the one-character overview symbol per unit type: $2C GRUNT, $30 RIDER, $34 BOOMER, $38 SPY, $3C COMCEN (plus one $00 pad). The facing (unitFlags AND 3) is added; the result indexes the 8x8 shapes at $9C6E + code*8, and, doubled after subtracting $2C, the 16x16 glyph pointer tables ($28A0, $6C35, $7512, $7538)."
  },
  {
   "addr": "079F",
   "length": 75,
   "type": "byteTable",
   "name": "terrainClassTable",
   "description": "Map cell value -> terrain class 0-8. Addressed as $077E,Y with the raw cell value, so the body runs from $077E+$21 = $079F to $077E+$6B = $07E9: cells $21-$34 -> 3 (lower contour), $35-$3F -> $FF (invalid), $40 -> 0 (blank), $41-$54 -> 5 (upper contour), $55-$5C -> 1 (river), $5D-$60 -> 2 (forest), $61-$64 -> 4 (lower hill), $65-$66 -> 6 (summit), $67 -> 7 (recycler), $68-$6B -> 8 (end zone). The same bytes are read as $07BE,X by $5BC8 with the index already reduced to cell-$40. The trainer also reads it as terrainClassTable $077E from $E773."
  },
  {
   "addr": "07EA",
   "length": 9,
   "type": "byteTable",
   "name": "terrainColourTable",
   "description": "Colour-RAM nibble per terrain class 0-8: 7,3,5,8,8,8,8,0,0 (yellow plain, cyan river, green forest, orange for every contour/hill/summit class, black for classes 7-8). Read at $27AB and $5BCB immediately after a terrainClassTable lookup."
  },
  {
   "addr": "07F3",
   "length": 13,
   "type": "unknown",
   "name": "table0400Tail",
   "description": "$00 filler to the end of the page; unreferenced."
  }
 ],
 "misclassified": [],
 "insights": [
  "$0548 chat line placeholder (35 spaces)",
  "$056C \"WORKING...\"",
  "$0576 \"GAME ABORTED.\"",
  "$0583 \"NOT A GAME FILM!\"",
  "$0593 \"SETUP UNITS. PRESS F 1 WHEN DONE.\"",
  "$05B4 \"TIMEOUT. RUN/STOP TO RESUME.\"",
  "$05D0 \"RESUMED\"",
  "$05D7 \"THE BATTLE BEGINS!\"",
  "$05E9 \"LAST QTR WARNING!\"",
  "$05FA \"PHONE TROUBLE.\"",
  "$0608 \"TRY AGAIN.\"",
  "$0636 \" MENUS XXXX DAMAGE XXX.\" (template, fields overwritten in place)",
  "$064D \"OFF\" / \"ON\" / \"FULL\" / \"HALF\" / \"NONE\" (five words at +0/+3/+5/+9/+13)",
  "$065E \"   CLICKS:\"",
  "$0668 \"    US:\"",
  "$066F \"   THEM:\"",
  "$0677 \"TYPE MAP NAME\" CR \" (F7 RANDOM)\" CR \" (F5 SYM/RND)\"",
  "$069F \"BTN TO ACCEPT\" CR \"(F 1 TO FLIP)\"",
  "Complete message id map, decoded from messagePtrLoTable/HiTable + messageSoundTable: $00 chat line ($0548, silent), $01 WORKING... ($056C, silent), $02 END OF FILM. ($8707, snd 3), $03 GAME ABORTED. ($0576, 3), $04 OPPONENT READY. ($8858, 3), $05 UNIT RECYCLED. ($8713, 4), $06/$07 SHOW ****/SPEED * ($8721/$872A, 3), $08 SPOTTED RECYCLER! ($8731, 4), $09 NOT A GAME FILM! ($0583, 3), $0A SETUP UNITS. PRESS F 1 WHEN DONE. ($0593, silent), $0B WAITING FOR OPPONENT... ($8867, 3), $0C COMCEN STUNNED! ($8742, 4), $0D SPOTTED ENEMY COMCEN! ($8751, 4), $0E SPY UNDER ATTACK! ($8766, 4), $0F SPOTTED ENEMY SPY! ($8777, 4), $10 WAITING FOR CONNECTION... ($887E, silent), $11 WE LOST ON POINTS! ($8789, $0E), $12 WE WON ON POINTS! ($879B, $0D), $13 IT WAS A DRAW. ($87AC, silent), $14 WE WERE KNOCKED OUT! ($87BA, $0E), $15 WE WON BY A KNOCKOUT! ($87CE, $0D), $16 GAME OVER. ($87E3, $19), $17 PICK UP PHONE THEN PRESS SPACE. ($8897, 6), $18 PRESS SPACE, WAIT, HANGUP PHONE. ($88B6, 6), $19 TIMEOUT. RUN/STOP TO RESUME. ($05B4, $19), $1A OPPONENT PICKING GAME/MAP. ($88D6, 3), $1B RESUMED ($05D0, $19), $1C THE BATTLE BEGINS! ($05D7, 3), $1D LAST QTR WARNING! ($05E9, $19), $1E unset ($FFFF, 3), $1F OPPONENT READY FOR NEW GAME. ($88F0, silent), $20/$21 unset ($FFFF) and patched at run time, $22 PHONE TROUBLE. ($05FA, $15), $23 TRY AGAIN. ($0608, 3). The $87xx strings live in the $6F00 overlay variant B.",
  "The terrain data model is entirely in this block: terrainClassTable maps the raw cell code to one of nine classes, terrainColourTable gives the colour-RAM nibble per class, tileVariantMaskTable gives the random variation mask per base tile, and unitGlyphBaseTable maps the five unit types to their symbol. Every cell code $21-$34 has the same class as $41-$54 shifted by $20, which is the contour offset the map generator uses ($0324 contourTileOffset).",
  "Only two of the nine terrain classes get a distinct colour: everything from class 3 to class 6 (contours, hills, summit) is drawn orange ($08), so the elevation rings differ only in shape.",
  "The label eaCopyrightMessage that XREF.txt attaches to $064D is stale - the `ea` boot file lived at $02A8-$030B, not here. $064D is optionWordTable (OFF/ON/FULL/HALF/NONE).",
  "D_0410/D_0420/D_0430/D_0432/D_0450/D_0464 inside mapNameSeedTable and D_04C8/D_04C9/D_04D0/D_04D1/D_04DF/D_04E7 inside scratchPageTail are run-time scratch addresses (unit scan lists, group scratch, the 2x2 tile buffer), not fields of the tables the disk holds there.",
  "$0400-$04FF is not stable data at all: only $0500-$07FF survives a game session. The page is successively the protection table + checksum routine, the BAM buffer for checkDiskId, the 512-byte RLE sprite buffer, overlay A's map-generator variables, the film directory, and the trainer's playbook."
 ]
}
