Add Space Invaders
authorNick Downing <nick@ndcode.org>
Tue, 5 Jul 2022 13:04:16 +0000 (23:04 +1000)
committerNick Downing <nick@ndcode.org>
Tue, 5 Jul 2022 13:04:16 +0000 (23:04 +1000)
.gitignore
doc/Emulating the Space Invaders look and feel - Tobias V. Langhoff.pdf [new file with mode: 0644]
doc/invaders_code.txt [new file with mode: 0644]
doc/invaders_hardware.txt [new file with mode: 0644]
doc/invaders_ram_use.txt [new file with mode: 0644]
doc/space_invaders_overlay.png [new file with mode: 0644]
emu_z80/emu_z80.c
invaders/Makefile [new file with mode: 0644]
orig/Makefile

index d6792a8..1962788 100644 (file)
 /galaxian/galmidw.v
 /galaxian/galmidw.w
 /galaxian/galmidw.y
+/invaders/invaders.e
+/invaders/invaders.f
+/invaders/invaders.g
+/invaders/invaders.h
 /pacman/82s123.7f
 /pacman/82s126.1m
 /pacman/82s126.3m
@@ -30,5 +34,6 @@
 /pacman/pacman.6h
 /pacman/pacman.6j
 /orig/galaxian.zip
+/orig/invaders.zip
 /orig/mspacman.zip
 /orig/pacman.zip
