;-------------------------------;
; 9k Space Invaders Version 1.1 ;
;                               ;
; Copyright (c) by Paul S. Reid ;
;      All rights reserved.     ;
;-------------------------------;

CODE_SEG                SEGMENT
                        ASSUME  CS:CODE_SEG,DS:CODE_SEG
                        ORG     100h

BEGIN:

;----------------------------------------------------------------------------------------------------------------------------------
; 6k Space Invaders
;----------------------------------------------------------------------------------------------------------------------------------

Start                   PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AH,0
                        MOV     AL,13h
                        INT     10h

                        CALL    InstallNewInt9          ; Install game keyboard handler
; Seed random number generator with clock
                        MOV     AX,040h
                        MOV     ES,AX
                        MOV     AX,ES:[06ch]
                        MOV     Seed,AX
; Set color palette
                        MOV     AX,CS                   ; Segment of palette buffer
                        MOV     ES,AX                   ; in ES
                        MOV     DX,OFFSET Palette       ; Offset of palette buffer in DX
                        MOV     AH,10h                  ; Function 10h (Get/set palette registers)
                        MOV     AL,12h                  ; Subfunction 12h (Set block of color registers)
                        MOV     BX,00h                  ; First color register to set
                        MOV     CX,05bh                 ; Number of color registers to set (255 = all of them)
                        INT     10h                     ; Set registers
; Draw top and bottom borders
                        MOV     AX,0a000h       ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        MOV     DI,0            ; Store address in destination register
                        MOV     CX,10240        ; 32 lines
DrawTop:                MOV     BX,0008fh       ; Random number between 0 and 20 in AX
                        MOV     TempStore,CX
                        CALL    Random          ; Call random routine
                        CMP     RandomNumber,1
                        JNZ     NoStar
                        MOV     AL,12
                        JMP     DrawTop2
NoStar:                 MOV     AL,8
DrawTop2:               STOSB
                        MOV     CX,TempStore
                        LOOP    DrawTop
                        MOV     DI,54400        ; Store address in destination register
                        MOV     CX,9600         ; 32 lines
DrawBottom:             MOV     BX,0008fh       ; Random number between 0 and 20 in AX
                        MOV     TempStore,CX
                        CALL    Random          ; Call random routine
                        CMP     RandomNumber,1
                        JNZ     NoStar2
                        MOV     AL,12
                        JMP     DrawBottom2
NoStar2:                MOV     AL,8
DrawBottom2:            STOSB
                        MOV     CX,TempStore
                        LOOP    DrawBottom
;Draw Invaders logo
                        LEA     AX,LogoOutline      ; Get address of sprite
                        MOV     BX,74               ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,10               ; Get color to draw sprite
                        CALL    DrawLogoLayer       ; Draw sprite
                        LEA     AX,LogoShadow       ; Get address of sprite
                        MOV     BX,74               ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,9                ; Get color to draw sprite
                        CALL    DrawLogoLayer       ; Draw sprite
                        LEA     AX,LogoLetters      ; Get address of sprite
                        MOV     BX,74               ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,11               ; Get color to draw sprite
                        CALL    DrawLogoLayer       ; Draw sprite

                        JMP     TitleScreen
; Clear video buffer
StartGame:              CALL    ResetGame

                        MOV     AX,CS           ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        LEA     DI,VideoBuffer  ; Store address in destination register
                        MOV     CX,21760        ; 136 lines (160 * 136)
                        MOV     AX,0
ClearAll2:              STOSW
                        LOOP    ClearAll2

                        CALL    DisplayStatus

; Outter game loop

RedrawBunkers:          CALL    DrawBunkers
                        MOV     FirstFrame,1

; Inner game loop

NoExit:                 LEA     AX,PlayersShip      ; Get address of sprite
                        MOV     BX,PlayerX          ; Get X position to draw sprite at
                        MOV     DL,130              ; Get Y position to draw sprite at
                        MOV     DH,1                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        CALL    CheckPlayerDead
                        MOV     AX,OFFSET Score[0]
                        MOV     ScoreValueOffset,AX
                        MOV     ScoreXOffset,67
                        CALL    DisplayScore
                        CALL    UpdateHighScore
                        MOV     AX,OFFSET HighS[0]
                        MOV     ScoreValueOffset,AX
                        MOV     ScoreXOffset,161
                        CALL    DisplayScore
; Prepare for buffer blit
                        LEA     SI,VideoBuffer
                        MOV     DI,10560        ; Store address in destination register
                        MOV     AX,0a000h       ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        MOV     CX,21760        ; 150 lines (136 * 150)
; Check vertical retrace
                        MOV             DX,03DAh            ; Get vertical retrace port address in DX
;RetraceStart:           IN             AL,DX               ; Grab retrace information
;                        TEST   AL,8                ; Did it start yet?
;                        JNZ            RetraceStart        ; No, wait until it does
RetraceEnd:             IN              AL,DX               ; Grab retrace information again
                        TEST    AL,8                ; Did it end yet?
                        JZ              RetraceEnd          ; No, loop until it does
; Blit buffer to video memory
BlitAll:                MOVSW
                        LOOP    BlitAll

                        CMP     FirstFrame,1
                        JNZ     NoFirstFrame
                        CALL    DrawInvaders
                        LEA     AX,GetReady
                        MOV     BX,82
                        MOV     DL,20
                        MOV     DH,7
                        CALL    PrintText
                        MOV     AH,0
                        INT     01ah
                        ADD     DL,18
                        MOV     PauseCounter,DL
Wait1:                  MOV     AH,0
                        INT     01ah
                        CMP     DL,PauseCounter
                        JNZ     Wait1
                        LEA     AX,GetReady
                        MOV     BX,82
                        MOV     DL,20
                        MOV     DH,0
                        CALL    PrintText
                        MOV     FirstFrame,0

NoFirstFrame:           CMP     SoundToggle,1
                        JNZ     NoSoundToggle
                        MOV     SoundToggle,0
                        XOR     Sound,080h

NoSoundToggle:          CALL    EraseInvaders
                        DEC     MoveCount
                        JNZ     NoInvaderMove
                        CALL    MoveInvaders

NoInvaderMove:          CMP     FireToggle,1
                        JNZ     NoFire
                        CMP     MissileX,0
                        JNZ     NoFire
                        CALL    ShootPlayerMissile

NoFire:                 CALL    DrawInvaders

                        CMP     MissileX,0
                        JZ      NoMissile
                        CALL    MovePlayerMissile

                        CMP     Collision,0
                        JZ      NoMissile
                        CALL    EraseInvaders
                        MOV     AX,OFFSET Score[0]
                        MOV     ScoreValueOffset,AX
                        MOV     ScoreXOffset,67
                        CALL    EraseScore
                        MOV     AX,OFFSET HighS[0]
                        MOV     ScoreValueOffset,AX
                        MOV     ScoreXOffset,161
                        CALL    EraseScore
                        CALL    CheckInvaderKill
                        CALL    DrawInvaders
                        MOV     Collision,0     ; Reset collision flag

NoMissile:              CMP     NextLevelToggle,0
                        JZ      NoNextLevel
                        CALL    NextLevel
                        JMP     RedrawBunkers

NoNextLevel:            CMP     PlayerDead,0
                        JZ      NoPlayerDead
                        JMP     KillPlayer

NoPlayerDead:           MOV     BX,0ffffh       ; Random number between 0 and 20 in AX
                        CALL    Random          ; Call random routine
                        CMP     RandomNumber[0],1
                        JNZ     NoMakeUFO
                        CMP     UFOX,0
                        JNZ     NoMakeUFO
                        DEC     UFOCounter
                        CMP     UFOCounter,0
                        JNZ     NoMakeUFO
                        MOV     UFOCounter,6
                        MOV     UFOX,50

NoMakeUFO:              CMP     UFOX,0
                        JZ      NoUFO
                        CALL    MoveUFO

NoUFO:                  MOV     BX,BombFreq     ; Random number between 0 and 20 in AX
                        CALL    Random          ; Call random routine
                        CMP     RandomNumber[0],1
                        JNZ     NoInvaderBomb
                        CALL    InvaderBomb

NoInvaderBomb:          DEC     BombMove
                        CMP     BombMove,0
                        JNZ     NoMoveBombs
                        MOV     AL,BombSpeed
                        MOV     BombMove,AL
                        CALL    MoveBombs

NoMoveBombs:            LEA     AX,PlayersShip      ; Get address of sprite
                        MOV     BX,PlayerX          ; Get X position to draw sprite at
                        MOV     DL,130              ; Get Y position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite

                        CMP     LeftToggle,1
                        JNZ     NoLeft
                        CALL    MovePlayerLeft

NoLeft:                 CMP     RightToggle,1
                        JNZ     NoRight
                        CALL    MovePlayerRight

NoRight:                CMP     ExitToggle,1
                        JZ      Exit
                        JMP     NoExit

; Clean up and exit

Exit:                   CALL    RemoveNewInt9

                        MOV     AH,0
                        MOV     AL,3
                        INT     10h

                        MOV     AH,4Ch          ; Exit function
                        INT     21h             ; Call DOS for exit

Start                   ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Update High Score
;----------------------------------------------------------------------------------------------------------------------------------

UpdateHighScore         PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AL,Score[0]
                        CMP     AL,HighS[0]
                        JZ      NextDigit1
                        JA      Update
                        JMP     NoUpdate
NextDigit1:             MOV     AL,Score[1]
                        CMP     AL,HighS[1]
                        JZ      NextDigit2
                        JA      Update
                        JMP     NoUpdate
NextDigit2:             MOV     AL,Score[2]
                        CMP     AL,HighS[2]
                        JZ      NextDigit3
                        JA      Update
                        JMP     NoUpdate
NextDigit3:             MOV     AL,Score[3]
                        CMP     AL,HighS[3]
                        JZ      NextDigit4
                        JA      Update
                        JMP     NoUpdate
NextDigit4:             MOV     AL,Score[4]
                        CMP     AL,HighS[4]
                        JA      Update
                        JMP     NoUpdate

Update:                 MOV     AL,Score[0]
                        MOV     HighS[0],AL
                        MOV     AL,Score[1]
                        MOV     HighS[1],AL
                        MOV     AL,Score[2]
                        MOV     HighS[2],AL
                        MOV     AL,Score[3]
                        MOV     HighS[3],AL
                        MOV     AL,Score[4]
                        MOV     HighS[4],AL

NoUpdate:               RET

UpdateHighScore         ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Display Status
;----------------------------------------------------------------------------------------------------------------------------------

DisplayStatus           PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

; Display "SCORE"
                        LEA     AX,SCO              ; Get address of sprite
                        MOV     BX,30               ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,5                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        LEA     AX,ORE              ; Get address of sprite
                        MOV     BX,46               ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,5                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        MOV     AX,OFFSET Score[0]
                        MOV     ScoreValueOffset,AX
                        MOV     ScoreXOffset,67
                        CALL    DisplayScore
; Display "HIGH"
                        LEA     AX,HIG              ; Get address of sprite
                        MOV     BX,130              ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,5                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        LEA     AX,GH               ; Get address of sprite
                        MOV     BX,146              ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,5                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        MOV     AX,OFFSET HighS[0]
                        MOV     ScoreValueOffset,AX
                        MOV     ScoreXOffset,161
                        CALL    DisplayScore
; Display lives
                        LEA     AX,PlayersShip      ; Get address of sprite
                        MOV     BX,266              ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,5                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        LEA     AX,Equal            ; Get address of sprite
                        MOV     BX,278              ; Get X position to draw sprite at
                        MOV     DL,0                ; Get Y position to draw sprite at
                        MOV     DH,5                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        MOV     AL,Lives
                        MOV     BX,285
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit

                        RET

DisplayStatus           ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Reset Game
;----------------------------------------------------------------------------------------------------------------------------------

