;  +--------------------------------------------------------------------+
;  |                           LaserBase!                               |
;  |             A game in assembly for the Winter 1987 START           |
;  |                        Version 100487  sunday                      |
;  |                    Written by Patrick Bass                         |
;  |                                                                    |
;  +--------------------------------------------------------------------+

;  Include the macro file for GEM AES access, and a .PRG init macro
        .include        "aesmac.s"

; Include the standard ATARI macros for BIOS/XBIOS/GEMDOS access
        .include        "atari.s"
        .include        "osmac.s"

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

; Initialize a ".PRG" style application.
        prg_init

; Inform GEM some activity may happen.
        appl_init   #handle

        graf_handle     handle, mcx, mcy, mcw, mch

        bsr     getpalette      ;save original palette.

; Lets figure out where the pictures will live, and load them.

        move.l  #titleram,d0    ;Find start of picture buffer.
        and.l   #$ffffff00,d0   ;Force a page boundry to pop up.
        add.l   #512,d0         ;...and correct for any shortsightedness.
        move.l  d0,tpix         ;move the picture address to a safe place.

        move.l  #foreram,d0     ;Find start of foreground picture buffer.
        and.l   #$ffffff00,d0   ;Force a page boundry to pop up.
        add.l   #512,d0         ;...and correct for any shortsightedness.
        move.l  d0,fpix         ;move the picture address to a safe place.

        move.l  #backram,d0     ;Find start of background picture buffer.
        and.l   #$ffffff00,d0   ;Force a page boundry to pop up.
        add.l   #512,d0         ;...and correct for any shortsightedness.
        move.l  d0,bpix         ;move the picture address to a safe place.

        bra     loadback

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        .even
backname:       .dc.b   "\\backgrnd.pi1",0,0
        .even

bpix:           .dc.l   1       ;The even-page start for the background.
bpal:           .dc.l   1       ;The palette location.

; Load the default background picture.
loadback:
        Fopen   #backname,#0    ;open the file for reading
        move.w  d0,fhandle      ;Remember ID number

        move.l  bpix,a0         ;Pick up picture buffer address
        sub.l   #32,a0          ;Back up 34 to allow for pallette and rez
        move.l  a0,bpal
        sub.l   #2,a0

        Fread   fhandle,#32066,a0       ;Read in picture.
        move.l  d0,filelen              ;Remember amount really read.

        Fclose  fhandle
        bra     loadfore

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        .even
forename:       .dc.b   "\\foregrnd.pi1",0,0
        .even

fpix:           .dc.l   1       ;The even page start of the foreground.
fpal:           .dc.l   1       ;The palette address.

; Now open and load the default foreground picture.
loadfore:
        Fopen   #forename,#0    ;open the file for reading
        move.w  d0,fhandle      ;Remember ID number

        move.l  fpix,a0         ;Pick up picture buffer address
        sub.l   #32,a0          ;Back up 34 to allow for pallette and rez
        move.l  a0,fpal
        sub.l   #2,a0

        Fread   fhandle,#32066,a0       ;Read in picture.
        move.l  d0,filelen              ;Remember amount really read.

        Fclose  fhandle
        bra     loadtitle

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        .even
titlename:      .dc.b   "\\title.pi1",0,0
        .even

tpix:           .dc.l   1       ;The even-page start for the title.
tpal:           .dc.l   1       ;The palette location.

; Load the default title picture.
loadtitle:
        Fopen   #titlename,#0   ;open the file for reading
        move.w  d0,fhandle      ;Remember ID number

        move.l  tpix,a0         ;Pick up picture buffer address
        sub.l   #32,a0          ;Back up 34 to allow for pallette and rez
        move.l  a0,tpal
        sub.l   #2,a0

        Fread   fhandle,#32066,a0       ;Read in picture.
        move.l  d0,filelen              ;Remember amount really read.

        Fclose  fhandle


;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        Getrez                  ;Go get the current resolution
        move.w  d0,resolution

        Physbase                ;Remember the original screen address
        move.l  d0,opix

        move.w  #1,wave
        move.w  #1,difficulty

        bsr     vbl_on

;- - - - - - - - - - - - - - - - -
; Quickly make sure no cities are enabled.

        move.l  #cenableflag,a0
        move.w  #3,d0
sac1:
        move.w  d0,d1
        asl.w   #1,d1
        move.w  #0,0(a0,d1.w)

        dbra    d0,sac1
;- - - - - - - - - - - - - - - - -

        bsr     quickinit

;        bsr     initpower

        bra     gamesetup

;---------------------------------------------------------------------
;---------------------------------------------------------------------
        .even
axmess: .dc.b   "0 Level test",13,10,0,0
        .even

advance:
        move.l  #axmess,a0
        add.b   #1,(a0)
        Print   #axmess
        rts


;---------------------------------------------------------------------
                .even
menusound:
                .dc.b   0,1
                .dc.b   1,1
                .dc.b   2,0,3,0,4,0,5,0,6,0
                .dc.b   7,$fe
                .dc.b   8,$10   ;$10
                .dc.b   13,9
                .dc.b   11,128
                .dc.b   12,16
                .dc.b   255,0,0,0
                .even

;.....................................................................
; A key debounce routine.
debounce:
        move.l  #60000,d0
deb1:
        dbra    d0,deb1
        rts

;---------------------------------------------------------------------
; Menu Handling Routines
;
; This routine handles all interaction with the opening menu screen.


domenu:
        v_hide_c  handle        ;Hide the mouse
        Setscreen opix,opix,#0  ;Display the picture in lores.
        movescreen  tpix,opix   ;Move title picture up there.
        Setpallete tpal         ;...using its own palette.
        v_show_c  handle        ;And reenable the mouse.

        bsr     handlesound     ;update the sound button.
        bsr     handlscroll     ;update the scroll button.
        bsr     handledifficulty  ;update the difficulty buttons.

        move.l  #scoremess,a0
        move.w  scorehi,d1
        bsr     decword
        move.w  scoremed,d1
        bsr     decword
        move.w  scorelo,d1
        bsr     decword

        vst_color handle,#9
        v_gtext handle,#22,#130,#scoretext
domm1:
        v_gtext handle,#20,#140,#scoremess

dom1:
        vq_mouse  handle,mx,my,mbutton

; Is the left-hand mouse button pressed?

        move.w  mbutton,d0      ;Pick up mouse button value.
        and.w   #1,d0           ;Check left button bit.
        beq     dom1            ;Branch if off.

; Hmmm...  It seems the left button is being pressed.
        tst.w   soundflag       ;is sound allowed?
        beq     dom1a           ;branch if not...

        Dosound  #menusound     ;Else make menu sound.
dom1a:        
        bsr     chektexit       ;Is the mouse pointer over the [EXIT] box?
        tst.w   d0              ;Check results.
        beq     dom2            ;Branch if not over [EXIT] button.

        move.w  #0,gamefinished ;So finish the game.
        rts

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
dom2:
        bsr     chektplay       ;Is the [PLAY] button being pressed?
        tst.w   d0
        beq     dom3            ;Branch if not, else...

        tst.w   scrollflag      ;Is scrolling allowed?
        beq     dom2a           ;branch if not.

;        bsr     scrolldown
        move.l  bpix,srcpixpointer
        bsr     scrollup
dom2a:
        move.w  #1,gamefinished ;The game is running...
        move.w  #1,wave         ;From wave number one.

        rts

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
dom3:
        bsr     chektsound      ;Is the [SOUND] button selected?
        tst.w   d0
        beq     dom4

        eor.w   #1,soundflag
        bsr     handlesound
        bsr     debounce
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
dom4:
        bsr     chektscroll
        tst.w   d0
        beq     dom5

        eor.w   #1,scrollflag
        bsr     handlscroll
        bsr     debounce

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
dom5:
        bsr     chektdiff
        tst.w   d0
        beq     dom6

        move.w  d0,difficulty
dom5a:
        bsr     handledifficulty
        bsr     debounce

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
dom6:
        bra     dom1

;.....................................................................
chektexit:
; Upper
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #163,d0         ;check for upper boundry
        blt     chxx            ;branch if higher up on the screen.
; Lower
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #192,d0         ;check for lower boundry
        bhi     chxx            ;branch if lower on the screen.
; Left
        move.w  mx,d0           ;check left edge of exit button
        cmp.w   #244,d0
        blt     chxx            ;branch if too far left
