;  Astro Battle
;  For Bally/Astrocade
;
;  Disassembly begun Aug. 1, 2011 by Adam Trionfo
;
;  Release History:
;  ----------------
;     Release .05 (Aug. 15, 2011) (All changes by R.C.D. on Aug. 13, 2011)
;        - Remaining RAM cells identified.
;        - MANY comments added
;        - TODO:
;             - Check out the actual UFO Bonus scoring, and 
;               the logic for launching one!
;             - Try to figure out the 3 "Invader Delay"s and why the 4th
;               "Invader's Shot Vector Block" is handled differently 
;               from the other three using L2589: ?
;             - Also add "off" at the end of "; No Keys are Masked" since 
;               they have ALL been masked "on", meaning that "None have
;               been masked inactive",  I say.
;     Release .04 (Aug. 11, 2011)
;        - MANY Comments and explanations added by R.C.D.
;        - Corrections to Music Score (concerning PUSHN) added by 
;          Adam Trionfo (at the recommendation of R.C.D.)
;     Release .03 (Aug. 9, 2011)
;        - Commented Music Scores 
;     Release .02 (August 9, 2011) (All changes by R.C.D. on Aug. 6, 2011)
;        - Vector Blocks identified
;        - Some comments added
;        -  Straightened out some columns.
;     Release .01 (August 5, 2011) 
;        - VERY Preliminary Release-- Released so that those who
;          are curious can take a look.
;
;  I disassembled this game using time, effort and the following
;  tools and materials:
;     1. Beyond Compare 3
;     2. DZ80 Disassembler (with BallyHVG.LUA disassembly script [by R.C.D.])
;     3. FC (File Compare) Command on Windows XP Command Line
;     4. "How to Program the Z80," Third Edition, By Rodnay Zaks
;     5. HVGLIB.H - Home Video Game Library header file
;     6. MESS Astrocade Emulator
;     7. "Home Video Game Manual for the Bally Astrocade"
;        (aka "Nutting" Manual) and Bally On-Board ROM Source Code
;     8. PS Pad (Text Editor which creates a sort of IDE for ZMac)
;     9. Windows XP Built-In Scientific Calculator
;     10. ZMac Assembler 1.3 (Windows 32 Version)
;
;  Lastly, but just as important as the rest, was that the disassembly
;  work was accompanied by Beethoven's Symphonies 1-9.  That is five
;  hours and forty minutes of music that I listened to over and over
;  while wading through the 3.2K of code and data.

INCLUDE "HVGLIB.H"  ; Home Video Game Library

; RAM that is initialized at Program startup
; $4E10 for 13-byte  "Player's Shot" Vector Block
; $4E1D for "Invader's Shot" Vector Block #1
; $4E2A for "Invader's Shot" Vector Block #2
; $4E37 for "Invader's Shot" Vector Block #3
; $4E44 for "Invader's Shot" Vector Block #4 [figured differently than the first three ??]

; $4E51 init to 8 for Player X Position (0 to 148)
; $4E52 set to 2 for Invader Explosion down-Counter
; $4E53 temp word Invader Explosion XY position
; $4E55 byte for Player Shot Off or On (0 or 82)

; Invader's 6-byte IX block [Upper-Left corner]
; $4E56 init to 3 for Invader Field X Left side
; $4E57 each new Wave x8 for Field Y Top
; $4E58 [not used ??]
; $4E59 byte current Row being Drawn Y Top
; $4E5A for Which Invader Row being Drawn
; $4E5B ?? Right Edge ?? IX+$05 0 to 3 [7 ??]

; Live Invaders 4 Row array of 8 bits per Row
; note: MS bit is Left Invader; LS is Right one
; $4E5C-$4E5F init to FF's for 32 bits of 1's

; $4E60 init to 1 for Invader Delta X (+1 or -1)
; $4E61 temp byte ?? Temp ?? [?? Row Y of Shot Invader ??]