ResetGame               PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     Frame,0

                        MOV     InvadersX,275
                        MOV     InvadersY,30
                        MOV     InvadersToggle[0],07ff0h
                        MOV     InvadersToggle[2],07ff0h
                        MOV     InvadersToggle[4],07ff0h
                        MOV     InvadersToggle[6],07ff0h
                        MOV     InvadersToggle[8],07ff0h
                        MOV     PlayerX,154
                        MOV     LeftToggle,0
                        MOV     RightToggle,0
                        MOV     FireToggle,0
                        MOV     ExitToggle,0
                        MOV     NextLevelToggle,0
                        MOV     MissileX,0
                        MOV     MissileY,0
                        MOV     UFOX,0
                        MOV     AX,CS           ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        LEA     DI,BombX
                        MOV     CX,22
                        MOV     AX,0
ClearLoop1:             STOSW
                        LOOP    ClearLoop1
                        LEA     DI,BombY
                        MOV     CX,22
ClearLoop2:             STOSB
                        LOOP    ClearLoop2
                        LEA     DI,BombType
                        MOV     CX,22
ClearLoop3:             STOSB
                        LOOP    ClearLoop3
                        MOV     BombFreq,010h
                        MOV     MoveCount,1
                        MOV     InvaderSpeed,55
                        MOV     Direction,0
                        MOV     Reversing,0
                        MOV     Collision,0
                        MOV     Score[0],48
                        MOV     Score[1],48
                        MOV     Score[2],48
                        MOV     Score[3],48
                        MOV     Score[4],48
                        MOV     Lives,51
                        MOV     BombMove,2
                        MOV     BombSpeed,2
                        MOV     PlayerDead,0
                        MOV     GameOverToggle,0
                        MOV     CurrentInvaderSpeed,55
                        MOV     CurrentInvaderY,30
                        MOV     CurrentBombFreq,010h

                        RET

ResetGame               ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Print Text
;----------------------------------------------------------------------------------------------------------------------------------

PrintText               PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     LetterCounter,AX
                        MOV     LetterXPos,BX
                        MOV     LetterYPos,DL
                        MOV     LetterColor,DH
                        SUB     LetterXPos,6

                        CMP     KeyPress,1
                        JNZ     PrintNext

                        MOV     KeyPress,0

                        CMP     ExitToggle,1
                        JNZ     NotExit2
                        JMP     Exit

NotExit2:               CMP     SoundToggle,1
                        JNZ     NotSound
                        MOV     SoundToggle,0
                        XOR     Sound,080h
                        JMP     PrintNext

NotSound:               CMP     GameStart,1
                        JNZ     PrintNext
                        MOV     GameStart,0
                        JMP     StartGame

PrintNext:              MOV     SI,LetterCounter
                        LODSB
                        INC     LetterCounter
                        ADD     LetterXPos,6
                        CMP     AL,0
                        JZ      DonePrinting
                        CMP     AL,32
                        JZ      PrintNext
                        MOV     BX,LetterXPos
                        MOV     DL,LetterYPos
                        MOV     DH,LetterColor
                        CALL    DisplayDigit
                        LEA     SI,VideoBuffer
                        MOV     DI,10560        ; Store address in destination register
                        MOV     AX,0a000h       ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        MOV     CX,21760        ; 150 lines (136 * 150)
                        MOV             DX,03DAh        ; Get vertical retrace port address in DX
RetraceEnd3:            IN              AL,DX           ; Grab retrace information again
                        TEST    AL,8            ; Did it end yet?
                        JZ              RetraceEnd3     ; No, loop until it does
BlitAll3:               MOVSW
                        LOOP    BlitAll3
                        JMP     PrintNext

DonePrinting:           RET

LetterCounter           DW      0
LetterXPos              DW      0
LetterYPos              DB      0
LetterColor             DB      0

PrintText               ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Title Screen - Never Returns!
;----------------------------------------------------------------------------------------------------------------------------------

TitleScreen             PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

; Clear video buffer
                        MOV     AX,CS           ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        LEA     DI,VideoBuffer  ; Store address in destination register
                        MOV     CX,21760        ; 136 lines (160 * 136)
                        MOV     AX,0
ClearAll:               STOSW
                        LOOP    ClearAll

                        MOV     KeyPress,0
                        MOV     GameStart,1

                        CALL    DisplayStatus

                        LEA     AX,InvadersTitle
                        MOV     BX,40
                        MOV     DL,20
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,Copyright
                        MOV     BX,0
                        MOV     DL,30
                        MOV     DH,030h
                        CALL    PrintText

                        LEA     AX,UFO              ; Get address of sprite
                        MOV     DL,50               ; Get Y position to draw sprite at
                        MOV     DH,3                ; Get color to draw sprite
                        MOV     BX,100              ; Get X position to draw sprite at
                        CALL    DrawLetter          ; Draw sprite
                        LEA     AX,UFOScore
                        MOV     BX,137
                        MOV     DL,50
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,TopInvader1      ; Get address of sprite
                        MOV     DL,60               ; Get Y position to draw sprite at
                        MOV     DH,010h             ; Get color to draw sprite
                        MOV     BX,103              ; Get X position to draw sprite at
                        CALL    DrawLetter          ; Draw sprite
                        LEA     AX,Row1Score
                        MOV     BX,137
                        MOV     DL,60
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,MiddleInvader2   ; Get address of sprite
                        MOV     DL,70               ; Get Y position to draw sprite at
                        MOV     DH,020h             ; Get color to draw sprite
                        MOV     BX,103              ; Get X position to draw sprite at
                        CALL    DrawLetter          ; Draw sprite
                        LEA     AX,Row2Score
                        MOV     BX,137
                        MOV     DL,70
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,MiddleInvader1   ; Get address of sprite
                        MOV     DL,80               ; Get Y position to draw sprite at
                        MOV     DH,030h             ; Get color to draw sprite
                        MOV     BX,103              ; Get X position to draw sprite at
                        CALL    DrawLetter          ; Draw sprite
                        LEA     AX,Row3Score
                        MOV     BX,137
                        MOV     DL,80
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,BottomInvader1   ; Get address of sprite
                        MOV     DL,90               ; Get Y position to draw sprite at
                        MOV     DH,040h             ; Get color to draw sprite
                        MOV     BX,103              ; Get X position to draw sprite at
                        CALL    DrawLetter          ; Draw sprite
                        LEA     AX,Row4Score
                        MOV     BX,137
                        MOV     DL,90
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,BottomInvader1   ; Get address of sprite
                        MOV     DL,100              ; Get Y position to draw sprite at
                        MOV     DH,050h             ; Get color to draw sprite
                        MOV     BX,103              ; Get X position to draw sprite at
                        CALL    DrawLetter          ; Draw sprite
                        LEA     AX,Row5Score
                        MOV     BX,137
                        MOV     DL,100
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,StartDocs
                        MOV     BX,0
                        MOV     DL,119
                        MOV     DH,050h
                        CALL    PrintText

                        LEA     AX,Distribution
                        MOV     BX,4
                        MOV     DL,129
                        MOV     DH,7
                        CALL    PrintText

                        MOV     GameStart,0

                        MOV     AH,0
                        INT     01ah
                        INC     DH
                        MOV     PauseCounter,DH

GetKey:                 CMP     KeyPress,1
                        JZ      KeyWasPressed

                        MOV     AH,0
                        INT     01ah
                        CMP     DH,PauseCounter
                        JNZ     GetKey
                        JMP     TitleScreen2

KeyWasPressed:          CMP     ExitToggle,1
                        JNZ     NotExit
                        JMP     Exit

NotExit:                CMP     SoundToggle,1
                        JNZ     NotSound2
                        MOV     SoundToggle,0
                        XOR     Sound,080h
                        JMP     GetKey

NotSound2:              JMP     StartGame

TitleScreen             ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Title Screen 2 - Never Returns!
;----------------------------------------------------------------------------------------------------------------------------------

TitleScreen2            PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

; Clear video buffer
                        MOV     AX,CS           ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        LEA     DI,VideoBuffer  ; Store address in destination register
                        MOV     CX,21760        ; 136 lines (160 * 136)
                        MOV     AX,0
ClearAllZ:              STOSW
                        LOOP    ClearAllZ

                        MOV     KeyPress,0
                        MOV     GameStart,1

                        CALL    DisplayStatus

                        LEA     AX,InvadersTitle
                        MOV     BX,40
                        MOV     DL,20
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,Copyright
                        MOV     BX,0
                        MOV     DL,30
                        MOV     DH,030h
                        CALL    PrintText

                        LEA     AX,Dedication
                        MOV     BX,70
                        MOV     DL,50
                        MOV     DH,010h
                        CALL    PrintText

                        LEA     AX,ThankYou
                        MOV     BX,64
                        MOV     DL,70
                        MOV     DH,010h
                        CALL    PrintText

                        LEA     AX,SoundTog
                        MOV     BX,55
                        MOV     DL,90
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,PlayKeys
                        MOV     BX,31
                        MOV     DL,100
                        MOV     DH,7
                        CALL    PrintText

                        LEA     AX,StartDocs
                        MOV     BX,0
                        MOV     DL,119
                        MOV     DH,050h
                        CALL    PrintText

                        LEA     AX,Distribution
                        MOV     BX,4
                        MOV     DL,129
                        MOV     DH,7
                        CALL    PrintText

                        MOV     GameStart,0

                        MOV     AH,0
                        INT     01ah
                        INC     DH
                        MOV     PauseCounter,DH

GetKey2:                CMP     KeyPress,1
                        JZ      KeyWasPressed2

                        MOV     AH,0
                        INT     01ah
                        CMP     DH,PauseCounter
                        JNZ     GetKey2
                        JMP     TitleScreen

KeyWasPressed2:         CMP     ExitToggle,1
                        JNZ     NotExitZ
                        JMP     Exit

NotExitZ:               CMP     SoundToggle,1
                        JNZ     NotSound3
                        MOV     SoundToggle,0
                        XOR     Sound,080h
                        JMP     GetKey2

NotSound3:              JMP     StartGame

TitleScreen2            ENDP

; Draw Letter with pause

DrawLetter              PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        CALL    DrawSprite      ; Draw sprite
; Prepare for buffer blit
                        LEA     SI,VideoBuffer
                        MOV     DI,10560        ; Store address in destination register
                        MOV     AX,0a000h       ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register
                        MOV     CX,21760        ; 150 lines (136 * 150)
; Check vertical retrace
                        MOV             DX,03DAh        ; Get vertical retrace port address in DX
RetraceEnd2:            IN              AL,DX           ; Grab retrace information again
                        TEST    AL,8            ; Did it end yet?
                        JZ              RetraceEnd2     ; No, loop until it does
; Blit buffer to video memory
BlitAll2:               MOVSW
                        LOOP    BlitAll2

NoKey:                  MOV     AH,0
                        INT     01ah
                        ADD     DL,3
                        MOV     PauseCounter,DL
Wait2:                  MOV     AH,0
                        INT     01ah
                        CMP     DL,PauseCounter
                        JNZ     Wait2

                        RET

DrawLetter              ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Game Over - Never Returns!
;----------------------------------------------------------------------------------------------------------------------------------

GameOver                PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     GameOverToggle,1

                        LEA     AX,GameOverMsg
                        MOV     BX,82
                        MOV     DL,20
                        MOV     DH,7
                        CALL    PrintText

                        MOV     GameOverToggle,0
                        MOV     AH,0
                        INT     01ah
                        ADD     DL,180
                        MOV     PauseCounter,DL
Wait3:                  MOV     AH,0
                        INT     01ah
                        CMP     DL,PauseCounter
                        JNZ     Wait3

                        JMP     TitleScreen

GameOver                ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Kill Player - Never returns!
;----------------------------------------------------------------------------------------------------------------------------------

KillPlayer              PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AL,Lives
                        MOV     BX,285
                        MOV     DL,0
                        MOV     DH,0
                        CALL    DisplayDigit
                        DEC     Lives
                        MOV     AL,Lives
                        MOV     BX,285
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit

                        CMP     Lives,48
                        JNZ     LifeLeft
; No life left - Wait for key before exiting game
                        JMP     GameOver
; Life left - Pause before continuing
LifeLeft:               MOV     AH,0
                        INT     01ah
                        ADD     DL,18
                        MOV     PauseCounter,DL