; Right
        move.w  mx,d0           ;check right edge of exit button
        cmp.w   #304,d0
        bhi     chxx            ;branch if too far right

        move.w  #1,d0                ;return a TRUE if OK.
        rts
chxx:
        move.w  #0,d0
        rts

;.....................................................................
chektplay:
; Upper
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #118,d0         ;check for upper boundry
        blt     achxx           ;branch if higher up on the screen.
; Lower
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #149,d0         ;check for lower boundry
        bhi     achxx           ;branch if lower on the screen.
; Left
        move.w  mx,d0           ;check left edge of exit button
        cmp.w   #244,d0
        blt     achxx            ;branch if too far left
; Right
        move.w  mx,d0           ;check right edge of exit button
        cmp.w   #304,d0
        bhi     achxx            ;branch if too far right

        move.w  #1,d0                ;return a TRUE if OK.
        rts
achxx:
        move.w  #0,d0
        rts

;.....................................................................
chektsound:
; Upper
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #118,d0         ;check for upper boundry
        blt     bchxx           ;branch if higher up on the screen.
; Lower
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #149,d0         ;check for lower boundry
        bhi     bchxx           ;branch if lower on the screen.
; Left
        move.w  mx,d0           ;check left edge of exit button
        cmp.w   #168,d0
        blt     bchxx            ;branch if too far left
; Right
        move.w  mx,d0           ;check right edge of exit button
        cmp.w   #228,d0
        bhi     bchxx            ;branch if too far right

        move.w  #1,d0                ;return a TRUE if OK.
        rts
bchxx:
        move.w  #0,d0
        rts

;.....................................................................
chektscroll:
; Upper
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #118,d0         ;check for upper boundry
        blt     cchxx           ;branch if higher up on the screen.
; Lower
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #149,d0         ;check for lower boundry
        bhi     cchxx           ;branch if lower on the screen.
; Left
        move.w  mx,d0           ;check left edge of scroll button
        cmp.w   #92,d0
        blt     cchxx            ;branch if too far left
; Right
        move.w  mx,d0           ;check right edge of scroll button
        cmp.w   #153,d0
        bhi     cchxx            ;branch if too far right

        move.w  #1,d0                ;return a TRUE if OK.
        rts
cchxx:
        move.w  #0,d0
        rts

;.....................................................................
; This routine checks each of the three difficulty boxes
;  and returns the number of the box as 1, 2, or 3, if found.

chektdiff:
; Upper
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #163,d0         ;check for upper boundry
        blt     dchxx           ;branch if higher up on the screen.
; Lower
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #192,d0         ;check for lower boundry
        bhi     dchxx           ;branch if lower on the screen.

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
; Left1
        move.w  mx,d0           ;check left edge of button
        cmp.w   #15,d0
        blt     dchxx            ;branch if too far left
; Right1
        move.w  mx,d0           ;check right edge of button
        cmp.w   #77,d0
        bhi     dchx2            ;branch if too far right

        move.w  #1,d0                ;return a TRUE if OK.
        rts

dchx2:
; Left2
        move.w  mx,d0           ;check left edge of button
        cmp.w   #92,d0
        blt     dchxx            ;branch if too far left
; Right2
        move.w  mx,d0           ;check right edge of button
        cmp.w   #153,d0
        bhi     dchx3            ;branch if too far right

        move.w  #2,d0                ;return a TRUE if OK.
        rts

dchx3:
; Left3
        move.w  mx,d0           ;check left edge of button
        cmp.w   #168,d0
        blt     dchxx            ;branch if too far left
; Right3
        move.w  mx,d0           ;check right edge of button
        cmp.w   #228,d0
        bhi     dchxx            ;branch if too far right

        move.w  #3,d0                ;return a TRUE if OK.
        rts

        
dchxx:
        move.w  #0,d0
        rts

;*********************************************************************


;.....................................................................
; This routine handles when the sound on/off button is pressed.

; Variables created:

soundflag:      .dc.w   1

                .even
soundmess:      .dc.b   "Sound",0,0
                .even
sonmess:        .dc.b   " On",0,0
                .even
soffmess:       .dc.b   "Off",0,0
                .even

;- - - - - - - - - - - - - - - - -
handlesound:
        vswr_mode  handle,#1    ;Back to replace mode.

        tst.w   soundflag
        bne     hs1             ;branch if off, turn it on.

; The sound flag is off.

        vst_color  handle,#10   ;10 is RED
        v_hide_c   handle
        v_gtext    handle,#177,#130,#soundmess
hs1a:
        v_gtext    handle,#182,#140,#soffmess
        v_show_c   handle
        rts

;. . . . . . . . . . . . . . . . . 
; The sound flag is on.
hs1:
        move.w  #1,soundflag

        vst_color  handle,#4
        v_hide_c   handle
        v_gtext    handle,#177,#130,#soundmess
hs1b:
        v_gtext    handle,#182,#140,#sonmess
        v_show_c   handle
        rts


;---------------------------------------------------------------------

; Variables created:

scrollflag:     .dc.w   1

                .even
scrollmess:     .dc.b   "Scroll",0,0
                .even
srlonmess:      .dc.b   " On",0,0
                .even
srloffmess:     .dc.b   "Off",0,0
                .even

;- - - - - - - - - - - - - - - - -
handlscroll:
        vswr_mode  handle,#1    ;Back to replace mode.

        tst.w   scrollflag
        bne     ahs1             ;branch if off, turn it on.

; The scroll flag is off.

        vst_color  handle,#10   ;10 is RED
        v_hide_c   handle
        v_gtext    handle,#101,#130,#scrollmess
ahs1a:
        v_gtext    handle,#106,#140,#srloffmess
        v_show_c   handle
        rts

;. . . . . . . . . . . . . . . . . 
; The scroll flag is ON.
ahs1:
        vst_color  handle,#4
        v_hide_c   handle
        v_gtext    handle,#101,#130,#scrollmess
ahs1b:
        v_gtext    handle,#106,#140,#srlonmess
        v_show_c   handle
        rts



;---------------------------------------------------------------------
; Handle Difficulty Buttons

; This routine will handle the user press of any of the three
; Difficulty buttons.  It redraws each of the buttons, using
; red for not selected, and green for selected.

; Variables created:

difficulty:     .dc.w   1               ; The difficulty level.

                .even
diffmess:       .dc.b   "Diff",0,0
                .even
difflowmess:    .dc.b   "Low",0,0
                .even
diffmedmess:    .dc.b   "Med",0,0
                .even
diffhimess:     .dc.b   " Hi",0,0
                .even

;- - - - - - - - - - - - - - - - -
handledifficulty:
        vswr_mode  handle,#1    ;Back to replace mode.

; Is this LOW difficulty?
        cmp.w   #1,difficulty
        bne     hdf1a           ;branch if not.

; Else choose color green.
        vst_color  handle,#4
        bra     hdf1b
hdf1a:
; Or choose color red if not selected
        vst_color  handle,#10   
hdf1b:
        v_hide_c   handle       ;Then hide mouse
        v_gtext    handle,#28,#175,#diffmess    
hdf1z:
        v_gtext    handle,#32,#185,#difflowmess
        v_show_c   handle       ;And restore the mouse

;. . . . . . . . . . . . . . . 
        cmp.w   #2,difficulty
        bne     hdf2a

        vst_color  handle,#4
        bra     hdf2b
hdf2a:
        vst_color  handle,#10   
hdf2b:
        v_hide_c   handle
        v_gtext    handle,#102,#175,#diffmess
hdf2z:
        v_gtext    handle,#105,#185,#diffmedmess
        v_show_c   handle

;. . . . . . . . . . . . . . .
        cmp.w   #3,difficulty
        bne     hdf3a

        vst_color  handle,#4
        bra     hdf3b
hdf3a:
        vst_color  handle,#10   
hdf3b:
        v_hide_c   handle
        v_gtext    handle,#182,#175,#diffmess
hdf3z:
        v_gtext    handle,#183,#185,#diffhimess
        v_show_c   handle


        rts





;---------------------------------------------------------------------
; Scrolling Routines
; This routine will scroll "opix" down one line.

; variable created:

llcorner:       .dc.l   0       ;The address of the screens lower left byte.
actcount:       .dc.w   0       ;The scroll action counter.

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
scrolldown:
        v_hide_c  handle

        move.l  opix,a0         ;erase top line.
        move.w  #79,d0
