A game for the Smart Pox

kLeft           equ Keys                ; F1
kRight          equ Keys + 2            ; F2
kFire           equ Keys + 4            ; F3
kMenu           equ Keys + 3            ; F5

iBase_X         equ 11                  ; Start position

wBase           equ 13                  ; Width
wBaseFlag       equ 11                  ; Width
wShip           equ 19                  ;

xShield_0       equ 10                  ; LHS
xShield_1       equ 35                  ; Middle
xShield_2       equ 60                  ; RHS

yShield         equ 92                  ; Shield Y

Base_Min        equ 6                   ; Clip X
Base_Max        equ 122                 ;

Inv_Min         equ 8                   ; Clip X
Inv_Max         equ 120                 ;

                ; Offsets for invaders

iFlags          equ 0                   ; b0=alive,b1=bottom inv,b2=last
inX             equ 1                   ;
inY             equ 2                   ;
iType           equ 3                   ;

lInv            equ 4                   ; Length of table entry (must be 4)

nInvs           equ 32                  ; 8 by 4 array

mFlags          equ 0                   ; b0=Alive,b1=base/inv
mX              equ 1                   ;
mY              equ 2                   ;
mdY             equ 3                   ;
mType           equ 4                   ;
mSpeed          equ 5                   ;
miSpeed         equ 6                   ;
mLife           equ 7                   ;

lMiss           equ 8                   ; Length

nMiss           equ 5                   ; Number of missiles

ssiTime         equ 800                 ; Time to appear
;ssiTime         equ 1                   ; Time to appear
ssTime          equ 4                   ; Speed

Game_Prog_Start equ *

                org Game_SRAM_Base      ; Trample here with gay abandon

Score_D         ds 2                    ; Score
Score_A         ds 2                    ; Displayed
Highscore_D     ds 2                    ; Highest
Highscore_A     ds 2                    ; Highest Displayed

Sheet_No        ds 1                    ; Current sheet no. 0..?

Game_Flag       ds 1                    ; Alive or dead or new sheet

Base_X          ds 1                    ; Position of base center

Base_Cnt_D      ds 1                    ; Number of bases
Base_Cnt_A      ds 1                    ; Displayed

NewBaseF        ds 1                    ; Had extra one

Inv_X_Step      ds 1                    ; Current step
Inv_Y_Step      ds 1                    ; Count to add to Y

Inv_Change_Dir  ds 1                    ; Flag for hit side

Inv_Moved_Flag  ds 1                    ; Flag for end of sheet

pInv_Move_Tab   ds 2                    ; Ptr to table of move order

Ship_Delay      ds 2                    ; Counter for spaceship
Ship_Flag       ds 1                    ; Alive/dead
Ship_Disp       ds 1                    ; Direction

pShip_Score     ds 2                    ; Ptr to score table

Ship_X          ds 1                    ; X of ship

Invaders_Tab    ds nInvs * lInv         ; Table for invaders

Missile_Tab     ds nMiss * lMiss        ; Table for missiles

ScorePage       ds 128                  ; The high-score, etc

                align 256

Frame_Buff      ds 9*256                ; ..[64]..DD[128]DD..[64].. x 9

        if * >= (Stack)                 ; Safe?
          def 31,"Too much SRAM !!"     ;
        endif                           ;

Code starts

                org Game_Prog_Start     ; Restore the assembly pointer

Put the game init here

        ; Exit

vForceReset     jmp ForceReset          ; Done

Start_Game      ld al,#128              ; Green
                ld dBright_Green,al     ;

                ld al,#0                ;
                ld dBright_Red,al       ;
;                ld dBright_Blue,al      ;

                ; Get the high-score

                ldw x,#eeHigh           ; Get the highscore from EEROM
                rcall Read_AL_EEROM     ;
                ld Highscore_D,al       ;

                ldw x,#eeHigh+1         ;
                rcall Read_AL_EEROM     ;
                ld Highscore_D+1,al     ;

                ; Was it valid?

                cp al,#$FF              ; Invalid ?
                bne SG_GotHigh          ; No, skip

                ; Invalid high-score, zero it

                ldw ah:al,#0            ; Clear high score
                ld Highscore_D,al       ;
                ld Highscore_D+1,al     ;

                ; Disable serial comms

SG_GotHigh      ld al,#0                ; Kill the serial comms
                ld UCSR0B,al            ;

                ; Get on with it...

New_Game        rcall Cls               ; Cls

                rcall Cls_Score         ; And the score

                rcall Init_Prog         ; Set up the timer etc.

                rcall Init_Game         ; Set up the game

                rcall Init_Base         ; Set up the next base

                rcall Init_Missiles     ; Clear the projectile list

Sheet_Lp        rcall Init_Sheet        ; Set up the sheet

                rcall Save_HighScore    ; Save it iff it's changed...

Game_Lp         ld al,Game_Valid        ; Should be $42?
                cp al,#$42              ;
                bne vForceReset         ; Nope, exit

                ; Randomize

                ld ah,Rand              ;
                add ah,al               ;
                ld Rand,ah              ;

                rcall Move_Missiles     ; Move the missiles
                rcall Move_Base         ; Move the base
                rcall Move_Invaders     ; Move one invader one place
                rcall Move_Spaceship    ; Move the ship, if present

                ld al,Base_Cnt_A        ; Get displayed count
                ld ah,Base_Cnt_D        ; Get real cnt

                cp al,ah                ; Same as displayed ?
                beq Game_DCE            ; Yes, skip

                rcall Disp_Base_Cnt     ; No, show new value

Game_DCE        ld al,Score_D           ; Get real score
                ld ah,Score_D+1         ;

                ld bl,Score_A           ; Get displayed score
                ld bh,Score_A+1         ;

                cp al,bl                ; Same
                cpc ah,bh               ;
                beq Game_SE             ; Yes, skip

                rcall Disp_Score        ; No, show new value

                ; New high-score ?

Game_SE         ld al,Highscore_D       ; Get real score
                ld ah,Highscore_D+1     ;

                ld bl,Highscore_A       ; Get displayed score
                ld bh,Highscore_A+1     ;

                cp al,bl                ; Same
                cpc ah,bh               ;
                beq Game_HSE            ; Yes, skip

                rcall Disp_HighScore    ; No, show new value

Game_HSE        rcall Paint_LCD         ; Paint the entire screen

                ld al,Game_Flag         ; Keep playing ?
                tst al                  ;
                bne Game_1              ; No, new sheet or killed

                ld al,kMenu             ; Check for exit
                sbrs al,#7              ;
                rjmp Game_Lp            ; No, carry on

                rcall Save_HighScore    ; Write the highscore

                jmp ForceReset          ; Back to system

        ; New sheet, etc?

Game_1          cp al,#1                ; New sheet ?
                beq Sheet_Lp            ; Yes

                push al                 ; Save state

                rcall Base_Explode      ; Bang !

                pop al                  ; Restore reason for death

                cp al,#3                ; All killed ? (landed)
                beq vNew_Game           ;

                ld al,Base_Cnt_D        ; Kill one base
                dec al                  ;
                ld Base_Cnt_D,al        ;

                beq vNew_Game           ; All killed

                ld al,#0                ; Clear flag
                ld Game_Flag,al         ;

                rjmp Game_Lp            ; Next base

                ; Game loop

                wdr                     ;

                rjmp Game_Lp            ; Loop

vNew_Game       rjmp New_Game           ; Short branches

Save_HighScore  ldw x,#eeHigh           ; Write the highscore to EEROM
                ld al,Highscore_D       ;
                rcall Write_AL_EEROM    ;

                ldw x,#eeHigh+1         ;
                ld al,Highscore_D+1     ;
                rcall Write_AL_EEROM    ;

                ret                     ; Done

Paint the frame-buffer, with or without scoreline

Paint_LCD       wdr                     ; Don't bite!

                ld al,Ship_Flag         ; Do we have a ship?
                tst al                  ;
                bne Paint_1             ; Yes, paint all the screen

                ; No ship, use the top page for scores, etc

                ld al,#0                ; Page 0
                ldw z,#ScorePage        ; Use this

                rjmp Paint_Page         ; As below