Wait4:                  MOV     AH,0
                        INT     01ah
                        CMP     DL,PauseCounter
                        JNZ     Wait4
                        CALL    EraseInvaders
                        CALL    ResetLevel

                        MOV     BX,0
Search3:                CMP     [BombY+BX],0
                        JNZ     KillBomb2
                        JMP     NoFoundSlot1

KillBomb2:              MOV     KillBombs,BX
                        MOV     DL,[BombY+BX]       ; Get Y position to draw sprite at
                        CMP     [BombType+BX],0
                        JZ      AnimatedBomb4
                        LEA     AX,StraightMissile  ; Get address of sprite
                        JMP     AllDone4
AnimatedBomb4:          CMP     Frame,1
                        JNZ     IsFrame004
                        LEA     AX,TwistedMissile1  ; Get address of sprite
                        JMP     AllDone4
IsFrame004:             LEA     AX,TwistedMissile2  ; Get address of sprite
AllDone4:               SHL     BX,1
                        MOV     BX,[BombX+BX]       ; Get X position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite
                        MOV     BX,KillBombs
                        MOV     [BombY+BX],0        ; Get X position to draw sprite at

NoFoundSlot1:           INC     BX
                        CMP     BX,22
                        JZ      AllBombsDead
                        JMP     Search3

AllBombsDead:           JMP     RedrawBunkers

KillBombs               DW      0

KillPlayer              ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Drop Invader Bomb
;----------------------------------------------------------------------------------------------------------------------------------

InvaderBomb             PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     BX,0002h
                        CALL    Random
;------------------------------------------------------------------
;                        CMP     RandomNumber[0],0
;                        JNZ     NoGood
;                        MOV     DL,83
;                        MOV     AH,2
;                        INT     21h
;                        JMP     Good
;NoGood:                 MOV     DL,32
;                        MOV     AH,2
;                        INT     21h
;Good:                   MOV     DL,00dh
;                        MOV     AH,2
;                        INT     21h
;------------------------------------------------------------------
                        MOV     DH,RandomNumber[0]
                        MOV     TempRand,DH
                        MOV     BX,0000bh       ; Random number between 0 and 11 in AX
                        CALL    Random          ; Call random routine
                        MOV     AX,08000h
                        MOV     CH,0
                        MOV     CL,RandomNumber[0]
                        INC     CX
LoopingZ:               SHR     AX,1
                        LOOP    LoopingZ
                        MOV     DL,0
                        TEST    InvadersToggle[8],AX
                        JZ      NoRow5Invader
                        MOV     DL,44
                        JMP     FoundY
NoRow5Invader:          TEST    InvadersToggle[6],AX
                        JZ      NoRow4Invader
                        MOV     DL,34
                        JMP     FoundY
NoRow4Invader:          TEST    InvadersToggle[4],AX
                        JZ      NoRow3Invader
                        MOV     DL,24
                        JMP     FoundY
NoRow3Invader:          TEST    InvadersToggle[2],AX
                        JZ      NoRow2Invader
                        MOV     DL,14
                        JMP     FoundY
NoRow2Invader:          TEST    InvadersToggle[0],AX
                        JZ      NoInvaders
                        MOV     DL,4

FoundY:                 MOV     AL,RandomNumber[0]
                        MOV     AH,0
                        MOV     CL,16
                        MUL     CL

                        ADD     AX,InvadersX
                        SUB     AX,200
                        ADD     DL,InvadersY

; AX Holds X, DL holds Y of bomb start position

                        MOV     BX,0
Search:                 CMP     [BombY+BX],0
                        JZ      FoundSlot
                        INC     BX
                        CMP     BX,22
                        JNZ     Search
                        JMP     NoInvaders

; BX Holds offset (bomb number)

FoundSlot:              MOV     [BombY+BX],DL
                        MOV     DH,TempRand
                        MOV     [BombType+BX],DH
                        SHL     BX,1
                        MOV     [BombX+BX],AX

NoInvaders:             RET

TempRand                DB      0

InvaderBomb             ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Move Invader Bombs
;----------------------------------------------------------------------------------------------------------------------------------

MoveBombs               PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     BX,0
Search2:                CMP     [BombY+BX],0
                        JNZ     GotSlot
                        JMP     NoFoundSlot

GotSlot:                MOV     TempCounter,BX
                        MOV     DL,[BombY+BX]       ; Get Y position to draw sprite at
                        CMP     [BombType+BX],0
                        JZ      AnimatedBomb1
                        LEA     AX,StraightMissile  ; Get address of sprite
                        JMP     AllDone1
AnimatedBomb1:          CMP     Frame,1
                        JNZ     IsFrame001
                        LEA     AX,TwistedMissile1  ; Get address of sprite
                        JMP     AllDone1
IsFrame001:             LEA     AX,TwistedMissile2  ; Get address of sprite
AllDone1:               SHL     BX,1
                        MOV     BX,[BombX+BX]       ; Get X position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite
                        MOV     BX,TempCounter
                        INC     [BombY+BX]
                        INC     [BombY+BX]
                        CMP     [BombY+BX],130
                        JNZ     DrawNextFrameA
                        MOV     [BombY+BX],0
                        JMP     NoFoundSlot
DrawNextFrameA:         MOV     DL,[BombY+BX]       ; Get Y position to draw sprite at
                        CMP     [BombType+BX],0
                        JZ      AnimatedBomb2
                        LEA     AX,StraightMissile  ; Get address of sprite
                        JMP     AllDone2
AnimatedBomb2:          CMP     Frame,1
                        JNZ     IsFrame002
                        LEA     AX,TwistedMissile1  ; Get address of sprite
                        JMP     AllDone2
IsFrame002:             LEA     AX,TwistedMissile2  ; Get address of sprite
AllDone2:               SHL     BX,1
                        MOV     BX,[BombX+BX]       ; Get X position to draw sprite at
                        MOV     DH,06h              ; Get color to draw sprite
                        MOV     Collision,0
                        CALL    DrawSprite          ; Draw sprite
                        CMP     Collision,1
                        JNZ     NoDeadPlayer
                        JMP     KillPlayer
NoDeadPlayer:           CMP     Collision,2
                        JZ      KillBomb
                        CMP     Collision,4
                        JNZ     NoAction
KillBomb:               MOV     BX,TempCounter
                        MOV     DL,[BombY+BX]       ; Get Y position to draw sprite at
                        CMP     [BombType+BX],0
                        JZ      AnimatedBomb3
                        LEA     AX,StraightMissile  ; Get address of sprite
                        JMP     AllDone3
AnimatedBomb3:          CMP     Frame,1
                        JNZ     IsFrame003
                        LEA     AX,TwistedMissile1  ; Get address of sprite
                        JMP     AllDone3
IsFrame003:             LEA     AX,TwistedMissile2  ; Get address of sprite
AllDone3:               SHL     BX,1
                        MOV     BX,[BombX+BX]       ; Get X position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite
                        MOV     BX,TempCounter
                        MOV     [BombY+BX],0        ; Get X position to draw sprite at
                        CMP     Collision,4
                        JNZ     NoAction
                        CALL    KillMissile
NoAction:               MOV     Collision,0
                        MOV     BX,TempCounter

NoFoundSlot:            INC     BX
                        CMP     BX,22
                        JZ      DoneMoveBombs
                        JMP     Search2

DoneMoveBombs:          RET

TempCounter             DW      0

MoveBombs               ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Move UFO
;----------------------------------------------------------------------------------------------------------------------------------

MoveUFO                 PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        DEC     UFOMove
                        CMP     UFOMove,0
                        JNZ     DoneUFO
                        MOV     UFOMove,2

                        LEA     AX,UFO              ; Get address of sprite
                        MOV     BX,UFOX             ; Get X position to draw sprite at
                        MOV     DL,10               ; Get Y position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite

                        INC     UFOX
                        CMP     UFOX,254
                        JNZ     DoNextUFOFrame
                        MOV     UFOX,0
                        JMP     DoneUFO

DoNextUFOFrame:         LEA     AX,UFO              ; Get address of sprite
                        MOV     BX,UFOX             ; Get X position to draw sprite at
                        MOV     DL,10               ; Get Y position to draw sprite at
                        MOV     DH,3                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

; Make sound

                        TEST    Sound,080h
                        JZ      NoSound1

                        MOV     AL,0b6h
                        OUT     043h,AL
                        MOV     AL,090h
                        OUT     042h,AL
                        MOV     AL,000h
                        OUT     042h,AL
                        IN      AL,061h
                        OR      AL,3
                        OUT     061h,AL

NoSound1:               MOV     CX,08000h
TimerZ:                 LOOP    TimerZ

                        IN      AL,061h
                        AND     AL,0fch
                        OUT     061h,AL

DoneUFO:                RET

UFOMove                 DB      2
UFOCounter              DB      6

MoveUFO                 ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Generate Random Number
;----------------------------------------------------------------------------------------------------------------------------------

Random                  PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AX,Seed
                        MUL     BX
                        MOV     CX,65531
                        DIV     CX
                        MOV     Seed,DX
                        MOV     RandomNumber[0],AL

                        RET

Seed                    DW      0
RandomNumber            DB      0

Random                  ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Next Level
;----------------------------------------------------------------------------------------------------------------------------------

NextLevel               PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        DEC     CurrentInvaderSpeed
                        ADD     CurrentInvaderY,002h
                        CMP     CurrentBombFreq,002h
                        JZ      NoDecrease
                        DEC     CurrentBombFreq

NoDecrease:             CALL    ResetLevel

                        RET

NextLevel               ENDP

; Reset Level

ResetLevel              PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     PlayerDead,0
                        MOV     NextLevelToggle,0
                        MOV     Frame,0
                        MOV     InvadersX,275
                        MOV     AL,CurrentInvaderY
                        MOV     InvadersY,AL
                        MOV     InvadersToggle[0],07ff0h
                        MOV     InvadersToggle[2],07ff0h
                        MOV     InvadersToggle[4],07ff0h
                        MOV     InvadersToggle[6],07ff0h
                        MOV     InvadersToggle[8],07ff0h
                        MOV     MoveCount,1
                        MOV     AL,CurrentInvaderSpeed
                        MOV     InvaderSpeed,AL
                        MOV     Direction,0
                        MOV     Reversing,0
                        MOV     Collision,0
                        MOV     AX,CurrentBombFreq
                        MOV     BombFreq,AX

                        RET

CurrentInvaderSpeed     DB      55
CurrentInvaderY         DB      30
CurrentBombFreq         DW      010h

ResetLevel              ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Increase Score
;----------------------------------------------------------------------------------------------------------------------------------

IncreaseScore           PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

RackScore:              CALL    ScorePlusOne
                        LOOP    RackScore

                        RET

IncreaseScore           ENDP

; Bump score up by 1

ScorePlusOne            PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        INC     Score[4]
                        CMP     Score[4],58
                        JNZ     Done
                        MOV     Score[4],48
                        INC     Score[3]
                        CMP     Score[3],58
                        JNZ     Done
                        MOV     Score[3],48
                        INC     Score[2]
                        CMP     Score[2],58
                        JNZ     Done
                        MOV     Score[2],48
                        INC     Score[1]
                        CMP     Score[1],58
                        JNZ     Done
                        MOV     Score[1],48
                        INC     Score[0]
                        MOV     TempCX,CX
                        MOV     AL,Lives
                        MOV     BX,285
                        MOV     DL,0
                        MOV     DH,0
                        CALL    DisplayDigit
                        INC     Lives
                        MOV     AL,Lives
                        MOV     BX,285
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit
                        MOV     CX,TempCX
                        CMP     Score[0],58
                        JNZ     Done

Done:                   RET

TempCX                  DW      0

ScorePlusOne            ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Display Score
;----------------------------------------------------------------------------------------------------------------------------------

DisplayScore            PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,5
                        CALL    DisplayDigit

                        RET

ScoreXOffset            DW      0
ScoreValueOffset        DW      0