srd0a:
        clr.l   (a0)+
        dbra    d0,srd0a


        move.w  #100,d2         ;try it one hundred times.
srd0:
        move.l  opix,a0         ;Find upper left corner.
        add.l   #31840,a0       ;(160*199)  find lower left corner.
        move.l  a0,llcorner     ;Remember it.

        move.w  #98,d0          ;For line=0 to 99
srd1:
        move.l  llcorner,a0     ;point at line to start on.
        move.l  a0,a1           ;copy to destination register
        sub.l   #160,a1         ;second line
        move.l  a1,a2           ;a2 is a0 source
        sub.l   #160,a2
        move.l  a2,a3           ;a3 is a1 source
        sub.l   #160,a3


        move.w  #39,d1          ;For long_on_line=39 to 0
srd2:
        move.l  (a2)+,(a0)+     ;Move upper line to lower line.
        move.l  (a3)+,(a1)+
        dbra    d1,srd2

        sub.l   #320,llcorner
        dbra    d0,srd1

        dbra    d2,srd0

        v_show_c  handle

        rts



;---------------------------------------------------------------------
; As we enter, we assume the screen is blank, and the source picture
;  is pointed at by "srcpixpointer".

srcpixpointer:  .dc.l   0       ;The address of the source picture.
ulcorner:       .dc.l   0



scrollup:
        v_hide_c  handle                ; Well, lets hide the mouse

        move.l  srcpixpointer,a5        ;point at source of picture.

        move.w  #98,d2                  ;try it about one hundred times.
sru0:
        move.l  opix,a0                 ;Find upper left dest corner.
        move.l  a0,ulcorner             ;Remember it.

; So first we need to copy the first two lines to the bottom of the dest.
        add.l   #31680,a0
        move.w  #79,d0
sru0a:
        move.l  (a5)+,(a0)+
        dbra    d0,sru0a

; And now we get to scroll the rest of the screen.
        move.w  #98,d0          ;For line=0 to 99
sru1:
        move.l  ulcorner,a0     ;point at line to start on.
        move.l  a0,a1           ;copy to destination register
        add.l   #160,a1         ;second line
        move.l  a1,a2           ;a2 is a0 source
        add.l   #160,a2
        move.l  a2,a3           ;a3 is a1 source
        add.l   #160,a3


        move.w  #39,d1          ;For long_on_line=39 to 0
sru2:
        move.l  (a2)+,(a0)+     ;Move lower line to upper line.
        move.l  (a3)+,(a1)+
        dbra    d1,sru2

        add.l   #320,ulcorner
        dbra    d0,sru1

        dbra    d2,sru0

        v_show_c  handle

        rts








;---------------------------------------------------------------------
; This routine is a catch-all screen redraw to refresh the screen.

quickinit:
        v_hide_c  handle
        Setscreen opix,opix,#0   ;Display the picture loaded.
        movescreen  bpix,opix
        Setpallete bpal
        v_show_c  handle

        vsm_height handle,#5
        vsm_color handle,#10
        vsm_type handle,#6

        graf_mouse #5,#0        ;Select crosshair cursor for mouse.

        move.w  #-1,frame       ;Turn off animation.
        move.w  #1,gamefinished ;game not finished

        bsr     initvideo

        bsr     addcity    

        move.w  #0,laserbase   ;update new base number
        move.w  #0,d0
        move.l  #laserx,a0
        move.l  #lasery,a1
        move.w  0(a0,d0.w),lx
        move.w  0(a1,d0.w),ly

        bsr     init_missles

        move.l  #0,d0
        bsr     drawcity
        move.l  #1,d0
        bsr     drawcity
        move.l  #2,d0
        bsr     drawcity
        move.l  #3,d0
        bsr     drawcity

        bsr     initpower

        rts

;---------------------------------------------------------------------
; This subroutine will assign 99% power to any active city.

ipcity:         .dc.w   0       ;Number of the city we work on.

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
initpower:
        move.w  #0,ipcity       ;FOR ipcity=0 to 3
inp1:
        move.w  ipcity,d0
        asl.w   #1,d0           ;Select city.
        move.l  #cenableflag,a0 ;Point to enable table (song in there?)
        move.w  0(a0,d0.w),d0   ;Grab city enable value, either 0 or 1
        beq     inp2            ;Branch if not enabled...

; Else, this city has been enabled for use.  We must assign power to it.
        move.l  #powertable,a0  ;List of power addresses
        move.w  ipcity,d0
        asl.w   #2,d0
        move.l  0(a0,d0.w),a0   ;Now points at power entry itself.

        tst.w   (a0)
        bne     inp2

        move.w  #99,(a0)        ;Enter number into table.
inp2:
        add.w   #1,ipcity       ;NEXT city
        cmp.w   #4,ipcity
        blt     inp1

        rts

;---------------------------------------------------------------------
; Variables created:

gamefinished:   .dc.w   1
wavefinished:   .dc.w   1       ;>0=game running
pauseflag:      .dc.w   1       ;>0=game running

lx:             .dc.w   1       ;Laser source X
ly:             .dc.w   1       ;Laser source Y
ldx:            .dc.w   1       ;laser destination X
ldy:            .dc.w   1       ;laser destination Y

omx:            .dc.w   1
omy:            .dc.w   1
mx:             .dc.w   1
my:             .dc.w   1
mbutton:        .dc.w   1

wave:           .dc.w   1


                .even
clock:          .dc.b   "Sample string",0,0
                .even

ctemp:          .dc.l   1






;=========== Main Game Loop ==========================================
gamesetup:
        bsr     domenu
        tst.w   gamefinished
        beq     gameout
nextwave:
        bsr     quickinit
        move.w  #1,wavefinished                 ;assume game running.

;- - - - - - - - - - - - - - - - - 
gameloop:
        Vsync
        vq_mouse  handle,mx,my,mbutton          ;get mouse parameters

        bsr     move_missle                     ;move amy missles

        bsr     checkforcity                    ;Check for city selection.

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
; Is the left-hand mouse button pressed?

        move.w  mbutton,d0      ;Pick up mouse button value.
        and.w   #1,d0           ;Check left button bit.
        beq     gl0             ;Branch if off.


; Hmmm...  It seems the left button is being pressed.
        bsr     checkexit       ;Is the mouse pointer over the [EXIT] box?
        tst.w   d0              ;Check results.
        beq     gl0a            ;Branch if not over [EXIT] button.

        bra     gamesetup       ;otherwise exit.
;--------------------------
gl0a:
        v_hide_c  handle
        bsr     fire_laser      ;and fire laser.
        v_show_c  handle

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
gl0:
        bsr     updatetextbox           ;Well, redraw everything down there
        bsr     test_end_of_wave        ;All missles dead?

        tst.w   wavefinished            ;Is this wave finished?
        bne     gameloop                ;branch if not yet.

;- - - - - - - - - - - - - - - - - 
        tst.w   scrollflag              ;Is scrolling enabled?
        beq     gl1a                    ;Branch if not.

gl1a:
        add.w   #1,wave                 ;Advance one wave

        tst.w   scrollflag
        beq     gl1b
        
        move.l  bpix,srcpixpointer      ;Point to the next picture
        bsr     scrollup                ;Scroll it into view.
gl1b:
        bra     nextwave
;=====================================================================


gameout:
lp12:
        tst.w   scrollflag
        beq     gl2a

        move.l  tpix,srcpixpointer
        bsr     scrollup
gl2a:
        graf_mouse #0,#0                ;Mouse back to an arrow.

        v_hide_c  handle                ;Hide it.
        Setscreen opix,opix,resolution  ;replace original screen.
        Setpallete  #orgpalette         ;And the original palette
        v_show_c  handle                ;And reshow the mouse.

        bsr     vbl_off                 ;Turn VBLs off, out of the chain

        appl_exit                       ;AES exit application call
        Pterm0                          ;And split.

;*********************************************************************



test_end_of_wave:
        move.w  #0,cmissle
        move.w  #0,wavefinished         ;Assume we are finished.
teow1:
        move.l  #misslelist,a0
        move.w  cmissle,d0
        asl.w   #1,d0
        tst.w   0(a0,d0.w)
        beq     teow2

        add.w   #1,wavefinished