Paint_1         ld al,#0                ; First page

Paint_Lp        ld zh,# high Frame_Buff ; Calc pointer
                add zh,al               ;
                ld zl,#64               ; First visible byte

Paint_Page      ld rLPAGE,al            ; Page

                push al                 ; Save
                call Paint_LCD_PageZ    ; Paint it
                pop al                  ; Restore

                inc al                  ; Next page
                cp al,#8                ; Loop
                bne Paint_Lp            ;

                ret                     ; Done

Init the game

Init_Prog       ld al,Game_Valid        ; Should we be here?
                cp al,#$42              ;
                bne vForceReset2        ; No, bugger off

                ; Grab control of the timers...

                ld Game_Enabled,al      ; Enable us

                ret                     ; Done

vForceReset2    jmp ForceReset          ; Silly branches

Clear the screen...

Cls_Score       ldw y,#ScorePage        ; Score page

                ld bl,#128              ; This many
                ld al,#$00              ;

Cls_Lp3         ld y+,al                ; Clear one
                dec bl                  ;
                bne Cls_Lp3             ;

                ret                     ; Done

Cls             ld yh,# high Frame_Buff ; First page

Cls_Lp          ld yl,#64               ; First byte

                ld bl,#128              ; This many
                ld al,#$00              ;

Cls_Lp2         ld y+,al                ; Clear one
                dec bl                  ;
                bne Cls_Lp2             ;

                ; Next 'page'

                inc yh                        ;
                cp yh,#( high Frame_Buff) + 8 ; End?
                bne Cls_Lp                    ; No, loop

                ret                     ; Done

Init the game

Init_Game       ld al,#0                ; Start at sheet 0
                ld Sheet_No,al          ;
                ld NewBaseF,al          ;

                ld Score_D,al           ;
                ld Score_D+1,al         ;

                ld al,#1                ; Make displayed value different,
                ld Score_A,al           ; to force an update

                rcall Disp_HighScore    ; Show the highest

                ld al,#3                ; Start with 3 bases
                ld Base_Cnt_D,al        ;

                ld al,#0                ; Force update
                ld Base_Cnt_A,al        ;

                rcall Init_Spaceship    ; Set up delay

                ret                     ; Done

Init the sheet

Init_Sheet      ld al,#0                ; Clear flag
                ld Game_Flag,al         ;

                ld al,Sheet_No          ; Get no. of attack wave
                ld ah,al                ; Save

                inc ah                  ; Step it
                and ah,#$07             ; Mask

                ld Sheet_No,ah          ; Next wave no (0..7)

                rcall Init_Invaders     ; Create the inv. data

                rcall Draw_Invaders     ; Show them

                rcall Draw_Shields      ; Show the shields

                ldw y,#Ship_Score_Tab   ; Reset ship's score count
                ld pShip_Score,yl       ;
                ld pShip_Score+1,yh     ;

                ret                     ; Dummy

Init the base

Init_Base       ld al,#iBase_X          ; Reset base position
                ld Base_X,al            ;

                rcall Draw_Base_AL      ; Show the base

                ret                     ; Done

Init the missiles

Init_Missiles   ldw y,#Missile_Tab      ; Point at table

                ld bl,#nMiss            ; Number

                ld al,#0                ; Null flags
IM_Lp           ld y+mFlags,al          ; Kill them

                adiw y,#lMiss           ; Skip

                dec bl                  ; Loop
                bne IM_Lp               ;

                ret                     ; Done

Clear_Missiles  ldw y,#Missile_Tab      ; Point at table

                ld bl,#nMiss            ; Number

CM_Lp           ld al,y+mFlags          ; Is it alive ?
                sbrs al,#0              ;
                rjmp CM_1               ; No, skip

                push bl                 ; Save cnt
                rcall Explode_Miss      ; Kill missile
                pop bl                  ;

CM_1            adiw y,#lMiss           ; Length of entry

                dec bl                  ; Loop
                bne CM_Lp               ;

                ret                     ; Done

Explode_Miss    rcall Undraw_Miss       ; Clear it

                ld al,#1                ; Fast(ish)
                ld y+miSpeed,al         ;

                ld al,y+mFlags          ; Assert explosion flag
                or al,#$80              ;
                ld y+mFlags,al          ;

                ld al,#6                ; Lifetime of explosion
                ld y+mLife,al           ;

                ld al,y+mX              ; Explosions are wider
                sub al,#2               ;
                ld y+mX,al              ;

                ret                     ; Done

Get_Miss_Space_Z ldw z,#Missile_Tab + lMiss ; Point to table
                ld bl,#nMiss - 1          ; Number to check

GMS_Lp          ld al,z+mFlags          ; Alive ?
                and al,#$01             ; Check, clear carry
                beq GMS_X               ; No, use

                adiw z,#lMiss           ; Skip

                dec bl                  ; Loop
                bne GMS_Lp              ;

                sec                     ; Fail
GMS_X           ret                     ; Done

Move_Missiles   ldw y,#Missile_Tab      ; Point at data area

                ld bl,#nMiss            ; Number of missiles

MM_Lp           ld al,y+mFlags          ; Alive ?
                sbrs al,#0              ;
                rjmp MM_Next            ; No, ignore it

                ld al,y+mSpeed          ; Count down
                dec al                  ;
                ld y+mSpeed,al          ;

                bne MM_Next             ; Skip till time

                push bl                 ; Save cnt
                rcall Move_Miss         ; Move it
                pop bl                  ;

MM_Next         adiw y,#lMiss           ; Step ptr

                dec bl                  ; Loop
                bne MM_Lp               ;

                ret                     ; Done

Move the missile at [Y]

Move_Miss       rcall Undraw_Miss       ; Undraw it

MM_Start        ld al,y+miSpeed         ; Reset speed
                ld y+mSpeed,al          ;

                ld al,y+mFlags          ; Proj. or explosion ?
                sbrc al,#7              ; Proj. or explosion ?
                rjmp MM_Explo           ; Explosion

                ld al,y+mY              ; Get it's Y
                ld ah,y+mdY             ; Move it
                add al,ah               ;
                ld y+mY,al              ; Store

                ; Randomize

                ld ah,Rand              ;
                add ah,al               ;
                ld Rand,ah              ;

                sbrc al,#7              ; Hit roof?
                rjmp vMME_Done          ; Hit roof... done

                cp al,#64               ; Hit ground ?
                bcc vMME_Done           ; Yes, done

                ; Look for collisions

                rcall Collide_Miss      ; Hit anything ?
                bne MM_Kill             ; Yes, kill etc.

                ; Cycle the type

                ld al,y+mType           ; Change type
                ld ah,#$01              ;
                xor al,ah               ;
                ld y+mType,al           ;

                rjmp Draw_Miss          ; Draw it

vMME_Done       rjmp MME_Done           ; Stupid short branches

MM_Kill         ld al,y+mY              ; Check for base killed
                cp al,#64-(5+5)         ; Possible ?
                bcs MMK_1               ; No, too high

                ld al,y+mdY             ; Direction?
                sbrc al,#7              ; Down?
                rjmp MMK_1              ; No, skip

                ld al,Base_X            ; Get the base X
                ld ah,y+mX              ; Get difference
                sub al,ah               ;
                bpl MMK_a               ; Positive

                neg al                  ; Abs

MMK_a           cp al,#7                ; Hit base ?
                bcc MMK_1               ; No, too far away

                ld al,#2                ; Base killed
                ld Game_Flag,al         ;

                ret                     ; Ignore rest of code

        ; Check for invader hit

MMK_1           ld bl,y+mX              ; Get X

                ld al,y+mY              ; Y
                sub al,#7               ; - 7
                ld cl,al                ;

                sub al,#-15             ; + 7
                ld ch,al                ;

                ldw z,#Invaders_Tab     ; Look in table

MMK_2_Lp        ld al,z+iFlags          ; Alive?
                sbrs al,#0              ;
                rjmp MMK_2_X            ; No, skip

                ld al,z+inX             ; Get X

                sub al,bl               ; Get dX
                bpl MMK_2a              ; Positive

                neg al                  ; Abs

