153 lines
11 KiB
JSON
Generated
153 lines
11 KiB
JSON
Generated
{
|
|
"chunk": "data_main_0800",
|
|
"unit": "game/main_0800",
|
|
"routines": [],
|
|
"variables": [],
|
|
"dataBlocks": [
|
|
{
|
|
"addr": "1DA2",
|
|
"length": 66,
|
|
"type": "byteTable",
|
|
"name": "scrollViewParamTables",
|
|
"description": "Twenty-two parallel 3-byte tables (one entry per direction: 0 = -1, 1 = 0, 2 = +1) that parameterise scrollViewBitmap ($1DE4), which shifts the 7x5-cell tactical view one cell without redrawing it. In order: $1DA2 bitmap copy start index ($5F,$00,$00), $1DA5 end index ($FF,$70,$60), $1DA8 the DEY/INY opcode patched into both copy loops ($88,$C8,$C8), $1DAB/$1DAE bitmap source and destination byte offsets (0,0,$10 / $10,0,0), $1DB1/$1DB4 bitmap source address lo/hi ($AAC8,$A208,$A488), $1DB7/$1DBA bitmap destination lo/hi ($AD48,$A208,$A208), $1DBD/$1DC0 bitmap row stride lo/hi ($FEC0 = -320 up, $0140 = +320), $1DC3 rows to copy (8,10,8), $1DC6/$1DC9 screen copy start/end index, $1DCC/$1DCF screen source/destination column offsets, $1DD2/$1DD5 screen source lo/hi ($8D59,$8C41,$8C91), $1DD8/$1DDB screen destination lo/hi ($8DA9,$8C41,$8C41) and $1DDE/$1DE1 screen row stride lo/hi ($FFD8 = -40 up, $0028 = +40). Colour RAM is handled by adding $4C to the screen high byte."
|
|
},
|
|
{
|
|
"addr": "2BDD",
|
|
"length": 27,
|
|
"type": "byteTable",
|
|
"name": "windowLeftTable",
|
|
"description": "Left screen column of the 27 predefined windows 0-26, read by drawWindowFrame with X = window index. 0 = the overview panel (column 0), 1 = the tactical view (column $18), 2 = the status panel, 5-$16 the $6F00 overlay screens, $18/$19 the main menu frames."
|
|
},
|
|
{
|
|
"addr": "2BF8",
|
|
"length": 27,
|
|
"type": "byteTable",
|
|
"name": "windowTopTable",
|
|
"description": "Top screen row of windows 0-26."
|
|
},
|
|
{
|
|
"addr": "2C13",
|
|
"length": 27,
|
|
"type": "byteTable",
|
|
"name": "windowWidthTable",
|
|
"description": "Width in character cells including the frame: window 0 is $16 = 22 wide (the 20x20 overview map plus its frame), window 1 is $10 = 16 (the 7x5-cell tactical view at 2 cells per map cell plus frame), window $18 is the full 40 columns."
|
|
},
|
|
{
|
|
"addr": "2C2E",
|
|
"length": 27,
|
|
"type": "byteTable",
|
|
"name": "windowHeightTable",
|
|
"description": "Height in character cells of windows 0-26 (window 0 = $16 = 22, window 1 = $0C = 12)."
|
|
},
|
|
{
|
|
"addr": "2C49",
|
|
"length": 54,
|
|
"type": "addrTable",
|
|
"name": "windowFramePtrTable",
|
|
"description": "27 little-endian pointers selecting each window's 9-byte frame tile set out of the ten sets at $9824-$987D in the graphics block. Windows 0-3 use the four decorated sets $985A/$9863/$986C/$9875, the rest reuse $9824 (thin box), $982D, $9836 (octagon), $983F (shadowed), $9848 (solid) and $9851 (blank/erase)."
|
|
},
|
|
{
|
|
"addr": "5A59",
|
|
"length": 33,
|
|
"type": "byteTable",
|
|
"name": "overviewPatternLo",
|
|
"description": "Low bytes of the overview-map pattern pointer for terrain index $00-$20 (33 entries), read by buildOverviewQuadrant at $5C40 with Y = mapCell - $40, or mapCell - $20 when the cell is below $40, clamped below $21 ($5BC3). Index 0 (blank ground) -> $5A9B; indices 1-8 cycle through the four contour-edge patterns $5A9F/$5AA3/$5AA7/$5AAB; 9-$0C -> $5AAF; $0D-$14 -> $5AB3; $15-$18 (river cells $55-$58) -> $5AC7/$5ACB/$5ACF/$5AD3; $19-$1C -> $5AC3; $1D-$20 (forest cells $5D-$60) -> $5ABB."
|
|
},
|
|
{
|
|
"addr": "5A7A",
|
|
"length": 33,
|
|
"type": "byteTable",
|
|
"name": "overviewPatternHi",
|
|
"description": "High bytes of the same 33 pointers - all $5A, because every pattern lives in this block."
|
|
},
|
|
{
|
|
"addr": "5A9B",
|
|
"length": 60,
|
|
"type": "byteTable",
|
|
"name": "overviewPatterns",
|
|
"description": "Fifteen patterns of four bitmap scanline bytes each. The overview draws each 2x2 block of map cells as one 8x8 character, so a pattern carries both horizontal halves as nibble pairs ($00/$33/$CC/$FF) and the quadrant mask picks the half that belongs to the cell. Contents: $5A9B 00 00 00 00 (blank), $5A9F 00 00 33 33, $5AA3 00 CC 33 33, $5AA7 33 00 00 00, $5AAB 33 CC 00 00 (the four contour edges), $5AAF 33 33 33 33, $5AB3 00 FF 00 00, $5AB7 FF FF FF FF (a live unit), $5ABB 33 CC 33 CC (forest checker), $5ABF FF 00 FF 00 (a cloaked unit), $5AC3 CC FF FF 33, $5AC7 33 FF FF FF, $5ACB CC FF FF FF, $5ACF FF FF FF 33, $5AD3 FF FF FF CC (the four river blob quadrants). $5AB7 and $5ABF are the only two not reachable through overviewPatternLo/Hi - buildOverviewQuadrant uses them directly for units."
|
|
},
|
|
{
|
|
"addr": "6782",
|
|
"length": 5,
|
|
"type": "byteTable",
|
|
"name": "sidVoiceRegOffsetTable",
|
|
"description": "SID register offset per voice, indexed by voice*2 so the driver can use the same X for its own state and for the chip: $00, (pad), $07, (pad), $0E."
|
|
},
|
|
{
|
|
"addr": "6787",
|
|
"length": 11,
|
|
"type": "byteTable",
|
|
"name": "sndCommandSlotTable",
|
|
"description": "Sound-script command 0-10 -> byte offset of its state slot from sndVoiceState ($6792): 0 duration ($00, also ends processing), 1 control/waveform ($01), 2 loop counter A ($06), 3 loop counter B ($07), 4/5 spare ($0C/$0D), 6 frequency ($12, 2 bytes), 7 pulse width ($18, 2), 8 AD/SR ($1E, 2), 9 frequency delta ($24, 2), 10 pulse delta ($2A, 2). runSoundScript adds voice*2 to the entry and treats every slot from $12 up as 16-bit ($66DF CPY #$12)."
|
|
},
|
|
{
|
|
"addr": "6792",
|
|
"length": 48,
|
|
"type": "byteTable",
|
|
"name": "sndVoiceState",
|
|
"description": "Work RAM, zero on disk: eight 6-byte rows of per-voice sound state (duration, control, loop counters, spares, frequency, pulse width, ADSR, and the two deltas), cleared per voice by startSound."
|
|
},
|
|
{
|
|
"addr": "67C2",
|
|
"length": 6,
|
|
"type": "byteTable",
|
|
"name": "sndDriverVars",
|
|
"description": "Work RAM, zero on disk: sndVolume, sndLastByte ($67C3, the current script byte), sndScratch, sndInitLock, sndCurrentSound, sndStartVoiceIndex."
|
|
},
|
|
{
|
|
"addr": "67C8",
|
|
"length": 3,
|
|
"type": "byteTable",
|
|
"name": "sndVoiceSoundId",
|
|
"description": "Work RAM, zero on disk: the sound id currently playing on each of the three voices (0 = free). $67CA is polled by the text engine at $C909/$C913 before it plays a UI beep."
|
|
},
|
|
{
|
|
"addr": "6831",
|
|
"length": 174,
|
|
"type": "wordTable",
|
|
"name": "soundPointerTable",
|
|
"description": "29 sound effects x three little-endian voice-script addresses (6 bytes per sound, $0000 = the sound does not use that voice). Sound $00 points all three voices at the 60-tick silence script $68DF (stop everything) and $1A/$1B/$1C silence voice 0/1/2 individually. Multi-voice effects are $06 ($6980/$69C9/$68DF), $0D ($6AA7/$6AB5/$6AC3), $0E ($6ADC/$6AEC/$6AFC), $15 ($68E7/$68F0/$68DF) and $19 ($6BFB/$6C15/$6C1B). Sounds $01-$07 and $0C use voice 0, $08-$0B voice 1 and $0F-$18 voice 2. messageSoundTable ($0612) picks the sound played with each status message."
|
|
},
|
|
{
|
|
"addr": "68DF",
|
|
"length": 854,
|
|
"type": "byteTable",
|
|
"name": "soundScriptData",
|
|
"description": "The bytecode for all the voice scripts, in the format interpreted by runSoundScript ($66C7): a byte $00-$0A stores the following one or two bytes into the state slot named by sndCommandSlotTable (slot 0 = duration ends the frame, duration 0 ends the voice); $40-$7F is a loop whose low six bits select a counter slot and which is followed by a 16-bit target address; $80-$FF adds the scenario random byte zp_5A to the frequency low byte (noise jitter). $68DF is the shared 60-tick silence script and $68E3 ('01 00 00 00') is the common end-of-sound target that the many '46 E3 68' jumps branch to."
|
|
},
|
|
{
|
|
"addr": "6C35",
|
|
"length": 40,
|
|
"type": "addrTable",
|
|
"name": "unitGlyphPointerTable",
|
|
"description": "20 little-endian pointers to the 32-byte unit glyphs that follow, indexed by unitType*4 + facing - the caller computes (unitFlags AND 3) + unitGlyphBaseTable[$0799 + unitType] - $2C and doubles it."
|
|
},
|
|
{
|
|
"addr": "6C5D",
|
|
"length": 640,
|
|
"type": "charset",
|
|
"name": "unitGlyphShapes",
|
|
"description": "20 multicolour unit glyphs of 16x16 pixels, 32 bytes each, stored as four 8-byte character cells in the order top-left, top-right, bottom-left, bottom-right. Every lit pixel is the bit pair %11, so the byte values are combinations of $00/$03/$0C/$30/$C0/$33/$3C/$F0/$FC/$FF. The 20 shapes are five unit types x four facings, all clearly recognisable when rendered: 0-3 GRUNT (a stubby figure with a head, up/down/left/right), 4-7 RIDER (a mounted figure with a wide base), 8-11 BOOMER (a heavy block with a protruding barrel), 12-15 SPY (a small chevron/arrow), 16-19 COMCEN (a large domed block). These are the big glyphs used in the 16x16-per-cell tactical view; the single-cell versions are the 8x8 shapes at $9DCE."
|
|
},
|
|
{
|
|
"addr": "6EDD",
|
|
"length": 35,
|
|
"type": "unknown",
|
|
"name": "mainProgramPadding",
|
|
"description": "$6EDD-$6EFF, all zero: filler to the end of the main program image (track 22-27). Unreferenced."
|
|
}
|
|
],
|
|
"misclassified": [],
|
|
"insights": [
|
|
"There are no message strings in any of the pure-data tails of the main program - all of the game's text lives in the $0400 block, the $8800 block, the $C000 overlay and the $6F00 overlays.",
|
|
"The 20 big unit glyphs at $6C5D and the 20 small ones at $9DCE are the same five types x four facings, reached through the same index arithmetic (unitGlyphBaseTable $0799 + facing): the tactical view uses the 16x16 multicolour pair table at $6C35, the overview map and the radar screens use the 8x8 one-bit shapes at $9C6E + code*8.",
|
|
"The sound system is a three-voice bytecode interpreter: 29 sounds x 3 voice scripts in a pointer table ($6831), 854 bytes of script ($68DF-$6C34), an 11-entry command/slot map ($6787), a 3-entry SID register offset table ($6782) and 54 bytes of work RAM ($6792-$67C7). Scripts can loop with two counters and add RNG jitter to the frequency, which is how the engine gets varied explosion noises out of so little data.",
|
|
"scrollViewBitmap never redraws the tactical view when the cursor moves one cell: it block-copies the bitmap, screen RAM and colour RAM by one cell using self-modified loops whose 22 parameters (including the DEY/INY opcode itself) come from the table group at $1DA2, then fills in only the newly exposed column and/or row.",
|
|
"The 27 windows the game can draw are fully data-driven: left/top/width/height at $2BDD/$2BF8/$2C13/$2C2E and a frame style pointer at $2C49 that selects one of ten 9-glyph tile sets in the graphics block. Window 0 is the 22x22 overview frame and window 1 the 16x12 tactical frame.",
|
|
"The strategic overview compresses two map cells per character in each axis, so each of the 33 terrain indices maps to a 4-byte pattern that already contains both horizontal halves; only 15 distinct patterns exist ($5A9B-$5AD6), including a solid $FF blob for a live unit and an $FF/$00 stripe for a cloaked one, which are the only two the index table never points at.",
|
|
"$6792-$67CA is described in the listing as five byteTables; on disk it is all zero and at run time it is the sound driver's work RAM (eight 6-byte voice-state rows plus nine scalars), not table data. The individual D_6793..D_67CA labels are its fields.",
|
|
"The $1DA2-$1DE3 tables are named individually in the listing but they are one column-store: 22 parallel arrays indexed by the same direction value 0-2, all consumed by the single routine scrollViewBitmap.",
|
|
"$6C35 is listed as pointing at 'the 32-byte unit glyphs below' with only the first target named (unitGlyphShapes); the other 19 targets ($6C7D..$6EBD) have no labels at all."
|
|
]
|
|
}
|