DisplayScore            ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Erase Score
;----------------------------------------------------------------------------------------------------------------------------------

EraseScore              PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,0
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,0
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,0
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,0
                        CALL    DisplayDigit

                        INC     ScoreValueOffset
                        ADD     ScoreXOffset,6

                        MOV     SI,ScoreValueOffset
                        LODSB
                        MOV     BX,ScoreXOffset
                        MOV     DL,0
                        MOV     DH,0
                        CALL    DisplayDigit

                        RET

EraseScore              ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Display / Erase Digit In Decimal
;----------------------------------------------------------------------------------------------------------------------------------

DisplayDigit            PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        CALL    FindDigit
                        CALL    DrawSprite          ; Draw sprite

                        RET

DisplayDigit            ENDP

FindDigit               PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

; Find Digit
                        CMP     AL,48
                        JNZ     NotZero
                        LEA     AX,Zero
                        JMP     GotDigit
NotZero:                CMP     AL,49
                        JNZ     NotOne
                        LEA     AX,One
                        JMP     GotDigit
NotOne:                 CMP     AL,50
                        JNZ     NotTwo
                        LEA     AX,Two
                        JMP     GotDigit
NotTwo:                 CMP     AL,51
                        JNZ     NotThree
                        LEA     AX,Three
                        JMP     GotDigit
NotThree:               CMP     AL,52
                        JNZ     NotFour
                        LEA     AX,Four
                        JMP     GotDigit
NotFour:                CMP     AL,53
                        JNZ     NotFive
                        LEA     AX,Five
                        JMP     GotDigit
NotFive:                CMP     AL,54
                        JNZ     NotSix
                        LEA     AX,Six
                        JMP     GotDigit
NotSix:                 CMP     AL,55
                        JNZ     NotSeven
                        LEA     AX,Seven
                        JMP     GotDigit
NotSeven:               CMP     AL,56
                        JNZ     NotEight
                        LEA     AX,Eight
                        JMP     GotDigit
NotEight:               CMP     AL,57
                        JNZ     NotNine
                        LEA     AX,Nine
                        JMP     GotDigit

NotNine:                CMP     AL,65
                        JNZ     NotA
                        LEA     AX,LetterA
                        JMP     GotDigit
NotA:                   CMP     AL,66
                        JNZ     NotB
                        LEA     AX,LetterB
                        JMP     GotDigit
NotB:                   CMP     AL,67
                        JNZ     NotC
                        LEA     AX,LetterC
                        JMP     GotDigit
NotC:                   CMP     AL,68
                        JNZ     NotD
                        LEA     AX,LetterD
                        JMP     GotDigit
NotD:                   CMP     AL,69
                        JNZ     NotE
                        LEA     AX,LetterE
                        JMP     GotDigit
NotE:                   CMP     AL,70
                        JNZ     NotF
                        LEA     AX,LetterF
                        JMP     GotDigit
NotF:                   CMP     AL,71
                        JNZ     NotG
                        LEA     AX,LetterG
                        JMP     GotDigit
NotG:                   CMP     AL,72
                        JNZ     NotH
                        LEA     AX,LetterH
                        JMP     GotDigit
NotH:                   CMP     AL,73
                        JNZ     NotI
                        LEA     AX,LetterI
                        JMP     GotDigit
NotI:                   CMP     AL,74
                        JNZ     NotJ
                        LEA     AX,LetterJ
                        JMP     GotDigit
NotJ:                   CMP     AL,75
                        JNZ     NotK
                        LEA     AX,LetterK
                        JMP     GotDigit
NotK:                   CMP     AL,76
                        JNZ     NotL
                        LEA     AX,LetterL
                        JMP     GotDigit
NotL:                   CMP     AL,77
                        JNZ     NotM
                        LEA     AX,LetterM
                        JMP     GotDigit
NotM:                   CMP     AL,78
                        JNZ     NotN
                        LEA     AX,LetterN
                        JMP     GotDigit
NotN:                   CMP     AL,79
                        JNZ     NotO
                        LEA     AX,LetterO
                        JMP     GotDigit
NotO:                   CMP     AL,80
                        JNZ     NotP
                        LEA     AX,LetterP
                        JMP     GotDigit
NotP:                   CMP     AL,81
                        JNZ     NotQ
                        LEA     AX,LetterQ
                        JMP     GotDigit
NotQ:                   CMP     AL,82
                        JNZ     NotR
                        LEA     AX,LetterR
                        JMP     GotDigit
NotR:                   CMP     AL,83
                        JNZ     NotS
                        LEA     AX,LetterS
                        JMP     GotDigit
NotS:                   CMP     AL,84
                        JNZ     NotT
                        LEA     AX,LetterT
                        JMP     GotDigit
NotT:                   CMP     AL,85
                        JNZ     NotU
                        LEA     AX,LetterU
                        JMP     GotDigit
NotU:                   CMP     AL,86
                        JNZ     NotV
                        LEA     AX,LetterV
                        JMP     GotDigit
NotV:                   CMP     AL,87
                        JNZ     NotW
                        LEA     AX,LetterW
                        JMP     GotDigit
NotW:                   CMP     AL,88
                        JNZ     NotX
                        LEA     AX,LetterX
                        JMP     GotDigit
NotX:                   CMP     AL,89
                        JNZ     NotY
                        LEA     AX,LetterY
                        JMP     GotDigit
NotY:                   CMP     AL,90
                        JNZ     NotZ
                        LEA     AX,LetterZ
                        JMP     GotDigit
NotZ:                   CMP     AL,61
                        JNZ     NotEqual
                        LEA     AX,Equal
                        JMP     GotDigit
NotEqual:               CMP     AL,40
                        JNZ     NotCopyright
                        LEA     AX,CopyrightSymbol
                        JMP     GotDigit
NotCopyright:           LEA     AX,Period

GotDigit:               RET

FindDigit               ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Check If Player Is Dead
;----------------------------------------------------------------------------------------------------------------------------------

CheckPlayerDead         PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        CMP     InvadersToggle[8],0
                        JZ      NoRow5Left
                        CMP     InvadersY,84
                        JNZ     NotDead
                        MOV     PlayerDead,1
                        JMP     NotDead

NoRow5Left:             CMP     InvadersToggle[6],0
                        JZ      NoRow4Left
                        CMP     InvadersY,94
                        JNZ     NotDead
                        MOV     PlayerDead,1
                        JMP     NotDead

NoRow4Left:             CMP     InvadersToggle[4],0
                        JZ      NoRow3Left
                        CMP     InvadersY,104
                        JNZ     NotDead
                        MOV     PlayerDead,1
                        JMP     NotDead

NoRow3Left:             CMP     InvadersToggle[2],0
                        JZ      NoRow2Left
                        CMP     InvadersY,114
                        JNZ     NotDead
                        MOV     PlayerDead,1
                        JMP     NotDead

NoRow2Left:             CMP     InvadersY,124
                        JNZ     NotDead
                        MOV     PlayerDead,1

NotDead:                RET

CheckPlayerDead         ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Check Invader Killed
;----------------------------------------------------------------------------------------------------------------------------------

CheckInvaderKill        PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AL,Collision
                        AND     AL,0f0h
                        CMP     AL,050h
                        JNZ     NoRow5Kill
                        CALL    SpeedUpInvaders
                        MOV     CH,0
                        MOV     CL,Collision
                        AND     CL,00fh
                        INC     CL
                        MOV     AX,08000h
Shifting1:              SHR     AX,1
                        LOOP    Shifting1
                        XOR     InvadersToggle[8],AX
                        MOV     CX,5
                        CALL    IncreaseScore

                        JMP     NoRow1Kill

NoRow5Kill:             MOV     AL,Collision
                        AND     AL,0f0h
                        CMP     AL,040h
                        JNZ     NoRow4Kill
                        CALL    SpeedUpInvaders
                        MOV     CH,0
                        MOV     CL,Collision
                        AND     CL,00fh
                        INC     CL
                        MOV     AX,08000h
Shifting2:              SHR     AX,1
                        LOOP    Shifting2
                        XOR     InvadersToggle[6],AX
                        MOV     CX,10
                        CALL    IncreaseScore
                        JMP     NoRow1Kill

NoRow4Kill:             MOV     AL,Collision
                        AND     AL,0f0h
                        CMP     AL,030h
                        JNZ     NoRow3Kill
                        CALL    SpeedUpInvaders
                        MOV     CH,0
                        MOV     CL,Collision
                        AND     CL,00fh
                        INC     CL
                        MOV     AX,08000h
Shifting3:              SHR     AX,1
                        LOOP    Shifting3
                        XOR     InvadersToggle[4],AX
                        MOV     CX,15
                        CALL    IncreaseScore
                        JMP     NoRow1Kill

NoRow3Kill:             MOV     AL,Collision
                        AND     AL,0f0h
                        CMP     AL,020h
                        JNZ     NoRow2Kill
                        CALL    SpeedUpInvaders
                        MOV     CH,0
                        MOV     CL,Collision
                        AND     CL,00fh
                        INC     CL
                        MOV     AX,08000h
Shifting4:              SHR     AX,1
                        LOOP    Shifting4
                        XOR     InvadersToggle[2],AX
                        MOV     CX,20
                        CALL    IncreaseScore
                        JMP     NoRow1Kill

NoRow2Kill:             MOV     AL,Collision
                        AND     AL,0f0h
                        CMP     AL,010h
                        JNZ     NoRow1Kill
                        CALL    SpeedUpInvaders
                        MOV     CH,0
                        MOV     CL,Collision
                        AND     CL,00fh
                        INC     CL
                        MOV     AX,08000h
Shifting5:              SHR     AX,1
                        LOOP    Shifting5
                        XOR     InvadersToggle[0],AX
                        MOV     CX,25
                        CALL    IncreaseScore
                        JMP     NoUFOKill

NoRow1Kill:             CMP     Collision,3
                        JNZ     NoUFOKill
                        LEA     AX,UFO              ; Get address of sprite
                        MOV     BX,UFOX             ; Get X position to draw sprite at
                        MOV     DL,10               ; Get Y position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite
                        MOV     UFOX,0
                        MOV     CX,100
                        CALL    IncreaseScore

NoUFOKill:              CMP     InvadersToggle[0],00000h
                        JNZ     NotAllDeadYet
                        CMP     InvadersToggle[2],00000h
                        JNZ     NotAllDeadYet
                        CMP     InvadersToggle[4],00000h
                        JNZ     NotAllDeadYet
                        CMP     InvadersToggle[6],00000h
                        JNZ     NotAllDeadYet
                        CMP     InvadersToggle[8],00000h
                        JNZ     NotAllDeadYet
                        MOV     NextLevelToggle,1

NotAllDeadYet:          RET

CheckInvaderKill        ENDP

; Speed up invaders upon a kill

SpeedUpInvaders         PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        CMP     InvaderSpeed,1
                        JZ      NoSpeedIncrease
                        DEC     InvaderSpeed

NoSpeedIncrease:        RET

SpeedUpInvaders         ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Move Invaders
;----------------------------------------------------------------------------------------------------------------------------------

MoveInvaders            PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        TEST    Reversing,080h
                        JNZ     NoReverse

                        MOV     BX,250
                        MOV     AX,InvadersToggle[0]
                        OR      AX,InvadersToggle[2]
                        OR      AX,InvadersToggle[4]
                        OR      AX,InvadersToggle[6]
                        OR      AX,InvadersToggle[8]
                        MOV     CX,10
FindLeft:               SHL     AX,1
                        TEST    AX,08000h
                        JNZ     DoneLeft
                        SUB     BX,16
                        LOOP    FindLeft

DoneLeft:               MOV     DX,298
                        MOV     AX,InvadersToggle[0]
                        OR      AX,InvadersToggle[2]
                        OR      AX,InvadersToggle[4]
                        OR      AX,InvadersToggle[6]
                        OR      AX,InvadersToggle[8]
                        MOV     CX,10
                        SHR     AX,1
                        SHR     AX,1
                        SHR     AX,1