MMK_2a          cp al,#5                ; Hit invader ?
                bcc MMK_2_X             ; Fail

                ld al,z+inY             ; Get Y

                cp al,ch                ; Top
                bcc MMK_2_X             ; Not this one
                cp al,cl                ; Bottom
                bcs MMK_2_X             ; No

                ; This (Z) invader hit

                push y,z                ; Save

                ldw y,z                 ; Point at it
                rcall Undraw_Inv        ; Clear it

                pop z,y                 ; Restore

                ld al,z+iFlags          ; Kill it
                and al,#$FE             ;
                ld z+iFlags,al          ;

                ld al,z+inX             ; Use its co-ords
                ld y+mX,al              ;

                ld al,z+inY             ; Use its co-ords
;                sub al,#-1              ;
                ld y+mY,al              ;

                ldw ah:al,#0010         ; Add score
                rcall Add_Score         ;

                rjmp MMK_4              ; Explode

MMK_2_X         ld al,z+iFlags          ; Last one?
                sbrc al,#2              ;
                rjmp MMK_3              ; Yes, done

                adiw z,#lInv            ; Skip

                rjmp MMK_2_Lp           ; Loop

                ; Hit spaceship ?

MMK_3           ld al,Ship_Flag         ; Is it alive ?
                tst al                  ;
                beq MMK_4               ; No, ignore

                ld ah,Ship_X            ; X

                ld al,y+mX              ; Get difference X
                sub al,ah               ;

                bpl MMK_3a              ; Positive

                neg al                  ; Abs

MMK_3a          cp al,#10               ; Hit ship?
                bcc MMK_4               ; Fail

                ld al,y+mY              ; In top line ?
                cp al,#8                ;
                bcc MMK_4               ; No, can't be ship

                ; Ship hit

                rcall Undraw_Ship       ; Remove the ship

                rcall Init_Spaceship    ; Reset ship

                ld zl,pShip_Score       ; Get score
                ld zh,pShip_Score+1     ;

                lpm al,z+               ;
                lpm ah,z+               ;

                rcall Add_Score         ; Step the score

                ld al,Ship_X            ; Move explosion to middle of ship
                ld y+mX,al              ;

                ld al,#0                ; Height
                ld y+mY,al              ;

MMK_4           ld al,y+mFlags          ; Assert explosion flag
                or al,#$80              ;
                ld y+mFlags,al          ;

                ld al,#6                ; Lifetime of explosion
                ld y+mLife,al           ;

MM_Explo        ld al,y+mLife           ; Time out ?
                dec al                  ;
                ld y+mLife,al           ;
                beq MME_Done            ; Yes, kill it

                ld al,Rand              ; Get a random no.
                and al,#$03             ;
                or al,#%100             ; Explosion shape 4..7
                ld y+mType,al           ;

                rjmp Draw_Miss          ; Show the explosion

MME_Done        ld al,#0                ; Kill it
                ld y+mFlags,al          ;
                ret                     ; Done

Draw a missile/explosion

Draw_Miss       ld ah,y+mType           ; 00x = Gr_Miss0 10=1a 11=1b
                                        ; 1xx = explosion
                sbrc ah,#2              ; Expl?
                rjmp DM_Expl            ; Yes, skip

                ; It's a missile

                ldw z,#Gr_Miss0         ; Assume it's a line
                ld bl,#1                ; Width := 1
                ld al,y+mX              ; X

                sbrs ah,#1              ; Type 00 or 01?
                rjmp DM_Draw            ; Yes, skip

                ldw z,#Gr_Miss1a        ; Assume it's 1a
                ld bl,#3                ; Width :=3
                dec al                  ; X:=X-1

                cp ah,#%10              ; 1a
                beq DM_Draw             ; Yes, skip

                ldw z,#Gr_Miss1b        ; It's 1b
                rjmp DM_Draw            ;

        ; The explosions

DM_Expl         ld bl,#5                ; Width = 5
                ld al,y+mX              ; X
                sub al,#2               ; LHS

                ldw z,#Gr_Exp0          ; 0?
                cp ah,#%100             ;
                beq DM_Draw             ; Yes, skip

                ldw z,#Gr_Exp1          ; 1?
                cp ah,#%101             ;
                beq DM_Draw             ; Yes, skip

                ldw z,#Gr_Exp2          ; 0?
                cp ah,#%110             ;
                beq DM_Draw             ; Yes, skip

                ldw z,#Gr_Exp3          ; Must be 3

DM_Draw         ld ah,y+mY              ; Top

                ; Now, calc the frame-buffer

OR_Sprite       ld xl,al                ; Setup the X address
                sub xl,#-64             ;

                ld xh,ah                ; Top-Y
                clc                     ;
                ror xh                  ; /8
                ror xh                  ;
                ror xh                  ;
                and xh,#%111            ;

                cp xh,#8                ; Off-bottom?
                bcc DMD_X               ; Yes, forget it, not visible

                sub xh,#-(high Frame_Buff); Point at the frame-buffer

                ; Now, point at the correct rotate data

                and ah,#%111            ; 0..7
                add ah,ah               ; * 2
                add zl,ah               ; Add to base
                adc zh,ah               ;
                sub zh,ah               ;

OR_SpriteLp     ld al,x                 ; Get the first byte
                lpm ah,z+               ;
                or al,ah                ;
                ld x,al                 ;

                inc xh                  ; Move down

                ld al,x                 ; Get the second byte
                lpm ah,z+               ;
                or al,ah                ;
                ld x+,al                ; Move right

                dec xh                  ; Back up

                adiw z,#7*2             ; Skip rotates

                dec bl                  ; Loop
                bne OR_SpriteLp         ;

DMD_X           ret                     ; Done

        ; Undraw a missile

Undraw_Miss     ld ah,y+mType           ; 00x = Gr_Miss0 10=1a 11=1b
                                        ; 1xx = explosion
                sbrc ah,#2              ; Expl?
                rjmp UDM_Expl           ; Yes, skip

                ; It's a missile

                ldw z,#Gr_Miss0         ; Assume it's a line
                ld bl,#1                ; Width := 1
                ld al,y+mX              ; X

                sbrs ah,#1              ; Type 00 or 01?
                rjmp UDM_Draw           ; Yes, skip

                ldw z,#Gr_Miss1a        ; Assume it's 1a
                ld bl,#3                ; Width :=3
                dec al                  ; X:=X-1

                cp ah,#%10              ; 1a
                beq UDM_Draw            ; Yes, skip

                ldw z,#Gr_Miss1b        ; It's 1b
                rjmp UDM_Draw           ;

        ; The explosions

UDM_Expl        ld bl,#5                ; Width = 5
                ld al,y+mX              ; X
                sub al,#2               ; LHS

                ldw z,#Gr_Exp0          ; 0?
                cp ah,#%100             ;
                beq UDM_Draw            ; Yes, skip

                ldw z,#Gr_Exp1          ; 1?
                cp ah,#%101             ;
                beq UDM_Draw            ; Yes, skip

                ldw z,#Gr_Exp2          ; 0?
                cp ah,#%110             ;
                beq UDM_Draw            ; Yes, skip

                ldw z,#Gr_Exp3          ; Must be 3

UDM_Draw        ld ah,y+mY              ; Top

                ; Now, calc the frame-buffer

AND_Sprite      ld xl,al                ; Setup the X address
                sub xl,#-64             ;

                ld xh,ah                ; Top-Y
                clc                     ;
                ror xh                  ; /8
                ror xh                  ;
                ror xh                  ;
                and xh,#%111            ;

                cp xh,#8                ; Off-bottom?
                bcc UDMD_X              ; Yes, forget it, not visible

                sub xh,#-(high Frame_Buff); Point at the frame-buffer

                ; Now, point at the correct rotate data

                and ah,#%111            ; 0..7
                add ah,ah               ; * 2
                add zl,ah               ; Add to base
                adc zh,ah               ;
                sub zh,ah               ;

AND_SpriteLp    ld al,x                 ; Get the first byte
                lpm ah,z+               ;
                com ah                  ;
                and al,ah               ;
                ld x,al                 ;

                inc xh                  ; Move down

                ld al,x                 ; Get the second byte
                lpm ah,z+               ;
                com ah                  ;
                and al,ah               ;
                ld x+,al                ; Move right

                dec xh                  ; Back up

                adiw z,#7*2             ; Skip rotates

                dec bl                  ; Loop
                bne AND_SpriteLp        ;