diff --git a/doc/Emulating the Space Invaders look and feel - Tobias V. Langhoff.pdf b/doc/Emulating the Space Invaders look and feel - Tobias V. Langhoff.pdf
new file mode 100644 (file)
index 0000000..8f31130
Binary files /dev/null and b/doc/Emulating the Space Invaders look and feel - Tobias V. Langhoff.pdf differ
diff --git a/doc/invaders_code.txt b/doc/invaders_code.txt
new file mode 100644 (file)
index 0000000..1f43ac9
--- /dev/null
@@ -0,0 +1,4655 @@
+http://computerarcheology.com/Arcade/SpaceInvaders/Code.html
+
+Space Invaders
+Hardware Info
+
+RAM Usage
+
+It is never completely finished:
+
+TODO Look at the various versions of the ROMs and see what's different
+TODO Check all X/Y references and make !Xr/Yr or !Xn/Yn
+A word on coordinates. Sometimes the code is easier to understand in the context of the screen in actual (not rotated) position. The comments will refer to Xn (X not-rotated) and Yn. Sometimes the code is easier to understand in the context of the rotated screen. The comments will refer to Xr (X rotated) and Yr.
+
+Startup and Interrupts
+Reset: 
+; Execution begins here on power-up and reset.
+0000: 00              NOP                         ; This provides a slot ...
+0001: 00              NOP                         ; ... to put in a JP for ...
+0002: 00              NOP                         ; ... development
+0003: C3 D4 18        JP      init                ; Continue startup at 18D4
+0006: 00 00      ; Padding before fixed ISR address
+
+ScanLine96: 
+;Interrupt brings us here when the beam is *near* the middle of the screen. The real middle
+;would be 224/2 = 112. The code pretends this interrupt happens at line 128.
+0008: F5              PUSH    AF                  ; Save ...
+0009: C5              PUSH    BC                  ; ...
+000A: D5              PUSH    DE                  ; ...
+000B: E5              PUSH    HL                  ; ... everything
+000C: C3 8C 00        JP      $008C               ; Continue ISR at 8C
+000F: 00         ; Padding before fixed ISR address
+
+ScanLine224:
+; Interrupt brings us here when the beam is at the end of the screen (line 224) when the VBLANK begins.
+0010: F5              PUSH    AF                  ; Save ...
+0011: C5              PUSH    BC                  ; ...
+0012: D5              PUSH    DE                  ; ...
+0013: E5              PUSH    HL                  ; ... everything
+0014: 3E 80           LD      A,$80               ; Flag that tells objects ...
+0016: 32 72 20        LD      (vblankStatus),A    ; ... on the lower half of the screen to draw/move
+0019: 21 C0 20        LD      HL,isrDelay         ; Decrement ...
+001C: 35              DEC     (HL)                ; ... the general countdown (used for pauses)
+001D: CD CD 17        CALL    CheckHandleTilt     ; Check and handle TILT
+0020: DB 01           IN      A,(INP1)            ; Read coin switch
+0022: 0F              RRCA                        ; Has a coin been deposited (bit 0)?
+0023: DA 67 00        JP      C,$0067             ; Yes ... note that switch is closed and continue at 3F with A=1
+0026: 3A EA 20        LD      A,(coinSwitch)      ; Switch is now open. Was it ...
+0029: A7              AND     A                   ; ... closed last time?
+002A: CA 42 00        JP      Z,$0042             ; No ... skip registering the credit
+;
+; Handle bumping credit count
+002D: 3A EB 20        LD      A,(numCoins)        ; Number of credits in BCD
+0030: FE 99           CP      $99                 ; 99 credits already?
+0032: CA 3E 00        JP      Z,$003E             ; Yes ... ignore this (better than rolling over to 00)
+0035: C6 01           ADD     A,$01               ; Bump number of credits
+0037: 27              DAA                         ; Make it binary coded decimal
+0038: 32 EB 20        LD      (numCoins),A        ; New number of credits
+003B: CD 47 19        CALL    DrawNumCredits      ; Draw credits on screen
+003E: AF              XOR     A                   ; Credit switch ...
+003F: 32 EA 20        LD      (coinSwitch),A      ; ... has opened
+;
+0042: 3A E9 20        LD      A,(suspendPlay)     ; Are we moving ...
+0045: A7              AND     A                   ; ... game objects?
+0046: CA 82 00        JP      Z,$0082             ; No ... restore registers and out
+0049: 3A EF 20        LD      A,(gameMode)        ; Are we in ...
+004C: A7              AND     A                   ; ... game mode?
+004D: C2 6F 00        JP      NZ,$006F            ; Yes ... go process game-play things and out
+0050: 3A EB 20        LD      A,(numCoins)        ; Number of credits
+0053: A7              AND     A                   ; Are there any credits (player standing there)?
+0054: C2 5D 00        JP      NZ,$005D            ; Yes ... skip any ISR animations for the splash screens
+0057: CD BF 0A        CALL    ISRSplTasks         ; Process ISR tasks for splash screens
+005A: C3 82 00        JP      $0082               ; Restore registers and out
+;
+; At this point no game is going and there are credits
+005D: 3A 93 20        LD      A,(waitStartLoop)   ; Are we in the ...
+0060: A7              AND     A                   ; ... "press start" loop?
+0061: C2 82 00        JP      NZ,$0082            ; Yes ... restore registers and out
+0064: C3 65 07        JP      WaitForStart        ; Start the "press start" loop
+;
+; Mark credit as needing registering
+0067: 3E 01           LD      A,$01               ; Remember switch ...
+0069: 32 EA 20        LD      (coinSwitch),A      ; ... state for debounce
+006C: C3 3F 00        JP      $003F               ; Continue
+;
+; Main game-play timing loop
+006F: CD 40 17        CALL    TimeFleetSound      ; Time down fleet sound and sets flag if needs new delay value
+0072: 3A 32 20        LD      A,(obj2TimerExtra)  ; Use rolling shot's timer to sync ...
+0075: 32 80 20        LD      (shotSync),A        ; ... other two shots
+0078: CD 00 01        CALL    DrawAlien           ; Draw the current alien (or exploding alien)
+007B: CD 48 02        CALL    RunGameObjs         ; Process game objects (including player object)
+007E: CD 13 09        CALL    TimeToSaucer        ; Count down time to saucer
+0081: 00              NOP                         ; ** Why are we waiting?
+;
+0082: E1              POP     HL                  ; Restore ...
+0083: D1              POP     DE                  ; ...
+0084: C1              POP     BC                  ; ...
+0085: F1              POP     AF                  ; ... everything
+0086: FB              EI                          ; Enable interrupts
+0087: C9              RET                         ; Return from interrupt
+
+0088: 00 00 00 00 ; ** Why waste the space?
+
+; Continues here at scanline 96
+;
+008C: AF              XOR     A                   ; Flag that tells ...
+008D: 32 72 20        LD      (vblankStatus),A    ; ... objects on the upper half of screen to draw/move
+0090: 3A E9 20        LD      A,(suspendPlay)     ; Are we moving ...
+0093: A7              AND     A                   ; ... game objects?
+0094: CA 82 00        JP      Z,$0082             ; No ... restore and return
+0097: 3A EF 20        LD      A,(gameMode)        ; Are we in ...
+009A: A7              AND     A                   ; ... game mode?
+009B: C2 A5 00        JP      NZ,$00A5            ; Yes .... process game objects and out
+009E: 3A C1 20        LD      A,(isrSplashTask)   ; Splash-animation tasks
+00A1: 0F              RRCA                        ; If we are in demo-mode then we'll process the tasks anyway
+00A2: D2 82 00        JP      NC,$0082            ; Not in demo mode ... done
+;
+00A5: 21 20 20        LD      HL,$2020            ; Game object table (skip player-object at 2010)
+00A8: CD 4B 02        CALL    $024B               ; Process all game objects (except player object)
+00AB: CD 41 01        CALL    CursorNextAlien     ; Advance cursor to next alien (move the alien if it is last one)
+00AE: C3 82 00        JP      $0082               ; Restore and return
+The Aliens
+InitRack:
+; Initialize the player's rack of aliens. Copy the reference-location and deltas from the
+; player's data bank.
+;
+00B1: CD 86 08        CALL    GetAlRefPtr         ; 2xFC Get current player's ref-alien position pointer
+00B4: E5              PUSH    HL                  ; Hold pointer
+00B5: 7E              LD      A,(HL)              ; Get player's ...
+00B6: 23              INC     HL                  ; ... ref-alien ...
+00B7: 66              LD      H,(HL)              ; ...
+00B8: 6F              LD      L,A                 ; ... coordinates
+00B9: 22 09 20        LD      (refAlienYr),HL     ; Set game's reference alien's X,Y
+00BC: 22 0B 20        LD      (alienPosLSB),HL    ; Set game's alien cursor bit position
+00BF: E1              POP     HL                  ; Restore pointer
+00C0: 2B              DEC     HL                  ; 21FB or 22FB ref alien's delta (left or right)
+00C1: 7E              LD      A,(HL)              ; Get ref alien's delta X
+00C2: FE 03           CP      $03                 ; If there is one alien it will move right at 3
+00C4: C2 C8 00        JP      NZ,$00C8            ; Not 3 ... keep it
+00C7: 3D              DEC     A                   ; If it is 3, back it down to 2 until it switches again
+00C8: 32 08 20        LD      (refAlienDXr),A     ; Store alien deltaY
+00CB: FE FE           CP      $FE                 ; Moving left?
+00CD: 3E 00           LD      A,$00               ; Value of 0 for rack-moving-right (not XOR so flags are unaffected)
+00CF: C2 D3 00        JP      NZ,$00D3            ; Not FE ... keep the value 0 for right
+00D2: 3C              INC     A                   ; It IS FE ... use 1 for left
+00D3: 32 0D 20        LD      (rackDirection),A   ; Store rack direction
+00D6: C9              RET                         ; Done
+
+00D7: 3E 02           LD      A,$02               ; Set ...
+00D9: 32 FB 21        LD      (p1RefAlienDX),A    ; ... player 1 and 2 ...
+00DC: 32 FB 22        LD      (p2RefAlienDX),A    ; ... alien delta to 2 (right 2 pixels)
+00DF: C3 E4 08        JP      $08E4               ; 
+
+00E2: 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00F0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;
+; This is heavily patched from a previous version of the code. There was a test here to jump to a
+; self-test routine on startup (based on a dip switch). Even the original code padded with zeros
+; to make the next function begin at 0100. Room for expansion?
+
+DrawAlien:
+; 2006 holds the index into the alien flag data grid. 2067 holds the MSB of the pointer (21xx or 22xx).
+; If there is an alien exploding time it down. Otherwise draw the alien if it alive (or skip if
+; it isn't). If an alien is drawn (or blank) then the 2000 alien-drawing flag is cleared.
+;
+0100: 21 02 20        LD      HL,$2002            ; Is there an ...
+0103: 7E              LD      A,(HL)              ; ... alien ...
+0104: A7              AND     A                   ; ... exploding?
+0105: C2 38 15        JP      NZ,AExplodeTime     ; Yes ... go time it down and out
+;
+0108: E5              PUSH    HL                  ; 2002 on the stack
+0109: 3A 06 20        LD      A,(alienCurIndex)   ; Get alien index ...
+010C: 6F              LD      L,A                 ; ... for the 21xx or 22xx pointer
+010D: 3A 67 20        LD      A,(playerDataMSB)   ; Get MSB ...
+0110: 67              LD      H,A                 ; ... of data area (21xx or 22xx)
+0111: 7E              LD      A,(HL)              ; Get alien status flag
+0112: A7              AND     A                   ; Is the alien alive?
+0113: E1              POP     HL                  ; HL=2002
+0114: CA 36 01        JP      Z,$0136             ; No alien ... skip drawing alien sprite (but flag done)
+0117: 23              INC     HL                  ; HL=2003 Bump descriptor
+0118: 23              INC     HL                  ; HL=2004 Point to alien's row
+0119: 7E              LD      A,(HL)              ; Get alien type
+011A: 23              INC     HL                  ; HL=2005 Bump descriptor
+011B: 46              LD      B,(HL)              ; Get animation number
+011C: E6 FE           AND     $FE                 ; Translate row to type offset as follows: ...
+011E: 07              RLCA                        ; ... 0,1 -> 32 (type 1) ...
+011F: 07              RLCA                        ; ... 2,3 -> 16 (type 2) ...
+0120: 07              RLCA                        ; ...   4 -> 32 (type 3) on top row
+0121: 5F              LD      E,A                 ; Sprite offset LSB
+0122: 16 00           LD      D,$00               ; MSB is 0
+0124: 21 00 1C        LD      HL,$1C00            ; Position 0 alien sprites
+0127: 19              ADD     HL,DE               ; Offset to sprite type
+0128: EB              EX      DE,HL               ; Sprite offset to DE
+0129: 78              LD      A,B                 ; Animation frame number
+012A: A7              AND     A                   ; Is it position 0?
+012B: C4 3B 01        CALL    NZ,$013B            ; No ... add 30 and use position 1 alien sprites
+012E: 2A 0B 20        LD      HL,(alienPosLSB)    ; Pixel position
+0131: 06 10           LD      B,$10               ; 16 rows in alien sprites
+0133: CD D3 15        CALL    DrawSprite          ; Draw shifted sprite
+;
+0136: AF              XOR     A                   ; Let the ISR routine ...
+0137: 32 00 20        LD      (waitOnDraw),A      ; ... advance the cursor to the next alien
+013A: C9              RET                         ; Out
+;
+013B: 21 30 00        LD      HL,$0030            ; Offset sprite pointer ...
+013E: 19              ADD     HL,DE               ; ... to animation frame 1 sprites
+013F: EB              EX      DE,HL               ; Back to DE
+0140: C9              RET                         ; Out
+
+CursorNextAlien:
+; This is called from the mid-screen ISR to set the cursor for the next alien to draw.
+; When the cursor moves over all aliens then it is reset to the beginning and the reference
+; alien is moved to its next position.
+;
+; The flag at 2000 keeps this in sync with the alien-draw routine called from the end-screen ISR.
+; When the cursor is moved here then the flag at 2000 is set to 1. This routine will not change
+; the cursor until the alien-draw routine at 100 clears the flag. Thus no alien is skipped.
+;
+0141: 3A 68 20        LD      A,(playerOK)        ; Is the player ...
+0144: A7              AND     A                   ; ... blowing up?
+0145: C8              RET     Z                   ; Yes ... ignore the aliens
+0146: 3A 00 20        LD      A,(waitOnDraw)      ; Still waiting on ...
+0149: A7              AND     A                   ; ... this alien to be drawn?
+014A: C0              RET     NZ                  ; Yes ... leave cursor in place
+014B: 3A 67 20        LD      A,(playerDataMSB)   ; Load alien-data ...
+014E: 67              LD      H,A                 ; ... MSB (either 21xx or 22xx)
+014F: 3A 06 20        LD      A,(alienCurIndex)   ; Load the xx part of the alien flag pointer
+0152: 16 02           LD      D,$02               ; When all are gone this triggers 1A1 to return from this stack frame
+0154: 3C              INC     A                   ; Have we drawn all aliens ...
+0155: FE 37           CP      $37                 ; ... at last position?
+0157: CC A1 01        CALL    Z,MoveRefAlien      ; Yes ... move the bottom/right alien and reset index to 0
+015A: 6F              LD      L,A                 ; HL now points to alien flag
+015B: 46              LD      B,(HL)              ; Is alien ...
+015C: 05              DEC     B                   ; ... alive?
+015D: C2 54 01        JP      NZ,$0154            ; No ... skip to next alien
+0160: 32 06 20        LD      (alienCurIndex),A   ; New alien index
+0163: CD 7A 01        CALL    GetAlienCoords      ; Calculate bit position and type for index
+0166: 61              LD      H,C                 ; The calculation returns the MSB in C
+0167: 22 0B 20        LD      (alienPosLSB),HL    ; Store new bit position
+016A: 7D              LD      A,L                 ; Has this alien ...
+016B: FE 28           CP      $28                 ; ... reached the end of screen?
+016D: DA 71 19        JP      C,$1971             ; Yes ... kill the player
+0170: 7A              LD      A,D                 ; This alien's ...
+0171: 32 04 20        LD      (alienRow),A        ; ... row index
+0174: 3E 01           LD      A,$01               ; Set the wait-flag for the ...
+0176: 32 00 20        LD      (waitOnDraw),A      ; ... draw-alien routine to clear
+0179: C9              RET                         ; Done
+
+GetAlienCoords:
+; Convert alien index in L to screen bit position in C,L.
+; Return alien row index (converts to type) in D.
+;
+017A: 16 00           LD      D,$00               ; Row 0
+017C: 7D              LD      A,L                 ; Hold onto alien index
+017D: 21 09 20        LD      HL,$2009            ; Get alien X ...
+0180: 46              LD      B,(HL)              ; ... to B
+0181: 23              INC     HL                  ; Get alien y ...
+0182: 4E              LD      C,(HL)              ; ... to C
+0183: FE 0B           CP      $0B                 ; Can we take a full row off of index?
+0185: FA 94 01        JP      M,$0194             ; No ... we have the row
+0188: DE 0B           SBC     A,$0B               ; Subtract off 11 (one whole row)
+018A: 5F              LD      E,A                 ; Hold the new index
+018B: 78              LD      A,B                 ; Add ...
+018C: C6 10           ADD     A,$10               ; ... 16 to bit ...
+018E: 47              LD      B,A                 ; ... position Y (1 row in rack)
+018F: 7B              LD      A,E                 ; Restore tallied index
+0190: 14              INC     D                   ; Next row
+0191: C3 83 01        JP      $0183               ; Keep skipping whole rows
+;
+0194: 68              LD      L,B                 ; We have the LSB (the row)
+0195: A7              AND     A                   ; Are we in the right column?
+0196: C8              RET     Z                   ; Yes ... X and Y are right
+0197: 5F              LD      E,A                 ; Hold index
+0198: 79              LD      A,C                 ; Add ...
+0199: C6 10           ADD     A,$10               ; ... 16 to bit ...
+019B: 4F              LD      C,A                 ; ... position X (1 column in rack)
+019C: 7B              LD      A,E                 ; Restore index
+019D: 3D              DEC     A                   ; We adjusted for 1 column
+019E: C3 95 01        JP      $0195               ; Keep moving over column
+
+MoveRefAlien:
+; The "reference alien" is the bottom left. All other aliens are drawn relative to this
+; reference. This routine moves the reference alien (the delta is set elsewhere) and toggles
+; the animation frame number between 0 and 1.
+;
+01A1: 15              DEC     D                   ; This decrements with each call to move
+01A2: CA CD 01        JP      Z,ReturnTwo         ; Return out of TWO call frames (only used if no aliens left)
+01A5: 21 06 20        LD      HL,$2006            ; Set current alien ...
+01A8: 36 00           LD      (HL),$00            ; ... index to 0
+01AA: 23              INC     HL                  ; Point to DeltaX
+01AB: 4E              LD      C,(HL)              ; Load DX into C
+01AC: 36 00           LD      (HL),$00            ; Set DX to 0
+01AE: CD D9 01        CALL    AddDelta            ; Move alien
+01B1: 21 05 20        LD      HL,$2005            ; Alien animation frame number
+01B4: 7E              LD      A,(HL)              ; Toggle ...
+01B5: 3C              INC     A                   ; ... animation ...
+01B6: E6 01           AND     $01                 ; ... number between ...
+01B8: 77              LD      (HL),A              ; ... 0 and 1
+01B9: AF              XOR     A                   ; Alien index in A is now 0
+01BA: 21 67 20        LD      HL,$2067            ; Restore H ...
+01BD: 66              LD      H,(HL)              ; ... to player data MSB (21 or 22)
+01BE: C9              RET                         ; Done
+
+01BF: 00 ; ** Why?
+
+InitAliens:
+; Initialize the 55 aliens from last to 1st. 1 means alive.
+;
+01C0: 21 00 21        LD      HL,$2100            ; Start of alien structures (this is the last alien)
+01C3: 06 37           LD      B,$37               ; Count to 55 (that's five rows of 11 aliens)
+01C5: 36 01           LD      (HL),$01            ; Bring alien to live
+01C7: 23              INC     HL                  ; Next alien
+01C8: 05              DEC     B                   ; All done?
+01C9: C2 C5 01        JP      NZ,$01C5            ; No ... keep looping
+01CC: C9              RET                         ; Done
+
+ReturnTwo:
+; If there are no aliens left on the screen then MoveDrawAlien comes here which returns from the
+; caller's stack frame.
+;
+01CD: E1              POP     HL                  ; Drop return to caller
+01CE: C9              RET                         ; Return to caller's caller
+Misc
+DrawBottomLine:
+; Draw a 1px line across the player's stash at the bottom of the screen.
+;
+01CF: 3E 01           LD      A,$01               ; Bit 1 set ... going to draw a 1-pixel stripe down left side
+01D1: 06 E0           LD      B,$E0               ; All the way down the screen
+01D3: 21 02 24        LD      HL,$2402            ; Screen coordinates (3rd byte from upper left)
+01D6: C3 CC 14        JP      $14CC               ; Draw line down left side
+
+AddDelta:
+; HL points to descriptor: DX DY XX YY except DX is already loaded in C
+; ** Why the "already loaded" part? Why not just load it here?
+;
+01D9: 23              INC     HL                  ; We loaded delta-x already ... skip over it
+01DA: 46              LD      B,(HL)              ; Get delta-y
+01DB: 23              INC     HL                  ; Skip over it
+01DC: 79              LD      A,C                 ; Add delta-x ...
+01DD: 86              ADD     A,(HL)              ; ... to x
+01DE: 77              LD      (HL),A              ; Store new x
+01DF: 23              INC     HL                  ; Skip to y
+01E0: 78              LD      A,B                 ; Add delta-y ...
+01E1: 86              ADD     A,(HL)              ; ... to y
+01E2: 77              LD      (HL),A              ; Store new y
+01E3: C9              RET                         ; Done
+
+CopyRAMMirror:
+; Block copy ROM mirror 1B00-1BBF to initialize RAM at 2000-20BF.
+;
+01E4: 06 C0           LD      B,$C0               ; Number of bytes
+01E6: 11 00 1B        LD      DE,$1B00            ; RAM mirror in ROM
+01E9: 21 00 20        LD      HL,$2000            ; Start of RAM
+01EC: C3 32 1A        JP      BlockCopy           ; Copy [DE]->[HL] and return
+Copy/Restore Shields
+DrawShieldPl1:
+; Draw the shields for player 1 (draws it in the buffer in the player's data area).
+;
+01EF: 21 42 21        LD      HL,$2142            ; Player 1 shield buffer (remember between games in multi-player)
+01F2: C3 F8 01        JP      $01F8               ; Common draw point
+;
+DrawShieldPl2:
+; Draw the shields for player 1 (draws it in the buffer in the player's data area).
+;
+01F5: 21 42 22        LD      HL,$2242            ; Player 2 shield buffer (remember between games in multi-player)
+;
+01F8: 0E 04           LD      C,$04               ; Going to draw 4 shields
+01FA: 11 20 1D        LD      DE,$1D20            ; Shield pixel pattern
+01FD: D5              PUSH    DE                  ; Hold the start for the next shield
+01FE: 06 2C           LD      B,$2C               ; 44 bytes to copy
+0200: CD 32 1A        CALL    BlockCopy           ; Block copy DE to HL (B bytes)
+0203: D1              POP     DE                  ; Restore start of shield pattern
+0204: 0D              DEC     C                   ; Drawn all shields?
+0205: C2 FD 01        JP      NZ,$01FD            ; No ... go draw them all
+0208: C9              RET                         ; Done
+
+RememberShields1:
+; Copy shields on the screen to player 1's data area.
+;
+0209: 3E 01           LD      A,$01               ; Not zero means remember
+020B: C3 1B 02        JP      $021B               ; Shuffle-shields player 1
+
+RememberShields2:
+; Copy shields on the screen to player 2's data area.
+;
+020E: 3E 01           LD      A,$01               ; Not zero means remember
+0210: C3 14 02        JP      $0214               ; Shuffle-shields player 2
+
+RestoreShields2:
+; Copy shields from player 2's data area to screen.
+;
+0213: AF              XOR     A                   ; Zero means restore
+0214: 11 42 22        LD      DE,$2242            ; Player 2 shield buffer (remember between games in multi-player)
+0217: C3 1E 02        JP      CopyShields         ; Shuffle-shields player 2
+
+RestoreShields1:
+; Copy shields from player 1's data area to screen.
+;
+021A: AF              XOR     A                   ; Zero means restore
+021B: 11 42 21        LD      DE,$2142            ; Player 1 shield buffer (remember between games in multi-player)
+
+CopyShields:
+; A is 1 for screen-to-buffer, 0 for to buffer-to-screen
+; HL is screen coordinates of first shield. There are 23 rows between shields.
+; DE is sprite buffer in memory.
+;
+021E: 32 81 20        LD      (tmp2081),A         ; Remember copy/restore flag
+0221: 01 02 16        LD      BC,$1602            ; 22 rows, 2 bytes/row (for 1 shield pattern)
+0224: 21 06 28        LD      HL,$2806            ; Screen coordinates
+0227: 3E 04           LD      A,$04               ; Four shields to move
+0229: F5              PUSH    AF                  ; Hold shield count
+022A: C5              PUSH    BC                  ; Hold sprite-size
+022B: 3A 81 20        LD      A,(tmp2081)         ; Get back copy/restore flag
+022E: A7              AND     A                   ; Not zero ...
+022F: C2 42 02        JP      NZ,$0242            ; ... means remember shidles
+0232: CD 69 1A        CALL    RestoreShields      ; Restore player's shields
+0235: C1              POP     BC                  ; Get back sprite-size
+0236: F1              POP     AF                  ; Get back shield count
+0237: 3D              DEC     A                   ; Have we moved all shields?
+0238: C8              RET     Z                   ; Yes ... out
+0239: D5              PUSH    DE                  ; Hold sprite buffer
+023A: 11 E0 02        LD      DE,$02E0            ; Add 2E0 (23 rows) to get to ...
+023D: 19              ADD     HL,DE               ; ... next shield on screen
+023E: D1              POP     DE                  ; restore sprite buffer
+023F: C3 29 02        JP      $0229               ; Go back and do all
+;
+0242: CD 7C 14        CALL    RememberShields     ; Remember player's shields
+0245: C3 35 02        JP      $0235               ; Continue with next shield
+Game Objects
+RunGameObjs:
+; Process game objects. Each game object has a 16 byte structure. The handler routine for the object
+; is at xx03 and xx04 of the structure. The pointer to xx04 is pushed onto the stack before calling
+; the handler.
+;
+; All game objects (except task 0 ... the player) are called at the mid-screen and end-screen renderings.
+; Each object decides when to run based on its Y (not rotated) coordinate. If an object is on the lower
+; half of the screen then it does its work when the beam is at the top of the screen. If an object is
+; on the top of the screen then it does its work when the beam is at the bottom. This keeps the
+; object from updating while it is being drawn which would result in an ugly flicker.
+;
+;
+; The player is only processed at the mid-screen interrupt. I am not sure why.
+;
+; The first three bytes of the structure are used for status and timers.
+;
+; If the first byte is FF then the end of the game-task list has been reached.
+; If the first byte is FE then the object is skipped.
+;
+; If the first-two bytes are non-zero then they are treated like a two-byte counter
+; and decremented as such. The 2nd byte is the LSB (moves the fastest).
+;
+; If the first-two bytes are zero then the third byte is treated as an additional counter. It
+; is decremented as such.
+;
+; When all three bytes reach zero the task is executed.
+;
+; The third-byte-counter was used as a speed-governor for the player's object, but evidently even the slowest
+; setting was too slow. It got changed to 0 (fastest possible).
+;
+0248: 21 10 20        LD      HL,$2010            ; First game object (active player)
+024B: 7E              LD      A,(HL)              ; Have we reached the ...
+024C: FE FF           CP      $FF                 ; ... end of the object list?
+024E: C8              RET     Z                   ; Yes ... done
+024F: FE FE           CP      $FE                 ; Is object active?
+0251: CA 81 02        JP      Z,$0281             ; No ... skip it
+0254: 23              INC     HL                  ; xx01
+0255: 46              LD      B,(HL)              ; First byte to B
+0256: 4F              LD      C,A                 ; Hold 1st byte
+0257: B0              OR      B                   ; OR 1st and 2nd byte
+0258: 79              LD      A,C                 ; Restore 1st byte
+0259: C2 77 02        JP      NZ,$0277            ; If word at xx00,xx02 is non zero then decrement it
+;
+025C: 23              INC     HL                  ; xx02
+025D: 7E              LD      A,(HL)              ; Get byte counter
+025E: A7              AND     A                   ; Is it 0?
+025F: C2 88 02        JP      NZ,$0288            ; No ... decrement byte counter at xx02
+0262: 23              INC     HL                  ; xx03
+0263: 5E              LD      E,(HL)              ; Get handler address LSB
+0264: 23              INC     HL                  ; xx04
+0265: 56              LD      D,(HL)              ; Get handler address MSB
+0266: E5              PUSH    HL                  ; Remember pointer to MSB
+0267: EB              EX      DE,HL               ; Handler address to HL
+0268: E5              PUSH    HL                  ; Now to stack (making room for indirect call)
+0269: 21 6F 02        LD      HL,$026F            ; Return address to 026F
+026C: E3              EX      (SP),HL             ; Return address (026F) now on stack. Handler in HL.
+026D: D5              PUSH    DE                  ; Push pointer to data struct (xx04) for handler to use
+026E: E9              JP      (HL)                ; Run object's code (will return to next line)
+026F: E1              POP     HL                  ; Restore pointer to xx04
+0270: 11 0C 00        LD      DE,$000C            ; Offset to next ...
+0273: 19              ADD     HL,DE               ; ... game task (C+4=10)
+0274: C3 4B 02        JP      $024B               ; Do next game task
+;
+; Word at xx00 and xx01 is non-zero. Decrement it and move to next task.
+0277: 05              DEC     B                   ; Decrement ...
+0278: 04              INC     B                   ; ... two ...
+0279: C2 7D 02        JP      NZ,$027D            ; ... byte ...
+027C: 3D              DEC     A                   ; ... value ...
+027D: 05              DEC     B                   ; ... at ...
+027E: 70              LD      (HL),B              ; ... xx00 ...
+027F: 2B              DEC     HL                  ; ... and ...
+0280: 77              LD      (HL),A              ; ... xx01
+;
+0281: 11 10 00        LD      DE,$0010            ; Next ...
+0284: 19              ADD     HL,DE               ; ... object descriptor
+0285: C3 4B 02        JP      $024B               ; Keep processing game objects
+;
+; Word at xx00 and xx01 is zero and byte at xx02 is non-zero. Decrement xx02 and
+; move to next task.
+0288: 35              DEC     (HL)                ; Decrement the xx02 counter
+0289: 2B              DEC     HL                  ; Back up to ...
+028A: 2B              DEC     HL                  ; ... start of game task
+028B: C3 81 02        JP      $0281               ; Next game task
+
+
+
+GameObj0:
+; Game object 0: Move/draw the player
+;
+; This task is only called at the mid-screen ISR. It ALWAYS does its work here, even though
+; the player can be on the top or bottom of the screen (not rotated).
+;
+028E: E1              POP     HL                  ; Get player object structure 2014
+028F: 23              INC     HL                  ; Point to blow-up status
+0290: 7E              LD      A,(HL)              ; Get player blow-up status
+0291: FE FF           CP      $FF                 ; Player is blowing up?
+0293: CA 3B 03        JP      Z,$033B             ; No ... go do normal movement
+;
+; Handle blowing up player
+0296: 23              INC     HL                  ; Point to blow-up delay count
+0297: 35              DEC     (HL)                ; Decrement the blow-up delay
+0298: C0              RET     NZ                  ; Not time for a new blow-up sprite ... out
+0299: 47              LD      B,A                 ; Hold sprite image number
+029A: AF              XOR     A                   ; 0
+029B: 32 68 20        LD      (playerOK),A        ; Player is NOT OK ... player is blowing up
+029E: 32 69 20        LD      (enableAlienFire),A ; Alien fire is disabled
+02A1: 3E 30           LD      A,$30               ; Reset count ...
+02A3: 32 6A 20        LD      (alienFireDelay),A  ; ... till alien shots are enabled
+02A6: 78              LD      A,B                 ; Restore sprite image number (used if we go to 39B)
+02A7: 36 05           LD      (HL),$05            ; Reload time between blow-up changes
+02A9: 23              INC     HL                  ; Point to number of blow-up changes
+02AA: 35              DEC     (HL)                ; Count down blow-up changes
+02AB: C2 9B 03        JP      NZ,DrawPlayerDie    ; Still blowing up ... go draw next sprite
+;
+; Blow up finished
+02AE: 2A 1A 20        LD      HL,(playerYr)       ; Player's coordinates
+02B1: 06 10           LD      B,$10               ; 16 Bytes
+02B3: CD 24 14        CALL    EraseSimpleSprite   ; Erase simple sprite (the player)
+02B6: 21 10 20        LD      HL,$2010            ; Restore player ...
+02B9: 11 10 1B        LD      DE,$1B10            ; ... structure ...
+02BC: 06 10           LD      B,$10               ; ... from ...
+02BE: CD 32 1A        CALL    BlockCopy           ; ... ROM mirror
+02C1: 06 00           LD      B,$00               ; Turn off ...
+02C3: CD DC 19        CALL    SoundBits3Off       ; ... all sounds
+02C6: 3A 6D 20        LD      A,(invaded)         ; Has rack reached ...
+02C9: A7              AND     A                   ; ... the bottom of the screen?
+02CA: C0              RET     NZ                  ; Yes ... done here
+02CB: 3A EF 20        LD      A,(gameMode)        ; Are we in ...
+02CE: A7              AND     A                   ; ... game mode?
+02CF: C8              RET     Z                   ; No ... return to splash screens
+02D0: 31 00 24        LD      SP,$2400            ; We aren't going to return
+02D3: FB              EI                          ; Enable interrupts (we just dropped the ISR context)
+02D4: CD D7 19        CALL    DsableGameTasks     ; Disable game tasks
+02D7: CD 2E 09        CALL    $092E               ; Get number of ships for active player
+02DA: A7              AND     A                   ; Any left?
+02DB: CA 6D 16        JP      Z,$166D             ; No ... handle game over for player
+02DE: CD E7 18        CALL    $18E7               ; Get player-alive status pointer
+02E1: 7E              LD      A,(HL)              ; Is player ...
+02E2: A7              AND     A                   ; ... alive?
+02E3: CA 2C 03        JP      Z,$032C             ; Yes ... remove a ship from player's stash and reenter game loop
+02E6: 3A CE 20        LD      A,(twoPlayers)      ; Multi-player game
+02E9: A7              AND     A                   ; Only one player?
+02EA: CA 2C 03        JP      Z,$032C             ; Yes ... remove a ship from player's stash and reenter game loop
+02ED: 3A 67 20        LD      A,(playerDataMSB)   ; Player data MSB
+02F0: F5              PUSH    AF                  ; Hold the MSB
+02F1: 0F              RRCA                        ; Player 1 is active player?
+02F2: DA 32 03        JP      C,$0332             ; Yes ... go store player 1 shields and come back to 02F8
+02F5: CD 0E 02        CALL    RememberShields2    ; No ... go store player 2 shields
+02F8: CD 78 08        CALL    $0878               ; Get ref-alien info and pointer to storage
+02FB: 73              LD      (HL),E              ; Hold the ...
+02FC: 23              INC     HL                  ; ... ref-alien ...
+02FD: 72              LD      (HL),D              ; ... screen coordinates
+02FE: 2B              DEC     HL                  ; Back up ...
+02FF: 2B              DEC     HL                  ; .. to delta storage
+0300: 70              LD      (HL),B              ; Store ref-alien's delta (direction)
+0301: 00              NOP                         ; ** Why?
+0302: CD E4 01        CALL    CopyRAMMirror       ; Copy RAM mirror (getting ready to switch players)
+0305: F1              POP     AF                  ; Restore active player MSB
+0306: 0F              RRCA                        ; Player 1?
+0307: 3E 21           LD      A,$21               ; Player 1 data pointer
+0309: 06 00           LD      B,$00               ; Cocktail bit=0 (player 1)
+030B: D2 12 03        JP      NC,$0312            ; It was player one ... keep data for player 2
+030E: 06 20           LD      B,$20               ; Cocktail bit=1 (player 2)
+0310: 3E 22           LD      A,$22               ; Player 2 data pointer
+0312: 32 67 20        LD      (playerDataMSB),A   ; Change players
+0315: CD B6 0A        CALL    TwoSecDelay         ; Two second delay
+0318: AF              XOR     A                   ; Clear the player-object ...
+0319: 32 11 20        LD      (obj0TimerLSB),A    ; ... timer (player can move instantly after switching players)
+031C: 78              LD      A,B                 ; Cocktail bit to A
+031D: D3 05           OUT     (SOUND2),A          ; Set the cocktail mode
+031F: 3C              INC     A                   ; Fleet sound 1 (first tone)
+0320: 32 98 20        LD      (soundPort5),A      ; Set the port 5 hold
+0323: CD D6 09        CALL    ClearPlayField      ; Clear center window
+0326: CD 7F 1A        CALL    RemoveShip          ; Remove a ship and update indicators
+0329: C3 F9 07        JP      $07F9               ; Tell the players that the switch has been made
+;
+032C: CD 7F 1A        CALL    RemoveShip          ; Remove a ship and update indicators
+032F: C3 17 08        JP      $0817               ; Continue into game loop
+;
+0332: CD 09 02        CALL    RememberShields1    ; Remember the shields for player 1
+0335: C3 F8 02        JP      $02F8               ; Back to switching-players above
+
+0338: 00 00 00 ; ** Why
+           
+; Player not blowing up ... handle inputs
+033B: 21 68 20        LD      HL,$2068            ; Player OK flag
+033E: 36 01           LD      (HL),$01            ; Flag 1 ... player is OK
+0340: 23              INC     HL                  ; 2069
+0341: 7E              LD      A,(HL)              ; Alien shots enabled?
+0342: A7              AND     A                   ; Set flags
+0343: C3 B0 03        JP      $03B0               ; Continue
+
+0346: 00              NOP                         ; ** Why?
+0347: 2B              DEC     HL                  ; 2069
+0348: 36 01           LD      (HL),$01            ; Enable alien fire
+
+034A: 3A 1B 20        LD      A,(playerXr)        ; Current player coordinates
+034D: 47              LD      B,A                 ; Hold it
+034E: 3A EF 20        LD      A,(gameMode)        ; Are we in ...
+0351: A7              AND     A                   ; ... game mode?
+0352: C2 63 03        JP      NZ,$0363            ; Yes ... use switches as player controls
+;
+0355: 3A 1D 20        LD      A,(nextDemoCmd)     ; Get demo command
+0358: 0F              RRCA                        ; Is it right?
+0359: DA 81 03        JP      C,MovePlayerRight   ; Yes ... do right
+035C: 0F              RRCA                        ; Is it left?
+035D: DA 8E 03        JP      C,MovePlayerLeft    ; Yes ... do left
+0360: C3 6F 03        JP      $036F               ; Skip over movement (draw player and out)
+; Player is in control
+0363: CD C0 17        CALL    ReadInputs          ; Read active player controls
+0366: 07              RLCA                        ; Test for ...
+0367: 07              RLCA                        ; ... right button
+0368: DA 81 03        JP      C,MovePlayerRight   ; Yes ... handle move right
+036B: 07              RLCA                        ; Test for left button
+036C: DA 8E 03        JP      C,MovePlayerLeft    ; Yes ... handle move left
+; Draw player sprite
+036F: 21 18 20        LD      HL,$2018            ; Active player descriptor
+0372: CD 3B 1A        CALL    ReadDesc            ; Load 5 byte sprite descriptor in order: EDLHB
+0375: CD 47 1A        CALL    ConvToScr           ; Convert HL to screen coordinates
+0378: CD 39 14        CALL    DrawSimpSprite      ; Draw player
+037B: 3E 00           LD      A,$00               ; Clear the task timer. Nobody changes this but it could have ...
+037D: 32 12 20        LD      (obj0TimerExtra),A  ; ... been speed set for the player with a value other than 0 (not XORA)
+0380: C9              RET                         ; Out
+
+MovePlayerRight:
+; Handle player moving right
+0381: 78              LD      A,B                 ; Player coordinate
+0382: FE D9           CP      $D9                 ; At right edge?
+0384: CA 6F 03        JP      Z,$036F             ; Yes ... ignore this
+0387: 3C              INC     A                   ; Bump X coordinate
+0388: 32 1B 20        LD      (playerXr),A        ; New X coordinate
+038B: C3 6F 03        JP      $036F               ; Draw player and out
+
+MovePlayerLeft: 
+; Handle player moving left
+038E: 78              LD      A,B                 ; Player coordinate
+038F: FE 30           CP      $30                 ; At left edge
+0391: CA 6F 03        JP      Z,$036F             ; Yes ... ignore this
+0394: 3D              DEC     A                   ; Bump X coordinate
+0395: 32 1B 20        LD      (playerXr),A        ; New X coordinate
+0398: C3 6F 03        JP      $036F               ; Draw player and out
+
+DrawPlayerDie:
+; Toggle the player's blowing-up sprite between two pictures and draw it
+039B: 3C              INC     A                   ; Toggle blowing-up ...
+039C: E6 01           AND     $01                 ; ... player sprite (0,1,0,1)
+039E: 32 15 20        LD      (playerAlive),A     ; Hold current state
+03A1: 07              RLCA                        ; *2
+03A2: 07              RLCA                        ; *4
+03A3: 07              RLCA                        ; *8
+03A4: 07              RLCA                        ; *16
+03A5: 21 70 1C        LD      HL,$1C70            ; Base blow-up sprite location
+03A8: 85              ADD     A,L                 ; Offset sprite ...
+03A9: 6F              LD      L,A                 ; ... pointer
+03AA: 22 18 20        LD      (plyrSprPicL),HL    ; New blow-up sprite picture
+03AD: C3 6F 03        JP      $036F               ; Draw new blow-up sprite and out
+
+03B0: C2 4A 03        JP      NZ,$034A            ; Alien shots enabled ... move player's ship, draw it, and out
+03B3: 23              INC     HL                  ; To 206A
+03B4: 35              DEC     (HL)                ; Time until aliens can fire
+03B5: C2 4A 03        JP      NZ,$034A            ; Not time to enable ... move player's ship, draw it, and out
+03B8: C3 46 03        JP      $0346               ; Enable alien fire ... move player's ship, draw it, and out
+
+
+GameObj1:
+; Game object 1: Move/draw the player shot
+;
+; This task executes at either mid-screen ISR (if it is on the top half of the non-rotated screen) or
+; at the end-screen ISR (if it is on the bottom half of the screen).
+;
+03BB: 11 2A 20        LD      DE,$202A            ; Object's Yn coordiante
+03BE: CD 06 1A        CALL    CompYToBeam         ; Compare to screen-update location
+03C1: E1              POP     HL                  ; Pointer to task data
+03C2: D0              RET     NC                  ; Make sure we are in the right ISR
+
+03C3: 23              INC     HL                  ; Point to 2025 ... the shot status
+03C4: 7E              LD      A,(HL)              ; Get shot status
+03C5: A7              AND     A                   ; Return if ...
+03C6: C8              RET     Z                   ; ... no shot is active
+;
+03C7: FE 01           CP      $01                 ; Shot just starting (requested elsewhere)?
+03C9: CA FA 03        JP      Z,InitPlyShot       ; Yes ... go initiate shot
+;
+03CC: FE 02           CP      $02                 ; Progressing normally?
+03CE: CA 0A 04        JP      Z,MovePlyShot       ; Yes ... go move it
+;
+03D1: 23              INC     HL                  ; 2026
+03D2: FE 03           CP      $03                 ; Shot blowing up (not because of alien)?
+03D4: C2 2A 04        JP      NZ,$042A            ; No ... try other options
+;
+; Shot blowing up because it left the playfield, hit a shield, or hit another bullet
+03D7: 35              DEC     (HL)                ; Decrement the timer
+03D8: CA 36 04        JP      Z,EndOfBlowup       ; If done then
+03DB: 7E              LD      A,(HL)              ; Get timer value
+03DC: FE 0F           CP      $0F                 ; Starts at 10 ... first decrement brings us here
+03DE: C0              RET     NZ                  ; Not the first time ... explosion has been drawn
+; Draw explosion first pass through timer loop
+03DF: E5              PUSH    HL                  ; Hold pointer to data
+03E0: CD 30 04        CALL    ReadPlyShot         ; Read shot descriptor
+03E3: CD 52 14        CALL    EraseShifted        ; Erase the sprite
+03E6: E1              POP     HL                  ; 2026 (timer flag)
+03E7: 23              INC     HL                  ; 2027 point to sprite LSB
+03E8: 34              INC     (HL)                ; Change 1C90 to 1C91
+03E9: 23              INC     HL                  ; 2028
+03EA: 23              INC     HL                  ; 2029
+03EB: 35              DEC     (HL)                ; Drop X coordinate ...
+03EC: 35              DEC     (HL)                ; ... by 2
+03ED: 23              INC     HL                  ; 202A
+03EE: 35              DEC     (HL)                ; Drop Y ...
+03EF: 35              DEC     (HL)                ; ... coordinate ...
+03F0: 35              DEC     (HL)                ; ... by ...
+03F1: 23              INC     HL                  ; ... 3
+03F2: 36 08           LD      (HL),$08            ; 202B 8 bytes in size of sprite
+03F4: CD 30 04        CALL    ReadPlyShot         ; Read player shot structure
+03F7: C3 00 14        JP      DrawShiftedSprite   ; Draw sprite and out
+;
+InitPlyShot:
+03FA: 3C              INC     A                   ; Type is now ...
+03FB: 77              LD      (HL),A              ; ... 2 (in progress)
+03FC: 3A 1B 20        LD      A,(playerXr)        ; Players Y coordinate
+03FF: C6 08           ADD     A,$08               ; To center of player
+0401: 32 2A 20        LD      (obj1CoorXr),A      ; Shot's Y coordinate
+0404: CD 30 04        CALL    ReadPlyShot         ; Read 5 byte structure
+0407: C3 00 14        JP      DrawShiftedSprite   ; Draw sprite and out
+;
+MovePlyShot:
+040A: CD 30 04        CALL    ReadPlyShot         ; Read the shot structure
+040D: D5              PUSH    DE                  ; Hold pointer to sprite image
+040E: E5              PUSH    HL                  ; Hold sprite coordinates
+040F: C5              PUSH    BC                  ; Hold sprite size (in B)
+0410: CD 52 14        CALL    EraseShifted        ; Erase the sprite from the screen
+0413: C1              POP     BC                  ; Restore size
+0414: E1              POP     HL                  ; Restore coords
+0415: D1              POP     DE                  ; Restore pointer to sprite image
+0416: 3A 2C 20        LD      A,(shotDeltaX)      ; DeltaX for shot
+0419: 85              ADD     A,L                 ; Move the shot ...
+041A: 6F              LD      L,A                 ; ... up the screen
+041B: 32 29 20        LD      (obj1CoorYr),A      ; Store shot's new X coordinate
+041E: CD 91 14        CALL    DrawSprCollision    ; Draw sprite with collision detection
+0421: 3A 61 20        LD      A,(collision)       ; Test for ...
+0424: A7              AND     A                   ; ... collision
+0425: C8              RET     Z                   ; No collision ... out
+;
+; Collision with alien detected
+0426: 32 02 20        LD      (alienIsExploding),A; Set to not-0 indicating ...
+0429: C9              RET                         ; ... an alien is blowing up
+;
+; Other shot-status options
+042A: FE 05           CP      $05                 ; Alien explosion in progress?
+042C: C8              RET     Z                   ; Yes ... nothing to do
+042D: C3 36 04        JP      EndOfBlowup         ; Anything else erases the shot and removes it from duty
+
+ReadPlyShot:
+0430: 21 27 20        LD      HL,$2027            ; Read 5 byte sprite structure for ...
+0433: C3 3B 1A        JP      ReadDesc            ; ... player shot
+
+EndOfBlowup:
+0436: CD 30 04        CALL    ReadPlyShot         ; Read the shot structure
+0439: CD 52 14        CALL    EraseShifted        ; Erase the player's shot
+043C: 21 25 20        LD      HL,$2025            ; Reinit ...
+043F: 11 25 1B        LD      DE,$1B25            ; ... shot structure ...
+0442: 06 07           LD      B,$07               ; ... from ...
+0444: CD 32 1A        CALL    BlockCopy           ; ... ROM mirror
+0447: 2A 8D 20        LD      HL,(sauScoreLSB)    ; Get pointer to saucer-score table
+044A: 2C              INC     L                   ; Every shot explosion advances it one
+044B: 7D              LD      A,L                 ; Have we passed ...
+044C: FE 63           CP      $63                 ; ... the end at 1D63 (bug! this should be $64 to cover all 16 values)
+044E: DA 53 04        JP      C,$0453             ; No .... keep it
+0451: 2E 54           LD      L,$54               ; Wrap back around to 1D54
+0453: 22 8D 20        LD      (sauScoreLSB),HL    ; New score pointer
+0456: 2A 8F 20        LD      HL,(shotCountLSB)   ; Increments with every shot ...
+0459: 2C              INC     L                   ; ... but only LSB ** ...
+045A: 22 8F 20        LD      (shotCountLSB),HL   ; ... used for saucer direction
+;
+045D: 3A 84 20        LD      A,(saucerActive)    ; Is saucer ...
+0460: A7              AND     A                   ; ... on screen?
+0461: C0              RET     NZ                  ; Yes ... don't reset it
+;
+; Setup saucer direction for next trip
+0462: 7E              LD      A,(HL)              ; Shot counter
+0463: E6 01           AND     $01                 ; Lowest bit set?
+0465: 01 29 02        LD      BC,$0229            ; Xr delta of 2 starting at Xr=29
+0468: C2 6E 04        JP      NZ,$046E            ; Yes ... use 2/29
+046B: 01 E0 FE        LD      BC,$FEE0            ; No ... Xr delta of -2 starting at Xr=E0
+046E: 21 8A 20        LD      HL,$208A            ; Saucer descriptor
+0471: 71              LD      (HL),C              ; Store Xr coordinate
+0472: 23              INC     HL                  ; Point to ...
+0473: 23              INC     HL                  ; ... delta Xr
+0474: 70              LD      (HL),B              ; Store delta Xr
+0475: C9              RET                         ; Done
+
+
+GameObj2:
+; Game object 2: Alien rolling-shot (targets player specifically)
+;
+; The 2-byte value at 2038 is where the firing-column-table-pointer would be (see other
+; shots ... next game objects). This shot doesn't use that table. It targets the player
+; specifically. Instead the value is used as a flag to have the shot skip its first
+; attempt at firing every time it is reinitialized (when it blows up).
+;
+; The task-timer at 2032 is copied to 2080 in the game loop. The flag is used as a
+; synchronization flag to keep all the shots processed on separate interrupt ticks. This
+; has the main effect of slowing the shots down.
+;
+; When the timer is 2 the squiggly-shot/saucer (object 4 ) runs.
+; When the timer is 1 the plunger-shot (object 3) runs.
+; When the timer is 0 this object, the rolling-shot, runs.
+;
+0476: E1              POP     HL                  ; Game object data
+0477: 3A 32 1B        LD      A,($1B32)           ; Restore delay from ...
+047A: 32 32 20        LD      (obj2TimerExtra),A  ; ... ROM mirror (value 2)
+047D: 2A 38 20        LD      HL,(rolShotCFirLSB) ; Get pointer to ...
+0480: 7D              LD      A,L                 ; ... column-firing table.
+0481: B4              OR      H                   ; All zeros?
+0482: C2 8A 04        JP      NZ,$048A            ; No ... must be a valid column. Go fire.
+0485: 2B              DEC     HL                  ; Decrement the counter
+0486: 22 38 20        LD      (rolShotCFirLSB),HL ; Store new counter value (run the shot next time)
+0489: C9              RET                         ; And out
+
+048A: 11 35 20        LD      DE,$2035            ; Rolling-shot data structure
+048D: 3E F9           LD      A,$F9               ; Last picture of "rolling" alien shot
+048F: CD 50 05        CALL    ToShotStruct        ; Set code to handle rolling-shot
+0492: 3A 46 20        LD      A,(pluShotStepCnt)  ; Get the plunger-shot step count
+0495: 32 70 20        LD      (otherShot1),A      ; Hold it
+0498: 3A 56 20        LD      A,(squShotStepCnt)  ; Get the squiggly-shot step count
+049B: 32 71 20        LD      (otherShot2),A      ; Hold it
+049E: CD 63 05        CALL    HandleAlienShot     ; Handle active shot structure
+04A1: 3A 78 20        LD      A,(aShotBlowCnt)    ; Blow up counter
+04A4: A7              AND     A                   ; Test if shot has cycled through blowing up
+04A5: 21 35 20        LD      HL,$2035            ; Rolling-shot data structure
+04A8: C2 5B 05        JP      NZ,FromShotStruct   ; If shot is still running, copy the updated data and out
+
+ResetShot:
+; The rolling-shot has blown up. Reset the data structure.
+04AB: 11 30 1B        LD      DE,$1B30            ; Reload ...
+04AE: 21 30 20        LD      HL,$2030            ; ... object ...
+04B1: 06 10           LD      B,$10               ; ... structure ...
+04B3: C3 32 1A        JP      BlockCopy           ; ... from ROM mirror and out
+
+
+GameObj3:
+; Game object 3: Alien plunger-shot
+; This is skipped if there is only one alien left on the screen.
+;
+04B6: E1              POP     HL                  ; Game object data
+04B7: 3A 6E 20        LD      A,(skipPlunger)     ; One alien left? Skip plunger shot?
+04BA: A7              AND     A                   ; Check
+04BB: C0              RET     NZ                  ; Yes. Only one alien. Skip this shot.
+04BC: 3A 80 20        LD      A,(shotSync)        ; Sync flag (copied from GO-2's timer value)
+04BF: FE 01           CP      $01                 ; GO-2 and GO-4 are idle?
+04C1: C0              RET     NZ                  ; No ... only one shot at a time
+
+04C2: 11 45 20        LD      DE,$2045            ; Plunger alien shot data structure
+04C5: 3E ED           LD      A,$ED               ; Last picture of "plunger" alien shot
+04C7: CD 50 05        CALL    ToShotStruct        ; Copy the plunger alien to the active structure
+04CA: 3A 36 20        LD      A,(rolShotStepCnt)  ; Step count from rolling-shot
+04CD: 32 70 20        LD      (otherShot1),A      ; Hold it
+04D0: 3A 56 20        LD      A,(squShotStepCnt)  ; Step count from squiggly shot
+04D3: 32 71 20        LD      (otherShot2),A      ; Hold it
+04D6: CD 63 05        CALL    HandleAlienShot     ; Handle active shot structure
+04D9: 3A 76 20        LD      A,(aShotCFirLSB)    ; LSB of column-firing table
+04DC: FE 10           CP      $10                 ; Been through all entries in the table?
+04DE: DA E7 04        JP      C,$04E7             ; Not yet ... table is OK
+04E1: 3A 48 1B        LD      A,($1B48)           ; Been through all ..
+04E4: 32 76 20        LD      (aShotCFirLSB),A    ; ... so reset pointer into firing-column table
+04E7: 3A 78 20        LD      A,(aShotBlowCnt)    ; Get the blow up timer
+04EA: A7              AND     A                   ; Zero means shot is done
+04EB: 21 45 20        LD      HL,$2045            ; Plunger shot data
+04EE: C2 5B 05        JP      NZ,FromShotStruct   ; If shot is still running, go copy the updated data and out
+;
+04F1: 11 40 1B        LD      DE,$1B40            ; Reload ...
+04F4: 21 40 20        LD      HL,$2040            ; ... object ...
+04F7: 06 10           LD      B,$10               ; ... structure ...
+04F9: CD 32 1A        CALL    BlockCopy           ; ... from mirror
+;
+04FC: 3A 82 20        LD      A,(numAliens)       ; Number of aliens on screen
+04FF: 3D              DEC     A                   ; Is there only one left?
+0500: C2 08 05        JP      NZ,$0508            ; No ... move on
+0503: 3E 01           LD      A,$01               ; Disable plunger shot ...
+0505: 32 6E 20        LD      (skipPlunger),A     ; ... when only one alien remains
+0508: 2A 76 20        LD      HL,(aShotCFirLSB)   ; Set the plunger shot's ...
+050B: C3 7E 06        JP      $067E               ; ... column-firing pointer data
+
+; Game task 4 when splash screen alien is shooting extra "C" with a squiggly shot
+050E: E1              POP     HL                  ; Ignore the task data pointer passed on stack
+;
+; GameObject 4 comes here if processing a squiggly shot
+050F: 11 55 20        LD      DE,$2055            ; Squiggly shot data structure
+0512: 3E DB           LD      A,$DB               ; LSB of last byte of picture
+0514: CD 50 05        CALL    ToShotStruct        ; Copy squiggly shot to
+0517: 3A 46 20        LD      A,(pluShotStepCnt)  ; Get plunger ...
+051A: 32 70 20        LD      (otherShot1),A      ; ... step count
+051D: 3A 36 20        LD      A,(rolShotStepCnt)  ; Get rolling ...
+0520: 32 71 20        LD      (otherShot2),A      ; ... step count
+0523: CD 63 05        CALL    HandleAlienShot     ; Handle active shot structure
+0526: 3A 76 20        LD      A,(aShotCFirLSB)    ; LSB of column-firing table pointer
+0529: FE 15           CP      $15                 ; Have we processed all entries?
+052B: DA 34 05        JP      C,$0534             ; No ... don't reset it
+052E: 3A 58 1B        LD      A,($1B58)           ; Reset the pointer ...
+0531: 32 76 20        LD      (aShotCFirLSB),A    ; ... back to the start of the table
+0534: 3A 78 20        LD      A,(aShotBlowCnt)    ; Check to see if squiggly shot is done
+0537: A7              AND     A                   ; 0 means blow-up timer expired
+0538: 21 55 20        LD      HL,$2055            ; Squiggly shot data structure
+053B: C2 5B 05        JP      NZ,FromShotStruct   ; If shot is still running, go copy the updated data and out
+
+; Shot explosion is over. Remove the shot.
+053E: 11 50 1B        LD      DE,$1B50            ; Reload
+0541: 21 50 20        LD      HL,$2050            ; ... object ...
+0544: 06 10           LD      B,$10               ; ... structure ...
+0546: CD 32 1A        CALL    BlockCopy           ; ... from mirror
+0549: 2A 76 20        LD      HL,(aShotCFirLSB)   ; Copy pointer to column-firing table ...
+054C: 22 58 20        LD      (squShotCFirLSB),HL ; ... back to data structure (for next shot)
+054F: C9              RET                         ; Done
+
+ToShotStruct:
+0550: 32 7F 20        LD      (shotPicEnd),A      ; LSB of last byte of last picture in sprite
+0553: 21 73 20        LD      HL,$2073            ; Destination is the shot-structure
+0556: 06 0B           LD      B,$0B               ; 11 bytes
+0558: C3 32 1A        JP      BlockCopy           ; Block copy and out
+
+FromShotStruct:
+055B: 11 73 20        LD      DE,$2073            ; Source is the shot-structure
+055E: 06 0B           LD      B,$0B               ; 11 bytes
+0560: C3 32 1A        JP      BlockCopy           ; Block copy and out
+
+HandleAlienShot:
+; Each of the 3 shots copy their data to the 2073 structure (0B bytes) and call this.
+; Then they copy back if the shot is still active. Otherwise they copy from the mirror.
+;
+; The alien "fire rate" is based on the number of steps the other two shots on the screen
+; have made. The smallest number-of-steps is compared to the reload-rate. If it is too
+; soon then no shot is made. The reload-rate is based on the player's score. The MSB
+; is looked up in a table to get the reload-rate. The smaller the rate the faster the
+; aliens fire. Setting rate this way keeps shots from walking on each other.
+;
+0563: 21 73 20        LD      HL,$2073            ; Start of active shot structure
+0566: 7E              LD      A,(HL)              ; Get the shot status
+0567: E6 80           AND     $80                 ; Is the shot active?
+0569: C2 C1 05        JP      NZ,$05C1            ; Yes ... go move it
+
+056C: 3A C1 20        LD      A,(isrSplashTask)   ; ISR splash task
+056F: FE 04           CP      $04                 ; Shooting the "C" ?
+0571: 3A 69 20        LD      A,(enableAlienFire) ; Alien fire enabled flag
+0574: CA B7 05        JP      Z,$05B7             ; We are shooting the extra "C" ... just flag it active and out
+0577: A7              AND     A                   ; Is alien fire enabled?
+0578: C8              RET     Z                   ; No ... don't start a new shot
+
+0579: 23              INC     HL                  ; 2074 step count of current shot
+057A: 36 00           LD      (HL),$00            ; clear the step count
+
+; Make sure it isn't too soon to fire another shot
+057C: 3A 70 20        LD      A,(otherShot1)      ; Get the step count of the 1st "other shot"
+057F: A7              AND     A                   ; Any steps made?
+0580: CA 89 05        JP      Z,$0589             ; No ... ignore this count
+0583: 47              LD      B,A                 ; Shuffle off step count
+0584: 3A CF 20        LD      A,(aShotReloadRate) ; Get the reload rate (based on MSB of score)
+0587: B8              CP      B                   ; Too soon to fire again?
+0588: D0              RET     NC                  ; Yes ... don't fire
+0589: 3A 71 20        LD      A,(otherShot2)      ; Get the step count of the 2nd "other shot"
+058C: A7              AND     A                   ; Any steps made?
+058D: CA 96 05        JP      Z,$0596             ; No steps on any shot ... we are clear to fire
+0590: 47              LD      B,A                 ; Shuffle off step count
+0591: 3A CF 20        LD      A,(aShotReloadRate) ; Get the reload rate (based on MSB of score)
+0594: B8              CP      B                   ; Too soon to fire again?
+0595: D0              RET     NC                  ; Yes ... don't fire
+0596: 23              INC     HL                  ; 2075
+0597: 7E              LD      A,(HL)              ; Get tracking flag
+0598: A7              AND     A                   ; Does this shot track the player?
+0599: CA 1B 06        JP      Z,$061B             ; Yes ... go make a tracking shot;
+059C: 2A 76 20        LD      HL,(aShotCFirLSB)   ; Column-firing table
+059F: 4E              LD      C,(HL)              ; Get next column to fire from
+05A0: 23              INC     HL                  ; Bump the ...
+05A1: 00              NOP                         ; % WHY?
+05A2: 22 76 20        LD      (aShotCFirLSB),HL   ; ... pointer into column table
+05A5: CD 2F 06        CALL    FindInColumn        ; Find alien in target column
+05A8: D0              RET     NC                  ; No alien is alive in target column ... out
+;
+05A9: CD 7A 01        CALL    GetAlienCoords      ; Get coordinates of alien (lowest alien in firing column)
+05AC: 79              LD      A,C                 ; Offset ...
+05AD: C6 07           ADD     A,$07               ; ... Y by 7
+05AF: 67              LD      H,A                 ; To H
+05B0: 7D              LD      A,L                 ; Offset ...
+05B1: D6 0A           SUB     $0A                 ; ... X down 10
+05B3: 6F              LD      L,A                 ; To L
+05B4: 22 7B 20        LD      (alienShotYr),HL    ; Set shot coordinates below alien
+;
+05B7: 21 73 20        LD      HL,$2073            ; Alien shot status
+05BA: 7E              LD      A,(HL)              ; Get the status
+05BB: F6 80           OR      $80                 ; Mark this shot ...
+05BD: 77              LD      (HL),A              ; ... as actively running
+05BE: 23              INC     HL                  ; 2074 step count
+05BF: 34              INC     (HL)                ; Give this shot 1 step (it just started)
+05C0: C9              RET                         ; Out
+;
+; Move the alien shot
+05C1: 11 7C 20        LD      DE,$207C            ; Alien-shot Y coordinate
+05C4: CD 06 1A        CALL    CompYToBeam         ; Compare to beam position
+05C7: D0              RET     NC                  ; Not the right ISR for this shot
+;
+05C8: 23              INC     HL                  ; 2073 status
+05C9: 7E              LD      A,(HL)              ; Get shot status
+05CA: E6 01           AND     $01                 ; Bit 0 is 1 if blowing up
+05CC: C2 44 06        JP      NZ,ShotBlowingUp    ; Go do shot-is-blowing-up sequence
+05CF: 23              INC     HL                  ; 2074 step count
+05D0: 34              INC     (HL)                ; Count the steps (used for fire rate)
+05D1: CD 75 06        CALL    $0675               ; Erase shot
+05D4: 3A 79 20        LD      A,(aShotImageLSB)   ; Get LSB of the image pointer
+05D7: C6 03           ADD     A,$03               ; Next set of images
+05D9: 21 7F 20        LD      HL,$207F            ; End of image
+05DC: BE              CP      (HL)                ; Have we reached the end of the set?
+05DD: DA E2 05        JP      C,$05E2             ; No ... keep it
+05E0: D6 0C           SUB     $0C                 ; Back up to the 1st image in the set
+05E2: 32 79 20        LD      (aShotImageLSB),A   ; New LSB image pointer
+05E5: 3A 7B 20        LD      A,(alienShotYr)     ; Get shot's Y coordinate
+05E8: 47              LD      B,A                 ; Hold it
+05E9: 3A 7E 20        LD      A,(alienShotDelta)  ; Get alien shot delta
+05EC: 80              ADD     A,B                 ; Add to shots coordinate
+05ED: 32 7B 20        LD      (alienShotYr),A     ; New shot Y coordinate
+05F0: CD 6C 06        CALL    $066C               ; Draw the alien shot
+05F3: 3A 7B 20        LD      A,(alienShotYr)     ; Shot's Y coordinate
+05F6: FE 15           CP      $15                 ; Still in the active playfield?
+05F8: DA 12 06        JP      C,$0612             ; No ... end it
+05FB: 3A 61 20        LD      A,(collision)       ; Did shot collide ...
+05FE: A7              AND     A                   ; ... with something?
+05FF: C8              RET     Z                   ; No ... we are done here
+0600: 3A 7B 20        LD      A,(alienShotYr)     ; Shot's Y coordinate
+0603: FE 1E           CP      $1E                 ; Is it below player's area?
+0605: DA 12 06        JP      C,$0612             ; Yes ... end it
+0608: FE 27           CP      $27                 ; Is it above player's area?
+060A: 00              NOP                         ; ** WHY?
+060B: D2 12 06        JP      NC,$0612            ; Yes ... end it
+060E: 97              SUB     A                   ; Flag that player ...
+060F: 32 15 20        LD      (playerAlive),A     ; ... has been struck
+;
+0612: 3A 73 20        LD      A,(aShotStatus)     ; Flag to ...
+0615: F6 01           OR      $01                 ; ... start shot ...
+0617: 32 73 20        LD      (aShotStatus),A     ; ... blowing up
+061A: C9              RET                         ; Out
+;
+; Start a shot right over the player
+061B: 3A 1B 20        LD      A,(playerXr)        ; Player's X coordinate
+061E: C6 08           ADD     A,$08               ; Center of player
+0620: 67              LD      H,A                 ; To H for routine
+0621: CD 6F 15        CALL    FindColumn          ; Find the column
+0624: 79              LD      A,C                 ; Get the column right over player
+0625: FE 0C           CP      $0C                 ; Is it a valid column?
+0627: DA A5 05        JP      C,$05A5             ; Yes ... use what we found
+062A: 0E 0B           LD      C,$0B               ; Else use ...
+062C: C3 A5 05        JP      $05A5               ; ... as far over as we can
+
+FindInColumn:
+; C contains the target column. Look for a live alien in the column starting with
+; the lowest position. Return C=1 if found ... HL points to found slot.
+062F: 0D              DEC     C                   ; Column that is firing
+0630: 3A 67 20        LD      A,(playerDataMSB)   ; Player's MSB (21xx or 22xx)
+0633: 67              LD      H,A                 ; To MSB of HL
+0634: 69              LD      L,C                 ; Column to L
+0635: 16 05           LD      D,$05               ; 5 rows of aliens
+0637: 7E              LD      A,(HL)              ; Get alien's status
+0638: A7              AND     A                   ; 0 means dead
+0639: 37              SCF                         ; In case not 0
+063A: C0              RET     NZ                  ; Alien is alive? Yes ... return
+063B: 7D              LD      A,L                 ; Get the flag pointer LSB
+063C: C6 0B           ADD     A,$0B               ; Jump to same column on next row of rack (+11 aliens per row)
+063E: 6F              LD      L,A                 ; New alien index
+063F: 15              DEC     D                   ; Tested all rows?
+0640: C2 37 06        JP      NZ,$0637            ; No ... keep looking for a live alien up the rack
+0643: C9              RET                         ; Didn't find a live alien. Return with C=0.
+
+ShotBlowingUp:
+; Alien shot is blowing up
+0644: 21 78 20        LD      HL,$2078            ; Blow up timer
+0647: 35              DEC     (HL)                ; Decrement the value
+0648: 7E              LD      A,(HL)              ; Get the value
+0649: FE 03           CP      $03                 ; First tick, 4, we draw the explosion
+064B: C2 67 06        JP      NZ,$0667            ; After that just wait
+064E: CD 75 06        CALL    $0675               ; Erase the shot
+0651: 21 DC 1C        LD      HL,$1CDC            ; Alien shot ...
+0654: 22 79 20        LD      (aShotImageLSB),HL  ; ... explosion sprite
+0657: 21 7C 20        LD      HL,$207C            ; Alien shot Y
+065A: 35              DEC     (HL)                ; Left two for ...
+065B: 35              DEC     (HL)                ; ... explosion
+065C: 2B              DEC     HL                  ; Point slien shot X
+065D: 35              DEC     (HL)                ; Up two for ...
+065E: 35              DEC     (HL)                ; ... explosion
+065F: 3E 06           LD      A,$06               ; Alien shot descriptor ...
+0661: 32 7D 20        LD      (alienShotSize),A   ; ... size 6
+0664: C3 6C 06        JP      $066C               ; Draw alien shot explosion
+
+0667: A7              AND     A                   ; Have we reached 0?
+0668: C0              RET     NZ                  ; No ... keep waiting
+0669: C3 75 06        JP      $0675               ; Erase the explosion and out
+;
+066C: 21 79 20        LD      HL,$2079            ; Alien shot descriptor
+066F: CD 3B 1A        CALL    ReadDesc            ; Read 5 byte structure
+0672: C3 91 14        JP      DrawSprCollision    ; Draw shot and out
+;
+0675: 21 79 20        LD      HL,$2079            ; Alien shot descriptor
+0678: CD 3B 1A        CALL    ReadDesc            ; Read 5 byte structure
+067B: C3 52 14        JP      EraseShifted        ; Erase the shot and out
+
+067E: 22 48 20        LD      (pluShotCFirLSB),HL ; From 50B, update ...
+0681: C9              RET                         ; ... column-firing table pointer and out
+
+       
+
+GameObj4:
+; Game object 4: Flying Saucer OR squiggly shot
+;
+; This task is shared by the squiggly-shot and the flying saucer. The saucer waits until the
+; squiggly-shot is over before it begins.
+;
+0682: E1              POP     HL                  ; Pull data pointer from the stack (not going to use it)
+0683: 3A 80 20        LD      A,(shotSync)        ; Sync flag (copied from GO-2's timer value)
+0686: FE 02           CP      $02                 ; Are GO-2 and GO-3 idle?
+0688: C0              RET     NZ                  ; No ... only one at a time
+0689: 21 83 20        LD      HL,$2083            ; Time-till-saucer flag
+068C: 7E              LD      A,(HL)              ; Is it time ...
+068D: A7              AND     A                   ; ... for a saucer?
+068E: CA 0F 05        JP      Z,$050F             ; No ... go process squiggly shot
+0691: 3A 56 20        LD      A,(squShotStepCnt)  ; Is there a ...
+0694: A7              AND     A                   ; ... squiggly shot going?
+0695: C2 0F 05        JP      NZ,$050F            ; Yes ... go handle squiggly shot
+
+0698: 23              INC     HL                  ; Saucer on screen flag
+0699: 7E              LD      A,(HL)              ; (2084) Is the saucer ...
+069A: A7              AND     A                   ; ... already on the screen?
+069B: C2 AB 06        JP      NZ,$06AB            ; Yes ... go handle it
+069E: 3A 82 20        LD      A,(numAliens)       ; Number of aliens remaining
+06A1: FE 08           CP      $08                 ; Less than ...
+06A3: DA 0F 05        JP      C,$050F             ; ... 8 ... no saucer
+06A6: 36 01           LD      (HL),$01            ; (2084) The saucer is on the screen
+06A8: CD 3C 07        CALL    $073C               ; Draw the flying saucer
+
+06AB: 11 8A 20        LD      DE,$208A            ; Saucer's Y coordinate
+06AE: CD 06 1A        CALL    CompYToBeam         ; Compare to beam position
+06B1: D0              RET     NC                  ; Not the right ISR for moving saucer
+
+06B2: 21 85 20        LD      HL,$2085            ; Saucer hit flag
+06B5: 7E              LD      A,(HL)              ; Has saucer ...
+06B6: A7              AND     A                   ; ... been hit?
+06B7: C2 D6 06        JP      NZ,$06D6            ; Yes ... don't move it
+
+06BA: 21 8A 20        LD      HL,$208A            ; Saucer's structure
+06BD: 7E              LD      A,(HL)              ; Get saucer's Y coordinate
+06BE: 23              INC     HL                  ; Bump to ...
+06BF: 23              INC     HL                  ; ... delta Y
+06C0: 86              ADD     A,(HL)              ; Move saucer
+06C1: 32 8A 20        LD      (saucerPriPicMSB),A ; New coordinate
+06C4: CD 3C 07        CALL    $073C               ; Draw the flying saucer
+06C7: 21 8A 20        LD      HL,$208A            ; Saucer's structure
+06CA: 7E              LD      A,(HL)              ; Y coordinate
+06CB: FE 28           CP      $28                 ; Too low? End of screen?
+06CD: DA F9 06        JP      C,$06F9             ; Yes ... remove from play
+06D0: FE E1           CP      $E1                 ; Too high? End of screen?
+06D2: D2 F9 06        JP      NC,$06F9            ; Yes ... remove from play
+06D5: C9              RET                         ; Done
+
+06D6: 06 FE           LD      B,$FE               ; Turn off ...
+06D8: CD DC 19        CALL    SoundBits3Off       ; ... flying saucer sound
+06DB: 23              INC     HL                  ; (2086) show-hit timer
+06DC: 35              DEC     (HL)                ; Count down show-hit timer
+06DD: 7E              LD      A,(HL)              ; Get current value
+06DE: FE 1F           CP      $1F                 ; Starts at 20 ... is this the first tick of show-hit timer?
+06E0: CA 4B 07        JP      Z,$074B             ; Yes ... go show the explosion
+06E3: FE 18           CP      $18                 ; A little later ...
+06E5: CA 0C 07        JP      Z,$070C             ; ... show the score besides the saucer and add it
+06E8: A7              AND     A                   ; Has timer expired?
+06E9: C0              RET     NZ                  ; No ... let it run
+06EA: 06 EF           LD      B,$EF               ; 1110_1111 (mask off saucer hit sound)
+06EC: 21 98 20        LD      HL,$2098            ; Get current ...
+06EF: 7E              LD      A,(HL)              ; ... value of port 5 sound
+06F0: A0              AND     B                   ; Mask off the saucer-hit sound
+06F1: 77              LD      (HL),A              ; Set the new value
+06F2: E6 20           AND     $20                 ; All sound off but ...
+06F4: D3 05           OUT     (SOUND2),A          ; ... cocktail cabinet bit
+06F6: 00              NOP                         ; ** Why
+06F7: 00              NOP                         ; **
+06F8: 00              NOP                         ; **
+;
+06F9: CD 42 07        CALL    $0742               ; Covert pixel pos from descriptor to HL screen and shift
+06FC: CD CB 14        CALL    ClearSmallSprite    ; Clear a one byte sprite at HL
+06FF: 21 83 20        LD      HL,$2083            ; Saucer structure
+0702: 06 0A           LD      B,$0A               ; 10 bytes in saucer structure
+0704: CD 5F 07        CALL    $075F               ; Re-initialize saucer structure
+
+0707: 06 FE           LD      B,$FE               ; Turn off UFO ...
+0709: C3 DC 19        JP      SoundBits3Off       ; ... sound and out
+
+070C: 3E 01           LD      A,$01               ; Flag the score ...
+070E: 32 F1 20        LD      (adjustScore),A     ; ... needs updating
+0711: 2A 8D 20        LD      HL,(sauScoreLSB)    ; Saucer score table
+0714: 46              LD      B,(HL)              ; Get score for this saucer
+0715: 0E 04           LD      C,$04               ; There are only 4 possibilities
+0717: 21 50 1D        LD      HL,$1D50            ; Possible scores table
+071A: 11 4C 1D        LD      DE,$1D4C            ; Print strings for each score
+071D: 1A              LD      A,(DE)              ; Find ...
+071E: B8              CP      B                   ; ... the ...
+071F: CA 28 07        JP      Z,$0728             ; ... print ...
+0722: 23              INC     HL                  ; ... string ...
+0723: 13              INC     DE                  ; ... for ...
+0724: 0D              DEC     C                   ; ... the ...
+0725: C2 1D 07        JP      NZ,$071D            ; ... score
+0728: 7E              LD      A,(HL)              ; Get LSB of message (MSB is 2088 which is 1D)
+0729: 32 87 20        LD      (saucerPriLocLSB),A ; Message's LSB (_50=1D94 100=1D97 150=1D9A 300=1D9D)
+072C: 26 00           LD      H,$00               ; MSB = 0 ...
+072E: 68              LD      L,B                 ; HL = B
+072F: 29              ADD     HL,HL               ; *2
+0730: 29              ADD     HL,HL               ; *4
+0731: 29              ADD     HL,HL               ; *8
+0732: 29              ADD     HL,HL               ; *16
+0733: 22 F2 20        LD      (scoreDeltaLSB),HL  ; Add score for hitting saucer (015 becomes 150 in BCD).
+0736: CD 42 07        CALL    $0742               ; Get the flying saucer score descriptor
+0739: C3 F1 08        JP      $08F1               ; Print the three-byte score and out
+
+073C: CD 42 07        CALL    $0742               ; Draw the ...
+073F: C3 39 14        JP      DrawSimpSprite      ; ... flying saucer
+
+0742: 21 87 20        LD      HL,$2087            ; Read flying saucer ...
+0745: CD 3B 1A        CALL    ReadDesc            ; ... structure
+0748: C3 47 1A        JP      ConvToScr           ; Convert pixel number to screen and shift and out
+;
+074B: 06 10           LD      B,$10               ; Saucer hit sound bit
+074D: 21 98 20        LD      HL,$2098            ; Current state of sounds
+0750: 7E              LD      A,(HL)              ; OR ...
+0751: B0              OR      B                   ; ... in ...
+0752: 77              LD      (HL),A              ; ... saucer-hit sound
+0753: CD 70 17        CALL    $1770               ; Turn off fleet sound and start saucer-hit
+0756: 21 7C 1D        LD      HL,$1D7C            ; Sprite for saucer blowing up
+0759: 22 87 20        LD      (saucerPriLocLSB),HL; Store it in structure
+075C: C3 3C 07        JP      $073C               ; Draw the flying saucer
+;
+075F: 11 83 1B        LD      DE,$1B83            ; Data for saucer (702 sets count to 0A)
+0762: C3 32 1A        JP      BlockCopy           ; Reset saucer object data
+
+
+WaitForStart:
+; Wait for player 1 start button press
+0765: 3E 01           LD      A,$01               ; Tell ISR that we ...
+0767: 32 93 20        LD      (waitStartLoop),A   ; ... have started to wait
+076A: 31 00 24        LD      SP,$2400            ; Reset stack
+076D: FB              EI                          ; Enable interrupts
+076E: CD 79 19        CALL    $1979               ; Suspend game tasks
+0771: CD D6 09        CALL    ClearPlayField      ; Clear center window
+0774: 21 13 30        LD      HL,$3013            ; Screen coordinates
+0777: 11 F3 1F        LD      DE,$1FF3            ; "PRESS"
+077A: 0E 04           LD      C,$04               ; Message length
+077C: CD F3 08        CALL    PrintMessage        ; Print it
+077F: 3A EB 20        LD      A,(numCoins)        ; Number of credits
+0782: 3D              DEC     A                   ; Set flags
+0783: 21 10 28        LD      HL,$2810            ; Screen coordinates
+0786: 0E 14           LD      C,$14               ; Message length
+0788: C2 57 08        JP      NZ,$0857            ; Take 1 or 2 player start
+078B: 11 CF 1A        LD      DE,$1ACF            ; "ONLY 1PLAYER BUTTON "
+078E: CD F3 08        CALL    PrintMessage        ; Print message
+0791: DB 01           IN      A,(INP1)            ; Read player controls
+0793: E6 04           AND     $04                 ; 1Player start button?
+0795: CA 7F 07        JP      Z,$077F             ; No ... wait for button or credit
+Start New Game
+NewGame:
+; 1 Player start
+0798: 06 99           LD      B,$99               ; Essentially a -1 for DAA
+079A: AF              XOR     A                   ; Clear two player flag
+;
+; 2 player start sequence enters here with a=1 and B=98 (-2)
+079B: 32 CE 20        LD      (twoPlayers),A      ; Set flag for 1 or 2 players
+079E: 3A EB 20        LD      A,(numCoins)        ; Number of credits
+07A1: 80              ADD     A,B                 ; Take away credits
+07A2: 27              DAA                         ; Convert back to DAA
+07A3: 32 EB 20        LD      (numCoins),A        ; New credit count
+07A6: CD 47 19        CALL    DrawNumCredits      ; Display number of credits
+07A9: 21 00 00        LD      HL,$0000            ; Score of 0000
+07AC: 22 F8 20        LD      (P1ScorL),HL        ; Clear player-1 score
+07AF: 22 FC 20        LD      (P2ScorL),HL        ; Clear player-2 score
+07B2: CD 25 19        CALL    $1925               ; Print player-1 score
+07B5: CD 2B 19        CALL    $192B               ; Print player-2 score
+07B8: CD D7 19        CALL    DsableGameTasks     ; Disable game tasks
+07BB: 21 01 01        LD      HL,$0101            ; Two bytes 1, 1
+07BE: 7C              LD      A,H                 ; 1 to A
+07BF: 32 EF 20        LD      (gameMode),A        ; 20EF=1 ... game mode
+07C2: 22 E7 20        LD      (player1Alive),HL   ; 20E7 and 20E8 both one ... players 1 and 2 are alive
+07C5: 22 E5 20        LD      (player1Ex),HL      ; Extra-ship is available for player-1 and player-2
+07C8: CD 56 19        CALL    DrawStatus          ; Print scores and credits
+07CB: CD EF 01        CALL    DrawShieldPl1       ; Draw shields for player-1
+07CE: CD F5 01        CALL    DrawShieldPl2       ; Draw shields for player-2
+07D1: CD D1 08        CALL    GetShipsPerCred     ; Get number of ships from DIP settings
+07D4: 32 FF 21        LD      (p1ShipsRem),A      ; Player-1 ships
+07D7: 32 FF 22        LD      (p2ShipsRem),A      ; Player-2 ships
+07DA: CD D7 00        CALL    $00D7               ; Set player-1 and player-2 alien racks going right
+07DD: AF              XOR     A                   ; Make a 0
+07DE: 32 FE 21        LD      (p1RackCnt),A       ; Player 1 is on first rack of aliens
+07E1: 32 FE 22        LD      (p2RackCnt),A       ; Player 2 is on first rack of aliens
+07E4: CD C0 01        CALL    InitAliens          ; Initialize 55 aliens for player 1
+07E7: CD 04 19        CALL    InitAliensP2        ; Initialize 55 aliens for player 2
+07EA: 21 78 38        LD      HL,$3878            ; Screen coordinates for lower-left alien
+07ED: 22 FC 21        LD      (p1RefAlienY),HL    ; Initialize reference alien for player 1
+07F0: 22 FC 22        LD      (p2RefAlienYr),HL   ; Initialize reference alien for player 2
+07F3: CD E4 01        CALL    CopyRAMMirror       ; Copy ROM mirror to RAM (2000 - 20C0)
+07F6: CD 7F 1A        CALL    RemoveShip          ; Initialize ship hold indicator
+;
+07F9: CD 8D 08        CALL    PromptPlayer        ; Prompt with "PLAY PLAYER "
+07FC: CD D6 09        CALL    ClearPlayField      ; Clear the playfield
+07FF: 00              NOP                         ; % Why?
+0800: AF              XOR     A                   ; Make a 0
+0801: 32 C1 20        LD      (isrSplashTask),A   ; Disable isr splash-task animation
+0804: CD CF 01        CALL    DrawBottomLine      ; Draw line across screen under player
+0807: 3A 67 20        LD      A,(playerDataMSB)   ; Current player
+080A: 0F              RRCA                        ; Right bit tells all
+080B: DA 72 08        JP      C,$0872             ; Go do player 1
+;
+080E: CD 13 02        CALL    RestoreShields2     ; Restore shields for player 2
+0811: CD CF 01        CALL    DrawBottomLine      ; Draw line across screen under player
+0814: CD B1 00        CALL    InitRack            ; Initialize alien rack for current player
+0817: CD D1 19        CALL    EnableGameTasks     ; Enable game tasks in ISR
+081A: 06 20           LD      B,$20               ; Enable ...
+081C: CD FA 18        CALL    SoundBits3On        ; ... sound amplifier
+;
+; GAME LOOP
+;
+081F: CD 18 16        CALL    PlrFireOrDemo       ; Initiate player shot if button pressed
+0822: CD 0A 19        CALL    PlyrShotAndBump     ; Collision detect player's shot and rack-bump
+0825: CD F3 15        CALL    CountAliens         ; Count aliens (count to 2082)
+0828: CD 88 09        CALL    AdjustScore         ; Adjust score (and print) if there is an adjustment
+082B: 3A 82 20        LD      A,(numAliens)       ; Number of live aliens
+082E: A7              AND     A                   ; All aliens gone?
+082F: CA EF 09        JP      Z,$09EF             ; Yes ... end of turn
+0832: CD 0E 17        CALL    AShotReloadRate     ; Update alien-shot-rate based on player's score
+0835: CD 35 09        CALL    $0935               ; Check (and handle) extra ship award
+0838: CD D8 08        CALL    SpeedShots          ; Adjust alien shot speed
+083B: CD 2C 17        CALL    ShotSound           ; Shot sound on or off with 2025
+083E: CD 59 0A        CALL    $0A59               ; Check if player is hit
+0841: CA 49 08        JP      Z,$0849             ; No hit ... jump handler
+0844: 06 04           LD      B,$04               ; Player hit sound
+0846: CD FA 18        CALL    SoundBits3On        ; Make explosion sound
+0849: CD 75 17        CALL    FleetDelayExShip    ; Extra-ship sound timer, set fleet-delay, play fleet movement sound
+084C: D3 06           OUT     (WATCHDOG),A        ; Feed the watchdog
+084E: CD 04 18        CALL    CtrlSaucerSound     ; Control saucer sound
+0851: C3 1F 08        JP      $081F               ; Continue game loop
+
+0854: 00 00 00                                    ; ** Why?
+
+; Test for 1 or 2 player start button press
+0857: 11 BA 1A        LD      DE,$1ABA            ; "1 OR 2PLAYERS BUTTON"
+085A: CD F3 08        CALL    PrintMessage        ; Print message
+085D: 06 98           LD      B,$98               ; -2 (take away 2 credits)
+085F: DB 01           IN      A,(INP1)            ; Read player controls
+0861: 0F              RRCA                        ; Test ...
+0862: 0F              RRCA                        ; ... bit 2
+0863: DA 6D 08        JP      C,$086D             ; 2 player button pressed ... do it
+0866: 0F              RRCA                        ; Test bit 3
+0867: DA 98 07        JP      C,NewGame           ; One player start ... do it
+086A: C3 7F 07        JP      $077F               ; Keep waiting on credit or button
+; 2 PLAYER START
+086D: 3E 01           LD      A,$01               ; Flag 2 player game
+086F: C3 9B 07        JP      $079B               ; Continue normal startup
+
+0872: CD 1A 02        CALL    RestoreShields1     ; Restore shields for player 1
+0875: C3 14 08        JP      $0814               ; Continue in game loop
+
+0878: 3A 08 20        LD      A,(refAlienDXr)     ; Alien deltaY
+087B: 47              LD      B,A                 ; Hold it
+087C: 2A 09 20        LD      HL,(refAlienYr)     ; Alien coordinates
+087F: EB              EX      DE,HL               ; Coordinates to DE
+0880: C3 86 08        JP      GetAlRefPtr         ; HL is 21FC or 22FC and out
+            
+0883: 00 00 00                                    ; ** Why?
+
+GetAlRefPtr:
+; Get pointer to player's alien ref coordiantes
+0886: 3A 67 20        LD      A,(playerDataMSB)   ; Player data MSB (21 or 22)
+0889: 67              LD      H,A                 ; To H
+088A: 2E FC           LD      L,$FC               ; 21FC or 22FC ... alien coordinates
+088C: C9              RET                         ; Done
+
+PromptPlayer:
+; Print "PLAY PLAYER <n>" and blink score for 2 seconds.
+;
+088D: 21 11 2B        LD      HL,$2B11            ; Screen coordinates
+0890: 11 70 1B        LD      DE,$1B70            ; Message "PLAY PLAYER<1>"
+0893: 0E 0E           LD      C,$0E               ; 14 bytes in message
+0895: CD F3 08        CALL    PrintMessage        ; Print the message
+0898: 3A 67 20        LD      A,(playerDataMSB)   ; Get the player number
+089B: 0F              RRCA                        ; C will be set for player 1
+089C: 3E 1C           LD      A,$1C               ; The "2" character
+089E: 21 11 37        LD      HL,$3711            ; Replace the "<1>" with "<2">
+08A1: D4 FF 08        CALL    NC,DrawChar         ; If player 2 ... change the message
+08A4: 3E B0           LD      A,$B0               ; Delay of 176 (roughly 2 seconds)
+08A6: 32 C0 20        LD      (isrDelay),A        ; Set the ISR delay value
+;
+08A9: 3A C0 20        LD      A,(isrDelay)        ; Get the ISR delay value
+08AC: A7              AND     A                   ; Has the 2 second delay expired?
+08AD: C8              RET     Z                   ; Yes ... done
+08AE: E6 04           AND     $04                 ; Every 4 ISRs ...
+08B0: C2 BC 08        JP      NZ,$08BC            ; ... flash the player's score
+08B3: CD CA 09        CALL    $09CA               ; Get the score descriptor for the active player
+08B6: CD 31 19        CALL    DrawScore           ; Draw the score
+08B9: C3 A9 08        JP      $08A9               ; Back to the top of the wait loop
+;
+08BC: 06 20           LD      B,$20               ; 32 rows (4 characters * 8 bytes each)
+08BE: 21 1C 27        LD      HL,$271C            ; Player-1 score on the screen
+08C1: 3A 67 20        LD      A,(playerDataMSB)   ; Get the player number
+08C4: 0F              RRCA                        ; C will be set for player 1
+08C5: DA CB 08        JP      C,$08CB             ; We have the right score coordinates
+08C8: 21 1C 39        LD      HL,$391C            ; Use coordinates for player-2's score
+08CB: CD CB 14        CALL    ClearSmallSprite    ; Clear a one byte sprite at HL
+08CE: C3 A9 08        JP      $08A9               ; Back to the top of the wait loop
+
+
+GetShipsPerCred:
+; Get number of ships from DIP settings
+08D1: DB 02           IN      A,(INP2)            ; DIP settings
+08D3: E6 03           AND     $03                 ; Get number of ships
+08D5: C6 03           ADD     A,$03               ; From 3-6
+08D7: C9              RET                         ; Out
+
+SpeedShots:
+; With less than 9 aliens on the screen the alien shots get a tad bit faster. Probably
+; because the advancing rack can catch them.
+;
+08D8: 3A 82 20        LD      A,(numAliens)       ; Number of aliens on screen
+08DB: FE 09           CP      $09                 ; More than 8?
+08DD: D0              RET     NC                  ; Yes ... leave shot speed alone
+08DE: 3E FB           LD      A,$FB               ; Normally FF (-4) ... now FB (-5)
+08E0: 32 7E 20        LD      (alienShotDelta),A  ; Speed up alien shots
+08E3: C9              RET                         ; Done
+
+08E4: 3A CE 20        LD      A,(twoPlayers)      ; Number of players
+08E7: A7              AND     A                   ; Skip if ...
+08E8: C0              RET     NZ                  ; ... two player
+08E9: 21 1C 39        LD      HL,$391C            ; Player 2's score
+08EC: 06 20           LD      B,$20               ; 32 rows is 4 digits * 8 rows each
+08EE: C3 CB 14        JP      ClearSmallSprite    ; Clear a one byte sprite (32 rows long) at HL
+
+08F1: 0E 03           LD      C,$03               ; Length of saucer-score message ... fall into print
+
+PrintMessage:
+; Print a message on the screen
+; HL = coordinates
+; DE = message buffer
+; C = length
+08F3: 1A              LD      A,(DE)              ; Get character
+08F4: D5              PUSH    DE                  ; Preserve
+08F5: CD FF 08        CALL    DrawChar            ; Print character
+08F8: D1              POP     DE                  ; Restore
+08F9: 13              INC     DE                  ; Next character
+08FA: 0D              DEC     C                   ; All done?
+08FB: C2 F3 08        JP      NZ,PrintMessage     ; Print all of message
+08FE: C9              RET                         ; Out
+
+;=============================================================
+DrawChar:
+; Get pointer to 8 byte sprite number in A and
+; draw sprite on screen at HL
+08FF: 11 00 1E        LD      DE,$1E00            ; Character set
+0902: E5              PUSH    HL                  ; Preserve
+0903: 26 00           LD      H,$00               ; MSB=0
+0905: 6F              LD      L,A                 ; Character number to L
+0906: 29              ADD     HL,HL               ; HL = HL *2
+0907: 29              ADD     HL,HL               ; *4
+0908: 29              ADD     HL,HL               ; *8 (8 bytes each)
+0909: 19              ADD     HL,DE               ; Get pointer to sprite
+090A: EB              EX      DE,HL               ; Now into DE
+090B: E1              POP     HL                  ; Restore HL
+090C: 06 08           LD      B,$08               ; 8 bytes each
+090E: D3 06           OUT     (WATCHDOG),A        ; Feed watchdog
+0910: C3 39 14        JP      DrawSimpSprite      ; To screen
+
+TimeToSaucer:
+0913: 3A 09 20        LD      A,(refAlienYr)      ; Reference alien's X coordinate
+0916: FE 78           CP      $78                 ; Don't process saucer timer ... ($78 is 1st rack Yr)
+0918: D0              RET     NC                  ; ... unless aliens are closer to bottom
+0919: 2A 91 20        LD      HL,(tillSaucerLSB)  ; Time to saucer
+091C: 7D              LD      A,L                 ; Is it time ...
+091D: B4              OR      H                   ; ... for a saucer
+091E: C2 29 09        JP      NZ,$0929            ; No ... skip flagging
+0921: 21 00 06        LD      HL,$0600            ; Reset timer to 600 game loops
+0924: 3E 01           LD      A,$01               ; Flag a ...
+0926: 32 83 20        LD      (saucerStart),A     ; ... saucer sequence
+0929: 2B              DEC     HL                  ; Decrement the ...
+092A: 22 91 20        LD      (tillSaucerLSB),HL  ; ... time-to-saucer
+092D: C9              RET                         ; Done
+
+;=============================================================
+; Get number of ships for acive player
+092E: CD 11 16        CALL    GetPlayerDataPtr    ; HL points to player data
+0931: 2E FF           LD      L,$FF               ; Last byte = numbe of ships
+0933: 7E              LD      A,(HL)              ; Get number of ships
+0934: C9              RET                         ; Done
+
+;=============================================================
+; Award extra ship if score has reached ceiling
+0935: CD 10 19        CALL    CurPlyAlive         ; Get descriptor of sorts
+0938: 2B              DEC     HL                  ; Back up ...
+0939: 2B              DEC     HL                  ; ... two bytes
+093A: 7E              LD      A,(HL)              ; Has extra ship ...
+093B: A7              AND     A                   ; already been awarded?
+093C: C8              RET     Z                   ; Yes ... ignore
+093D: 06 15           LD      B,$15               ; Default 1500
+093F: DB 02           IN      A,(INP2)            ; Read DIP settings
+0941: E6 08           AND     $08                 ; Extra ship at 1000 or 1500
+0943: CA 48 09        JP      Z,$0948             ; 0=1500
+0946: 06 10           LD      B,$10               ; Awarded at 1000
+0948: CD CA 09        CALL    $09CA               ; Get score descriptor for active player
+094B: 23              INC     HL                  ; MSB of score ...
+094C: 7E              LD      A,(HL)              ; ... to accumulator
+094D: B8              CP      B                   ; Time for an extra ship?
+094E: D8              RET     C                   ; No ... out
+094F: CD 2E 09        CALL    $092E               ; Get pointer to number of ships
+0952: 34              INC     (HL)                ; Bump number of ships
+0953: 7E              LD      A,(HL)              ; Get the new total
+0954: F5              PUSH    AF                  ; Hang onto it for a bit
+0955: 21 01 25        LD      HL,$2501            ; Screen coords for ship hold
+0958: 24              INC     H                   ; Bump to ...
+0959: 24              INC     H                   ; ... next
+095A: 3D              DEC     A                   ; ... spot
+095B: C2 58 09        JP      NZ,$0958            ; Find spot for new ship
+095E: 06 10           LD      B,$10               ; 16 byte sprite
+0960: 11 60 1C        LD      DE,$1C60            ; Player sprite
+0963: CD 39 14        CALL    DrawSimpSprite      ; Draw the sprite
+0966: F1              POP     AF                  ; Restore the count
+0967: 3C              INC     A                   ; +1
+0968: CD 8B 1A        CALL    $1A8B               ; Print the number of ships
+096B: CD 10 19        CALL    CurPlyAlive         ; Get descriptor for active player of some sort
+096E: 2B              DEC     HL                  ; Back up ...
+096F: 2B              DEC     HL                  ; ... two bytes
+0970: 36 00           LD      (HL),$00            ; Flag extra ship has been awarded
+0972: 3E FF           LD      A,$FF               ; Set timer ...
+0974: 32 99 20        LD      (extraHold),A       ; ... for extra-ship sound
+0977: 06 10           LD      B,$10               ; Make sound ...
+0979: C3 FA 18        JP      SoundBits3On        ; ... for extra man
+
+AlienScoreValue:
+097C: 21 A0 1D        LD      HL,$1DA0            ; Table for scores for hitting alien
+097F: FE 02           CP      $02                 ; 0 or 1 (lower two rows) ...
+0981: D8              RET     C                   ; ... return HL points to value 10
+0982: 23              INC     HL                  ; next value
+0983: FE 04           CP      $04                 ; 2 or 3 (middle two rows) ...
+0985: D8              RET     C                   ; ... return HL points to value 20
+0986: 23              INC     HL                  ; Top row ...
+0987: C9              RET                         ; ... return HL points to value 30
+
+AdjustScore:
+; Adjust the score for the active player. 20F1 is 1 if there is a new value to add.
+; The adjustment is in 20F2,20F3. Then print the score.
+0988: CD CA 09        CALL    $09CA               ; Get score structure for active player
+098B: 3A F1 20        LD      A,(adjustScore)     ; Does the score ...
+098E: A7              AND     A                   ; ... need increasing?
+098F: C8              RET     Z                   ; No ... done
+0990: AF              XOR     A                   ; Mark score ...
+0991: 32 F1 20        LD      (adjustScore),A     ; ... as adjusted
+0994: E5              PUSH    HL                  ; Hold the pointer to the structure
+0995: 2A F2 20        LD      HL,(scoreDeltaLSB)  ; Get requested adjustment
+0998: EB              EX      DE,HL               ; Adjustment to DE
+0999: E1              POP     HL                  ; Get back pointer to structure
+099A: 7E              LD      A,(HL)              ; Add adjustment ...
+099B: 83              ADD     A,E                 ; ... first byte
+099C: 27              DAA                         ; Adjust it for BCD
+099D: 77              LD      (HL),A              ; Store new LSB
+099E: 5F              LD      E,A                 ; Add adjustment ...
+099F: 23              INC     HL                  ; ... to ...
+09A0: 7E              LD      A,(HL)              ; ... second ...
+09A1: 8A              ADC     A,D                 ; ... byte
+09A2: 27              DAA                         ; Adjust for BCD (cary gets dropped)
+09A3: 77              LD      (HL),A              ; Store second byte
+09A4: 57              LD      D,A                 ; Second byte to D (first byte still in E)
+09A5: 23              INC     HL                  ; Load ...
+09A6: 7E              LD      A,(HL)              ; ... the ...
+09A7: 23              INC     HL                  ; ... screen ...
+09A8: 66              LD      H,(HL)              ; ... coordinates ...
+09A9: 6F              LD      L,A                 ; ... to HL
+09AA: C3 AD 09        JP      Print4Digits        ; ** Usually a good idea, but wasted here
+
+Print4Digits:
+; Print 4 digits in DE
+09AD: 7A              LD      A,D                 ; Get first 2 digits of BCD or hex
+09AE: CD B2 09        CALL    DrawHexByte         ; Print them
+09B1: 7B              LD      A,E                 ; Get second 2 digits of BCD or hex (fall into print)
+
+DrawHexByte:
+; Display 2 digits in A to screen at HL
+09B2: D5              PUSH    DE                  ; Preserve
+09B3: F5              PUSH    AF                  ; Save for later
+09B4: 0F              RRCA                        ; Get ...
+09B5: 0F              RRCA                        ; ...
+09B6: 0F              RRCA                        ; ...
+09B7: 0F              RRCA                        ; ... left digit
+09B8: E6 0F           AND     $0F                 ; Mask out lower digit's bits
+09BA: CD C5 09        CALL    $09C5               ; To screen at HL
+09BD: F1              POP     AF                  ; Restore digit
+09BE: E6 0F           AND     $0F                 ; Mask out upper digit
+09C0: CD C5 09        CALL    $09C5               ; To screen
+09C3: D1              POP     DE                  ; Restore
+09C4: C9              RET                         ; Done
+;
+09C5: C6 1A           ADD     A,$1A               ; Bump to number characters
+09C7: C3 FF 08        JP      DrawChar            ; Continue ...
+
+; Get score descriptor for active player
+09CA: 3A 67 20        LD      A,(playerDataMSB)   ; Get active player
+09CD: 0F              RRCA                        ; Test for player
+09CE: 21 F8 20        LD      HL,$20F8            ; Player 1 score descriptor
+09D1: D8              RET     C                   ; Keep it if player 1 is active
+09D2: 21 FC 20        LD      HL,$20FC            ; Else get player 2 descriptor
+09D5: C9              RET                         ; Out
+
+ClearPlayField:
+; Clear center window of screen
+09D6: 21 02 24        LD      HL,$2402            ; Thrid from left, top of screen
+09D9: 36 00           LD      (HL),$00            ; Clear screen byte
+09DB: 23              INC     HL                  ; Next in row
+09DC: 7D              LD      A,L                 ; Get X ...
+09DD: E6 1F           AND     $1F                 ; ... coordinate
+09DF: FE 1C           CP      $1C                 ; Edge minus a buffer?
+09E1: DA E8 09        JP      C,$09E8             ; No ... keep going
+09E4: 11 06 00        LD      DE,$0006            ; Else ... bump to
+09E7: 19              ADD     HL,DE               ; ... next edge + buffer
+09E8: 7C              LD      A,H                 ; Get Y coordinate
+09E9: FE 40           CP      $40                 ; Reached bottom?
+09EB: DA D9 09        JP      C,$09D9             ; No ... keep going
+09EE: C9              RET                         ; Done
+
+09EF: CD 3C 0A        CALL    $0A3C               ; 
+09F2: AF              XOR     A                   ; Suspend ...
+09F3: 32 E9 20        LD      (suspendPlay),A     ; ... ISR game tasks
+09F6: CD D6 09        CALL    ClearPlayField      ; Clear playfield
+09F9: 3A 67 20        LD      A,(playerDataMSB)   ; Hold current player number ...
+09FC: F5              PUSH    AF                  ; ... on stack
+09FD: CD E4 01        CALL    CopyRAMMirror       ; Block copy RAM mirror from ROM
+0A00: F1              POP     AF                  ; Restore ...
+0A01: 32 67 20        LD      (playerDataMSB),A   ; ... current player number
+0A04: 3A 67 20        LD      A,(playerDataMSB)   ; ** Why load this again? Nobody ever jumps to 0A04?
+0A07: 67              LD      H,A                 ; To H
+0A08: E5              PUSH    HL                  ; Hold player-data pointer
+0A09: 2E FE           LD      L,$FE               ; 2xFE ... rack count
+0A0B: 7E              LD      A,(HL)              ; Get the number of racks the player has beaten
+0A0C: E6 07           AND     $07                 ; 0-7
+0A0E: 3C              INC     A                   ; Now 1-8
+0A0F: 77              LD      (HL),A              ; Update count since player just beat a rack
+0A10: 21 A2 1D        LD      HL,$1DA2            ; Starting coordinate of alien table
+0A13: 23              INC     HL                  ; Find the ...
+0A14: 3D              DEC     A                   ; ... right entry ...
+0A15: C2 13 0A        JP      NZ,$0A13            ; ... in the table
+0A18: 7E              LD      A,(HL)              ; Get the starting Y coordiante
+0A19: E1              POP     HL                  ; Restore player's pointer
+0A1A: 2E FC           LD      L,$FC               ; 2xFC ...
+0A1C: 77              LD      (HL),A              ; Set rack's starting Y coordinate
+0A1D: 23              INC     HL                  ; Point to X
+0A1E: 36 38           LD      (HL),$38            ; Set rack's starting X coordinate to 38
+0A20: 7C              LD      A,H                 ; Player ...
+0A21: 0F              RRCA                        ; ... number to carry
+0A22: DA 33 0A        JP      C,$0A33             ; 2nd player stuff
+0A25: 3E 21           LD      A,$21               ; Start fleet with ...
+0A27: 32 98 20        LD      (soundPort5),A      ; ... first sound
+0A2A: CD F5 01        CALL    DrawShieldPl2       ; Draw shields for player 2
+0A2D: CD 04 19        CALL    InitAliensP2        ; Initalize aliens for player 2
+0A30: C3 04 08        JP      $0804               ; Continue at top of game loop
+;
+0A33: CD EF 01        CALL    DrawShieldPl1       ; Draw shields for player 1
+0A36: CD C0 01        CALL    InitAliens          ; Initialize aliens for player 1
+0A39: C3 04 08        JP      $0804               ; Continue at top of game loop
+;
+0A3C: CD 59 0A        CALL    $0A59               ; Check player collision
+0A3F: C2 52 0A        JP      NZ,$0A52            ; Player is not alive ... skip delay
+0A42: 3E 30           LD      A,$30               ; Half second delay
+0A44: 32 C0 20        LD      (isrDelay),A        ; Set ISR timer
+0A47: 3A C0 20        LD      A,(isrDelay)        ; Has timer expired?
+0A4A: A7              AND     A                   ; Check exipre
+0A4B: C8              RET     Z                   ; Out if done
+0A4C: CD 59 0A        CALL    $0A59               ; Check player collision
+0A4F: CA 47 0A        JP      Z,$0A47             ; No collision ... wait on timer
+0A52: CD 59 0A        CALL    $0A59               ; Wait for ...
+0A55: C2 52 0A        JP      NZ,$0A52            ; ... collision to end
+0A58: C9              RET                         ; Done
+
+; Check to see if player is hit
+0A59: 3A 15 20        LD      A,(playerAlive)     ; Active player hit flag
+0A5C: FE FF           CP      $FF                 ; All FFs means player is OK
+0A5E: C9              RET                         ; Out
+
+ScoreForAlien:
+; Start the hit-alien sound and flag the adjustment for the score.
+; B contains the row, which determines the score value.
+0A5F: 3A EF 20        LD      A,(gameMode)        ; Are we in ...
+0A62: A7              AND     A                   ; ... game mode?
+0A63: CA 7C 0A        JP      Z,$0A7C             ; No ... skip scoring in demo
+0A66: 48              LD      C,B                 ; Hold row number
+0A67: 06 08           LD      B,$08               ; Alien hit sound
+0A69: CD FA 18        CALL    SoundBits3On        ; Enable sound
+0A6C: 41              LD      B,C                 ; Restore row number
+0A6D: 78              LD      A,B                 ; Into A
+0A6E: CD 7C 09        CALL    AlienScoreValue     ; Look up the score for the alien
+0A71: 7E              LD      A,(HL)              ; Get the score value
+0A72: 21 F3 20        LD      HL,$20F3            ; Pointer to score delta
+0A75: 36 00           LD      (HL),$00            ; Upper byte of score delta is "00"
+0A77: 2B              DEC     HL                  ; Point to score delta LSB
+0A78: 77              LD      (HL),A              ; Set score for hitting alien
+0A79: 2B              DEC     HL                  ; Point to adjust-score-flag
+0A7A: 36 01           LD      (HL),$01            ; The score will get changed elsewhere
+0A7C: 21 62 20        LD      HL,$2062            ; Return exploding-alien descriptor
+0A7F: C9              RET                         ; Out
+
+Animate:
+; Start the ISR moving the sprite. Return when done.
+0A80: 3E 02           LD      A,$02               ; Start simple linear ...
+0A82: 32 C1 20        LD      (isrSplashTask),A   ; ... sprite animation (splash)
+0A85: D3 06           OUT     (WATCHDOG),A        ; Feed watchdog
+0A87: 3A CB 20        LD      A,(splashReached)   ; Has the ...
+0A8A: A7              AND     A                   ; ... sprite reached target?
+0A8B: CA 85 0A        JP      Z,$0A85             ; No ... wait
+0A8E: AF              XOR     A                   ; Stop ...
+0A8F: 32 C1 20        LD      (isrSplashTask),A   ; ... ISR animation
+0A92: C9              RET                         ; Done
+
+PrintMessageDel:
+; Print message from DE to screen at HL (length in C) with a
+; delay between letters.
+0A93: D5              PUSH    DE                  ; Preserve
+0A94: 1A              LD      A,(DE)              ; Get character
+0A95: CD FF 08        CALL    DrawChar            ; Draw character on screen
+0A98: D1              POP     DE                  ; Preserve
+0A99: 3E 07           LD      A,$07               ; Delay between letters
+0A9B: 32 C0 20        LD      (isrDelay),A        ; Set counter
+0A9E: 3A C0 20        LD      A,(isrDelay)        ; Get counter
+0AA1: 3D              DEC     A                   ; Is it 1?
+0AA2: C2 9E 0A        JP      NZ,$0A9E            ; No ... wait on it
+0AA5: 13              INC     DE                  ; Next in message
+0AA6: 0D              DEC     C                   ; All done?
+0AA7: C2 93 0A        JP      NZ,PrintMessageDel  ; No ... do all
+0AAA: C9              RET                         ; Out
+
+SplashSquiggly:
+0AAB: 21 50 20        LD      HL,$2050            ; Pointer to game-object 4 timer
+0AAE: C3 4B 02        JP      $024B               ; Process squiggly-shot in demo mode
+
+OneSecDelay:
+; Delay 64 interrupts
+0AB1: 3E 40           LD      A,$40               ; Delay of 64 (tad over 1 sec)
+0AB3: C3 D7 0A        JP      WaitOnDelay         ; Do delay
+
+TwoSecDelay:
+; Delay 128 interrupts
+0AB6: 3E 80           LD      A,$80               ; Delay of 80 (tad over 2 sec)
+0AB8: C3 D7 0A        JP      WaitOnDelay         ; Do delay
+
+SplashDemo:
+0ABB: E1              POP     HL                  ; Drop the call to ABF and ...
+0ABC: C3 72 00        JP      $0072               ; ... do a demo game loop without sound
+
+ISRSplTasks:
+; Different types of splash tasks managed by ISR in splash screens. The ISR
+; calls this if in splash-mode. These may have been bit flags to allow all 3
+; at the same time. Maybe it is just easier to do a switch with a rotate-to-carry.
+;
+0ABF: 3A C1 20        LD      A,(isrSplashTask)   ; Get the ISR task number
+0AC2: 0F              RRCA                        ; In demo play mode?
+0AC3: DA BB 0A        JP      C,SplashDemo        ; 1: Yes ... go do game play (without sound)
+0AC6: 0F              RRCA                        ; Moving little alien from point A to B?
+0AC7: DA 68 18        JP      C,SplashSprite      ; 2: Yes ... go move little alien from point A to B
+0ACA: 0F              RRCA                        ; Shooting extra "C" with squiggly shot?
+0ACB: DA AB 0A        JP      C,SplashSquiggly    ; 4: Yes ... go shoot extra "C" in splash
+0ACE: C9              RET                         ; No task to do
+
+; Message to center of screen.
+; Only used in one place for "SPACE  INVADERS"
+0ACF: 21 14 2B        LD      HL,$2B14            ; Near center of screen
+0AD2: 0E 0F           LD      C,$0F               ; 15 bytes in message
+0AD4: C3 93 0A        JP      PrintMessageDel     ; Print and out
+
+WaitOnDelay:
+; Wait on ISR counter to reach 0
+0AD7: 32 C0 20        LD      (isrDelay),A        ; Delay counter
+0ADA: 3A C0 20        LD      A,(isrDelay)        ; Get current delay
+0ADD: A7              AND     A                   ; Zero yet?
+0ADE: C2 DA 0A        JP      NZ,$0ADA            ; No ... wait on it
+0AE1: C9              RET                         ; Out
+
+IniSplashAni:
+; Init the splash-animation block
+0AE2: 21 C2 20        LD      HL,$20C2            ; The splash-animation descriptor
+0AE5: 06 0C           LD      B,$0C               ; C bytes
+0AE7: C3 32 1A        JP      BlockCopy           ; Block copy DE to descriptor
+
+;=============================================================
+; After initialization ... splash screens
+0AEA: AF              XOR     A                   ; Make a 0
+0AEB: D3 03           OUT     (SOUND1),A          ; Turn off sound
+0AED: D3 05           OUT     (SOUND2),A          ; Turn off sound
+0AEF: CD 82 19        CALL    $1982               ; Turn off ISR splash-task
+0AF2: FB              EI                          ; Enable interrupts (using them for delays)
+0AF3: CD B1 0A        CALL    OneSecDelay         ; One second delay
+0AF6: 3A EC 20        LD      A,(splashAnimate)   ; Splash screen type
+0AF9: A7              AND     A                   ; Set flags based on type
+0AFA: 21 17 30        LD      HL,$3017            ; Screen coordinates (middle near top)
+0AFD: 0E 04           LD      C,$04               ; 4 characters in "PLAY"
+0AFF: C2 E8 0B        JP      NZ,$0BE8            ; Not 0 ... do "normal" PLAY
+0B02: 11 FA 1C        LD      DE,$1CFA            ; The "PLAy" with an upside down 'Y'
+0B05: CD 93 0A        CALL    PrintMessageDel     ; Print the "PLAy"
+0B08: 11 AF 1D        LD      DE,$1DAF            ; "SPACE  INVADERS" message
+0B0B: CD CF 0A        CALL    $0ACF               ; Print to middle-ish of screen
+0B0E: CD B1 0A        CALL    OneSecDelay         ; One second delay
+0B11: CD 15 18        CALL    DrawAdvTable        ; Draw "SCORE ADVANCE TABLE" with print delay
+0B14: CD B6 0A        CALL    TwoSecDelay         ; Two second delay
+0B17: 3A EC 20        LD      A,(splashAnimate)   ; Do splash ...
+0B1A: A7              AND     A                   ; ... animations?
+0B1B: C2 4A 0B        JP      NZ,$0B4A            ; Not 0 ... no animations
+;
+; Animate small alien replacing upside-down Y with correct Y
+0B1E: 11 95 1A        LD      DE,$1A95            ; Animate sprite from Y=FE to Y=9E step -1
+0B21: CD E2 0A        CALL    IniSplashAni        ; Copy to splash-animate structure
+0B24: CD 80 0A        CALL    Animate             ; Wait for ISR to move sprite (small alien)
+0B27: 11 B0 1B        LD      DE,$1BB0            ; Animate sprite from Y=98 to Y=FF step 1
+0B2A: CD E2 0A        CALL    IniSplashAni        ; Copy to splash-animate structure
+0B2D: CD 80 0A        CALL    Animate             ; Wait for ISR to move sprite (alien pulling upside down Y)
+0B30: CD B1 0A        CALL    OneSecDelay         ; One second delay
+0B33: 11 C9 1F        LD      DE,$1FC9            ; Animate sprite from Y=FF to Y=97 step 1
+0B36: CD E2 0A        CALL    IniSplashAni        ; Copy to splash-animate structure
+0B39: CD 80 0A        CALL    Animate             ; Wait for ISR to move sprite (alien pushing Y)
+0B3C: CD B1 0A        CALL    OneSecDelay         ; One second delay
+0B3F: 21 B7 33        LD      HL,$33B7            ; Where the splash alien ends up
+0B42: 06 0A           LD      B,$0A               ; 10 rows
+0B44: CD CB 14        CALL    ClearSmallSprite    ; Clear a one byte sprite at HL
+0B47: CD B6 0A        CALL    TwoSecDelay         ; Two second delay
+;
+; Play demo
+0B4A: CD D6 09        CALL    ClearPlayField      ; Clear playfield
+0B4D: 3A FF 21        LD      A,(p1ShipsRem)      ; Number of ships for player-1
+0B50: A7              AND     A                   ; If non zero ...
+0B51: C2 5D 0B        JP      NZ,$0B5D            ; ... keep it (counts down between demos)
+0B54: CD D1 08        CALL    GetShipsPerCred     ; Get number of ships from DIP settings
+0B57: 32 FF 21        LD      (p1ShipsRem),A      ; Reset number of ships for player-1
+0B5A: CD 7F 1A        CALL    RemoveShip          ; Remove a ship from stash and update indicators
+;
+0B5D: CD E4 01        CALL    CopyRAMMirror       ; Block copy ROM mirror to initialize RAM
+0B60: CD C0 01        CALL    InitAliens          ; Initialize all player 1 aliens
+0B63: CD EF 01        CALL    DrawShieldPl1       ; Draw shields for player 1 (to buffer)
+0B66: CD 1A 02        CALL    RestoreShields1     ; Restore shields for player 1 (to screen)
+0B69: 3E 01           LD      A,$01               ; ISR splash-task ...
+0B6B: 32 C1 20        LD      (isrSplashTask),A   ; ... playing demo
+0B6E: CD CF 01        CALL    DrawBottomLine      ; Draw playfield line
+;
+0B71: CD 18 16        CALL    PlrFireOrDemo       ; In demo ... process demo movement and always fire
+0B74: CD F1 0B        CALL    $0BF1               ; Check player shot and aliens bumping edges of screen and hidden message
+0B77: D3 06           OUT     (WATCHDOG),A        ; Feed watchdog
+0B79: CD 59 0A        CALL    $0A59               ; Has demo player been hit?
+0B7C: CA 71 0B        JP      Z,$0B71             ; No ... continue game
+0B7F: AF              XOR     A                   ; Remove player shot ...
+0B80: 32 25 20        LD      (plyrShotStatus),A  ; ... from activity
+0B83: CD 59 0A        CALL    $0A59               ; Wait for demo player ...
+0B86: C2 83 0B        JP      NZ,$0B83            ; ... to stop exploding
+;
+; Credit information
+0B89: AF              XOR     A                   ; Turn off ...
+0B8A: 32 C1 20        LD      (isrSplashTask),A   ; ... splash animation
+0B8D: CD B1 0A        CALL    OneSecDelay         ; One second delay
+0B90: CD 88 19        CALL    $1988               ; ** Something else at one time? Jump straight to clear-play-field
+0B93: 0E 0C           LD      C,$0C               ; Message size
+0B95: 21 11 2C        LD      HL,$2C11            ; Screen coordinates
+0B98: 11 90 1F        LD      DE,$1F90            ; "INSERT  COIN"
+0B9B: CD F3 08        CALL    PrintMessage        ; Print message
+0B9E: 3A EC 20        LD      A,(splashAnimate)   ; Do splash ...
+0BA1: FE 00           CP      $00                 ; ... animations?
+0BA3: C2 AE 0B        JP      NZ,$0BAE            ; Not 0 ... not on this screen
+0BA6: 21 11 33        LD      HL,$3311            ; Screen coordinates
+0BA9: 3E 02           LD      A,$02               ; Character "C"
+0BAB: CD FF 08        CALL    DrawChar            ; Put an extra "C" for "CCOIN" on the screen
+0BAE: 01 9C 1F        LD      BC,$1F9C            ; "<1 OR 2 PLAYERS>  "
+0BB1: CD 56 18        CALL    ReadPriStruct       ; Load the screen,pointer
+0BB4: CD 4C 18        CALL    $184C               ; Print the message
+0BB7: DB 02           IN      A,(INP2)            ; Display coin info (bit 7) ...
+0BB9: 07              RLCA                        ; ... on demo screen?
+0BBA: DA C3 0B        JP      C,$0BC3             ; 1 means no ... skip it
+0BBD: 01 A0 1F        LD      BC,$1FA0            ; "*1 PLAYER  1 COIN "
+0BC0: CD 3A 18        CALL    $183A               ; Load the descriptor
+0BC3: CD B6 0A        CALL    TwoSecDelay         ; Print TWO descriptors worth
+0BC6: 3A EC 20        LD      A,(splashAnimate)   ; Doing splash ...
+0BC9: FE 00           CP      $00                 ; ... animation?
+0BCB: C2 DA 0B        JP      NZ,$0BDA            ; Not 0 ... not on this screen
+0BCE: 11 D5 1F        LD      DE,$1FD5            ; Animation for small alien to line up with extra "C"
+0BD1: CD E2 0A        CALL    IniSplashAni        ; Copy the animation block
+0BD4: CD 80 0A        CALL    Animate             ; Wait for the animation to complete
+0BD7: CD 9E 18        CALL    $189E               ; Animate alien shot to extra "C"
+0BDA: 21 EC 20        LD      HL,$20EC            ; Toggle ...
+0BDD: 7E              LD      A,(HL)              ; ... the ...
+0BDE: 3C              INC     A                   ; ... splash screen ...
+0BDF: E6 01           AND     $01                 ; ... animation for ...
+0BE1: 77              LD      (HL),A              ; ... next time
+0BE2: CD D6 09        CALL    ClearPlayField      ; Clear play field
+0BE5: C3 DF 18        JP      $18DF               ; Keep splashing
+
+0BE8: 11 AB 1D        LD      DE,$1DAB            ; "PLAY" with normal 'Y'
+0BEB: CD 93 0A        CALL    PrintMessageDel     ; Print it
+0BEE: C3 0B 0B        JP      $0B0B               ; Continue with splash (HL will be pointing to next message)
+
+0BF1: CD 0A 19        CALL    PlyrShotAndBump     ; Check if player is shot and aliens bumping the edge of screen
+0BF4: C3 9A 19        JP      CheckHiddenMes      ; Check for hidden-message display sequence
+
+MessageCorp:
+; "TAITO COP"
+0BF7: 13 00 08 13 0E 26 02 0E 0F
+Diagnostics Routine
+The very center 2K of the code map is an expansion area. It originally contained a 1K diagnostics routine beginning at 1000. The original code would check bit 0 of port 0 (wired to DIP4) and jump to this routine if the switch was flipped. The routine was removed in this Midway version of the code. And it was removed in later versions of the TAITO code line.
+
+The original routine is shown here for reference.
+
+0C00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0C20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0C40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0C60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0C80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0CA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0CC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0CE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+0D00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0D20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0D40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0D60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0D80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0DA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0DC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0DE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+0E00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0E20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0E40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0E60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0E80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0EA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0EC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0EE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+0F00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0F20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0F40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0F60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0F80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0FA0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0FC0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+0FE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+; The original TAITO code had a self-check routine here. The opening jump was to E2, which was a
+; check on bit 0 of port 0 (the DIP4 switch for self test). If the bit was set the code came here.
+; When Midway branched the code, they left the check out.
+
+1000: 00              NOP                         ; Three bytes for ...
+1001: 00              NOP                         ; ... development code ...
+1002: 00              NOP                         ; ... jump opcode
+;
+1003: AF              XOR     A                   ; Turn off ...
+1004: D3 03           OUT     (SOUND1),A          ; ... sound effects (AMP ENABLE bit 5)
+1006: 0E 03           LD      C,$03               ;
+1008: 06 55           LD      B,$55               ;
+100A: 21 00 20        LD      HL,$2000            ;
+100D: 70              LD      (HL),B              ;
+100E: 23              INC     HL                  ;
+100F: 7C              LD      A,H                 ;
+1010: FE 40           CP      $40                 ;
+1012: C2 0D 10        JP      NZ,$100D            ; 
+1015: 21 00 20        LD      HL,$2000            ;
+1018: 7E              LD      A,(HL)              ;
+1019: A8              XOR     B                   ;
+101A: C2 90 11        JP      NZ,$1190            ; 
+101D: 23              INC     HL                  ;
+101E: 7C              LD      A,H                 ;
+101F: FE 40           CP      $40                 ;
+1021: C2 18 10        JP      NZ,$1018            ; 
+1024: 06 AA           LD      B,$AA               ;
+1026: 21 00 20        LD      HL,$2000            ;
+1029: 70              LD      (HL),B              ;
+102A: 23              INC     HL                  ;
+102B: 7C              LD      A,H                 ;
+102C: FE 40           CP      $40                 ;
+102E: C2 29 10        JP      NZ,$1029            ; 
+1031: 21 00 20        LD      HL,$2000            ;
+1034: 7E              LD      A,(HL)              ;
+1035: A8              XOR     B                   ;
+1036: C2 90 11        JP      NZ,$1190            ; 
+1039: 23              INC     HL                  ;
+103A: 7C              LD      A,H                 ;
+103B: FE 40           CP      $40                 ;
+103D: C2 34 10        JP      NZ,$1034            ; 
+1040: 0D              DEC     C                   ;
+1041: C2 08 10        JP      NZ,$1008            ; 
+1044: 21 00 20        LD      HL,$2000            ;
+1047: 06 00           LD      B,$00               ;
+1049: 78              LD      A,B                 ;
+104A: 77              LD      (HL),A              ;
+104B: 23              INC     HL                  ;
+104C: 04              INC     B                   ;
+104D: 78              LD      A,B                 ;
+104E: FE FF           CP      $FF                 ;
+1050: C2 55 10        JP      NZ,$1055            ; 
+1053: 06 00           LD      B,$00               ;
+1055: 7C              LD      A,H                 ;
+1056: FE 40           CP      $40                 ;
+1058: C2 49 10        JP      NZ,$1049            ; 
+105B: 21 00 20        LD      HL,$2000            ;
+105E: 06 00           LD      B,$00               ;
+1060: 7E              LD      A,(HL)              ;
+1061: A8              XOR     B                   ;
+1062: C2 90 11        JP      NZ,$1190            ; 
+1065: 04              INC     B                   ;
+1066: 78              LD      A,B                 ;
+1067: FE FF           CP      $FF                 ;
+1069: C2 6E 10        JP      NZ,$106E            ; 
+106C: 06 00           LD      B,$00               ;
+106E: 23              INC     HL                  ;
+106F: 7C              LD      A,H                 ;
+1070: FE 40           CP      $40                 ;
+1072: C2 60 10        JP      NZ,$1060            ; 
+1075: 31 00 24        LD      SP,$2400            ;
+1078: CD 83 11        CALL    $1183               ; 
+107B: 11 48 13        LD      DE,$1348            ;
+107E: 21 01 25        LD      HL,$2501            ;
+1081: CD 55 11        CALL    $1155               ; 
+1084: 21 01 27        LD      HL,$2701            ;
+1087: CD 55 11        CALL    $1155               ; 
+108A: 21 01 33        LD      HL,$3301            ;
+108D: CD 55 11        CALL    $1155               ; 
+1090: 21 07 2A        LD      HL,$2A07            ;
+1093: 0E 0F           LD      C,$0F               ;
+1095: 11 6F 13        LD      DE,$136F            ;
+1098: D5              PUSH    DE                  ;
+1099: CD 57 11        CALL    $1157               ; 
+109C: D1              POP     DE                  ;
+109D: 21 07 2E        LD      HL,$2E07            ;
+10A0: 0E 0F           LD      C,$0F               ;
+10A2: CD 57 11        CALL    $1157               ; 
+10A5: 3E 1D           LD      A,$1D               ;
+10A7: 21 0B 2E        LD      HL,$2E0B            ;
+10AA: CD 66 11        CALL    $1166               ; 
+10AD: 06 0B           LD      B,$0B               ;
+10AF: 21 0E 34        LD      HL,$340E            ;
+10B2: 11 7E 13        LD      DE,$137E            ;
+10B5: 0E 06           LD      C,$06               ;
+10B7: C5              PUSH    BC                  ;
+10B8: CD 57 11        CALL    $1157               ; 
+10BB: 01 FA 00        LD      BC,$00FA            ;
+10BE: 09              ADD     HL,BC               ;
+10BF: C1              POP     BC                  ;
+10C0: 05              DEC     B                   ;
+10C1: C2 B5 10        JP      NZ,$10B5            ; 
+10C4: 06 02           LD      B,$02               ;
+10C6: C5              PUSH    BC                  ;
+10C7: 21 0D 34        LD      HL,$340D            ;
+10CA: 22 00 20        LD      (waitOnDraw),HL     ; 
+10CD: 3E 01           LD      A,$01               ;
+10CF: F5              PUSH    AF                  ;
+10D0: F6 20           OR      $20                 ;
+10D2: D3 03           OUT     (SOUND1),A          ; 
+10D4: CD 05 11        CALL    $1105               ; 
+10D7: 3E 20           LD      A,$20               ;
+10D9: D3 03           OUT     (SOUND1),A          ; 
+10DB: CD 10 11        CALL    $1110               ; 
+10DE: F1              POP     AF                  ;
+10DF: 07              RLCA                        ;
+10E0: FE 20           CP      $20                 ;
+10E2: C2 CF 10        JP      NZ,$10CF            ; 
+10E5: 3E 01           LD      A,$01               ;
+10E7: F5              PUSH    AF                  ;
+10E8: D3 05           OUT     (SOUND2),A          ; 
+10EA: CD 05 11        CALL    $1105               ; 
+10ED: AF              XOR     A                   ;
+10EE: D3 05           OUT     (SOUND2),A          ; 
+10F0: CD 10 11        CALL    $1110               ; 
+10F3: F1              POP     AF                  ;
+10F4: 07              RLCA                        ;
+10F5: FE 40           CP      $40                 ;
+10F7: C2 E7 10        JP      NZ,$10E7            ; 
+10FA: C1              POP     BC                  ;
+10FB: 05              DEC     B                   ;
+10FC: C2 C6 10        JP      NZ,$10C6            ; 
+10FF: CD 29 11        CALL    $1129               ; 
+1102: C3 FF 10        JP      $10FF               ; 
+1105: 2A 00 20        LD      HL,(waitOnDraw)     ; 
+1108: 3E 0F           LD      A,$0F               ;
+110A: CD 66 11        CALL    $1166               ; 
+110D: C3 1F 11        JP      $111F               ; 
+1110: CD 1F 11        CALL    $111F               ; 
+1113: 2A 00 20        LD      HL,(waitOnDraw)     ; 
+1116: 3E 28           LD      A,$28               ;
+1118: CD 66 11        CALL    $1166               ; 
+111B: 22 00 20        LD      (waitOnDraw),HL     ; 
+111E: C9              RET                         ;
+111F: 3E 60           LD      A,$60               ;
+1121: CD CE 11        CALL    $11CE               ; 
+1124: 3D              DEC     A                   ;
+1125: C2 21 11        JP      NZ,$1121            ; 
+1128: C9              RET                         ;
+1129: F5              PUSH    AF                  ;
+112A: 21 0E 2B        LD      HL,$2B0E            ;
+112D: DB 01           IN      A,(INP1)            ; 
+112F: CD 3C 11        CALL    $113C               ; 
+1132: 21 0E 2F        LD      HL,$2F0E            ;
+1135: DB 02           IN      A,(INP2)            ; 
+1137: CD 3C 11        CALL    $113C               ; 
+113A: F1              POP     AF                  ;
+113B: C9              RET                         ;
+113C: 06 08           LD      B,$08               ;
+113E: C5              PUSH    BC                  ;
+113F: E5              PUSH    HL                  ;
+1140: 0F              RRCA                        ;
+1141: F5              PUSH    AF                  ;
+1142: 3E 28           LD      A,$28               ;
+1144: DA 49 11        JP      C,$1149             ; 
+1147: 3E 25           LD      A,$25               ;
+1149: CD 66 11        CALL    $1166               ; 
+114C: F1              POP     AF                  ;
+114D: E1              POP     HL                  ;
+114E: 23              INC     HL                  ;
+114F: C1              POP     BC                  ;
+1150: 05              DEC     B                   ;
+1151: C2 3E 11        JP      NZ,$113E            ; 
+1154: C9              RET                         ;
+1155: 0E 0D           LD      C,$0D               ;
+1157: 1A              LD      A,(DE)              ;
+1158: D5              PUSH    DE                  ;
+1159: E5              PUSH    HL                  ;
+115A: CD 66 11        CALL    $1166               ; 
+115D: E1              POP     HL                  ;
+115E: 23              INC     HL                  ;
+115F: D1              POP     DE                  ;
+1160: 13              INC     DE                  ;
+1161: 0D              DEC     C                   ;
+1162: C2 57 11        JP      NZ,$1157            ; 
+1165: C9              RET                         ;
+1166: 11 00 12        LD      DE,$1200            ;
+1169: E5              PUSH    HL                  ;
+116A: 6F              LD      L,A                 ;
+116B: 26 00           LD      H,$00               ;
+116D: 29              ADD     HL,HL               ;
+116E: 29              ADD     HL,HL               ;
+116F: 29              ADD     HL,HL               ;
+1170: 19              ADD     HL,DE               ;
+1171: EB              EX      DE,HL               ;
+1172: E1              POP     HL                  ;
+1173: 06 08           LD      B,$08               ;
+1175: C5              PUSH    BC                  ;
+1176: 1A              LD      A,(DE)              ;
+1177: 77              LD      (HL),A              ;
+1178: 13              INC     DE                  ;
+1179: 01 20 00        LD      BC,$0020            ;
+117C: 09              ADD     HL,BC               ;
+117D: C1              POP     BC                  ;
+117E: 05              DEC     B                   ;
+117F: C2 75 11        JP      NZ,$1175            ; 
+1182: C9              RET                         ;
+1183: 21 00 24        LD      HL,$2400            ;
+1186: 36 00           LD      (HL),$00            ;
+1188: 23              INC     HL                  ;
+1189: 7C              LD      A,H                 ;
+118A: FE 40           CP      $40                 ;
+118C: C2 86 11        JP      NZ,$1186            ; 
+118F: C9              RET                         ;
+1190: 06 01           LD      B,$01               ;
+1192: 0F              RRCA                        ;
+1193: DA 9A 11        JP      C,$119A             ; 
+1196: 04              INC     B                   ;
+1197: C3 92 11        JP      $1192               ; 
+119A: 7D              LD      A,L                 ;
+119B: 21 D8 12        LD      HL,$12D8            ;
+119E: 0F              RRCA                        ;
+119F: D2 A5 11        JP      NC,$11A5            ; 
+11A2: 21 B8 13        LD      HL,$13B8            ;
+11A5: 78              LD      A,B                 ;
+11A6: 07              RLCA                        ;
+11A7: 07              RLCA                        ;
+11A8: 07              RLCA                        ;
+11A9: 47              LD      B,A                 ;
+11AA: 58              LD      E,B                 ;
+11AB: 16 00           LD      D,$00               ;
+11AD: 19              ADD     HL,DE               ;
+11AE: EB              EX      DE,HL               ;
+11AF: 06 08           LD      B,$08               ;
+11B1: 21 11 30        LD      HL,$3011            ;
+11B4: 1A              LD      A,(DE)              ;
+11B5: 77              LD      (HL),A              ;
+11B6: 78              LD      A,B                 ;
+11B7: 01 20 00        LD      BC,$0020            ;
+11BA: 09              ADD     HL,BC               ;
+11BB: 47              LD      B,A                 ;
+11BC: 13              INC     DE                  ;
+11BD: 05              DEC     B                   ;
+11BE: C2 B4 11        JP      NZ,$11B4            ; 
+11C1: 06 08           LD      B,$08               ;
+11C3: 21 12 30        LD      HL,$3012            ;
+11C6: 11 40 13        LD      DE,$1340            ;
+11C9: D3 06           OUT     (WATCHDOG),A        ; 
+11CB: C3 B4 11        JP      $11B4               ; 
+11CE: CD 29 11        CALL    $1129               ; 
+11D1: D3 06           OUT     (WATCHDOG),A        ; 
+11D3: C9              RET                         ;
+11D4: FF              RST     0X38                ;
+11D5: FF              RST     0X38                ;
+11D6: FF              RST     0X38                ;
+11D7: FF              RST     0X38                ;
+11D8: FF              RST     0X38                ;
+11D9: FF              RST     0X38                ;
+11DA: FF              RST     0X38                ;
+11DB: FF              RST     0X38                ;
+11DC: FF              RST     0X38                ;
+11DD: FF              RST     0X38                ;
+11DE: FF              RST     0X38                ;
+11DF: FF              RST     0X38                ;
+11E0: FF              RST     0X38                ;
+11E1: FF              RST     0X38                ;
+11E2: FF              RST     0X38                ;
+11E3: FF              RST     0X38                ;
+11E4: FF              RST     0X38                ;
+11E5: FF              RST     0X38                ;
+11E6: FF              RST     0X38                ;
+11E7: FF              RST     0X38                ;
+11E8: FF              RST     0X38                ;
+11E9: FF              RST     0X38                ;
+11EA: FF              RST     0X38                ;
+11EB: FF              RST     0X38                ;
+11EC: FF              RST     0X38                ;
+11ED: FF              RST     0X38                ;
+11EE: FF              RST     0X38                ;
+11EF: FF              RST     0X38                ;
+11F0: FF              RST     0X38                ;
+11F1: FF              RST     0X38                ;
+11F2: FF              RST     0X38                ;
+11F3: FF              RST     0X38                ;
+11F4: FF              RST     0X38                ;
+11F5: FF              RST     0X38                ;
+11F6: FF              RST     0X38                ;
+11F7: FF              RST     0X38                ;
+11F8: FF              RST     0X38                ;
+11F9: FF              RST     0X38                ;
+11FA: FF              RST     0X38                ;
+11FB: FF              RST     0X38                ;
+11FC: FF              RST     0X38                ;
+11FD: FF              RST     0X38                ;
+11FE: FF              RST     0X38                ;
+11FF: FF              RST     0X38                ;
+1200: 00              NOP                         ;
+1201: 70              LD      (HL),B              ;
+1202: 88              ADC     A,B                 ;
+1203: A8              XOR     B                   ;
+1204: E8              RET     PE                  ;
+1205: 68              LD      L,B                 ;
+1206: 08              EX      AF,AF'              ;
+1207: F0              RET     P                   ;
+1208: 00              NOP                         ;
+1209: 20 50           JR      NZ,$125B            ; 
+120B: 88              ADC     A,B                 ;
+120C: 88              ADC     A,B                 ;
+120D: F8              RET     M                   ;
+120E: 88              ADC     A,B                 ;
+120F: 88              ADC     A,B                 ;
+1210: 00              NOP                         ;
+1211: 78              LD      A,B                 ;
+1212: 88              ADC     A,B                 ;
+1213: 88              ADC     A,B                 ;
+1214: 78              LD      A,B                 ;
+1215: 88              ADC     A,B                 ;
+1216: 88              ADC     A,B                 ;
+1217: 78              LD      A,B                 ;
+1218: 00              NOP                         ;
+1219: 70              LD      (HL),B              ;
+121A: 88              ADC     A,B                 ;
+121B: 08              EX      AF,AF'              ;
+121C: 08              EX      AF,AF'              ;
+121D: 08              EX      AF,AF'              ;
+121E: 88              ADC     A,B                 ;
+121F: 70              LD      (HL),B              ;
+1220: 00              NOP                         ;
+1221: 78              LD      A,B                 ;
+1222: 88              ADC     A,B                 ;
+1223: 88              ADC     A,B                 ;
+1224: 88              ADC     A,B                 ;
+1225: 88              ADC     A,B                 ;
+1226: 88              ADC     A,B                 ;
+1227: 78              LD      A,B                 ;
+1228: 00              NOP                         ;
+1229: F8              RET     M                   ;
+122A: 08              EX      AF,AF'              ;
+122B: 08              EX      AF,AF'              ;
+122C: 78              LD      A,B                 ;
+122D: 08              EX      AF,AF'              ;
+122E: 08              EX      AF,AF'              ;
+122F: F8              RET     M                   ;
+1230: 00              NOP                         ;
+1231: F8              RET     M                   ;
+1232: 08              EX      AF,AF'              ;
+1233: 08              EX      AF,AF'              ;
+1234: 78              LD      A,B                 ;
+1235: 08              EX      AF,AF'              ;
+1236: 08              EX      AF,AF'              ;
+1237: 08              EX      AF,AF'              ;
+1238: 00              NOP                         ;
+1239: F0              RET     P                   ;
+123A: 08              EX      AF,AF'              ;
+123B: 08              EX      AF,AF'              ;
+123C: 08              EX      AF,AF'              ;
+123D: C8              RET     Z                   ;
+123E: 88              ADC     A,B                 ;
+123F: F0              RET     P                   ;
+1240: 00              NOP                         ;
+1241: 88              ADC     A,B                 ;
+1242: 88              ADC     A,B                 ;
+1243: 88              ADC     A,B                 ;
+1244: F8              RET     M                   ;
+1245: 88              ADC     A,B                 ;
+1246: 88              ADC     A,B                 ;
+1247: 88              ADC     A,B                 ;
+1248: 00              NOP                         ;
+1249: 70              LD      (HL),B              ;
+124A: 20 20           JR      NZ,$126C            ; 
+124C: 20 20           JR      NZ,$126E            ; 
+124E: 20 70           JR      NZ,$12C0            ; 
+1250: 00              NOP                         ;
+1251: 80              ADD     A,B                 ;
+1252: 80              ADD     A,B                 ;
+1253: 80              ADD     A,B                 ;
+1254: 80              ADD     A,B                 ;
+1255: 80              ADD     A,B                 ;
+1256: 88              ADC     A,B                 ;
+1257: 70              LD      (HL),B              ;
+1258: 00              NOP                         ;
+1259: 88              ADC     A,B                 ;
+125A: 48              LD      C,B                 ;
+125B: 28 18           JR      Z,$1275             ; 
+125D: 28 48           JR      Z,$12A7             ; 
+125F: 88              ADC     A,B                 ;
+1260: 00              NOP                         ;
+1261: 08              EX      AF,AF'              ;
+1262: 08              EX      AF,AF'              ;
+1263: 08              EX      AF,AF'              ;
+1264: 08              EX      AF,AF'              ;
+1265: 08              EX      AF,AF'              ;
+1266: 08              EX      AF,AF'              ;
+1267: F8              RET     M                   ;
+1268: 00              NOP                         ;
+1269: 88              ADC     A,B                 ;
+126A: D8              RET     C                   ;
+126B: A8              XOR     B                   ;
+126C: A8              XOR     B                   ;
+126D: 88              ADC     A,B                 ;
+126E: 88              ADC     A,B                 ;
+126F: 88              ADC     A,B                 ;
+1270: 00              NOP                         ;
+1271: 88              ADC     A,B                 ;
+1272: 88              ADC     A,B                 ;
+1273: 98              SBC     B                   ;
+1274: A8              XOR     B                   ;
+1275: C8              RET     Z                   ;
+1276: 88              ADC     A,B                 ;
+1277: 88              ADC     A,B                 ;
+1278: 00              NOP                         ;
+1279: 70              LD      (HL),B              ;
+127A: 88              ADC     A,B                 ;
+127B: 88              ADC     A,B                 ;
+127C: 88              ADC     A,B                 ;
+127D: 88              ADC     A,B                 ;
+127E: 88              ADC     A,B                 ;
+127F: 70              LD      (HL),B              ;
+1280: 00              NOP                         ;
+1281: 78              LD      A,B                 ;
+1282: 88              ADC     A,B                 ;
+1283: 88              ADC     A,B                 ;
+1284: 78              LD      A,B                 ;
+1285: 08              EX      AF,AF'              ;
+1286: 08              EX      AF,AF'              ;
+1287: 08              EX      AF,AF'              ;
+1288: 00              NOP                         ;
+1289: 70              LD      (HL),B              ;
+128A: 88              ADC     A,B                 ;
+128B: 88              ADC     A,B                 ;
+128C: 88              ADC     A,B                 ;
+128D: A8              XOR     B                   ;
+128E: 48              LD      C,B                 ;
+128F: B0              OR      B                   ;
+1290: 00              NOP                         ;
+1291: 78              LD      A,B                 ;
+1292: 88              ADC     A,B                 ;
+1293: 88              ADC     A,B                 ;
+1294: 78              LD      A,B                 ;
+1295: 28 48           JR      Z,$12DF             ; 
+1297: 88              ADC     A,B                 ;
+1298: 00              NOP                         ;
+1299: 70              LD      (HL),B              ;
+129A: 88              ADC     A,B                 ;
+129B: 08              EX      AF,AF'              ;
+129C: 70              LD      (HL),B              ;
+129D: 80              ADD     A,B                 ;
+129E: 88              ADC     A,B                 ;
+129F: 70              LD      (HL),B              ;
+12A0: 00              NOP                         ;
+12A1: F8              RET     M                   ;
+12A2: 20 20           JR      NZ,$12C4            ; 
+12A4: 20 20           JR      NZ,$12C6            ; 
+12A6: 20 20           JR      NZ,$12C8            ; 
+12A8: 00              NOP                         ;
+12A9: 88              ADC     A,B                 ;
+12AA: 88              ADC     A,B                 ;
+12AB: 88              ADC     A,B                 ;
+12AC: 88              ADC     A,B                 ;
+12AD: 88              ADC     A,B                 ;
+12AE: 88              ADC     A,B                 ;
+12AF: 70              LD      (HL),B              ;
+12B0: 00              NOP                         ;
+12B1: 88              ADC     A,B                 ;
+12B2: 88              ADC     A,B                 ;
+12B3: 88              ADC     A,B                 ;
+12B4: 88              ADC     A,B                 ;
+12B5: 88              ADC     A,B                 ;
+12B6: 50              LD      D,B                 ;
+12B7: 20 00           JR      NZ,$12B9            ; 
+12B9: 88              ADC     A,B                 ;
+12BA: 88              ADC     A,B                 ;
+12BB: 88              ADC     A,B                 ;
+12BC: A8              XOR     B                   ;
+12BD: A8              XOR     B                   ;
+12BE: D8              RET     C                   ;
+12BF: 88              ADC     A,B                 ;
+12C0: 00              NOP                         ;
+12C1: 88              ADC     A,B                 ;
+12C2: 88              ADC     A,B                 ;
+12C3: 50              LD      D,B                 ;
+12C4: 20 50           JR      NZ,$1316            ; 
+12C6: 88              ADC     A,B                 ;
+12C7: 88              ADC     A,B                 ;
+12C8: 00              NOP                         ;
+12C9: 88              ADC     A,B                 ;
+12CA: 88              ADC     A,B                 ;
+12CB: 50              LD      D,B                 ;
+12CC: 20 20           JR      NZ,$12EE            ; 
+12CE: 20 20           JR      NZ,$12F0            ; 
+12D0: 00              NOP                         ;
+12D1: F8              RET     M                   ;
+12D2: 80              ADD     A,B                 ;
+12D3: 40              LD      B,B                 ;
+12D4: 20 10           JR      NZ,$12E6            ; 
+12D6: 08              EX      AF,AF'              ;
+12D7: F8              RET     M                   ;
+12D8: 00              NOP                         ;
+12D9: 70              LD      (HL),B              ;
+12DA: 88              ADC     A,B                 ;
+12DB: C8              RET     Z                   ;
+12DC: A8              XOR     B                   ;
+12DD: 98              SBC     B                   ;
+12DE: 88              ADC     A,B                 ;
+12DF: 70              LD      (HL),B              ;
+12E0: 00              NOP                         ;
+12E1: 20 30           JR      NZ,$1313            ; 
+12E3: 20 20           JR      NZ,$1305            ; 
+12E5: 20 20           JR      NZ,$1307            ; 
+12E7: 70              LD      (HL),B              ;
+12E8: 00              NOP                         ;
+12E9: 70              LD      (HL),B              ;
+12EA: 88              ADC     A,B                 ;
+12EB: 80              ADD     A,B                 ;
+12EC: 60              LD      H,B                 ;
+12ED: 10 08           DJNZ    $12F7               ; 
+12EF: F8              RET     M                   ;
+12F0: 00              NOP                         ;
+12F1: F8              RET     M                   ;
+12F2: 80              ADD     A,B                 ;
+12F3: 40              LD      B,B                 ;
+12F4: 60              LD      H,B                 ;
+12F5: 80              ADD     A,B                 ;
+12F6: 88              ADC     A,B                 ;
+12F7: 70              LD      (HL),B              ;
+12F8: 00              NOP                         ;
+12F9: 40              LD      B,B                 ;
+12FA: 60              LD      H,B                 ;
+12FB: 50              LD      D,B                 ;
+12FC: 48              LD      C,B                 ;
+12FD: F8              RET     M                   ;
+12FE: 40              LD      B,B                 ;
+12FF: 40              LD      B,B                 ;
+1300: 00              NOP                         ;
+1301: F8              RET     M                   ;
+1302: 08              EX      AF,AF'              ;
+1303: 78              LD      A,B                 ;
+1304: 80              ADD     A,B                 ;
+1305: 80              ADD     A,B                 ;
+1306: 88              ADC     A,B                 ;
+1307: 70              LD      (HL),B              ;
+1308: 00              NOP                         ;
+1309: E0              RET     PO                  ;
+130A: 10 08           DJNZ    $1314               ; 
+130C: 78              LD      A,B                 ;
+130D: 88              ADC     A,B                 ;
+130E: 88              ADC     A,B                 ;
+130F: 70              LD      (HL),B              ;
+1310: 00              NOP                         ;
+1311: F8              RET     M                   ;
+1312: 80              ADD     A,B                 ;
+1313: 40              LD      B,B                 ;
+1314: 20 10           JR      NZ,$1326            ; 
+1316: 10 10           DJNZ    $1328               ; 
+1318: 00              NOP                         ;
+1319: 70              LD      (HL),B              ;
+131A: 88              ADC     A,B                 ;
+131B: 88              ADC     A,B                 ;
+131C: 70              LD      (HL),B              ;
+131D: 88              ADC     A,B                 ;
+131E: 88              ADC     A,B                 ;
+131F: 70              LD      (HL),B              ;
+1320: 00              NOP                         ;
+1321: 70              LD      (HL),B              ;
+1322: 88              ADC     A,B                 ;
+1323: 88              ADC     A,B                 ;
+1324: F0              RET     P                   ;
+1325: 80              ADD     A,B                 ;
+1326: 40              LD      B,B                 ;
+1327: 38 00           JR      C,$1329             ; 
+1329: 20 A8           JR      NZ,$12D3            ; 
+132B: 70              LD      (HL),B              ;
+132C: 20 70           JR      NZ,$139E            ; 
+132E: A8              XOR     B                   ;
+132F: 20 00           JR      NZ,$1331            ; 
+1331: 10 20           DJNZ    $1353               ; 
+1333: 40              LD      B,B                 ;
+1334: 80              ADD     A,B                 ;
+1335: 40              LD      B,B                 ;
+1336: 20 10           JR      NZ,$1348            ; 
+1338: 00              NOP                         ;
+1339: 00              NOP                         ;
+133A: 00              NOP                         ;
+133B: 00              NOP                         ;
+133C: 00              NOP                         ;
+133D: 00              NOP                         ;
+133E: 00              NOP                         ;
+133F: 20 00           JR      NZ,$1341            ; 
+1341: 00              NOP                         ;
+1342: 00              NOP                         ;
+1343: 00              NOP                         ;
+1344: 00              NOP                         ;
+1345: 00              NOP                         ;
+1346: 00              NOP                         ;
+1347: 00              NOP                         ;
+1348: 26 0F           LD      H,$0F               ;
+134A: 0B              DEC     BC                  ;
+134B: 28 01           JR      Z,$134E             ; 
+134D: 0C              INC     C                   ;
+134E: 0C              INC     C                   ;
+134F: 28 12           JR      Z,$1363             ; 
+1351: 01 0D 13        LD      BC,$130D            ;
+1354: 28 26           JR      Z,$137C             ; 
+1356: 03              INC     BC                  ;
+1357: 08              EX      AF,AF'              ;
+1358: 05              DEC     B                   ;
+1359: 03              INC     BC                  ;
+135A: 0B              DEC     BC                  ;
+135B: 28 09           JR      Z,$1366             ; 
+135D: 0E 10           LD      C,$10               ;
+135F: 0F              RRCA                        ;
+1360: 12              LD      (DE),A              ;
+1361: 14              INC     D                   ;
+1362: 26 03           LD      H,$03               ;
+1364: 08              EX      AF,AF'              ;
+1365: 05              DEC     B                   ;
+1366: 03              INC     BC                  ;
+1367: 0B              DEC     BC                  ;
+1368: 28 13           JR      Z,$137D             ; 
+136A: 0F              RRCA                        ;
+136B: 15              DEC     D                   ;
+136C: 0E 04           LD      C,$04               ;
+136E: 28 10           JR      Z,$1380             ; 
+1370: 0F              RRCA                        ;
+1371: 12              LD      (DE),A              ;
+1372: 14              INC     D                   ;
+1373: 1C              INC     E                   ;
+1374: 28 28           JR      Z,$139E             ; 
+1376: 1B              DEC     DE                  ;
+1377: 1C              INC     E                   ;
+1378: 1D              DEC     E                   ;
+1379: 1E 1F           LD      E,$1F               ;
+137B: 20 21           JR      NZ,$139E            ; 
+137D: 22 25 15        LD      ($1525),HL          ; 
+1380: 06 0F           LD      B,$0F               ;
+1382: 27              DAA                         ;
+1383: 06 25           LD      B,$25               ;
+1385: 0D              DEC     C                   ;
+1386: 09              ADD     HL,BC               ;
+1387: 13              INC     DE                  ;
+1388: 13              INC     DE                  ;
+1389: 0C              INC     C                   ;
+138A: 25              DEC     H                   ;
+138B: 0C              INC     C                   ;
+138C: 01 15 27        LD      BC,$2715            ;
+138F: 08              EX      AF,AF'              ;
+1390: 25              DEC     H                   ;
+1391: 09              ADD     HL,BC               ;
+1392: 0E 16           LD      C,$16               ;
+1394: 27              DAA                         ;
+1395: 08              EX      AF,AF'              ;
+1396: 25              DEC     H                   ;
+1397: 05              DEC     B                   ;
+1398: 18 14           JR      $13AE               ; 
+139A: 12              LD      (DE),A              ;
+139B: 01 25 09        LD      BC,$0925            ;
+139E: 0E 16           LD      C,$16               ;
+13A0: 27              DAA                         ;
+13A1: 1C              INC     E                   ;
+13A2: 25              DEC     H                   ;
+13A3: 09              ADD     HL,BC               ;
+13A4: 0E 16           LD      C,$16               ;
+13A6: 27              DAA                         ;
+13A7: 1D              DEC     E                   ;
+13A8: 25              DEC     H                   ;
+13A9: 09              ADD     HL,BC               ;
+13AA: 0E 16           LD      C,$16               ;
+13AC: 27              DAA                         ;
+13AD: 1E 25           LD      E,$25               ;
+13AF: 09              ADD     HL,BC               ;
+13B0: 0E 16           LD      C,$16               ;
+13B2: 27              DAA                         ;
+13B3: 1F              RRA                         ;
+13B4: 25              DEC     H                   ;
+13B5: 15              DEC     D                   ;
+13B6: 06 0F           LD      B,$0F               ;
+13B8: 27              DAA                         ;
+13B9: 08              EX      AF,AF'              ;
+13BA: 25              DEC     H                   ;
+13BB: 16 09           LD      D,$09               ;
+13BD: 04              INC     B                   ;
+13BE: 27              DAA                         ;
+13BF: 12              LD      (DE),A              ;
+13C0: 20 50           JR      NZ,$1412            ; 
+13C2: 88              ADC     A,B                 ;
+13C3: 88              ADC     A,B                 ;
+13C4: F8              RET     M                   ;
+13C5: 88              ADC     A,B                 ;
+13C6: 88              ADC     A,B                 ;
+13C7: 00              NOP                         ;
+13C8: 78              LD      A,B                 ;
+13C9: 88              ADC     A,B                 ;
+13CA: 88              ADC     A,B                 ;
+13CB: 78              LD      A,B                 ;
+13CC: 88              ADC     A,B                 ;
+13CD: 88              ADC     A,B                 ;
+13CE: 78              LD      A,B                 ;
+13CF: 00              NOP                         ;
+13D0: 70              LD      (HL),B              ;
+13D1: 88              ADC     A,B                 ;
+13D2: 08              EX      AF,AF'              ;
+13D3: 08              EX      AF,AF'              ;
+13D4: 08              EX      AF,AF'              ;
+13D5: 88              ADC     A,B                 ;
+13D6: 70              LD      (HL),B              ;
+13D7: 00              NOP                         ;
+13D8: 70              LD      (HL),B              ;
+13D9: 90              SUB     B                   ;
+13DA: 90              SUB     B                   ;
+13DB: 90              SUB     B                   ;
+13DC: 90              SUB     B                   ;
+13DD: 90              SUB     B                   ;
+13DE: 70              LD      (HL),B              ;
+13DF: 00              NOP                         ;
+13E0: E0              RET     PO                  ;
+13E1: 20 20           JR      NZ,$1403            ; 
+13E3: E0              RET     PO                  ;
+13E4: 20 20           JR      NZ,$1406            ; 
+13E6: E0              RET     PO                  ;
+13E7: 00              NOP                         ;
+13E8: 3E 02           LD      A,$02               ;
+13EA: 02              LD      (BC),A              ;
+13EB: 1E 02           LD      E,$02               ;
+13ED: 02              LD      (BC),A              ;
+13EE: 02              LD      (BC),A              ;
+13EF: 00              NOP                         ;
+13F0: 3C              INC     A                   ;
+13F1: 02              LD      (BC),A              ;
+13F2: 02              LD      (BC),A              ;
+13F3: 02              LD      (BC),A              ;
+13F4: 32 22 3C     ;LD    ($3C22),A          ;
+13F7: 00              NOP                         ;
+13F8: 22 22 22        LD      (+22),HL            ; 
+13FB: 3E 22           LD      A,$22               ;
+13FD: 22 22 00     ;LD    ($0022),HL         ;
+
+
+;1000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;10A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;10C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;10E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1140: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1160: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;11A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;11C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;11E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1220: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1240: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1260: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1280: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;12A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;12C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;12E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1320: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1340: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1360: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;1380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;13A0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;13C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+;13E0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+
+DrawShiftedSprite:
+; The only differences between this and EraseSimpleSprite is two CPL instructions in the latter and
+; the use of AND instead of OR. NOP takes the same amount of time/space as CPL. So the two NOPs
+; here make these two parallel routines the same size and speed.
+;
+1400: 00              NOP                         ; Time/size pad to match CPL in EraseShiftedSprite
+1401: CD 74 14        CALL    CnvtPixNumber       ; Convert pixel number to coord and shift
+1404: 00              NOP                         ; Time/size pad to match CPL in EraseShiftedSprite
+1405: C5              PUSH    BC                  ; Hold count
+1406: E5              PUSH    HL                  ; Hold start coordinate
+1407: 1A              LD      A,(DE)              ; Get the picture bits
+1408: D3 04           OUT     (SHFT_DATA),A       ; Store in shift register
+140A: DB 03           IN      A,(SHFT_IN)         ; Read the shifted pixels
+140C: B6              OR      (HL)                ; OR them onto the screen
+140D: 77              LD      (HL),A              ; Store them back to screen
+140E: 23              INC     HL                  ; Next colummn on screen
+140F: 13              INC     DE                  ; Next in picture
+1410: AF              XOR     A                   ; Shift over ...
+1411: D3 04           OUT     (SHFT_DATA),A       ; ... to next byte in register (shift in 0)
+1413: DB 03           IN      A,(SHFT_IN)         ; Read the shifted pixels
+1415: B6              OR      (HL)                ; OR them onto the screen
+1416: 77              LD      (HL),A              ; Store them back to screen
+1417: E1              POP     HL                  ; Restore starting coordinate
+1418: 01 20 00        LD      BC,$0020            ; Add 32 ...
+141B: 09              ADD     HL,BC               ; ... to coordinate (move to next row)
+141C: C1              POP     BC                  ; Restore count
+141D: 05              DEC     B                   ; All done?
+141E: C2 05 14        JP      NZ,$1405            ; No ... go do all rows
+1421: C9              RET                         ; Done
+
+1422: 00 00 ; ** Why?
+
+EraseSimpleSprite:
+; Clear a sprite from the screen (standard pixel number descriptor).
+; ** We clear 2 bytes even though the draw-simple only draws one.
+1424: CD 74 14        CALL    CnvtPixNumber       ; Convert pixel number in HL
+1427: C5              PUSH    BC                  ; Hold
+1428: E5              PUSH    HL                  ; Hold
+1429: AF              XOR     A                   ; 0
+142A: 77              LD      (HL),A              ; Clear screen byte
+142B: 23              INC     HL                  ; Next byte
+142C: 77              LD      (HL),A              ; Clear byte
+142D: 23              INC     HL                  ; ** Is this to mimic timing? We increment then pop
+142E: E1              POP     HL                  ; Restore screen coordinate
+142F: 01 20 00        LD      BC,$0020            ; Add 1 row ...
+1432: 09              ADD     HL,BC               ; ... to screen coordinate
+1433: C1              POP     BC                  ; Restore counter
+1434: 05              DEC     B                   ; All rows done?
+1435: C2 27 14        JP      NZ,$1427            ; Do all rows
+1438: C9              RET                         ; out
+
+DrawSimpSprite:
+; Display character to screen
+; HL = screen coordinates
+; DE = character data
+; B = number of rows
+1439: C5              PUSH    BC                  ; Preserve counter
+143A: 1A              LD      A,(DE)              ; From character set ...
+143B: 77              LD      (HL),A              ; ... to screen
+143C: 13              INC     DE                  ; Next in character set
+143D: 01 20 00        LD      BC,$0020            ; Next row ...
+1440: 09              ADD     HL,BC               ; ... on screen
+1441: C1              POP     BC                  ; Restore counter
+1442: 05              DEC     B                   ; Decrement counter
+1443: C2 39 14        JP      NZ,DrawSimpSprite   ; Do all
+1446: C9              RET                         ; Out
+
+1447: 00 00 00 00 00 00 00 00 00 00 00 ; ** Why?
+                        
+EraseShifted:
+; Erases a shifted sprite from screen (like for player's explosion)
+1452: CD 74 14        CALL    CnvtPixNumber       ; Convert pixel number in HL to coorinates with shift
+1455: C5              PUSH    BC                  ; Hold BC
+1456: E5              PUSH    HL                  ; Hold coordinate
+1457: 1A              LD      A,(DE)              ; Get picture value
+1458: D3 04           OUT     (SHFT_DATA),A       ; Value into shift register
+145A: DB 03           IN      A,(SHFT_IN)         ; Read shifted sprite picture
+145C: 2F              CPL                         ; Reverse it (erasing bits)
+145D: A6              AND     (HL)                ; Erase the bits from the screen
+145E: 77              LD      (HL),A              ; Store the erased pattern back
+145F: 23              INC     HL                  ; Next column on screen
+1460: 13              INC     DE                  ; Next in image
+1461: AF              XOR     A                   ; Shift register over ...
+1462: D3 04           OUT     (SHFT_DATA),A       ; ... 8 bits (shift in 0)
+1464: DB 03           IN      A,(SHFT_IN)         ; Read 2nd byte of image
+1466: 2F              CPL                         ; Reverse it (erasing bits)
+1467: A6              AND     (HL)                ; Erase the bits from the screen
+1468: 77              LD      (HL),A              ; Store the erased pattern back
+1469: E1              POP     HL                  ; Restore starting coordinate
+146A: 01 20 00        LD      BC,$0020            ; Add 32 ...
+146D: 09              ADD     HL,BC               ; ... to next row
+146E: C1              POP     BC                  ; Restore BC (count)
+146F: 05              DEC     B                   ; All rows done?
+1470: C2 55 14        JP      NZ,$1455            ; No ... erase all
+1473: C9              RET                         ; Done
+
+CnvtPixNumber:
+; Convert pixel number in HL to screen coordinate and shift amount.
+; HL gets screen coordinate.
+; Hardware shift-register gets amount.
+1474: 7D              LD      A,L                 ; Get X coordinate
+1475: E6 07           AND     $07                 ; Shift by pixel position
+1477: D3 02           OUT     (SHFTAMNT),A        ; Write shift amount to hardware
+1479: C3 47 1A        JP      ConvToScr           ; HL = HL/8 + 2000 (screen coordinate)
+
+RememberShields:
+; In a multi-player game the player's shields are block-copied to and from RAM between turns.
+; HL = screen pointer
+; DE = memory buffer
+; B = number of rows
+; C = number of columns
+147C: C5              PUSH    BC                  ; Hold counter
+147D: E5              PUSH    HL                  ; Hold start
+147E: 7E              LD      A,(HL)              ; From sprite ... (should be DE)
+147F: 12              LD      (DE),A              ; ... to screen ... (should be HL)
+1480: 13              INC     DE                  ; Next in sprite
+1481: 23              INC     HL                  ; Next on screen
+1482: 0D              DEC     C                   ; All columns done?
+1483: C2 7E 14        JP      NZ,$147E            ; No ... do multi columns
+1486: E1              POP     HL                  ; Restore screen start
+1487: 01 20 00        LD      BC,$0020            ; Add 32 ...
+148A: 09              ADD     HL,BC               ; ... to get to next row
+148B: C1              POP     BC                  ; Pop the counters
+148C: 05              DEC     B                   ; All rows done?
+148D: C2 7C 14        JP      NZ,RememberShields  ; No ... do multi rows
+1490: C9              RET                         ; Done
+
+DrawSprCollision:
+1491: CD 74 14        CALL    CnvtPixNumber       ; Convert pixel number to coord and shift
+1494: AF              XOR     A                   ; Clear the ...
+1495: 32 61 20        LD      (collision),A       ; ... collision-detection flag
+1498: C5              PUSH    BC                  ; Hold count
+1499: E5              PUSH    HL                  ; Hold screen
+149A: 1A              LD      A,(DE)              ; Get byte
+149B: D3 04           OUT     (SHFT_DATA),A       ; Write first byte to shift register
+149D: DB 03           IN      A,(SHFT_IN)         ; Read shifted pattern
+149F: F5              PUSH    AF                  ; Hold the pattern
+14A0: A6              AND     (HL)                ; Any bits from pixel collide with bits on screen?
+14A1: CA A9 14        JP      Z,$14A9             ; No ... leave flag alone
+14A4: 3E 01           LD      A,$01               ; Yes ... set ...
+14A6: 32 61 20        LD      (collision),A       ; ... collision flag
+14A9: F1              POP     AF                  ; Restore the pixel pattern
+14AA: B6              OR      (HL)                ; OR it onto the screen
+14AB: 77              LD      (HL),A              ; Store new screen value
+14AC: 23              INC     HL                  ; Next byte on screen
+14AD: 13              INC     DE                  ; Next in pixel pattern
+14AE: AF              XOR     A                   ; Write zero ...
+14AF: D3 04           OUT     (SHFT_DATA),A       ; ... to shift register
+14B1: DB 03           IN      A,(SHFT_IN)         ; Read 2nd half of shifted sprite
+14B3: F5              PUSH    AF                  ; Hold pattern
+14B4: A6              AND     (HL)                ; Any bits from pixel collide with bits on screen?
+14B5: CA BD 14        JP      Z,$14BD             ; No ... leave flag alone
+14B8: 3E 01           LD      A,$01               ; Yes ... set ...
+14BA: 32 61 20        LD      (collision),A       ; ... collision flag
+14BD: F1              POP     AF                  ; Restore the pixel pattern
+14BE: B6              OR      (HL)                ; OR it onto the screen
+14BF: 77              LD      (HL),A              ; Store new screen pattern
+14C0: E1              POP     HL                  ; Starting screen coordinate
+14C1: 01 20 00        LD      BC,$0020            ; Add 32 ...
+14C4: 09              ADD     HL,BC               ; ... to get to next row
+14C5: C1              POP     BC                  ; Restore count
+14C6: 05              DEC     B                   ; All done?
+14C7: C2 98 14        JP      NZ,$1498            ; No ... do all rows
+14CA: C9              RET                         ; Done
+
+ClearSmallSprite:
+; Clear a one byte sprite at HL. B=number of rows.
+14CB: AF              XOR     A                   ; 0
+14CC: C5              PUSH    BC                  ; Preserve BC
+14CD: 77              LD      (HL),A              ; Clear screen byte
+14CE: 01 20 00        LD      BC,$0020            ; Bump HL ...
+14D1: 09              ADD     HL,BC               ; ... one screen row
+14D2: C1              POP     BC                  ; Restore
+14D3: 05              DEC     B                   ; All done?
+14D4: C2 CC 14        JP      NZ,$14CC            ; No ... clear all
+14D7: C9              RET                         
+
+PlayerShotHit:
+; The player's shot hit something (or is being removed from play)
+;
+14D8: 3A 25 20        LD      A,(plyrShotStatus)  ; Player shot flag
+14DB: FE 05           CP      $05                 ; Alien explosion in progress?
+14DD: C8              RET     Z                   ; Yes ... ignore this function
+14DE: FE 02           CP      $02                 ; Normal movement?
+14E0: C0              RET     NZ                  ; No ... out
+;
+14E1: 3A 29 20        LD      A,(obj1CoorYr)      ; Get Yr coordinate of player shot
+14E4: FE D8           CP      $D8                 ; Compare to 216 (40 from Top-rotated)
+14E6: 47              LD      B,A                 ; Hold value for later
+14E7: D2 30 15        JP      NC,$1530            ; Yr is within 40 from top initiate miss-explosion (shot flag 3)
+14EA: 3A 02 20        LD      A,(alienIsExploding); Is an alien ...
+14ED: A7              AND     A                   ; ... blowing up?
+14EE: C8              RET     Z                   ; No ... out
+;
+14EF: 78              LD      A,B                 ; Get original Yr coordinate back to A
+14F0: FE CE           CP      $CE                 ; Compare to 206 (50 from rotated top)
+14F2: D2 79 15        JP      NC,$1579            ; Yr is within 50 from top? Yes ... saucer must be hit
+14F5: C6 06           ADD     A,$06               ; Offset to coordinate for wider "explosion" picture
+14F7: 47              LD      B,A                 ; Hold that
+14F8: 3A 09 20        LD      A,(refAlienYr)      ; Ref alien Y coordianate
+
+; If the lower 4 rows are all empty then the reference alien's Y coordinate will wrap around from 0 to F8.
+; At this point the top row of aliens is in the shields and we will assume that everything is within
+; the rack.
+
+14FB: FE 90           CP      $90                 ; This is true if ...
+14FD: D2 04 15        JP      NC,CodeBug1         ; ... aliens are down in the shields
+1500: B8              CP      B                   ; Compare to shot's coordinate
+1501: D2 30 15        JP      NC,$1530            ; Outside the rack-square ... do miss explosion
+
+CodeBug1:
+;
+; We get here if the player's shot hit something within the rack area (a shot or an alien).
+; Find the alien that is (or would be) where the shot hit. If there is no alien alive at the row/column
+; thn the player hit an alien missile. If there is an alien then explode the alien.
+;
+; There is a code bug here, but it is extremely subtle. The algorithm for finding the row/column in the
+; rack works by adding 16 to the reference coordinates (X for column, Y for row) until it passes or equals
+; the target coordinates. This works great as long as the target point is within the alien's rack area.
+; If the reference point is far to the right, the column number will be greater than 11, which messes
+; up the column/row-to-pointer math.
+;
+; The entire rack of aliens is based on the lower left alien. Imagine all aliens are dead except the
+; upper left. It wiggles down the screen and enters the players shields on the lower left where it begins
+; to eat them. Imagine the player is under his own shields on the right side of the screen and fires a
+; shot into his own shield.
+;
+; The alien is in the rack on row 4 (rows are numbered from bottom up starting with 0). The shot hits
+; the shields below the alien's Y coordinate and gets correctly assigned to row 3. The alien is in the rack
+; at column 0 (columns are numbered from left to right starting with 0). The shot hits the shields far to
+; the right of the alien's X coordinate. The algorithm says it is in column 11. But 0-10 are the only
+; correct values.
+;
+; The column/row-to-pointer math works by multiplying the row by 11 and adding the column. For the alien
+; that is 11*4 + 0 = 44. For the shot that is 11*3 +11 = 44. The game thinks the shot hit the alien.
+;
+1504: 68              LD      L,B                 ; L now holds the shot coordinate (adjusted)
+1505: CD 62 15        CALL    FindRow             ; Look up row number to B
+1508: 3A 2A 20        LD      A,(obj1CoorXr)      ; Player's shot's Xr coordinate ...
+150B: 67              LD      H,A                 ; ... to H
+150C: CD 6F 15        CALL    FindColumn          ; Get alien's coordinate
+150F: 22 64 20        LD      (expAlienYr),HL     ; Put it in the exploding-alien descriptor
+1512: 3E 05           LD      A,$05               ; Flag alien explosion ...
+1514: 32 25 20        LD      (plyrShotStatus),A  ; ... in progress
+1517: CD 81 15        CALL    GetAlienStatPtr     ; Get descriptor for alien
+151A: 7E              LD      A,(HL)              ; Is alien ...
+151B: A7              AND     A                   ; ... alive
+151C: CA 30 15        JP      Z,$1530             ; No ... must have been an alien shot
+;
+151F: 36 00           LD      (HL),$00            ; Make alien invader dead
+1521: CD 5F 0A        CALL    ScoreForAlien       ; Makes alien explosion sound and adjust score
+1524: CD 3B 1A        CALL    ReadDesc            ; Load 5 byte sprite descriptor
+1527: CD D3 15        CALL    DrawSprite          ; Draw explosion sprite on screen
+152A: 3E 10           LD      A,$10               ; Initiate alien-explosion
+152C: 32 03 20        LD      (expAlienTimer),A   ; ... timer to 16
+152F: C9              RET                         ; Out
+;
+; Player shot leaving playfield, hitting shield, or hitting an alien shot
+1530: 3E 03           LD      A,$03               ; Mark ...
+1532: 32 25 20        LD      (plyrShotStatus),A  ; ... player shot hit something other than alien
+1535: C3 4A 15        JP      $154A               ; Finish up
+;
+AExplodeTime:
+; Time down the alien explosion. Remove when done.
+1538: 21 03 20        LD      HL,$2003            ; Decrement alien explosion ...
+153B: 35              DEC     (HL)                ; ... timer
+153C: C0              RET     NZ                  ; Not done  ... out
+153D: 2A 64 20        LD      HL,(expAlienYr)     ; Pixel pointer for exploding alien
+1540: 06 10           LD      B,$10               ; 16 row pixel
+1542: CD 24 14        CALL    EraseSimpleSprite   ; Clear the explosion sprite from the screen
+1545: 3E 04           LD      A,$04               ; 4 means that ...
+1547: 32 25 20        LD      (plyrShotStatus),A  ; ... alien has exploded (remove from active duty)
+;
+154A: AF              XOR     A                   ; Turn off ...
+154B: 32 02 20        LD      (alienIsExploding),A; ... alien-is-blowing-up flag
+154E: 06 F7           LD      B,$F7               ; Turn off ...
+1550: C3 DC 19        JP      SoundBits3Off       ; ... alien exploding sound
+
+1553: 00                          
+    
+Cnt16s:
+; Count number of 16s needed to bring reference (in A) up to target (in H).
+; If the reference starts out beyond the target then we add 16s as long as
+; the reference has a signed bit. But these aren't signed quantities. This
+; doesn't make any sense. This counting algorithm produces questionable
+; results if the reference is beyond the target.
+;
+1554: 0E 00           LD      C,$00               ; Count of 16s
+1556: BC              CP      H                   ; Compare reference coordinate to target
+1557: D4 90 15        CALL    NC,WrapRef          ; If reference is greater or equal then do something questionable ... see below
+155A: BC              CP      H                   ; Compare reference coordinate to target
+155B: D0              RET     NC                  ; If reference is greater or equal then done
+155C: C6 10           ADD     A,$10               ; Add 16 to reference
+155E: 0C              INC     C                   ; Bump 16s count
+155F: C3 5A 15        JP      $155A               ; Keep testing
+
+FindRow:
+; L contains a Yr coordinate. Find the row number within the rack that corresponds
+; to the Yr coordinate. Return the row coordinate in L and the row number in C.
+;
+1562: 3A 09 20        LD      A,(refAlienYr)      ; Reference alien Yr coordinate
+1565: 65              LD      H,L                 ; Target Yr coordinate to H
+1566: CD 54 15        CALL    Cnt16s              ; Count 16s needed to bring ref alien to target
+1569: 41              LD      B,C                 ; Count to B
+156A: 05              DEC     B                   ; Base 0
+156B: DE 10           SBC     A,$10               ; The counting also adds 16 no matter what
+156D: 6F              LD      L,A                 ; To coordinate
+156E: C9              RET                         ; Done
+
+FindColumn:
+; H contains a Xr coordinate. Find the column number within the rack that corresponds
+; to the Xr coordinate. Return the column coordinate in H and the column number in C.
+;
+156F: 3A 0A 20        LD      A,(refAlienXr)      ; Reference alien Yn coordinate
+1572: CD 54 15        CALL    Cnt16s              ; Count 16s to bring Y to target Y
+1575: DE 10           SBC     A,$10               ; Subtract off extra 16
+1577: 67              LD      H,A                 ; To H
+1578: C9              RET                         ; Done
+
+1579: 3E 01           LD      A,$01               ; Mark flying ...
+157B: 32 85 20        LD      (saucerHit),A       ; ... saucer has been hit
+157E: C3 45 15        JP      $1545               ; Remove player shot
+
+GetAlienStatPtr:
+; B is row number. C is column number (starts at 1).
+; Return pointer to alien-status flag for current player.
+1581: 78              LD      A,B                 ; Hold original
+1582: 07              RLCA                        ; *2
+1583: 07              RLCA                        ; *4
+1584: 07              RLCA                        ; *8
+1585: 80              ADD     A,B                 ; *9
+1586: 80              ADD     A,B                 ; *10
+1587: 80              ADD     A,B                 ; *11
+1588: 81              ADD     A,C                 ; Add row offset to column offset
+1589: 3D              DEC     A                   ; -1
+158A: 6F              LD      L,A                 ; Set LSB of HL
+158B: 3A 67 20        LD      A,(playerDataMSB)   ; Set ...
+158E: 67              LD      H,A                 ; ... MSB of HL with active player indicator
+158F: C9              RET                         
+
+WrapRef:
+; This is called if the reference point is greater than the target point. I believe the goal is to
+; wrap the reference back around until it is lower than the target point. But the algorithm simply adds
+; until the sign bit of the the reference is 0. If the target is 2 and the reference is 238 then this
+; algorithm moves the reference 238+16=244 then 244+16=4. Then the algorithm stops. But the reference is
+; STILL greater than the target.
+;
+; Also imagine that the target is 20 and the reference is 40. The algorithm adds 40+16=56, which is not
+; negative, so it stops there.
+;
+; I think the intended code is "JP NC" instead of "JP M", but even that doesn't make sense.
+;
+1590: 0C              INC     C                   ; Increase 16s count
+1591: C6 10           ADD     A,$10               ; Add 16 to ref
+1593: FA 90 15        JP      M,WrapRef           ; Keep going till result is positive
+1596: C9              RET                         ; Out
+
+RackBump:
+; When rack bumps the edge of the screen then the direction flips and the rack
+; drops 8 pixels. The deltaX and deltaY values are changed here. Interestingly
+; if there is only one alien left then the right value is 3 instead of the
+; usual 2. The left direction is always -2.
+1597: 3A 0D 20        LD      A,(rackDirection)   ; Get rack direction
+159A: A7              AND     A                   ; Moving right?
+159B: C2 B7 15        JP      NZ,$15B7            ; No ... handle moving left
+;
+159E: 21 A4 3E        LD      HL,$3EA4            ; Line down the right edge of playfield
+15A1: CD C5 15        CALL    $15C5               ; Check line down the edge
+15A4: D0              RET     NC                  ; Nothing is there ... return
+15A5: 06 FE           LD      B,$FE               ; Delta X of -2
+15A7: 3E 01           LD      A,$01               ; Rack now moving right
+;
+15A9: 32 0D 20        LD      (rackDirection),A   ; Set new rack direction
+15AC: 78              LD      A,B                 ; B has delta X
+15AD: 32 08 20        LD      (refAlienDXr),A     ; Set new delta X
+15B0: 3A 0E 20        LD      A,(rackDownDelta)   ; Set delta Y ...
+15B3: 32 07 20        LD      (refAlienDYr),A     ; ... to drop rack by 8
+15B6: C9              RET                         ; Done
+;
+15B7: 21 24 25        LD      HL,$2524            ; Line down the left edge of playfield
+15BA: CD C5 15        CALL    $15C5               ; Check line down the edge
+15BD: D0              RET     NC                  ; Nothing is there ... return
+15BE: CD F1 18        CALL    $18F1               ; Get moving-right delta X value of 2 (3 if just one alien left)
+15C1: AF              XOR     A                   ; Rack now moving left
+15C2: C3 A9 15        JP      $15A9               ; Set rack direction
+;
+15C5: 06 17           LD      B,$17               ; Checking 23 bytes in a line up the screen from near the bottom
+15C7: 7E              LD      A,(HL)              ; Get screen memory
+15C8: A7              AND     A                   ; Is screen memory empty?
+15C9: C2 6B 16        JP      NZ,$166B            ; No ... set carry flag and out
+15CC: 23              INC     HL                  ; Next byte on screen
+15CD: 05              DEC     B                   ; All column done?
+15CE: C2 C7 15        JP      NZ,$15C7            ; No ... keep looking
+15D1: C9              RET                         ; Return with carry flag clear
+
+15D2: 00              NOP                         ; ** Why? Something optimized?
+    
+DrawSprite:
+; Draw sprite at [DE] to screen at pixel position in HL
+; The hardware shift register is used in converting pixel positions
+; to screen coordinates.
+15D3: CD 74 14        CALL    CnvtPixNumber       ; Convert pixel number to screen/shift
+15D6: E5              PUSH    HL                  ; Preserve screen coordinate
+15D7: C5              PUSH    BC                  ; Hold for a second
+15D8: E5              PUSH    HL                  ; Hold for a second
+15D9: 1A              LD      A,(DE)              ; From sprite data
+15DA: D3 04           OUT     (SHFT_DATA),A       ; Write data to shift register
+15DC: DB 03           IN      A,(SHFT_IN)         ; Read back shifted amount
+15DE: 77              LD      (HL),A              ; Shifted sprite to screen
+15DF: 23              INC     HL                  ; Adjacent cell
+15E0: 13              INC     DE                  ; Next in sprite data
+15E1: AF              XOR     A                   ; 0
+15E2: D3 04           OUT     (SHFT_DATA),A       ; Write 0 to shift register
+15E4: DB 03           IN      A,(SHFT_IN)         ; Read back remainder of previous
+15E6: 77              LD      (HL),A              ; Write remainder to adjacent
+15E7: E1              POP     HL                  ; Old screen coordinate
+15E8: 01 20 00        LD      BC,$0020            ; Offset screen ...
+15EB: 09              ADD     HL,BC               ; ... to next row
+15EC: C1              POP     BC                  ; Restore count
+15ED: 05              DEC     B                   ; All done?
+15EE: C2 D7 15        JP      NZ,$15D7            ; No ... do all
+15F1: E1              POP     HL                  ; Restore HL
+15F2: C9              RET                         ; Done
+
+CountAliens:
+; Count number of aliens remaining in active game and return count 2082 holds the current count.
+; If only 1, 206B gets a flag of 1 ** but ever nobody checks this
+15F3: CD 11 16        CALL    GetPlayerDataPtr    ; Get active player descriptor
+15F6: 01 00 37        LD      BC,$3700            ; B=55 aliens to check?
+15F9: 7E              LD      A,(HL)              ; Get byte
+15FA: A7              AND     A                   ; Is it a zero?
+15FB: CA FF 15        JP      Z,$15FF             ; Yes ... don't count it
+15FE: 0C              INC     C                   ; Count the live aliens
+15FF: 23              INC     HL                  ; Next alien
+1600: 05              DEC     B                   ; Count ...
+1601: C2 F9 15        JP      NZ,$15F9            ; ... all alien indicators
+1604: 79              LD      A,C                 ; Get the count
+1605: 32 82 20        LD      (numAliens),A       ; Hold it
+1608: FE 01           CP      $01                 ; Just one?
+160A: C0              RET     NZ                  ; No keep going
+160B: 21 6B 20        LD      HL,$206B            ; Set flag if ...
+160E: 36 01           LD      (HL),$01            ; ... only one alien left
+1610: C9              RET                         ; Out
+
+GetPlayerDataPtr:
+; Set HL with 2100 if player 1 is active or 2200 if player 2 is active
+;
+1611: 2E 00           LD      L,$00               ; Byte boundary
+1613: 3A 67 20        LD      A,(playerDataMSB)   ; Active player number
+1616: 67              LD      H,A                 ; Set HL to data
+1617: C9              RET                         ; Done
+
+PlrFireOrDemo:
+; Initiate player fire if button is pressed.
+; Demo commands are parsed here if in demo mode
+1618: 3A 15 20        LD      A,(playerAlive)     ; Is there an active player?
+161B: FE FF           CP      $FF                 ; FF = alive
+161D: C0              RET     NZ                  ; Player has been shot - no firing
+161E: 21 10 20        LD      HL,$2010            ; Get player ...
+1621: 7E              LD      A,(HL)              ; ... task ...
+1622: 23              INC     HL                  ; ... timer ...
+1623: 46              LD      B,(HL)              ; ... value
+1624: B0              OR      B                   ; Is the timer 0 (object active)?
+1625: C0              RET     NZ                  ; No ... no firing till player object starts
+1626: 3A 25 20        LD      A,(plyrShotStatus)  ; Does the player have ...
+1629: A7              AND     A                   ; ... a shot on the screen?
+162A: C0              RET     NZ                  ; Yes ... ignore
+162B: 3A EF 20        LD      A,(gameMode)        ; Are we in ...
+162E: A7              AND     A                   ; ... game mode?
+162F: CA 52 16        JP      Z,$1652             ; No ... in demo mode ... constant firing in demo
+1632: 3A 2D 20        LD      A,(fireBounce)      ; Is fire button ...
+1635: A7              AND     A                   ; ... being held down?
+1636: C2 48 16        JP      NZ,$1648            ; Yes ... wait for bounce
+1639: CD C0 17        CALL    ReadInputs          ; Read active player controls
+163C: E6 10           AND     $10                 ; Fire-button pressed?
+163E: C8              RET     Z                   ; No ... out
+163F: 3E 01           LD      A,$01               ; Flag
+1641: 32 25 20        LD      (plyrShotStatus),A  ; Flag shot active
+1644: 32 2D 20        LD      (fireBounce),A      ; Flag that fire button is down
+1647: C9              RET                         ; Out
+1648: CD C0 17        CALL    ReadInputs          ; Read active player controls
+164B: E6 10           AND     $10                 ; Fire-button pressed?
+164D: C0              RET     NZ                  ; Yes ... ignore
+164E: 32 2D 20        LD      (fireBounce),A      ; Else ... clear flag
+1651: C9              RET                         ; Out
+; Handle demo (constant fire, parse demo commands)
+1652: 21 25 20        LD      HL,$2025            ; Demo fires ...
+1655: 36 01           LD      (HL),$01            ; ... constantly
+1657: 2A ED 20        LD      HL,(demoCmdPtrLSB)  ; Demo command bufer
+165A: 23              INC     HL                  ; Next position
+165B: 7D              LD      A,L                 ; Command buffer ...
+165C: FE 7E           CP      $7E                 ; ... wraps around
+165E: DA 63 16        JP      C,$1663             ; ... Buffer from 1F74 to 1F7E
+1661: 2E 74           LD      L,$74               ; ... overflow
+1663: 22 ED 20        LD      (demoCmdPtrLSB),HL  ; Next demo command
+1666: 7E              LD      A,(HL)              ; Get next command
+1667: 32 1D 20        LD      (nextDemoCmd),A     ; Set command for movement
+166A: C9              RET                         ; Done
+
+166B: 37              SCF                         ; Set carry flag
+166C: C9              RET                         ; Done
+
+166D: AF              XOR     A                   ; 0
+166E: CD 8B 1A        CALL    $1A8B               ; Print ZERO ships remain
+1671: CD 10 19        CALL    CurPlyAlive         ; Get active-flag ptr for current player
+1674: 36 00           LD      (HL),$00            ; Flag player is dead
+1676: CD CA 09        CALL    $09CA               ; Get score descriptor for current player
+1679: 23              INC     HL                  ; Point to high two digits
+167A: 11 F5 20        LD      DE,$20F5            ; Current high score upper two digits
+167D: 1A              LD      A,(DE)              ; Is player score greater ...
+167E: BE              CP      (HL)                ; ... than high score?
+167F: 1B              DEC     DE                  ; Point to LSB
+1680: 2B              DEC     HL                  ; Point to LSB
+1681: 1A              LD      A,(DE)              ; Go ahead and fetch high score lower two digits
+1682: CA 8B 16        JP      Z,$168B             ; Upper two are the same ... have to check lower two
+1685: D2 98 16        JP      NC,$1698            ; Player score is lower than high ... nothing to do
+1688: C3 8F 16        JP      $168F               ; Player socre is higher ... go copy the new high score
+;
+168B: BE              CP      (HL)                ; Is lower digit higher? (upper was the same)
+168C: D2 98 16        JP      NC,$1698            ; No ... high score is still greater than player's score
+168F: 7E              LD      A,(HL)              ; Copy the new ...
+1690: 12              LD      (DE),A              ; ... high score lower two digits
+1691: 13              INC     DE                  ; Point to MSB
+1692: 23              INC     HL                  ; Point to MSB
+1693: 7E              LD      A,(HL)              ; Copy the new ...
+1694: 12              LD      (DE),A              ; ... high score upper two digits
+1695: CD 50 19        CALL    PrintHiScore        ; Draw the new high score
+1698: 3A CE 20        LD      A,(twoPlayers)      ; Number of players
+169B: A7              AND     A                   ; Is this a single player game?
+169C: CA C9 16        JP      Z,$16C9             ; Yes ... short message
+169F: 21 03 28        LD      HL,$2803            ; Screen coordinates
+16A2: 11 A6 1A        LD      DE,$1AA6            ; "GAME OVER PLAYER< >"
+16A5: 0E 14           LD      C,$14               ; 20 characters
+16A7: CD 93 0A        CALL    PrintMessageDel     ; Print message
+16AA: 25              DEC     H                   ; Back up ...
+16AB: 25              DEC     H                   ; ... to player indicator
+16AC: 06 1B           LD      B,$1B               ; "1"
+16AE: 3A 67 20        LD      A,(playerDataMSB)   ; Player number
+16B1: 0F              RRCA                        ; Is this player 1?
+16B2: DA B7 16        JP      C,$16B7             ; Yes ... keep the digit
+16B5: 06 1C           LD      B,$1C               ; Else ... set digit 2
+16B7: 78              LD      A,B                 ; To A
+16B8: CD FF 08        CALL    DrawChar            ; Print player number
+16BB: CD B1 0A        CALL    OneSecDelay         ; Short delay
+16BE: CD E7 18        CALL    $18E7               ; Get current player "alive" flag
+16C1: 7E              LD      A,(HL)              ; Is player ...
+16C2: A7              AND     A                   ; ... alive?
+16C3: CA C9 16        JP      Z,$16C9             ; No ... skip to "GAME OVER" sequence
+16C6: C3 ED 02        JP      $02ED               ; Switch players and game loop
+;
+16C9: 21 18 2D        LD      HL,$2D18            ; Screen coordinates
+16CC: 11 A6 1A        LD      DE,$1AA6            ; "GAME OVER PLAYER< >"
+16CF: 0E 0A           LD      C,$0A               ; Just the "GAME OVER" part
+16D1: CD 93 0A        CALL    PrintMessageDel     ; Print message
+16D4: CD B6 0A        CALL    TwoSecDelay         ; Long delay
+16D7: CD D6 09        CALL    ClearPlayField      ; Clear center window
+16DA: AF              XOR     A                   ; Now in ...
+16DB: 32 EF 20        LD      (gameMode),A        ; ... demo mode
+16DE: D3 05           OUT     (SOUND2),A          ; All sound off
+16E0: CD D1 19        CALL    EnableGameTasks     ; Enable ISR game tasks
+16E3: C3 89 0B        JP      $0B89               ; Print credit information and do splash
+
+16E6: 31 00 24        LD      SP,$2400            ; Reset stack
+16E9: FB              EI                          ; Enable interrupts
+16EA: AF              XOR     A                   ; Flag ...
+16EB: 32 15 20        LD      (playerAlive),A     ; ... player is shot
+16EE: CD D8 14        CALL    PlayerShotHit       ; Player's shot collision detection
+16F1: 06 04           LD      B,$04               ; Player has been hit ...
+16F3: CD FA 18        CALL    SoundBits3On        ; ... sound
+16F6: CD 59 0A        CALL    $0A59               ; Has flag been set?
+16F9: C2 EE 16        JP      NZ,$16EE            ; No ... wait for the flag
+16FC: CD D7 19        CALL    DsableGameTasks     ; Disable ISR game tasks
+16FF: 21 01 27        LD      HL,$2701            ; Player's stash of ships
+1702: CD FA 19        CALL    $19FA               ; Erase the stash of shps
+1705: AF              XOR     A                   ; Print ...
+1706: CD 8B 1A        CALL    $1A8B               ; ... a zero (number of ships)
+
+1709: 06 FB           LD      B,$FB               ; Turn off ...
+170B: C3 6B 19        JP      $196B               ; ... player shot sound
+
+AShotReloadRate:
+; Use the player's MSB to determine how fast the aliens reload their
+; shots for another fire.
+170E: CD CA 09        CALL    $09CA               ; Get score descriptor for active player
+1711: 23              INC     HL                  ; MSB value
+1712: 7E              LD      A,(HL)              ; Get the MSB value
+1713: 11 B8 1C        LD      DE,$1CB8            ; Score MSB table
+1716: 21 A1 1A        LD      HL,$1AA1            ; Corresponding fire reload rate table
+1719: 0E 04           LD      C,$04               ; Only 4 entries (a 5th value of 7 is used after that)
+171B: 47              LD      B,A                 ; Hold the score value
+171C: 1A              LD      A,(DE)              ; Get lookup from table
+171D: B8              CP      B                   ; Compare them
+171E: D2 27 17        JP      NC,$1727            ; Equal or below ... use this table entry
+1721: 23              INC     HL                  ; Next ...
+1722: 13              INC     DE                  ; ... entry in table
+1723: 0D              DEC     C                   ; Do all ...
+1724: C2 1C 17        JP      NZ,$171C            ; ... 4 entries in the tables
+1727: 7E              LD      A,(HL)              ; Load the shot reload value
+1728: 32 CF 20        LD      (aShotReloadRate),A ; Save the value for use in shot routine
+172B: C9              RET                         ; Done
+
+; Shot sound on or off depending on 2025
+ShotSound:
+172C: 3A 25 20        LD      A,(plyrShotStatus)  ; Player shot flag
+172F: FE 00           CP      $00                 ; Active shot?
+1731: C2 39 17        JP      NZ,$1739            ; Yes ... go
+1734: 06 FD           LD      B,$FD               ; Sound mask
+1736: C3 DC 19        JP      SoundBits3Off       ; Mask off sound
+;
+1739: 06 02           LD      B,$02               ; Sound bit
+173B: C3 FA 18        JP      SoundBits3On        ; OR on sound
+
+173E: 00 00 ; ** Why?
+
+TimeFleetSound:
+; This called from the ISR times down the fleet and sets the flag at 2095 if
+; the fleet needs a change in sound handling (new delay, new sound)
+1740: 21 9B 20        LD      HL,$209B            ; Pointer to hold time for fleet
+1743: 35              DEC     (HL)                ; Decrement hold time
+1744: CC 6D 17        CALL    Z,$176D             ; If 0 turn fleet movement sound off
+1747: 3A 68 20        LD      A,(playerOK)        ; Is player OK?
+174A: A7              AND     A                   ; 1  means OK
+174B: CA 6D 17        JP      Z,$176D             ; Player not OK ... fleet movement sound off and out
+174E: 21 96 20        LD      HL,$2096            ; Current time on fleet sound
+1751: 35              DEC     (HL)                ; Count down
+1752: C0              RET     NZ                  ; Not time to change sound ... out
+1753: 21 98 20        LD      HL,$2098            ; Current sound port 3 value
+1756: 7E              LD      A,(HL)              ; Get value
+1757: D3 05           OUT     (SOUND2),A          ; Set sounds
+1759: 3A 82 20        LD      A,(numAliens)       ; Number of aliens on active screen
+175C: A7              AND     A                   ; Is it zero?
+175D: CA 6D 17        JP      Z,$176D             ; Yes ... turn off fleet movement sound and out
+1760: 2B              DEC     HL                  ; (2097) Point to fleet timer reload
+1761: 7E              LD      A,(HL)              ; Get fleet delay value
+1762: 2B              DEC     HL                  ; (2096) Point to fleet timer
+1763: 77              LD      (HL),A              ; Reload the timer
+1764: 2B              DEC     HL                  ; Point to change-sound
+1765: 36 01           LD      (HL),$01            ; (2095) time to change sound
+1767: 3E 04           LD      A,$04               ; Set hold ...
+1769: 32 9B 20        LD      (fleetSndHold),A    ; ... time for fleet sound
+176C: C9              RET                         ; Done
+
+176D: 3A 98 20        LD      A,(soundPort5)      ; Current sound port 3 value
+1770: E6 30           AND     $30                 ; Mask off fleet movement sounds
+1772: D3 05           OUT     (SOUND2),A          ; Set sounds
+1774: C9              RET                         ; Out
+
+FleetDelayExShip:
+; This game-loop routine handles two sound functions. The routine does:
+; 1) Time out the extra-ship awarded sound and turn it off when done
+; 2) Load the fleet sound delay based on number of remaining aliens
+; 3) Make the changing fleet sound
+;
+; The 2095 flag is set by the ISR and cleared here. The ISR does the timing and sets 2095 when it
+; is time to make a new fleet sound.
+;
+1775: 3A 95 20        LD      A,(changeFleetSnd)  ; Time for new ...
+1778: A7              AND     A                   ; ... fleet movement sound?
+1779: CA AA 17        JP      Z,$17AA             ; No ... skip to extra-man timing
+177C: 21 11 1A        LD      HL,$1A11            ; Number of aliens list coupled ...
+177F: 11 21 1A        LD      DE,$1A21            ; ... with delay list
+1782: 3A 82 20        LD      A,(numAliens)       ; Get the number of aliens on the screen
+1785: BE              CP      (HL)                ; Compare it to the first list value
+1786: D2 8E 17        JP      NC,$178E            ; Number of live aliens is higher than value ... use the delay
+1789: 23              INC     HL                  ; Move to ...
+178A: 13              INC     DE                  ; ... next list value
+178B: C3 85 17        JP      $1785               ; Find the right delay
+178E: 1A              LD      A,(DE)              ; Get the delay from the second list
+178F: 32 97 20        LD      (fleetSndReload),A  ; Store the new alien sound delay
+1792: 21 98 20        LD      HL,$2098            ; Get current state ...
+1795: 7E              LD      A,(HL)              ; ... of sound port
+1796: E6 30           AND     $30                 ; Mask off all fleet movement sounds
+1798: 47              LD      B,A                 ; Hold the value
+1799: 7E              LD      A,(HL)              ; Get current state
+179A: E6 0F           AND     $0F                 ; This time ONLY the fleet movement sounds
+179C: 07              RLCA                        ; Shift next to next sound
+179D: FE 10           CP      $10                 ; Overflow?
+179F: C2 A4 17        JP      NZ,$17A4            ; No ... keep it
+17A2: 3E 01           LD      A,$01               ; Reset back to first sound
+17A4: B0              OR      B                   ; Add fleet sounds to current sound value
+17A5: 77              LD      (HL),A              ; Store new sound value
+17A6: AF              XOR     A                   ; Restart ...
+17A7: 32 95 20        LD      (changeFleetSnd),A  ; ... waiting on fleet time
+;
+17AA: 21 99 20        LD      HL,$2099            ; Sound timer for award extra ship
+17AD: 35              DEC     (HL)                ; Time expired?
+17AE: C0              RET     NZ                  ; No ... leave sound playing
+17AF: 06 EF           LD      B,$EF               ; Turn off bit set with #$10 (award extra ship)
+17B1: C3 DC 19        JP      SoundBits3Off       ; Stop sound and out
+
+SndOffExtPly:
+17B4: 06 EF           LD      B,$EF               ; Mask off sound bit 4 (Extended play)
+17B6: 21 98 20        LD      HL,$2098            ; Current sound content
+17B9: 7E              LD      A,(HL)              ; Get current sound bits
+17BA: A0              AND     B                   ; Turn off extended play
+17BB: 77              LD      (HL),A              ; Remember settings
+17BC: D3 05           OUT     (SOUND2),A          ; Turn off extended play
+17BE: C9              RET                         ; Out
+
+17BF: 00 ; ** Why?
+
+ReadInputs:
+; Read control inputs for active player
+17C0: 3A 67 20        LD      A,(playerDataMSB)   ; Get active player
+17C3: 0F              RRCA                        ; Test player
+17C4: D2 CA 17        JP      NC,$17CA            ; Player 2 ... read port 2
+17C7: DB 01           IN      A,(INP1)            ; Player 1 ... read port 1
+17C9: C9              RET                         ; Out
+17CA: DB 02           IN      A,(INP2)            ; Get controls for player 2
+17CC: C9              RET                         ; Out
+
+; Check and handle TILT
+CheckHandleTilt:
+17CD: DB 02           IN      A,(INP2)            ; Read input port
+17CF: E6 04           AND     $04                 ; Tilt?
+17D1: C8              RET     Z                   ; No tilt ... return
+17D2: 3A 9A 20        LD      A,(tilt)            ; Already in TILT handle?
+17D5: A7              AND     A                   ; 1 = yes
+17D6: C0              RET     NZ                  ; Yes ... ignore it now
+17D7: 31 00 24        LD      SP,$2400            ; Reset stack
+17DA: 06 04           LD      B,$04               ; Do this 4 times
+17DC: CD D6 09        CALL    ClearPlayField      ; Clear center window
+17DF: 05              DEC     B                   ; All done?
+17E0: C2 DC 17        JP      NZ,$17DC            ; No ... do again
+17E3: 3E 01           LD      A,$01               ; Flag ...
+17E5: 32 9A 20        LD      (tilt),A            ; ... handling TILT
+17E8: CD D7 19        CALL    DsableGameTasks     ; Disable game tasks
+17EB: FB              EI                          ; Re-enable interrupts
+17EC: 11 BC 1C        LD      DE,$1CBC            ; Message "TILT"
+17EF: 21 16 30        LD      HL,$3016            ; Center of screen
+17F2: 0E 04           LD      C,$04               ; Four letters
+17F4: CD 93 0A        CALL    PrintMessageDel     ; Print "TILT"
+17F7: CD B1 0A        CALL    OneSecDelay         ; Short delay
+17FA: AF              XOR     A                   ; Zero
+17FB: 32 9A 20        LD      (tilt),A            ; TILT handle over
+17FE: 32 93 20        LD      (waitStartLoop),A   ; Back into splash screens
+1801: C3 C9 16        JP      $16C9               ; Handle game over for player
+
+CtrlSaucerSound:
+1804: 21 84 20        LD      HL,$2084            ; Saucer on screen flag
+1807: 7E              LD      A,(HL)              ; Is the saucer ...
+1808: A7              AND     A                   ; ... on the screen?
+1809: CA 07 07        JP      Z,$0707             ; No ... UFO sound off
+180C: 23              INC     HL                  ; Saucer hit flag
+180D: 7E              LD      A,(HL)              ; (2085) Get saucer hit flag
+180E: A7              AND     A                   ; Is saucer in "hit" sequence?
+180F: C0              RET     NZ                  ; Yes ... out
+1810: 06 01           LD      B,$01               ; Retrigger saucer ...
+1812: C3 FA 18        JP      SoundBits3On        ; ... sound (retrigger makes it warble?)
+  
+DrawAdvTable:
+; Draw "SCORE ADVANCE TABLE"
+1815: 21 10 28        LD      HL,$2810            ; 0x410 is 1040 rotCol=32, rotRow=16
+1818: 11 A3 1C        LD      DE,$1CA3            ; "*SCORE ADVANCE TABLE*"
+181B: 0E 15           LD      C,$15               ; 21 bytes in message
+181D: CD F3 08        CALL    PrintMessage        ; Print message
+1820: 3E 0A           LD      A,$0A               ; 10 bytes in every "=xx POINTS" string
+1822: 32 6C 20        LD      (temp206C),A        ; Hold the count
+1825: 01 BE 1D        LD      BC,$1DBE            ; Coordinate/sprite for drawing table
+1828: CD 56 18        CALL    ReadPriStruct       ; Get HL=coordinate, DE=image
+182B: DA 37 18        JP      C,$1837             ; Move on if done
+182E: CD 44 18        CALL    $1844               ; Draw 16-byte sprite
+1831: C3 28 18        JP      $1828               ; Do all in table
+;
+1834: CD B1 0A        CALL    OneSecDelay         ; One second delay
+1837: 01 CF 1D        LD      BC,$1DCF            ; Coordinate/message for drawing table
+183A: CD 56 18        CALL    ReadPriStruct       ; Get HL=coordinate, DE=message
+183D: D8              RET     C                   ; Out if done
+183E: CD 4C 18        CALL    $184C               ; Print message
+1841: C3 3A 18        JP      $183A               ; Do all in table
+;
+1844: C5              PUSH    BC                  ; Hold BC
+1845: 06 10           LD      B,$10               ; 16 bytes
+1847: CD 39 14        CALL    DrawSimpSprite      ; Draw simple
+184A: C1              POP     BC                  ; Restore BC
+184B: C9              RET                         ; Out
+;
+184C: C5              PUSH    BC                  ; Hold BC
+184D: 3A 6C 20        LD      A,(temp206C)        ; Count of 10 ...
+1850: 4F              LD      C,A                 ; ... to C
+1851: CD 93 0A        CALL    PrintMessageDel     ; Print the message with delay between letters
+1854: C1              POP     BC                  ; Restore BC
+1855: C9              RET                         ; Out
+
+ReadPriStruct:
+; Read a 4-byte print-structure pointed to by BC
+; HL=Screen coordiante, DE=pointer to message
+; If the first byte is FF then return with Carry Set, Carry Cleared otherwise.
+1856: 0A              LD      A,(BC)              ; Get the screen LSB
+1857: FE FF           CP      $FF                 ; Valid?
+1859: 37              SCF                         ; If not Carry will be Set
+185A: C8              RET     Z                   ; Return if 255
+185B: 6F              LD      L,A                 ; Screen LSB to L
+185C: 03              INC     BC                  ; Next
+185D: 0A              LD      A,(BC)              ; Read screen MSB
+185E: 67              LD      H,A                 ; Screen MSB to H
+185F: 03              INC     BC                  ; Next
+1860: 0A              LD      A,(BC)              ; Read message LSB
+1861: 5F              LD      E,A                 ; Message LSB to E
+1862: 03              INC     BC                  ; Next
+1863: 0A              LD      A,(BC)              ; Read message MSB
+1864: 57              LD      D,A                 ; Message MSB to D
+1865: 03              INC     BC                  ; Next (for next print)
+1866: A7              AND     A                   ; Clear Carry
+1867: C9              RET                         ; Done
+
+SplashSprite:
+; Moves a sprite up or down in splash mode. Interrupt moves the sprite. When it reaches
+; Y value in 20CA the flag at 20CB is raised. The image flips between two pictures every
+; 4 movements.
+
+1868: 21 C2 20        LD      HL,$20C2            ; Descriptor
+186B: 34              INC     (HL)                ; Change image
+186C: 23              INC     HL                  ; Point to delta-x
+186D: 4E              LD      C,(HL)              ; Get delta-x
+186E: CD D9 01        CALL    AddDelta            ; Add delta-X and delta-Y to X and Y
+1871: 47              LD      B,A                 ; Current y coordinate
+1872: 3A CA 20        LD      A,(splashTargetY)   ; Has sprite reached ...
+1875: B8              CP      B                   ; ... target coordinate?
+1876: CA 98 18        JP      Z,$1898             ; Yes ... flag and out
+1879: 3A C2 20        LD      A,(splashAnForm)    ; Image number
+187C: E6 04           AND     $04                 ; Watching bit 3 for flip delay
+187E: 2A CC 20        LD      HL,(splashImRestLSB); Image
+1881: C2 88 18        JP      NZ,$1888            ; Did bit 3 go to 0? No ... keep current image
+1884: 11 30 00        LD      DE,$0030            ; 16*3 ...
+1887: 19              ADD     HL,DE               ; ...  use other image form
+1888: 22 C7 20        LD      (splashImageLSB),HL ; Image to descriptor structure
+188B: 21 C5 20        LD      HL,$20C5            ; X,Y,Image descriptor
+188E: CD 3B 1A        CALL    ReadDesc            ; Read sprite descriptor
+1891: EB              EX      DE,HL               ; Image to DE, position to HL
+1892: C3 D3 15        JP      DrawSprite          ; Draw the sprite
+
+1895: 00 00 00                          
+
+1898: 3E 01           LD      A,$01               ; Flag that sprite ...
+189A: 32 CB 20        LD      (splashReached),A   ; ... reached location
+189D: C9              RET                         ; Out
+
+;Animate alien shot to extra "C" in splash
+189E: 21 50 20        LD      HL,$2050            ; Task descriptor for game object 4 (squiggly shot)
+18A1: 11 C0 1B        LD      DE,$1BC0            ; Task info for animate-shot-to-extra-C
+18A4: 06 10           LD      B,$10               ; Block copy ...
+18A6: CD 32 1A        CALL    BlockCopy           ; ... 16 bytes
+18A9: 3E 02           LD      A,$02               ; Set shot sync ...
+18AB: 32 80 20        LD      (shotSync),A        ; ... to run the squiggly shot
+18AE: 3E FF           LD      A,$FF               ; Shot direction (-1)
+18B0: 32 7E 20        LD      (alienShotDelta),A  ; Alien shot delta
+18B3: 3E 04           LD      A,$04               ; Animate ...
+18B5: 32 C1 20        LD      (isrSplashTask),A   ; ... shot
+18B8: 3A 55 20        LD      A,(squShotStatus)   ; Has shot ...
+18BB: E6 01           AND     $01                 ; ... collided?
+18BD: CA B8 18        JP      Z,$18B8             ; No ... keep waiting
+18C0: 3A 55 20        LD      A,(squShotStatus)   ; Wait ...
+18C3: E6 01           AND     $01                 ; ... for explosion ...
+18C5: C2 C0 18        JP      NZ,$18C0            ; ... to finish
+18C8: 21 11 33        LD      HL,$3311            ; Here is where the extra C is
+18CB: 3E 26           LD      A,$26               ; Space character
+18CD: 00              NOP                         ; ** Why?
+18CE: CD FF 08        CALL    DrawChar            ; Draw character
+18D1: C3 B6 0A        JP      TwoSecDelay         ; Two second delay and out
+
+; Initializiation comes here
+;
+init:
+18D4: 31 00 24        LD      SP,$2400            ; Set stack pointer just below screen
+18D7: 06 00           LD      B,$00               ; Count 256 bytes
+18D9: CD E6 01        CALL    $01E6               ; Copy ROM to RAM
+18DC: CD 56 19        CALL    DrawStatus          ; Print scores and credits
+;
+18DF: 3E 08           LD      A,$08               ; Set alien ...
+18E1: 32 CF 20        LD      (aShotReloadRate),A ; ... shot reload rate
+18E4: C3 EA 0A        JP      $0AEA               ; Top of splash screen loop
+
+; Get player-alive flag for OTHER player
+18E7: 3A 67 20        LD      A,(playerDataMSB)   ; Player data MSB
+18EA: 21 E7 20        LD      HL,$20E7            ; Alive flags (player 1 and 2)
+18ED: 0F              RRCA                        ; Bit 1=1 for player 1
+18EE: D0              RET     NC                  ; Player 2 ... we have it ... out
+18EF: 23              INC     HL                  ; Player 1's flag
+18F0: C9              RET                         ; Done
+
+; If there is one alien left then the right motion is 3 instead of 2. That's
+; why the timing is hard to hit after the change.
+18F1: 06 02           LD      B,$02               ; Rack moving right delta X
+18F3: 3A 82 20        LD      A,(numAliens)       ; Number of aliens on screen
+18F6: 3D              DEC     A                   ; Just one left?
+18F7: C0              RET     NZ                  ; No ... use right delta X of 2
+18F8: 04              INC     B                   ; Just one alien ... move right at 3 instead of 2
+18F9: C9              RET                         ; Done
+
+SoundBits3On:
+; Add in bit for sound
+18FA: 3A 94 20        LD      A,(soundPort3)      ; Current value of sound port
+18FD: B0              OR      B                   ; Add in new sounds
+18FE: 32 94 20        LD      (soundPort3),A      ; New value of sound port
+1901: D3 03           OUT     (SOUND1),A          ; Write new value to sound hardware
+1903: C9              RET                         
+
+InitAliensP2:
+1904: 21 00 22        LD      HL,$2200            ; Player 2 data area
+1907: C3 C3 01        JP      $01C3               ; Initialize player 2 aliens
+
+PlyrShotAndBump:
+190A: CD D8 14        CALL    PlayerShotHit       ; Player's shot collision detection
+190D: C3 97 15        JP      RackBump            ; Change alien deltaX and deltaY when rack bumps edges
+
+CurPlyAlive:
+; Get the current player's alive status
+1910: 21 E7 20        LD      HL,$20E7            ; Alive flags
+1913: 3A 67 20        LD      A,(playerDataMSB)   ; Player 1 or 2
+1916: 0F              RRCA                        ; Will be 1 if player 1
+1917: D8              RET     C                   ; Return if player 1
+1918: 23              INC     HL                  ; Bump to player 2
+1919: C9              RET                         ; Return
+
+DrawScoreHead:
+; Print score header " SCORE<1> HI-SCORE SCORE<2> "
+191A: 0E 1C           LD      C,$1C               ; 28 bytes in message
+191C: 21 1E 24        LD      HL,$241E            ; Screen coordinates
+191F: 11 E4 1A        LD      DE,$1AE4            ; Score header message
+1922: C3 F3 08        JP      PrintMessage        ; Print score header
+
+1925: 21 F8 20        LD      HL,$20F8            ; Player 1 score descriptor
+1928: C3 31 19        JP      DrawScore           ; Print score
+
+192B: 21 FC 20        LD      HL,$20FC            ; Player 2 score descriptor
+192E: C3 31 19        JP      DrawScore           ; Print score
+
+DrawScore:
+; Print score.
+; HL = descriptor
+1931: 5E              LD      E,(HL)              ; Get score LSB
+1932: 23              INC     HL                  ; Next
+1933: 56              LD      D,(HL)              ; Get score MSB
+1934: 23              INC     HL                  ; Next
+1935: 7E              LD      A,(HL)              ; Get coordinate LSB
+1936: 23              INC     HL                  ; Next
+1937: 66              LD      H,(HL)              ; Get coordiante MSB
+1938: 6F              LD      L,A                 ; Set LSB
+1939: C3 AD 09        JP      Print4Digits        ; Print 4 digits in DE
+
+; Print message "CREDIT "
+193C: 0E 07           LD      C,$07               ; 7 bytes in message
+193E: 21 01 35        LD      HL,$3501            ; Screen coordinates
+1941: 11 A9 1F        LD      DE,$1FA9            ; Message = "CREDIT "
+1944: C3 F3 08        JP      PrintMessage        ; Print message
+
+DrawNumCredits:
+; Display number of credits on screen
+1947: 3A EB 20        LD      A,(numCoins)        ; Number of credits
+194A: 21 01 3C        LD      HL,$3C01            ; Screen coordinates
+194D: C3 B2 09        JP      DrawHexByte         ; Character to screen
+
+PrintHiScore:
+1950: 21 F4 20        LD      HL,$20F4            ; Hi Score descriptor
+1953: C3 31 19        JP      DrawScore           ; Print Hi-Score
+
+DrawStatus:
+; Print scores (with header) and credits (with label)
+1956: CD 5C 1A        CALL    ClearScreen         ; Clear the screen
+1959: CD 1A 19        CALL    DrawScoreHead       ; Print score header
+195C: CD 25 19        CALL    $1925               ; Print player 1 score
+195F: CD 2B 19        CALL    $192B               ; Print player 2 score
+1962: CD 50 19        CALL    PrintHiScore        ; Print hi score
+1965: CD 3C 19        CALL    $193C               ; Print credit lable
+1968: C3 47 19        JP      DrawNumCredits      ; Number of credits
+
+196B: CD DC 19        CALL    SoundBits3Off       ; From 170B with B=FB. Turn off player shot sound
+196E: C3 71 16        JP      $1671               ; Update high-score if player's score is greater
+
+1971: 3E 01           LD      A,$01               ; Set flag that ...
+1973: 32 6D 20        LD      (invaded),A         ; ... aliens reached bottom of screen
+1976: C3 E6 16        JP      $16E6               ; End of round
+
+1979: CD D7 19        CALL    DsableGameTasks     ; Disable ISR game tasks
+197C: CD 47 19        CALL    DrawNumCredits      ; Display number of credits on screen
+197F: C3 3C 19        JP      $193C               ; Print message "CREDIT"
+
+1982: 32 C1 20        LD      (isrSplashTask),A   ; Set ISR splash task
+1985: C9              RET                         ; Done
+
+; The original code (from TAITO) printed this message on the screen. When Midway branched the code
+; they changed the logic so it isn't printed.
+
+1986: 8B 19 ; Points to print TAITO CORPORATION message ... not sure why
+               
+1988: C3 D6 09        JP      ClearPlayField      ; Clear playfield and out
+
+; Print "*TAITO CORPORATION*"
+198B: 21 03 28        LD      HL,$2803            ; Screen coordinates
+198E: 11 BE 19        LD      DE,$19BE            ; Message "*TAITO CORPORATION*"
+1991: 0E 13           LD      C,$13               ; Messgae length
+1993: C3 F3 08        JP      PrintMessage        ; Print message
+
+; The original TAITO code:
+;1985: C3 8B 19     JP    $198B              ;
+;1988: CD D6 09     CALL  $09D6              ;
+;198B: 21 03 28     LD    HL,$2803           ;
+;198E: 11 BE 19     LD    DE,$19BE           ;
+;1991: 0E 13        LD    C,$13              ;
+;1993: C3 F3 08     JP    $08F3              ;
+
+1996: 00 00 00 00 ; ** Why?
+                         
+CheckHiddenMes:
+; There is a hidden message "TAITO COP" (with no "R") in the game. It can only be
+; displayed in the demonstration game during the splash screens. You must enter
+; 2 seqences of buttons. Timing is not critical. As long as you eventually get all
+; the buttons up/down in the correct pattern then the game will register the
+; sequence.
+;
+; 1st: 2start(down) 1start(up)   1fire(down) 1left(down) 1right(down)
+; 2nd: 2start(up)   1start(down) 1fire(down) 1left(down) 1right(up)
+;
+; Unfortunately MAME does not deliver the simultaneous button presses correctly. You can see the message in
+; MAME by changing 19A6 to 02 and 19B1 to 02. Then the 2start(down) is the only sequence.
+;
+199A: 3A 1E 20        LD      A,(hidMessSeq)      ; Has the 1st "hidden-message" sequence ...
+199D: A7              AND     A                   ; ... been registered?
+199E: C2 AC 19        JP      NZ,$19AC            ; Yes ... go look for the 2nd sequence
+19A1: DB 01           IN      A,(INP1)            ; Get player inputs
+19A3: E6 76           AND     $76                 ; 0111_0110 Keep 2Pstart, 1Pstart, 1Pshot, 1Pleft, 1Pright
+19A5: D6 72           SUB     $72                 ; 0111_0010 1st sequence: 2Pstart, 1Pshot, 1Pleft, 1Pright
+19A7: C0              RET     NZ                  ; Not first sequence ... out
+19A8: 3C              INC     A                   ; Flag that 1st sequence ...
+19A9: 32 1E 20        LD      (hidMessSeq),A      ; ... has been entered
+19AC: DB 01           IN      A,(INP1)            ; Check inputs for 2nd sequence
+19AE: E6 76           AND     $76                 ; 0111_0110 Keep 2Pstart, 1Pstart, 1Pshot, 1Pleft, 1Pright
+19B0: FE 34           CP      $34                 ; 0011_0100 2nd sequence: 1Pstart, 1Pshot, 1Pleft
+19B2: C0              RET     NZ                  ; If not second sequence ignore
+19B3: 21 1B 2E        LD      HL,$2E1B            ; Screen coordinates
+19B6: 11 F7 0B        LD      DE,$0BF7            ; Message = "TAITO COP" (no R)
+19B9: 0E 09           LD      C,$09               ; Message length
+19BB: C3 F3 08        JP      PrintMessage        ; Print message and out
+
+MessageTaito:
+; "*TAITO CORPORATION*"
+19BE: 28 13 00 08 13 0E 26 02 0E 11 0F 0E 11      
+19CB: 00 13 08 0E 0D 28
+
+EnableGameTasks:
+; Enable ISR game tasks
+19D1: 3E 01           LD      A,$01               ; Set ISR ...
+19D3: 32 E9 20        LD      (suspendPlay),A     ; ... game tasks enabled
+19D6: C9              RET                         ; Done
+
+DsableGameTasks:
+; Disable ISR game tasks
+; Clear 20E9 flag
+19D7: AF              XOR     A                   ; Clear ISR game tasks flag
+19D8: C3 D3 19        JP      $19D3               ; Save a byte (the RET)
+19DB: 00                                          ; ** Here is the byte saved. I wonder if this was an optimizer pass.
+
+SoundBits3Off:
+; Turn off bit in sound port
+19DC: 3A 94 20        LD      A,(soundPort3)      ; Current sound effects value
+19DF: A0              AND     B                   ; Mask bits off
+19E0: 32 94 20        LD      (soundPort3),A      ; Store new hold value
+19E3: D3 03           OUT     (SOUND1),A          ; Change sounds
+19E5: C9              RET                         ; Done
+
+DrawNumShips:
+; Show ships remaining in hold for the player
+19E6: 21 01 27        LD      HL,$2701            ; Screen coordinates
+19E9: CA FA 19        JP      Z,$19FA             ; None in reserve ... skip display
+; Draw line of ships
+19EC: 11 60 1C        LD      DE,$1C60            ; Player sprite
+19EF: 06 10           LD      B,$10               ; 16 rows
+19F1: 4F              LD      C,A                 ; Hold count
+19F2: CD 39 14        CALL    DrawSimpSprite      ; Display 1byte sprite to screen
+19F5: 79              LD      A,C                 ; Restore remaining
+19F6: 3D              DEC     A                   ; All done?
+19F7: C2 EC 19        JP      NZ,$19EC            ; No ... keep going
+; Clear remainder of line
+19FA: 06 10           LD      B,$10               ; 16 rows
+19FC: CD CB 14        CALL    ClearSmallSprite    ; Clear 1byte sprite at HL
+19FF: 7C              LD      A,H                 ; Get Y coordinate
+1A00: FE 35           CP      $35                 ; At edge?
+1A02: C2 FA 19        JP      NZ,$19FA            ; No ... do all
+1A05: C9              RET                         ; Out
+
+CompYToBeam:
+;
+; The ISRs set the upper bit of 2072 based on where the beam is. This is compared to the
+; upper bit of an object's Y coordinate to decide whic ISR should handle it. When the
+; beam passes the halfway point (or near it ... at scanline 96), the upper bit is cleared.
+; When the beam reaches the end of the screen the upper bit is set.
+;
+; The task then runs in the ISR if the Y coordiante bit matches the 2072 flag. Objects that
+; are at the top of the screen (upper bit of Y clear) run in the mid-screen ISR when
+; the beam has moved to the bottom of the screen. Objects that are at the bottom of the screen
+; (upper bit of Y set) run in the end-screen ISR when the beam is moving back to the top.
+;
+; The pointer to the object's Y coordinate is passed in DE. CF is set if the upper bits are
+; the same (the calling ISR should execute the task).
+;
+1A06: 21 72 20        LD      HL,$2072            ; Get the ...
+1A09: 46              LD      B,(HL)              ; ... beam position status
+1A0A: 1A              LD      A,(DE)              ; Get the task structure flag
+1A0B: E6 80           AND     $80                 ; Only upper bits count
+1A0D: A8              XOR     B                   ; XOR them together
+1A0E: C0              RET     NZ                  ; Not the same (CF cleared)
+1A0F: 37              SCF                         ; Set the CF if the same
+1A10: C9              RET                         ; Done
+
+; Alien delay lists. First list is the number of aliens. The second list is the corresponding delay.
+; This delay is only for the rate of change in the fleet's sound.
+; The check takes the first num-aliens-value that is lower or the same as the actual num-aliens on screen.
+;
+; The game starts with 55 aliens. The aliens are move/drawn one per interrupt which means it
+; takes 55 interrupts. The first delay value is 52 ... which is almost in sync with the number
+; of aliens. It is a tad faster and you can observe the sound and steps getting out of sync.
+;
+1A11: 32 2B 24 1C 16 11 0D 0A 08 07 06 05 04 03 02 01
+1A21: 34 2E 27 22 1C 18 15 13 10 0E 0D 0C 0B 09 07 05     
+1A31: FF   ; ** Needless terminator. The list value "1" catches everything.
+
+BlockCopy:
+; Copy from [DE] to [HL] (b bytes)
+1A32: 1A              LD      A,(DE)              ; Copy from [DE] to ...
+1A33: 77              LD      (HL),A              ; ... [HL]
+1A34: 23              INC     HL                  ; Next destination
+1A35: 13              INC     DE                  ; Next source
+1A36: 05              DEC     B                   ; Count in B
+1A37: C2 32 1A        JP      NZ,BlockCopy        ; Do all
+1A3A: C9              RET                         ; Done
+
+ReadDesc:
+; Load 5 bytes sprite descriptor from [HL]
+1A3B: 5E              LD      E,(HL)              ; Descriptor ...
+1A3C: 23              INC     HL                  ; ... sprite ...
+1A3D: 56              LD      D,(HL)              ; ...
+1A3E: 23              INC     HL                  ; ... picture
+1A3F: 7E              LD      A,(HL)              ; Descriptor ...
+1A40: 23              INC     HL                  ; ... screen ...
+1A41: 4E              LD      C,(HL)              ; ...
+1A42: 23              INC     HL                  ; ... location
+1A43: 46              LD      B,(HL)              ; Number of bytes in sprite
+1A44: 61              LD      H,C                 ; From A,C to ...
+1A45: 6F              LD      L,A                 ; ... H,L
+1A46: C9              RET                         ; Done
+
+ConvToScr:
+; The screen is organized as one-bit-per-pixel.
+; In: HL contains pixel number (bbbbbbbbbbbbbppp)
+; Convert from pixel number to screen coordinates (without shift)
+; Shift HL right 3 bits (clearing the top 2 bits)
+; and set the third bit from the left.
+1A47: C5              PUSH    BC                  ; Hold B (will mangle)
+1A48: 06 03           LD      B,$03               ; 3 shifts (divide by 8)
+1A4A: 7C              LD      A,H                 ; H to A
+1A4B: 1F              RRA                         ; Shift right (into carry, from doesn't matter)
+1A4C: 67              LD      H,A                 ; Back to H
+1A4D: 7D              LD      A,L                 ; L to A
+1A4E: 1F              RRA                         ; Shift right (from/to carry)
+1A4F: 6F              LD      L,A                 ; Back to L
+1A50: 05              DEC     B                   ; Do all ...
+1A51: C2 4A 1A        JP      NZ,$1A4A            ; ... 3 shifts
+1A54: 7C              LD      A,H                 ; H to A
+1A55: E6 3F           AND     $3F                 ; Mask off all but screen (less than or equal 3F)
+1A57: F6 20           OR      $20                 ; Offset into RAM
+1A59: 67              LD      H,A                 ; Back to H
+1A5A: C1              POP     BC                  ; Restore B
+1A5B: C9              RET                         ; Done
+
+ClearScreen:
+; Clear the screen
+; Thanks to Mark Tankard for pointing out what this really does
+1A5C: 21 00 24        LD      HL,$2400            ; Screen coordinate
+1A5F: 36 00           LD      (HL),$00            ; Clear it
+1A61: 23              INC     HL                  ; Next byte
+1A62: 7C              LD      A,H                 ; Have we done ...
+1A63: FE 40           CP      $40                 ; ... all the screen?
+1A65: C2 5F 1A        JP      NZ,$1A5F            ; No ... keep going
+1A68: C9              RET                         ; Out
+
+RestoreShields:
+; Logically OR the player's shields back onto the playfield
+; DE = sprite
+; HL = screen
+; C = bytes per row
+; B = number of rows
+1A69: C5              PUSH    BC                  ; Preserve BC
+1A6A: E5              PUSH    HL                  ; Hold for a bit
+1A6B: 1A              LD      A,(DE)              ; From sprite
+1A6C: B6              OR      (HL)                ; OR with screen
+1A6D: 77              LD      (HL),A              ; Back to screen
+1A6E: 13              INC     DE                  ; Next sprite
+1A6F: 23              INC     HL                  ; Next on screen
+1A70: 0D              DEC     C                   ; Row done?
+1A71: C2 6B 1A        JP      NZ,$1A6B            ; No ... do entire row
+1A74: E1              POP     HL                  ; Original start
+1A75: 01 20 00        LD      BC,$0020            ; Bump HL by ...
+1A78: 09              ADD     HL,BC               ; ... one screen row
+1A79: C1              POP     BC                  ; Restore
+1A7A: 05              DEC     B                   ; Row counter
+1A7B: C2 69 1A        JP      NZ,RestoreShields   ; Do all rows
+1A7E: C9              RET                         
+
+RemoveShip:
+; Remove a ship from the players stash and update the
+; hold indicators on the screen.
+1A7F: CD 2E 09        CALL    $092E               ; Get last byte from player data
+1A82: A7              AND     A                   ; Is it 0?
+1A83: C8              RET     Z                   ; Skip
+1A84: F5              PUSH    AF                  ; Preserve number remaining
+1A85: 3D              DEC     A                   ; Remove a ship from the stash
+1A86: 77              LD      (HL),A              ; New number of ships
+1A87: CD E6 19        CALL    DrawNumShips        ; Draw the line of ships
+1A8A: F1              POP     AF                  ; Restore number
+1A8B: 21 01 25        LD      HL,$2501            ; Screen coordinates
+1A8E: E6 0F           AND     $0F                 ; Make sure it is a digit
+1A90: C3 C5 09        JP      $09C5               ; Print number remaining
+Data From Here Down
+1A93: 00 00       
+
+; Splash screen animation structure 1
+; 00   Image form (increments each draw)
+; 00   Delta X
+; FF   Delta Y is -1
+; B8   X coordinate
+; FE   Y starting coordiante
+; 1C20 Base image (small alien)
+; 10   Size of image (16 bytes)
+; 9E   Target Y coordiante
+; 00   Reached Y flag
+; 1C20 Base iamge (small alien)
+1A95: 00 00 FF B8 FE 20 1C 10 9E 00 20 1C   
+
+ShotReloadRate:
+; The tables at 1CB8 and 1AA1 control how fast shots are created. The speed is based
+; on the upper byte of the player's score. For a score of less than or equal 0200 then
+; the fire speed is 30. For a score less than or equal 1000 the shot speed is 10. Less
+; than or equal 2000 the speed is 0B. Less than or equal 3000 is 08. And anything
+; above 3000 is 07.
+;
+; 1CB8: 02 10 20 30
+;
+1AA1: 30 10 0B 08                           
+1AA5: 07           ; Fastest shot firing speed
+
+MessageGOver:
+; GAME OVER PLAYER< >"
+1AA6: 06 00 0C 04 26 0E 15 04 11 26 26 0F   
+1AB2: 0B 00 18 04 11 24 26 25               
+
+MessageB1or2:
+; "1 OR 2PLAYERS BUTTON"
+1ABA: 1B 26 0E 11 26 1C 0F 0B 00 18 04      
+1AC5: 11 12 26 01 14 13 13 0E 0D 26
+
+Message1Only:
+; "ONLY 1PLAYER BUTTON "
+; Note the space on the end ... both alternatives are same length
+1ACF: 0E 0D 0B 18 26 1B 0F 0B 00 18 04 11 26 26 
+1ADD: 01 14 13 13 0E 0D 26                  
+
+MessageScore:
+; " SCORE<1> HI-SCORE SCORE<2>"
+1AE4: 26 12 02 0E 11 04 24 1B 25 26 07 08   
+1AF0: 3F 12 02 0E 11 04 26 12 02 0E 11 04   
+1AFC: 24 1C 25 26                     
+
+;-------------------------- RAM initialization -----------------------------
+; Coppied to RAM (2000) C0 bytes as initialization.
+; See the description of RAM at the top of this file for the details on this data.
+
+1B00: 01 00 00 10 00 00 00 00 02 78 38 78 38 00 F8 00
+1B10: 00 80 00 8E 02 FF 05 0C 60 1C 20 30 10 01 00 00   
+1B20: 00 00 00 BB 03 00 10 90 1C 28 30 01 04 00 FF FF   
+1B30: 00 00 02 76 04 00 00 00 00 00 04 EE 1C 00 00 03    
+1B40: 00 00 00 B6 04 00 00 01 00 1D 04 E2 1C 00 00 03 
+1B50: 00 00 00 82 06 00 00 01 06 1D 04 D0 1C 00 00 03
+1B60: FF 00 C0 1C 00 00 10 21 01 00 30 00 12 00 00 00         
+
+; These don't need to be copied over to RAM (see 1BA0 below).
+MesssageP1:
+; "PLAY PLAYER<1>"
+1B70: 0F 0B 00 18 26 0F 0B 00 18 04 11 24 1B 25 FC 
+1B7F: 00 
+
+1B80: 01 FF FF 00 00 00 20 64 1D D0 29 18 02 54 1D 00               
+1B90: 08 00 06 00 00 01 40 00 01 00 00 10 9E 00 20 1C                                 
+; These don't need to be copied over to RAM I believe this to be a mistake. The constant at 01E4 is C0,
+; which is the size of this mirror with the added sprite. It should be A0. I believe there was a macro
+; to size this area and later the splash screens where put in. Some of the data spilled over into this
+; and the macro automatically included it. No harm.
+Alien Pulling Upside Down 'Y'
+; Alien sprite type C pulling upside down Y
+AlienSprCYA:
+; ........
+; **......
+; ..*.....
+; ...****.
+; ..*.*...
+; **..*...
+; ...*....
+; .*.**...
+; *.****..
+; ...*.**.
+; ..******
+; ..******
+; ...*.**.
+; *.****..
+; .*.**...
+; ........
+1BA0: 00 03 04 78 14 13 08 1A 3D 68 FC FC 68 3D 1A 00                                    
+
+1BB0: 00 00 01 B8 98 A0 1B 10 FF 00 A0 1B 00 00 00 00                                    
+;--------------------------- End of initialization copy -------------------------
+
+
+; Shot descriptor for splash shooting the extra "C"
+1BC0: 00 10 00 0E 05 00 00 00 00 00 07 D0 1C C8 9B 03
+AlienSprCYB:
+; Alien sprite C pulling upside down Y. Note the difference between this and the first picutre
+; above. The Y is closer to the ship. This gives the effect of the Y kind of "sticking" in the
+; animation.
+; ........
+; ........
+; **......
+; ..*.....
+; ...****.
+; ..*.*...
+; **.*....
+; *..**...
+; .*.***..
+; *.**.**.
+; .*.*****
+; .*.*****
+; *.**.**.
+; .*.***..
+; *..**...
+; ........
+;
+1BD0: 00 00 03 04 78 14 0B 19 3A 6D FA FA 6D 3A 19 00                                    
+
+; More RAM initialization copied by 18D9
+1BE0: 00 00 00 00 00 00 00 00 00 01 00 00 01 74 1F 00                                    
+1BF0: 80 00 00 00 00 00 1C 2F 00 00 1C 27 00 00 1C 39 
+
+AlienSprA:
+Alien Images
+; Alien sprite type A,B, and C at positions 0
+;  ........ ........ ........
+;  ........ ........ ........
+;  *..***.. ........ ........
+;  *..****. ...****. ........
+;  .*.****. *.***... *..**...
+;  .***.**. .*****.* .*.***..
+;  ..**.*** ..**.**. *.**.**.
+;  .*.***** ..****.. .*.*****
+;  .*.***** ..****.. .*.*****
+;  ..**.*** ..****.. *.**.**.
+;  .***.**. ..**.**. .*.***..
+;  .*.****. .*****.* *..**...
+;  *..****. *.***... ........
+;  *..***.. ...****. ........
+;  ........ ........ ........
+;  ........ ........ ........
+1C00: 00 00 39 79 7A 6E EC FA FA EC 6E 7A 79 39 00 00 
+1C10: 00 00 00 78 1D BE 6C 3C 3C 3C 6C BE 1D 78 00 00 
+1C20: 00 00 00 00 19 3A 6D FA FA 6D 3A 19 00 00 00 00 
+
+AlienSprB:
+; Alien sprite type A,B, and C at positions 1
+;  ........ ........ ........
+;  ........ ........ ........
+;  ...***.. ........ ........
+;  .*.****. .***.... ........
+;  *******. ...**... .*.**...
+;  *.**.**. .*****.* *.****..
+;  ..**.*** *.**.**. ...*.**.
+;  .*.***** *.****.. ..******
+;  .*.***** ..****.. ..******
+;  ..**.*** *.****.. ...*.**.
+;  *.**.**. *.**.**. *.****..
+;  *******. .*****.* .*.**...
+;  .*.****. ...**... ........
+;  ...***.. .***.... ........
+;  ........ ........ ........
+;  ........ ........ ........
+1C30: 00 00 38 7A 7F 6D EC FA FA EC 6D 7F 7A 38 00 00 
+1C40: 00 00 00 0E 18 BE 6D 3D 3C 3D 6D BE 18 0E 00 00 
+1C50: 00 00 00 00 1A 3D 68 FC FC 68 3D 1A 00 00 00 00 
+Player Sprite
+PlayerSprite:
+;  ........
+;  ........
+;  ****....
+;  *****...
+;  *****...
+;  *****...
+;  *****...
+;  *******.
+;  ********
+;  *******.
+;  *****...
+;  *****...
+;  *****...
+;  *****...
+;  ****....
+;  ........
+1C60: 00 00 0F 1F 1F 1F 1F 7F FF 7F 1F 1F 1F 1F 0F 00 
+
+
+PlrBlowupSprites:
+;  ........
+;  ..*.....
+;  *.......
+;  **..*...
+;  **......
+;  ***.....
+;  **..**.*
+;  ****....
+;  ****.*..
+;  **......
+;  ****.*..
+;  *..*..*.
+;  ..*.....
+;  **......
+;  ........
+;  *.......
+;
+1C70: 00 04 01 13 03 07 B3 0F 2F 03 2F 49 04 03 00 01 
+;
+;  ......*.
+;  ...*....
+;  *.*.....
+;  **...*.*
+;  .*.*....
+;  **......
+;  **.**.*.
+;  ****....
+;  ***..*..
+;  ***..*..
+;  **.*....
+;  **.*..*.
+;  ......*.
+;  ..*....*
+;  *...*...
+;  ...*..*.
+1C80: 40 08 05 A3 0A 03 5B 0F 27 27 0B 4B 40 84 11 48 
+Player Shot Sprite
+PlayerShotSpr:
+1C90: 0F    ; ++++....
+Player Shot Exploding
+ShotExploding:
+; *..**..*
+; ..****..
+; .******.
+; *.****..
+; ..****.*
+; .*****..
+; ..*****.
+; *..**..*
+1C91: 99 3C 7E 3D BC 3E 7C 99     
+      
+Message10Pts:
+; Ran out of space at 1DFE
+1C99: 27 1B 1A 26 0F 0E 08 0D 13 12    ; "=10 POINTS"
+
+MessageAdv:
+; "*SCORE ADVANCE TABLE*"
+1CA3: 28 12 02 0E 11 04 26 00                                 
+1CAB: 03 15 00 0D 02 04 26 13                                 
+1CB3: 00 01 0B 04 28                                    
+
+
+AReloadScoreTab:
+; The tables at 1CB8 and 1AA1 control how fast shots are created. The speed is based
+; on the upper byte of the player's score. For a score of less than or equal 0200 then
+; the fire speed is 30. For a score less than or equal 1000 the shot speed is 10. Less
+; than or equal 2000 the speed is 0B. Less than or equal 3000 is 08. And anything
+; above 3000 is 07.
+;
+; 1AA1: 30 10 0B 08
+; 1AA5: 07           ; Fastest shot firing speed
+;
+1CB8: 02 10 20 30                           
+
+MessageTilt:
+1CBC: 13 08 0B 13   ; "TILT"
+Alien Exploding Sprite
+; Alien exploding sprite
+AlienExplode:
+;  ........
+;  ...*....
+;  *..*..*.
+;  .*...*..
+;  ..*.*...
+;  *......*
+;  .*....*.
+;  ........
+;  .*....*.
+;  *......*
+;  ..*.*...
+;  .*...*..
+;  *..*..*.
+;  ...*....
+;  ........
+;  ........
+1CC0: 00 08 49 22 14 81 42 00 42 81 14 22 49 08 00 00 
+Squigly Shot Sprite
+; Squigly shot picture in 4 animation frames
+SquiglyShot:
+1CD0: 44   ; ..*...*.
+1CD1: AA   ; .*.*.*.*
+1CD2: 10   ; ....*...
+
+1CD3: 88   ; ...*...*
+1CD4: 54   ; ..*.*.*.
+1CD5: 22   ; .*...*..
+
+1CD6: 10   ; ....*...
+1CD7: AA   ; .*.*.*.*
+1CD8: 44   ; ..*...*.
+                                 
+1CD9: 22   ; .*...*..
+1CDA: 54   ; ..*.*.*.
+1CDB: 88   ; ...*...*
+Alien Shot Exploding
+; Alien shot exploding
+AShotExplo:      
+; .*.*..*.
+; *.*.*...
+; .*****.*
+; ******..
+; .****.*.
+; *.*..*..
+1CDC: 4A 15 BE 3F 5E 25                                
+Plunger Shot Sprite
+; Alien shot ... the plunger looking one
+PlungerShot:
+1CE2: 04  ; ..*.....
+1CE3: FC  ; ..******
+1CE4: 04  ; ..*.....
+
+1CE5: 10  ; ....*...
+1CE6: FC  ; ..******
+1CE7: 10  ; ....*...
+
+1CE8: 20  ; .....*..
+1CE9: FC  ; ..******
+1CEA: 20  ; .....*..
+
+1CEB: 80  ; .......*
+1CEC: FC  ; ..******
+1CED: 80  ; .......*
+Rolling Shot Sprite
+; Alien shot ... the rolling one
+RollShot:
+1CEE: 00  ; ........
+1CEF: FE  ; .*******
+1CF0: 00  ; ........
+
+1CF1: 24  ; ..*..*..
+1CF2: FE  ; .*******
+1CF3: 12  ; .*..*...
+
+1CF4: 00  ; ........
+1CF5: FE  ; .*******
+1CF6: 00  ; ........
+
+1CF7: 48  ; ...*..*.
+1CF8: FE  ; .*******
+1CF9: 90  ; ....*..*
+               
+MessagePlayUY:
+1CFA: 0F 0B 00 29    ; "PLAy" with an upside down 'Y' for splash screen
+                      
+1CFE: 00 00        
+                            
+ColFireTable:
+; This table decides which column a shot will fall from. The column number is read from the
+; table (1-11) and the pointer increases for the shot type. For instance, the "squiggly" shot
+; will fall from columns in this order: 0B, 01, 06, 03. If you play the game you'll see that
+; order.
+;
+; The "plunger" shot uses index 00-0F (inclusive)
+; The "squiggly" shot uses index 06-14 (inclusive)
+; The "rolling" shot targets the player
+1D00: 01 07 01 01 01 04 0B 01 06 03 01 01 0B 09 02 08                                    
+1D10: 02 0B 04 07 0A    
+;
+; This appears to be part of the column-firing table, but it is never used.
+; Perhaps this was originally intended for the "rolling" shot but then the
+; "rolling" was change to target the player specifically.
+1D15: 05 02 05 04 06 07 08 0A 06 0A 03              
+Shield Image
+ShieldImage:
+; Shield image pattern. 2 x 22 = 44 bytes.
+;
+;************....
+;*************...
+;**************..
+;***************.
+;****************
+;..**************
+;...*************
+;....************
+;....************
+;....************
+;....************
+;....************
+;....************
+;....************
+;...*************
+;..**************
+;****************
+;****************
+;***************.
+;**************..
+;*************...
+;************....
+;
+1D20: FF 0F FF 1F FF 3F FF 7F FF FF FC FF F8 FF F0 FF F0 FF F0 FF F0 FF                                    
+1D36: F0 FF F0 FF F0 FF F8 FF FC FF FF FF FF FF FF 7F FF 3F FF 1F FF 0F                                    
+
+
+1D4C: 05 10 15 30  ; Table of possible saucer scores
+1D50: 94 97 9A 9D  ; Table of corresponding string prints for each possible score
+
+SaucerScrTab:
+; 208D points here to the score given when the saucer is shot. It advances
+; every time the player-shot is removed. The code wraps after 15, but there
+; are 16 values in this table. This is a bug in the code at 044E (thanks to
+; Colin Dooley for finding this).
+;
+; Thus the one and only 300 comes up every 15 shots (after an initial 8).
+1D54: 10 05 05 10 15 10 10 05 30 10 10 10 05 15 10 05                                 
+Flying Saucer Sprite
+SpriteSaucer:
+; ........
+; ........
+; ........
+; ........
+; ..*.....
+; ..**....
+; .****...
+; ***.**..
+; .*****..
+; ..*****.
+; ..*.***.
+; .******.
+; .******.
+; ..*.***.
+; ..*****.
+; .*****..
+; ***.**..
+; .****...
+; ..**....
+; ..*.....
+; ........
+; ........
+; ........
+; ........
+1D64: 00 00 00 00 04 0C 1E 37 3E 7C 74 7E 7E 74 7C 3E 37 1E 0C 04 00 00 00 00
+
+SpriteSaucerExp:
+;........
+;.*...*..
+;........
+;*.*..*.*
+;......*.
+;...*....
+;...**..*
+;*.****..
+;.**.**.*
+;..****..
+;.**.**..
+;*.***...
+;....*...
+;...*..*.
+;.*...**.
+;.**.**.*
+;*.***...
+;...**..*
+;...*....
+;.*....*.
+;....*..*
+;...*....
+;........
+;........
+1D7C: 00 22 00 A5 40 08 98 3D B6 3C 36 1D 10 48 62 B6 1D 98 08 42 90 08 00 00  
+         
+SaucSoreStr:
+1D94: 26 1F 1A  ; _50
+1D97: 1B 1A 1A  ; 100
+1D9A: 1B 1F 1A  ; 150
+1D9D: 1D 1A 1A  ; 300
+
+AlienScores:
+; Score table for hitting alien type
+1DA0: 10 ; Bottom 2 rows
+1DA1: 20 ; Middle row
+1DA2: 30 ; Highest row
+         
+AlienStartTable:
+; Starting Y coordinates for aliens at beginning of rounds. The first round is initialized to $78 at 07EA.
+; After that this table is used for 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, and 9th. The 10th starts over at
+; 1DA3 (60).
+1DA3: 60                                    
+1DA4: 50                                    
+1DA5: 48                                    
+1DA6: 48                                    
+1DA7: 48                                    
+1DA8: 40                                    
+1DA9: 40                                    
+1DAA: 40   
+                                 
+MessagePlayY:
+1DAB: 0F 0B 00 18   ; "PLAY" with normal Y
+
+MessageInvaders:
+; "SPACE  INVADERS"
+1DAF: 12 0F 00 02 04 26 26 08 0D 15 00 03 04 11 12 
+
+; Tables used to draw "SCORE ADVANCE TABLE" information
+1DBE: 0E 2C 68 1D           ; Flying Saucer
+1DC2: 0C 2C 20 1C           ; Alien C, sprite 0
+1DC6: 0A 2C 40 1C           ; Alien B, sprite 1
+1DCA: 08 2C 00 1C           ; Alien A, sprite 0
+1DCE: FF                    ; End of list
+;
+AlienScoreTable:
+1DCF: 0E 2E E0 1D           ; "=? MYSTERY"
+1DD3: 0C 2E EA 1D           ; "=30 POINTS"
+1DD7: 0A 2E F4 1D           ; "=20 POINTS"
+1DDB: 08 2E 99 1C           ; "=10 POINTS"
+1DDF: FF                    ; End of list
+
+MessageMyst:
+1DE0: 27 38 26 0C 18 12 13 04 11 18   ; "=? MYSTERY"
+
+Message30Pts:
+1DEA: 27 1D 1A 26 0F 0E 08 0D 13 12   ; "=30 POINTS"
+
+Message20Pts:
+1DF4: 27 1C 1A 26 0F 0E 08 0D 13 12   ; "=20 POINTS"
+
+; Ran out of space here. The "=10" message is up at 1C99. That keeps
+; the font table firmly at 1E00.
+
+1DFE: 00 00 ; Padding to put font table at 1E00
+Text Character Sprites
+; 8 byte sprites
+; The screen is turned so rotate these pictures counter-clockwise.
+; Some of the font characters at the end were never needed. The ROM overwrites these characters with
+; data near the end. For instance, 1F90 would be a character but has the "INSERT COIN" message. The "?"
+; character is at 1FC0 and is used in messages as is 1FF8 "-". The "light colored" tiles in the grid below
+; show the character slots that have been repurposed.
+Characters:
+1E00: 00 1F 24 44 24 1F 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1E08: 00 7F 49 49 49 36 00 00  ; *****... *******. .*****.. *******. *******. *******. .*****.. *******.
+1E10: 00 3E 41 41 41 22 00 00  ; ..*..*.. *..*..*. *.....*. *.....*. *..*..*. ...*..*. *.....*. ...*....
+1E18: 00 7F 41 41 41 3E 00 00  ; ..*...*. *..*..*. *.....*. *.....*. *..*..*. ...*..*. *.....*. ...*....
+1E20: 00 7F 49 49 49 41 00 00  ; ..*..*.. *..*..*. *.....*. *.....*. *..*..*. ...*..*. *.*...*. ...*....
+1E28: 00 7F 48 48 48 40 00 00  ; *****... .**.**.. .*...*.. .*****.. *.....*. ......*. ***...*. *******.
+1E30: 00 3E 41 41 45 47 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1E38: 00 7F 08 08 08 7F 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+
+1E40: 00 00 41 7F 41 00 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1E48: 00 02 01 01 01 7E 00 00  ; ........ .*...... *******. *******. *******. *******. .*****.. *******.
+1E50: 00 7F 08 14 22 41 00 00  ; *.....*. *....... ...*.... *....... .....*.. ....*... *.....*. ...*..*.
+1E58: 00 7F 01 01 01 01 00 00  ; *******. *....... ..*.*... *....... ...**... ...*.... *.....*. ...*..*.
+1E60: 00 7F 20 18 20 7F 00 00  ; *.....*. *....... .*...*.. *....... .....*.. ..*..... *.....*. ...*..*.
+1E68: 00 7F 10 08 04 7F 00 00  ; ........ .******. *.....*. *....... *******. *******. .*****.. ....**..
+1E70: 00 3E 41 41 41 3E 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1E78: 00 7F 48 48 48 30 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+
+1E80: 00 3E 41 45 42 3D 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1E88: 00 7F 48 4C 4A 31 00 00  ; .*****.. *******. .*..**.. ......*. .******. ..*****. *******. **...**.
+1E90: 00 32 49 49 49 26 00 00  ; *.....*. ...*..*. *..*..*. ......*. *....... .*...... .*...... ..*.*...
+1E98: 00 40 40 7F 40 40 00 00  ; *.*...*. ..**..*. *..*..*. *******. *....... *....... ..**.... ...*....
+1EA0: 00 7E 01 01 01 7E 00 00  ; .*....*. .*.*..*. *..*..*. ......*. *....... .*...... .*...... ..*.*...
+1EA8: 00 7C 02 01 02 7C 00 00  ; *.****.. *...**.. .**..*.. ......*. .******. ..*****. *******. **...**.
+1EB0: 00 7F 02 0C 02 7F 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1EB8: 00 63 14 08 14 63 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+
+1EC0: 00 60 10 0F 10 60 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1EC8: 00 43 45 49 51 61 00 00  ; .....**. **....*. .*****.. ........ **...*.. .*....*. ..**.... .*..***.
+1ED0: 00 3E 45 49 51 3E 00 00  ; ....*... *.*...*. *.*...*. *....*.. *.*...*. *.....*. ..*.*... *...*.*.
+1ED8: 00 00 21 7F 01 00 00 00  ; ****.... *..*..*. *..*..*. *******. *..*..*. *..*..*. ..*..*.. *...*.*.
+1EE0: 00 23 45 49 49 31 00 00  ; ....*... *...*.*. *...*.*. *....... *..*..*. *..**.*. *******. *...*.*.
+1EE8: 00 42 41 49 59 66 00 00  ; .....**. *....**. .*****.. ........ *...**.. .**..**. ..*..... .***..*.
+1EF0: 00 0C 14 24 7F 04 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1EF8: 00 72 51 51 51 4E 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+
+1F00: 00 1E 29 49 49 46 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1F08: 00 40 47 48 50 60 00 00  ; .****... ......*. .**.**.. *...**.. ...*.... ........ ........ ..*.*...
+1F10: 00 36 49 49 49 36 00 00  ; *..*.*.. ***...*. *..*..*. *..*..*. ..*.*... *.....*. ........ ..*.*...
+1F18: 00 31 49 49 4A 3C 00 00  ; *..*..*. ...*..*. *..*..*. *..*..*. .*...*.. .*...*.. ........ ..*.*...
+1F20: 00 08 14 22 41 00 00 00  ; *..*..*. ....*.*. *..*..*. .*.*..*. *.....*. ..*.*... ........ ..*.*...
+1F28: 00 00 41 22 14 08 00 00  ; .**...*. .....**. .**.**.. ..****.. ........ ...*.... ........ ..*.*...
+1F30: 00 00 00 00 00 00 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+1F38: 00 14 14 14 14 14 00 00  ; ........ ........ ........ ........ ........ ........ ........ ........
+
+1F40: 00 22 14 7F 14 22 00 00  ; ........ ........
+1F48: 00 03 04 78 04 03 00 00  ; .*...*.. **......
+                               ; ..*.*... ..*.....
+                               ; *******. ...****.
+                               ; ..*.*... ..*.....
+                               ; .*...*.. **......
+                               ; ........ ........
+                               ; ........ ........
+
+MessageP1or2:
+1F50: 24 1B 26 0E 11 26 1C 26  ; "<1 OR 2 PLAYERS>  "
+1F58: 0F 0B 00 18 04 11 12 25               
+1F60: 26 26 
+
+Message1Coin:
+1F62: 28 1B 26 0F 0B 00 18 04  ; "*1 PLAYER  1 COIN "
+1F6A: 11 26 26 1B 26 02 0E 08 
+1F72: 0D 26                           
+
+DemoCommands:
+; (1=Right, 2=Left)
+1F74: 01 01 00 00 01 00 02 01 00 02 01 00
+Alien Sprite Carrying 'Y'
+; Small alien pushing Y back onto screen
+AlienSprCA:
+; .....**.
+; ....*...
+; ****....
+; ....*...
+; .....**.
+; ....**..
+; ...**...
+; .*.**...
+; *.****..
+; ...*.**.
+; ..******
+; ..******
+; ...*.**.
+; *.****..
+; .*.**...
+; ........
+                
+1F80: 60 10 0F 10 60 30 18 1A 3D 68 FC FC 68 3D 1A 00               
+
+MessageCoin:
+1F90: 08 0D 12 04 11 13 26 26 02 0E 08 0D   ; "INSERT  COIN"
+                          
+CreditTable:
+1F9C: 0D 2A 50 1F                 ; "<1 OR 2 PLAYERS>  " to screen at 2A0D
+1FA0: 0A 2A 62 1F                 ; "*1 PLAYER  1 COIN " to screen at 2A0A
+1FA4: 07 2A E1 1F                 ; "*2 PLAYERS 2 COINS" to screen at 2A07
+1FA8: FF                          ; Terminates "table print"
+
+MessageCredit:
+1FA9: 02 11 04 03 08 13 26       ; "CREDIT " (with space on the end)
+
+AlienSprCB:
+; ........
+; .....**.
+; ....*...
+; ****....
+; ....*...
+; .....**.
+; ...***..
+; *..**...
+; .*.***..
+; *.**.**.
+; .*.*****
+; .*.*****
+; *.**.**.
+; .*.***..
+; *..**...
+; ........
+1FB0: 00 60 10 0F 10 60 38 19 3A 6D FA FA 6D 3A 19 00               
+
+1FC0: 00 20 40 4D 50 20 00 00               ; "?"
+
+1FC8: 00 
+
+; Splash screen animation structure 3
+; 00   Image form (increments each draw)
+; 00   Delta X
+; FF   Delta Y is -1
+; B8   X coordinate
+; FF   Y starting coordiante
+; 1F80 Base image (small alien with Y)
+; 10   Size of image (16 bytes)
+; 97   Target Y coordiante
+; 00   Reached Y flag
+; 1F80 Base iamge (small alien with Y)
+;
+1FC9: 00 00 FF B8 FF 80 1F 10 97 00 80 1F 
+
+; Splash screen animation structure 4
+; 00   Image form (increments each draw)
+; 00   Delta X
+; 01   Delta Y is 1
+; D0   X coordinate
+; 22   Y starting coordiante
+; 1C20 Base image (small alien)
+; 10   Size of image (16 bytes)
+; 94   Target Y coordiante
+; 00   Reached Y flag
+; 1C20 Base iamge (small alien)
+;
+1FD5: 00 00 01 D0 22 20 1C 10 94 00 20 1C 
+
+Message2Coins:
+1FE1: 28 1C 26 0F 0B 00 18 04    ; "*2 PLAYERS 2 COINS"
+1FE9: 11 12 26 1C 26 02 0E 08 
+1FF1: 0D 12                              
+
+MessagePush:
+1FF3: 0F 14 12 07 26             ; "PUSH " (with space on the end)
+
+1FF8: 00 08 08 08 08 08 00 00               ; 3F:"-"
diff --git a/doc/invaders_hardware.txt b/doc/invaders_hardware.txt
new file mode 100644 (file)
index 0000000..503b89d
--- /dev/null
@@ -0,0 +1,167 @@
+http://computerarcheology.com/Arcade/SpaceInvaders/Hardware.html
+
+Hardware
+Much of this comes from the comments in the MAME emulator.
+
+invaders.h 0000-07FF
+invaders.g 0800-0FFF
+invaders.f 1000-17FF
+invaders.e 1800-1FFF
+Interrupts
+The mame/drivers/mw8080bw.c comments have the following information about the interrupts:
+
+        The CPU's INT line is asserted via a D flip-flop at E3.
+        The flip-flop is clocked by the expression (!(64V | !128V) | VBLANK).
+        According to this, the LO to HI transition happens when the vertical
+        sync chain is 0x80 and 0xda and VBLANK is 0 and 1, respectively.
+        These correspond to lines 96 and 224 as displayed.
+        The interrupt vector is provided by the expression:
+        0xc7 | (64V << 4) | (!64V << 3), giving 0xcf and 0xd7 for the vectors.
+        The flip-flop, thus the INT line, is later cleared by the CPU via
+        one of its memory access control signals.
+The value CF is RST 8 and D7 is RST 10.
+
+If I understand this right then the system gets RST 8 when the beam is *near* the middle of the screen and RST 10 when it is at the end (start of VBLANK).
+
+Video
+The raster resolution is 256x224 at 60Hz. The monitor is rotated in the cabinet 90 degrees counter-clockwise.
+
+The screens pixels are on/off (1 bit each). 256*224/8 = 7168 (7K) bytes.
+
+Memory Map
+0000-1FFF 8K ROM
+2000-23FF 1K RAM
+2400-3FFF 7K Video RAM
+4000- RAM mirror
+I/O Ports
+0000pr INP0    See below
+0001pr INP1    See below
+0002pr INP2    See below
+0003pr SHFT_IN See below
+0002pw SHFTAMNT        See below
+0003pw SOUND1  See below
+0004pw SHFT_DATA       See below
+0005pw SOUND2  See below
+0006pw WATCHDOG        See below
+These ports are mapped into the 8080's I/O address space (not the memory space):
+
+  Read
+   00        INPUTS (Mapped in hardware but never used by the code)
+   01        INPUTS
+   02        INPUTS
+   03        bit shift register read
+  Write
+   02        shift amount (3 bits)
+   03        sound bits
+   04        shift data
+   05        sound bits
+   06        watch-dog  
+Port 07 is also demultiplexed. The schematics say the select signal is wired directly to input-port-0's bit 7. This doesn't make sense.
+
+Dedicated Shift Hardware
+The 8080 instruction set does not include opcodes for shifting. An 8-bit pixel image must be shifted into a 16-bit word for the desired bit-position on the screen. Space Invaders adds a hardware shift register to help with the math.
+
+16 bit shift register:
+
+       f              0        bit
+       xxxxxxxxyyyyyyyy
+       
+       Writing to port 4 shifts x into y, and the new value into x, eg.
+       $0000,
+       write $aa -> $aa00,
+       write $ff -> $ffaa,
+       write $12 -> $12ff, ..
+       
+       Writing to port 2 (bits 0,1,2) sets the offset for the 8 bit result, eg.
+       offset 0:
+       rrrrrrrr                result=xxxxxxxx
+       xxxxxxxxyyyyyyyy
+       
+       offset 2:
+         rrrrrrrr      result=xxxxxxyy
+       xxxxxxxxyyyyyyyy
+       
+       offset 7:
+              rrrrrrrr result=xyyyyyyy
+       xxxxxxxxyyyyyyyy
+       
+       Reading from port 3 returns said result.
+Inputs
+Port 0
+ bit 0 DIP4 (Seems to be self-test-request read at power up)
+ bit 1 Always 1
+ bit 2 Always 1
+ bit 3 Always 1
+ bit 4 Fire
+ bit 5 Left
+ bit 6 Right
+ bit 7 ? tied to demux port 7 ?
+
+Port 1
+ bit 0 = CREDIT (1 if deposit)
+ bit 1 = 2P start (1 if pressed)
+ bit 2 = 1P start (1 if pressed)
+ bit 3 = Always 1
+ bit 4 = 1P shot (1 if pressed)
+ bit 5 = 1P left (1 if pressed)
+ bit 6 = 1P right (1 if pressed)
+ bit 7 = Not connected
+
+Port 2
+ bit 0 = DIP3 00 = 3 ships  10 = 5 ships
+ bit 1 = DIP5 01 = 4 ships  11 = 6 ships
+ bit 2 = Tilt
+ bit 3 = DIP6 0 = extra ship at 1500, 1 = extra ship at 1000
+ bit 4 = P2 shot (1 if pressed)
+ bit 5 = P2 left (1 if pressed)
+ bit 6 = P2 right (1 if pressed)
+ bit 7 = DIP7 Coin info displayed in demo screen 0=ON
+
+Port 3
+  bit 0-7 Shift register data
+Output
+Port 2:
+ bit 0,1,2 Shift amount
+
+Port 3: (discrete sounds)
+ bit 0=UFO (repeats)        SX0 0.raw
+ bit 1=Shot                 SX1 1.raw
+ bit 2=Flash (player die)   SX2 2.raw
+ bit 3=Invader die          SX3 3.raw
+ bit 4=Extended play        SX4
+ bit 5= AMP enable          SX5
+ bit 6= NC (not wired)
+ bit 7= NC (not wired)
+ Port 4: (discrete sounds)
+ bit 0-7 shift data (LSB on 1st write, MSB on 2nd)
+
+Port 5:
+ bit 0=Fleet movement 1     SX6 4.raw
+ bit 1=Fleet movement 2     SX7 5.raw
+ bit 2=Fleet movement 3     SX8 6.raw
+ bit 3=Fleet movement 4     SX9 7.raw
+ bit 4=UFO Hit              SX10 8.raw
+ bit 5= NC (Cocktail mode control ... to flip screen)
+ bit 6= NC (not wired)
+ bit 7= NC (not wired)
+
+Port 6:
+ Watchdog ... read or write to reset
+Screen Geometry
+2400 - 3FFF (1C00 bytes = 256 * 28) 28*8=224. Screen is 256x224 pixels.
+
+The map below shows the raster layout. Take this map and rotate it counter clockwise once. Thus the first byte is lower left. First "row" ends upper left. Last byte is upper right.
+
+     2400     2401     2402        ....   241F
+     01234567 01234567 01234567    ....   01234567
+     2420     2421     2422        ....   243F
+     01234567 01234567 01234567    ....   01234567
+    
+     .                                    .
+     .                                    .
+     .                                    .
+     .                                    .
+     3FE0     3FE1     3FE2        ....   3FFF
+     01234567 01234567 01234567    ....   01234567
diff --git a/doc/invaders_ram_use.txt b/doc/invaders_ram_use.txt
new file mode 100644 (file)
index 0000000..979ea52
--- /dev/null
@@ -0,0 +1,282 @@
+http://computerarcheology.com/Arcade/SpaceInvaders/RAMUse.html
+
+RAM Usage
+2000   waitOnDraw      Cleared by alien-draw and set by next-alien. This ensures no alien gets missed while drawing.
+2001           
+2002   alienIsExploding        Not-0 if an alien is exploding, 0 if not exploting
+2003   expAlienTimer   Time (ISR ticks) left in alien-explosion
+2004   alienRow        Row number of current alien (cursor)
+2005   alienFrame      Animation frame number (0 or 1) for current alien (cursor)
+2006   alienCurIndex   Alien cursor index (from 0 to 54)
+2007   refAlienDYr     Reference alien delta Yr
+2008   refAlienDXr     Reference alien deltaXr
+2009   refAlienYr      Reference alien Yr coordinate
+200A   refAlienXr      Reference alien Xr coordinate
+200B   alienPosLSB     Alien cursor bit pos (LSB)
+200C   alienPosMSB     Alien cursor bit pos (MSB)
+200D   rackDirection   Value 0 if rack is moving right or 1 if rack is moving left
+200E   rackDownDelta   Constant value of alien rack dropping after bumping screen edge
+200F           
+2010   obj0TimerMSB    
+2011   obj0TimerLSB    Wait 128 interrupts (about 2 secs) before player task starts
+2012   obj0TimerExtra  
+2013   obj0HanlderLSB  
+2014   oBJ0HanlderMSB  Player handler code at 028E
+2015   playerAlive     Player is alive (FF=alive). Toggles between 0 and 1 for blow-up images.
+2016   expAnimateTimer Time till next blow-up sprite change (reloaded to 5)
+2017   expAnimateCnt   Number of changes left in blow-up sequence
+2018   plyrSprPicL     Player sprite descriptor ... picture LSB
+2019   plyrSprPicM     Player sprite descriptor ... picture MSB
+201A   playerYr        Player sprite descriptor ... location LSB
+201B   playerXr        Player sprite descriptor ... location MSB
+201C   plyrSprSiz      Player sprite descriptor ... size of sprite
+201D   nextDemoCmd     Next movement command for demo
+201E   hidMessSeq      Set to 1 after 1st of 2 sequences are entered for hidden-message display
+201F           Appears to be unused
+2020   obj1TimerMSB    
+2021   obj1TimerLSB    
+2022   obj1TimerExtra  All 0's ... run immediately
+2023   obj1HandlerLSB  
+2024   obj1HandlerMSB  Shot handler code at 03BB
+2025   plyrShotStatus  0 if available, 1 if just initiated, 2 moving normally, 3 hit something besides alien, 5 if alien explosion is in progress, 4 if alien has exploded (remove from active duty)
+2026   blowUpTimer     Sprite blow-up timer
+2027   obj1ImageLSB    
+2028   obj1ImageMSB    Sprite image at 1C90 (just one byte)
+2029   obj1CoorYr      Player shot Y coordinate
+202A   obj1CoorXr      Player shot X coordinate
+202B   obj1ImageSize   Size of shot image (just one byte)
+202C   shotDeltaX      Shot's delta X
+202D   fireBounce      1 if button has been handled but remains down
+202E           
+202F           
+2030   obj2TimerMSB    
+2031   obj2TimerLSB    
+2032   obj2TimerExtra  GO-3 runs when this is 1. GO-4 runs when this is 2. (copied to 2080 in game loop)
+2033   obj2HandlerLSB  
+2034   obj2HandlerMSB  Handler code at 0476
+2035   rolShotStatus   
+2036   rolShotStepCnt  
+2037   rolShotTrack    A 0 means this shot tracks the player
+2038   rolShotCFirLSB  Pointer to column-firing table LSB (not used for targeting)
+2039   rolShotCFirMSB  Pointer to column-firing table MSB (not used for MSB counter
+203A   rolShotBlowCnt  
+203B   rolShotImageLSB 
+203C   rolShotImageMSB 
+203D   rolShotYr       
+203E   rolShotXr       
+203F   rolShotSize     
+2040   obj3TimerMSB    
+2041   obj3TimerLSB    
+2042   obj3TimerExtra  
+2043   obj3HandlerLSB  
+2044   obj3HandlerMSB  Handler code at 04B6
+2045   pluShotStatus   
+2046   pluShotStepCnt  
+2047   pluShotTrack    A 1 means this shot does not track the player
+2048   pluShotCFirLSB  Pointer to column-firing table LSB
+2049   pluShotCFirMSB  Pointer to column-firing table MSB
+204A   pluShotBlowCnt  
+204B   pluShotImageLSB 
+204C   pluShotImageMSB 
+204D   pluShotYr       
+204E   pluSHotXr       
+204F   pluShotSize     
+2050   obj4TimerMSB    
+2051   obj4TimerLSB    
+2052   obj4TimerExtra  
+2053   obj4HandlerLSB  
+2054   obj4HandlerMSB  Handler code at 0682
+2055   squShotStatus   
+2056   squShotStepCnt  
+2057   squShotTrack    A 1 means this shot does not track the player
+2058   squShotCFirLSB  Pointer to column-firing table LSB
+2059   squShotCFirMSB  Pointer to column-firing table MSB
+205A   squSHotBlowCnt  
+205B   squShotImageLSB 
+205C   squShotImageMSB 
+205D   squShotYr       
+205E   squShotXr       
+205F   squShotSize     
+2060   endOfTasks      FF marks the end of the tasks list
+2061   collision       Set to 1 if sprite-draw detects collision
+2062   expAlienLSB     
+2063   expAlienMSB     Exploding alien picture 1CC0
+2064   expAlienYr      Y coordinate of exploding alien
+2065   expAlienXr      X coordinate of exploding alien
+2066   expAlienSize    Size of exploding alien sprite (16 bytes)
+2067   playerDataMSB   Current player's data-pointer MSB (21xx or 22xx)
+2068   playerOK        1 means OK, 0 means blowing up
+2069   enableAlienFire 1 means aliens can fire, 0 means not
+206A   alienFireDelay  Count down till aliens can fire (2069 flag is then set)
+206B   oneAlien        1 when only one alien is on screen
+206C   temp206C        Holds the value ten ... number of characters in each "=xx POINTS" string but gets set to 18 in mem copy before game.
+206D   invaded Set to 1 when player blows up because rack has reached bottom
+206E   skipPlunger     When there is only one alien left this goes to 1 to disable the plunger-shot when it ends
+206F           
+2070   otherShot1      When processing a shot, this holds one of the other shot's info
+2071   otherShot2      When processing a shot, this holds one of the other shot's info
+2072   vblankStatus    80=screen is being drawn (don't touch), 0=blanking in progress (ok to change)
+2073   aShotStatus     Bit 0 set if shot is blowing up, bit 7 set if active
+2074   aShotStepCnt    Count of steps made by shot (used for fire reload rate)
+2075   aShotTrack      0 if shot tracks player or 1 if it uses the column-fire table
+2076   aShotCFirLSB    Pointer to column-firing table LSB
+2077   aShotCFirMSB    Pointer to column-firing table MSB
+2078   aShotBlowCnt    Alen shot blow up counter. At 3 the explosion is drawn. At 0 it is done.
+2079   aShotImageLSB   Alien shot image LSB
+207A   aShotImageMSB   Alien shot image MSB
+207B   alienShotYr     Alien shot delta Y
+207C   alienShotXr     Alien shot delta X
+207D   alienShotSize   Alien shot size
+207E   alienShotDelta  Alien shot speed. Normally -1 but set to -4 with less than 9 aliens
+207F   shotPicEnd      the last picture in the current alien shot animation
+2080   shotSync        All 3 shots are synchronized to the GO-2 timer. This is copied from timer in the game loop
+2081   tmp2081 Used to hold the remember/restore flag in shield-copy routine
+2082   numAliens       Number of aliens on screen
+2083   saucerStart     Flag to start saucer (set to 1 when 2091:2092 counts down to 0)
+2084   saucerActive    Saucer is on screen (1 means yes)
+2085   saucerHit       Saucer has been hit (1 means draw it but don't move it)
+2086   saucerHitTime   Hit-sequence timer (explosion drawn at 1F, score drawn at 18)
+2087   saucerPriLocLSB Mystery ship print descriptor ... coordinate LSB
+2088   saucerPriLocMSB Mystery ship print descriptor ... coordinate MSB
+2089   saucerPriPicLSB Mystery ship print descriptor ... message LSB
+208A   saucerPriPicMSB Mystery ship print descriptor ... message MSB
+208B   saucerPriSize   Mystery ship print descriptor ... number of characters
+208C   saucerDeltaY    Mystery ship delta Y
+208D   sauScoreLSB     Pointer into mystery-ship score table (MSB)
+208E   sauScoreMSB     Pointer into mystery-ship score table (LSB)
+208F   shotCountLSB    Bumped every shot-removal. Saucer's direction is bit 0. (0=2/29, 1=-2/E0)
+2090   shotCountMSB    Read as two-bytes with 208F, but never used as such.
+2091   tillSaucerLSB   
+2092   tillSaucerMSB   Count down every game loop. When it reaches 0 saucer is triggerd. Reset to 600.
+2093   waitStartLoop   1=in wait-for-start loop, 0=in splash screens
+2094   soundPort3      Current status of sound port (out $03)
+2095   changeFleetSnd  Set to 1 in ISR if time to change the fleet sound
+2096   fleetSndCnt     Delay until next fleet movement tone
+2097   fleetSndReload  Reload value for fleet sound counter
+2098   soundPort5      Current status of sound port (out $05)
+2099   extraHold       Duration counter for extra-ship sound
+209A   tilt    1 if tilt handling is in progress
+209B   fleetSndHold    Time to hold fleet-sound at each change
+209C           
+209D           
+209E           
+209F           
+20A0           
+20A1           
+20A2           
+20A3           
+20A4           
+20A5           
+20A6           
+20A7           
+20A8           
+20A9           
+20AA           
+20AB           
+20AC           
+20AD           
+20AE           
+20AF           
+20B0           
+20B1           
+20B2           
+20B3           
+20B4           
+20B5           
+20B6           
+20B7           
+20B8           
+20B9           
+20BA           
+20BB           
+20BC           
+20BD           
+20BE           
+20BF           
+20C0   isrDelay        Delay counter decremented in ISR
+20C1   isrSplashTask   1=In demo, 2=Little-alien and Y, 4=shooting extra 'C'
+20C2   splashAnForm    Image form (increments each draw)
+20C3   splashDeltaX    Delta X
+20C4   splashDeltaY    Delta Y
+20C5   splashYr        Y coordinate
+20C6   splashXr        X coordinate
+20C7   splashImageLSB  
+20C8   splashImageMSB  Base image 1BA0 (small alien with upside down Y)
+20C9   splashImageSize Size of image (16 bytes)
+20CA   splashTargetY   Target Y coordinate
+20CB   splashReached   Reached target Y flag (1 when reached)
+20CC   splashImRestLSB Base image for restore 1BA0 is small alien with upside down Y
+20CD   splashImRestMSB 
+20CE   twoPlayers      1 for yes, 0 means 1 player
+20CF   aShotReloadRate Based on the MSB of the player's score ... how fast the aliens reload their shots
+20D0           ; This is where the alien-sprite-carying-the-Y ...
+20D1           ; ... lives in ROM
+20D2           
+20D3           
+20D4           
+20D5           
+20D6           
+20D7           
+20D8           
+20D9           
+20DA           
+20DB           
+20DC           
+20DD           
+20DE           
+20DF           
+20E0           
+20E1           
+20E2           
+20E3           
+20E4           
+20E5   player1Ex       Extra ship has been awarded = 0
+20E6   player2Ex       Extra ship has been awarded = 0
+20E7   player1Alive    1 if player is alive, 0 if dead (after last man)
+20E8   player2Alive    1 if player is alive, 0 if dead (after last man)
+20E9   suspendPlay     1=game things are moving, 0=game things are suspended
+20EA   coinSwitch      1=switch down, 0=switch up (used to debounce coin switch)
+20EB   numCoins        number of coin credits in BCD format (99 max)
+20EC   splashAnimate   0 for animation during splash and 1 for not. This alternates after every cycle.
+20ED   demoCmdPtrLSB   pointer to demo commands LSB 1663
+20EE   demoCmdPtrMSB   pointer to demo commands MSB
+20EF   gameMode        1=game running, 0=demo or splash screens
+20F0           
+20F1   adjustScore     Set to 1 if score needs adjusting
+20F2   scoreDeltaLSB   Score adjustment (LSB)
+20F3   scoreDeltaMSB   Score adjustment (MSB)
+20F4   HiScorL Hi-score descriptor ... value LSB
+20F5   HiScorM Hi-score descriptor ... value MSB
+20F6   HiScorLoL       Hi-score descriptor ... location LSB
+20F7   HiScorLoM       Hi-score descriptor ... location MSB
+20F8   P1ScorL Hi-score descriptor ... value LSB
+20F9   P1ScorM Hi-score descriptor ... value MSB
+20FA   P1ScorLoL       Hi-score descriptor ... location LSB
+20FB   P1ScorLoM       Hi-score descriptor ... location MSB
+20FC   P2ScorL Hi-score descriptor ... value LSB
+20FD   P2ScorM Hi-score descriptor ... value MSB
+20FE   P2ScorLoL       Hi-score descriptor ... location LSB
+20FF   P2ScorLoM       Hi-score descriptor ... location MSB
+Player 1 specific data
+2100:2136              Player 1 alien ship indicators (0=dead) 11*5 = 55
+2137:2141              Unused 11 bytes (room for another row of aliens?)
+2142:21F1              Player 1 shields remembered between rounds 44 bytes * 4 shields ($B0 bytes)
+21F2:21FA              Unused 9 bytes
+21FB   p1RefAlienDX    Player 1 reference-alien delta X
+21FC   p1RefAlienY     Player 1 reference-alien Y coordinate
+21FD   p1RefAlienX     Player 1 reference-alien X coordiante
+21FE   p1RackCnt       Player 1 rack-count (starts at 0 but get incremented to 1-8)
+21FF   p1ShipsRem      Ships remaining after current dies
+Player 2 specific data
+2200:2236              Player 2 alien ship indicators (0=dead) 11*5 = 55
+2237:2241              Unused 11 bytes (room for another row of aliens?)
+2242:22F1              Player 2 shields remembered between rounds 44 bytes * 4 shields ($B0 bytes)
+22F2:22FA              Unused 9 bytes
+22FB   p2RefAlienDX    Player 2 reference-alien delta X
+22FC   p2RefAlienYr    Player 2 reference-alien Y coordinate
+22FD   p2RefAlienXr    Player 2 reference-alien X coordinate
+22FE   p2RackCnt       Player 2 rack-count (starts at 0 but get incremented to 1-8)
+22FF   p2ShipsRem      Ships remaining after current dies
+Stack
+2300:23DD              Unused (stack space)
+23DE:23FF              In the emulator the stack consumes this area (roughly 16 levels)
diff --git a/doc/space_invaders_overlay.png b/doc/space_invaders_overlay.png
new file mode 100644 (file)
index 0000000..2321594
Binary files /dev/null and b/doc/space_invaders_overlay.png differ
index 6a02f63..5168485 100644 (file)
 #include "stty_sane.h"
 #include "z80/z80.h"
 
+#define INVADERS 1
 #define GALAXIAN 0
-#define PACMAN 1
+#define PACMAN 0
 #define APPLE 0
 
-#if GALAXIAN
+#if INVADERS
+#define INVADERS_WIDTH 224
+#define INVADERS_HEIGHT 256
+
+#define PADDED_WIDTH INVADERS_WIDTH
+#define PADDED_HEIGHT INVADERS_HEIGHT
+
+#define WINDOW_X_SCALE 3
+#define WINDOW_Y_SCALE 3
+#elif GALAXIAN
 #define GALAXIAN_WIDTH 224
 #define GALAXIAN_HEIGHT 256
 
 #define WINDOW_HEIGHT (PADDED_HEIGHT * WINDOW_Y_SCALE)
 
 #define CYCLES_PER_SAMPLE 68 // 44100 Hz @ 3 MHz
+#if INVADERS
+#define SAMPLES_PER_UPDATE 362 // 120 Hz @ 44100 Hz
+#else
 #define SAMPLES_PER_UPDATE 735 // 60 Hz @ 44100 Hz
+#endif
+
+#if INVADERS
+#define INPUT_PORT0 0
+#define INPUT_PORT1 1
+#define INPUT_PORT2 2
+
+#define SHIFT_COUNT 2
+#define SHIFT_INPUT 3
+#define SHIFT_OUTPUT 4
 
-#if GALAXIAN
+#define RAM_START 0x2000
+#define RAM_SIZE 0x2000
+
+#define VIDEO_RAM 0x2400
+#elif GALAXIAN
 #define RAM_START 0x4000
+#define RAM_SIZE 0x1000
+
 #define TILE_RAM 0x5000
 #define SPRITE_RAM 0x5800
 
-#define IO_PAGE 0x6000
+#define IO_START 0x6000
+#define IO_SIZE 0x2000
+
 #define HW_INT_ENABLE 0x6031 // z80 7001
 #define HW_STARS_ENABLE 0x6034 // z80 7004
 #elif PACMAN
 #define INT_VECTOR 0
 
 #define RAM_START 0x4000
+#define RAM_SIZE 0x1000
+
 #define TILE_RAM 0x4000
 #define PALETTE_RAM 0x4400
 #define SPRITE_CONFIG 0x4ff0
 
-#define IO_PAGE 0x5000
+#define IO_START 0x5000
+#define IO_SIZE 0x100
+
 #define HW_INT_ENABLE 0x5100 // z80 5000
 #define SPRITE_COORDS 0x5160 // z80 5060
 #else // APPLE
-#define IO_PAGE 0xe000
+#define IO_START 0xe000
+#define IO_SIZE 0x100
+
 #define HW_KBD 0xe000 // R last key pressed + 128
 #define HW_CLR80COL 0xe000 // W use $C002-C005 for aux mem (80STOREOFF)
 #define HW_SET80COL 0xe001 // W use PAGE2 for aux mem (80STOREON)
@@ -178,6 +215,12 @@ SDL_Renderer *renderer;
 SDL_Texture *texture;
 SDL_Surface *surface;
 uint32_t frame[WINDOW_HEIGHT][WINDOW_WIDTH];
+#if INVADERS
+// false: we will render the top half next
+// true: we will render the bottom half next
+// the rendered version of the other half remains unaltered in frame[]
+bool frame_half;
+#endif
 
 #if APPLE
 // see palette.py
@@ -199,14 +242,20 @@ uint32_t palette[0x10] = {
   0xffbcffe1,
   0xffffffff,
 };
-#endif
 
 // can make this green or amber to be more realistic
 uint32_t mono_palette[2] = {0xff000000, 0xffffffff};
+#endif
 
 z80 cpu;
 
-#if GALAXIAN
+#if INVADERS
+#define ROM_INVADERS_H_ADDR 0
+#define ROM_INVADERS_G_ADDR 0x800
+#define ROM_INVADERS_F_ADDR 0x1000
+#define ROM_INVADERS_E_ADDR 0x1800
+#define MEM_SIZE 0x4000
+#elif GALAXIAN
 #define ROM_GALMIDW_U_ADDR 0
 #define ROM_GALMIDW_V_ADDR 0x800
 #define ROM_GALMIDW_W_ADDR 0x1000
@@ -281,7 +330,21 @@ uint8_t usleep_lo;
 uint8_t dos_lo;
 int usleep_count, exit_flag;
 
-#if GALAXIAN
+#if INVADERS
+uint16_t shift_buffer;
+uint8_t shift_count;
+
+// just for now until we have invaders audio
+#define C0X0_SOFT_SWITCH_TAPEOUT 4
+#define C0X0_SOFT_SWITCH_SPKR 8
+uint8_t c0x0_soft_switches = 0;
+
+// every n cycles, sample the tape and speaker outputs to here
+#define C0X0_SOFT_SWITCHES_BUF_SIZE 0x400 // next power of 2 >= 441 * 2
+int c0x0_soft_switches_buf_head;
+int c0x0_soft_switches_buf_count;
+uint8_t c0x0_soft_switches_buf[C0X0_SOFT_SWITCHES_BUF_SIZE];
+#elif GALAXIAN
 // just for now until we have galaxian audio
 #define C0X0_SOFT_SWITCH_TAPEOUT 4
 #define C0X0_SOFT_SWITCH_SPKR 8
@@ -641,20 +704,30 @@ void dos(char *line) {
 }
 
 uint8_t rb(void *userdata, uint16_t addr0) {
-#if GALAXIAN
+#if INVADERS
   int addr = addr0;
 
-  if (addr < IO_PAGE) {
+  if (addr < RAM_START + RAM_SIZE) { // ROM, RAM
 #if MEM_TRACE
     int pc = cpu.pc;
     fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
 #endif
     return mem[addr];
   }
-  else if (addr < 0x8000 && (addr & 0x7f8) == 0) {
-    addr -= IO_PAGE;
+#elif GALAXIAN
+  int addr = addr0;
+
+  if (addr < RAM_START + RAM_SIZE) { // ROM, RAM
+#if MEM_TRACE
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
+#endif
+    return mem[addr];
+  }
+  if (addr < IO_START + IO_SIZE && (addr & 0x7f8) == 0) { // I/O
+    addr -= IO_START;
     addr = (addr & 7) | ((addr >> 8) & 0x18);
-    addr += IO_PAGE;
+    addr += IO_START;
 #if MEM_TRACE
     int pc = cpu.pc;
     fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
@@ -664,7 +737,7 @@ uint8_t rb(void *userdata, uint16_t addr0) {
 #elif PACMAN
   int addr = addr0;
 
-  if (addr < IO_PAGE + 0x100) {
+  if (addr < IO_START + 0x100) { // ROM, RAM, I/O
 #if MEM_TRACE
     int pc = cpu.pc;
     fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
@@ -686,7 +759,7 @@ uint8_t rb(void *userdata, uint16_t addr0) {
   }
 
   int addr = addr0;
-  if ((addr & 0xff00) != IO_PAGE) {
+  if ((addr & 0xff00) != IO_START) {
 #if APPLE_IIE
     if (addr < 0x200) {
       if (c00x_soft_switches & C00X_SOFT_SWITCH_ALTZP)
@@ -1027,22 +1100,34 @@ uint8_t rb(void *userdata, uint16_t addr0) {
 }
 
 void wb(void *userdata, uint16_t addr0, uint8_t val) {
-#if GALAXIAN
+#if INVADERS
+  int addr = addr0;
+
+  if (addr < RAM_START) // ROM
+    ;
+  else if (addr < RAM_START + RAM_SIZE) { // RAM
+#if MEM_TRACE
+    int pc = cpu.pc;
+    fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
+#endif
+    mem[addr] = val;
+  }
+#elif GALAXIAN
   int addr = addr0;
 
-  if (addr < RAM_START)
+  if (addr < RAM_START) // ROM
     ;
-  else if (addr < IO_PAGE) {
+  else if (addr < RAM_START + RAM_SIZE) { // RAM
 #if MEM_TRACE
     int pc = cpu.pc;
     fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
 #endif
     mem[addr] = val;
   }
-  else if (addr < 0x8000 && (addr & 0x7f8) == 0) {
-    addr -= IO_PAGE;
+  else if (addr < IO_START + IO_SIZE && (addr & 0x7f8) == 0) { // I/O
+    addr -= IO_START;
     addr = (addr & 7) | ((addr >> 8) & 0x18);
-    addr += IO_PAGE | 0x20; // separate read and write registers
+    addr += IO_START | 0x20; // separate read and write registers
 #if MEM_TRACE
     int pc = cpu.pc;
     fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
@@ -1052,10 +1137,10 @@ void wb(void *userdata, uint16_t addr0, uint8_t val) {
 #elif PACMAN
   int addr = addr0;
 
-  if (addr < RAM_START)
+  if (addr < RAM_START) // ROM
     ;
-  else if (addr < IO_PAGE + 0x100) {
-    if (addr >= IO_PAGE)
+  else if (addr < IO_START + 0x100) { // RAM, I/O
+    if (addr >= IO_START)
       addr += 0x100; // separate read and write registers
 #if MEM_TRACE
     int pc = cpu.pc;
@@ -1088,7 +1173,7 @@ void wb(void *userdata, uint16_t addr0, uint8_t val) {
   }
 #endif
 
-  if ((addr & 0xff00) != IO_PAGE) {
+  if ((addr & 0xff00) != IO_START) {
 #if APPLE_IIE
     if (addr < 0x200) {
       if (c00x_soft_switches & C00X_SOFT_SWITCH_ALTZP)
@@ -1268,6 +1353,16 @@ uint8_t in(z80 *const z, uint8_t port) {
 #endif
 
   switch (port) {
+#if INVADERS
+  case INPUT_PORT0:
+    return 0x8f;
+  case INPUT_PORT1:
+    return 0x88;
+  case INPUT_PORT2:
+    return 0;
+  case SHIFT_INPUT:
+    return (uint8_t)(((shift_buffer << shift_count) & 0xff00) >> 8);
+#endif 
   case STDIN_DATA:
     {
       uint8_t data = 'X' - 0x40;
@@ -1324,7 +1419,14 @@ void out(z80 *const z, uint8_t port, uint8_t val) {
 #endif
 
   switch (port) {
-#if PACMAN
+#if INVADERS
+  case SHIFT_COUNT:
+    shift_count = val;
+    break;
+  case SHIFT_OUTPUT:
+    shift_buffer = (shift_buffer >> 8) | (val << 8);
+    break;
+#elif PACMAN
   case INT_VECTOR:
     int_vector = val;
     break;
@@ -1959,10 +2061,46 @@ int main(int argc, char **argv) {
       SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff);
       SDL_RenderClear(renderer);
 
-#if GALAXIAN
+#if INVADERS
+      // send z80 a vertical refresh interrupt
+      int j0, j1;
+      if (frame_half == false) {
+        z80_gen_int(&cpu, 0xcf); // rst 8
+        j0 = 0;
+        j1 = 96;
+        frame_half = true;
+      }
+      else {
+        z80_gen_int(&cpu, 0xd7); // rst 0x10
+        j0 = 96;
+        j1 = INVADERS_WIDTH;
+        frame_half = false;
+      }
+
+      for (int i = 0; i < INVADERS_HEIGHT; ++i) {
+        int y = i * WINDOW_Y_SCALE;
+        int i1 = i ^ 0xff;
+        for (int j = j0; j < j1; ++j) {
+          int x = j * WINDOW_X_SCALE;
+          uint32_t rgb = -(
+            (mem[(i1 >> 3) + (j << 5) + VIDEO_RAM] >> (i1 & 7)) & 1
+          );
+          if (i >= 32 && i < 64)
+            rgb &= 0xffff0000; // red flying saucer area
+          else if (
+            i >= 184 &&
+            (i < 240 || (j >= 25 && j < 136))
+          )
+            rgb &= 0xff00ff00; // green base and lives area
+          for (int k = 0; k < WINDOW_Y_SCALE; ++k)
+            for (int l = 0; l < WINDOW_X_SCALE; ++l)
+              frame[y + k][x + l] = rgb;
+        }
+      }
+#elif GALAXIAN
       // send z80 a vertical refresh interrupt
       if (mem[HW_INT_ENABLE] & 1)
-        cpu.nmi_pending = true;
+        z80_gen_nmi(&cpu);
 
       // draw stars
       if (mem[HW_STARS_ENABLE] & 1) {
@@ -2157,10 +2295,8 @@ int main(int argc, char **argv) {
       } 
 #elif PACMAN
       // send z80 a vertical refresh interrupt
-      if (mem[HW_INT_ENABLE] & 1) {
-        cpu.int_pending = true;
-        cpu.int_data = int_vector;
-      }
+      if (mem[HW_INT_ENABLE] & 1)
+        z80_gen_int(&cpu, int_vector);
 
       // draw tiles
       for (int i = 0; i < 36; ++i)
diff --git a/invaders/Makefile b/invaders/Makefile
new file mode 100644 (file)
index 0000000..ec63935
--- /dev/null
@@ -0,0 +1,39 @@
+# need to install intelhex package in Python first:
+#   pip3 install --user intelhex
+BIN2HEX=bin2hex.py
+
+ROM_INVADERS_H_ADDR=0
+ROM_INVADERS_G_ADDR=0x800
+ROM_INVADERS_F_ADDR=0x1000
+ROM_INVADERS_E_ADDR=0x1800
+
+ROMS= \
+invaders.h \
+invaders.g \
+invaders.f \
+invaders.e
+
+all: invaders0.ihx
+
+invaders0.ihx: ${ROMS:%=%.ihx}
+       hexmerge.py -o $@ $^
+
+invaders.h.ihx: invaders.h
+       ${BIN2HEX} --offset=${ROM_INVADERS_H_ADDR} $< $@
+
+invaders.g.ihx: invaders.g
+       ${BIN2HEX} --offset=${ROM_INVADERS_G_ADDR} $< $@
+
+invaders.f.ihx: invaders.f
+       ${BIN2HEX} --offset=${ROM_INVADERS_F_ADDR} $< $@
+
+invaders.e.ihx: invaders.e
+       ${BIN2HEX} --offset=${ROM_INVADERS_E_ADDR} $< $@
+
+${ROMS}: ../orig/invaders.zip
+       rm -f ${ROMS}
+       unzip -j $< ${ROMS}
+       touch ${ROMS}
+
+clean:
+       rm -f *.ihx ${ROMS}
index 757c7a3..7411145 100644 (file)
@@ -1,6 +1,7 @@
 .PHONY: all
 all: \
 galaxian.zip \
+invaders.zip \
 mspacman.zip \
 pacman.zip
 
@@ -8,6 +9,11 @@ galaxian.zip:
        rm -f $@
        wget https://archive.org/download/Namco-Classics-MAME-Roms/$@
 
+# actually Space Invaders M (Midway licensed; usual US version)
+invaders.zip:
+       rm -f $@
+       wget https://archive.org/download/arcade_invaders/$@
+
 mspacman.zip:
        rm -f $@
        wget https://archive.org/download/Namco-Classics-MAME-Roms/$@
@@ -22,5 +28,6 @@ clean:
 realclean:
        rm -f \
 galaxian.zip \
+invaders.zip \
 mspacman.zip \
 pacman.zip