teow2:
        add.w   #1,cmissle
        move.w  cmissle,d0
        cmp.w   maxmissle,d0
        blt     teow1

        rts

;"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
boomsound:
                
bsnote:
                .dc.b   0,$34
                .dc.b   1,0
                .dc.b   2,$34
                .dc.b   3,0

                .dc.b   4,0,5,0,6,0
                .dc.b   7,$fc
                .dc.b   8
bsvol:
                .dc.b   16
                .dc.b   9,16

                .dc.b   10,0,11,0

                .dc.b   12,16
                .dc.b   13,9

                .dc.b   255,0,0,0
                .even

                .even
firesound:
                .dc.b   0,$80
                .dc.b   1,5
                .dc.b   2,0,3,0,4,0,5,0,6,0
                .dc.b   7,$fe
                .dc.b   8,$10
                .dc.b   13,9
                .dc.b   11,128
                .dc.b   12,16
                .dc.b   255,0,0,0
                .even
;
;---------------------------------------------------------------------
hits:           .dc.w   0

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
fire_laser:
        tst.w   soundflag       ;Is sound allowed?
        beq     fl1             ;branch if not...
     
        Dosound #firesound      ;Else buzz buzz buzz buzz
fl1:
; before we fire, does ths city have enought power to fire?
        move.l  #powertable,a0  ;List of power addresses
        move.w  laserbase,d0
        asl.w   #2,d0
        move.l  0(a0,d0.w),a0   ;Now points at power entry itself.

        tst.w   (a0)            ;What;s the value in there?
        beq     flxax           ; Branch out if no power available.

;" " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " " "
; But, if there is power available for a shot...
; First, update the Laser destination from the current mouse position.
        move.w  mx,ldx
        move.w  my,ldy

; Next, select some color, switch to XOR drawmode, and draw laser beam.
        vsl_color  handle,#8            ;Select laser color
        vswr_mode  handle,#3            ;Select XOR mode
        v_pline  handle,lx,ly,ldx,ldy   ;draw first line.
        Vsync
        v_pline  handle,lx,ly,ldx,ldy   ;XOR it off.
        vswr_mode  handle,#1            ;Back to replace mode.

; This city has just expended some power.  Lets show it.
        move.l  #powertable,a0  ;List of power addresses
        move.w  laserbase,d0
        asl.w   #2,d0
        move.l  0(a0,d0.w),a0   ;Now points at power entry itself.

        move.w  (a0),d0         ;grab value there
        beq     f22             ;dont bump a zero down.

        sub.w   #1,(a0)         ;else bump the power down by one.
f22:


flxax:
        rts

;---------------------------------------------------------------------
; This routine will return TRUE if mouse pointer is in the EXIT
; rectangle when this routine is called.
; You must call vq_mouse before calling this routine.

checkexit:
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #184,d0         ;check for upper boundry
        blt     cxx             ;branch if higher up on the screen.

        move.w  mx,d0           ;check left edge of exit button
        cmp.w   #280,d0
        blt     cx1             ;branch if too far left

        move.l  #-1,d0          ;return a TRUE if OK.
        rts
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
cx1:
        move.w  wave,d0
        move.w  #1,d1
        abcd    d0,d1
        move.w  d1,wave

        bsr     quickinit
cxx:
        move.l  #0,d0           ;return a FALSE if not OK.
        rts


;---------------------------------------------------------------------
; In here we have the responsibility of redrawing all the information
;  along the window at the bottom of the screen.

; Variables created:
                .even
wavemess:       .dc.b   "Wave:  ",0,0
                .even
missmess:       .dc.b   "00",0,0
                .even
scoremess:      .dc.b   "000000",0,0
                .even
p0mess:         .dc.b   "00%",0,0
                .even
p1mess:         .dc.b   "00%",0,0
                .even
p2mess:         .dc.b   "00%",0,0
                .even
p3mess:         .dc.b   "00%",0,0
                .even
scoretext:      .dc.b   "Score:",0,0
                .even

; The place where the score is kept.
scorelo:        .dc.w   0
scoremed:       .dc.w   0
scorehi:        .dc.w   0

; A table of addresses of city power memory locations.
powertable:     .dc.l   power0,power1,power2,power3,power3

; This is where each cities power is kept.
power0:         .dc.w   0
power1:         .dc.w   0
power2:         .dc.w   0
power3:         .dc.w   0

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
updatetextbox:
; So the first thing to do is point at the wavenumber buffer,
;  and build the wave amount as a string into it.
        move.l  #wavemess+5,a0
        move.w  wave,d1
        bsr     decword

; ...and then place the string onto the screen.
        vst_color handle,#9
        v_gtext handle,#7,#193,#wavemess
dum2:
; Ditto with the misslebase number to the right of the wave number.
        move.l  #missmess,a0
        move.w  laserbase,d1                ;misslebase ustabe
        add.w   #1,d1
        bsr     decword
dum1:
        vst_color handle,#7
        v_gtext handle,#71,#193,#missmess

dum3:
; The score is handled about the same, except it is three bytes wide.
        move.l  #scoremess,a0
        move.w  scorehi,d1
        bsr     decword
        move.w  scoremed,d1
        bsr     decword
        move.w  scorelo,d1
        bsr     decword

        vst_color handle,#8
        v_gtext handle,#96,#193,#scoremess

dum3a:
; The power is handled about the same, except it is four bytes wide.
        move.l  #p0mess,a0
        clr.l   d0
        move.w  power0,d0
        bsr     binbcd
        bsr     decword
        vst_color handle,#9
        v_gtext handle,#154,#193,#p0mess
dum4:
        move.l  #p1mess,a0
        clr.l   d0
        move.w  power1,d0
        bsr     binbcd
        bsr     decword
        vst_color handle,#10
        v_gtext handle,#186,#193,#p1mess
dum5:
        move.l  #p2mess,a0
        clr.l   d0
        move.w  power2,d0
        bsr     binbcd
        bsr     decword
        vst_color handle,#11
        v_gtext handle,#218,#193,#p2mess
dum6:
        move.l  #p3mess,a0
        clr.l   d0
        move.w  power3,d0
        bsr     binbcd
        bsr     decword
        vst_color handle,#12
        v_gtext handle,#250,#193,#p3mess
dum7:
        rts

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; Builds string starting where (a0) points.
decword:
        move.w  d1,-(sp)        ;Stack our Word
        bra     decbyte

        lsr.w   #8,d1           ;Shift word 12 places to right
        lsr.w   #4,d1           ;. . .
        bsr     decnibbl        ;Print a nybble
        move.w  (sp),d1         ;Get
        lsr.w   #8,d1           ;next
        bsr     decnibbl        ;digit...
decbyte:  
        move.w  (sp),d1         ;Print
        lsr.w   #4,d1           ;up
        bsr     decnibbl        ;a
        move.w  (sp)+,d1        ;byte
decnibbl:
        and.w   #15,d1          ;Mask useless contents
        cmp.b   #9,d1           ;Is it a non numeric digit?
        bls     decnib2         ;Yes, so dont correct for ALpha
        
        add.b   #7,d1           ;Skip symbols in ASCII, to get alphas
decnib2: 
        add.b   #$30,d1         ;Convert to ASCII from numeric
        move.b  d1,(a0)+
        rts

;---------------------------------------------------------------------
; enter with value in d0.w

binbcd:
        move.w  #1,d2           ;addition in decimal needs this in a dx.
        move.w  #0,d1           ;erase the answer.
        tst.w   d0              ; and branch out quickly
        beq     binx            ; if the number passed in is a zero.
bin2:
; Otherwise the number in d0.w is one or greater.
        sub.b   #1,d0           ; Bump it down by one.
        bmi     binx            ; branch on wrap through zero.

        abcd    d2,d1           ;...and add one to the answer.
        bra     bin2            ; and go back for the next digit.
binx:
        rts

;---------------------------------------------------------------------
; This routine will examine each city rectangle, and if the city
; is enabled, point the laser/misslebase to it.

checkforcity:
        move.w  my,d0           ;check the vertical dimension
        cmp.w   #145,d0         ;check for upper boundry
        blt     cfcx            ;branch if higher up on the screen.

        cmp.w   #170,d0         ;check the lower boundry
        bgt     cfcx            ;branch out if lower on the screen.

;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
        move.w  mx,d0           ;check left edge of city0
        cmp.w   #15,d0
        blt     cfcx            ;branch if too far left

        cmp.w   #50,d0          ;check right edge.
        bgt     cfc1            ;branch if farther right