UDMD_X          ret                     ; Done

        ; Has this missile collided with anything?

Collide_Miss    ldw z,#Gr_Miss0         ; Assume it's a line
                ld bl,#1                ; Width := 1
                ld al,y+mX              ; X

                ld ah,y+mType           ; 0x = Gr_Miss0 10=1a 11=1b

                sbrs ah,#1              ; Type 00 or 01?
                rjmp CM_Check           ; Yes, skip

                ldw z,#Gr_Miss1a        ; Assume it's 1a
                ld bl,#3                ; Width :=3
                dec al                  ; X:=X-1

                cp ah,#%10              ; 1a
                beq CM_Check            ; Yes, skip

                ldw z,#Gr_Miss1b        ; It's 1b

CM_Check        ld ah,y+mY              ; Top

                ; Now, calc the frame-buffer

Check_Sprite    ld xl,al                ; Setup the X address
                sub xl,#-64             ;

                ld xh,ah                ; Top-Y
                clc                     ;
                ror xh                  ; /8
                ror xh                  ;
                ror xh                  ;
                and xh,#%111            ;

                cp xh,#8                ; Off-bottom?
                bcc CS_No               ; Yes, forget it, not visible

                sub xh,#-(high Frame_Buff); Point at the frame-buffer

                ; Now, point at the correct rotate data

                and ah,#%111            ; 0..7
                add ah,ah               ; * 2
                add zl,ah               ; Add to base
                adc zh,ah               ;
                sub zh,ah               ;

Check_SpriteLp  ld al,x                 ; Get the first byte
                lpm ah,z+               ;
                and al,ah               ; Hit?
                bne CS_Yes              ;

                inc xh                  ; Move down

                ld al,x+                ; Get the second byte
                lpm ah,z+               ;
                and al,ah               ;
                bne CS_Yes              ; Hit?

                dec xh                  ; Back up

                adiw z,#7*2             ; Skip rotates

                dec bl                  ; Loop
                bne Check_SpriteLp      ;

CS_No           xor al,al               ; Z
CS_Yes          ret                     ; Done

Step the ship's score

Step_Ship_Score ld zl,pShip_Score       ; Step pointer
                ld zh,pShip_Score+1     ;

                adiw z,#2               ; Step it

                lpm al,z+               ; Read it
                lpm ah,z                ;

                dec z                   ; Move back

                cp al,#0                ; 0?
                cpc al,ah               ;
                bne SSS_Set             ; No, skip

                ldw z,#SST_1            ; Reset the pointer

SSS_Set         ld pShip_Score,zl       ;
                ld pShip_Score+1,zh     ;

SSS_X           ret                     ; Done

Init the spaceship

Init_Spaceship  ldw x,#ssiTime          ; Set up wait count
                ld Ship_Delay,xl        ;
                ld Ship_Delay+1,xh      ;

                ld al,#0                ; Ship active flag
                ld Ship_Flag,al         ;

IS_X            ret                     ; Done

Move the spaceship

Move_Spaceship  ld yl,Ship_Delay        ; Count down
                ld yh,Ship_Delay+1      ;
                dec y                   ;
                ld Ship_Delay,yl        ;
                ld Ship_Delay+1,yh      ;

                bne IS_X                ; Not time yet

                ldw y,#ssTime           ; Reset count
                ld Ship_Delay,yl        ;
                ld Ship_Delay+1,yh      ;

                ld al,Ship_Flag         ; Alive ?
                tst al                  ;
                bne MS_Move             ; Yes, move it

                ld al,#1                ; Flag alive
                ld Ship_Flag,al         ;

                ld yh,#0-(wShip/2)      ; LHS
                ld yl,#2                ; Move right

                ld al,Rand              ; Get random
                and al,#$01             ;
                bne MS_1                ; Go right

                ld yh,#127+(wShip/2)    ; RHS
                ld yl,#-2               ; Move left

MS_1            ld Ship_X,yh            ; Set X
                ld Ship_Disp,yl         ; Set Disp

                rjmp Draw_Ship          ; Show it

MS_Move         rcall Undraw_Ship       ; Clear it

                ld al,Ship_X            ; Get X
                ld ah,Ship_Disp         ; Step it
                add al,ah               ;
                ld Ship_X,al            ;

                ; Ship visble?

                ld ah,al                ; Both sides visible?
                sub al,#-wShip/2        ; RHS
                sub ah,#wShip/2         ; LHS
                and al,ah               ; Both visible if top-bit not set

                and al,#$80             ; Done ?
                bne Init_Spaceship      ; Yes, kill it

                ; Fall into...

                rjmp Draw_Ship          ; Draw it

Init the invaders (AL=Sheet number)

Init_Invaders   and al,#$07             ; Only eight waves

                ldw z,#Inv_Y_Table      ; Look-up start Y
                add zl,al               ;
                adc zh,al               ;
                sub zh,al               ;

                lpm cl,z                ; Get the Y

                ldw y,#Invaders_Tab     ; Point at data area

                ldw z,#Invaders_Data    ; Definition for init.

                ld bl,#nInvs            ; Number of invaders

II_Lp           lpm al,z+               ; Get flags
                ld y+iFlags,al          ; Store

                lpm al,z+               ; Get X
                sub al,#-8              ; Add an offset
                ld y+inX,al             ; Store

                lpm al,z+               ; Get Y
                add al,cl               ; Add start Y
                ld y+inY,al             ; Store

                ld al,z+                ; Get Type
                ld y+iType,al           ; Store

                adiw y,#lInv            ; Step ptr

                dec bl                  ; Loop
                bne II_Lp               ;

                ld al,#0                ; Clear flags
                ld Inv_Change_Dir,al    ;
                ld Inv_Y_Step,al        ;

                ld al,#2                ; Step size
                ld Inv_X_Step,al        ;

                ldw y,#Inv_Move_R_Tab   ; Table to use
                ld pInv_Move_Tab,yl     ;
                ld pInv_Move_Tab+1,yh   ;

                ret                     ; Done

Draw_Invaders   ldw y,#Invaders_Tab     ; Data for the invaders

DI_Lp           rcall Draw_Inv          ; Draw the thing

                ld al,y+iFlags          ; Last invader ?
                sbrc al,#2              ;
                ret                     ; Yes, done

                adiw y,#lInv            ; Step ptr

                rjmp DI_Lp              ; Loop

MI_Next_Step    ld al,Inv_Moved_Flag    ; Have we moved any ?
                tst al                  ;
                bne MINS_OK             ; Yes, continue

                ld al,#1                ; New sheet
                ld Game_Flag,al         ;

                ret                     ; Done

MINS_OK         ld al,#0                ; Clear stepping down flag
                ld Inv_Y_Step,al        ;
                ld Inv_Moved_Flag,al    ; kill any alive flag

                ldw z,#Inv_Move_R_Tab   ; Table for right
                ldw x,#Inv_Move_L_Tab   ; Table for left

                ld al,Inv_X_Step        ; L or R?
                sbrs al,#7              ;
                rjmp MINS_R             ; +ve

                ; Swap tables

                ld al,xl                ;
                ld xl,zl                ;
                ld zl,al                ;

                ld al,xh                ;
                ld xh,zh                ;
                ld zh,al                ;

MINS_R          ld al,Inv_Change_Dir    ; Check flag
                tst al                  ;
                beq MINS_1              ; Don't bounce

                ld al,#0                ; Clear flag
                ld Inv_Change_Dir,al    ;

                ; Swap tables

                ld al,xl                ;
                ld xl,zl                ;
                ld zl,al                ;

                ld al,xh                ;
                ld xh,zh                ;
                ld zh,al                ;

                ld al,Inv_X_Step        ; Swap dirn
                neg al                  ;
                ld Inv_X_Step,al        ;

                ld al,#2                ; Set Y step
                ld Inv_Y_Step,al        ;

MINS_1          ld pInv_Move_Tab,zl     ; Store ptr
                ld pInv_Move_Tab+1,zh   ;