FindRight:              SHR     AX,1
                        TEST    AX,00001h
                        JNZ     DoneRight
                        ADD     DX,16
                        LOOP    FindRight

DoneRight:              CMP     InvadersX,DX
                        JZ      Reverse
                        CMP     InvadersX,BX
                        JNZ     NoReverse
Reverse:                XOR     Direction,080h
                        ADD     InvadersY,2
                        MOV     Reversing,080h
                        JMP     Animate

NoReverse:              MOV     Reversing,0
                        TEST    Direction,080h
                        JZ      MoveInvadersLeft

                        INC     InvadersX
                        JMP     Animate

MoveInvadersLeft:       DEC     InvadersX

Animate:                XOR     Frame,080h
                        MOV     AH,InvaderSpeed
                        MOV     MoveCount,AH

; Make sound

                        TEST    Sound,080h
                        JZ      NoSound2

                        MOV     AL,0b6h
                        OUT     043h,AL
                        MOV     AL,090h
                        OUT     042h,AL
                        MOV     AL,00Fh
                        OUT     042h,AL
                        IN      AL,061h
                        OR      AL,3
                        OUT     061h,AL

NoSound2:               MOV     CX,08000h
Timer1:                 LOOP    Timer1

                        IN      AL,061h
                        AND     AL,0fch
                        OUT     061h,AL

                        RET

MoveInvaders            ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Shoot Player Missile
;----------------------------------------------------------------------------------------------------------------------------------

ShootPlayerMissile      PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AX,PlayerX
                        MOV     MissileX,AX
                        MOV     MissileY,123

; Make sound

                        TEST    Sound,080h
                        JZ      NoSound3

                        MOV     AL,0b6h
                        OUT     043h,AL
                        MOV     AL,090h
                        OUT     042h,AL
                        MOV     AL,001h
                        OUT     042h,AL
                        IN      AL,061h
                        OR      AL,3
                        OUT     061h,AL

NoSound3:               MOV     CX,08000h
Timer2:                 LOOP    Timer2

                        IN      AL,061h
                        AND     AL,0fch
                        OUT     061h,AL

                        RET

ShootPlayerMissile      ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Move Player Missile
;----------------------------------------------------------------------------------------------------------------------------------

MovePlayerMissile       PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        LEA     AX,StraightMissile  ; Get address of sprite
                        MOV     BX,MissileX         ; Get X position to draw sprite at
                        MOV     DL,MissileY         ; Get Y position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite

                        DEC     MissileY
                        DEC     MissileY

                        CMP     MissileY,09
                        JNZ     DrawNextFrame
                        MOV     MissileX,0
                        JMP     MissileDead

DrawNextFrame:          LEA     AX,StraightMissile  ; Get address of sprite
                        MOV     BX,MissileX         ; Get X position to draw sprite at
                        MOV     DL,MissileY         ; Get Y position to draw sprite at
                        MOV     DH,04h              ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

                        CMP     Collision,0
                        JZ      MissileDead
                        CMP     Collision,4
                        JZ      MissileDead
                        CMP     Collision,6
                        JZ      MissileDead
                        CALL    KillMissile

MissileDead:            RET

MovePlayerMissile       ENDP

; Kill Player Missile

KillMissile             PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        LEA     AX,StraightMissile  ; Get address of sprite
                        MOV     BX,MissileX         ; Get X position to draw sprite at
                        MOV     DL,MissileY         ; Get Y position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite
                        MOV     MissileX,0

                        RET

KillMissile             ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Move Player's Ship Left
;----------------------------------------------------------------------------------------------------------------------------------

MovePlayerLeft          PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        CMP     PlayerX,50
                        JZ      NoMoreLeft
                        DEC     PlayerX

NoMoreLeft:             RET

MovePlayerLeft          ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Move Player's Ship Right
;----------------------------------------------------------------------------------------------------------------------------------

MovePlayerRight         PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        CMP     PlayerX,259
                        JZ      NoMoreRight
                        INC     PlayerX

NoMoreRight:            RET

MovePlayerRight         ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; New Interrupt 9 Handler - Replaces normal keyboard handler during game play
;
; Interrupt 015h: Calling AH = 04fh (check for this - Int 15 also has other
;                                    subfuctions!)
;                 Routine will look at AL, where the caller (Int 9) will have
;                 placed the scan code.
;
;                 Place any new scan code for int 9 to process into AL and set
;                 carry flag before return.
;
;                 Just clear carry flag to have int 9 ignore the keypress.
;----------------------------------------------------------------------------------------------------------------------------------

; Installs new int 9 handler

InstallNewInt9          PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AH,035h                         ; Ask for interrupt address function
                        MOV     AL,015h                         ; Interrupt we're asking for
                        INT     021h                            ; Ask for it
                        MOV     Word Ptr OldInt9Address,BX      ; Save current segment of interrupt
                        MOV     Word Ptr OldInt9Address[2],ES   ; Save current offset of interrupt

                        MOV     AH,025h                         ; Insert new address for interrupt function
                        MOV     AL,015h                         ; Interupt we want to change
                        MOV     DX,Offset NewInt9Handler        ; New address to point to (this TSR)
                        INT     021h                            ; Set it

                        RET

OldInt9Address          DD      0   ; Buffer for original interrupt address
StoreAX                 DW      0

InstallNewInt9          ENDP

; Removes new int 9 handler

RemoveNewInt9           PROC    NEAR
                        Assume  CS:CODE_SEG,DS:NOTHING

                        MOV     AX,Word Ptr OldInt9Address[2]
                        MOV     DS,AX
                        MOV     AH,025h                         ; Insert new address for interrupt function
                        MOV     AL,015h                         ; Interupt we want to change
                        MOV     DX,Word Ptr OldInt9Address      ; New address to point to (this TSR)
                        INT     021h                            ; Set it

                        RET

RemoveNewInt9           ENDP

; Actual routine to be called when int 9 is tripped

NewInt9Handler          PROC    FAR
                        Assume  CS:CODE_SEG,DS:Nothing

                        CMP     AH,04fh
                        JNZ     NotIntercept

                        TEST    AL,080h
                        JNZ     NoKeyPress
                        MOV     KeyPress,1

; Check left arrow

NoKeyPress:             CMP     AL,04Bh                 ; Has left arrow been pressed?
                        JNZ     NoLeftOn
                        MOV     LeftToggle,1

NoLeftOn:               CMP     AL,0CBh                 ; Has left arrow been released?
                        JNZ     NoLeftOff
                        MOV     LeftToggle,0

; Check right arrow

NoLeftOff:              CMP     AL,04Dh                 ; Has right arrow been pressed?
                        JNZ     NoRightOn
                        MOV     RightToggle,1

NoRightOn:              CMP     AL,0CDh                 ; Has right arrow been released?
                        JNZ     NoRightOff
                        MOV     RightToggle,0

; Check ctrl

NoRightOff:             CMP     AL,01Dh                 ; Has ctrl been pressed?
                        JNZ     NoFireOn
                        MOV     FireToggle,1

NoFireOn:               CMP     AL,09Dh                 ; Has ctrl been released?
                        JNZ     NoFireOff
                        MOV     FireToggle,0

; Check ESC

NoFireOff:              CMP     AL,001h                 ; Has ESC been pressed?
                        JNZ     NoESCOn
                        MOV     ExitToggle,1

NoESCOn:                CMP     AL,01fh
                        JNZ     NotIntercept
                        MOV     SoundToggle,1