; At this point we have determined the mouse pointer to be within
;  a rectangle around city 0.  First, check to see if this
;  city has been enabled for use.

        move.w  #0,d0           ;Select city 0.
        move.l  #cenableflag,a0 ;Point to enable table (song in there?)
        move.w  0(a0,d0.w),d0   ;Grab city enable value, either 0 or 1
        beq     cfc1            ;Branch if not enabled...

; Else, this city has been enabled for use.  We must select it.

        move.w  #0,laserbase   ;update new base number
        move.w  #0,d0           ;Place city number here, too.
        move.l  #laserx,a0      ;Point to laser tables.
        move.l  #lasery,a1
        move.w  0(a0,d0.w),lx   ;Grab laserbase values.
        move.w  0(a1,d0.w),ly

        tst.w   soundflag       ;Is sound allowed?
        beq     cfc1            ;Branch if not...

        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
cfc1:
        move.w  mx,d0           ;check left edge of city1
        cmp.w   #90,d0
        blt     cfcx            ;branch if too far left
        cmp.w   #125,d0         ;check right edge.
        bgt     cfc2            ;branch if farther right

        move.w  #2,d0
        move.l  #cenableflag,a0
        move.w  0(a0,d0.w),d0
        beq     cfc2

        move.w  #1,laserbase
        move.w  #2,d0
        move.l  #laserx,a0
        move.l  #lasery,a1
        move.w  0(a0,d0.w),lx
        move.w  0(a1,d0.w),ly

        tst.w   soundflag       ;Is sound allowed?
        beq     cfc2            ;Branch if not...

        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
cfc2:
        move.w  mx,d0           ;check left edge of city2
        cmp.w   #170,d0
        blt     cfcx            ;branch if too far left
        cmp.w   #205,d0         ;check right edge.
        bgt     cfc3            ;branch if farther right

        move.w  #4,d0
        move.l  #cenableflag,a0
        move.w  0(a0,d0.w),d0
        beq     cfc3

        move.w  #2,laserbase   ;update new base number
        move.w  #4,d0
        move.l  #laserx,a0
        move.l  #lasery,a1
        move.w  0(a0,d0.w),lx
        move.w  0(a1,d0.w),ly

        tst.w   soundflag       ;Is sound allowed?
        beq     cfc3            ;Branch if not...

        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
cfc3:
        move.w  mx,d0           ;check left edge of city3
        cmp.w   #280,d0
        blt     cfcx            ;branch if too far left
        cmp.w   #310,d0         ;check right edge.
        bgt     cfcx            ;branch if farther right

        move.w  #6,d0
        move.l  #cenableflag,a0
        move.w  0(a0,d0.w),d0
        beq     cfcx

        move.w  #3,laserbase   ;update new base number
        move.w  #6,d0
        move.l  #laserx,a0
        move.l  #lasery,a1
        move.w  0(a0,d0.w),lx
        move.w  0(a1,d0.w),ly

        tst.w   soundflag       ;Is sound allowed?
        beq     cfcx            ;Branch if not...

        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
cfcx:
        rts


;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vhandle:        .dc.w   1
fhandle:        .dc.w   1               ;The file handle

resolution:     .dc.w   1               ;The original screen resolution

; The number of the active base.
laserbase:      .dc.w   1

; The x,y coordinates for the base of the laser.
laserx:         .dc.w   45,111,188,290,0
lasery:         .dc.w   151,155,155,151,140

;The enable flags for each base.
cenableflag:     .dc.w   0,0,0,0,0

;---------------------------------------------------------------------
; This routine will attempt to add one more city to the enabled list.
;
rflag:          .dc.w   0

addcity:
wave2enable:
        move.l  #cenableflag,a0         ;So point to the enable table
        move.w  #0,d0                   ;Reset the city counter
        move.w  #0,rflag                ;And reset the local flag.
ac1:
        tst.w   rflag                   ;have we enabled a city yet?
        bne     ac2                     ;Branch if yes.

; Else we havent enabled a city in this routine yet..
        move.w  d0,d1                   ;copy city number to companion.
        asl.w   #1,d1                   ;Indexize the friend
        tst.w   0(a0,d1.w)              ;Is this city enabled yet?
        bne     ac2                     ;Branch if it is.

        move.w  #1,0(a0,d1.w)           ;Otherwise enable it.
        add.w   #1,rflag                ;And remind ourselves weve done it.
ac2:
        add.w   #1,d0                   ;NEXT city
        cmp.w   #4,d0
        blt     ac1

        rts

;*********************************************************************
; Missle attack Logic Control center.
; 
; This is the routine which advances the attacking missles.
; Each available missle is advanced one step.  If it has
;  reached its destination, explode it, else advance and return.

; On exit, register d0=0=all missles extinguished,  d0>0 more to go.

;Variables created:

maxmissle:      .dc.w   20      ;The maximum number of active missles.
missposition:   .dc.w   0       ;used for initial placement of missles.

; Missle enable flags
; 0=not available.
; 1=available.
; 2=in flight.
; 3=exploding.

; room for twenty missles.
misslelist:     .dc.w   1,1,1,1,1,1,1,1,1,1,1,1,1,1,10,0,0,0,0,0

;Missle velocities
; Velocities are divided by one hundred. I.E. "54" is really ".54".
bmissxvel:       .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
bmissyvel:       .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

; The incredible looping divide counters
missxpos:       .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
missypos:       .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

missxvel:       .dc.w   -12,54,-31,40,-37,44,-14,22,-39,22
                .dc.w   27,-30,53,-45,30,-27,25,-54,43,-30
                .dc.w   -30,20,-30,40,-30,20,-30,20,-30,40

missyvel:       .dc.w   10,20,30,40,50,60,70,80,90,100
                .dc.w   90,90,90,90,90,90,90,90,90,90

; Suggested velocities for the different waves.
missyvtable:    .dc.w   30,45,49,59,30

cmissle:        .dc.w   0       ; The number of the current missle.
cmissstep:      .dc.w   0       ;The current step in the missle path.

; The current missle X and Y coordinates
misslex:        .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
missley:        .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; The old missle X and Y coordinates
omisslex:       .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
omissley:       .dc.w   0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

missx:          .dc.w   0
missy:          .dc.w   0
omissx:         .dc.w   0
omissy:         .dc.w   0

mxvel:          .dc.w   0
myvel:          .dc.w   0
mxp:            .dc.w   0
myp:            .dc.w   0

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
; Here we are initializing the missle positions ready for the game.

init_missles:
; Depending on the wave number, select number of missles.
        move.w  wave,d0
        cmp.w   #1,d0           ;if this is wave 1
        bne     inn1

        move.w  #5,maxmissle    ;Then use 5 missles
        bra     inn4
inn1:
        move.w  wave,d0
        cmp.w   #2,d0           ;If this is wave 2
        bne     inn2

        move.w  #10,maxmissle   ;Use ten missles
        bra     inn4
inn2:
        move.w  wave,d0
        cmp.w   #3,d0           ;If this is wave 3
        bhi     inn3

        move.w  #15,maxmissle   ;Then use 15 missles   
        bra     inn4
inn3:
        move.w  #20,maxmissle   ;Otherwise use twenty missles.
inn4:
;---- now we have decided how many missle to rain down ---------------

        move.l  #misslex,a0
        move.l  #missley,a1

        move.l  #omisslex,a2
        move.l  #omissley,a3

        move.w  #0,cmissle
        move.w  #160,missposition
inm1:
        move.w  missposition,(a0)+      ; New X register.  
        move.w  #0,(a1)+                ; Y register always zero
        move.w  missposition,(a2)+      ; New X register.  
        move.w  #0,(a3)+                ; Y register always zero

        add.w   #1,cmissle
        move.w  cmissle,d0
        cmp.w   maxmissle,d0
        blt     inm1

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
; Now its time to update the enabled missle list.
        move.w  #0,cmissle              ;Point to first missle
        move.l  #misslelist,a0          ;point to list of entries.
inm2:
        move.w  cmissle,d0              ;using this entry...
        cmp.w   maxmissle,d0            ;have we reached the end?
        bge     inm3                    ;Branch if yes.

        asl.w   #1,d0
        move.w  #1,0(a0,d0.w)           ;otherwise store a TRUE there.
        bra     inm4