Move_Invaders   ld zl,pInv_Move_Tab     ; Get the next invader to move
                ld zh,pInv_Move_Tab+1   ;

                lpm al,z+               ; Get its no.
                tst al                  ; End ?
                beq MI_Next_Step        ; Yes, reset ptr

                ld pInv_Move_Tab,zl     ;
                ld pInv_Move_Tab+1,zh   ;

                dec al                  ; 0..35

                ld ah,#lInv             ; * lInv
                mul al,ah               ;

                ldw y,#Invaders_Tab     ; Index into the table
                add yl,r0               ;
                adc yh,r1               ;

                ld al,y                 ; Alive ?
                sbrs al,#0              ;
                rjmp Move_Invaders      ; No, get next one

                ld al,#1                ; Assert one moved flag
                ld Inv_Moved_Flag,al    ;

                rcall Undraw_Inv        ; Clear it

                ld al,Inv_X_Step        ; Move it

                ld ah,y+inX             ;
                add ah,al               ;
                ld y+inX,ah             ;

                sbrc al,#7              ; Check dirn
                rjmp MI_L               ; Moving left

                cp ah,#Inv_Max          ; Hit RHS ?
                bcs MI_0                ; No

                ld al,#1                ; Flag it
                ld Inv_Change_Dir,al    ;

                rjmp MI_0               ; Next

MI_L            cp ah,#Inv_Min          ; Hit LHS ?
                bcc MI_0                ; No

                ld al,#1                ; Flag it
                ld Inv_Change_Dir,al    ;

MI_0            ld ah,Inv_Y_Step        ; Move it
                ld al,y+inY             ;
                add al,ah               ;
                ld y+inY,al             ;

                ; Randomize

                ld ah,Rand              ;
                add ah,al               ;
                ld Rand,ah              ;

                ; Check Y

                cp al,#60-5;;104-5      ; Landed ?
                bcs MI_1                ; No

                ld al,#3                ; All killed
                ld Game_Flag,al         ;

MI_1            ld al,y+iType           ; Change shape
                ld ah,al                ;

                inc al                  ; Step

                xor al,ah               ;
                and al,#$FC             ; Up to 4 shapes
                xor al,ah               ;

                ld y+iType,al           ; Store new shape

                rcall Draw_Inv          ; Show it

                ; Now do firing . . .

                ld al,Rand              ; Get a random
                and al,#$1D             ; Do we want to fire ?
                bne MI_X                ; No, exit

                rcall Get_Miss_Space_Z  ; Space in the table ?
                bcs MI_X                ; No, ignore

MI_GL_Lp        ld al,y+iFlags          ; Alive ?
                sbrs al,#0              ;
                rjmp MI_GL_1            ; No, skip

                ldw x,y                 ; Save ptr

MI_GL_1         sbrc al,#1              ; Bottom?
                rjmp MI_GL_X            ; Yes, done

                adiw y,#lInv            ; Skip it

                rjmp MI_GL_Lp           ; Loop

MI_X            ret                     ; Done

MI_GL_X         ldw y,x                 ; Get last live one

                ld al,#1                ; Create it
                ld z+mFlags,al          ;

                ld al,y+inX             ; Get X
                ld z+mX,al              ;

                ld al,y+inY             ; Get Y
                sub al,#-6              ; + 6
                ld z+mY,al              ;

                ld al,Rand              ; Get type
                and al,#$02             ;
                ld z+mType,al           ; Type 0 (line) or 1 (Zig-Zag)

                ld al,#2                ; Step downwards
                ld z+mdY,al             ;

                ld al,Rand              ; Get random speed
                ror al                  ;
                ror al                  ;
                and al,#$07             ;
                sub al,#-3              ;
                ld z+miSpeed,al         ;

                ldw y,z                 ; Get the pointer to this projectile
                rjmp MM_Start           ; Move the projectile

Move the base

Move_Base       ld al,kLeft             ; Left flag
                and al,#$80             ;

                ld ah,kRight            ; Right flag
                and ah,#$80             ;

                xor al,ah               ; Same ?
                beq MB_Draw             ; Yes, redraw

                ld bl,#1                ; Assume Right

                tst ah                  ; Right ?
                bne MB_Move             ;

                ld bl,#-1               ; Left

MB_Move         push bl                 ; Save

                ld al,Base_X            ; Get X
                rcall Undraw_Base_AL    ; Remove the base

                pop bl                  ; Restore

                ld al,Base_X            ; Get X
                add al,bl               ; Step X
                
                cp al,#Base_Min         ; Clip
                bcs MB_Draw             ; Fail

                cp al,#Base_Max         ; Clip
                bcc MB_Draw             ; Fail

                ld Base_X,al            ; Save new posn.

                ; Draw the base

MB_Draw         ld al,Base_X            ; X
                rcall Draw_Base_AL      ; Show it

                ld al,kFire             ; Fire pressed ?
                and al,#$80             ;
                beq MB_X                ; No, skip

                ldw y,#Missile_Tab      ; Point at base's missile entry

                ld al,y+mFlags          ; Alive ?
                sbrc al,#0              ;
MB_X            ret                     ; Yes, exit

                rcall Step_Ship_Score   ; Change ship score

                ld al,#1                ; Create it
                ld y+mFlags,al          ;

                ld al,Base_X            ; Get X
                ld y+mX,al              ; Store

                ld al,#64-(5+4)         ; Missile Y
                ld y+mY,al              ;

                ld al,#0                ; Type 0 (line)
                ld y+mType,al           ;

                ld al,#-2               ; Step upwards
                ld y+mdY,al             ;

                ld al,#1                ; Fast missile
                ld y+miSpeed,al         ;

                rjmp MM_Start           ; Move the projectile

Draw the base at X=AL

Draw_Base_AL    sub al,#wBase/2         ; LHS

                ld xh,# high Frame_Buff + 7 ; Last page
                ld xl,al                ; X
                sub xl,#-64             ; Add 64

                ; Write the Base...

                ldw z,#Gr_Base          ; Pixel mask
                ld bl,#wBase            ; Width

OR_Stripe       ld al,x                 ; Get the display

                lpm ah,z+               ; Graphics
                or al,ah                ;
                ld x+,al                ;

                dec bl                  ; Loop
                bne OR_Stripe           ;

                ret                     ; Done

Undraw the base at X=AL

Undraw_Base_AL  sub al,#wBase/2         ; LHS

                ld xh,#( high Frame_Buff ) + 7 ; Last page
                ld xl,al                ; X
                sub xl,#-64             ; Add 64

                ; Write the Base...

                ldw z,#Gr_Base          ; Pixel mask
                ld bl,#wBase            ; Width

AND_Stripe      ld al,x                 ; Get the display

                lpm ah,z+               ; Graphics
                com ah                  ; Invert
                and al,ah               ;
                ld x+,al                ;

                dec bl                  ; Loop
                bne AND_Stripe          ;

                ret                     ; Done

Draw a base explosion (AH) at X=AL

Draw_BaseExpl   sub al,#(wBase+1)/2     ; LHS

                ld xh,# high Frame_Buff + 7 ; Last page
                ld xl,al                ; X
                sub xl,#-64             ; Add 64

                ; Write the Base...

                ldw z,#Gr_BaseExp0      ; Pixel mask
                cp ah,#0                ;
                beq DBE_1               ;

                ldw z,#Gr_BaseExp1      ; Pixel mask
                cp ah,#1                ;
                beq DBE_1               ;

                ldw z,#Gr_BaseExp2      ; Pixel mask
                cp ah,#2                ;
                beq DBE_1               ;

                ldw z,#Gr_BaseExp3      ; Pixel mask

DBE_1           ld bl,#wBase+2          ; Width
                rjmp OR_Stripe          ; OR it

Undraw a base explosion (AH) at X=AL

Undraw_BaseExpl sub al,#(wBase+1)/2     ; LHS

                ld xh,# high Frame_Buff + 7 ; Last page
                ld xl,al                ; X
                sub xl,#-64             ; Add 64

                ; Write the Base...

                ldw z,#Gr_BaseExp0      ; Pixel mask
                cp ah,#0                ;
                beq UDBE_1              ;

                ldw z,#Gr_BaseExp1      ; Pixel mask
                cp ah,#1                ;
                beq UDBE_1              ;

                ldw z,#Gr_BaseExp2      ; Pixel mask
                cp ah,#2                ;
                beq UDBE_1              ;

                ldw z,#Gr_BaseExp3      ; Pixel mask