; Edge Limit 2-byte IY block [compare to Field X Left side]
; [note: computed based on Invader's Footprint quite often]
; $4E62 init to 1 for ?? Right edge Limit [may be reversed ??]
; $4E63 init to $20 for ?? Left edge Limit [can go negative]

; $4E64 [not used ??]
; $4E65 store Live Invader's Footprint [Live Invaders Array overlapped into one byte ??]
; $4E66 init to $50 for Invader Delay A [the lower these go, the faster the Invaders march ??]
; $4E67 init to $50 for Invader Delay B
; $4E68 init to $50 for Invader Delay C
; $4E69 [not used ??]
; $4E6A for UFO Delta X [0 or reverse of Invader Delta X]
; $4E6B for UFO X Position (1 to 150)

; System RAM locations
; TIMOUT byte [[[aka TIMer until blakOUT] see DNA pg. 46 !!] and pg. 14 of original BALLY.H !!]
; CT0 byte Wait 2 for Next Invader Shot ?? 
; CT1 byte [not used ??] 
; CT2 byte Pause for 2 Interrupts
; CT3 byte Wait for 6 or Live Invaders times 2 ?? 
; CT4 byte Wait for ?? [varies] guesstimated Music Score times
; [CT5-CT7 not used]

SCORE   EQU   $4E6C     ; Player's Score (2 Bytes, BCD) Max Score is 9999

; $4E6E  1 for first Wave up-Counter byte x8 for $4E57

LIVES   EQU   $4E6F     ; Number of Player Bases (or "Lives")

; $4E70 init 0 for Extra Base Flag
; $4E71 init 0 [then not used ??]

GAMDIF  EQU   $4E72     ; Game Difficulty Setting

; $4E73 [not used ??]
; $4E74 for Heart Beep Counter (Tone 0-3)
; $4E75 for Heart Beat Counter (Odd/Even delay)
; $4E76 [set to Live Invaders times 2, but not used ??]
; $4E77 set to 41 for UFO Explosion down-Counter
; $4E78 word for [random 1-3]00 UFO Bonus Score
; $4E7A for UFO Explosion X Position
; $4E7B for UFO Explosion Y Position

MUSSTK  EQU   $4F12     ; Music Stack Pointer

; $4FA0 for System Stack top

        ORG     FIRSTC          ; FIRST address in Cartridge

        DB      "U"             ; User Cartridge Sentinel

; On-Board ROM Menu Data Structure
        DW      MENUST          ; Link to Head of On-Board MENU STart
        DW      L2AF7           ; Address of "ASTRO BATTLE" menu text
        DW      L2007           ; Jump here if "ASTRO BATTLE" selected

L2007:  SYSSUK  MENU            ; UPI display a MENU
        DW      L2946           ; ... "ENTER LEVEL"
        DW      L2952           ; ... Menu List = 10578
        ;
; continue after selecting Difficulty
L200D:  LD      A,$01           ; Set-up "AMATEUR" Game
        JR      STARTG

L2011:  LD      A,$02           ; Set-up "INTERMEDIATE" Game
        JR      STARTG

L2015:  LD      A,$03           ; Set-up "PROFESSIONAL" Game
        JR      STARTG

L2019:  LD      A,$00           ; Set-up "NOVICE" Game
; entry point for all difficulties
STARTG: LD      (GAMDIF),A      ; Start Game
        LD      SP,$4FA0

; Setup 8 Color Registers
; -----------------------
; Use Port $0B (COLBX, write COLor BloCK multi-port) to
; setup the eight Color Registers [instead of SYSTEM COLSET ??].
; (See "DNA Manual" Page 88 has more information)
        LD      HL,L2B06        ; Start add. of COLTBL to send to
                                ; eight color regs.
        LD      B,$08           ; Count for OTIR instruction
        LD      C,$0B           ; Port 11 for OTIR instruction
        OTIR                    ; Reset color registers

; Setup Vertical Blank line
; -------------------------
;   Make room for stack, variables, tables, etc. in the scratchpad
;   (hidden) area at the bottom of the screen.  The total possible
;   vertical resolution is 102.  Only 90 lines will be displayed.
;   RAM Setup works out to:
;
;      $4000-$4E0F -  3,600 Bytes (90 Lines)
;      $4E10-$4FFF -  496 Bytes (12 lines + 16 Scratchpad Bytes)
;
;   (See "DNA Manual" Pages 85 and 90 has more information)
        LD      A,$B4           ; 180 dec. (90 pixel lines times 2) for
        OUT     (VERBL),A       ;  Port 10 - Vertical Blank [at scan]line

; Setup for Interrupts
; --------------------
;   Initialize first of four screen interrupts to run once EI encountered
        LD      A,IRVEC1 >> 8   ; High Order Byte Address of Interrupt Vector
        LD      I,A             ; Load Interrupt Vector Register
        LD      A,IRVEC1 & $FF  ; Get Low Order Byte Address
        OUT     (INFBK),A       ; Port $0D, INterrupt FeedBacK Register
        LD      A,10*2          ; Screen Line 10 times 2 [below Score]
        OUT     (INLIN),A       ; Port $0E, INterrupt LINe Register
        LD      A,$08
        OUT     (INMOD),A       ; Port $0F, INterrupt MODe Register [Screen Ints. only]

; Set Horizontal Color Boundary and Background Color
; --------------------------------------------------
;   Horizontal Color Boundary (Bits 0-5 of Port $09)
;   Background Color (Bits 6 and 7 of Port $09)
;   (See "DNA Manual" Pages 88-89 has more information)
        LD      A,10000000B     ; HCB = 0, BC=2, which is COL2L
        OUT     (HORCB),A       ; Port 9 - Horizontal Color Boundary

; Finish Setup for Interrupts
; ---------------------------
        IM      2               ; Set Interrupt Mode 2 Condition
        EI                      ; Enable Interrupts

; Initialize 7 Bytes in Scratchpad Area:
; --------------------------------------
;    Set Initial Number of Bases (or "lives")
        LD      A,$03           ; Initial Number of Bases is 3
        LD      (LIVES),A       ; Set Number of Bases (or "Lives")
        LD      A,$01
        LD      ($4E6E),A       ; Initialize Wave Counter to 1
        LD      HL,$0000        ; Initial Player Score is zero points
        LD      (SCORE),HL      ; Set Player's Score
        LD      ($4E70),HL      ; Initialize Extra Base flag and ?? to 0
        LD      ($4E77),A       ; Initialize UFO Explosion counter to 0

; Clear Screen and Beginning of Scratchpad
; ----------------------------------------
; loop here when all 32 Invaders destroyed
L205B:  SYSSUK  FILL            ; UPI FILL memory with data
        DW      NORMEM          ; NORmal MEMory start
        DW      3678            ; Fill from $4000-$4E5D
        DB      $00             ; Data = 0

; Initialize Scratch RAM
; ----------------------
;   This loops to initialize 5 Vector Blocks of 13 bytes each.
;   When the loop is complete, scratchpad will look like this:
;
;   Vector IX Base  +$02   +$07   +$09   +$0C
;   Block    =$20    =$01   =$01   =$02   =$01
;   ------  ------  -----  -----  ----- ------
;    #1     $4E10,  $4E12, $4E17, $4E19, $4E1C
;    #2     $4E1D,  $4E1F, $4E24, $4E26, $4E29
;    #3     $4E2A,  $4E2C, $4E31, $4E33, $4E36
;    #4     $4E37,  $4E39, $4E3E, $4E40, $4E43
;    #5     $4E44,  $4E46, $4E4B, $4E4D, $4E50
; 
; "Looks like 4 shots at a time for the Aliens and 1 for the Player!" R.D.

        LD      B,5             ; Setup Loop to run 5 times
        LD      DE,$0D          ; Index Displacement
        LD      IX,$4E10        ; Index Base (First Byte of Scratchpad)
L206B:  LD      (IX+VBMR),$20   ; set VB Magic Register for X-OR draw/erase
        LD      (IX+VBTIMB),$01 ; set Vector Block TIMeBase to single step
        LD      (IX+VBXCHK),$01 ; set bit 0 to Check X LiMiTs (not used ??)
        LD      (IX+VBDYH),$02  ; set Delta Y High to 2 pixel speed
        LD      (IX+VBYCHK),$01 ; set bit 0 to Check Y LiMiTs
        ADD     IX,DE           ; Increment Index by Displacement $0D
        DJNZ    L206B           ; Has loop run 5 times?  If not, then Loop

; Initialize 7 Bytes in Scratchpad Area
; -------------------------------------
        LD      A,$01
        LD      ($4E60),A       ; Initialize Invader Delta X to 1 (going Right)
        LD      ($4E62),A       ; Initialize Right Limit to 1 [should be $22 ??]
        LD      HL,$FC80
        LD      ($4E18),HL      ; Initialize Player's Shot VBDY to -2.5
        LD      A,$08
        LD      ($4E51),A       ; Initialize Player X Position to 8
        LD      A,$20
        LD      ($4E63),A       ; Initialize Left Limit to 32 [should be 0 ??]
        LD      A,$03
        LD      ($4E56),A       ; Initialize Invader Field X Left to 3

; Initialize $4E5C-$4E5F to $FF [populate 4 rows of 8 Invaders each]
; ----------------------------
        LD      B,4             ; Setup Loop to run 4 times
        LD      HL,$4E5C        ; Setup First byte to Initialize to $FF
L20A5:  LD      (HL),$FF        ; Initialize 1 byte of Scratchpad to $FF
        INC     HL              ; Increment Scratchpad Byte by 1
        DJNZ    L20A5           ; Has loop run 4 times?  If not, then Loop

; current Wave x8 pixels to lower Invaders' starting position
        LD      A,($4E6E)       ; read Wave Counter
        SLA     A               ; times 8
        SLA     A
        SLA     A
        LD      ($4E57),A       ; Initialize Invader Field Y Top
        LD      A,($4E6E)
        INC     A
        LD      ($4E6E),A       ; bump up Wave Counter

; Write Four Player "Protective Bunkers"
; ---------------------------------------
;   The Four Bunker's X,Y Coordinate's are:
;      Bunker 1 (Left-Most):    10, 65
;      Bunker 2 (Middle-Left):  50, 65
;      Bunker 3 (Middle-Right): 90, 65
;      Bunker 4 (Right-Most):  130, 65
;
        LD      B,4             ; Setup Loop to run 4 times
        LD      E,10            ; Setup First X Coordinate [0-159]
L20C1:  LD      HL,L29A5        ; Pattern of Player's "Protective Bunkers"
        XOR     A               ; Magic Register = 0 for PLOP
        LD      D,65            ; Y Coordinate [0-101]
        PUSH    DE              ; Save DE for X Coordinate
        PUSH    BC
        SYSTEM  WRITP           ; Write a "Protective Bunkers" Screen
        ;
        POP     BC
        POP     DE              ;
        LD      A,E             ; Load Old X Coordinate into Accum
        ADD     A,40            ; Increase X Coordinate by 40 pixels
        LD      E,A             ; X Coordinate for Next Bunker
        DJNZ    L20C1           ; Has loop run 4 times?  If not, then Loop

; Restore CALL L26AB and remove jump [?? note from ??]
        CALL    L26AB           ; do Display "BASES" and bases left on screen
        CALL    L25BC           ; do Display "SCORE" and Player's Score

; Write 4 Rows of Invaders
; ------------------------
        LD      B,4             ; Setup Loop to run 4 times
L20DB:  CALL    L27E6           ; do Draw a Row of Invaders
        PUSH    BC              ; BC Used in Delay Loops, So Save BC on Stack

; Delay Loop
;   Pause before writing another row of Invaders.
        LD      B,$FF           ; Setup Outer Loop to Run 255 times
OUTRL1: LD      C,$FF           ; Setup Inner Loop to Run 255 Times
INERL1: DEC     C               ; Decrement Inner Loop
        JR      NZ,INERL1       ; Has Inner Loop Run 255 Times?
        DJNZ    OUTRL1          ; Has Outer Loop Run 255 Times?
        POP     BC              ; Done with Delay Loops, So Restore BC
        DJNZ    L20DB           ; Has loop run 4 times?  If not, then Loop
        CALL    L27E6           ; do Draw a Row of Invaders [?? a FIFTH ROW ??]
        IN      A,(INTST)       ; =&(8) ; clear INTercept STatus [not needed??]
        LD      A,$28
        LD      ($4E68),A       ; init Invader Delay C to 40
        LD      ($4E66),A       ; init Invader Delay A to 40
        LD      ($4E67),A       ; init Invader Delay B to 40
L20FB:  EI
        LD      A,(CT3)         ; read Counter/Timer #3
        OR      A
        JR      NZ,L2148        ; bypass if CT3 not counted down
        LD      A,($4E75)
        BIT     0,A             ; Odd or Even Heart Beat pass?
        JP      NZ,L213C
        LD      A,$00           ; Variable delay for Even pass
        OUT     (VOLC),A        ; &(21)= 0 ; mute VOLume of tone C
        LD      A,($4E75)
        DEC     A               ; count down Heart Beat byte
        LD      ($4E75),A
        LD      HL,$4E5C        ; point at Live Invaders array
        LD      C,$00
        LD      D,$04
; loop for all 4 rows
L211C:  LD      A,(HL)
        LD      B,8             ; Setup Loop to run 8 times
; loop for all 8 Invader bits
L211F:  BIT     0,A
        JR      Z,L2124
        INC     C               ; count Live Invaders
L2124:  SRL     A
        DJNZ    L211F           ; Has loop run 8 times?  If not, then Loop
        INC     HL
        DEC     D
        JR      NZ,L211C        ; to Next Row
        LD      A,C
        SLA     A               ; Live Invaders times 2
        NOP
        NOP
        LD      ($4E76),A       ; [writen, but not used !!]
        ADD     A,$00           ; [fudge factor ??]
        LD      (CT3),A         ; write to Counter/Timer #3
        JP      L2148

; else fixed delay for Odd pass
L213C:  LD      A,($4E75)
        DEC     A               ; count down Heart Beat byte
        LD      ($4E75),A
        LD      A,$06
        LD      (CT3),A         ; write 6 to Counter/Timer #3
; continue after checking/setting CT3 delay
L2148:  NOP
        CALL    L26BB           ; do Output HeartBeep [one of 0-3]
        LD      IY,$4E62        ; point at 2-item Edge Limit array
        LD      A,($4E5A)       ; read Invader Row being Drawn
        CP      $04
        JR      NZ,L216F        ; skip if NOT Done all 4 Rows ??
        LD      A,($4E56)       ; read Field X Left edge
        LD      B,A
        CP      (IY+$00)        ; $4E62 ?? for Right Limit
        CALL    Z,L26E6         ; do Reverse and Drop Invaders if at edge
        LD      A,B
        CP      (IY+$01)        ; $4E63 ?? for Left Limit
        CALL    Z,L26E6         ; do Reverse and Drop Invaders if at edge
        LD      A,($4E60)       ; read Invader Delta X [+1 or -1]
        ADD     A,B
        LD      ($4E56),A       ; write new Field X Left
L216F:  CALL    L27E6           ; do Draw a Row of Invaders
        XOR     A
        LD      B,$04
        LD      HL,$4E5C        ; point at Live Invaders array
L2178:  OR      (HL)            ; Collapse into one byte...
        INC     HL
        DJNZ    L2178
        LD      C,A             ; ...footprint of Live Invaders
        LD      B,A
        LD      ($4E65),A       ; write to Invader's Footprint
        OR      A
        JR      NZ,L218A        ; if any Invaders remaining
        CALL    L257B           ; else do Silence all Sound Ports
        JP      L205B           ; to Restart on Next Wave

L218A:  LD      A,$22           ; Compute Right X edge Limit
L218C:  BIT     0,C             ; test Right Invader bit
        JR      NZ,L2197        ; until occupied bit found
        ADD     A,$10           ; 34 + 16 for each empty spot
        OR      A               ; [clear CY flag ??]
        SRL     C
        JR      L218C           ; loop Next bit

L2197:  LD      ($4E62),A       ; write to Right X Limit
        XOR     A               ; Compute Left X edge Limit
L219B:  BIT     7,B             ; test Left Invader bit
        JR      NZ,L21A5        ; until occupied bit found
        SUB     $10             ; 0 - 16 for each empty spot
        SLA     B
        JR      L219B           ; loop Next bit

L21A5:  LD      ($4E63),A       ; write to Left X Limit
        LD      A,($4E70)       ; Extra Base flagged already?
        OR      A
        JR      NZ,L21CE
        LD      HL,(SCORE)      ; Prepare to work on Player's Score
        BIT     4,H             ; 1000 BCD hit?
        JR      Z,L21CE
        LD      A,(LIVES)       ; Load ACCUM with Number of Bases
        INC     A               ; Increase [] Bases by 1
        LD      (LIVES),A       ; Award Player Extra Base
        LD      ($4E70),A       ; and write to Extra Base flag
        CALL    L26AB           ; do Display "BASES" and bases left on screen
        LD      A,$48           ; write 72 to Counter/Timer #4
        LD      (CT4),A

; When I played this sound effect it makes no noise.  The Score is
;   short.  Maybe it is shutting off all sound ports?
        SYSSUK  BMUSIC          ; UPI Begin playing MUSIC
        DW      MUSSTK          ; ... Music Stack = $4F12
        DB      $C0             ; ... Voices = Tone A only
        DW      L290E           ; ... Score Address for No Noise
        ;
L21CE:  LD      A,(GAMDIF)      ; load Accum with Game Difficuly
        CP      $02             ; is the difficulty set to "INTERMEDIATE"?
        JR      C,L21EC         ; less if "NOVICE" of "AMATEUR"
        JR      Z,L21E2         ; if Yes
        LD      A,($4E67)       ; else "PROFESSIONAL"
        OR      A
        JR      Z,L21F7
        SUB     $02             ; decrease Invader Delay B by 2
        LD      ($4E67),A
L21E2:  LD      A,($4E68)
        OR      A
        JR      Z,L21F7
        DEC     A               ; decrease Invader Delay C by 1
        LD      ($4E68),A
L21EC:  LD      A,($4E66)
        OR      A
        JR      Z,L21F7
        SUB     $01             ; decrease Invader Delay A by 1
        LD      ($4E66),A
L21F7:  LD      A,(LIVES)       ; Load Number of Bases into Accum
        OR      A               ; Use OR to set Zero Flag
        JP      Z,L24FA         ; If Number of Bases =0 then jump

        LD      A,(GAMDIF)      ; Load Game Difficulty into Accum
        OR      A               ; Is the difficulty set to "NOVICE"?
        JP      Z,L227F         ; If difficulty is "NOVICE" then jump
        LD      A,($4E51)       ; read Player X Position
        LD      B,A
        LD      A,($4E56)       ; read Field X Left
        CP      B
        JP      NC,L227F
        LD      IX,$4E44        ; point at Invader's Shot VB #4
        BIT     VBSACT,(IX+VBSTAT) ; test Vector Block STATus = ACTive?
        JP      NZ,L227F
        LD      C,A
        LD      A,B
        SUB     C
        SRL     A
        SRL     A
        SRL     A
        SRL     A
        LD      C,$80
L2228:  OR      A
        JR      Z,L2230
        DEC     A
        SRL     C
        JR      L2228

; ?? routine
L2230:  LD      A,($4E65)       ; read Invader's Footprint
        LD      D,A
        AND     C
        JP      Z,L227F
        LD      A,($4E57)       ; read current Field Y Top
        ADD     A,$1F
        LD      H,A
        LD      IY,$4E5C        ; point at Live Invaders array
        LD      A,C
        LD      E,$00
        AND     (IY+$03)        ; ?? in Bottom Row...
        JR      NZ,L225C
        LD      E,$08
        LD      A,C
        AND     (IY+$02)        ; ...or...
        JR      NZ,L225C
        LD      E,$10
        LD      A,C
        AND     (IY+$01)        ; ...or...
        JR      NZ,L225C
        LD      E,$18           ; ...must be Top Row
L225C:  LD      A,H
        SUB     E
        LD      (IX+VBYH),A     ; save as Vector Block Y High
        CP      $52
        JP      NC,L227F        ; if ?? Too Low?
        LD      A,($4E56)       ; read Field X Left
; loop on 8 bits of ??
L2269:  BIT     7,C
        JR      NZ,L2273
        SLA     C
        ADD     A,$10
        JR      L2269

L2273:  ADD     A,$06
        LD      (IX+VBXH),A     ; save as Vector Block X High
        LD      (IX+VBSTAT),$80 ; set VBSACTive bit
        CALL    L270A           ; do Draw Invader's Shot #[??]
; skip to here if too low ??
L227F:  LD      A,(CT0)         ; read Counter/Timer #0
        OR      A
        JP      NZ,L20FB        ; break if CT0 not counted down
        LD      A,$02           ; write 2 to Counter/Timer #0
        LD      (CT0),A
        IN      A,(SW0)         ; read SWitches 0 for player 1 hand control
        LD      B,A
        BIT     CHLEFT,A        ; if pressed Left...
        JR      Z,L22A0
        LD      A,($4E51)       ; read Player X Position
        CP      $01
        JR      C,L22B0         ; ...and not at Left Edge
        DEC     A
        DEC     A
        LD      ($4E51),A       ; write Player X Position - 2
        JR      L22B0

L22A0:  BIT     CHRIGH,B        ; if pressed Right...
        JR      Z,L22B0
        LD      A,($4E51)       ; read Player X Position
        CP      $94
        JR      NC,L22B0        ; ...and not at Right Edge
        INC     A
        INC     A
        LD      ($4E51),A       ; write Player X Position + 2
; test Player One trigger
L22B0:  BIT     CHTRIG,B        ; if Trigger NOT pulled
        JR      NZ,L22BA
        XOR     A
        LD      ($4E55),A       ; set Player's Shot Off ??
        JR      L22E9

L22BA:  LD      A,($4E55)       ; else Trigger pulled
        OR      A
        JR      NZ,L22E9
        LD      A,($4E11)       ; if Player's Shot Y stopped...
        BIT     VBSACT,A
        JR      NZ,L22E9
        LD      A,$80           ; ...and VBSTAT not ACTive
        LD      ($4E11),A       ; then turn it on again, and
        LD      A,($4E51)       ; read Player X Position
        ADD     A,$04
        LD      ($4E16),A       ; plus 4 for Player's Shot VBXH
        LD      A,$52
        LD      ($4E55),A       ; 82 for Player Shot On
        LD      ($4E1B),A       ; and Player's Shot VBYH
        LD      A,(CT4)         ; read Counter/Timer #4
        OR      A
        JR      NZ,L22E9        ; bypass if CT4 not counted down
        SYSSUK  BMUSIC          ; UPI Begin playing MUSIC
        DW      MUSSTK          ; ... Music Stack = $4F12
        DB      $C0             ; Setup Voices, Use Tone A  
        DW      L2870           ; Base (Player's Ship) Firing
        ;
; continue after Trigger test
L22E9:  LD      A,($4E51)       ; read Player X Position
        LD      E,A
        LD      A,$00           ; Magic Register to Use
        LD      B,6             ; Y Pattern Size
        LD      C,3             ; X Pattern Size
        LD      D,$54           ; Y Coordinate = 84
        LD      HL,L2993        ; Pattern Address
        SYSTEM  WRIT            ; UPI WRITe Player's Base
        ;
        CALL    L271B           ; do Blank Player's Old Shot
        LD      IX,$4E2A
        CALL    L270A           ; do Erase Invader's Shot #2
        LD      IX,$4E37
        CALL    L270A           ; do Erase Invader's Shot #3
        LD      HL,$4E67        ; point at Invader Delay B
        CALL    L2733           ; do ??
        CALL    L2589           ; do Draw and Check for Collision
        LD      IX,$4E1D
        CALL    L270A           ; do Erase Invader's Shot #1
        LD      HL,$4E66        ; point at Invader Delay A
        CALL    L2733           ; do ??
        CALL    L2589           ; do Draw and Check for Collision
        LD      IX,$4E2A        ; point at Invader's Shot VB #2
        BIT     VBSACT,(IX+VBSTAT) ; test Vector Block STATus = ACTive?
        JR      NZ,L233A
        LD      A,($4E65)       ; read Invader's Footprint
        OR      A
L2332:  SLA     A
        JR      NC,L2332
        OR      A
        JP      Z,L2343
L233A:  LD      HL,$4E68        ; point at Invader Delay C
        CALL    L2733           ; do ??
        CALL    L2589           ; do Draw and Check for Collision
L2343:  LD      A,(GAMDIF)
        OR      A
        JP      Z,L2380
        LD      IX,$4E44
        CALL    L270A           ; do Erase Invader's Shot #4
        LD      HL,L2AF3        ; Limit Table Address [for Invaders]
        SYSTEM  VECT            ; UPI VECTor move coordinate
        ;
        LD      (IX+VBTIMB),$01 ; set Vector Block TIMeBase to single step
        BIT     VBCLAT,(IX+VBYCHK) ; test VB Y CHecK for Limit ATtained
        JR      Z,L236B         ; if still moving
        LD      (IX+VBSTAT),$00 ; else clear VBSACTive bit
        LD      (IX+VBYH),$00   ; clear Vector Block Y High
        JP      L2380

L236B:  IN      A,(INTST)       ; =&(8) ; clear INTercept STatus
        CALL    L270A           ; do Draw Invader's Shot #4
        IN      A,(INTST)       ; =&(8) ; read INTercept STatus
        OR      A
        JP      Z,L2380         ; skip if No collision
        CALL    L270A           ; else do Erase Invader's Shot #4
        LD      (IX+VBSTAT),$00 ; clear VBSACTive bit
        CALL    L2598           ; do ??
; then move Player's Shot
L2380:  LD      IX,$4E10        ; Vector Block for Player's Shot
        LD      HL,L29E8        ; Limit Table Address [for Player]
        SYSTEM  VECT            ; UPI VECTor move coordinate
        ;
        LD      (IX+VBTIMB),$01 ; set Vector Block TIMeBase to single step
        BIT     VBCLAT,(IX+VBYCHK) ; test VB Y CHecK for Limit ATtained
        JR      NZ,L239C        ; if Player's Shot reached Top of Screen
        BIT     VBSACT,(IX+VBSTAT) ; else test Vector Block STATus = ACTive?
        JP      Z,L24CA         ; if Not moving
        JR      L2412           ; else to continue...

; Player's Shot [always ??] made Contact [or Hit the Top]
L239C:  LD      (IX+VBSTAT),$00 ; clear $4E11's ?? VBSACTive bit
        LD      A,$01
        LD      ($4E1C),A       ; reset Player's Shot VBYCHK to VBCLMT
        LD      A,$02
        LD      ($4E52),A       ; write 2 to Invader Explosion counter
        LD      A,($4E16)       ; read Player's Shot VB X High
        LD      E,A
        LD      A,($4E1B)       ; read Player's Shot VB Y High
        LD      D,A
        LD      ($4E53),DE      ; write word to Explosion XY position
        LD      A,($4E6A)       ; read UFO Delta X
        OR      A
        JP      Z,L24CA         ; if UFO NOT moving
        LD      A,($4E6B)       ; else read UFO X Position
        NEG
        ADD     A,E
        JP      M,L24CA
        CP      $0E
        JP      NC,L24CA
        LD      A,D
        CP      $0E
        JP      NC,L24CA
        LD      A,$00
        LD      ($4E52),A       ; clear Invader Explosion counter
        LD      ($4E6A),A       ; and clear UFO Delta X
        SYSSUK  RANGED          ; UPI RANGED random number
        DB      $03             ; ... Cutoff = 3
        ;
        INC     A               ; now 1 to 3
        LD      B,A
        LD      HL,(SCORE)      ; Prepare to work with Player's Score
        ADD     A,H             ; Load High Byte of Score into Accum
        OR      A
        DAA                     ; Decimal Adjust Accumulator
        LD      H,A
        LD      (SCORE),HL
        PUSH    BC
        SYSSUK  BMUSIC          ; UPI Begin playing MUSIC
        DW      MUSSTK          ; ... Music Stack = $4F12
        DB      $C0             ; Setup Voices, Use Tone A
        DW      L28ED           ; Score Address of "UFO Explosion"
        ;
        LD      A,$87           ; write 135 to Counter/Timer #4
        LD      (CT4),A
        POP     BC
        LD      A,($4E6B)       ; copy UFO X Position to
        LD      ($4E7A),A       ;  UFO Explosion X Position
        LD      A,$08           ; write 8 to UFO Explosion Y Position
        LD      ($4E7B),A
        LD      A,$29           ; write 41 to UFO Explosion counter
        LD      ($4E77),A
        LD      H,B             ; still 1-3
        LD      L,$00
        LD      ($4E78),HL      ; write to ??
        CALL    L25BC           ; do Display "SCORE" and Player's Score
        JP      L24CA

; ...continue ??
L2412:  IN      A,(INTST)       ; =&(8) ; clear INTercept STatus
        CALL    L26F7           ; do Draw a Player's Shot
        IN      A,(INTST)       ; =&(8) ; read INTercept STatus
        OR      A
        JP      Z,L24CA
        CALL    L271B           ; do Blank Player's Old Shot
        LD      A,($4E16)
        LD      E,A             ; X Coordinate for UL corner of Rectangle
        LD      A,($4E1B)
        LD      D,A             ; Y Coordinate for UL corner of Rectangle
        LD      C,$04           ; X-Size of Rectangle in Pixels
        LD      B,$04           ; Y-Size of Rectangle in Pixels
        LD      A,$00           ; Color Mask to Write Rectangle with
        SYSTEM  RECTAN          ; UPI paint a RECTANgle
        ;
        LD      IX,$4E10
        LD      A,($4E57)       ; read current Field Y Top
        LD      H,A
        ADD     A,$1D
        LD      L,A
        LD      E,$04
        LD      C,(IX+VBXH)     ; read Vector Block X High
        LD      D,(IX+VBYH)     ; read Vector Block Y High
        LD      IY,$4E5C        ; point at Live Invaders array
L2447:  LD      A,H
        NEG
        ADD     A,D
        CP      $08
        JR      C,L245E
        INC     IY              ; Next ??
        DEC     E               ; ?? Row
        LD      B,$08
L2454:  INC     H               ; H = H + 8 loop [why a loop ??]
        DJNZ    L2454
        LD      A,H
        CP      L
        JP      NC,L239C        ; to Player's Shot Collided ?? if ??
        JR      L2447           ; to loop ??

L245E:  LD      A,H
        LD      ($4E61),A       ; save ?? Temp
        LD      L,E
        LD      A,($4E56)       ; read Field X Left
        LD      H,A
        LD      E,10000000B     ; $80 for Left Invader bit
L2469:  LD      A,H
        NEG
        ADD     A,C
        CP      $0F
        JR      C,L2481
        OR      A
        JP      C,L239C         ; to Player's Shot Collided ?? if ??
        LD      B,$10
L2477:  INC     H               ; H = H + 16 loop [why a loop ??]
        DJNZ    L2477
        SRL     E
        JP      C,L239C         ; to Player's Shot Collided ?? if ??
        JR      L2469           ; loop

L2481:  LD      A,E             ; ?? Mask out Dead Invader here ??
        CPL
        AND     (IY+$00)
        LD      (IY+$00),A
        LD      A,($4E61)       ; un-save ?? Temp
        LD      D,A
        LD      E,H
        SLA     L               ; ?? times 16 for Points
        SLA     L
        SLA     L
        SLA     L
        LD      H,$00
        LD      BC,(SCORE)
        ADD     HL,BC
        LD      A,L
        OR      A               ; [clear CY flag]
        DAA                     ; Decimal Adjust Accumulator
        LD      L,A
        LD      A,$00
        ADC     A,H
        DAA                     ; Decimal Adjust Accumulator
        LD      H,A
        LD      (SCORE),HL
        LD      B,9             ; Y-Size of Recangle (9 Pixels)
        LD      C,12            ; X-Size of Recangle (12 Pixels)
        LD      A,$00           ; Color Mask to Write Rectangle with
        SYSTEM  RECTAN          ; UPI paint a RECTANgle
        ;
        CALL    L25BC           ; do Display "SCORE" and Player's Score
        PUSH    HL
        PUSH    IX
        LD      A,(CT4)         ; read Counter/Timer #4
        OR      A
        JR      NZ,L24C4        ; bypass if CT4 not counted down
        SYSSUK  BMUSIC          ; UPI Begin playing MUSIC
        DW      MUSSTK          ; ... Music Stack = $4F12
        DB      $C0             ; Setup Voices, Use Tone A
        DW      L288C           ; Invader Exploding Sound Effect
        ;
L24C4:  POP     IX
        POP     HL
        JP      L239C           ; to Player's Shot Collided ??

; ??
L24CA:  LD      A,($4E57)       ; read current Field Y Top
        CP      $12
        CALL    NC,L25CC        ; do ?? if ??
        CALL    L27BF           ; do ??
        CALL    L252E           ; do ??
        LD      B,$04
        LD      C,$04
        LD      IY,$4E5C        ; point at Live Invaders array
L24E0:  LD      A,(IY+$03)
        OR      A
        JR      NZ,L24EB
        DEC     IY
        DEC     C
        DJNZ    L24E0
L24EB:  SLA     C
        SLA     C
        SLA     C
        LD      A,($4E57)       ; read current Field Y Top
        ADD     A,C
        CP      $57
        JP      C,L20FB
L24FA:  SYSSUK  STRDIS          ; UPI STRing DISplay
        DB      $32             ; ... X = 50
        DB      $19             ; ... Y = 25
        DB      $6C             ; ... Options (2x X-OR Write in Color 3)
        DW      L293C           ; ... String Address "GAME"
        ;
        EI
        SYSSUK  STRDIS          ; UPI STRing DISplay
        DB      $32             ; ... X = 50
        DB      $2A             ; ... Y = 42
        DB      $6C             ; ... Options (2x X-OR Write in Color 3)
        DW      L2941           ; ... String Address "OVER"
        ;
        CALL    L257B           ; do Silence all Sound Ports
        LD      HL,$DFFF
L250F:  DEC     HL
        LD      A,H
        OR      L
        JR      NZ,L250F
        LD      A,$F0           ; set TIMeOUT to 4 minutes
        LD      (TIMOUT),A
L2519:  SYSSUK  SENTRY          ; UPI SENse TRansition
        DW      L2523           ; ... Keymask Address = 9507
        ;
        SYSSUK  DOIT            ; UPI DOIT table, branch to [translation han]dler
        DW      L2527           ; ... Table Address = 9511
        ;
        JR      L2519

; Key Mask Address for SENTRY
; No Keys are Masked
L2523:  DB      $FF     ; KEYpad column 3 (left side)    x x CE 1 4 7 MR C  T
        DB      $FF     ; KEYpad column 2 (center left)  x x 0  2 5 8 MS ^  O
        DB      $FF     ; KEYpad column 1 (center right) x x .  3 6 9 CH v  P
        DB      $FF     ; KEYpad column 0 (right side)   x x =  + - X Di %

; DOIT Table
; This table seems to be set-up so that when the trigger or any
; key is pressed then the game jumps to the beginning of the
; On-Board ROM and starts again.  This occurs when a game is over.
L2527:  JMPd    ST0, $0000, $00 ; Sentry, Trigger 0 for player 1 has changed
        JMPd    SKYD, $0000, $00 ; Sentry, KeY is now Down
        DB      $FF             ; End DOIT Table ($FF is > $C0)

; Explode UFO routine
L252E:  NOP
        LD      A,($4E77)       ; read UFO Explosion counter
        OR      A
        RET     Z               ; bail if NOT Exploding
        DEC     A
        LD      ($4E77),A       ; bump down Explosion counter
        CP      $28
        JP      Z,L2561         ; to Display Bonus if first step
        OR      A
        JP      Z,L255D         ; to Blank Explosion if now 0
        BIT     0,A             ; Odd or Even?
        JR      Z,L2551
        LD      HL,L29FE        ; Pattern Address (UFO Explosion #1)
        LD      DE,($4E7A)      ; Explosion XY Screen Position [not: Screen Address Used !!]
        LD      A,$20           ; Magic Register for X-OR
        SYSTEM  WRITR           ; UPI WRITe Relative
        ;
        RET

L2551:  LD      HL,L2A0F        ; Pattern Address (UFO Explosion #2)
        LD      DE,($4E7A)      ; Explosion XY Screen Position [not: Screen Address Used !!]
        LD      A,$20           ; Magic Register for X-OR
        SYSTEM  WRITR           ; UPI WRITe Relative
        ;
        RET

; Blank UFO Explosion
L255D:  CALL    L263E           ; do Erase UFO subroutine [could be JP ??]
        RET

; Display Bonus Score next to UFO
L2561:  LD      A,($4E6B)       ; read UFO X Position
        CP      $4A
        JR      NC,L256C        ; if Right of Center of Screen 
        ADD     A,$14           ; else [0-73] print to Right of UFO
        JR      L256E

L256C:  SUB     $1C             ; [at 74 or higher] print to Left of UFO
L256E:  LD      D,$08           ; DE Holds X,Y Coordinate
        LD      E,A             ;
        LD      HL,$4E78        ; Address of BCD Number for UFO Bonus
        LD      B,$83           ; Extended Options (0 Supp, 3 digits)
        LD      C,$04           ; Standard Alphanumeric Options Byte
        SYSTEM  DISNUM          ; UPI DISplay NUMber [PLOP in Color 1]
        ;
        RET

; Silence all Sound Ports
L257B:  NOP
        PUSH    AF
        LD      A,$00           ; Get Ready to Zero-out Sound Ports
        OUT     (VIBRA),A       ; &(20) = write VIBRAto frequency & range
        OUT     (VOLC),A        ; &(21) = write VOLume of tone C
        OUT     (VOLAB),A       ; &(22) = write VOLumes of tones A & B
        OUT     (VOLN),A        ; &(23) = write VOLume of Noise
        POP     AF
        RET

; Draw Invader's Shot [#1, 2, or 3] and Check for Collision routine
L2589:  IN      A,(INTST)       ; =&(8) ; clear INTercept STatus
        CALL    L270A           ; do Draw Invader's Shot #[??]
        IN      A,(INTST)       ; =&(8) ; read INTercept STatus
        OR      A
        RET     Z               ; done if No collision
        CALL    L270A           ; do Erase Invader's Shot #[??]
        LD      (IX+VBSTAT),A   ; set VBSACTive bit 7 to ??
; Collision ?? Invader's Shot #4 finishes here ??
L2598:  LD      E,(IX+VBXH)     ; read VB X High for UL Corner of Rectangle
        LD      D,(IX+VBYH)     ; read Vector Block Y High
        DEC     D               ; Y Coordinate for UL corner of Rectangle
        XOR     A               ; Color 0 Mask to Write Rectangle with
        LD      B,7             ; Y-Size of Rectangle (7 Pixels)
        LD      C,4             ; X-Size of Rectangle (4 Pixels)
        SYSTEM  RECTAN          ; UPI paint a RECTANgle
        ;
        LD      A,(IX+VBYH)     ; read Vector Block Y High
        CP      $50
        RET     C               ; if above 80 a Bunker was hit
        LD      A,($4E51)       ; read Player X Position
        LD      E,A
        LD      A,(IX+VBXH)     ; read Vector Block X High
        SUB     E
        DEC     A
        CP      $08
        RET     NC
        POP     HL              ; eat Return Address and continue...
        JP      L264A

; Display "SCORE" and Player's Score
; ----------------------------------
;    This routine displays the string "SCORE" on the
;    top-middle of screen followed by the player's score

; Display Player's Score
L25BC:  SYSSUK  DISNUM          ; UPI DISplay NUMber [PLOP Write]
        DB      124             ; X Coordinate (Character Position 17)
        DB      0               ; Y Coordinate (Top of Screen)
        DB      $0C             ; Options ("On Color" = 3, "Off Color" = 0)
        DB      $84             ; Extended Options (Suppress Leading Zero
                                ;   and Display 4 Digits)
        DW      SCORE           ; BCD Number Address of Player's Score
        ;
; Display "SCORE String"
        SYSSUK  STRDIS          ; UPI STRing DISplay
        DB      $50             ; ... X = 80
        DB      $00             ; ... Y = 0
        DB      $1C             ; ... Options (OR Write in Color 3)
        DW      L2936           ; ... String Address "SCORE"
        ;
        RET

; ?? routine
L25CC:  LD      A,($4E77)       ; read UFO Explosion counter
        OR      A
        RET     NZ              ; bail if Exploding
        LD      A,($4E6A)       ; read UFO Delta X
        OR      A
        JR      NZ,L260E        ; if already in Motion
        LD      A,$96
        SYSTEM  RANGED          ; UPI RANGED random number 0 to 149
        ;
        CP      $03
        RET     NZ
        SYSTEM  RANGED          ; UPI RANGED random number 0 to 2
        ;
        CP      $01             ; [only start Once in 150 x 3 calls]
        RET     NZ
        LD      A,(CT4)         ; read Counter/Timer #4
        OR      A
        JR      NZ,L25F5        ; bypass if CT4 not counted down
        SYSSUK  BMUSIC          ; UPI Begin playing MUSIC
        DW      MUSSTK          ; ... Music Stack = $4F12
        DB      $C0             ; Setup Voices, Use Tone A
        DW      L28D1           ; Score Address of "UFO Flying"
        ;
        LD      A,$32           ; write 50 to Counter/Timer #4
        LD      (CT4),A
L25F5:  NOP
        LD      A,($4E60)       ; read Invader Delta X [+1 or -1]
        NEG
        LD      ($4E6A),A       ; write -Delta X to UFO Delta X
        OR      A
        JP      M,L2609         ; if negative [moving Left] Delta
        LD      A,$00           ; else [Right] write 0 to UFO X Position
        LD      ($4E6B),A
        JR      L260E

L2609:  LD      A,$96           ; write 150 to UFO X Position
        LD      ($4E6B),A
; start sound effect (if not already playing)
L260E:  LD      A,(CT4)         ; read Counter/Timer #4
        OR      A
        JR      NZ,L2620        ; bypass if CT4 not counted down
        LD      A,$28           ; write 40 to Counter/Timer #4
        LD      (CT4),A
        SYSSUK  BMUSIC          ; UPI Begin playing MUSIC
        DW      MUSSTK          ; ... Music Stack = $4F12
        DB      $C0             ; ... Setup Voices, Use Tone A
        DW      L28D1           ; ... Score Address of "UFO Flying"
; move then Draw UFO (or Erase if at limits)
L2620:  NOP
        LD      A,($4E6A)       ; read UFO Delta X
        LD      C,A
        LD      A,($4E6B)
        ADD     A,C             ; add to UFO X Position
        LD      ($4E6B),A
        OR      A
        JR      Z,L263E         ; to Erase UFO if at Left edge
        CP      $97
        JR      Z,L263E         ; to Erase UFO if at Right edge
        LD      E,A             ; X Coordinate
        LD      D,$09           ; Y Coordinate
        LD      A,$00           ; Magic Register to PLOP
        LD      HL,L2A45        ; Pattern Address (UFO)
        SYSTEM  WRITP           ; UPI WRITe with Pattern size
        ;
        RET

; Erase UFO subroutine
L263E:  XOR     A
        LD      ($4E6A),A       ; write 0 to UFO Delta X
        SYSSUK  RECTAN          ; UPI paint a RECTANgle
        DB      $00             ; ... X = 0
        DB      $08             ; ... Y = 8
        DB      $9F             ; ... Width = 159
        DB      $07             ; ... Height = 7
        DB      $00             ; ... Color = 0
        ;
        RET

; ...continued ??
L264A:  NOP
        PUSH    HL
        PUSH    IX
        SYSSUK  BMUSIC          ; UPI Begin playing MUSIC
        DW      MUSSTK          ; ... Music Stack = $4F12
        DB      $FC             ; ; Setup Voices, Use Tones A, B, and C
        DW      L28A9           ; Score Address of "Base Exploding"
        ;
        POP     IX
        POP     HL
        LD      A,$46           ; write 70 to Base Explosion counter
        LD      ($4E7C),A
L265D:  LD      A,$02           ; write 2 to Counter/Timer #2
        LD      (CT2),A
L2662:  LD      A,(CT2)         ; read Counter/Timer #2 [Wait for 2 interrupts!!]
        OR      A
        JR      NZ,L2662        ; loop (-$05) while CT2 not counted down
        LD      A,($4E7C)       ; read Base Explosion counter again
        OR      A
        RET     Z               ; exit if NOT Exploding
        DEC     A
        LD      ($4E7C),A       ; bump down Explosion counter
        OR      A
        JP      Z,L268F         ; to Blank if now 0
        BIT     0,A             ; Odd or Even step?
        JP      Z,L267F
        LD      HL,L2A25        ; point at Base Explosion #1
        JR      L2682

L267F:  LD      HL,L2A35        ; point at Base Explosion #2
L2682:  LD      A,($4E51)       ; read Player X Position
        LD      E,A             ; X Coordinate
        LD      D,$54           ; Y Coordinate
        LD      A,$20           ; Magic Register for X-OR
        SYSTEM  WRITR           ; UPI WRITe Relative
        ;
        JP      L265D           ; to loop

; blank Explosion and 
L268F:  CALL    L257B           ; do Silence all Sound Ports
        SYSSUK  RECTAN          ; UPI paint a RECTANgle
        DB      $00             ; ... X = 0
        DB      $4F             ; ... Y = 79
        DB      $9F             ; ... Width = 159
        DB      $0B             ; ... Height = 11
        DB      $00             ; ... Color = 0
        ;
        LD      A,$08           ; write 8 to Player X Position
        LD      ($4E51),A
        LD      A,(LIVES)       ; Load ACCUM with Number of Bases
        DEC     A               ; Decrease Extra Bases by 1
        LD      (LIVES),A       ; A Player's Base has been Destroyed
        CALL    L26AB           ; do Display "BASES" and bases left on screen
        JP      L20FB           ; to continue ??

; Display "BASES" and Bases Available
; -----------------------------------;
;    This routine displays the string "BASES" in the
;    top-left corner followed by the number of bases
;    left available to the player.

; Display Bases Left or ("Lives")
L26AB:  SYSSUK  DISNUM          ; UPI DISplay NUMber [PLOP Write]
        DB      48              ; X Coordinate (Character Position 7)
        DB      0               ; Y Coordinate (Top of Screen)
        DB      $0C             ; Options ("On Color" = 3, "Off Color" = 0)
        DB      $82             ; Extended Options (Suppress Leading Zero
                                ;   and Display 2 Digits)
        DW      LIVES           ; Address of "Lives"
        ;
; Display "BASES" String
        SYSSUK  STRDIS          ; UPI STRing DISplay
        DB      8               ; X Coordinate
        DB      0               ; Y Coordinate (Top of Screen)
        DB      $1C             ; Options (OR Write, Color = 3 on Color = 0)
        DW      L2930           ; String Address for "BASES"
        ;
        RET

; Cycle and Output HeartBeep routine
L26BB:  LD      A,($4E75)
        BIT     0,A             ; Odd or Even Heart Beat pass?
        RET     NZ
        LD      A,$92           ; Beep on Even pass only
        OUT     (TONMO),A       ; &(16)= 146; write TONe Master Oscillator
        LD      A,($4E76)       ; [read, but not used !!]
        LD      A,$0F
        OUT     (VOLC),A        ; &(21) = 15; for max VOLume of tone C
        LD      HL,L286C        ; point at Heartbeat Pitch table
        LD      A,($4E74)       ; cycle Heart Beep tone from 0-3
        CP      $03
        JR      NC,L26D9
        INC     A
        JR      L26DB

L26D9:  LD      A,$00
L26DB:  LD      ($4E74),A       ; save Heart Beep + 1
        LD      E,A
        LD      D,$00
        ADD     HL,DE
        LD      A,(HL)
        OUT     (TONEC),A       ; &(19)= Note ; write TONe C oscillator
        RET

; Reverse Direction and Drop Invaders [by 2 pixels] routine
L26E6:  LD      A,($4E60)       ; read Invader Delta X
        NEG
        LD      ($4E60),A       ; write -Delta X
        LD      A,($4E57)       ; old Field Y Top + 2 for new Y Top
        INC     A
        INC     A
        LD      ($4E57),A
        RET

; Draw a Player's Shot
L26F7:  LD      IX,$4E10        ; point at Player's Shot Vector Block
        LD      (IX+VBMR),$20
        BIT     VBSACT,(IX+VBSTAT) ; test Vector Block STATus = ACTive?
        RET     Z
        LD      HL,L29F5        ; Pattern Address (Player's Shot)
        SYSTEM  VWRITR          ; UPI Vector WRITe Relative
        ;
        RET

; Draw or Erase an Invader's Shot
L270A:  BIT     VBSACT,(IX+VBSTAT) ; test Vector Block STATus = ACTive?
        RET     Z
        LD      A,(IX+VBYH)     ; read Vector Block Y High
        CP      $14
        RET     C
        LD      HL,L29EC        ; Pattern Address (Invader's Shot)
        SYSTEM  VWRITR          ; UPI VECTOR WRITe Relative
        ;
        RET

; Blank Player's OLD Shot routine
L271B:  LD      IX,$4E10        ; point at Player's Shot Vector Block
        BIT     VBSACT,(IX+VBSTAT) ; test Vector Block STATus = ACTive?
        RET     Z
        LD      D,(IX+VBYH)     ; read VB Y High for UL Corner of Rectangle
        LD      E,(IX+VBXH)     ; read VB X High for UL Corner of Rectangle
        LD      B,$06           ; Y-Size of Rectangle in Pixels
        LD      C,$01           ; X-Size of Rectangle in Pixels
        LD      A,$00           ; Color Mask to Write Rectangle with
        SYSTEM  RECTAN          ; UPI PAINT A RECTANGLE
        ;
        RET

; ?? routine
L2733:  PUSH    HL              ; store the Invader Delay pointer
        IN      A,(INTST)       ; =&(8) ; clear INTercept STatus [why??]
        LD      A,(IX+VBSTAT)   ; read Vector Block STATus
        BIT     VBSACT,A
        JP      NZ,L27A2        ; skip if already ACTive bit
        LD      A,(HL)          ; read Invader's Delay value ??
        OR      A
        JP      NZ,L27A2        ; skip if moving ??
        LD      A,$08
        SYSTEM  RANGED          ; UPI RANGED random number 0 to 7
        ;
        LD      B,A
        LD      C,$80
L274A:  OR      A
        JR      Z,L2752
        DEC     A
        SRL     C
        JR      L274A

L2752:  LD      A,($4E65)       ; read Invader's Footprint
        LD      D,A
L2756:  LD      A,D
        AND     C
        JR      NZ,L275E
        RLC     C
        JR      L2756

L275E:  LD      A,$78
        LD      (HL),A
        LD      (IX+VBSTAT),$80 ; set VBSACTive bit
        LD      A,($4E57)       ; read current Field Y Top
        ADD     A,$1F
        LD      H,A
        LD      IY,$4E5C        ; point at Live Invaders array
        LD      A,C
        LD      E,$00
        AND     (IY+$03)
        JR      NZ,L2789
        LD      E,$08
        LD      A,C
        AND     (IY+$02)
        JR      NZ,L2789
        LD      E,$10
        LD      A,C
        AND     (IY+$01)
        JR      NZ,L2789
        LD      E,$18
L2789:  LD      A,H
        SUB     E
        LD      (IX+VBYH),A     ; save as Vector Block Y High
        CP      $52
        JR      NC,L27BB        ; exit if ?? below Line 81
        LD      A,($4E56)       ; read Field X Left
L2795:  BIT     7,C
        JR      NZ,L279F
        SLA     C
        ADD     A,$10
        JR      L2795

L279F:  LD      (IX+VBXH),A     ; save as Vector Block X High
; skip to here on ??
L27A2:  LD      HL,L2AF3        ; Limit Table for [Invader's Shots] VECT
        SYSTEM  VECT            ; UPI VECTOR MOVE COORDINATE
        ;
        LD      (IX+VBTIMB),$01 ; set Vector Block TIMeBase to single step
        POP     HL              ; restore the Invader Delay pointer
        INC     HL              ; plus 1 ??
        BIT     VBCLAT,(IX+VBYCHK) ; test VB Y CHecK for Limit ATtained
        RET     Z
; else hit Bottom of the screen
L27B2:  LD      (IX+VBSTAT),$00 ; clear VBSACTive bit
        LD      (IX+VBYH),$00   ; clear Vector Block Y High
        RET

; clean exit for ??
L27BB:  POP     HL              ; restore the Invader Delay pointer
        INC     HL              ; plus 1 ??
        JR      L27B2

; Explode a Invader routine
L27BF:  LD      A,($4E52)       ; read Invader Explosion counter
        OR      A
        RET     Z               ; bail if NOT Exploding
        DEC     A
        LD      ($4E52),A       ; bump down Explosion counter
        JR      Z,L27D6         ; to Blank if now 0
        LD      HL,L29FE        ; Pattern Address {Invader Explosion}
        LD      DE,($4E53)      ; Explosion X, Y Coordinate
        LD      A,$20           ; Magic Register for X-OR
        SYSTEM  WRITR           ; UPI WRITe Relative [On, then Off]
        ;
        RET

; Blank Invader Explosion
L27D6:  LD      DE,($4E53)      ; read word Explosion XY position
        DEC     E               ; center with X - 4
        DEC     E
        DEC     E
        DEC     E
        LD      C,$09           ; Width/Height = 6 x 9
        LD      B,$06
        XOR     A
        SYSTEM  RECTAN          ;  UPI paint (blank) RECTANgle
        ;
        RET     

; Draw a Row of Invaders
; ----------------------
;   This routine draw one row of Invaders.
L27E6:  EXX                     ; Exchange Alternate Registers
        LD      A,($4E5A)       ; limit [Which Row] to 0 through 3
        CP      $04
        JR      C,L27F3
        LD      A,$00
        LD      ($4E5A),A       ; clear [Which Row] if 4 or more
L27F3:  LD      HL,$4E5C        ; point at first of 4 $FFs [32 Bits for 32 Invaders]
        LD      E,A
        LD      D,$00
        ADD     HL,DE           ; add 0-3 for $4E5C thru $4E5F [8 Bits for 8 Invaders]
        LD      B,(HL)
        LD      IX,$4E56
        LD      A,(IX+$01)      ; read $4E57 ?? current Field Y Top
        SLA     E               ; 0-3 times 8
        SLA     E
        SLA     E
        ADD     A,E             ; Field Top plus ??
        LD      (IX+$03),A      ; save as $4E59 ?? current Row Y Top
        LD      (IX+$05),$00    ; clear $4E5B ??
; loop for ??
L2810:  BIT     7,B             ; test ??
        JR      Z,L285F         ; break if ??
        LD      IY,L2920        ; point at 'Invader patterns by Row' table
        LD      D,$00
        LD      E,(IX+$04)      ; read $4E5A ?? [Which Row 0-3 from the top??]
        SLA     E               ; times 4
        SLA     E
        LD      A,($4E56)       ; read Field X Left
        AND     $02             ; mask 00000010B for ?? Alternate Invader pattern
        ADD     A,E             ; ?? plus Row x 4
        LD      E,A
        ADD     IY,DE           ; add ?? offset to get:
        LD      L,(IY+$00)      ; H and L Make the Pattern...
        LD      H,(IY+$01)      ;   ...Address for WRITP
        LD      E,(IX+$00)      ; read $4E56 ?? Field X Left
        LD      A,(IX+$05)      ; read $4E5B ??
        SLA     A               ; times 8
        SLA     A
        SLA     A
        SLA     A
        ADD     A,E             ; plus ??
        LD      E,A             ; X Coordinate for WRITP
        LD      D,(IX+$03)      ; $4E59 ?? Y Coordinate for WRITP
        LD      A,$00           ; Magic Register for WRITP
        PUSH    IX
        PUSH    BC
        SYSTEM  WRITP           ; UPI WRITe with Pattern size
        ;
        LD      A,(GAMDIF)      ; Read GAMe DIFficulty
        LD      B,$FF           ; Default Delay
        CP      $02
        JR      C,L2859         ; if Amateur or Novice
        JR      Z,L2857         ; if Imtermediate [medium Delay]
        JR      L285C           ; else Professional [no Delay]

L2857:  LD      B,$64
L2859:  NOP
        DJNZ    L2859           ; delay Loop by Difficulty
L285C:  POP     BC
        POP     IX
; to next Invader bit
L285F:  INC     (IX+$05)        ; $4E5B ?? [for right edge ??]
        SLA     B
        JR      NZ,L2810        ; while Invaders remain in Row
        INC     (IX+$04)        ; $4E5A ?? [for Next Row to draw ??]
        EXX                     ; Exchange Alternate Registers
        RET

; L286B: ?? [loose RETurn, not used ??]
        DB      $C9

; Sound Effects and Music Scores
; ------------------------------

; Heartbeat Pitch table
L286C:
        DB      G0              ; $FD note values
        DB      A0              ; $E1
        DB      B0              ; $C8
        DB      C1              ; $BD

; Sound Effect of Base (Player's Ship) Firing Laser Cannon
; Music Score, Called from BMUSIC on $22E2
; BMUSIC Setup Tone A for this Music Score 
L2870:  MASTER  $92             ; Set Tone of Master Oscillator to $92
        OUTPUT  $04, $85        ; Set VIBRA (Port $14) frequency & range to $85
        LEGSTA                  ; Flip to LEGato from STAccato
        VOLUME  $06, $00        ; Sets Volumes TONE A = 6, Tone B = 0, and Tone C = 0
        NOTE1   $12,C6          ; Duration, Tone A Note
        NOTE1   $02,DS6         ; Duration, Tone A Note
        NOTE1   $04,C6          ; Duration, Tone A Note
        VOLUME  $24,$00         ; Sets Volumes Tone A = 4, Tone B = 2, and Tone C = 0
        VOICEM  $F0             ; Voices, Use Tone A and B
        NOTE2   $04,DS6,A5      ; Duration, Tone B Note
        NOTE2   $04,F5,A5       ; Duration, Tone B Note
        OUTPUT  $04,$00         ; Set VIBRA (Port $14) frequency & range to 0
        QUIET                   ; Stops Music and Sets Volume to 0 

; Invader Exploding Sound Effect
; Music Score, Called from BMUSIC on $24BD
; BMUSIC Setup Tone A for this Music Score
L288C:  MASTER  $92             ; Set Tone of Master Oscillator to $92
        VOLUME  $06,$00         ; Sets Volumes Tone A = 6, Tone B = 0, and Tone C = 0
        LEGSTA                  ; Flip to LEGato from STAccato
        NOTE1   $01,DS5         ; Duration, Tone A Note
        PUSHN   3               ; Push Number onto Music Stack
L2895:  NOTE1   $01,C5          ; Duration, Tone A Note
        NOTE1   $01,DS5         ; Duration, Tone A Note
        NOTE1   $01,G5          ; Duration, Tone A Note
        NOTE1   $01,DS5         ; Duration, Tone A Note
        NOTE1   $01,$0C         ; Duration, Tone A Note
        NOTE1   $01,F5          ; Duration, Tone A Note
        NOTE1   $01,G5          ; Duration, Tone A Note
        NOTE1   $01,F5          ; Duration, Tone A Note
        DSJNZ   L2895           ; Decrement Stack Top and Jump [if Not Zero]         
        QUIET                   ; Stops Music and Sets Volume to 0

; Sound Effect of "Base Exploding"
; Music Score, Called from BMUSIC on $264E
; BMUSIC Setup Tones A, B and C for this Music Score
L28A9:  MASTER  255             ; Set Tone of Master Oscillator to $FF
        VOLUME  $FF,$1F         ; Sets Volumes Tone A = 15, Tone B = 15, Tone C = 15, [and NM = 1]
        LEGSTA                  ; Flip to LEGato from STAccato
        OUTPUT  $07,$F0         ; Noise Volume = 15 
        NOTE3   50,$88,$D4,$F8  ; Duration = 50/60'th of a sec, TC= TB= TA=
        VOLUME  $CA,$1C         ; Sets Volumes Tone A = 10, Tone B = 12, Tone C = 12, [and NM = 1]
        OUTPUT  $07,$B8         ; Noise Volume = 184
        NOTE3   30,$88,$D2,$FA  ; Duration = 30/60'th of a Sec, TC= TB= TA=
        VOLUME  $BA,$1B         ; Sets Volumes Tone A = 10, Tone B = 11, Tone C = 11, [and NM = 1]
        OUTPUT  $07,$80         ; Noise Volume = 8
        NOTE3   30,$8E,$DD,$FF  ; Duration = 30/60'th of a Sec, TC= TB= TA=
        VOLUME  $86,$16         ; Sets Volumes Tone A = 6, Tone B = 8, Tone C = 6, [and NM = 0]
        OUTPUT  $07,$00         ; Noise Volume = 0
        NOTE3   25,$90,$E0,$FF  ; Duration = 25/60'th of a Sec, TC= TB= TA=
        QUIET

; Sound Effect of "UFO Flying"
; Music Score, Called from BMUSIC on $25EB and $261B
; BMUSIC Setup Tone A for this Music Score
L28D1:  MASTER  146             ; Set Tone of Master Oscillator to 146
        LEGSTA                  ; Flip to LEGato from STAccato
        PUSHN   3               ; Push Number onto Music Stack
        OUTPUT  $02,$09         ; [Port $12] Tone B = 9
L28D7:  PUSHN   13              ; Push Number onto Music Stack
L28D8:  VOLUME  $14,$00         ; Sets Volumes Tone A = 4, Tone B = 1, and Tone C = 0
        NOTE1   $01,$0B         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$0C         ; Duration = 1/60'th of a Sec, TA=
        VOLUME  $05,$00         ; Sets Volumes Tone A = 5, Tone B = 0, and Tone C = 0
        NOTE1   $01,$0F         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$0C         ; Duration = 1/60'th of a Sec, TA=
        DSJNZ   L28D8           ; Decrement Stack Top and Jump
        DSJNZ   L28D7           ; Decrement Stack Top and Jump
        QUIET

; Sound Effect of "UFO Explosion"
; Music Score, Called from BMUSIC on $23EB
; BMUSIC Setup Tone A for this Music Score
L28ED:  MASTER  146             ; Set Tone of Master Oscillator to 146
        VOLUME  $06,$00         ; Sets Volumes Tone A = 6, Tone B = 0, and Tone C = 0
        LEGSTA                  ; Flip to LEGato from STAccato
        NOTE1   $01,$0A         ; Duration = 1/60'th of a Sec, TA=
        PUSHN   9               ; Push Number onto Music Stack
L28F6:  NOTE1   $01,$09         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$08         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$07         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$08         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$09         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$0A         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$0B         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$0C         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$0B         ; Duration = 1/60'th of a Sec, TA=
        NOTE1   $01,$0A         ; Duration = 1/60'th of a Sec, TA=
        DSJNZ   L28F6           ; Decrement Stack Top and Jump
        QUIET

; When I played this sound effect it makes no noise.  The Score is
; short.  Tone A SHOULD be making two notes at about half volume...
; I'm not sure why this isn't workin.
;
; Sound Effect of "Bonus Base Awarded"
; Music Score, Called from BMUSIC on $21C7
; BMUSIC Setup Tone A for this Music Score
L290E:  MASTER  $92             ; Set Tone of Master Oscillator to 146
        LEGSTA                  ; Flip to LEGato from STAccato
        PUSHN   9               ; Push Number onto Music Stack
L2912:  VOLUME  $09,$00         ; Sets Volumes Tone A = 9, Tone B = 0, and Tone C = 0
        NOTE1   4,$0C           ; Duration = 4/60'th of a Sec, TA=
        VOLUME  $09,$00         ; Sets Volumes Tone A = 9, Tone B = 0, and Tone C = 0
        NOTE1   4,$07           ; Duration = 4/60'th of a Sec, TA=
        DSJNZ   L2912           ; Decrement Stack Top and Jump [if Not Zero]
        QUIET

; Invader Pattern pairs for 4 Rows table
L2920:  DW      L2A8B           ; Green Invader (Top Row) pattern address
        DW      L2AA5           ; Green Invader (Alt. Version) ditto...
        DW      L2A57           ; Red Invader (Top-Middle Row)
        DW      L2A71           ; Red Invader (Alt. Version)
        DW      L2ABF           ; Blue Invader - Second-from-Bottom Row
        DW      L2AD9           ; Blue Invader - Second-from-Bottom Row (Alt. Version)
        DW      L2AD9           ; Blue Invader - Bottom-Row Invader [again but swapped]
        DW      L2ABF           ; Blue Invader - Bottom-Row Invader (Alt. Version)

L2930:  DB      "BASES",$00
L2936:  DB      "SCORE",$00
L293C:  DB      "GAME",$00
L2941:  DB      "OVER",$00
L2946:  DB      "ENTER LEVEL",$00

L2952:  DW      L2958   ; Link to Choice 2
        DW      L296A   ; Address of Choice 1 Menu Text, "NOVICE"
        DW      L2019   ; Jump here if Choice 1 is selected
L2958:  DW      L295E   ; Link to Choice 3
        DW      L2971   ; Address of Choice 2 Menu Text, "AMATEUR"
        DW      L200D   ; Jump here if Choice 2 is selected
L295E   DW      L2964   ; Link to Choice 4
        DW      L2979   ; Address of Choice 3 Menu Text, "INTERMEDIATE"
        DW      L2011   ; Jump here if Choice 3 is selected
L2964   DW      $0000   ; Last Link in Linked List
        DW      L2986   ; Address of Choice 3 Menu Text, "PROFESSIONAL"
        DW      L2015   ; Jump here if Choice 4 is selected

L296A:  DB      "NOVICE",$00
L2971:  DB      "AMATEUR",$00
L2979:  DB      "INTERMEDIATE",$00
L2986:  DB      "PROFESSIONAL",$00

; Pattern (Player's Base, 3x6) note: ALL are in 4-Color
L2993:  DB      00000000B,11000000B,00000000B ; . . . . 3 . . . . . . .
        DB      00000000B,11000000B,00000000B ; . . . . 3 . . . . . . .
        DB      00000011B,11110000B,00000000B ; . . . 3 3 3 . . . . . .
        DB      00001111B,11111100B,00000000B ; . . 3 3 3 3 3 . . . . .
        DB      00001111B,11111100B,00000000B ; . . 3 3 3 3 3 . . . . .
        DB      00001111B,11111100B,00000000B ; . . 3 3 3 3 3 . . . . .

; Pattern (Player's "Protective Bunkers")
L29A5:  DB      5, 13           ; 5 bytes, 13 lines pattern size
        DB      00000011B,11111111B,11111111B,11111111B,11000000B
        DB      00001111B,11111111B,11111111B,11111111B,11110000B
        DB      00111111B,11111111B,11111111B,11111111B,11111100B
        DB      11111111B,11111111B,11111111B,11111111B,11111111B
        DB      11111111B,11111111B,11111111B,11111111B,11111111B
        DB      11111111B,11111111B,11111111B,11111111B,11111111B
        DB      11111111B,11111111B,11111111B,11111111B,11111111B
        DB      11111111B,11111111B,11111111B,11111111B,11111111B
        DB      11111111B,11111111B,11111111B,11111111B,11111111B
        DB      11111111B,11110000B,00000000B,00001111B,11111111B
        DB      11111111B,11000000B,00000000B,00000011B,11111111B
        DB      11111111B,00000000B,00000000B,00000000B,11111111B
        DB      11111111B,00000000B,00000000B,00000000B,11111111B

; Limit Table Address for Player's Shot VECT
L29E8:  DB      1                ; X Lower Limit (Left Edge of Screen + 1)
        DB      160              ; X Upper Limit (Right Edge of Screen)
        DB      10               ; Y Lower Limit (Right Below the Score)
        DB      90               ; Y Upper Limit (Bottom of Screen)

; Pattern, Invader's Shot (for VWRITR)
L29EC:  DB      0, 0            ; X,Y Displacement
        DB      1, 5            ; X, Y Size
        DB      00000000B       ; . . . .
        DB      00100000B       ; . 2 . .
        DB      10000000B       ; 2 . . .
        DB      00100000B       ; . 2 . .
        DB      10000000B       ; 2 . . .

; Pattern, Player's Shot (for VWRITR)
L29F5:  DB      0, 0            ; X,Y Displacement
        DB      1, 5            ; X, Y Size
        DB      10000000B       ; 2 . . .
        DB      10000000B       ; 2 . . .
        DB      10000000B       ; 2 . . .
        DB      10000000B       ; 2 . . .
        DB      10000000B       ; 2 . . .

; Pattern Address (Invader Explosion, and UFO Explosion #1)
L29FE:  DB      $FC, $00            ; X,Y Displacement
        DB      2, 6                ; X, Y Size
        DB      00110000B,00001100B ; . 3 . . . . 3 .
        DB      00111100B,00001100B ; . 3 3 . . . 3 .
        DB      00110111B,11000111B ; . 3 1 3 3 . 1 3
        DB      11110101B,01010111B ; 3 3 1 1 1 1 1 3
        DB      00111111B,11111100B ; . 3 3 3 3 3 3 .
        DB      11001111B,11111111B ; 3 . 3 3 3 3 3 3
        
        DB      $FC             ; stray -4 X Displacement ??

; Pattern (UFO Explosion #2)
L2A0F:  DB      0, 0            ; X, Y Displacement
        DB      3, 6            ; X, Y Pattern Size
        DB      10101101B,00010111B,01000011B ; 2 2 3 1 . 1 1 3 1 . . 3
        DB      00111000B,10001111B,00101101B ; . 3 2 . 2 . 3 3 . 2 3 1
        DB      00001100B,11111111B,10101010B ; . . 3 . 3 3 3 3 2 2 2 2
        DB      10011001B,00100011B,01111111B ; 2 1 2 1 . 2 . 3 1 3 3 3
        DB      11100000B,00000011B,00000110B ; 3 2 . . . . . 3 . . 1 2
        DB      00101101B,11110000B,10011100B ; . 2 3 1 3 3 . . 2 1 3 .

; Pattern (Base Explosion #1)
L2A25:  DB      0, 0            ; X, Y Displacement
        DB      2, 6            ; X, Y Pattern Size
        DB      00100000B,00000100B ; . 2 . . . . 1 .
        DB      10100000B,00101010B ; 2 2 . . . 2 2 2
        DB      10101000B,00000010B ; 2 2 2 . . . . 2
        DB      10101010B,10101111B ; 2 2 2 2 2 2 3 3
        DB      11111111B,00111000B ; 3 3 3 3 . 3 2 .
        DB      01100011B,10101010B ; 1 2 . 3 2 2 2 2

; Pattern (Base Explosion #2)
L2A35:  DB      0, 0            ; X, Y Displacement
        DB      2, 6            ; X, Y Pattern Size
        DB      10000010B,10000010B ; 2 . . 2 2 . . 2
        DB      10100010B,10000010B ; 2 2 . 2 2 . . 2
        DB      10100010B,10011010B ; 2 2 . 2 2 1 2 2
        DB      01101111B,11010011B ; 1 2 3 3 3 1 . 3
        DB      00100010B,10010110B ; . 2 . 2 2 1 1 2
        DB      10100000B,10100000B ; 2 2 . . 2 2 . .

; Pattern (UFO)
L2A45:  DB      4, 4            ; X, Y Pattern Size
        DB      00000000B,00101010B,10100000B,00000000B ; . . . . . 2 2 2 2 2 . . . . . .
        DB      00000010B,10101010B,10101010B,00000000B ; . . . 2 2 2 2 2 2 2 2 2 . . . .
        DB      00101000B,10001000B,10001000B,10100000B ; . 2 2 . 2 . 2 . 2 . 2 . 2 2 . .
        DB      00001010B,10101010B,10101010B,10000000B ; . . 2 2 2 2 2 2 2 2 2 2 2 . . .

; Pattern - Red Invader (Top-Middle Row)
; Uses Colors 0-2 (Right side of Horizontal Color Boundary)
;        COL2R - Red (Invader's Body)
;        COL1R - Blue (Invader's Eyes)
;        COL0R - Black (Background)
L2A57:  DB      3, 8            ; X, Y Pattern Size
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,10000010B,00000000B ; . . . . 2 . . 2 . . . .
        DB      00001000B,00101000B,00100000B ; . . 2 . . 2 2 . . 2 . .
        DB      00001010B,10101010B,10100000B ; . . 2 2 2 2 2 2 2 2 . .
        DB      00001010B,01101001B,10100000B ; . . 2 2 1 2 2 1 2 2 . .
        DB      00000000B,10000010B,00000000B ; . . . . 2 . . 2 . . . .
        DB      00000000B,00101000B,00000000B ; . . . . . 2 2 . . . . .

; Pattern - Red Invader (Alt. Version)
L2A71:  DB      3, 8            ; X, Y Pattern Size
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,10000010B,00000000B ; . . . . 2 . . 2 . . . .
        DB      00000000B,00101000B,00000000B ; . . . . . 2 2 . . . . .
        DB      00000010B,10101010B,10000000B ; . . . 2 2 2 2 2 2 . . .
        DB      00001010B,01101001B,10100000B ; . . 2 2 1 2 2 1 2 2 . .
        DB      00001000B,10000010B,00100000B ; . . 2 . 2 . . 2 . 2 . .
        DB      00000000B,10000010B,00000000B ; . . . . 2 . . 2 . . . .

; Pattern - Green Invader (Top Row)
; Uses Colors 0-2 (Right side of Horizontal Color Boundary)
;        COL2R - Red (Invader's Eyes)
;        COL1R - Green (Invader's Body)
;        COL0R - Black (Background)
L2A8B:  DB      3, 8            ; X, Y Pattern Size
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000001B,00000000B,01000000B ; . . . 1 . . . . 1 . . .
        DB      00000000B,01010101B,00000000B ; . . . . 1 1 1 1 . . . .
        DB      00000001B,10010110B,01000000B ; . . . 1 2 1 1 2 1 . . .
        DB      00000101B,01010101B,01010000B ; . . 1 1 1 1 1 1 1 1 . .
        DB      00010000B,00000000B,00000100B ; . 1 . . . . . . . . 1 .
        DB      00000101B,00000000B,01010000B ; . . 1 1 . . . . 1 1 . .

; Pattern - Green Invader (Alt. Version)
L2AA5:  DB      3, 8            ; X, Y Pattern Size
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,01000001B,00000000B ; . . . . 1 . . 1 . . . .
        DB      00000000B,01010101B,00000000B ; . . . . 1 1 1 1 . . . .
        DB      00000001B,10010110B,01000000B ; . . . 1 2 1 1 2 1 . . .
        DB      00000101B,01010101B,01010000B ; . . 1 1 1 1 1 1 1 1 . .
        DB      00010000B,00000000B,00000100B ; . 1 . . . . . . . . 1 .
        DB      00010000B,00000000B,00000100B ; . 1 . . . . . . . . 1 .

; Pattern - Blue Invader - Second-from-Bottom AND Bottom-Row Invader
L2ABF:  DB      3, 8            ; X, Y Pattern Size
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00010000B,01010101B,00000100B ; . 1 . . 1 1 1 1 . . 1 .
        DB      00010001B,01010101B,01000100B ; . 1 . 1 1 1 1 1 1 . 1 .
        DB      00010101B,10010110B,01010100B ; . 1 1 1 2 1 1 2 1 1 1 .
        DB      00000000B,01010101B,00000000B ; . . . . 1 1 1 1 . . . .
        DB      00000000B,01000001B,00000000B ; . . . . 1 . . 1 . . . .
        DB      00000001B,00000000B,01000000B ; . . . 1 . . . . 1 . . .

; Pattern - Blue Invader - (Alt. Version) [swap these for Bottom-Row]
L2AD9:  DB      3, 8            ; X, Y Pattern Size
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,00000000B,00000000B ; . . . . . . . . . . . .
        DB      00000000B,01010101B,00000000B ; . . . . 1 1 1 1 . . . .
        DB      00000001B,01010101B,01000000B ; . . . 1 1 1 1 1 1 . . .
        DB      00010101B,10010110B,01010100B ; . 1 1 1 2 1 1 2 1 1 1 .
        DB      00010000B,01010101B,00000100B ; . 1 . . 1 1 1 1 . . 1 .
        DB      00010000B,01101001B,00000100B ; . 1 . . 1 2 2 1 . . 1 .
        DB      00000100B,00010100B,00010000B ; . . 1 . . 1 1 . . 1 . .

; Limit Table Address for Invader's Shot VECT
L2AF3:  DB      0                ; X Lower Limit (Left Edge of Screen)
        DB      160              ; X Upper Limit (Right Edge of Screen)
        DB      0                ; Y Lower Limit (Top of Screen)
        DB      85               ; Y Upper Limit (Right Above the Player's Ship)

L2AF7:  DB      "ASTRO BATTLE",$00
        DB      $00
        DB      $00

; 8 Bytes COLTBL - Color Table for Color Register
;   [COLxL Left Colors not used since the boundary is at 0, and
;   COL1R and COL3R overridden by Interrupt Routines 1 thru 4.]
; Left side of Horizontal Color Boundary
L2B06:  DB      $22             ; COL3L - Purple
        DB      $64             ; COL2L - Orange
        DB      $74             ; COL1L - Yellow
        DB      $07             ; COL0L - White
; Right side of Horizontal Color Boundary
        DB      $22             ; COL3R - Purple
        DB      $54             ; COL2R - Red (Invaders and Bunkers)
        DB      $BC             ; COL1R - Green (Invaders)
        DB      $00             ; COL0R - Black (Background)

L2B0E:  DB      "LEVEL",$00

; [not used ??]
L2B14:  DB      $D1
        DB      $3A
        DB      $68
        DB      $06
        DB      $D6
        DB      $00
        DB      $D6
        DB      $01
        DB      $9F
        DB      $32
        DB      $6E
        DB      $06
        DB      $1F
        DB      $D2
        DB      $30
        DB      $2B
        DB      $11
        DB      $69
        DB      $06
        DB      $01
        DB      $66
        DB      $06
        DB      $CD
        DB      $3A
        DB      $34
        DB      $C3
        DB      $3D
        DB      $2B
        DB      $CD
        DB      $11
        DB      $14
        DB      $22
        DB      $66
        DB      $06
        DB      $2A
        DB      $05
        DB      $00
        DB      $23
        DB      $22
        DB      $05
        DB      $00
        DB      $2A
        DB      $07
        DB      $00
        DB      $23
        DB      $22
        DB      $07
        DB      $00
        DB      $C9
        DB      $CD
        DB      $15
        DB      $2B
        DB      $21
        DB      $1B
        DB      $2E
        DB      $36
        DB      $FF
        DB      $21
        DB      $CD
        DB      $00
        DB      $22
        DB      $6F
        DB      $06
        DB      $CD
        DB      $1A
        DB      $2D
        DB      $3A
        DB      $71
        DB      $06
        DB      $E6
        DB      $7F
        DB      $FE
        DB      $0D
        DB      $CA
        DB      $EB
        DB      $2C
        DB      $3A
        DB      $71
        DB      $06
        DB      $FE
        DB      $27
        DB      $CA
        DB      $71
        DB      $2B
        DB      $CD
        DB      $54
        DB      $2D
        DB      $CD
        DB      $1A
        DB      $2D
        DB      $C3
        DB      $E8
        DB      $2C
        DB      $11
        DB      $80
        DB      $00
        DB      $2A
        DB      $66
        DB      $06
        DB      $19
        DB      $EB
        DB      $2A
        DB      $66
        DB      $06
        DB      $44
        DB      $4D
        DB      $CD
        DB      $C1

; Interupt Routine Table
;   [Divides the screen into 4 zones with different color pallets]
; ----------------------
IRVEC1: DW      ISR1            ; Interrupt Service Routine #1
IRVEC2: DW      ISR2            ; Interrupt Service Routine #2
IRVEC3: DW      ISR3            ; Interrupt Service Routine #3
IRVEC4: DW      ISR4            ; Interrupt Service Routine #4
IRVEC5: DW      ISR5            ; Interrupt Service Routine #5

; Interrupt Service Routine #1 [occurs right below Score
;   1) Setup next Interrupt (IRVEC2) to occur below Top Row of Invaders
;   2) Output Red to Color Register 3 COL3R so the Red Invaders will be red.]
; ----------------------------
ISR1:   NOP
        PUSH    AF              ; store environment
        PUSH    HL
        PUSH    BC
        LD      HL,CT0          ; point at Counter/Timer #0
        LD      B,$07           ; Setup Loop to run 7 times
L2B93:  LD      A,(HL)
        OR      A
        JR      Z,L2B98
        DEC     A               ; count down current Counter/Timer (0-7) to 0
L2B98:  LD      (HL),A
        INC     HL              ; point at next Counter/Timer
        DJNZ    L2B93           ; Has loop run 7 times?  If not, then Loop
        POP     BC
        POP     HL
        DI                      ; Disable Interrupts
        IM      2               ; Set Interrupt Mode 2 Condition
        LD      A,($4E57)       ; read current Field Y Top
        ADD     A,$07           ; plus 7, times 2 for Screen Line
        SLA     A
        OUT     (INLIN),A       ; Port $D, INterrupt LINe [below Top Row of Invaders]
        LD      A,IRVEC2 >> 8   ; High Order Byte Address of Interrupt Vector #2
        LD      I,A             ; Load Interrupt Vector Register
        LD      A,IRVEC2 & $FF  ; Get Low Order Byte Address [$82]
        OUT     (INFBK),A       ; Port $D, INterrupt FeedBacK Register
        LD      A,$62           ; Get Ready to Output Red into Register
        OUT     (COL3R),A       ; Port $3, COLor 3 Right
        POP     AF              ; restore environment
        EI
        RET

; Interrupt Service Routine #3 [occurs at Top of Player's Base (if alive)]
; ----------------------------
;   1) Setup next Interrupt (IRVEC4) to occur on Screen Line 90
;   2) Output Yellow to Color Register 3 COL3R so that the Player's Base
;      will be yellow.
ISR3:   NOP
        PUSH    AF
        LD      A,90*2          ; Screen Line [Bottom of Screen]
        OUT     (INLIN),A       ; Port $D, INterrupt LINe
        LD      A,IRVEC4 >> 8   ; High Order Byte Address of Interrupt Vector #4
        LD      I,A             ; Load Interrupt Vector Register
        LD      A,IRVEC4 & $FF  ; Get Low Order Byte Address
        OUT     (INFBK),A       ; Port $D, INterrupt FeedBacK Register
        LD      A,$7F           ; Get Ready to Output Yellow into Register
        OUT     (COL3R),A       ; Port $3, COLor 3 Right
        POP     AF
        EI
        RET

; Interrupt Service Routine #4 [occurs at Bottom of Screen]
; ----------------------------
;   1) Setup next Interrupt (IRVEC1) to occur on Screen Line 9
;   2) Output White to Color Register 3 COL3R so that the "BASES"
;      and "SCORE" strings at the top of the screen will be white.
;   3) Output Red to Color Register 1 COL1R so that the hidden
;      scatchpad area at the bottom on the screen will be red,
;      thus matching the border color.
ISR4:   NOP
        PUSH    AF
        PUSH    HL
        PUSH    DE
        PUSH    BC
        CALL    STIMER          ; do Decrement Sound Timers
        LD      A,9*2           ; Screen Line [below Score]
        OUT     (INLIN),A       ; Port $F, INterrupt LINe
        LD      A,IRVEC1 >> 8   ; High Order Byte Address of Interrupt Vector #1
        LD      I,A             ; Load Interrupt Vector Register
        LD      A,IRVEC1 & $FF  ; Get Low Order Byte Address
        OUT     (INFBK),A       ; Port $D, INterrupt FeedBacK Register
        LD      A,$07           ; Get Ready to Output White into Register
        OUT     (COL3R),A       ; Port $3, COLor 3 Right
        LD      A,$BC           ; Get Ready to Output Green into Register
        OUT     (COL1R),A       ; Port $1, COLor 1 Right
        POP     BC
        POP     DE
        POP     HL
        POP     AF
        EI
        RET

; Interrupt Service Routine #2 [occurs below Top Row of Invaders]
; ----------------------------
;   1) Setup next Interrupt (IRVEC3) to occur on Screen Line 78
;   2) Output Blue to Color Register 1 COL1R so that the Red Invader
;      will have blue eyes and [also to Color Register 3 COL3R so]
;      the Invaders on Row 3 and 4 will have a blue body.
ISR2:   NOP
        PUSH    AF
        LD      A,($4E57)       ; read current Field Y Top
        CP      $47             ; Compare to 71
        JR      NC,L2C0C
        LD      A,78*2          ; Screen Line [Top of Player's Base]
        OUT     (INLIN),A       ; Port $F, INterrupt LINe
        LD      A,IRVEC3 >> 8   ; High Order Byte Address of Interrupt Vector #3
        LD      I,A             ; Load Interrupt Vector Register
        LD      A,IRVEC3 & $FF  ; Get Low Order Byte Address
        OUT     (INFBK),A       ; Port $D, INterrupt FeedBacK Register
        LD      A,$FC           ; Get Ready to Output Blue into Register
        OUT     (COL1R),A       ; Port $1, write COLor 1 Right
        POP     AF
        EI
        RET

; if Invaders too low, skip IRVEC3 and go straight to IRVEC4
L2C0C:  NOP
        LD      A,90*2          ; Screen Line [Bottom of Screen]
        OUT     (INLIN),A       ; Port $F, INterrupt LINe
        LD      A,IRVEC4 >> 8   ; High Order Byte Address of Interrupt Vector #4
        LD      I,A             ; Load Interrupt Vector Register
        LD      A,IRVEC4 & $FF  ; Get Low Order Byte Address
        OUT     (INFBK),A       ; Port $D, INterrupt FeedBacK Register
        LD      A,$FC           ; Get Ready to Output Blue into Register
        OUT     (COL3R),A       ; Port $3, COLor 3 Right
        LD      A,$FC           ; Get Ready to Output Blue into Register
        OUT     (COL1R),A       ; Port $1, COLor 1 Right
        POP     AF
        EI
        RET

; Interrupt Service Routine #5
; ----------------------------
;   See routine seems to be a placeholder for an ISR that was
;   never written.
ISR5:   NOP
        RET

L2C26:  DB      $40
        DB      $C2
        DB      $58
        DB      $2C
        DB      $01
        DB      $04
        DB      $00
        DB      $2A
        DB      $D0
        DB      $28
        DB      $09
        DB      $4E
        DB      $23
        DB      $46
        DB      $11
        DB      $79
        DB      $06
        DB      $CD
        DB      $B8
        DB      $33
        DB      $3A
        DB      $79
        DB      $06
        DB      $F6
        DB      $80
        DB      $32
        DB      $79
        DB      $06
        DB      $01
        DB      $7B
        DB      $06
        DB      $C5
        DB      $11
        DB      $03
        DB      $00
        DB      $01
        DB      $7D
        DB      $06
        DB      $CD
        DB      $9C
        DB      $33
        DB      $01
        DB      $7C
        DB      $06
        DB      $CD
        DB      $FD
        DB      $2D
        DB      $C3
        DB      $BC
        DB      $2C
        DB      $3A
        DB      $72
        DB      $06
        DB      $D6
        DB      $07
        DB      $D6
        DB      $01
        DB      $9F
        DB      $F5
        DB      $3A
        DB      $72
        DB      $06
        DB      $D6
        DB      $02
        DB      $D6
        DB      $01
        DB      $9F
        DB      $C1
        DB      $48
        DB      $B1
        DB      $F5
        DB      $3E
        DB      $00
        DB      $11
        DB      $73
        DB      $06
        DB      $CD
        DB      $2B
        DB      $3D
        DB      $B5
        DB      $C6
        DB      $FF
        DB      $9F
        DB      $C1
        DB      $48
        DB      $A1
        DB      $1F
        DB      $D2
        DB      $B7
        DB      $2C

; Astro Battle has a LOT of empty space at the end of the ROM.
; From $2C80-$2FFF (895 bytes is completely empty).  To make this match with
; the ROM, this space is filled with FF's.

        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF,$FF,$FF,$FF,$FF,$FF,$FF
        DB      $FF             ; Last byte is $2FFF