inm3:
        asl.w   #1,d0
        move.w  #0,0(a0,d0.w)           ;else store a FALSE.
inm4:
        add.w   #1,cmissle              ;NEXT cmissle
        move.w  cmissle,d0
        cmp.w   #20,d0                  ;Through real end of table.
        blt     inm2

;---   ---   ---   ---   ---   ---   ---   ---   ---   ---   ---   ---
; Now its time to update the xvel and yvelof the  missle list.
        move.w  #0,cmissle              ;Point to first missle
        move.l  #missyvtable,a0         ;point to list of entries.
        move.l  #missyvel,a1
ainm2:
        move.w  wave,d0                 ;using this entry...
        cmp.w   #4,d0
        blo     ainm2a

        move.w  #3,d0
ainm2a:
        asl.w   #1,d0                   ;using this index
        move.w  0(a0,d0.w),d1           ;grab suggested y velocities

        move.w  cmissle,d2              ;for this missle, however
        move.w  d2,d3                   ;(copy into d3)
        asl.w   #1,d2                   ;indexize the missle number
        and.w   #15,d3                   ;round off d3 to 0-3
        add.w   d3,d1                   ;add it into the suggested y vel
        move.w  d1,0(a1,d2.w)           ;store resulting value on vel table.
      
        add.w   #1,cmissle              ;NEXT cmissle
        move.w  cmissle,d0
        cmp.w   #20,d0                  ;Through real end of table.
        blt     ainm2

;---   ---   ---   ---   ---   ---   ---   ---   ---   ---   ---   ---
        rts

;---------------------------------------------------------------------
; This routine will calculate the x,y velocities for each missle
; The Y velocity is a rolling counter 00-99, every time the Y
; register scrolls increment the x position.
; The procedure followed is:

; Let x=(lx-mx) neg to right, positive to left.
; Let y=(ly-my)*100 always positive.
; Let Y_velocity=(Y/X)  (actually a percentage*100)

; variables created:

cvx:            .dc.w   0
cvy:            .dc.w   0

;.. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
calc_velocities:
        move.l  #missxvel,a0
        move.l  #missyvel,a1

        move.w  #0,d0           ;FOR missle=0 to 9
cva1:
        move.w  lx,d1
        move.w  mx,d2
        sub.w   d2,d1
        move.w  d1,cvx

        move.w  ly,d1
        move.w  my,d2
        sub.w   d2,d1
        mulu.w  #100,d1
        move.w  d1,cvy

        move.w  cvy,d1
        move.w  cvx,d2
;        divu.w  cvy,cvx

        rts

;---------------------------------------------------------------------
; A routine to refresh the X,Y pointers according to "cmissle"

get_missle:
; First, recover the last known missle X,Y coordinates.
        move.l  #misslex,a0
        move.l  #missley,a1
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  0(a0,d0.w),missx
        move.w  0(a1,d0.w),missy

; next, recover the old missle X,Y coordinates.
        move.l  #omisslex,a0
        move.l  #omissley,a1
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  0(a0,d0.w),omissx
        move.w  0(a1,d0.w),omissy

; remember this missles X and Y velocity figures.
        move.l  #missxvel,a0
        move.l  #missyvel,a1
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  0(a0,d0.w),mxvel
        move.w  0(a1,d0.w),myvel

; And also recover their looping divider counter.
        move.l  #missxpos,a0
        move.l  #missypos,a1
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  0(a0,d0.w),mxp
        move.w  0(a1,d0.w),myp

        rts

;---------------------------------------------------------------------
; A routine to update the X,Y tables according to "cmissle"

set_missle:
; Set this missles current X and Y values in memory.
        move.l  #misslex,a0
        move.l  #missley,a1
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  missx,0(a0,d0.w)
        move.w  missy,0(a1,d0.w)

; Set this missles old position in memory.
        move.l  #omisslex,a0
        move.l  #omissley,a1
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  omissx,0(a0,d0.w)
        move.w  omissy,0(a1,d0.w)

; Set this missles last known looping divider counter in memory.
        move.l  #missxpos,a0
        move.l  #missypos,a1
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  mxp,0(a0,d0.w)
        move.w  myp,0(a1,d0.w)

       rts


;---------------------------------------------------------------------
move_missle:
        move.w  #0,cmissle        ;FOR missle=0 to 19
mms1:
; Recover this missles status and position information
        bsr     get_missle

; Check to see if this missle is enabled for use.
        move.l  #misslelist,a0  ;point to address table.
        move.w  cmissle,d0      ;We are interested in missle "cmissle"
        asl.w   #1,d0           ;Indexize it.
        tst.w   0(a0,d0.w)      ;Check enable value on table.
        beq     mms1a           ;Branch if not enabled for use.

; Otherwise, compare the missle position against the laser position.
        move.w  ldx,d0          ;Load laser position
        move.w  ldy,d1
        move.w  missx,d2        ;Load missle position.
        move.w  missy,d3

; Now compare the two locations together, if they match, the missle is hit.
        cmp.w   d0,d2
        bne     mms1ab
        cmp.w   d1,d3
        bne     mms1ab          ;Branch if no match.

doflash:
; Else they match, so start flash animation.
        move.w  #1,aniflag
aflxa1:
; ...and we stay in this loop until the vertical-blank run
; counter finishes and resets the aniflag.
        tst.w   aniflag
        bne     aflxa1

        Dosound  #boomsound

        v_hide_c handle
        vswr_mode  handle,#3            ;Select XOR mode
        v_pline handle,omissx,omissy,omissx,omissy
        vswr_mode  handle,#1            ;Back to replace mode.
        v_show_c handle

        bsr     increase_score

; And remove this missle from the active list.
        move.l  #misslelist,a0
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  #0,0(a0,d0.w)
        bra     mms1a
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mms1ab:
        move.w  missy,d0        ;however, are we low enough to explode?
        cmp.w   #150,d0
        blt     mms1aa          ;branch if too high.

;        bsr     acheckforcity   ;exploding near a city?
        move.w  #1,aniflag
bflxa1:
; ...and we stay in this loop until the vertical-blank run
; counter finishes and resets the aniflag.
        tst.w   aniflag
        bne     bflxa1


        v_hide_c handle
        vswr_mode  handle,#3            ;Select XOR mode
        v_pline handle,omissx,omissy,omissx,omissy
        vswr_mode  handle,#1            ;Back to replace mode.
        v_show_c handle

; And remove this missle from the active list.
        move.l  #misslelist,a0
        move.w  cmissle,d0
        asl.w   #1,d0
        move.w  #0,0(a0,d0.w)

        bra     mms1a

;---------------------------------------------------------------------
; otherwise this missle is enabled for use.
mms1aa:
        bsr     advance_missle  ;Advance the missle
        bsr     draw_missle     ;Redraw the missle 
        bsr     set_missle      ;Remember the new missle coordinates.
mms1a:
        add.w   #1,cmissle      ;NEXT missle
        move.w  cmissle,d0
        cmp.w   maxmissle,d0
        blt     mms1

        rts


;---------------------------------------------------------------------
advance_missle:
        tst.w   mxvel
        bmi     advxback

; But it seems we are moving forward... so...
        move.w  mxp,d0
        add.w   mxvel,d0
        cmp.w   #100,d0
        blt     adms1

        sub.w   #100,d0
        add.w   #1,missx
adms1:
        move.w  d0,mxp
        bra     advydirection

; Looks like we move to the left.
advxback:
        move.w  mxp,d0
        add.w   mxvel,d0
        cmp.w   #-100,d0
        bgt     adms2

        add.w   #100,d0
        sub.w   #1,missx
adms2:
        move.w  d0,mxp

advydirection:
        move.w  myp,d0
        add.w   myvel,d0
        cmp.w   #100,d0
        blt     advd1

        sub.w   #100,d0
        add.w   #1,missy
advd1:
        move.w  d0,myp

        rts


;---------------------------------------------------------------------
; This routine will XOR the missle image in at misslex, missley

; Variables created:

omx1:           .dc.w   0
omy1:           .dc.w   0
omx2:           .dc.w   0
omy2:           .dc.w   0

draw_missle:
        v_hide_c handle
        vswr_mode  handle,#3            ;Select XOR mode
        v_pline handle,omissx,omissy,omissx,omissy
        v_pline handle,missx,missy,missx,missy
        vswr_mode  handle,#1            ;Back to replace mode.
        v_show_c handle

        move.w  missx,omissx
        move.w  missy,omissy

        rts