UDBE_1          ld bl,#wBase+2          ; Width
                rjmp AND_Stripe         ; OR it

Draw the ship

Draw_Ship       ld al,Ship_X            ; Get it's X
                sub al,#wShip/2         ; LHS

                ld xh,# high Frame_Buff ; First page
                ld xl,al                ; X
                sub xl,#-64             ; Add 64

                ; Write the Ship

                ldw z,#Gr_Ship          ; Pixel mask
                ld bl,#wShip            ; Width

                rjmp OR_Stripe          ; OR it...

Undraw the ship

Undraw_Ship     ld al,Ship_X            ; Get it's X
                sub al,#wShip/2         ; LHS

                ld xh,# high Frame_Buff ; First page
                ld xl,al                ; X
                sub xl,#-64             ; Add 64

                ; Write the Ship

                ldw z,#Gr_Ship          ; Pixel mask
                ld bl,#wShip            ; Width

                rjmp AND_Stripe         ; AND it...

Draw the invader (pInv -> Y)

Draw_Inv        ldw z,#Gr_Inv0          ; Assume this one
                ld bl,#8                ; Width := 8

                ld al,y+inX             ; X
                sub al,#3               ; LHS

                ld ah,y+inY             ; Top

                rjmp OR_Sprite          ; Draw it

Undraw the invader (pInv -> Y)

Undraw_Inv      ldw z,#Gr_Inv0          ; Assume it's a line
                ld bl,#8                ; Width := 8
                ld al,y+inX             ; X
                sub al,#3               ; LHS

                ld ah,y+inY             ; Top

                rjmp AND_Sprite         ; Draw it

Draw the shields

Draw_Shields    ldw y,#Frame_Buff + $640 + 7 ; Point at the first
                rcall Draw_Shield            ;

                ldw y,#Frame_Buff + $640 + 38;
                rcall Draw_Shield            ;

                ldw y,#Frame_Buff + $640 + 69;
                rcall Draw_Shield            ;

                ldw y,#Frame_Buff + $640 +100;
                rcall Draw_Shield            ;

                ret                          ; Done

        ; Draw one shield

Draw_Shield     ldw z,#Gr_Shield        ; Shape
                ld bl,#21               ; Width

DS_Lp           lpm al,z+               ; Get it
                ld y,al                 ; Store it
                inc yh                  ;
                lpm al,z+               ;
                ld y+,al                ;
                dec yh                  ;

                dec bl                  ; Loop
                bne DS_Lp               ;

                ret                     ; Done

Decimal convert x -> digit at [y]

Dec_Conv        push z                  ; Save

                ldw z,#1000             ; First digit
                rcall DC_Digit          ; Get the first digit

                rcall Plant_Digit       ; Show it

                ldw z,#100              ;
                rcall DC_Digit          ; Get the first digit

                rcall Plant_Digit       ; Show it

                ldw z,#10               ;
                rcall DC_Digit          ; Get the first digit

                rcall Plant_Digit       ; Show it

                ld al,xl                ; Last digit
                rcall Plant_Digit       ; Show it

                pop z                   ; Restore
                ret                     ;

        ; Calc the digit

DC_Digit        ld al,#0                ; Presume 0

DCD_Lp          sub xl,zl               ; Try it
                sbc xh,zh               ;

                bcs DCD_X               ; Nope, exit

                inc al                  ; One more

                rjmp DCD_Lp             ; Loop

        ; Restore

DCD_X           add xl,zl               ;
                adc xh,zh               ;

                ret                     ;

        ; Write the digit to the display

Plant_Digit     ldw z,#Gr_Digits        ; Point at the 'Font'

                add al,al               ; * 8
                add al,al               ;
                add al,al               ;

                add zl,al               ; Add base
                adc zh,al               ;
                sub zh,al               ;

                ld bl,#7                ; Width

PD_Lp           lpm al,z+               ; Copy it
                ld y+,al                ;

                dec bl                  ; Loop
                bne PD_Lp               ;

                ret                     ; Done

Add AX to the score

Add_Score       ld xl,Score_D           ; Add this to the score
                ld xh,Score_D+1         ;

                add al,xl               ;
                adc ah,xh               ;

                ld Score_D,al           ;
                ld Score_D+1,ah         ;

                ; Is this higher than the high-score ?

                ld xl,Highscore_D       ; New high-score?
                ld xh,Highscore_D+1     ;

                cp xl,al                ; New highscore?
                cpc xh,ah               ;
                bcc AS_No               ; No, skip

                ld Highscore_D,al       ; Set the new high-score
                ld Highscore_D+1,ah     ;

                ; New base at 1000?

AS_No           ld xl,NewBaseF          ; Had it?
                tst xl                  ;
                bne AS_X                ; Yes, skip

                ; Score >=1000?

                ldw x,#1000             ; Base here

                cp al,xl                ; >1000
                cpc ah,xh               ;
                bcs AS_X                ; No, skip

                ; Hit the flag

                ld al,#1                ; NZ
                ld NewBaseF,al          ;

                ; Inc the base count

                ld al,Base_Cnt_D        ; Step the count
                inc al                  ;
                ld Base_Cnt_D,al        ;

AS_X            ret                     ; Done

Show the score

Disp_Score      ldw y,#ScorePage        ; X

                ld xl,Score_D           ; Get the score
                ld Score_A,xl           ; Flag it

                ld xh,Score_D+1         ;
                ld Score_A+1,xh         ;

                rjmp Dec_Conv           ; Show it

Show the high-score

Disp_HighScore  ldw y,#ScorePage+128-(4*7) ; X

                ld xl,Highscore_D       ; Get the score
                ld Highscore_A,xl       ; Flag it

                ld xh,Highscore_D+1     ;
                ld Highscore_A+1,xh     ;

                rjmp Dec_Conv           ; Show it

Show the remaining bases

Disp_Base_Cnt   ld al,Base_Cnt_D        ; Get displayed count
                ld Base_Cnt_A,al        ; Save it

                ld ah,al                ; Base count

                ld al,#40               ; X
                rcall DBC_Show          ;

                ld al,#53               ; X
                dec ah                  ;
                rcall DBC_Show          ;

                ld al,#66               ; X
                dec ah                  ;
                rcall DBC_Show          ;

                ret                     ; Done

DBC_Show        push ah                 ; Save the count

                cp ah,#2                ; >1
                bpl DBCS_Show           ;

                rcall Undraw_BaseFlag   ; Undraw it

                pop ah                  ;
                ret                     ; Done

        ; Draw it

DBCS_Show       rcall Draw_BaseFlag     ; Draw it

                pop ah                  ;
                ret                     ; Done

Explode the base

Base_Explode    rcall Clear_Missiles    ; Clear them

                ld bl,#27               ; Count

BE_Lp           push bl                 ; Save cnt

                ld ah,Rand              ; Get a random explosion shape
                and ah,#$03             ;

                push ah                 ; Save

                ld al,Base_X            ; LHS
                rcall Draw_BaseExpl     ; Draw it

                rcall Move_Missiles     ; So that they can explode

                ldw x,#2                ; Some delay

BE_Wait         push x                  ; Save
                rcall Paint_LCD         ; Render it
                pop x                   ;

                dec x                   ; Dec cnt
                bne BE_Wait             ;

                pop ah                  ; Restore un-draw shape

                ld al,Base_X            ; LHS
                rcall Undraw_BaseExpl   ; Undraw it

                pop bl                  ; Loop
                dec bl                  ;
                bne BE_Lp               ;

                ret                     ; Done

Draw the base-flag at X=AL

Draw_BaseFlag   sub al,#wBaseFlag/2     ; LHS

                ldw x,#ScorePage        ; Last page
                add xl,al               ; X
                adc xh,al               ;
                sub xh,al               ;

                ; Write the Base...

                ldw z,#Gr_BaseFlag      ; Pixel mask
                ld bl,#wBaseFlag        ; Width

                rjmp OR_Stripe          ; Show it

