modemwars/disassembly/game/unitStartTemplatesF000.s
2026-08-23 02:09:40 -05:00

426 lines
34 KiB
ArmAsm

; ============================================================================
; $F000-$F6FF - unit start-position templates (track 18 sectors 8-14)
; ============================================================================
; What is STORED here is four 400-byte templates at $F000, $F190, $F320 and $F4B0; each is four parallel
; 100-entry arrays - starting column, starting row, flags (facing in bits 0-1, side in bit 5, grouped in
; bit 6, group id in bits 2-4) and unit type. One template is chosen per game type and copied into the
; live unit arrays. The standard roster is 28 GRUNT, 12 RIDER, 6 BOOMER, 3 SPY and 1 COMCEN per side.
; What the same addresses hold at RUN TIME is different: $F000-$F63F becomes the 40x40 battlefield map
; (one byte per cell) and the unit record arrays start at $F640 in 100-byte slices, so the templates are
; overwritten as soon as a game starts.
; The 192 bytes at $F640-$F6FF are not used at all: they are a fragment of an older build of the game's
; own options-list printer, left in the sector by the development system.
.setcpu "6502"
.include "c64.inc"
.include "zeropage.inc"
.org $F000
; unitStartTemplatesF000 - the whole file. Track 18 sectors 8-14 hold pure data: four 400-byte unit
; start-position templates at $F000, $F190, $F320 and $F4B0, followed by 192 bytes at $F640-$F6FF that
; are not data at all but a fragment of an older build's code (see the note there). Nothing in this
; file is a battlefield: the 40x40 map that occupies $F000-$F63F at run time is built from the 24-bit
; map seed by generateBattlefieldMap ($6F04) and overwrites all four templates before the first frame.
; Loaded by loadMapAndSetup ($10AB): setLoadDest $F000, then 7 sectors from track 18 sector 8, once
; per session from startGameFromSetup ($0B35). Read by exactly one routine, loadUnitStartTemplate
; ($ECF3, in the comm tail that track 34 sectors 12-15 put at $EC00), which overlay A calls at $79E6
; and $82FD: n = unitLayoutByGameType[$78B8 + (gameTypeOptions $0BA3 & 7)] = 2,2,2,1,3,0,0 for game
; types 0-6, and it then copies two whole pages (512 bytes) from $F000 + 400*n to $F640, where the
; live unit records begin. Only the first 400 bytes are the template; the extra 112 bytes overwrite
; unitDestCol ($F7D0-$F833) and the first twelve entries of unitDestRow ($F834-$F83F), which
; initAllUnits rewrites at once, so the spill is harmless. For templates 0-2 the spill is the head of
; the next template; for template 3 the source ($F4B0-$F6AF) overlaps the destination ($F640-$F83F)
; and, because the copy runs upwards, it re-reads what it has just written and duplicates template 3's
; own first 112 bytes - which is also why the leftover code at $F640-$F6AF is destroyed before it
; could ever be read as data. The copy is guarded by 'bit 7 of $F640 set' = 'the arrays still hold the
; disk image'. As loaded from disk $F640 is $0A (an opcode of the leftover code), which fails that
; test, so startGameSession stores $FF there first ($78E4). Game type -> template: 0 SCRIMAGE, 1 QB
; SNEAK, 2 THE BOMB -> template 2; 3 FACE-OFF -> template 1; 4 SLUGGERS -> template 3; 5 FULL WAR, 6
; DEFENDER -> template 0. (There is no game type 7; it would index $78BF = $04 and copy from $F000 +
; 1600 = $F640.) Each template is four parallel 100-entry arrays - +$000 starting column, +$064
; starting row, +$0C8 flags, +$12C type - i.e. exactly the first four of the fourteen 100-byte
; unit-record arrays that live from $F640 upwards $64 apart. Entry i describes unit i: 0-49 side 0,
; 50-99 side 1, 49 and 99 the two COMCENs. Coordinates are cells of the 40x40 field: columns 3-36,
; side 0 in the bottom half (rows 20-33), side 1 in the top half (rows 6-19). Player 1's machine
; rotates the map and every unit coordinate to 39-x (rotateMapAndMirrorCodes $EC58,
; mirrorAllUnitCoordinates $EC91), so both players see their own army at the bottom. How much of a
; template survives the copy: initAllUnits ($3D8A) -> initUnitRecord ($3DA0) keeps the column, the
; row, flags bits 2-4 (group id) and bit 6 (belongs to a group), and type bits 0-2 (the unit type)
; plus bit 7 ($FF = empty slot). It rebuilds the facing (flags bits 0-1) and the side (flags bit 5)
; from the unit index and clears type bits 3-4, so those bits of the stored data are consistent with
; the rest but are never actually used. unitStartTemplate0 ($F000-$F18F) - the full roster, used by
; game types 5 FULL WAR and 6 DEFENDER. All 100 slots are in play: per side 28 GRUNT (units 0-27), 12
; RIDER (28-39), 6 BOOMER (40-45), 3 SPY (46-48) and 1 COMCEN (49). Three wings, each an eleven-unit
; group of nine grunts and two boomers in rows 25-28 with a four-rider group in front of it in rows
; 30-31. Side 0: group 3 DELTA = units 4,7,10,11,14,15,18,19,20,40,44 on the left (columns 3-7),
; group 4 EASY = 1,2,3,13,16,17,22,23,27,41,45 in the centre (17-21), group 5 FOXTROT =
; 0,5,8,9,12,21,24,25,26,42,43 on the right (32-36); rider group 0 ALPHA = 28,29,30,32 (columns 5-6),
; 1 BAKER = 31,33,34,37 (19-20), 2 CHARLIE = 35,36,38,39 (33-34). Loose (flags $00): the three spies
; 46-48 in row 23, and in the back row 33 the COMCEN 49 at column 20 with one GRUNT, unit 6, beside it
; at column 19. Side 1 is the exact 180-degree mirror of side 0 as a formation - every
; (column,row,type,group) of side 0 occurs on side 1 as (39-column, 39-row, same type, same group) -
; but the indices within a group are not mirrored, so unit i+50 is not the mirror image of unit i.
unitStartTemplate0:
.byte $22,$13,$11,$13,$04,$23,$13,$03,$24,$21; F000 "....#..$! unitCol[0-49]: side 0's starting map column, ten units per row; the last entry is the COMCEN
.byte $05,$07,$21,$12,$06,$05,$14,$13,$04,$06; F00A ..!.......
.byte $05,$22,$14,$12,$22,$20,$23,$15,$06,$05; F014 .".." #...
.byte $06,$13,$05,$13,$14,$22,$22,$14,$21,$21; F01E ....."".!!
.byte $06,$14,$21,$23,$04,$12,$13,$22,$05,$14; F028 ..!#..."..
.byte $06,$07,$23,$05,$04,$03,$22,$22,$06,$12; F032 ..#..."".. unitCol[50-99]: side 1's columns; the last entry is unit 99, side 1's COMCEN
.byte $15,$16,$13,$14,$21,$13,$04,$24,$14,$23; F03C ....!..$.#
.byte $22,$21,$20,$15,$05,$14,$05,$14,$22,$21; F046 "! ....."!
.byte $14,$13,$14,$22,$21,$05,$05,$06,$06,$13; F050 ..."!.....
.byte $13,$23,$21,$15,$04,$06,$22,$14,$05,$13; F05A .#!..."...
; unitRow - array 2 of 4 ($F064-$F0C7): the starting map row 0-39 of each unit, copied to unitRowTable
; $F6A4. Side 0 occupies rows 23-33 in this template and side 1 the mirrored rows 6-16.
template0StartRow:
.byte $1B,$19,$1B,$1A,$1A,$1B,$21,$1B,$1B,$1A; F064 ......!... unitRow[0-49]: side 0's rows, the bottom half of the field
.byte $19,$1B,$1B,$1A,$1B,$1A,$1A,$1B,$1B,$1A; F06E ..........
.byte $1B,$19,$1B,$1B,$1A,$1B,$1A,$1B,$1F,$1E; F078 ..........
.byte $1E,$1F,$1F,$1E,$1E,$1F,$1E,$1F,$1F,$1E; F082 ..........
.byte $1C,$1C,$1C,$1C,$1C,$1C,$17,$17,$17,$21; F08C .........!
.byte $0D,$0C,$0D,$0C,$0D,$0C,$0E,$0D,$0C,$0C; F096 .......... unitRow[50-99]: side 1's rows, the 39-row mirror of side 0's
.byte $0C,$0C,$0D,$0C,$0D,$0C,$0C,$0C,$06,$0C; F0A0 ..........
.byte $0C,$0C,$0C,$0D,$0D,$0E,$0E,$0D,$09,$09; F0AA ..........
.byte $08,$09,$09,$08,$08,$09,$08,$09,$08,$08; F0B4 ..........
.byte $0B,$0B,$0B,$0B,$0B,$0B,$10,$10,$10,$06; F0BE ..........
; unitFlags - array 3 of 4 ($F0C8-$F12B): bits 0-1 facing (0 = up, 1 = down), bits 2-4 group id 0-6 =
; ALPHA, BAKER, CHARLIE, DELTA, EASY, FOXTROT, GROVER (names at $C92C), bit 5 side, bit 6 = belongs to
; a group, bit 7 (the blitz charge at run time) always 0 here. So a side-0 entry is $00 when loose
; and $40 + 4*g in group g; a side-1 entry is $21 when loose and $61 + 4*g in group g. Copied to
; unitFlagsTable $F708; initUnitRecord ($3DC6) keeps only bits 2-4 and 6 and rebuilds facing and side
; from the unit index, so the group id and the group-member bit are the only part that matters.
template0StartFlags:
.byte $54,$50,$50,$50,$4C,$54,$00,$4C,$54,$54; F0C8 TPPPLT.LTT unitFlags[0-49]: side 0 - $00 loose, $40/$44/$48/$4C/$50/$54 = groups ALPHA..FOXTROT
.byte $4C,$4C,$54,$50,$4C,$4C,$50,$50,$4C,$4C; F0D2 LLTPLLPPLL
.byte $4C,$54,$50,$50,$54,$54,$54,$50,$40,$40; F0DC LTPPTTTP@@
.byte $40,$44,$40,$44,$44,$48,$48,$44,$48,$48; F0E6 @D@DDHHDHH
.byte $4C,$50,$54,$54,$4C,$50,$00,$00,$00,$00; F0F0 LPTTLP....
.byte $75,$75,$6D,$75,$75,$75,$6D,$6D,$75,$71; F0FA uumuuummuq unitFlags[50-99]: side 1 - $21 loose, $61/$65/$69/$6D/$71/$75 = the same six groups
.byte $71,$71,$71,$71,$6D,$71,$75,$6D,$21,$6D; F104 qqqqmqum!m
.byte $6D,$6D,$6D,$71,$75,$71,$75,$71,$61,$61; F10E mmmququqaa
.byte $65,$65,$65,$61,$61,$69,$69,$69,$69,$65; F118 eeeaaiiiie
.byte $71,$6D,$6D,$71,$75,$75,$21,$21,$21,$21; F122 qmmquu!!!!
; unitType - array 4 of 4 ($F12C-$F18F): $10 + type for a side-0 unit and $18 + type for a side-1
; unit, type 0 GRUNT, 1 RIDER, 2 BOOMER, 3 SPY, 4 COMCEN (names at $C964); $FF marks a slot that is
; not in play. Copied to unitTypeTable $F76C. At run time bits 3-4 of this byte are the 'has already
; scored that end zone' markers and bit 6 is 'dug in', but initUnitRecord ($3DB9) clears bits 3-4
; while it resets each unit, so of the stored value only bits 0-2 and the $FF (bit 7 =
; destroyed/empty, tested by placeUnitOnMap at $3E11) ever reach the engine.
template0StartType:
.byte $10,$10,$10,$10,$10,$10,$10,$10,$10,$10; F12C .......... unitType[0-49]: side 0 - $10 GRUNT, $11 RIDER, $12 BOOMER, $13 SPY, $14 COMCEN; 28/12/6/3/1
.byte $10,$10,$10,$10,$10,$10,$10,$10,$10,$10; F136 ..........
.byte $10,$10,$10,$10,$10,$10,$10,$10,$11,$11; F140 ..........
.byte $11,$11,$11,$11,$11,$11,$11,$11,$11,$11; F14A ..........
.byte $12,$12,$12,$12,$12,$12,$13,$13,$13,$14; F154 ..........
.byte $18,$18,$18,$18,$18,$18,$18,$18,$18,$18; F15E .......... unitType[50-99]: side 1 - $18 GRUNT .. $1C COMCEN; the same roster as side 0
.byte $18,$18,$18,$18,$18,$18,$18,$18,$18,$18; F168 ..........
.byte $18,$18,$18,$18,$18,$18,$18,$18,$19,$19; F172 ..........
.byte $19,$19,$19,$19,$19,$19,$19,$19,$19,$19; F17C ..........
.byte $1A,$1A,$1A,$1A,$1A,$1A,$1B,$1B,$1B,$1C; F186 ..........
; unitStartTemplate1 ($F190-$F31F) - used by game type 3 FACE-OFF only. Roster per side: 28 RIDER
; (units 0-27), 3 SPY (46-48), 1 COMCEN (49); slots 28-45 are empty ($FF in the type array). The
; riders form seven 2x2 squads, one per group name, drawn up in a single line: side 0 groups 0 ALPHA
; .. 6 GROVER occupy rows 22-23 at columns 22-23, 19-20, 16-17, 13-14, 10-11, 7-8 and 4-5, with the
; three spies in row 21 at columns 5, 14 and 23 and the COMCEN at (14,25). Side 1 is the exact
; per-index 180-degree mirror: unit i+50 stands at (39-column, 39-row) of unit i and carries the same
; type and the same group id. The 18 empty slots on each side still carry column and row bytes, which
; are dead data - they are verbatim runs of template 0: entries 28-45 repeat template 0's entries 7-24
; and entries 78-95 repeat template 0's entries 57-74, in both the column and the row array. Their
; flag bytes were cleaned to $00 / $21. Only the $FF in the type array is read.
unitStartTemplate1:
.byte $16,$17,$16,$17,$13,$14,$13,$14,$10,$11; F190 .......... unitCol[0-49] of template 1: entries 28-45 are dead slots, entry 49 the COMCEN
.byte $10,$11,$0D,$0E,$0D,$0E,$0A,$0B,$0A,$0B; F19A ..........
.byte $07,$08,$07,$08,$04,$05,$04,$05,$03,$24; F1A4 .........$
.byte $21,$05,$07,$21,$12,$06,$05,$14,$13,$04; F1AE !..!......
.byte $06,$05,$22,$14,$12,$22,$05,$0E,$17,$0E; F1B8 ..".."....
.byte $11,$10,$11,$10,$14,$13,$14,$13,$17,$16; F1C2 .......... unitCol[50-99]: side 1's columns; entries 78-95 dead, entry 99 the COMCEN
.byte $17,$16,$1A,$19,$1A,$19,$1D,$1C,$1D,$1C; F1CC ..........
.byte $20,$1F,$20,$1F,$23,$22,$23,$22,$22,$06; F1D6 . .#"#"".
.byte $12,$15,$16,$13,$14,$21,$13,$04,$24,$14; F1E0 .....!..$.
.byte $23,$22,$21,$20,$15,$05,$22,$19,$10,$19; F1EA #"! .."...
template1StartRow:
.byte $16,$16,$17,$17,$16,$16,$17,$17,$16,$16; F1F4 .......... unitRow[0-49] (see $F064): rider line rows 22-23, spies row 21, COMCEN row 25
.byte $17,$17,$16,$16,$17,$17,$16,$16,$17,$17; F1FE ..........
.byte $16,$16,$17,$17,$16,$16,$17,$17,$1B,$1B; F208 ..........
.byte $1A,$19,$1B,$1B,$1A,$1B,$1A,$1A,$1B,$1B; F212 ..........
.byte $1A,$1B,$19,$1B,$1B,$1A,$15,$15,$15,$19; F21C ..........
.byte $11,$11,$10,$10,$11,$11,$10,$10,$11,$11; F226 .......... unitRow[50-99]: side 1 - rider line 16-17, spies 18, COMCEN 14
.byte $10,$10,$11,$11,$10,$10,$11,$11,$10,$10; F230 ..........
.byte $11,$11,$10,$10,$11,$11,$10,$10,$0D,$0C; F23A ..........
.byte $0C,$0C,$0C,$0D,$0C,$0D,$0C,$0C,$0C,$06; F244 ..........
.byte $0C,$0C,$0C,$0C,$0D,$0D,$12,$12,$12,$0E; F24E ..........
template1StartFlags:
.byte $40,$40,$40,$40,$44,$44,$44,$44,$48,$48; F258 @@@@DDDDHH unitFlags[0-49] (see $F0C8): seven side-0 squads of four, $40 ALPHA .. $58 GROVER
.byte $48,$48,$4C,$4C,$4C,$4C,$50,$50,$50,$50; F262 HHLLLLPPPP
.byte $54,$54,$54,$54,$58,$58,$58,$58,$00,$00; F26C TTTTXXXX..
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F276 ..........
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F280 ..........
.byte $61,$61,$61,$61,$65,$65,$65,$65,$69,$69; F28A aaaaeeeeii unitFlags[50-99]: the same seven squads on side 1, $61 ALPHA .. $79 GROVER
.byte $69,$69,$6D,$6D,$6D,$6D,$71,$71,$71,$71; F294 iimmmmqqqq
.byte $75,$75,$75,$75,$79,$79,$79,$79,$21,$21; F29E uuuuyyyy!!
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F2A8 !!!!!!!!!!
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F2B2 !!!!!!!!!!
template1StartType:
.byte $11,$11,$11,$11,$11,$11,$11,$11,$11,$11; F2BC .......... unitType[0-49] (see $F12C): 28 x $11 RIDER, 18 x $FF, 3 x $13 SPY, $14 COMCEN
.byte $11,$11,$11,$11,$11,$11,$11,$11,$11,$11; F2C6 ..........
.byte $11,$11,$11,$11,$11,$11,$11,$11,$FF,$FF; F2D0 ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F2DA ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$13,$13,$13,$14; F2E4 ..........
.byte $19,$19,$19,$19,$19,$19,$19,$19,$19,$19; F2EE .......... unitType[50-78]: side 1's 28 riders ($19) and the first empty slot
.byte $19,$19,$19,$19,$19,$19,$19,$19,$19,$19; F2F8 ..........
.byte $19,$19,$19,$19,$19,$19,$19,$19,$FF; F302 .........
; Template 1's unitType[79-99]: the rest of the empty slots, then the three SPYs ($1B) and the COMCEN
; ($1C) of side 1. The label here has nothing to do with the template - it is the RUN-TIME meaning of
; the address: map cell (19,19) = $F000 + 40*19 + 19, which the map generator writes at $6F86 ($55, a
; river bend) when a point-symmetric map needs its two river halves joined at the centre.
D_F30B:
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F30B .......... unitType[79-95] $FF empty, [96-98] $1B SPY, [99] $1C COMCEN
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$1B,$1B,$1B; F315 ..........
.byte $1C ; F31F .
; unitStartTemplate2 ($F320-$F4AF) - used by game types 0 SCRIMAGE, 1 QB SNEAK and 2 THE BOMB. Eleven
; units a side and no groups at all (flags $00 / $21 throughout). It is a football formation: units
; 0-6 are the line of scrimmage in row 21 - a RIDER split out at column 7, GRUNTs at 14, 17, 20, 23
; and 26, a RIDER split out at column 33 - unit 7 is the RIDER 'quarterback' at (20,23), units 8 and 9
; the two RIDER backs at (18,25) and (22,25), and unit 49 the COMCEN at (20,25). Slots 10-48 are
; empty ($FF). Side 1 is the same formation reflected in the rows (side-1 row = 39 - side-0 row) but
; its columns are 40 - column instead of 39 - column, so on player 1's mirrored display side 1's line
; sits one cell to the left of side 0's; both COMCENs are stored at column 20. applyGameTypeDefaults
; ($7C85, in the map generator overlay) trims this roster once it has been copied: QB SNEAK deletes
; units 0-6, leaving only the quarterback, the two backs and the COMCEN, and THE BOMB deletes units
; 0-98 and puts unit 49 back as a COMCEN, so that game is fought by the two command centres and one
; extra drone each. The 39 empty slots a side are dead data: their column and row bytes are template
; 0's own entries at the same index, so this template was edited from a copy of template 0. The two
; exceptions are slots 10 (33,20) and 60 (27,19), which are not template-0 values - the formation
; evidently had a twelfth unit a side at some point.
unitStartTemplate2:
.byte $07,$0E,$11,$14,$17,$1A,$21,$14,$12,$16; F320 ......!... unitCol[0-18]: the line of scrimmage (7,14,17,20,23,26,33), the quarterback and the two backs
.byte $21,$07,$21,$12,$06,$05,$14,$13,$04; F32A !.!......
; Template 2's unitCol[19] - part of an empty slot, dead data. The label is the RUN-TIME meaning of
; the address: map cell (19,20) = $F000 + 40*20 + 19, written with $58 by the map generator at $6F81.
D_F333:
.byte $06 ; F333 . unitCol[19] = $06, unused
; Template 2's unitCol[20-49], all of them empty slots except the COMCEN at the end. The label is
; again the run-time meaning: map cell (20,20), cleared to $40 at $6F8B so that the two halves of a
; mirrored river join cleanly.
D_F334:
.byte $05,$22,$14,$12,$22,$20,$23,$15,$06,$05; F334 .".." #... unitCol[20] = $05, unused; entries 20-48 dead, entry 49 the COMCEN at column 20
.byte $06,$13,$05,$13,$14,$22,$22,$14,$21,$21; F33E ....."".!!
.byte $06,$14,$21,$23,$04,$12,$13,$22,$05,$14; F348 ..!#..."..
.byte $21,$1A,$17,$14,$11,$0E,$07,$14,$16,$12; F352 !......... unitCol[50-99]: side 1's line at 33,26,23,20,17,14,7, quarterback 57, backs 58/59, COMCEN 99
.byte $1B,$16,$13,$14,$21,$13,$04,$24,$14,$23; F35C ....!..$.#
.byte $22,$21,$20,$15,$05,$14,$05,$14,$22,$21; F366 "! ....."!
.byte $14,$13,$14,$22,$21,$05,$05,$06,$06,$13; F370 ..."!.....
.byte $13,$23,$21,$15,$04,$06,$22,$14,$05,$14; F37A .#!..."...
template2StartRow:
.byte $15,$15,$15,$15,$15,$15,$15,$17,$19,$19; F384 .......... unitRow[0-49] (see $F064): row 21 the line, 23 the quarterback, 25 the backs and the COMCEN
.byte $14,$1B,$1B,$1A,$1B,$1A,$1A,$1B,$1B,$1A; F38E ..........
.byte $1B,$19,$1B,$1B,$1A,$1B,$1A,$1B,$1F,$1E; F398 ..........
.byte $1E,$1F,$1F,$1E,$1E,$1F,$1E,$1F,$1F,$1E; F3A2 ..........
.byte $1C,$1C,$1C,$1C,$1C,$1C,$17,$17,$17,$19; F3AC ..........
.byte $12,$12,$12,$12,$12,$12,$12,$10,$0E,$0E; F3B6 .......... unitRow[50-99]: side 1's mirror - row 18 the line, 16 the quarterback, 14 the backs/COMCEN
.byte $13,$0C,$0D,$0C,$0D,$0C,$0C,$0C,$06,$0C; F3C0 ..........
.byte $0C,$0C,$0C,$0D,$0D,$0E,$0E,$0D,$09,$09; F3CA ..........
.byte $08,$09,$09,$08,$08,$09,$08,$09,$08,$08; F3D4 ..........
.byte $0B,$0B,$0B,$0B,$0B,$0B,$10,$10,$10,$0E; F3DE ..........
template2StartFlags:
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F3E8 .......... unitFlags[0-49]: $00 for every side-0 unit - nothing is in a group in these game types
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F3F2 ..........
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F3FC ..........
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F406 ..........
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F410 ..........
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F41A !!!!!!!!!! unitFlags[50-99]: $21 for every side-1 unit (bit 5 side, bit 0 facing down), no groups
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F424 !!!!!!!!!!
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F42E !!!!!!!!!!
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F438 !!!!!!!!!!
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F442 !!!!!!!!!!
template2StartType:
.byte $11,$10,$10,$10,$10,$10,$11,$11,$11,$11; F44C .......... unitType[0-49] (see $F12C): $11, five $10, four $11, then $FF to unit 48 and $14 COMCEN
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F456 ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F460 ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F46A ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$14; F474 ..........
.byte $19,$18,$18,$18,$18,$18,$19,$19,$19,$19; F47E .......... unitType[50-99]: the same eleven units on side 1 ($19 RIDER, $18 GRUNT, $1C COMCEN)
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F488 ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F492 ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F49C ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$1C; F4A6 ..........
; unitStartTemplate3 ($F4B0-$F63F) - used by game type 4 SLUGGERS. Roster per side: 12 GRUNT (units
; 0-11), 12 RIDER (12-23), 4 BOOMER (24-27), 3 SPY (46-48) and 1 COMCEN (49); slots 28-45 are empty.
; Every combat unit is in a 2x2 squad of four, one squad per group name: side 0 has the grunt squads 0
; ALPHA at columns 19-20 rows 26-27, 1 BAKER at 17-18 rows 27-28 and 2 CHARLIE at 21-22 rows 27-28
; packed around the COMCEN at (20,30); the rider squads 3 DELTA at columns 9-10, 4 EASY at 19-20 and 5
; FOXTROT at 29-30, all in rows 23-24; and the boomer squad 6 GROVER at 19-20 rows 28-29. The three
; spies stand loose in row 22 at columns 9, 20 and 30. Side 1 is the exact per-index 180-degree
; mirror (unit i+50 = (39-column, 39-row) of unit i, same type, same group). As in template 1 the 18
; empty slots a side keep dead column and row bytes copied from template 0 (entries 28-45 = template
; 0's 7-24, entries 78-95 = template 0's 57-74); only their $FF type matters. This is also the one
; template whose 512-byte copy reads past its own end, into $F640-$F6AF - see the note there.
unitStartTemplate3:
.byte $13,$14,$13,$14,$11,$12,$11,$12,$15,$16; F4B0 .......... unitCol[0-49] of template 3: three grunt squads, three rider squads, a boomer squad, then dead slots
.byte $15,$16,$09,$0A,$09,$0A,$13,$14,$13,$14; F4BA ..........
.byte $1D,$1E,$1D,$1E,$13,$14,$13,$14,$03,$24; F4C4 .........$
.byte $21,$05,$07,$21,$12,$06,$05,$14,$13,$04; F4CE !..!......
.byte $06,$05,$22,$14,$12,$22,$09,$14,$1E,$14; F4D8 ..".."....
.byte $14,$13,$14,$13,$16,$15,$16,$15,$12,$11; F4E2 .......... unitCol[50-99]: side 1's columns, the 39-column mirror of side 0's
.byte $12,$11,$1E,$1D,$1E,$1D,$14,$13,$14,$13; F4EC ..........
.byte $0A,$09,$0A,$09,$14,$13,$14,$13,$22,$06; F4F6 ........".
.byte $12,$15,$16,$13,$14,$21,$13,$04,$24,$14; F500 .....!..$.
.byte $23,$22,$21,$20,$15,$05,$1E,$13,$09,$13; F50A #"! ......
template3StartRow:
.byte $1A,$1A,$1B,$1B,$1B,$1B,$1C,$1C,$1B,$1B; F514 .......... unitRow[0-49] (see $F064): riders 23-24, grunts 26-28, boomers 28-29, spies 22, COMCEN 30
.byte $1C,$1C,$17,$17,$18,$18,$17,$17,$18,$18; F51E ..........
.byte $17,$17,$18,$18,$1C,$1C,$1D,$1D,$1B,$1B; F528 ..........
.byte $1A,$19,$1B,$1B,$1A,$1B,$1A,$1A,$1B,$1B; F532 ..........
.byte $1A,$1B,$19,$1B,$1B,$1A,$16,$16,$16,$1E; F53C ..........
.byte $0D,$0D,$0C,$0C,$0C,$0C,$0B,$0B,$0C,$0C; F546 .......... unitRow[50-99]: side 1's rows 9-17, the mirror of side 0's
.byte $0B,$0B,$10,$10,$0F,$0F,$10,$10,$0F,$0F; F550 ..........
.byte $10,$10,$0F,$0F,$0B,$0B,$0A,$0A,$0D,$0C; F55A ..........
.byte $0C,$0C,$0C,$0D,$0C,$0D,$0C,$0C,$0C,$06; F564 ..........
.byte $0C,$0C,$0C,$0C,$0D,$0D,$11,$11,$11,$09; F56E ..........
template3StartFlags:
.byte $40,$40,$40,$40,$44,$44,$44,$44,$48,$48; F578 @@@@DDDDHH unitFlags[0-49] (see $F0C8): seven side-0 squads of four, $40 ALPHA .. $58 GROVER
.byte $48,$48,$4C,$4C,$4C,$4C,$50,$50,$50,$50; F582 HHLLLLPPPP
.byte $54,$54,$54,$54,$58,$58,$58,$58,$00,$00; F58C TTTTXXXX..
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F596 ..........
.byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00; F5A0 ..........
.byte $61,$61,$61,$61,$65,$65,$65,$65,$69,$69; F5AA aaaaeeeeii unitFlags[50-99]: the same seven squads on side 1, $61 ALPHA .. $79 GROVER
.byte $69,$69,$6D,$6D,$6D,$6D,$71,$71,$71,$71; F5B4 iimmmmqqqq
.byte $75,$75,$75,$75,$79,$79,$79,$79,$21,$21; F5BE uuuuyyyy!!
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F5C8 !!!!!!!!!!
.byte $21,$21,$21,$21,$21,$21,$21,$21,$21,$21; F5D2 !!!!!!!!!!
template3StartType:
.byte $10,$10,$10,$10,$10,$10,$10,$10,$10,$10; F5DC .......... unitType[0-35] (see $F12C): 12 x $10 GRUNT, 12 x $11 RIDER, 4 x $12 BOOMER, then $FF
.byte $10,$10,$11,$11,$11,$11,$11,$11,$11,$11; F5E6 ..........
.byte $11,$11,$11,$11,$12,$12,$12,$12,$FF,$FF; F5F0 ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF ; F5FA ......
; Template 3's unitType[36-49]: the last empty slots, the three SPYs ($13) and the COMCEN ($14) of
; side 0. The label is the RUN-TIME meaning of the address: $F600 is where the 40x40 map's last 64
; cells begin (cells 1536-1599), the tail that clearMapMarkers walks separately at $7536/$7541 after
; its six full pages.
D_F600:
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F600 .......... unitType[36-45] $FF empty, [46-48] $13 SPY, [49] $14 COMCEN
.byte $13,$13,$13,$14 ; F60A ....
.byte $18,$18,$18,$18,$18,$18,$18,$18,$18,$18; F60E .......... unitType[50-99]: 12 x $18, 12 x $19, 4 x $1A, 18 x $FF, 3 x $1B and $1C - side 1's roster
.byte $18,$18,$19,$19,$19,$19,$19,$19,$19,$19; F618 ..........
.byte $19,$19,$19,$19,$1A,$1A,$1A,$1A,$FF,$FF; F622 ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF; F62C ..........
.byte $FF,$FF,$FF,$FF,$FF,$FF,$1B,$1B,$1B,$1C; F636 ..........
; $F640-$F6FF - 192 bytes that belong to no template and that the game never uses. They are a
; fragment of 6502 code from an OLDER build of the game, left in the mastering machine's memory when
; this block was written to the disk; the loader reads all seven sectors, so it comes along for the
; ride.
; Nothing ever reads it as data: the only reader of this file, loadUnitStartTemplate ($ECF3), copies
; at most $F4B0-$F6AF (template 3), and because that copy writes 400 bytes ahead of its own read
; pointer it has already replaced $F640-$F6AF with template 3's data before it gets there. The one
; byte that IS read is $F640 itself, as the 'the arrays still hold the disk image' flag - and it holds
; $0A, bit 7 clear, which would mean 'already loaded', so startGameSession stores $FF over it first
; ($78E4). Once a game starts this area is the live unitCol[0-99] ($F640) and unitRow[0-99] ($F6A4)
; arrays, which is what the labels below name; the bytes printed under them are the leftover code, not
; array data, and the labels fall in the middle of its instructions. Disassembled, the fragment is the
; tail of one routine plus two complete ones, each with a recognisable counterpart in the shipped
; build at a different address:
; $F640 asl a / sta $3F / lda #$14 / jmp $C097
; the tail of setRepairMessageWindow, which in the shipped build ($19E1) ends 'lda #$0A /
; sta textCursorCol / lda #$14 / jmp setCursorRow': cursor to row 20, column 2*A.
; $F648 lda #$0C sta $3B / lda #$09 sta $39 sta $40 / lda #$12 sta $3C / lda #$00 sta $3F /
; jsr $C099 / lda #$61 sta $3D / lda #$B2 ldy #$CA jsr $C133
; printOptionsList: text window left column 12, rows 9-18, width 18, colour $61, then the
; heading from $CAB2. The shipped printOptionsList ($19F3) is the same code with column 6,
; width $1D and the heading at $CB13.
; $F668 lda $92CD bne / lda $0881 beq
; 'is a game running?' - $92CD is the old build's gameEndCountdown and $0881 its
; gameEndReason; the shipped test at $1A13 uses $92C9 and $0BA8.
; $F672 lda #$10 ldy #$66 jsr $C133 / jsr $C137 / lda $E03B beq / jsr $C137 / rts
; no game: print the main menu from $6610, then LOAD GAME FILM, then DISCONNECT/SET VOICE if
; the link flag $E03B is set. Shipped: the same sequence at $1A36 with the text at $CC1F.
; $F685 lda #$98 ldy #$66 jsr $C133 / lda $0876 bmi / jsr $C137 / lda #$53 ldy #$CA jmp $C133
; a game is running: ABORT GAME from $6698, VOICE PAUSE unless the film-playback flag
; $0876 is set, then ' (EXIT)' from $CA53. Shipped ($1A1B): $CCA6, two flag tests, $CAB2.
; $F69B lda #$FF sta $924A / lda $0881 bne $F711 / jsr $1648 / ldy #$02 / lda $0876 bmi /
; lda $087F bmi / iny / sty $91D5 / dey / sty $91D6 / dec $3B / lda $3B sta $3F /
; lda #$0B sta $91D7 / jsr $C097 / jsr $5F41 / ldy $91D6 beq / jsr $1205 / jmp $1648
; miscTabAction, the MISC-tab options menu: two items, three in a modem game that is not a
; replay, highlight bar from row 11, run the selector, and on '(EXIT)' reprint the list. The
; shipped miscTabAction ($1A49) is instruction for instruction the same, with the menu state
; one byte lower ($91D4/$91D5/$91D6 instead of $91D5/$91D6/$91D7).
; $F6D8 jsr $0CD8 / lda $E03B beq / lda $0877 bmi,beq / lda #$00 sta $73 sta $9164 /
; lda $E044 bmi / jsr $C7FF / lda #$8C jsr $5178 / lda #$26 sta $7F / (jsr, cut off)
; the ABORT GAME path: if the link is up and a game session is agreed, clear the exchange
; throttle, skip the handshake when the opponent module is the trainer ($E044 = the old
; build's commBuildId), show 'WORKING...', queue command $8C reason 0, wait $26 ticks.
; Shipped: $1A86-$1AAE, with commBuildId $E030, showWorkingMessage $C853, queueCmd2 $561F.
; The block ends in the middle of that last JSR: only its $20 opcode fits in the seven sectors. What
; dates the fragment to a different build is that every one of its own addresses differs from the
; shipped equivalent - printOptionsList $1648 vs $19F3, setMenuTextWindow $1205 vs $1575,
; runInGameOptionsMenu $5F41 vs $65A0, queueCmd2 $5178 vs $561F, showWorkingMessage $C7FF vs $C853,
; the mode flags $0876/$0877/$087F/$0881 vs $0B9B/$0B9C/$0BA5/$0BA8, the menu text $6610/$6698/$CA53
; vs $CC1F/$CCA6/$CAB2, linkPollDelay $9164 vs $9163, commBuildId $E044 vs $E030 - while the low-level
; text engine entries it calls ($C097 setCursorRow, $C099 updateCursorPointers, $C133 printString,
; $C137 printStringAtPointer) and the link-active flag $E03B are at exactly the addresses the shipped
; build uses. So it is the same program a few hundred bytes shorter, before the $0800 and $C000
; blocks were rearranged. (Confidence: high that it is leftover code and that these are the matching
; routines; which build it came from cannot be pinned down further.)
unitColTable:
.byte $0A ; F640 map column of each of the 100 units; the parallel unit arrays follow every $64 bytes (0-49 side 0, 50-99 side 1, 49/99 = the comcens)
.byte $85,$3F,$A9,$14,$4C,$97,$C0; F641 .?..L..
.byte $A9 ; F648 the old build's printOptionsList starts here; the shipped one is at $19F3
.byte $0C,$85,$3B,$A9,$09,$85,$39,$85; F649 ..;...9.
.byte $40,$A9,$12,$85,$3C,$A9,$00,$85; F651 @...<...
.byte $3F,$20,$99,$C0,$A9,$61,$85,$3D; F659 ? ...a.=
.byte $A9,$B2,$A0,$CA,$20,$33,$C1,$AD; F661 .... 3..
.byte $CD,$92,$D0,$05,$AD,$81,$08,$F0; F669 ........
side0ComcenCol:
.byte $13 ; F671 unitColTable[49]: column of side 0's COMCEN
side1UnitColTable:
.byte $A9 ; F672 unitColTable+50: the columns of side 1's units, indexed by that side's ordinal 0-49
.byte $10,$A0,$66,$20,$33,$C1,$20,$37; F673 ..f 3. 7
.byte $C1,$AD,$3B,$E0,$F0,$03,$20,$37; F67B ..;... 7
.byte $C1,$60 ; F683 .`
.byte $A9 ; F685 'a game is running' branch: ABORT GAME / VOICE PAUSE / (EXIT)
.byte $98,$A0 ; F686 ..
unitFlagsTableAlias:
.byte $66 ; F688 unitFlagsTable - $80, so it can be indexed with a raw map byte ($80 | unit)
.byte $20,$33,$C1,$AD,$76,$08,$30,$03; F689 3..v.0.
.byte $20,$37,$C1,$A9,$53,$A0,$CA,$4C; F691 7..S..L
.byte $33,$C1 ; F699 3.
.byte $A9 ; F69B the old build's miscTabAction starts here; the shipped one is at $1A49
.byte $FF,$8D,$4A,$92,$AD,$81,$08; F69C ..J....
side1ComcenCol:
.byte $D0 ; F6A3 unitColTable[99]: column of side 1's COMCEN
unitRowTable:
.byte $6C ; F6A4 map row of each of the 100 units
.byte $20,$48,$16,$A0,$02,$AD,$76,$08; F6A5 H....v.
.byte $30,$06,$AD,$7F,$08,$30,$01,$C8; F6AD 0....0..
.byte $8C,$D5,$91,$88,$8C,$D6,$91,$C6; F6B5 ........
.byte $3B,$A5,$3B,$85,$3F,$A9,$0B,$8D; F6BD ;.;.?...
.byte $D7,$91,$20,$97,$C0,$20,$41,$5F; F6C5 .. .. A_
.byte $AC,$D6,$91,$F0,$06,$20,$05,$12; F6CD ..... ..
side0ComcenRow:
.byte $4C ; F6D5 unitRowTable[49]: row of side 0's COMCEN
side1UnitRowTable:
.byte $48 ; F6D6 unitRowTable+50: the rows of side 1's units
.byte $16 ; F6D7 .
.byte $20 ; F6D8 the ABORT GAME path: tell the opponent with command $8C and hang up (shipped $1A86)
.byte $D8,$0C,$AD,$3B,$E0,$F0,$2E,$AD; F6D9 ...;....
.byte $77,$08,$30,$29,$F0,$24,$A9,$00; F6E1 w.0).$..
.byte $85,$73,$8D ; F6E9 .s.
unitTypeTableAlias:
.byte $64 ; F6EC unitTypeTable - $80, so it can be indexed with a raw map byte ($80 | unit)
.byte $91,$AD,$44,$E0,$30,$18,$20,$FF; F6ED ..D.0. .
.byte $C7,$A9,$8C,$20,$78,$51,$A9,$26; F6F5 ... xQ.&
.byte $85,$7F ; F6FD ..
.byte $20 ; F6FF $20 = the opcode of a JSR whose address bytes fell outside the seven sectors