;---------------------------------------------------------------------
; This routine will examine each city rectangle, and if the city
; is enabled, point disable it

acheckforcity:
        move.w  missy,d0        ;check the vertical dimension
        cmp.w   #145,d0         ;check for upper boundry
        blt     acfcx            ;branch if higher up on the screen.

        cmp.w   #170,d0         ;check the lower boundry
        bgt     acfcx            ;branch out if lower on the screen.

;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
        move.w  missx,d0           ;check left edge of city0
        cmp.w   #15,d0
        blt     acfcx            ;branch if too far left

        cmp.w   #50,d0          ;check right edge.
        bgt     acfc1            ;branch if farther right

; This city has just died.  Lets show it.
        move.l  #powertable,a0  ;List of power addresses
        move.w  #0,d0
        move.l  0(a0,d0.w),a0   ;Now points at power entry itself.

        move.w  #0,(a0)         ;erase value there

        tst.w   soundflag       ;Is sound allowed?
        beq     acfc1            ;Branch if not...

;        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
acfc1:
        move.w  missx,d0           ;check left edge of city1
        cmp.w   #90,d0
        blt     acfcx            ;branch if too far left
        cmp.w   #125,d0         ;check right edge.
        bgt     acfc2            ;branch if farther right

; This city has just died.  Lets show it.
        move.l  #powertable,a0  ;List of power addresses
        move.w  #2,d0
        move.l  0(a0,d0.w),a0   ;Now points at power entry itself.

        move.w  #0,(a0)         ;erase value there

        tst.w   soundflag       ;Is sound allowed?
        beq     acfc2            ;Branch if not...

;        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
acfc2:
        move.w  missx,d0           ;check left edge of city2
        cmp.w   #170,d0
        blt     acfcx            ;branch if too far left
        cmp.w   #205,d0         ;check right edge.
        bgt     acfc3            ;branch if farther right

; This city has just died.  Lets show it.
        move.l  #powertable,a0  ;List of power addresses
        move.w  #4,d0
        move.l  0(a0,d0.w),a0   ;Now points at power entry itself.

        move.w  #0,(a0)         ;erase value there

        tst.w   soundflag       ;Is sound allowed?
        beq     acfc3            ;Branch if not...

;        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
acfc3:
        move.w  missx,d0           ;check left edge of city3
        cmp.w   #280,d0
        blt     acfcx            ;branch if too far left
        cmp.w   #310,d0         ;check right edge.
        bgt     acfcx            ;branch if farther right

; This city has just died.  Lets show it.
        move.l  #powertable,a0  ;List of power addresses
        move.w  #6,d0
        move.l  0(a0,d0.w),a0   ;Now points at power entry itself.

        move.w  #0,(a0)         ;erase value there

        tst.w   soundflag       ;Is sound allowed?
        beq     acfcx            ;Branch if not...

;        Bconout #CON,#7         ;Else Scream.
;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
acfcx:
        rts



;
;---------------------------------------------------------------------
; This routine will insert the address of our vbl routine into
; the chain of addresses kept on the vbl table.  We dont actually
; follow regulation, and find a slot with a zero in it, but we
; grab the first address in the list, remember it, and insert the
; address of our routine in its place.  When we get finished, we
; jump to the original routine.

; Variables created:

vbladr: .dc.l   1       ;The saved address of the vbi slot.
scradr: .dc.l   1       ;The screen address

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
vbl_on:
        Super                   ;So enter supervisor

        move.l  _vblqueue,a0    ;Find the start of the vbl list
        move.l  (a0),vbladr     ;Pocket the first address there.

        move.l  #vblproc,(a0)   ;Move our routine address over its place.

        User                    ;return to user mode.

        rts

;---------------------------------------------------------------------
; This is the routine performed during vertical blank.
; variables created:

jiffycounter:   .dc.l   0               ;A running frame counter


;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
vblproc:
        move.l  d0,-(sp)                ;Stack register used.
        move.l  d1,-(sp)
vblp1:
        add.l   #1,jiffycounter

        bsr     do_animate

        move.l  (sp)+,d1
        move.l  (sp)+,d0                ;Unstack register used

        move.l  vbladr,-(sp)            ;Point to where we continue.
        rts

;---------------------------------------------------------------------
; This is a three-byte long binary coded decimal counter.

increase_score:
        move.w  scorelo,d0
        move.w  #1,d1
        abcd    d0,d1
        move.w  d1,scorelo

        cmp.w   #0,d1
        bne     ins1

        move.w  scoremed,d0
        move.w  #0,d1
        abcd    d0,d1
        move.w  d1,scoremed

        cmp.w   #0,d1
        bne     ins1

        move.w  scorehi,d0
        move.w  #0,d1
        abcd    d0,d1
        move.w  d1,scorehi
ins1:
        rts

;---------------------------------------------------------------------
; Animation control center
; The explosion animation is more or less controlled from this location.

; variables created:

palpointer:     .dc.l   0,0

paltable:       .dc.l   pal0,pal1,pal2,pal3,pal4
                .dc.l   pal5,pal6,pal7,pal8,pal9
                .dc.l   pala,palb,palc,pald,pale,palf,palf

pal0:           .dc.w   $777,$777,$777,$777,$777,$777,$777,$777
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal1:           .dc.w   $777,$777,$777,$777,$777,$777,$777,$777
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal2:           .dc.w   $777,$777,$777,$777,$777,$777,$777,$777
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal3:           .dc.w   $777,$777,$777,$777,$777,$777,$777,$777
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal4:           .dc.w   $777,$777,$777,$777,$777,$777,$777,$777
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal5:           .dc.w   $777,$777,$777,$777,$777,$777,$777,$777
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal6:           .dc.w   $767,$656,$646,$636,$626,$767,$767,$767
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal7:           .dc.w   $757,$545,$535,$525,$515,$757,$757,$757
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal8:           .dc.w   $747,$434,$424,$414,$404,$735,$735,$735
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pal9:           .dc.w   $646,$411,$411,$511,$511,$523,$523,$523
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pala:           .dc.w   $545,$411,$411,$433,$422,$422,$422,$422
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

palb:           .dc.w   $533,$400,$400,$400,$311,$311,$311,$311
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

palc:           .dc.w   $511,$400,$400,$400,$200,$200,$200,$500
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pald:           .dc.w   $500,$300,$300,$300,$200,$200,$200,$400
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

pale:           .dc.w   $300,$200,$300,$400,$707,$707,$707,$300
                .dc.w   $750,$700,$707,$347,$004,$333,$555,$777

palf:          .dc.w   $000,$020,$030,$040,$050,$060,$070,$770
               .dc.w   $750,$700,$707,$347,$004,$333,$555,$777


swidth:         .dc.w   0
sheight:        .dc.w   0

aniflag:        .dc.w   0
frame:          .dc.w   0

;. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
do_animate:
; First, is animation running?
        tst.w   aniflag
        beq     doax            ;branch if not.

; Otherwise animation running.  At start?
        move.w  frame,d0
        cmp.w   #16,d0
        bcc     doa_off

        move.l  #paltable,a0
        asl.w   #2,d0
        move.l  0(a0,d0.w),palpointer
        Setpallete palpointer

        add.w   #1,frame
        rts

doa_off:
        Setpallete bpal
        move.w  #0,aniflag
        move.w  #0,frame
doax:
        rts

;---------------------------------------------------------------------
; This routine will disconnect our vbl routine from the chain.

vbl_off:
        Super                           ;Enter supervisor
        move.l  _vblqueue,a0            ;Point to first entry.
        move.l  vbladr,(a0)             ;replace original value
        User                            ;return to user mode.

        rts

;---------------------------------------------------------------------
; Remember original palette

; Variables created:

orgpalette:     .dc.w  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
getpalette:
        Super                   ;So enter supervisior

        move.l  #15,d1          ;We will move 16 words
        move.l  #color0,a0      ;Point to the source in hardware
        move.l  #orgpalette,a1  ;Poin to the destination right above
gp1:
        move.w  (a0)+,d0        ;pick up a word from hardware.
        and.w   #$0777,d0       ;mask off any random crap
        move.w  d0,(a1)+        ;place down on RAM table.

        dbra    d1,gp1          ;perform loop

        User                    ;return to user mode.

        rts