Undraw the base-flag at X=AL

Undraw_BaseFlag sub al,#wBaseFlag/2     ; LHS

                ldw x,#ScorePage        ; Last page
                add xl,al               ; X
                adc xh,al               ;
                sub xh,al               ;

                ; Write the Base...

                ldw z,#Gr_BaseFlag      ; Pixel mask
                ld bl,#wBaseFlag        ; Width

                rjmp AND_Stripe         ; Show it

Write al to [x] in the EEROM

Write_AL_EEROM  push ah                 ; Save

                out EEARL,xl            ; Set the address
                out EEARH,xh            ;

                ; Read the EEROM and see if it's the same

                sbi EECR,#0             ; Read EEROM

                in ah,EEDR              ; Get it

                cp al,ah                ; Same ?
                beq WE_X                ; Yes, skip the write

                ; Now we write the EEROM

                out EEDR,al             ; Preset the data

                ; Now, this CAN'T BE interrupted

                ld ah,#$00              ; Setup for DI
                out SREG,ah             ; DI

                ; Write the EEROM

                sbi EECR,#2             ; Enable write EEROM
                sbi EECR,#1             ; Write EEROM

                ; EI

                ld ah,#$80              ; Setup for EI
                out SREG,ah             ; EI

                ; Now, we have to hang around while the EEROM writes

DWWE_Wait       sbic EECR,#1            ; Wait until this is clear
                rjmp DWWE_Wait          ;

                ; Done

WE_X            pop ah                  ; Restore
                ret                     ; Done

Read a byte from the EEROM at X DON'T FUCK WITH AH,Z

Read_AL_EEROM   out EEARH,xh            ; Set the address
                out EEARL,xl            ;

                ; Kick the EEROM to read it

                sbi EECR,#0             ; Read

                in al,EEDR              ; Get the next byte

                ret                     ; Done

Timer 0 IRQ al saved

Game_iT0        ret                     ; Done

Timer 1 IRQ (100uS) ax,bx,x,y all saved

Game_iT1        ld al,Rand              ; Change it
                sub al,#-13             ;
                ld Rand,al              ;

                ret                     ; Done

Data

Inv_Y_Table     db 8,9,10,11,13,15,17,19 ; Top line Y for each sheet

; Initial data for invaders
;               Flag,X,Y,Type

Invaders_Data   db 1,0,0,0            ; 1 X,Y,Type
                db 1,0,9,4            ; 2
                db 1,0,18,8           ; 3
                db 3,0,27,8           ; 4

                db 1,9,0,1            ; 5
                db 1,9,9,5            ; 6
                db 1,9,18,9           ; 7
                db 3,9,27,9           ; 8

                db 1,18,0,0           ; 9
                db 1,18,9,4           ; 10
                db 1,18,18,8          ; 11
                db 3,18,27,8          ; 12

                db 1,27,0,1           ; 13
                db 1,27,9,5           ; 14
                db 1,27,18,9          ; 15
                db 3,27,27,9          ; 16

                db 1,36,0,0           ; 17
                db 1,36,9,4           ; 18
                db 1,36,18,8          ; 19
                db 3,36,27,8          ; 20

                db 1,45,0,1           ; 21
                db 1,45,9,5           ; 22
                db 1,45,18,9          ; 23
                db 3,45,27,9          ; 24

                db 1,54,0,0           ; 25
                db 1,54,9,4           ; 26
                db 1,54,18,8          ; 27
                db 3,54,27,8          ; 28

                db 1,63,0,1           ; 29
                db 1,63,9,5           ; 30
                db 1,63,18,9          ; 31
                db 7,63,27,9          ; 32

Inv_Move_R_Tab  db 32,28,24,20,16,12,8,4 ; Table for move right order
                db 31,27,23,19,15,11,7,3 ;
                db 30,26,22,18,14,10,6,2 ;
                db 29,25,21,17,13, 9,5,1 ;
                db 0                     ; Sentinel

Inv_Move_L_Tab  db 4, 8,12,16,20,24,28,32;
                db 3, 7,11,15,19,23,27,31;
                db 2, 6,10,14,18,22,26,30;
                db 1, 5, 9,13,17,21,25,29;
                db 0                     ; Sentinel

Ship_Score_Tab  dw 50,150,100
SST_1           dw 50,200,50,45
                dw 50,100,50,25
                dw 50,60,70,80
                dw 200,10,200,75
                dw 100,150,50,300
                dw 0

Base graphics

Gr_Base         db %11100000            ;
                db %11110000            ;
                db %11110000            ;
                db %11110000            ;
                db %11110000            ;
                db %11111000            ;
                db %11111100            ;
                db %11111000            ;
                db %11110000            ;
                db %11110000            ;
                db %11110000            ;
                db %11110000            ;
                db %11100000            ;

Gr_BaseFlag     db %01100000            ;
                db %01110000            ;
                db %01110000            ;
                db %01110000            ;
                db %01111000            ;
                db %01111100            ;
                db %01111000            ;
                db %01110000            ;
                db %01110000            ;
                db %01110000            ;
                db %01100000            ;
                db 0
                db 0

Gr_BaseExp0     db %01010000            ;
                db %10101000            ;
                db %01010100            ;
                db %10010010            ;
                db %01101000            ;
                db %11001010            ;
                db %10101000            ;
                db %00111100            ;
                db %11101010            ;
                db %01010100            ;
                db %10111010            ;
                db %01110100            ;
                db %10110000            ;
                db %11001000            ;
                db %01010000            ;

Gr_BaseExp1     db %10100000            ;
                db %01100100            ;
                db %00101010            ;
                db %01001100            ;
                db %10010100            ;
                db %00101100            ;
                db %01010010            ;
                db %10101011            ;
                db %00110100            ;
                db %10101100            ;
                db %01010110            ;
                db %10011101            ;
                db %01010110            ;
                db %00100100            ;
                db %00100000            ;

Gr_BaseExp2     db %00000000            ;
                db %00001000            ;
                db %01001000            ;
                db %10000100            ;
                db %00101000            ;
                db %10001000            ;
                db %00100100            ;
                db %01010000            ;
                db %10100100            ;
                db %01001000            ;
                db %01010100            ;
                db %10100000            ;
                db %01010100            ;
                db %00010000            ;
                db %00000000            ;

Gr_BaseExp3     db %00000000            ;
                db %00000000            ;
                db %00010000            ;
                db %10010000            ;
                db %01101000            ;
                db %01001010            ;
                db %10101000            ;
                db %00111100            ;
                db %10101000            ;
                db %01010100            ;
                db %10101000            ;
                db %01010000            ;
                db %00100000            ;
                db %00000000            ;
                db %00000000            ;

Ship graphic

Gr_Ship         db %00001000            ;
                db %00001000            ;
                db %00010100            ;
                db %00010100            ;
                db %00010100            ;
                db %00110100            ;
                db %00110100            ;
                db %00111110            ;
                db %00111110            ;
                db %00010110            ;
                db %00010110            ;
                db %00111110            ;
                db %00111110            ;
                db %00110100            ;
                db %00110100            ;
                db %00010100            ;
                db %00010100            ;
                db %00001000            ;
                db %00001000            ;

Invader graphics

;...xx...
;..xxxx..
;.x.xx.x.
;.x.xx.x.
;.xxxxxx.
;..x..x..
;.x....x.
;..x..x..