; Clear keyboard buffer (BIOS routine is still called, and it annoyingly beeps when it's buffer is full)



NotIntercept:
                        MOV     StoreAX,AX
                        MOV     AX,40:[01ch]
                        MOV     40:[01ah],AX
                        MOV     AX,StoreAX

;                        MOV     AX,040h
;                        MOV     ES,AX
;                        MOV     DS,AX
;                        MOV     DI,01ah
;                        MOV     SI,01ch
;                        MOVSW

                        CLC

; Call original interrupt routine

;                        CALL    OldInt9Address  ; Call normal interrupt routine

                        IRET
;                        RET     2       ; Return from TSR

NewInt9Handler          ENDP

;---------------------------------------------------------------------
;                        JMP     StartPrint
;CharacterTable          DB             "0123456789ABCDEF"
;StartPrint:             MOV     AL,RandomNumber[0]
;                        MOV     CX,04h
;Looper1:                SHR     AL,1
;                        LOOP    Looper1
;                        LEA     SI,CharacterTable
;                        MOV     AH,0
;                        ADD     SI,AX
;                        CLD
;                        LODSB
;                        MOV     DL,AL
;                        MOV     AH,2
;                        INT     21h
;                        MOV     AL,RandomNumber[0]
;                        AND     AL,0fh
;                        LEA     SI,CharacterTable
;                        MOV     AH,0
;                        ADD     SI,AX
;                        CLD
;                        LODSB
;                        MOV     DL,AL
;                        MOV     AH,2
;                        INT     21h
;                        MOV     DL,00dh
;                        MOV     AH,2
;                        INT     21h
;---------------------------------------------------------------------

;----------------------------------------------------------------------------------------------------------------------------------
; Draw Bunkers
;----------------------------------------------------------------------------------------------------------------------------------

DrawBunkers             PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     BunkerXL,70
                        MOV     BunkerYL,100
                        CALL    DrawBunker

                        MOV     BunkerXL,122
                        MOV     BunkerYL,100
                        CALL    DrawBunker

                        MOV     BunkerXL,174
                        MOV     BunkerYL,100
                        CALL    DrawBunker

                        MOV     BunkerXL,226
                        MOV     BunkerYL,100
                        CALL    DrawBunker

                        RET

DrawBunkers             ENDP

; Draw Single Bunker

DrawBunker              PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        LEA     AX,BunkerLeftTop    ; Get address of sprite
                        MOV     BX,BunkerXL         ; Get X position to draw sprite at
                        MOV     DL,BunkerYL         ; Get Y position to draw sprite at
                        MOV     DH,2                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

                        ADD     BunkerYL,7

                        LEA     AX,BunkerLeftMiddle ; Get address of sprite
                        MOV     BX,BunkerXL         ; Get X position to draw sprite at
                        MOV     DL,BunkerYL         ; Get Y position to draw sprite at
                        MOV     DH,2                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

                        ADD     BunkerYL,7

                        LEA     AX,BunkerLeftBottom ; Get address of sprite
                        MOV     BX,BunkerXL         ; Get X position to draw sprite at
                        MOV     DL,BunkerYL         ; Get Y position to draw sprite at
                        MOV     DH,2                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

                        ADD     BunkerXL,16
                        SUB     BunkerYL,14

                        LEA     AX,BunkerRightTop   ; Get address of sprite
                        MOV     BX,BunkerXL         ; Get X position to draw sprite at
                        MOV     DL,BunkerYL         ; Get Y position to draw sprite at
                        MOV     DH,2                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

                        ADD     BunkerYL,7

                        LEA     AX,BunkerRightMiddle; Get address of sprite
                        MOV     BX,BunkerXL         ; Get X position to draw sprite at
                        MOV     DL,BunkerYL         ; Get Y position to draw sprite at
                        MOV     DH,2                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

                        ADD     BunkerYL,7

                        LEA     AX,BunkerRightBottom; Get address of sprite
                        MOV     BX,BunkerXL         ; Get X position to draw sprite at
                        MOV     DL,BunkerYL         ; Get Y position to draw sprite at
                        MOV     DH,2                ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite

                                                RET                     ; Done drawing, return to caller

BunkerXL                DW      0
BunkerYL                DB      0

DrawBunker              ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Draw Invaders
;----------------------------------------------------------------------------------------------------------------------------------

DrawInvaders            PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AX,InvadersX
                        MOV     InvadersXL,AX
                        MOV     AL,InvadersY
                        MOV     InvadersYL,AL
                        LEA     SI,InvadersToggle ; Setup source pointer to sprite data

                        MOV     ColorL,010h
                        TEST    Frame,80h
                        JZ      FrameIsZero1
                        LEA     AX,TopInvader2
                        JMP     Skip1
FrameIsZero1:           LEA     AX,TopInvader1
Skip1:                  MOV     SpriteAddressL,AX
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    DrawInvaderRow

                        MOV     ColorL,020h
                        TEST    Frame,80h
                        JZ      FrameIsZero2
                        LEA     AX,MiddleInvader2
                        JMP     Skip2
FrameIsZero2:           LEA     AX,MiddleInvader1
Skip2:                  MOV     SpriteAddressL,AX
                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    DrawInvaderRow

                        MOV     ColorL,030h
                        TEST    Frame,80h
                        JZ      FrameIsZero3
                        LEA     AX,MiddleInvader1
                        JMP     Skip3
FrameIsZero3:           LEA     AX,MiddleInvader2
Skip3:                  MOV     SpriteAddressL,AX
                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    DrawInvaderRow

                        MOV     ColorL,040h
                        TEST    Frame,80h
                        JZ      FrameIsZero4
                        LEA     AX,BottomInvader2
                        JMP     Skip4
FrameIsZero4:           LEA     AX,BottomInvader1
Skip4:                  MOV     SpriteAddressL,AX
                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    DrawInvaderRow

                        MOV     ColorL,050h
                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    DrawInvaderRow

                        MOV     Collision,0     ; No collision detection on invaders - Causes problems when invaders get to bunkers

                                                RET                     ; Done drawing, return to caller

InvadersXL              DW      0
InvadersYL              DB      0
Temporary2L             DW      0

DrawInvaders            ENDP

; Draw Row of Invaders

DrawInvaderRow          PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        SHL     AX,1
                        MOV     CounterL,11
DrawRow:                TEST    AX,8000h        ; Check left most bit
                        JZ      BitIsZero1      ; Jump if bit is 0
                        MOV     Temporary1L,AX
                        MOV     AX,SpriteAddressL   ; Get address of sprite
                        MOV     BX,InvadersXL       ; Get X position to draw sprite at
                        SUB     BX,200
                        MOV     DL,InvadersYL       ; Get Y position to draw sprite at
                        MOV     DH,ColorL           ; Get color to draw sprite
                        CALL    DrawSprite          ; Draw sprite
                        MOV     AX,Temporary1L
BitIsZero1:             SHL     AX,1            ; Shift data left for next bit
                        ADD     InvadersXL,16
                        DEC     CounterL
                        INC     ColorL
                        JNZ     DrawRow

                        ADD     InvadersYL,10
                        MOV     AX,InvadersX
                        MOV     InvadersXL,AX

                                                RET                     ; Done drawing, return to caller

CounterL                DB      0
SpriteAddressL          DW      0
ColorL                  DB      0
Temporary1L             DW      0

DrawInvaderRow          ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Erase Invaders
;----------------------------------------------------------------------------------------------------------------------------------

EraseInvaders           PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     AX,InvadersX
                        MOV     InvadersXL,AX
                        MOV     AL,InvadersY
                        MOV     InvadersYL,AL
                        LEA     SI,InvadersToggle ; Setup source pointer to sprite data

                        TEST    Frame,80h
                        JZ      FrameIsZeroA
                        LEA     AX,TopInvader2
                        JMP     SkipA
FrameIsZeroA:           LEA     AX,TopInvader1
SkipA:                  MOV     SpriteAddressL,AX
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    EraseInvaderRow

                        TEST    Frame,80h
                        JZ      FrameIsZeroB
                        LEA     AX,MiddleInvader2
                        JMP     SkipB
FrameIsZeroB:           LEA     AX,MiddleInvader1
SkipB:                  MOV     SpriteAddressL,AX
                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    EraseInvaderRow

                        TEST    Frame,80h
                        JZ      FrameIsZeroC
                        LEA     AX,MiddleInvader1
                        JMP     SkipC
FrameIsZeroC:           LEA     AX,MiddleInvader2
SkipC:                  MOV     SpriteAddressL,AX
                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    EraseInvaderRow

                        TEST    Frame,80h
                        JZ      FrameIsZeroD
                        LEA     AX,BottomInvader2
                        JMP     SkipD
FrameIsZeroD:           LEA     AX,BottomInvader1
SkipD:                  MOV     SpriteAddressL,AX
                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    EraseInvaderRow

                        MOV     SI,Temporary2L
                        CLD                     ; Make sure we increment SI
                        LODSW                   ; Get 2 bytes from invaders alive toggles
                        MOV     Temporary2L,SI
                        CALL    EraseInvaderRow

                                                RET                     ; Done drawing, return to caller

EraseInvaders           ENDP

; Erase Row of Invaders

EraseInvaderRow         PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        SHL     AX,1
                        MOV     CounterL,11
DrawRowA:               TEST    AX,8000h        ; Check left most bit
                        JZ      BitIsZeroA      ; Jump if bit is 0
                        MOV     Temporary1L,AX
                        MOV     AX,SpriteAddressL   ; Get address of sprite
                        MOV     BX,InvadersXL       ; Get X position to draw sprite at
                        SUB     BX,200
                        MOV     DL,InvadersYL       ; Get Y position to draw sprite at
                        CALL    EraseSprite         ; Draw sprite
                        MOV     AX,Temporary1L
BitIsZeroA:             SHL     AX,1            ; Shift data left for next bit
                        ADD     InvadersXL,16
                        DEC     CounterL
                        JNZ     DrawRowA

                        ADD     InvadersYL,10
                        MOV     AX,InvadersX
                        MOV     InvadersXL,AX

                                                RET                     ; Done drawing, return to caller

EraseInvaderRow         ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Draw Logo Layer
;----------------------------------------------------------------------------------------------------------------------------------

DrawLogoLayer           PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     SI,AX           ; Setup source pointer to sprite data
                        MOV     AL,DL           ; Get Y position of sprite in AL
                        MOV     AH,0            ; Zero high byte of AX for following shifts
                        SHL     AX,1            ; Calculate Y position * 320 (find address of row)
                        SHL     AX,1            ; Y Position shifted left 6 times + Y Position shifted left 8 times
                        SHL     AX,1
                        SHL     AX,1
                        SHL     AX,1
                        SHL     AX,1
                        MOV     CX,AX
                        SHL     CX,1
                        SHL     CX,1
                        ADD     AX,CX
                        ADD     AX,BX           ; Add X position to address
                        MOV     DI,AX           ; Store address in destination register
                        MOV     AX,0a000h       ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register

                        MOV     Row,5

DoNextRow:              MOV     Column,11

DoNextSprite:           MOV     DL,7            ; Do 7 lines of sprite
                        CLD                     ; Make sure we increment SI and DI
DrawLinesZ:             LODSW                   ; Get 2 bytes from sprite data (16 bits = 1 line of sprite image)
                        MOV     BX,AX           ; Transfer data to an unused register
                        MOV     CX,16           ; Scan all 16 bits
DoLineZ:                TEST    BX,8000h        ; Check left most bit
                        JZ      BitIsZeroZ      ; Jump if bit is 0
                        MOV     AL,DH           ; Bit is 1, get color of sprite
                        STOSB                   ; And draw the pixel on the screen
                        JMP     SkipZ           ; Skip the bit is 0 stuff
BitIsZeroZ:             INC     DI              ; Bit was 0, increment destination register
SkipZ:                  SHL     BX,1            ; Shift data left for next bit
                        LOOP    DoLineZ         ; Keep going until no more bits to check
                        ADD     DI,304          ; Increment address to next screen line (320 - 16 bits)
                        DEC     DL              ; Decrease line count
                        JNZ     DrawLinesZ      ; Draw lines until no more lines left to draw

                        SUB     DI,2224         ; Do next sprite in row
                        DEC     Column
                        CMP     Column,0
                        JNZ     DoNextSprite

                        ADD     DI,2064         ; Do next sprite in row
                        DEC     Row
                        CMP     Row,0
                        JNZ     DoNextRow

                                                RET                     ; Done drawing, return to caller

Column                  DB      0
Row                     DB      0

DrawLogoLayer           ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Draw Sprite
;----------------------------------------------------------------------------------------------------------------------------------

DrawSprite              PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     SI,AX           ; Setup source pointer to sprite data
                        MOV     AL,DL           ; Get Y position of sprite in AL
                        MOV     AH,0            ; Zero high byte of AX for following shifts
                        SHL     AX,1            ; Calculate Y position * 320 (find address of row)
                        SHL     AX,1            ; Y Position shifted left 6 times + Y Position shifted left 8 times
                        SHL     AX,1
                        SHL     AX,1
                        SHL     AX,1
                        SHL     AX,1
                        MOV     CX,AX
                        SHL     CX,1
                        SHL     CX,1
                        ADD     AX,CX
                        LEA     CX,VideoBuffer  ; Get address of video buffer
                        ADD     AX,CX           ; Add offset to video buffer
                        ADD     AX,BX           ; Add X position to address
                        MOV     DI,AX           ; Store address in destination register
                        MOV     AX,CS           ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register

                        MOV     DL,7            ; Do 7 lines
                        CLD                     ; Make sure we increment SI and DI
DrawLines:              LODSW                   ; Get 2 bytes from sprite data (16 bits = 1 line of sprite image)
                        MOV     BX,AX           ; Transfer data to an unused register
                        MOV     CX,16           ; Scan all 16 bits
DoLine:                 TEST    BX,8000h        ; Check left most bit
                        JZ      BitIsZero       ; Jump if bit is 0
                        CMP     Collision,0
                        JNZ     NoCollision
                        MOV     AL,ES:[DI]
                        CMP     AL,0
                        JZ      NoCollision
                        MOV     Collision,AL
NoCollision:            MOV     AL,DH           ; Bit is 1, get color of sprite
                        STOSB                   ; And draw the pixel on the screen
                        JMP     Skip            ; Skip the bit is 0 stuff
BitIsZero:              INC     DI              ; Bit was 0, increment destination register
Skip:                   SHL     BX,1            ; Shift data left for next bit
                        LOOP    DoLine          ; Keep going until no more bits to check
                        ADD     DI,304          ; Increment address to next screen line (320 - 16 bits)
                        DEC     DL              ; Decrease line count
                        JNZ     DrawLines       ; Draw lines until no more lines left to draw

                                                RET                     ; Done drawing, return to caller

DrawSprite              ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Erase Sprite
;----------------------------------------------------------------------------------------------------------------------------------

EraseSprite             PROC    NEAR
                        Assume  CS:CODE_SEG,DS:CODE_SEG

                        MOV     SI,AX           ; Setup source pointer to sprite data
                        MOV     AL,DL           ; Get Y position of sprite in AL
                        MOV     AH,0            ; Zero high byte of AX for following shifts
                        SHL     AX,1            ; Calculate Y position * 320 (find address of row)
                        SHL     AX,1            ; Y Position shifted left 6 times + Y Position shifted left 8 times
                        SHL     AX,1
                        SHL     AX,1
                        SHL     AX,1
                        SHL     AX,1
                        MOV     CX,AX
                        SHL     CX,1
                        SHL     CX,1
                        ADD     AX,CX
                        LEA     CX,VideoBuffer  ; Get address of video buffer
                        ADD     AX,CX           ; Add offset to video buffer
                        ADD     AX,BX           ; Add X position to address
                        MOV     DI,AX           ; Store address in destination register
                        MOV     AX,CS           ; Get segment of video memory
                        MOV     ES,AX           ; Store it in destination segment register

                        MOV     DL,7            ; Do 7 lines
                        CLD                     ; Make sure we increment SI and DI
DrawLines2:             LODSW                   ; Get 2 bytes from sprite data (16 bits = 1 line of sprite image)
                        MOV     BX,AX           ; Transfer data to an unused register
                        MOV     CX,16           ; Scan all 16 bits
DoLine2:                TEST    BX,8000h        ; Check left most bit
                        JZ      BitIsZero2      ; Jump if bit is 0
                        MOV     AL,0            ; Bit is 1, get color of sprite
                        STOSB                   ; And draw the pixel on the screen
                        JMP     SkipAA          ; Skip the bit is 0 stuff
BitIsZero2:             INC     DI              ; Bit was 0, increment destination register
SkipAA:                 SHL     BX,1            ; Shift data left for next bit
                        LOOP    DoLine2         ; Keep going until no more bits to check
                        ADD     DI,304          ; Increment address to next screen line (320 - 16 bits)
                        DEC     DL              ; Decrease line count
                        JNZ     DrawLines2      ; Draw lines until no more lines left to draw

                                                RET                     ; Done drawing, return to caller

EraseSprite             ENDP

;----------------------------------------------------------------------------------------------------------------------------------
; Sprite data
;----------------------------------------------------------------------------------------------------------------------------------

TopInvader1             DW      0c00h,1e00h,2d00h,3f00h,1200h,2100h,1200h
TopInvader2             DW      0c00h,1e00h,2d00h,3f00h,1200h,2100h,4080h

MiddleInvader1          DW      2100h,9e40h,0ad40h,7f80h,3f00h,2100h,4080h
MiddleInvader2          DW      2100h,1e00h,2d00h,7f80h,0bf40h,0a140h,1200h

BottomInvader1          DW      01e00h,7f80h,0ccc0h,0ffc0h,2100h,4c80h,2100h
BottomInvader2          DW      01e00h,7f80h,0ccc0h,0ffc0h,2100h,4c80h,8040h

TwistedMissile1         DW      0000h,0000h,0000h,0800h,0400h,0800h,0400h
TwistedMissile2         DW      0000h,0000h,0000h,0400h,0800h,0400h,0800h

UFO                     DW      0ff0h,0ff0h,0ffffh,0ffffh,0ffffh,7ffeh,3ffch

PlayersShip             DW      0400h,0e00h,7fc0h,0ffe0h,0ffe0h,0ffe0h,0000h

StraightMissile         DW      0000h,0000h,0000h,0400h,0400h,0400h,0400h

BunkerLeftTop           DW      0fffh,1fffh,3fffh,7fffh,0ffffh,0ffffh,0ffffh
BunkerLeftMiddle        DW      0ffffh,0ffffh,0ffffh,0ffffh,0ffffh,0ffffh,0ffffh
BunkerLeftBottom        DW      0ff81h,0fe00h,0fc00h,0f800h,0f800h,0f000h,0000h
BunkerRightTop          DW      0f000h,0f800h,0fc00h,0fe00h,0ff00h,0ff00h,0ff00h
BunkerRightMiddle       DW      0ff00h,0ff00h,0ff00h,0ff00h,0ff00h,0ff00h,0ff00h
BunkerRightBottom       DW      0ff00h,7f00h,3f00h,1f00h,1f00h,0f00h,0000h

SCO                     DW      071c7h,08a28h,08208h,07208h,00a08h,08a28h,071c7h
ORE                     DW      03cf8h,0a280h,0a280h,0bcf0h,0a280h,0a280h,022f8h

HIG                     DW      08be7h,08888h,08888h,0f88bh,08888h,08888h,08be7h
GH                      DW      02200h,0a200h,02200h,0be00h,0a200h,0a200h,02200h

Zero                    DW      3800h,4400h,4c00h,5400h,6400h,4400h,3800h
One                     DW      1000h,3000h,1000h,1000h,1000h,1000h,3800h
Two                     DW      3800h,4400h,0400h,1800h,2000h,4000h,7c00h
Three                   DW      3800h,4400h,0400h,1800h,0400h,4400h,3800h
Four                    DW      4400h,4400h,4400h,7c00h,0400h,0400h,0400h
Five                    DW      7c00h,4000h,4000h,7800h,0400h,4400h,3800h
Six                     DW      3800h,4400h,4000h,7800h,4400h,4400h,3800h
Seven                   DW      7c00h,0400h,0800h,1000h,1000h,1000h,1000h
Eight                   DW      3800h,4400h,4400h,3800h,4400h,4400h,3800h
Nine                    DW      3800h,4400h,4400h,3c00h,0400h,4400h,3800h

Equal                   DW      0000h,0000h,7c00h,0000h,7c00h,0000h,0000h
Period                  DW      0000h,0000h,0000h,0000h,0000h,0000h,1000h
CopyrightSymbol         DW      1e00h,2100h,4c80h,4880h,4c80h,2100h,1e00h

LetterA                 DW      3800h,4400h,4400h,7c00h,4400h,4400h,4400h
LetterB                 DW      7800h,4400h,4400h,7800h,4400h,4400h,7800h
LetterC                 DW      3800h,4400h,4000h,4000h,4000h,4400h,3800h
LetterD                 DW      7800h,4400h,4400h,4400h,4400h,4400h,7800h
LetterE                 DW      7c00h,4000h,4000h,7800h,4000h,4000h,7c00h
LetterF                 DW      7c00h,4000h,4000h,7800h,4000h,4000h,4000h
LetterG                 DW      3800h,4400h,4000h,5c00h,4400h,4400h,3800h
LetterH                 DW      4400h,4400h,4400h,7c00h,4400h,4400h,4400h
LetterI                 DW      7c00h,1000h,1000h,1000h,1000h,1000h,7c00h
LetterJ                 DW      0400h,0400h,0400h,0400h,0400h,4400h,3800h
LetterK                 DW      4400h,4800h,5000h,6000h,5000h,4800h,4400h
LetterL                 DW      4000h,4000h,4000h,4000h,4000h,4000h,7c00h
LetterM                 DW      4400h,6c00h,5400h,4400h,4400h,4400h,4400h
LetterN                 DW      4400h,6400h,5400h,4c00h,4400h,4400h,4400h
LetterO                 DW      3800h,4400h,4400h,4400h,4400h,4400h,3800h
LetterP                 DW      7800h,4400h,4400h,7800h,4000h,4000h,4000h
LetterQ                 DW      3800h,4400h,4400h,4400h,4400h,4c00h,3c00h
LetterR                 DW      7800h,4400h,4400h,7800h,4400h,4400h,4400h
LetterS                 DW      3800h,4400h,4000h,3800h,0400h,4400h,3800h
LetterT                 DW      7c00h,1000h,1000h,1000h,1000h,1000h,1000h
LetterU                 DW      4400h,4400h,4400h,4400h,4400h,4400h,3800h
LetterV                 DW      4400h,4400h,4400h,4400h,4400h,2800h,1000h
LetterW                 DW      4400h,4400h,4400h,4400h,5400h,6c00h,4400h
LetterX                 DW      4400h,4400h,2800h,1000h,2800h,4400h,4400h
LetterY                 DW      4400h,4400h,2800h,1000h,1000h,1000h,1000h
LetterZ                 DW      7c00h,0400h,0800h,1000h,2000h,4000h,7c00h

LogoOutline             DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,007ffh,01800h,02000h,04000h,040ffh,0403fh
                        DW      00000h,0e3ffh,01400h,00c00h,00400h,00607h,0fa03h
                        DW      00000h,0f80fh,00610h,00120h,000a0h,0c0e0h,0c0c1h
                        DW      00000h,0fc00h,00200h,00101h,00102h,00082h,08084h
                        DW      00000h,01fffh,06000h,08000h,00060h,000a0h,0011fh
                        DW      00000h,003ffh,08400h,04800h,04800h,0500fh,0900fh
                        DW      00000h,0ff80h,00040h,00040h,00080h,0ff00h,0c000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h

                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      02000h,01c00h,003fch,00fc3h,0103eh,01000h,00800h
                        DW      0e200h,01900h,00503h,00301h,00281h,00280h,00440h
                        DW      00181h,00682h,0f903h,00100h,00200h,08207h,04408h
                        DW      08044h,04048h,0c028h,00028h,00018h,0e018h,0100ch
                        DW      00100h,00200h,00200h,0047eh,00381h,00001h,00003h
                        DW      02000h,02000h,0403fh,04020h,0803fh,08000h,00000h
                        DW      02000h,02000h,0c000h,00000h,0f000h,00800h,00800h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h

                        DW      00000h,00000h,00000h,01fe0h,02011h,02009h,01009h
                        DW      00000h,00000h,00000h,0fc0fh,00310h,000d0h,00038h
                        DW      00700h,000ffh,00000h,0f1feh,00a01h,00600h,00300h
                        DW      03840h,0c03fh,00000h,00fe0h,01010h,09010h,05010h
                        DW      04408h,083f0h,00000h,07fe0h,08010h,08008h,08004h
                        DW      0100bh,00ff0h,00000h,00fffh,01000h,01000h,01000h
                        DW      0000dh,0fff0h,00000h,0f80fh,00610h,00110h,00090h
                        DW      00000h,0ffffh,00000h,0fff8h,00005h,00005h,0000ah
                        DW      01000h,0e000h,00000h,0ffffh,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,0803fh,060c0h,01100h,00a00h
                        DW      00000h,00000h,00000h,0ff00h,00080h,00040h,00040h

                        DW      01005h,00804h,00802h,00402h,00401h,00201h,00200h
                        DW      00008h,0800ch,08003h,08000h,080c0h,04070h,0c04ch
                        DW      00280h,00140h,00140h,000a0h,00090h,00048h,00044h
                        DW      02809h,02809h,01809h,00c0ah,0040ah,00406h,00206h
                        DW      00002h,00002h,00001h,00600h,00500h,00780h,00000h
                        DW      0100fh,01009h,0100ah,0900ah,0900ah,0500ch,0300ch
                        DW      000a0h,000a0h,000a0h,000a0h,000c0h,000c0h,000c0h
                        DW      03ff2h,03f04h,00084h,00084h,0ff08h,08008h,0ffc8h
                        DW      001c0h,001c0h,00000h,00000h,003c0h,00240h,00440h
                        DW      00a07h,00a07h,03100h,040e0h,0201ch,017e6h,00818h
                        DW      0e040h,09f80h,07000h,00800h,00400h,00400h,00400h

                        DW      00100h,00100h,00080h,0007fh,00000h,00000h,00000h
                        DW      0a023h,06020h,06010h,09fe0h,00000h,00000h,00000h
                        DW      00022h,0c021h,03010h,00fe0h,00000h,00000h,00000h
                        DW      00004h,00004h,0c004h,03ffbh,00000h,00000h,00000h
                        DW      00000h,003e0h,00420h,0f81fh,00000h,00000h,00000h
                        DW      03000h,01000h,01000h,0efffh,00000h,00000h,00000h
                        DW      00140h,00680h,01880h,0e07fh,00000h,00000h,00000h
                        DW      00030h,00030h,00050h,0ff8fh,00000h,00000h,00000h
                        DW      00420h,00410h,00810h,0f00fh,00000h,00000h,00000h
                        DW      00800h,00800h,00c00h,0f3ffh,00000h,00000h,00000h
                        DW      00400h,00800h,07000h,08000h,00000h,00000h,00000h

LogoLetters             DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,007ffh,01fffh,03fffh,03f00h,03fc0h
                        DW      00000h,00000h,0e3ffh,0f3ffh,0fbffh,0f9f8h,001fch
                        DW      00000h,00000h,0f80fh,0fe1fh,0ff1fh,03f3fh,03f3eh
                        DW      00000h,00000h,0fc00h,0fe00h,0fe01h,0ff01h,07f03h
                        DW      00000h,00000h,01fffh,07fffh,0ff9fh,0ff1fh,0fe00h
                        DW      00000h,00000h,003ffh,087ffh,087ffh,08ff0h,00ff0h
                        DW      00000h,00000h,0ff80h,0ff80h,0ff00h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h

                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      01fffh,003ffh,00003h,00000h,00fc1h,00fffh,007ffh
                        DW      001ffh,0e0ffh,0f8fch,0fcfeh,0fc7eh,0fc7fh,0f83fh
                        DW      0fe7eh,0f87ch,000fch,000ffh,001ffh,001f8h,083f0h
                        DW      07f83h,03f87h,03fc7h,0ffc7h,0ffe7h,01fe7h,00ff3h
                        DW      0fe00h,0fc00h,0fc00h,0f800h,0fc7eh,0fffeh,0fffch
                        DW      01fffh,01fffh,03fc0h,03fc0h,07fc0h,07fffh,0ffffh
                        DW      0c000h,0c000h,00000h,00000h,00000h,0f000h,0f000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h

                        DW      00000h,00000h,00000h,00000h,01fe0h,01ff0h,00ff0h
                        DW      00000h,00000h,00000h,00000h,0fc0fh,0ff0fh,0ffc7h
                        DW      000ffh,00000h,00000h,00000h,0f1feh,0f9ffh,0fcffh
                        DW      0c03fh,00000h,00000h,00000h,00fe0h,00fe0h,08fe0h
                        DW      083f0h,00000h,00000h,00000h,07fe0h,07ff0h,07ff8h
                        DW      00ff0h,00000h,00000h,00000h,00fffh,00fffh,00fffh
                        DW      0fff0h,00000h,00000h,00000h,0f80fh,0fe0fh,0ff0fh
                        DW      0ffffh,00000h,00000h,00000h,0fff8h,0fff8h,0fff1h
                        DW      0e000h,00000h,00000h,00000h,0ffffh,0ffffh,0ffffh
                        DW      00000h,00000h,00000h,00000h,0803fh,0e0ffh,0f1ffh
                        DW      00000h,00000h,00000h,00000h,0ff00h,0ff80h,0ff80h

                        DW      00ff8h,007f8h,007fch,003fch,003feh,001feh,001ffh
                        DW      0fff7h,07ff3h,07ffch,07fffh,07f3fh,03f8fh,03f83h
                        DW      0fc7fh,0fe3fh,0fe3fh,0ff1fh,0ff0fh,0ff87h,0ff83h
                        DW      0c7f0h,0c7f0h,0e7f0h,0f3f1h,0fbf1h,0fbf9h,0fdf9h
                        DW      0fffch,0fffch,0fffeh,0f9ffh,0f8ffh,0f87fh,0ffffh
                        DW      00ff0h,00ff0h,00ff1h,00ff1h,00ff1h,08ff3h,0cff3h
                        DW      0ff1fh,0ff1fh,0ff1fh,0ff1fh,0ff3fh,0ff3fh,0ff3fh
                        DW      0c001h,0c003h,0ff03h,0ff03h,00007h,00007h,00007h
                        DW      0fe3fh,0fe3fh,0ffffh,0ffffh,0fc3fh,0fc3fh,0f83fh
                        DW      0f1f8h,0f1f8h,0c0ffh,0801fh,0c003h,0e001h,0f7e7h
                        DW      01f80h,00000h,08000h,0f000h,0f800h,0f800h,0f800h

                        DW      000ffh,000ffh,0007fh,00000h,00000h,00000h,00000h
                        DW      01fc0h,09fc0h,09fe0h,00000h,00000h,00000h,00000h
                        DW      0ffc1h,03fc0h,00fe0h,00000h,00000h,00000h,00000h
                        DW      0fffbh,0fffbh,03ffbh,00000h,00000h,00000h,00000h
                        DW      0ffffh,0f81fh,0f81fh,00000h,00000h,00000h,00000h
                        DW      0cfffh,0efffh,0efffh,00000h,00000h,00000h,00000h
                        DW      0fe3fh,0f87fh,0e07fh,00000h,00000h,00000h,00000h
                        DW      0ffcfh,0ffcfh,0ff8fh,00000h,00000h,00000h,00000h
                        DW      0f81fh,0f80fh,0f00fh,00000h,00000h,00000h,00000h
                        DW      0f7ffh,0f7ffh,0f3ffh,00000h,00000h,00000h,00000h
                        DW      0f800h,0f000h,08000h,00000h,00000h,00000h,00000h

LogoShadow              DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      01fffh,07800h,0e000h,0c000h,08000h,00000h,00000h
                        DW      087ffh,00400h,00000h,00000h,00000h,00000h,00000h
                        DW      0f00fh,00410h,00000h,00000h,00000h,00000h,00000h
                        DW      0fc00h,00200h,00000h,00000h,00000h,00000h,00000h
                        DW      00fffh,02000h,08000h,00000h,00000h,00000h,00000h
                        DW      080ffh,0c000h,04000h,00000h,00000h,00000h,00000h
                        DW      0ffe0h,00060h,00000h,00000h,00000h,00000h,03000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h

                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,03c00h,0303ch,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00001h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,08000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,0003fh,00381h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,0001fh,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,0fc00h,00c00h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h

                        DW      00000h,00000h,0ff03h,0e003h,04002h,04002h,02000h
                        DW      00000h,00000h,0f03fh,00030h,00000h,00000h,00000h
                        DW      00000h,00000h,0c3fch,00200h,00000h,00000h,00000h
                        DW      00000h,00000h,01fc0h,01000h,00000h,00000h,00000h
                        DW      00000h,00000h,07fe0h,00010h,00008h,00004h,00000h
                        DW      00000h,00000h,00fffh,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,0f807h,00600h,00100h,00000h,00000h
                        DW      00000h,00000h,0fffch,00004h,00000h,00000h,00000h
                        DW      00000h,00000h,03fffh,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,0e007h,07800h,01c00h,00c00h,00400h
                        DW      00000h,00000h,0ffe0h,000f0h,00070h,00030h,00000h

                        DW      02000h,01001h,01001h,00800h,00800h,00400h,00400h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00001h,00000h,00000h,00200h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,04000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00080h,00000h,00000h,00000h,07fe0h,00020h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00200h
                        DW      00000h,00000h,00000h,03800h,01ce0h,00818h,00000h
                        DW      00000h,06000h,00f00h,00700h,00300h,00300h,00200h

                        DW      00200h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      04000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h
                        DW      00000h,00000h,00000h,00000h,00000h,00000h,00000h

;----------------------------------------------------------------------------------------------------------------------------------
; Variables
;----------------------------------------------------------------------------------------------------------------------------------

PauseCounter            DB      0
GameStart               DB      0
Frame                   DB      0
InvadersX               DW      275
InvadersY               DB      30
InvadersToggle          DW      07ff0h,07ff0h,07ff0h,07ff0h,07ff0h
PlayerX                 DW      154
LeftToggle              DB      0
RightToggle             DB      0
FireToggle              DB      0
ExitToggle              DB      0
SoundToggle             DB      0
KeyPress                DB      0
Sound                   DB      080h
NextLevelToggle         DB      0
MissileX                DW      0
MissileY                DB      0
UFOX                    DW      0
BombX                   DW      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
BombY                   DB      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
BombType                DB      0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
BombFreq                DW      010h
MoveCount               DB      1
InvaderSpeed            DB      55
Direction               DB      0
Reversing               DB      0
Collision               DB      0
Score                   DB      48,48,48,48,48
HighS                   DB      48,48,48,48,48
FirstFrame              DB      0
Lives                   DB      48
BombMove                DB      2
BombSpeed               DB      2
PlayerDead              DB      0
GameOverToggle          DB      0
InvadersTitle           DB      "S  P  A  C  E     I  N  V  A  D  E  R  S",0
Copyright               DB      "COPYRIGHT (  1995 BY PAUL S REID. ALL RIGHTS RESERVED",0
UFOScore                DB      "=   100 POINTS",0
Row1Score               DB      "=    25 POINTS",0
Row2Score               DB      "=    20 POINTS",0
Row3Score               DB      "=    15 POINTS",0
Row4Score               DB      "=    10 POINTS",0
Row5Score               DB      "=     5 POINTS",0
StartDocs               DB      "ANY KEY TO START GAME. ESC AT ANY TIME TO EXIT TO DOS",0
Dedication              DB      "...DEDICATED TO MY WIFE DEB...",0
ThankYou                DB      "THANKS TO BRENT KYLE AND TOM SWAN",0
SoundTog                DB      "PRESS S TO TOGGLE SOUND AT ANY TIME",0
PlayKeys                DB      "LEFT AND RIGHT CURSOR TO MOVE. CTRL TO FIRE",0
Distribution            DB      ".THIS GAME AND SOURCE CODE ARE FREELY DISTRIBUTABLE.",0
GameOverMsg             DB      "G  A  M  E      O  V  E  R",0
GetReady                DB      "G  E  T      R  E  A  D  Y",0
TempStore               DW      0
Palette                 DB      00,00,00    ; Background
                        DB      21,63,63    ; Player's Ship
                        DB      63,21,21    ; Bunker
                        DB      63,21,21    ; UFO
                        DB      63,63,63    ; Missiles
                        DB      21,63,21    ; Status Letters
                        DB      63,63,00    ; Bombs
                        DB      63,63,63    ; DOS text (just for diagnostic printing if required)
                        DB      12,00,21    ; Top and bottom border backgrounds
                        DB      33,00,42    ; Logo shadow color
                        DB      00,00,00    ; Logo outline color
                        DB      63,63,00    ; Logo letters color
                        DB      41,41,41    ; Logo stars
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      21,63,21    ; Row 1 invader 1
                        DB      21,63,21    ; Row 1 invader 2
                        DB      21,63,21    ; Row 1 invader 3
                        DB      21,63,21    ; Row 1 invader 4
                        DB      21,63,21    ; Row 1 invader 5
                        DB      21,63,21    ; Row 1 invader 6
                        DB      21,63,21    ; Row 1 invader 7
                        DB      21,63,21    ; Row 1 invader 8
                        DB      21,63,21    ; Row 1 invader 9
                        DB      21,63,21    ; Row 1 invader 10
                        DB      21,63,21    ; Row 1 invader 11
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      21,63,21    ; Row 2 invader 1
                        DB      21,63,21    ; Row 2 invader 2
                        DB      21,63,21    ; Row 2 invader 3
                        DB      21,63,21    ; Row 2 invader 4
                        DB      21,63,21    ; Row 2 invader 5
                        DB      21,63,21    ; Row 2 invader 6
                        DB      21,63,21    ; Row 2 invader 7
                        DB      21,63,21    ; Row 2 invader 8
                        DB      21,63,21    ; Row 2 invader 9
                        DB      21,63,21    ; Row 2 invader 10
                        DB      21,63,21    ; Row 2 invader 11
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      21,63,63    ; Row 3 invader 1
                        DB      21,63,63    ; Row 3 invader 2
                        DB      21,63,63    ; Row 3 invader 3
                        DB      21,63,63    ; Row 3 invader 4
                        DB      21,63,63    ; Row 3 invader 5
                        DB      21,63,63    ; Row 3 invader 6
                        DB      21,63,63    ; Row 3 invader 7
                        DB      21,63,63    ; Row 3 invader 8
                        DB      21,63,63    ; Row 3 invader 9
                        DB      21,63,63    ; Row 3 invader 10
                        DB      21,63,63    ; Row 3 invader 11
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      21,63,63    ; Row 4 invader 1
                        DB      21,63,63    ; Row 4 invader 2
                        DB      21,63,63    ; Row 4 invader 3
                        DB      21,63,63    ; Row 4 invader 4
                        DB      21,63,63    ; Row 4 invader 5
                        DB      21,63,63    ; Row 4 invader 6
                        DB      21,63,63    ; Row 4 invader 7
                        DB      21,63,63    ; Row 4 invader 8
                        DB      21,63,63    ; Row 4 invader 9
                        DB      21,63,63    ; Row 4 invader 10
                        DB      21,63,63    ; Row 4 invader 11
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      00,00,00
                        DB      63,21,63    ; Row 5 invader 1
                        DB      63,21,63    ; Row 5 invader 2
                        DB      63,21,63    ; Row 5 invader 3
                        DB      63,21,63    ; Row 5 invader 4
                        DB      63,21,63    ; Row 5 invader 5
                        DB      63,21,63    ; Row 5 invader 6
                        DB      63,21,63    ; Row 5 invader 7
                        DB      63,21,63    ; Row 5 invader 8
                        DB      63,21,63    ; Row 5 invader 9
                        DB      63,21,63    ; Row 5 invader 10
                        DB      63,21,63    ; Row 5 invader 11

VideoBuffer             DB      0

CODE_SEG                ENDS

                        END     BEGIN