;---------------------------------------------------------------------
        .even
filename:
        .dc.b   0,0,"                                   ",0
        .even
pathname:
        .dc.b   "C:\\*.*",0,"                           ",0
        .even

;---------------------------------------------------------------------
getfile:
; In fact, go out a get a path and filename for a picture.

        fsel_input  #pathname,#filename,handle

; So now we have the path, plus some crap past the last significant
; forward slash, and the files name, in pathname and filename.
; First, we need to find the very last forward slash in the path...

        move.l  #pathname,a0    ;Find the path name address.
        move.l  #0,temp         ;Reset slash position holder
        move.l  #0,d0           ;Reset active character counter
llpx1:
        add.l   #1,d0           ;Point to the next character
        move.b  (a0),d1         ;Grab the character there...
        cmp.b   #"\\",d1        ;...and see if its a forward slash.
        bne     llpx2           ;Branch over next line if not.

        move.l  d0,temp         ;Remember the slash position
llpx2:
        tst.b   (a0)+           ;Test for the zero at the end of the string
        bne     llpx1           ;Branch back up if not there.

        move.l  #pathname,a0    ;Remember the address of the path start
        add.l   temp,a0         ;Add in the slash offset.

; Now "a0" points at the character position _just_after_ the 
; right-hand-most forward slash in the path string.

        move.l  #filename,a1    ;Point to the filename address start.
llp1:
        move.b  (a1)+,(a0)+     ;Copy the character there over to the path.
        bne     llp1            ;...and branch back if it wasnt the line end

        move.b  #0,(a0)         ;add insurance.
        rts

;---------------------------------------------------------------------
; Hex printout routines,
; Entry: Prints hex string of d1.w as hexascii digits.
; Exit: No register damage.

hexbyte: 
        move.w  d1,-(sp)        ;Stack our byte
        bra.s   dobyte          ;Print up just a byte-long
hexlong: 
        swap    d1              ;Get top word at bottom
        bsr     hexword         ;Print up top word
        swap    d1              ;Get low word again to fall into hexword
hexword: 
        move.w  d1,-(sp)        ;Stack our Word
        lsr.w   #8,d1           ;Shift word 12 places to right
        lsr.w   #4,d1           ;. . .
        bsr.s   hexnibbl        ;Print a nybble
        move.w  (sp),d1         ;Get
        lsr.w   #8,d1           ;next
        bsr.s   hexnibbl        ;digit...
dobyte:  
        move.w  (sp),d1         ;Print
        lsr.w   #4,d1           ;up
        bsr.s   hexnibbl        ;a
        move.w  (sp)+,d1        ;byte
hexnibbl:
        and.w   #15,d1          ;Mask useless contents
        cmp.b   #9,d1           ;Is it a non numeric digit?
        bls.s   hexnib2         ;Yes, so dont correct for ALpha
        
        add.b   #7,d1           ;Skip symbols in ASCII, to get alphas
hexnib2: 
        add.b   #$30,d1         ;Convert to ASCII from numeric
        Bconout #CON,d1
        rts


;---- Video Routines -------------------------------------------------

; generic from and to pointer locations.
frompointer:    .dc.l   1
maskpointer:    .dc.l   1
topointer:      .dc.l   1

; Pointers to source,dest rectangles for cities 0,1,2,3.
srccity:        .dc.l   1,1,1,1,1
srcdcity:       .dc.l   1,1,1,1,1
descity:        .dc.l   1,1,1,1,1

;---------------------------------------------------------------------
initvideo:
        move.l  #srccity,a1     ;Point to source table
        move.l  #srcdcity,a3    ;source of dead city

        move.l  fpix,a0         ;Find initial offset
        move.l  a0,a2
        add.l   #22400,a0

        move.l  a0,(a1)+        ;City zero
        move.l  a2,(a3)+
        add.l   #40,a0
        add.l   #40,a2

        move.l  a0,(a1)+        ;City one
        move.l  a2,(a3)+
        add.l   #48,a0
        add.l   #48,a2

        move.l  a0,(a1)+        ;City two
        move.l  a2,(a3)+
        add.l   #48,a0
        add.l   #48,a2

        move.l  a0,(a1)+        ;City three
        move.l  a2,(a3)+


        move.l  #descity,a1
 
        move.l  opix,a0         ;Find initial offset
        add.l   #22400,a0
        move.l  a0,(a1)+        ;City zero
        add.l   #40,a0
        move.l  a0,(a1)+        ;City one
        add.l   #48,a0
        move.l  a0,(a1)+        ;City two
        add.l   #48,a0
        move.l  a0,(a1)+        ;City three
       rts

;---------------------------------------------------------------------
; This routine wants the number of the city to draw passed in d0.
; Cities are arraigned: 0 - 1 - 2 - 3  onscreen.

drawcity:
        move.w  #3,swidth               ;Set the width of the move
        move.w  #32,sheight             ;Set the height of the move.

; Before we can draw the city, we need to check if we _can_ draw it.
        move.l  d0,d1           ;First, check city enable flag.
        asl.w   #1,d1           ;Double for use as index.
        move.l  #cenableflag,a0 ;point to table
        move.w  0(a0,d1.w),d1   ;grab this citys flag.
        beq     dcitx           ;branch out if city not enabled.

; At this point, weve determined the city may be drawn.
        asl.w   #2,d0           ;city number times four for address index.

; We have a table of four addresses, each pointing to the start
; in memory of where the cities are on the foreground map.
        move.l  #srccity,a0     ;point to source city image table.
        add.l   d0,a0           ;add in offset from start of table.
        move.l  (a0),frompointer        ;Grab address off table

; We have a table of four addresses, each pointing to the start
; in memory of where the cities will be on the playground map.
        move.l  #descity,a0     ;Point to destination table start.
        add.l   d0,a0           ;add in address offset.
        move.l  (a0),topointer  ;Grab address off table.

; Now go and actually draw the image using the "from" and "to" pointers.
        bsr     draw_image
dcitx:
        rts

;---------------------------------------------------------------------
; This routine wants the number of the city to draw passed in d0.
; Cities are arraigned: 0 - 1 - 2 - 3  onscreen.

drawdcity:
        rts
        move.w  #3,swidth               ;Set the width of the move
        move.w  #32,sheight             ;Set the height of the move.

; At this point, weve determined the city may be drawn.
        asl.w   #2,d0           ;city number times four for address index.

; We have a table of four addresses, each pointing to the start
; in memory of where the cities are on the foreground map.
        move.l  #srcdcity,a0     ;point to source city image table.
        move.l  0(a0,d0.w),frompointer        ;Grab address off table

; We have a table of four addresses, each pointing to the start
; in memory of where the cities will be on the playground map.
        move.l  #descity,a0     ;Point to destination table start.
        move.l  0(a0,d0.w),topointer  ;Grab address off table.

; Now go and actually draw the image using the "from" and "to" pointers.
        bsr     draw_image
ddcitx:
        rts

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
draw_image:
        move.w  sheight,d1      ;height to d1
        subq.w  #1,d1           ;height-1=height if count starts at zero
di1:    
        move.w  swidth,d0       ;width to d0
        move.l  frompointer,a0  ;absolute screen address to a0
        move.l  topointer,a1
di0:    
        move.l  (a0)+,(a1)+     ;load screen image into d6 and d7
        move.l  (a0)+,(a1)+     ;2 words each covers all 4 planes
        dbf     d0,di0          ;repeat for 'width' times

        add.l   #160,frompointer
        add.l   #160,topointer
        dbf     d1,di1          ;repeat 'height' times
        rts                     ;done

;--------------------------------------------------------
        .even
eolmess:
        .dc.b   13,10,0,0

        .even
cmess:  .dc.b   ":",0,0


;-----------------------------------

pix:            .dc.l   1
opix:           .dc.l   1
opal:           .dc.l   1

temp:           .dc.l   1

filelen:        .dc.l   1

handle:         .dc.w   1


mcx:            .dc.w   1
mcy:            .dc.w   1
mcw:            .dc.w   1
mch:            .dc.w   1


;.....................................................................
; Include the file which builds the GEM arrays
        .include        "gemend.s"

titleram:       .ds.l   10000
foreram:        .ds.l   10000
backram:        .ds.l   10000

screenbuf:      .ds.l   1000


        .end