Gr_Inv0         db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000

                db %01011100,%00000000
                db %10111000,%00000000
                db %01110000,%00000001
                db %11100000,%00000010
                db %11000000,%00000101
                db %10000000,%00001011
                db %00000000,%00010111
                db %00000000,%00101110

                db %10110010,%00000000
                db %01100100,%00000001
                db %11001000,%00000010
                db %10010000,%00000101
                db %00100000,%00001011
                db %01000000,%00010110
                db %10000000,%00101100
                db %00000000,%01011001

                db %00011111,%00000000  ;
                db %00111110,%00000000  ;
                db %01111100,%00000000  ;
                db %11111000,%00000000  ;
                db %11110000,%00000001  ;
                db %11100000,%00000011  ;
                db %11000000,%00000111  ;
                db %10000000,%00001111  ;

                db %00011111,%00000000  ;
                db %00111110,%00000000  ;
                db %01111100,%00000000  ;
                db %11111000,%00000000  ;
                db %11110000,%00000001  ;
                db %11100000,%00000011  ;
                db %11000000,%00000111  ;
                db %10000000,%00001111  ;

                db %10110010,%00000000
                db %01100100,%00000001
                db %11001000,%00000010
                db %10010000,%00000101
                db %00100000,%00001011
                db %01000000,%00010110
                db %10000000,%00101100
                db %00000000,%01011001

                db %01011100,%00000000
                db %10111000,%00000000
                db %01110000,%00000001
                db %11100000,%00000010
                db %11000000,%00000101
                db %10000000,%00001011
                db %00000000,%00010111
                db %00000000,%00101110

                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000
                db %00000000,%00000000

;...xx...
;..xxxx..
;.x.xx.x.
;.x.xx.x.
;.xxxxxx.
;..x..x..
;...xx...
;..x..x..

;.x..x...
;..x..x..
;.xxxxxx.
;xx.xx.xx
;xx.xx.xx
;.xxxxxx.
;.x....xx
;xx......

;...x..x.
;..x..x..
;.xxxxxx.
;xx.xx.xx
;xx.xx.xx
;.xxxxxx.
;xx....x.
;......xx

;x.......
;.x....xx
;..xxxx..
;.x.xx.x.
;xx.xx.x.
;xxxxxxxx
;x......x
;.......x

;.......x
;xx....x.
;..xxxx..
;.x.xx.x.
;.x.xx.xx
;xxxxxxxx
;x......x
;x.......

;..xxxx..
;.xx..xx.
;xxxxxxxx
;xxxxxx.x
;x.xxxx.x
;x.xxxx..
;..x..xx.
;.xx.....

;..xxxx..
;.xx..xx.
;xxxxxxxx
;x.xxxxxx
;x.xxxx.x
;..xxxx.x
;.xx..x..
;.....xx.

Missile graphics

Gr_Miss0        db %00011111,%00000000  ;
                db %00111110,%00000000  ;
                db %01111100,%00000000  ;
                db %11111000,%00000000  ;
                db %11110000,%00000001  ;
                db %11100000,%00000011  ;
                db %11000000,%00000111  ;
                db %10000000,%00001111  ;

Gr_Miss1a       db %00000010,%00000000  ;
                db %00000100,%00000000  ;
                db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;

                db %00010101,%00000000  ;
                db %00101010,%00000000  ;
                db %01010100,%00000000  ;
                db %10101000,%00000000  ;
                db %01010000,%00000001  ;
                db %10100000,%00000010  ;
                db %01000000,%00000101  ;
                db %10000000,%00001010  ;

                db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;
                db %00000000,%00000010  ;
                db %00000000,%00000100  ;

Gr_Miss1b       db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;
                db %00000000,%00000010  ;
                db %00000000,%00000100  ;

                db %00010101,%00000000  ;
                db %00101010,%00000000  ;
                db %01010100,%00000000  ;
                db %10101000,%00000000  ;
                db %01010000,%00000001  ;
                db %10100000,%00000010  ;
                db %01000000,%00000101  ;
                db %10000000,%00001010  ;

                db %00000010,%00000000  ;
                db %00000100,%00000000  ;
                db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;

Shield

Gr_Shield       db %11110000,%00000011  ;
                db %11111100,%00000011  ;
                db %11111110,%00000011  ;
                db %11111111,%00000011  ;
                db %11111111,%00000001  ;
                db %11111111,%00000001  ;
                db %11111111,%00000001  ;
                db %11111111,%00000000  ;
                db %11111111,%00000000  ;
                db %11111111,%00000000  ;
                db %11111111,%00000000  ;
                db %11111111,%00000000  ;
                db %11111111,%00000000  ;
                db %11111111,%00000000  ;
                db %11111111,%00000001  ;
                db %11111111,%00000001  ;
                db %11111111,%00000001  ;
                db %11111111,%00000011  ;
                db %11111110,%00000011  ;
                db %11111100,%00000011  ;
                db %11110000,%00000011  ;

Explosions

Gr_Exp2         equ *
Gr_Exp3         equ *

Gr_Exp0         db %00000100,%00000000  ;
                db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;
                db %00000000,%00000010  ;

                db %00010100,%00000000  ;
                db %00101000,%00000000  ;
                db %01010000,%00000000  ;
                db %10100000,%00000000  ;
                db %01000000,%00000001  ;
                db %10000000,%00000010  ;
                db %00000000,%00000101  ;
                db %00000000,%00001010  ;

                db %00011111,%00000000  ;
                db %00111110,%00000000  ;
                db %01111100,%00000000  ;
                db %11111000,%00000000  ;
                db %11110000,%00000001  ;
                db %11100000,%00000011  ;
                db %11000000,%00000111  ;
                db %10000000,%00001111  ;

                db %00000101,%00000000  ;
                db %00001010,%00000000  ;
                db %00010100,%00000000  ;
                db %00101000,%00000000  ;
                db %01010000,%00000000  ;
                db %10100000,%00000000  ;
                db %01000000,%00000001  ;
                db %10000000,%00000010  ;

                db %00000010,%00000000  ;
                db %00000100,%00000000  ;
                db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;

Gr_Exp1         db %00000010,%00000000  ;
                db %00000100,%00000000  ;
                db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;

                db %00001010,%00000000  ;
                db %00010100,%00000000  ;
                db %00101000,%00000000  ;
                db %01010000,%00000000  ;
                db %10100000,%00000000  ;
                db %01000000,%00000001  ;
                db %10000000,%00000010  ;
                db %00000000,%00000101  ;

                db %00000111,%00000000  ;
                db %00001110,%00000000  ;
                db %00011100,%00000000  ;
                db %00111000,%00000000  ;
                db %01110000,%00000000  ;
                db %11100000,%00000000  ;
                db %11000000,%00000001  ;
                db %10000000,%00000011  ;

                db %00011000,%00000000  ;
                db %00110000,%00000000  ;
                db %01100000,%00000000  ;
                db %11000000,%00000000  ;
                db %10000000,%00000001  ;
                db %00000000,%00000011  ;
                db %00000000,%00000110  ;
                db %00000000,%00001100  ;

                db %00000100,%00000000  ;
                db %00001000,%00000000  ;
                db %00010000,%00000000  ;
                db %00100000,%00000000  ;
                db %01000000,%00000000  ;
                db %10000000,%00000000  ;
                db %00000000,%00000001  ;
                db %00000000,%00000010  ;

Decimal table

Gr_Digits       db %00000000 ; 0
                db %00111110 ;
                db %01000001 ;
                db %01000001 ;
                db %01000001 ;
                db %00111110 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 1
                db %00000000 ;
                db %01000010 ;
                db %01111111 ;
                db %01000000 ;
                db %00000000 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 2
                db %01000010 ;
                db %01100001 ;
                db %01010001 ;
                db %01001001 ;
                db %01000110 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 3
                db %01000001 ;
                db %01001001 ;
                db %01001001 ;
                db %00110110 ;
                db %00000000 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 4
                db %00010000 ;
                db %00011000 ;
                db %00010100 ;
                db %01111111 ;
                db %00010000 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 5
                db %01001111 ;
                db %01001001 ;
                db %01001001 ;
                db %01001001 ;
                db %00110001 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 6
                db %00111110 ;
                db %01001001 ;
                db %01001001 ;
                db %01001001 ;
                db %00110000 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 7
                db %00000001 ;
                db %00000001 ;
                db %01111001 ;
                db %00000101 ;
                db %00000011 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 8
                db %00110110 ;
                db %01001001 ;
                db %01001001 ;
                db %01001001 ;
                db %00110110 ;
                db %00000000 ;
                db %00000000 ;

                db %00000000 ; 9
                db %00000110 ;
                db %00001001 ;
                db %01001001 ;
                db %01001001 ;
                db %00111110 ;
                db %00000000 ;
                db %00000000 ;

EEROM

eeHigh          equ $FFE        ; Last two bytes of EEROM