Ideas in the Night

Category Archives: Programming

For example on Commodore 64 one can use absolute memory addresses somewhat freely; it is sufficient to know the memory map of C64. But on Amiga the case is completely different, because Amiga has multitasking operating system.

As it comes to allocating memory, even if one programs ”hard coded” program, that is: A program that overrides the operation of the operating system and use use directly Amiga’s hardware (Amiga has few co-processors), one can’t assume, that one can ”steal” memory anywhere one wants. In other words one can’t use absolute memory addressing and put one’s data anywhere one wants, because when the user closes the program, the whole multitasking environment can be ”broken”: There can be ”garbage” on the screen or some programs may have crashed, because the ”hard coded” program may have written its own data instead of the data on previously running programs in multitasking environment.

Still, on Amiga there is one absolute memory address, that every programmer in practice must use to get anything done when using the OS, namely address 4. From that memory address one gets so called execbase, that is necessary to call any system routines.

In order to make ”hard coded” program run faster on an Amiga it is practically necessary to stop the operation of the operating system (on an Amiga the OS routines are in ROM, though there are libraries, that are loaded (”opened” by the language of the programmer) to RAM that add more functionality to the OS). There are two ways to do that: To call OS’s Forbid() or Disable().

Image courtesy of jesadaphorn at FreeDigitalPhotos.net

Image courtesy of jesadaphorn at FreeDigitalPhotos.net

Using Forbid() is ”nice” way to stop the operation of the operating system, it forbids the task swapping of the OS, that is: All the programs on the background on the OS are stopped, until Wait() routine is called (or some of the Intuition library’s routines). Of course, when one codes “hard coded” program, one probably doesn’t use OS’s Wait(), but one’s own code using directly the hardware. When exiting ”hard coded” program, the programmer must now call Permit() in order to make the OS continue its tasks normally.

A way to get ”hard coded” program to run even faster, is to use Disable(), but that is quite naughty way to stop OS considering that the user may have a lot of programs and tasks running on the OS. Disable() stops the interruptions of the OS on the background, that is: The running of all the programs and also the interruption routines they may of their own are stopped.

Wait() routine allows interruptions regardless of Disable(), but returns the ”disabled state” after the CPU has finished the Wait() routine. Though, again in ”hard coded” programs, the programmer doesn’t probably use Wait(), but one’s own code to wait for something using directly the hardware.

If Disable() has been used, in the end of the program, one must use Enable() in order to get the OS functioning again. But if the programmer has used Disable(), there is no way to guarantee that even after Enable(), the OS is functioning normally as it was before executing the ”hard coded” program.

Still, there are some speed critical things or things where OS must be stopped for just a ”short” time on Amiga, where Disable() may be the only way to get a program working properly. Now, because Disable() ”forbids” interruption requests of the OS by setting Paula’s (a co-processor) INTENA register’s bit 14, it’s also a question of how long Disable() has stopped the OS; the longer the Disable() has stopped the OS, the more uncertain it is, that the OS is working completely – if at all – normally after Enable(). Usually the interruptions of the OS should not be stopped for over 250 microseconds at once.

Advertisements

As far as I can remember, my old Quest of Love-project was something I made with Amiga mostly in the year 2004. It seems I started something related to the project in 2003.

First I was going to do the project fully in assembly, but later I decided to switch to C, when programming the actual game.

Below is a video of the experimental intro/demo, that tells a story in the scroll text in Finnish.

The demo that is coded in MC68040 assembly uses only system routines. Notice that in the scroll text the bitplanes jump separately.

For curiosity, I ran into some problems when coding the routine that clears the scroll text area. Because 68040 processor is a lot faster than Blitter, I have used CPU for clearing the area. In the fastest version I tried to use 68040’s move16 instruction, but I had some problems with it with Amiga’s CHIP memory.

I composed the musics with Amiga’s MED. The music routine is not included in the source below, because it’s linked to main code from object code. The routine is the one that comes with MED.

The music module is also converted to object code that is linked to the main code.

I really am not good at all at making graphics and the graphics in the demo are only at experimental level… Some of the graphics are in fact something that I made, when was about 16 years old… 🙂

When coding the demo, I hadn’t decided yet, that am I going to program the game in assembly or in C. This is why there is some code that was supposed to be used in the game, but is not used in the demo.

The comments and labels are partly in English and partly in Finnish in this old project…

Anyway, if you are interested in, how the demo was coded, see below:

 

               MACHINE  68040

               incdir   "Work:Assembler/include"

               include  "QuestOfLove.i"        ; Offsetit kirjastokutsuille, ym.
               include  "Intuition/intuition.i"
               include  "Libraries/iff.i"

; MED:in ProPlayer2.a:han liittyvät viittaukset

               xref  _startmusic
               xref  _endmusic
               xref  _modnum
               xref  _mymodule
               xref  _PlayModule
               xref  _StopPlayer

IDCMPf         set   VANILLAKEY

Liput          set   BORDERLESS!ACTIVATE!RMBTRAP

BITPLANE          equ   1024
DEMOFRAME         equ   16
FONTWIDTH         equ   10-4

MAP_WIDTH         equ   63
MAP_HEIGHT        equ   61

VISIBLE_BLOCKS_X  equ   13-1
VISIBLE_BLOCKS_Y  equ   11-1

RED_TILE          equ   8
LOW_WATER         equ   10
COL_TILE          equ   12
DEEP_WATER        equ   14

GHOST             equ   18
VIITTAMIES        equ   20
KORUNAINEN        equ   21
FOUNTAIN          equ   22
FOUNTAIN2         equ   23
      
TOWN              equ   49+48*63    ; (49,48) (origo = 0,0)

;------------------------------------------------------------------------------
; Ohjelma alkaa
;------------------------------------------------------------------------------

   section  Koodi,Code

               movem.l  d2-d7/a2-a6,-(sp)

               move.w   $dff006,rnd_more     ; Satunnaislukuja varten

; Avataan kirjastot

               lea      intuinimi,a1
               moveq    #0,d0
               LibCall  Exec,OpenLibrary
               move.l   d0,Intuibase

               lea      dosnimi,a1
               moveq    #0,d0
               LibCall  Exec,OpenLibrary
               move.l   d0,Dosbase

               LibCall  Dos,Output           ; Tulostusta varten
               move.l   d0,outfile           ;

               lea      GFXnimi,a1
               moveq    #0,d0
               LibCall  Exec,OpenLibrary
               move.l   d0,GFXbase

               lea      DiskFontnimi,a1
               moveq    #0,d0
               LibCall  Exec,OpenLibrary
               move.l   d0,DiskFontbase

               lea      IFFnimi,a1
               moveq    #16,d0               ; versio
               LibCall  Exec,OpenLibrary
               move.l   d0,IFFbase

; Avataan oma fontti

               lea      textattr,a0
               LibCall  DiskFont,OpenDiskFont
               move.l   d0,Font
               beq      CleanUp

; Avataan omistus-sourcescreen & window
; (Lähde, mihin varsinaisesti ladataan omistuskuva)

               lea      OmistusNaytto,a0
               LibCall  Intui,OpenScreen
               move.l   d0,Om_Naytto
               beq      CleanUp

               move.l   Om_Naytto,a0            ; Otetaan nayton
               add.l    #44,a0                  ; viewport
               lea      colortable,a1           ; Värikartan alkuosoite
                                                ; (Tässä vaiheessa pelkää
                                                ;  mustaa)
               moveq    #32,d0                  ; 32 väriä
               LibCall  GFX,LoadRGB4

               move.l   Om_Naytto,oms_addy
               lea      UusiIkkuna4,a0
               LibCall  Intui,OpenWindow
               move.l   d0,Om_Ikkuna
               beq      CleanUp

               move.l   Om_Ikkuna,a0            ; Otetaan ikkunan
               move.l   50(a0),Om_rastport      ; rastport

               lea      omistusfile,a0
               move.l   #IFFL_MODE_READ,d0
               LibCall  IFF,_LVOOpenIFF
               move.l   d0,iff
               cmp.l    #0,d0
               beq      clean

               move.l   iff,a1
               move.l   Om_Naytto,a0
               lea      sc_BitMap(a0),a0
               LibCall  IFF,_LVODecodePic

; Avataan oma screen, tämä on näkyvä screen

               lea      UusiNaytto,a0 
               LibCall  Intui,OpenScreen
               move.l   d0,MinunNaytto
               beq      CleanUp

; Avataan ikkuna yllä avatulle näytölle

               move.l   MinunNaytto,NaytonOsoite
               lea      UusiIkkuna,a0
               LibCall  Intui,OpenWindow
               move.l   d0,MinunIkkuna
               beq      CleanUp

               move.l   MinunIkkuna,a0          ; Otetaan ikkunan
               move.l   50(a0),rastport         ; rastport

               move.l   MinunNaytto,a0          ; Otetaan nayton
               add.l    #44,a0                  ; viewport
               move.l   a0,viewport

; Ladataan "kehysfile" (kuva äsken avatulle näytölle)

               lea      kehysfile,a0
               move.l   #IFFL_MODE_READ,d0
               LibCall  IFF,_LVOOpenIFF
               move.l   d0,iff_kehysfile
               cmp.l    #0,d0
               beq      clean

               move.l   iff_kehysfile,a1
               lea      myBitMap1,a0
               LibCall  IFF,_LVODecodePic

; Ladataan block-file, värikartta lopussa

               lea      blockfile,a0
               move.l   #IFFL_MODE_READ,d0
               LibCall  IFF,_LVOOpenIFF
               move.l   d0,iff_blockfile
               cmp.l    #0,d0
               beq      clean

               move.l   iff_blockfile,a1
               lea      blockBitMap,a0
               LibCall  IFF,_LVODecodePic

; Asetetaan värit näytölle

               move.l   iff_blockfile,a1
               lea      colortable,a0
               LibCall  IFF,_LVOGetColorTab    ; Kutsun tulos: D0:ssa värien määrä

               move.l   viewport,a0
;               move.l   #colortable,a1
               lea      colortable,a1
               moveq    #32,d0                 ; 32 väriä
               LibCall  GFX,LoadRGB4

; Asetetaan värit näytölle

;               move.l   iff,a1
;               lea      colortable,a0
;               LibCall  IFF,_LVOGetColorTab    ; Kutsun tulos: D0:ssa värien määrä
;               move.l   viewport,a0
;               lea      colortable,a1
;               moveq    #32,d0                 ; 32 väriä
;               LibCall  GFX,LoadRGB4

;               move.l   #blockdata+5120,a0      ; Värienkierrätyksessä käytetään
;               lea      colortable,a1           ; colortablea...
;               moveq    #32-1,d7
;initCTSil      move.w   (a0)+,(a1)+
;               dbf      d7,initCTSil

;               move.l   viewport,a0
;               lea      colortable,a1           ; Värikartan alkuosoite
;               moveq    #32,d0                  ; 32 väriä
;               LibCall  GFX,LoadRGB4

; Avataan "omistusikkuna" näytölle

               move.l   MinunNaytto,screenaddy
               lea      UusiIkkuna3,a0
               LibCall  Intui,OpenWindow
               move.l   d0,OmistusIkkuna
               beq      CleanUp

               move.l   OmistusIkkuna,a0
               move.l   50(a0),o_rastport       ; Omistusikkunan rastport

; Joitain alustuksia...

               moveq    #8-1,d7                 ; Kopioidaan värienkierrätystä
               lea      colortable+32,a0        ; varten kierrätettävät värit
               lea      copytable,a1            ; toiseen taulukkoon...
copycol        move.w   (a0)+,(a1)+
               dbf      d7,copycol

               move.b   #FONTWIDTH,Laskuri
               move.l   #13,FontColor
               move.l   #0,frameY

               move.l   viewport,a0             ; Muutetaan feidauskuvaa
               moveq    #2,d0                   ; varten yhden värirekisterin
               moveq    #0,d1                   ; arvo mustaksi
               moveq    #0,d2
               moveq    #0,d3
               LibCall  GFX,SetRGB4

               jsr      _startmusic             ; Alun feidausmusiikit

               bsr      FadeIn                  ; Tulostetaan alkukuva
                                                ; pisteittäin

               move.l   #50*12,d1
               LibCall  Dos,Delay

; Tähän voisi laittaa mustan laatikon piirtämisen...
;
;               bsr      FadeOut                 ; Pyyhitään alkukuva
                                                ; pisteittäin

               move.l   viewport,a0             ; Asetetaan yllä muutettu
               moveq    #2,d0                   ; väri takaisin
               lea      colortable+4,a1         ; 4 = 2*2
               move.w   (a1),d1
               lsr.w    #8,d1                   ; Red
               and.l    #$f,d1
               move.w   (a1),d2
               lsr.w    #4,d2                   ; Green
               and.l    #$f,d2
               move.w   (a1),d3
               and.l    #$f,d3                  ; Blue
               LibCall  GFX,SetRGB4

               move.l   OmistusIkkuna,d0        ; Suljetaan omistusikkuna
               beq      CleanUp
               move.l   d0,a0
               LibCall  Intui,CloseWindow
               clr.l    OmistusIkkuna

; Kopiodaan myBitMap1:een ladattu kuva myBitMap2:een

               lea      myBitMap1,a0            ; Lähde bitmap-structuren osoite
               moveq    #0,d0                   ; Lähde: Yläkulman x-koord.
               moveq    #0,d1                   ; Lähde: Yläkulman y-koord.
               lea      myBitMap2,a1            ; Kohde bitmap-structuren osoite
               moveq    #0,d2                   ; Kohde: x-koord.
               moveq    #0,d3                   ; Kohde: y-koord.
               move.l   #320,d4                 ; x-koko
               move.l   #256,d5                 ; y-koko
               move.l   #$c0,d6                 ; Minterm
               moveq    #$1f,d7                 ; 5 bittitasoa
               lea      Puskuri,a2              ; Puskuri
               LibCall  GFX,BltBitMap

               move.l   #Gamefield+8,gamefield  ; gamefield-osoittimeen
                                                ; käytettävä gamefield
               move.l   #Hahmot,hahmot          ;
               move.l   #monster_map,hahmo_map

               bsr      InitGhosts
               bsr      SwapBitMaps

               jsr      _StopPlayer
               move.w   #0,_modnum              ; Main-demon musiikki
               move.l   _mymodule,a0
               jsr      _PlayModule

;------------------------------------------------------------------------------
; Pääohjelma --------------------------------------------------------------
;------------------------------------------------------------------------------
MainProgram    tst.b    Quit
               bne      CleanUp

               move.l   viewport,a0
               LibCall  GFX,WaitBOVP

               addq.b   #1,Demoonko

               cmp.b    #1,DemoDone
               beq      MainLoppu

; Tähän rutiinikutstut ...

               bsr      TextScroll
               bsr      DrawMap

               moveq    #0,d0
               move.b   Demoonko,d0
               divu.w   #3,d0
               swap     d0
               cmp.w    #0,d0
               bne      animframetst

; Aliohjelmat, jotka suoritetaan joka 3. frame

               bsr      HandlePlayer
               bsr      HandleCharacters
               bsr      SwapBitMaps          ; *
               bsr      ikkunanviestit
               bra      MainProgram

animframetst   moveq    #0,d0
               move.b   Demoonko,d0
               divu.w   #8,d0                ; Joka 8.frame on animaatioframe
               swap     d0
               cmp.w    #0,d0                ; Ovatko 16 alinta bittiä nollia?
               bne.s    ei_anim
               bsr      ColourCycling
ei_anim        
               cmp.b    #DEMOFRAME,Demoonko  ; Joka 16.frame käydään demossa
               bne      MainProgram          ; (tässä versiossa DEMOFRAMEn
               cmp.b    #1,DemoMode
               beq.s    demhon
               move.b   #0,Demoonko
               bra      MainProgram
demhon         bsr      HandleDemo           ;  oltava parillinen)
               move.b   #0,Demoonko
               bra      MainProgram

ikkunanviestit
               move.l   MinunIkkuna,a0       ; Ikkunan osoitin
               move.l   wd_UserPort(a0),a2   ; UserPort-osoitin
               moveq    #0,d1
               move.b   15(a2),d1            ; Signaalibitin numero
               moveq    #0,d0
               bset.l   d1,d0

Loop           move.l   a2,a0                ; UserPort-osoitin
               LibCall  Exec,GetMsg
               tst.l    d0
               bne.s    lueviesti
               rts
lueviesti      move.l   d0,a1                ; Viestin osoitin
               move.l   im_Class(a1),d2      ; Viestin luokka
               move.w   im_Code(a1),d3       ; Viestin koodi
               moveq    #0,d4
               moveq    #0,d5
               LibCall  Exec,ReplyMsg        ; Vastataan viestiin
WhatsHappening 
;               cmp.l    #MOUSEBUTTONS,d2     ; Viesti: Hiiren nappi?
;               bne.s    Next
;               move.b   #1,Quit
;               rts
Next1          cmp.l    #VANILLAKEY,d2       ; Viesti: Näppäin?
               bne      Next
               bsr      Nappis
Next           rts

;------------------------------------------------------------------------------
; Näppisohjaus. Samaa koodia käytetään sellaisenaan myös
; demoliikkeen ohjaamiseen. Blocked-rutiini palauttaa D0:aan joko luvun 0 tai 1
; sen mukaan, voiko suuntaan liikkua (0 = voi liikkua, 1 = ei).
;------------------------------------------------------------------------------
Nappis
               lea      OmaHahmo,a1

               cmp.b    #27,d3                  ; Esc
               bne.s    nap
               move.b   #1,Quit
               rts

nap            cmp.b    #'e',d3                  ; e-näppäin
               bne.s    spacebar

; Lasketaan pelaajan globaali paikka kartalla ja katsotaan, ollaanko
; kaupungin päällä. Tarvitsen näemmä kuitenkin jonkinlaisen "Kaupungissako"
; -muuttujan, jottei käy niin, että kaupungissa ollessa pelaajan painaessa
; e:tä, tullaan uudestaan kaupunkiin... Tarkistus tehdään vain e:tä
; painettaessa, joten pääohjelmaan ei tule "turhaa" tarkistusta.
;
; Unohtamani syyn lisäksi Blocked-rutiinia on uusittava tulevaisuudessa
; kaupunkien ja linnojen vuoksi (ellei sitten jokainen kaupunki ja linna ole
; samankokoisia kuin pääkartta).

               tst.b    inTown                  ; Ollaanko jo kaupungissa?
               bne.s    notown

               move.l   (a1),d0                 ; MapX
               move.l   4(a1),d1                ; MapY
               addq.l   #6,d0                   ; x-keskitys
               addq.l   #5,d1                   ; y-keskitys
               move.l   8(a1),d4                ; ScreenX
               move.l   12(a1),d5               ; ScreenY
               asr.l    #4,d4
               asr.l    #4,d5
               add.l    d4,d0
               add.l    d5,d1
               mulu.w   #MAP_WIDTH,d1
               add.l    d1,d0                   ; D0:ssa on nyt paikka kartalla
               cmp.w    #TOWN,d0                ; Ollaanko kaupungissa?
               bne.s    notown
               move.l   #Townfield+8,gamefield
               move.l   #Ihmiset_Town,hahmot
               move.l   #TownHahmoMap,hahmo_map
               move.l   #25,(a1)                ; Asetetaan alkukoordinaatit
               move.l   #50,4(a1)               ; kaupungissa oleskelua varten
               move.l   #0,8(a1)                ; ScreenX
               move.l   #(16*3),12(a1)          ; ScreenY (pixeleinä)
               move.b   #1,inTown
notown         rts

spacebar       ;cmp.b    #64,d3                  ; Välilyönti?
               cmp.b    #' ',d3
               bne.s    ohjaus

               cmp.b    #0,DemoDone             ; Jos painettiin ja jos ollaan
               beq.s    demokehissa             ; "loppuhuipentumassa", niin
               move.b   #1,RestartAll           ; restartoidaan alkuun...
               rts

demokehissa    cmp.b    #1,DemoMode             ; Jos taas oltiin normaalissa
               beq.s    toggle                  ; karttaosuudessa, niin
               move.b   #1,DemoMode             ; toggletetaan DemoMoodia
               rts
toggle         move.b   #0,DemoMode
               rts

; Ylös päin

ohjaus
               cmp.b    #'8',d3
               bne.s    ne
               cmp.l    #0,4(a1)
               bne.s    mapUpko
               sub.l    #16,12(a1)
               bsr      Blocked
               beq.s    poUp
               add.l    #16,12(a1)
               rts
mapUpko        cmp.l    #0,12(a1)
               ble.s    mapUp
               sub.l    #16,12(a1)           ;
               bsr      Blocked
               beq.s    poUpko
               add.l    #16,12(a1)
poUpko         rts
mapUp          subq.l   #1,4(a1)
               bsr      Blocked
               beq.s    poUp
               addq.l   #1,4(a1)
poUp           rts

; Alas päin

ne             cmp.b    #'2',d3
               bne.s    ne2
               cmp.l    #MAP_HEIGHT-11,4(a1)
               bne.s    mapDownko
               add.l    #16,12(a1)
               bsr      Blocked
               beq.s    poDownko
               sub.l    #16,12(a1)
poDownko       rts
mapDownko      cmp.l    #0,12(a1)
               bge.s    mapDown
               add.l    #16,12(a1)
               bsr      Blocked
               beq.s    poDown
               sub.l    #16,12(a1)
               rts
mapDown        addq.l   #1,4(a1)
               bsr      Blocked
               beq.s    poDown
               subq.l   #1,4(a1)
poDown         rts

; Vasemmalle

ne2            cmp.b    #'4',d3
               bne.s    ne3
               cmp.l    #0,(a1)
               bne.s    mapLeftko
               sub.l    #16,8(a1)
               bsr      Blocked
               beq.s    poLeftko
               add.l    #16,8(a1)
poLeftko       rts
mapLeftko      cmp.l    #0,8(a1)
               ble.s    mapLeft
               sub.l    #16,8(a1)
               bsr      Blocked
               beq.s    poLeftko
               add.l    #16,8(a1)
               rts
mapLeft        subq.l   #1,(a1)
               bsr      Blocked
               beq.s    poLeft
               addq.l   #1,(a1)
poLeft         rts

; Oikealle

ne3            cmp.b    #'6',d3
               bne.s    ne4
               cmp.l    #MAP_WIDTH-13,(a1)
               bne.s    mapRightko
               add.l    #16,8(a1)
               bsr      Blocked
               beq.s    poRightko
               sub.l    #16,8(a1)
poRightko      rts             
mapRightko     cmp.l    #0,8(a1)
               bge.s    mapRight
               add.l    #16,8(a1)
               bsr      Blocked
               beq.s    poRightko
               rts
mapRight       addq.l   #1,(a1)
               bsr      Blocked
               beq.s    ne4
               subq.l   #1,(a1)
ne4            rts
;------------------------------------------------------------------------------
; Blocked -- tarkistaa voiko valittuun kulkusuuntaan mennä, palauttaa
; D0:ssa 0 jos voi; 1 jos ei. Olettaa rekisterit Näppis-aliohjelman mukaisiksi.
; Ks. Huomautus Nappis-rutiinissa...
;------------------------------------------------------------------------------
Blocked        move.l   gamefield,a2

               lea      OmaHahmo,a1
               move.l   (a1),d0              ; "Pelaajan" MapX
               move.l   4(a1),d1             ; "Pelaajan" MapY
               move.l   8(a1),d2             ; ScreenX
               move.l   12(a1),d3            ; ScreenY
               addq.l   #6,d0                ; Keskitys
               addq.l   #5,d1                ; Keskitys
               lsl.w    #1,d0
               lsl.w    #1,d1
               mulu.w   #MAP_WIDTH,d1
               asr.l    #3,d2                ; /16 * 2 ("LSL.W #1,DX valmiina")
               asr.l    #3,d3                ; /16 * 2 ("LSL.W #1,DY valmiina")
               move.l   d3,d4
               muls.w   #MAP_WIDTH,d3        ; ASR:n ja MULS:n voisi "yhdistää"
               add.l    d0,a2
               add.l    d1,a2
               add.l    d2,a2
               add.l    d3,a2

; Aluksi katsotaan, onko kävelty ulos kartalta

               tst.b    inTown
               beq.w    blockedko
               cmp.l    #-(6*2),d2                 ; "x1"
               bge.s    eks2
               bsr.w    backtomainmap
               rts
eks2           cmp.w    #6*2,d2
               ble.s    yy1
               bsr.w    backtomainmap
               rts
yy1            cmp.l    #-(5*2),d4
               bge.s    yy2
               bsr.w    backtomainmap
               rts
yy2            cmp.w    #5*2,d4
               ble.s    blockedko
               bsr.w    backtomainmap
               rts

blockedko      cmp.w    #RED_TILE,(a2)       ; Punainen tiili
               bne.s    nxt1
               moveq    #1,d0
               rts
nxt1           cmp.w    #LOW_WATER,(a2)      ; Matala vesi
               bne.s    nxt2
               moveq    #1,d0
               rts
nxt2           cmp.w    #COL_TILE,(a2)       ; Värikäs seinä
               bne.s    nxt3
               moveq    #1,d0
               rts
nxt3           cmp.w    #DEEP_WATER,(a2)     ; Syvä vesi
               bne.s    nxtN1
               moveq    #1,d0
               rts
nxtN1          cmp.w    #FOUNTAIN,(a2)
               bne.s    nxtN2
               moveq    #1,d0
               rts
nxtN2          cmp.w    #FOUNTAIN2,(a2)
               bne.s    nxt4
               moveq    #1,d0
               rts

; Katsotaan, onko kävelty kartalla olevan hahmon päälle

nxt4           move.l   hahmo_map,a2
;              cmp.l    #0,a2                ; Tässä versiossa hoidetaan varsin
;              beq      nxt6                 ; kömpelösti tsekkaus pelaajan
                                             ; törmäämisestä eri hahmoihin...
                                             ; Tosin pienellä lisähiomisella
                                             ; kokonaisuudesta saa varsin
                                             ; näppärän.
                                             ; Voisi miettiä myös toisenlaista
                                             ; "tietorakennetta": monster_map
                                             ; pitäisi sisällään myös monste-
                                             ; reiden koordinaatit...
               add.l    d0,a2
               add.l    d1,a2
               add.l    d2,a2
               add.l    d3,a2

               cmp.w    #17,(a2)             ; Nainen vihreällä hameella
               bne.s    nxt5
               bsr      LoppuHuipentuma
               bsr      SwapBitMaps
               moveq    #0,d0                ; Kone sekoaa, jos palautetaan
                                             ; luku  1
               rts

nxt5           cmp.w    #GHOST,(a2)
               bne      nxt7                 ; .s

               movem.l  d0-d2/a0,-(sp)
               move.l   #Hahmot+24,a0

; Lasketaan D0:aan pelaajan varsinainen x-koordinaatti kartalla, tulos D0:aan

               move.l   (a1),d0              ; Pelaajan MapX
               move.l   8(a1),d1             ; Pelaajan ScreenX
               asr.l    #4,d1
               add.l    d1,d0
               addq.l   #6,d0                ; "Keskitys"

; Lasketaan D1:een pelaajan varsinainen y-koordinaatti kartalla, tulos D1:een

               move.l   4(a1),d1             ; Pelaajan MapY
               move.l   12(a1),d2            ; Pelaajan ScreenY
               asr.l    #4,d2
               add.l    d2,d1
               addq.l   #5,d1                ; "Keskitys"

cmpX           cmp.l    #0,20(a0)
               bne.s    elossa
               add.l    #24,a0
               cmp.l    #-1,(a0)
               bne.s    cmpX
               moveq    #0,d0                ; Blockiin voi siirtyä
               movem.l  (sp)+,d0-d2/a0
               rts

elossa         move.l   (a0),d2              ; "cmpX"
               cmp.l    d0,d2                ; Onko PlyX == MonsterX ?
               beq.s    cmpY
               add.l    #24,a0               ; Seuraavan monsterin kohdalle
               cmp.l    #-1,(a0)             ; Loppuivatko monsterit?
               bne.s    cmpX
               movem.l  (sp)+,d0-d2/a0
               moveq    #0,d0                ; Blockiin voi siirtyä
               rts

cmpY           move.l   4(a0),d2
               cmp.l    d1,d2
               beq.s    eraseMonster
               add.l    #24,a0               ; Seuraavan monsterin kohdalle
               cmp.l    #-1,(a0)
               bne.s    cmpX
               movem.l  (sp)+,d0-d2/a0
               moveq    #0,d0                ; Blockiin voi siirtyä
               rts

eraseMonster   move.l   #0,20(a0)            ; Monsteri kuollut
               move.l   #12,20(a1)           ; Frame-counter sädekehälle
               movem.l  (sp)+,d0-d2/a0
nxt6           moveq    #0,d0                ; Palautetaan nolla, jos
                                             ; uuteen paikkaan voi mennä
               rts
nxt7           cmp.w    #VIITTAMIES,(a2)
               bne.s    nxt8
               moveq    #1,d0
               rts
nxt8           cmp.w    #KORUNAINEN,(a2)
               bne.s    nxt9
               moveq    #1,d0
               rts
nxt9           moveq    #0,d0
               rts

backtomainmap  move.l   #Gamefield+8,gamefield  ; Takaisin pääkartalle
               move.l   #Hahmot,hahmot
               move.l   #monster_map,hahmo_map
               move.l   #49-6,(a1)              ; Koordinaatit kuntoon
               move.l   #48-5,4(a1)          ; pääkartaa varten...
               move.l   #0,8(a1)             ;  ScreenX
               move.l   #0,12(a1)            ;  ScreenY
               move.b   #0,inTown
               moveq    #0,d0                ; "Loppumerkki" "parent-rutiinille"
               rts

;------------------------------------------------------------------------------
; Piirretään kartta (13*11 blockia)
;------------------------------------------------------------------------------
DrawMap        move.l   #MAP_WIDTH*2,d4   ; Pelikentän leveys wordeina (*2)
               sub.l    #26,d4            ; VISIBLE_BLOCKS_X * 2

               lea      OmaHahmo,a2
               move.l   #7+41*40,d2       ; ((320-13*16)/2)/8 + 41*40

; Lasketaan karttadatan vasen yläkulma ("dynaaminen origo") pelaajan
; koordinaattien perusteella

               move.l   (a2),d0           ; Pelaajan MapX
               move.l   4(a2),d1          ; Pelaajan MapY
               lsl.w    #1,d0             ; x parilliseksi
;              lsl.w    #1,d1             ; y parilliseksi
               mulu.w   #MAP_WIDTH*2,d1   ; kerrotaan y*2 kartan leveydellä
               add.l    d1,d0
               move.l   gamefield,a3
               add.l    d0,a3             ; "Dynaaminen origo"

; Kartan tulostus jaettu 2:lle rasterikierrokselle...

               move.l   DrawBitMap,a2     ; Tulostus silmukan nopeuttamiseksi
                                          ; DrawBitMap a2:een...

               lea      blockBitMap,a6

               move.l   frameY,d5
               mulu.w   #2*MAP_WIDTH,d5   ; *2 = parilliseksi
               add.l    d5,a3
               move.l   frameY,d5
               mulu.w   #40*16,d5
               add.l    d5,d2             ; Lisätään frameY-paikka "paikkaan"
               
               cmp.l    #3,frameY
               bge.s    lines4
               moveq    #3-1,d7
               bra.s    mapsil
lines4         moveq    #4-1,d7

mapsil         moveq    #VISIBLE_BLOCKS_X,d6
xsil

; Lasketaan paikka, mistä piirretään (D0)

               move.w   (a3)+,d0          ; Blockin "y-koordinaatti"
               lsl.w    #5,d0

; Kopioidaan blocki blockbitmapista...

               move.l   8(a6),a0          ; Source X
               add.l    d0,a0             ; Source
               move.l   8(a2),a1          ; Dest, BitPlane1
               add.l    d2,a1
               moveq    #16-1,d5          ; 16 pixeliä
bpl1sil        move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,bpl1sil

               move.l   12(a6),a0         ; X Source
               add.l    d0,a0             ; Source
               move.l   12(a2),a1         ; Dest, BitPlane2
               add.l    d2,a1
               moveq    #15,d5
bpl2sil        move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,bpl2sil

               move.l   16(a6),a0         ; Source
               add.l    d0,a0             ; Source
               move.l   16(a2),a1         ; Dest, BitPlane3
               add.l    d2,a1
               moveq    #15,d5
bpl3sil        move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,bpl3sil

               move.l   20(a6),a0         ; Source
               add.l    d0,a0             ; Source
               move.l   20(a2),a1         ; Dest, BitPlane4
               add.l    d2,a1
               moveq    #15,d5
bpl4sil        move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,bpl4sil

               move.l   24(a6),a0         ; Source
               add.l    d0,a0             ; Source
               move.l   24(a2),a1         ; Dest, BitPlane5
               add.l    d2,a1
               moveq    #15,d5
bpl5sil        move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,bpl5sil

               addq.l   #2,d2
               dbf      d6,xsil
               add.l    #40*16-(13*2),d2
               add.l    d4,a3
               dbf      d7,mapsil         ; "ysil"

               cmp.l    #3,frameY
               bge.s    kolomone
               addq.l   #3,frameY
               rts
kolomone       addq.l   #4,frameY
               cmp.l    #9,frameY
               blt.s    gouoon
               move.l   #0,frameY
gouoon         rts


; ------------------------------------------------------------------------------
; Joka 16. frame luetaan suunta demoliikettä varten
; ------------------------------------------------------------------------------
HandleDemo     moveq    #0,d3
               lea      Demoliike(pc),a0
               move.l   demomoveind,d0
               move.b   (a0,d0),d3
               bne.s    demojatkuu        ; Jos D0:ssa 0, niin pois demosta
               rts
demojatkuu     bsr      Nappis
               addq.l   #1,demomoveind
               rts

;------------------------------------------------------------------------------
; SwapBitMaps
;------------------------------------------------------------------------------
SwapBitMaps    tst.b    Kumpi
               beq.s    nholla
               move.b   #0,Kumpi
               move.l   viewport,a0
               move.l   vp_RasInfo(a0),a0
               lea      ri_BitMap(a0),a0
               move.l   #myBitMap1,(a0)
               move.l   #myBitMap2,DrawBitMap
               move.l   #myBitMap1,ShowBitMap
               move.l   viewport,a0
               LibCall  GFX,ScrollVPort
               rts
nholla         move.b   #1,Kumpi
               move.l   viewport,a0
               move.l   vp_RasInfo(a0),a0
               lea      ri_BitMap(a0),a0 
               move.l   #myBitMap2,(a0)
               move.l   #myBitMap1,DrawBitMap
               move.l   #myBitMap2,ShowBitMap
               move.l   viewport,a0
               LibCall  GFX,ScrollVPort
               rts

; -----------------------------------------------------------------------------
; A0:ssa tekstin alkuosoite
; -----------------------------------------------------------------------------
Print          move.l   a0,d2
etsi_0         tst.b    (a0)+
               bne.s    etsi_0
               subq.l   #1,a0
               sub.l    d2,a0
               move.l   a0,d3
               move.l   outfile,d1
               LibCall  Dos,Write
               rts


;-------------------------------------------------------------------------------
; Hoidellaan kartalla vaeltavat hahmot
;-------------------------------------------------------------------------------
HandleCharacters
               addq.b   #1,mm_delay

               move.l   hahmot,a3
;               lea      Hahmot,a3
hahmosil       cmp.l    #0,20(a3)         ; Jos hahmo ei ole elossa, niin
               beq      seuraava          ; mennään seuraavan kohdalle

               move.l   OmaHahmo,d0       ; Pelaajan MapX
               move.l   OmaHahmo+4,d1     ; Pelaajan MapY
               move.l   (a3),d2           ; Hahmon x-koordinaatti
               move.l   4(a3),d3          ; Hahmon y-koordinaatti

               cmp.b    #4,mm_delay       ; 3*4 framen viive
               bne.s    visible           ; Aina kuitenkin piirretään, jottei
                                          ; kartta peitä

               move.l   16(a3),d5         ; Liikkuvako?
               tst.l    d5                ; Onko hahmo liikkuva?
               bmi.s    visible           ; Ei, katsotaan onko näkyvissä
               bsr      MoveCharacter

visible        move.l   (a3),d2           ; Hahmon x-koordinaatti
               move.l   4(a3),d3          ; Hahmon y-koordinaatti
               move.l   OmaHahmo,d0       ; Pelaajan MapX
               move.l   OmaHahmo+4,d1     ; Pelaajan MapY
               sub.l    d0,d2
               cmp.l    #0,d2             ;
               blt.s    seuraava          ; Jos PelaajaX - HahmoX 0 !
               move.l   d0,(a0)+

               addq.l   #2,d2
               cmp.l    #10,d2            ; Jos rivi monstereita täynnä,
               ble.s    cont              ; niin aloitetaan seuraava kaksi
               moveq    #3,d2             ; blockia alempaa
               addq.l   #2,d3
cont           dbf      d7,bmsil
               move.l   #$ffffffff,(a0)   ; Loppumerkki monstereille

               movem.l  (sp)+,d0-d4
               
; Täytetään taistelukenttä blockeista, so. piirretään kyseinen kenttä

FillField      moveq    #42,d3            ; BltBitMap: Kohteen y-koord.
               moveq    #11-1,d7          ; y: 11 blockia
fbfsil_y       moveq    #13-1,d6          ; x: 13 blockia
               moveq    #56,d2            ; BltBitMap: Kohteen x-koord.
fbfsil_x       moveq    #0,d0
               move.w   (a2)+,d0
               lsl.l    #4,d0             ; Blockin järj.no. pixeleiksi (x)

               movem.l  d6-d7/a2,-(sp)

;               move.l   blockScreen,a0
;               lea      sc_BitMap(a0),a0  ; Lähde bitmap-structuren osoite
               moveq    #0,d1             ; Lähde: Yläkulman y-koord.
               move.l   MinunNaytto,a1    ; Kohde bitmap-structuren
               lea      sc_BitMap(a1),a1  ; osoite
               move.l   #16,d4            ; x-koko
               move.l   #16,d5            ; y-koko
               move.l   #$c0,d6           ; Minterm
               move.l   #$1f,d7           ; 5 bittitasoa
               lea      Puskuri,a2        ; Puskuri
;               LibCall  GFX,BltBitMap
               
               movem.l  (sp)+,d6-d7/a2

               add.l    #16,d2
               dbf      d6,fbfsil_x
               add.l    #16,d3
               dbf      d7,fbfsil_y
               rts

;-------------------------------------------------------------------------------
; Blitataan taistelutilanteen monsteri
; - HUOM! Muista, että LibCall-makro käyttää A6:sta !
;-------------------------------------------------------------------------------
BlitBattleMonster
               movem.l  d0-d7/a0-a6,-(sp)

;               move.l   blockScreen,a0
;               lea      sc_BitMap(a0),a0  ; Lähde bitmap-structuren osoite
               lsl.l    #4,d0             ; Lähde: Yläkulman x-koord.
               moveq    #0,d1             ; Lähde: Yläkulman y-koord.
               move.l   MinunNaytto,a1    ; Kohde bitmap-structuren
               lea      sc_BitMap(a1),a1  ; osoite
               lsl.l    #4,d2             ; Kohde: x-koord.
               lsl.l    #4,d3             ; Kohde: y-koord.
               add.l    #56,d2            ; Keskitetään koordinaatit
               add.l    #42,d3            ; karttanäkymään
               move.l   #16,d4            ; x-koko
               move.l   #16,d5            ; y-koko
               move.l   #$c0,d6           ; Minterm
               moveq    #$1f,d7           ; 5 bittitasoa
               lea      Puskuri,a2        ; Puskuri
;               LibCall  GFX,BltBitMap

               movem.l  (sp)+,d0-d7/a0-a6
               rts

;-------------------------------------------------------------------------------
; Loppuhuipentuma!
;-------------------------------------------------------------------------------
LoppuHuipentuma
               move.l   a1,-(sp)
               movem.l  d0-d7/a0-a6,-(sp)
               jsr      _StopPlayer
               move.w   #1,_modnum
               move.l   _mymodule,a0
               jsr      _PlayModule
               movem.l  (sp)+,d0-d7/a0-a6

               move.l   #Lovefield+8,a3
               bsr      DrawField

               move.l   #16,d0
               lsl.w    #1,d0             ; Wordeiksi
               lsl.w    #4,d0             ; *16
                                          ; Muualla koodissa tämä on muodossa
                                          ; LSL.W #5,D0

               move.l   #1+7+41*40,d2     ; ((320-13*16)/2)/8 + 41*40
               add.l    #6*(16/8),d2
               add.l    #5*40*16,d2
               move.l   #boyMask(pc),a2
               bsr      DrawMonster


               move.l   #17,d0
               lsl.w    #1,d0             ; Wordeiksi
               lsl.w    #4,d0             ; *16
                                          ; Muualla koodissa tämä on muodossa
                                          ; LSL.W #5,D0

               move.l   #1+7+41*40,d2     ; ((320-13*16)/2)/8 + 41*40
               add.l    #5*(16/8),d2
               add.l    #5*40*16,d2
               move.l   #girlMask(pc),a2
               bsr      DrawMonster

               move.b   #1,DemoDone
               move.l   (sp)+,a1
               rts

;------------------------------------------------------------------------------
; Hoidellaan "pelaaja" ("oma hahmo").
; Pelaajan karttakoordinaatit tarkoittavat paikkaa kulloisenkin näkymän
; vasemassa yläkulmassa. Kuvaruudelle hahmo piirretään kuitenkin keskelle,
; jolloin hahmon aktuaalinen paikka kartalla on eri kuin näkymän vasenta
; yläkulmaa vastaava paikka kartalla.
;------------------------------------------------------------------------------
HandlePlayer
               lea      OmaHahmo,a0
               move.l   8(a0),d4          ; x-koordinaatti (screen)
               move.l   12(a0),d5         ; y-koordinaatti (screen)
;               move.l   16(a0),d0         ; Graafinen järjestysnumero
;              lsl.l    #5,d0             ; 4 + 1

               move.l   20(a0),d6         ; Sädekehä on/off
               beq.s    ei_kehaa

               subq.l   #1,20(a0)
               cmp.l    #0,20(a0)
               bgt.s    sadekehaon
               move.l   #0,20(a0)
               bra.s    ei_kehaa

sadekehaon     
               move.l   Om_Naytto,a0
               lea      sc_BitMap(a0),a0
               move.l   #159,d0
               moveq    #0,d1
               move.l   DrawBitMap,a1
               move.l   #56+5*16,d2
               add.l    d4,d2
               move.l   #41+4*16,d3
               add.l    d5,d3
               moveq    #48,d4
               moveq    #48,d5
               move.l   #$c0,d6           ; Minterm
               moveq    #31,d7
               LibCall  GFX,BltBitMap
               rts

ei_kehaa       move.l   #16*2*16,d0
               move.l   #4859,d2          ; ((320-13*16)/2)/8 + 41*40 +
                                          ; 6*(16/8) + (5*16)*40
               move.l   8(a0),d4          ; x-koordinaatti (screen)
               move.l   12(a0),d5         ; y-koordinaatti (screen)
               asr.l    #3,d4             ; screenX pixeleistä tavuiksi
               add.l    d4,d2
               muls     #40,d5
               add.l    d5,d2

               bsr      DrawBlock         ; D0 = lähde-osoitteeseen lisättävä
                                          ; paikka, D2 = kohde-osoitteeseen
                                          ; lisättävä paikka
               rts


;------------------------------------------------------------------------------
; Scrollaus
;------------------------------------------------------------------------------
TextScroll     
               cmp.b    #0,Laskuri
               bne      kopioi

; Pyyhitään vanha kirjain pois. Väristä johtuen 4:n bittitason
; käsittely riittää.

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   8(a0),a0          ; BitPlane1
               add.l    #124*40,a0
               moveq    #14-1,d7
csil1          move.w   #0,(a0)
               add.l    #40,a0
               dbf      d7,csil2

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   12(a0),a0         ; BitPlane2
               add.l    #124*40,a0
               moveq    #14-1,d7
csil2          move.w   #0,(a0)
               add.l    #40,a0
               dbf      d7,csil2

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   16(a0),a0         ; BitPlane3
               add.l    #124*40,a0
               moveq    #14-1,d7
csil3          move.w   #0,(a0)
               add.l    #40,a0
               dbf      d7,csil3

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   20(a0),a0         ; BitPlane4
               add.l    #124*40,a0
               moveq    #14-1,d7
csil4          move.w   #0,(a0)
               add.l    #40,a0
               dbf      d7,csil4

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   24(a0),a0         ; BitPlane5
               add.l    #124*40,a0
               moveq    #14-1,d7
csil5          move.w   #0,(a0)
               add.l    #40,a0
               dbf      d7,csil5

; Tulostetaan uusi kirjain

               move.l   Om_rastport,a1
               moveq    #13,d0               ; Fontin väri
               LibCall  GFX,SetAPen

               move.l   Om_rastport,a1     ; Piirtokynä scrollWindowin "origoon"
               moveq    #0,d0
               move.l   #33+100,d1        ; Huomaa fontin baseline
               LibCall  GFX,Move

               move.l   Om_rastport,a1
               lea      ScrolliTeksti(pc),a0
               move.l   TextInd,d0
               add.l    d0,a0
               cmp.b    #0,(a0)
               bne.s    notrestart
               rts                        ; Scrolleri ei tässä versiossa
                                          ; restartoidu
;               move.l   #0,TextInd
;               lea      ScrolliTeksti,a0
notrestart     moveq    #1,d0             ; Tulostetaan yksi kirjain
               LibCall  GFX,Text

               move.b   #FONTWIDTH,Laskuri
               addq.l   #1,TextInd
               move.l   #0,CopyInd

; Kopioidaan blockWindowista pala kirjainta scrollaavaan ikkunaan

kopioi         move.l   Om_rastport,a0
               move.l   CopyInd,d0        ; Lähde x-koord
               move.l   #25+100,d1        ; Lähde y-koord
               move.l   Om_rastport,a1
               move.l   #318,d2           ; Kohde x-koord
               move.l   #0+100,d3         ; Kohde y-koord
               moveq    #2,d4             ; x-koko
               moveq    #14,d5            ; y-koko
               move.l   #$c0,d6           ; Minterm
               LibCall  GFX,ClipBlit

; Scrollataan scrolli-ikkunalla

               move.l   Om_rastport,a1
               moveq    #2,d0             ; x-steppi
               moveq    #0,d1             ; y-steppi
               moveq    #0,d2             ; x1
               move.l   #100,d3           ; y1
               move.l   #319,d4           ; x2
               move.l   #112,d5           ; y2
               LibCall  GFX,ScrollRaster

               subq.b   #1,Laskuri
               addq.l   #2,CopyInd

; Pyyhitään scrollitekstialue kokonaan (320*16)

               moveq    #0,d0
               moveq    #0,d1
               moveq    #0,d2
               moveq    #0,d3
               moveq    #0,d4
               moveq    #0,d5
               moveq    #0,d6

               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   8(a1),a1          ; BitPlane1
               add.l    #235*40,a1
               moveq    #22-1,d7          ; 616 tavua
cs1            movem.l  d0-d6,(a1)        ; 28 tavua
               add.l    #28,a1
               dbf      d7,cs1
               movem.l  d0-d5,(a1)        ; 24 tavua

               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   12(a1),a1          ; BitPlane2
               add.l    #235*40,a1
               moveq    #21,d7            ;
cs2            movem.l  d0-d6,(a1)
               add.l    #28,a1
               dbf      d7,cs2
               movem.l  d0-d5,(a1)        ; 24 tavua

               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   16(a1),a1          ; BitPlane3
               add.l    #235*40,a1
               moveq    #21,d7            ;
cs3            movem.l  d0-d6,(a1)
               add.l    #28,a1
               dbf      d7,cs3
               movem.l  d0-d5,(a1)        ; 24 tavua

               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   20(a1),a1          ; BitPlane4
               add.l    #235*40,a1
               moveq    #21,d7            ;
cs4            movem.l  d0-d6,(a1)
               add.l    #28,a1
               dbf      d7,cs4
               movem.l  d0-d5,(a1)        ; 24 tavua

               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   24(a1),a1          ; BitPlane5
               add.l    #235*40,a1
               moveq    #22-1,d7          ;
cs5            movem.l  d0-d6,(a1)
               add.l    #28,a1
               dbf      d7,cs5
               movem.l  d0-d5,(a1)        ; 24 tavua

; Kopsataan yksöispuskurointi-scrollin gfx DrawBitMappiin. Kopsaus hoidetaan
; omalla CPU-pohjaisella rutiinilla. Pitää tarkistaa MOVE16-käskyn tapaa
; viitata muistiosoitteisiin; näyttää todella olevan jotain hässäkkää
; CHIP-muistin kanssa...

;              lea      Pomppu,a2
;              add.l    pind,a2
;              move.l   (a2),d0
;              cmp.l    #1,d0
;              bne.s    nou
;              move.l   #-4,pind
;              moveq    #0,d0
;nou           addq.l   #4,pind

               lea      Pomppu2(pc),a2
               add.l    pind,a2
               move.l   (a2),d0
               cmp.l    #1,d0
               bne.s    nouh2
               move.l   #-4,pind
               moveq    #0,d0
nouh2          addq.l   #4,pind

               lea      Pomppu2(pc),a2
               add.l    pind2,a2
               move.l   (a2),d1
               cmp.l    #1,d1
               bne.s    nou2
               move.l   #-4,pind2
               moveq    #0,d1
nou2           addq.l   #4,pind2

; Kopioidaan scrolliscreeniltä scrollaus paikalleen pomppudatojen kera

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   8(a0),a0          ; BitPlane1
               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   8(a1),a1          ; BitPlane1
               add.l    #100*40,a0
               add.l    #237*40,a1
               add.l    d0,a1
               moveq    #120-1,d7         ; (30-1 = ((320/8) * 12) / 16 )
copysil1       move.l   (a0)+,(a1)+       ; (move16)
               dbf      d7,copysil1

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   12(a0),a0          ; BitPlane2
               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   12(a1),a1          ; BitPlane2
               add.l    #100*40,a0
               add.l    #237*40,a1
               moveq    #120-1,d7
copysil2       move.l   (a0)+,(a1)+
               dbf      d7,copysil2

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   16(a0),a0         ; BitPlane3
               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   16(a1),a1         ; BitPlane3
               add.l    #100*40,a0
               add.l    #237*40,a1
               add.l    d1,a1
               moveq    #120-1,d7         ; 30-1
copysil3       move.l   (a0)+,(a1)+
               dbf      d7,copysil3

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   20(a0),a0         ; BitPlane4
               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   20(a1),a1         ; BitPlane4
               add.l    #100*40,a0
               add.l    #237*40,a1
               add.l    d1,a1
               moveq    #120-1,d7         ; 30-1
copysil4       move.l   (a0)+,(a1)+
               dbf      d7,copysil4

               move.l   Om_Naytto,a0      ; Lähde-screenin
               lea      sc_BitMap(a0),a0  ; bitmap-structuren osoite
               move.l   24(a0),a0         ; BitPlane5
               move.l   ShowBitMap,a1     ; Kohde-bitmap -structuuri
               move.l   24(a1),a1         ; BitPlane5
               add.l    #100*40,a0
               add.l    #237*40,a1
               add.l    d1,a1
               moveq    #120-1,d7         ; 30-1
copysil5       move.l   (a0)+,(a1)+
               dbf      d7,copysil5

               rts

;------------------------------------------------------------------------------
; Piirretään 16*16 monster; erona DrawBlock-rutiiniin se, että grafiikka
; "OR'itetaan" taustagrafiikan kanssa.
;------------------------------------------------------------------------------
DrawMonster    movem.l  d5-d7/a0/a3,-(sp)

               move.l   DrawBitMap,a3
               move.l   #blockplane1,a0
               add.l    d0,a0             ; Source
               move.l   8(a3),a1          ; Dest, BitPlane1
               add.l    d2,a1
               moveq    #15,d5            ; 16 pixeliä
dmbpl1sil      move.w   (a0)+,d6
               move.w   (a1),d7
               and.w    (a2)+,d7
               or.w     d6,d7
               move.w   d7,(a1)
               add.l    #40,a1
               dbf      d5,dmbpl1sil

               sub.l    #32,a2
               move.l   #blockplane2,a0
               add.l    d0,a0             ; Source
               move.l   12(a3),a1         ; Dest, BitPlane2
               add.l    d2,a1
               moveq    #15,d5
dmbpl2sil      move.w   (a0)+,d6
               move.w   (a1),d7
               and.w    (a2)+,d7
               or.w     d6,d7
               move.w   d7,(a1)
               add.l    #40,a1
               dbf      d5,dmbpl2sil

               sub.l    #32,a2
               move.l   #blockplane3,a0
               add.l    d0,a0             ; Source
               move.l   16(a3),a1         ; Dest, BitPlane3
               add.l    d2,a1
               moveq    #15,d5
dmbpl3sil      move.w   (a0)+,d6
               move.w   (a1),d7
               and.w    (a2)+,d7
               or.w     d6,d7
               move.w   d7,(a1)
               add.l    #40,a1
               dbf      d5,dmbpl3sil

               sub.l    #32,a2
               move.l   #blockplane4,a0
               add.l    d0,a0             ; Source
               move.l   20(a3),a1         ; Dest, BitPlane4
               add.l    d2,a1
               moveq    #15,d5
dmbpl4sil      move.w   (a0)+,d6
               move.w   (a1),d7
               and.w    (a2)+,d7
               or.w     d6,d7
               move.w   d7,(a1)
               add.l    #40,a1
               dbf      d5,dmbpl4sil

               sub.l    #32,a2
               move.l   #blockplane5,a0
               add.l    d0,a0             ; Source
               move.l   24(a3),a1         ; Dest, BitPlane5
               add.l    d2,a1
               moveq    #15,d5
dmbpl5sil      move.w   (a0)+,d6
               move.w   (a1),d7
               and.w    (a2)+,d7
               or.w     d6,d7
               move.w   d7,(a1)
               add.l    #40,a1
               dbf      d5,dmbpl5sil

               movem.l  (sp)+,d5-d7/a0/a3
               rts

;-------------------------------------------------------------------------------
; Värien kierrätykset (2 kpl)
; Idea: Ohjelman alussa kierrätettävät värit on kopioitu omaan taulukkoonsa.
; Kierrätysrutiinissa tästä taulukosta väriarvot kopioidaan varsinaiseen
; väritaulukkoon positioihin (k...k+4) siten, että ensimmäinen kopioitava
; väri on kopiotaulukon värinumero (järj.numero), minkä ilmoittaa
; muuttuja "cind".
;-------------------------------------------------------------------------------
ColourCycling
               moveq    #0,d0
               move.l   #colortable+32,a0    ; 16. wordin kohdalle
               move.l   #copytable,a1

; Kierrätetään värit 16..19 (1. väri on numero 0)

               moveq    #4-1,d7
               move.b   cind,d0
ccsil          move.w   (a1,d0.b),(a0)+
               addq.l   #2,d0
               cmp.l    #8,d0
               blt.s    kunnossa
               moveq    #0,d0
kunnossa       dbf      d7,ccsil

; Kierrätetään värit 20..23 (1. väri on numero 0)

               move.l   #copytable+8,a1      ; 8 = 4*2
               moveq    #4-1,d7
               move.b   cind,d0
ccsil2         move.w   (a1,d0.b),(a0)+
               addq.l   #2,d0
               cmp.l    #8,d0
               blt.s    kunnossa2
               moveq    #0,d0
kunnossa2      dbf      d7,ccsil2

; cind-muuttujan (indikaattori väritaulukkoon) muuttaminen saa aikaan
; lopulta värien kierrätyksen

               addq.b   #2,cind
               cmp.b    #8,cind
               blt.s    indok
               move.b   #0,cind

indok          move.l   viewport,a0
               lea      colortable,a1
               moveq    #32,d0
               LibCall  GFX,LoadRGB4

               rts

;------------------------------------------------------------------------------
; Piirretään kartta (13*11 blockia), A3 = osoite karttaan
;------------------------------------------------------------------------------
DrawField      movem.l  d0-d7,-(sp)

               moveq    #0,d0
               move.l   #7+41*40,d2       ; ((320-13*16)/2)/8 + 41*40
               moveq    #VISIBLE_BLOCKS_Y,d7
mapsildf       moveq    #VISIBLE_BLOCKS_X,d6
xsildf

; Lasketaan paikka, mistä piirretään (D0)

               move.w   (a3)+,d0          ; Blockin "y-koordinaatti"
               lsl.w    #5,d0             ; 4+1

; Kopioidaan blocki blockbitmapista...

               bsr      DrawBlock

               addq.l   #2,d2
               dbf      d6,xsildf
               add.l    #40*16-(13*2),d2
               dbf      d7,mapsildf       ; "ysil"

               movem.l  (sp)+,d0-d7
               rts

;------------------------------------------------------------------------------
; Piirretään 16*16 blocki
;------------------------------------------------------------------------------
DrawBlock      movem.l  d5/a0-a2,-(sp)

               move.l   DrawBitMap,a2
               move.l   #blockplane1,a0
               add.l    d0,a0             ; Source
               move.l   8(a2),a1          ; Dest, BitPlane1
               add.l    d2,a1
               moveq    #15,d5            ; 16 pixeliä
dbpl1sil       move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,dbpl1sil

               move.l   #blockplane2,a0
               add.l    d0,a0             ; Source
               move.l   12(a2),a1         ; Dest, BitPlane2
               add.l    d2,a1
               moveq    #15,d5
dbpl2sil       move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,dbpl2sil

               move.l   #blockplane3,a0
               add.l    d0,a0             ; Source
               move.l   16(a2),a1         ; Dest, BitPlane3
               add.l    d2,a1
               moveq    #15,d5
dbpl3sil       move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,dbpl3sil

               move.l   #blockplane4,a0
               add.l    d0,a0             ; Source
               move.l   20(a2),a1         ; Dest, BitPlane4
               add.l    d2,a1
               moveq    #15,d5
dbpl4sil       move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,dbpl4sil

               move.l   #blockplane5,a0
               add.l    d0,a0             ; Source
               move.l   24(a2),a1         ; Dest, BitPlane5
               add.l    d2,a1
               moveq    #15,d5
dbpl5sil       move.w   (a0)+,(a1)
               add.l    #40,a1
               dbf      d5,dbpl5sil

               movem.l  (sp)+,d5/a0-a2
               rts

;------------------------------------------------------------------------------
;
;------------------------------------------------------------------------------
MainLoppu      move.b   #0,Demoonko
mloop          tst.b    Quit
               bne      CleanUp

;               move.l   viewport,a0      ; mloop-kokonaisuus vaikuttaa
;               LibCall  GFX,WaitBOVP     ; olevan liian nopea WaitBOVP:lle
               LibCall  GFX,WaitTOF

               bsr      TextScroll                                     

               addq.b   #1,Demoonko
               cmp.b    #8,Demoonko
               blt.s    mliv
               bsr      ColourCycling
               move.b   #0,Demoonko

mliv           bsr      ikkunanviestit

               cmp.b    #1,RestartAll
               bne.s    mloop

; Restartoidaan kaikki ...

               bsr      InitGhosts
               move.b   #0,DemoDone
               move.b   #1,DemoMode
               move.b   #0,RestartAll
               move.b   #0,Demoonko
               move.l   #0,demomoveind
               move.l   #0,TextInd
               move.l   #0,CopyInd
               move.l   #4*11,pind
               move.l   #0,pind2
               move.b   #0,cind
               move.b   #0,Laskuri
               move.l   #0,frameY
               move.b   #FONTWIDTH,Laskuri
               move.l   #13,FontColor

               lea      OmaHahmo,a0
               move.l   #0,(a0)+
               move.l   #0,(a0)+
               move.l   #-48,(a0)+
               move.l   #-48,(a0)+
               move.l   #16,(a0)+
               move.l   #0,(a0)+

               jsr      _StopPlayer
               move.w   #0,_modnum
               move.l   _mymodule,a0
               jsr      _PlayModule

               bra      MainProgram


;------------------------------------------------------------------------------
; Tulostetaan alkukuva pisteittäin näkyviin.
; HUOM! Nämä FadeIn ja FadeOut-rutiinit vaativat, että kuvassa ei ole
; pohjavärinä väriä 0!
;------------------------------------------------------------------------------
FadeIn         move.l   #2860-1,d7           ; 110*24 - 1 (pisteiden määrä)
               move.b   #0,points            ; 110*26

; Aluksi arvotaan tarvittaessa 20-1 kertaa piste; jos ei saada vapaata
; pistettä, niin siirrytään sellaiseen mekaanisesti.

rsil           moveq    #20,d6
readpixel      bsr      ArvoXjaY             ; Arvotaan x- ja y-koordinaatti
               move.l   o_rastport,a1
               move.l   x,d0
               move.l   y,d1
               LibCall  GFX,ReadPixel
               cmp.l    #0,d0                ; Jos arvotussa pisteessä ei ole
               beq.s    drawpix              ; pistettä, niin tulostetaan...
               dbf      d6,readpixel

; Siirrytään mekaanisesti vapaaseen pisteeseen.
; Jos rutiinin alussa kokonaispistemäärä on laitettu liian suureksi, jäädään
; ikuiseen silmukkaan...

readpixel2     move.l   o_rastport,a1
               move.l   x,d0
               move.l   y,d1
               LibCall  GFX,ReadPixel
               cmp.l    #0,d0                ; Jos arvotussa pisteessä ei ole
               beq.s    drawpix              ; pixeliä, niin tulostetaan...
                                             
               addq.l   #1,x
               cmp.l    #110,x
               bge.s    addy
               bra      readpixel2
addy           addq.l   #1,y
               move.l   #0,x
               cmp.l    #26,y
               bge.s    zeroy
               bra      readpixel2
zeroy          move.l   #0,y
               bra      readpixel2


drawpix        move.l   Om_rastport,a1
               move.l   x,d0
               move.l   y,d1  
               LibCall  GFX,ReadPixel        ; Laittaa D0:aan värirekisterin
                                             ; järjestysnumeron

               move.l   o_rastport,a1
               LibCall  GFX,SetAPen          

               addq.b   #1,points            ; Tulostetaan 10 pistettä
               cmp.b    #10,points           ; framessa
               bne.s    nowait
               move.b   #0,points
               LibCall  GFX,WaitTOF
nowait
               move.l   x,d0
               move.l   y,d1
               move.l   o_rastport,a1
               LibCall  GFX,WritePixel

               move.w   $dff006,rnd_more     ; Satunnaisuuden lisääntymisen
                                             ; toivossa...
               dbf      d7,rsil
               rts

;------------------------------------------------------------------------------
; Hävitetään alkukuva pisteittäin
;------------------------------------------------------------------------------
FadeOut        move.l   #2640-1,d7           ; 110*24 - 1 (pisteiden määrä)
               move.b   #0,points

; Aluksi arvotaan tarvittaessa 20-1 kertaa piste; jos ei saada sopivaa
; pistettä (pisteessä oltava pixeli), niin siirrytään sellaiseen mekaanisesti

orsil          moveq    #20,d6
oreadpixel     bsr      ArvoXjaY             ; Arvotaan x- ja y-koordinaatti
               move.l   o_rastport,a1
               move.l   x,d0
               move.l   y,d1
               LibCall  GFX,ReadPixel
               cmp.l    #0,d0                ; Jos arvotussa pisteessä on
               bne.s    odrawpix             ; pixeli, niin pyyhitään se...
               dbf      d6,oreadpixel

; Siirrytään mekaanisesti sopivaan pisteeseen.
; Jos rutiinin alussa kokonaispistemäärä on laitettu liian suureksi, jäädään
; ikuiseen silmukkaan...

oreadpixel2    move.l   o_rastport,a1
               move.l   x,d0
               move.l   y,d1
               LibCall  GFX,ReadPixel
               cmp.l    #0,d0                ; Jos arvotussa pisteessä on
               bne.s    odrawpix             ; pixeli, niin pyyhitään...
                                             
               addq.l   #1,x
               cmp.l    #110,x
               bge.s    oaddy
               bra      oreadpixel2
oaddy          addq.l   #1,y
               move.l   #0,x
               cmp.l    #24,y
               bge.s    ozeroy
               bra      oreadpixel2
ozeroy         move.l   #0,y
               bra      oreadpixel2


odrawpix       move.l   o_rastport,a1
               moveq    #0,d0                ; Taustaväri piirtoväriksi
               LibCall  GFX,SetAPen          

               addq.b   #1,points            ; Tulostetaan 12 pistettä
               cmp.b    #12,points           ; framessa
               bne.s    onowait
               move.b   #0,points
               LibCall  GFX,WaitTOF
onowait
               move.l   x,d0
               move.l   y,d1
               move.l   o_rastport,a1
               LibCall  GFX,WritePixel

               move.w   $dff006,rnd_more     ; Satunnaisuuden lisääntymisen
                                             ; toivossa...
               dbf      d7,orsil
               rts

;-------------------------------------------------------------------------------
; Arvotaan x- ja y-koord. FadeIn ja FadeOut-rutiineille.
; Satunnaisluku siis väleille x in [0,109] ja y in [0,23]
; Välin yläreunaan ei näemmä tahdo saada useinkaan suoraan arvoa, mistä syystä
; tässä arvotaan luku väleille [0,110] ja [0,24] sekä tarvittaessa vähennetään
; luku 1.
;-------------------------------------------------------------------------------
ArvoXjaY       move.b   $bfe601,d0           ; Arvotaan x
               fmove.w  d0,fp0

               move.w   $dff006,d0
               move.w   rnd_more,d2
               mulu.l   d2,d0
               move.w   d0,rnd_more
               fmove.w  d0,fp1

               fmul.l   fp0,fp1
               fsin.l   fp1
               fmul.l   #110,fp1              ; Satunnaisluvut välillä 0-109
               fabs.l   fp1
               fmove.l  fp1,d0
               cmp.l    #110,d0              ; *
               bne.s    arvoy
               subq.l   #1,d0

arvoy          move.b   $bfe601,d1           ; Arvotaan y
               fmove.w  d1,fp0

               move.w   $dff006,d1
               move.w   rnd_more,d2
               mulu     d2,d1
               fmove.w  d1,fp1

               fmul.l   fp0,fp1
               fsin.l   fp1
               fmul.l   #24,fp1              ; Satunnaisluvut välillä 0-23
               fabs.l   fp1
               fmove.l  fp1,d1
               cmp.l    #24,d1
               bne.s    savexy
               subq.l   #1,d1

savexy         and.l    #$0000ffff,d0        ; Vain 16-bittinen osa
               and.l    #$0000ffff,d1        ; koordinaatteja varten jäljelle
               move.l   d0,x                 ; Talletetaan koordinaatit
               move.l   d1,y                 ; muistiosoitteisiin x ja y
               rts

;------------------------------------------------------------------------------
; RND(x)
; - Yläraja luvulle on annettu rekisterissä D4, ohjelma arpoo kuitenkin
;   luvun väliltä [0,D4+1], ja tarvittaessa vähentää tuloksesta yhden
;------------------------------------------------------------------------------

Random         movem.l  d0-d2,-(sp)
               move.l   d4,d2
               addq.l   #1,d2
               fmovecr  #0,fp0               ; Pii
               fdiv.l   #180,fp0             ; 1 aste radiaaneina
               move.b   $bfe601,d0           ; Arvotaan x
               move.w   $dff006,d1
               mulu.l   d1,d0
               fmul.l   d0,fp0
               fsin.l   fp0
               fabs.l   fp0
               fmul.l   d2,fp0
               fmove.l  fp0,d0
               cmp.l    d4,d0                ; Jos "arvottu" luku on suurempi
               ble.s    arvoOK               ; (+1) kuin annettu yläraja, niin
               subq.l   #1,d0                ; vähennetään yksi

arvoOK         move.l   d0,rnd_number
               movem.l  (sp)+,d0-d2
               rts

;-------------------------------------------------------------------------------
; Arvotaan muutamalle mörölle koordinaatit
;-------------------------------------------------------------------------------
InitGhosts     moveq    #10-1,d7
               lea      tenghosts,a0
IGSil          moveq    #MAP_WIDTH-1,d4
               bsr      Random
               move.l   rnd_number,d0
               moveq    #MAP_HEIGHT-1,d4
               bsr      Random
               move.l   rnd_number,d1

; Katsotaan onko arvotussa paikassa blocki, minkä päälle ei saa mennä

               move.l   d0,d2                ; Työkopiot x:stä
               move.l   d1,d3                ; ja y:stä
               move.l   gamefield,a2
               lsl.w    #1,d2                ; Hahmon mapX parilliseksi
               lsl.w    #1,d3                ; Hahmon mapY parilliseksi
               mulu.w   #MAP_WIDTH,d3
               add.l    d3,d2
               add.l    d2,a2
               cmp.w    #RED_TILE,(a2)
               beq.s    IGSil
               cmp.w    #COL_TILE,(a2)
               beq.s    IGSil
               cmp.w    #LOW_WATER,(a2)
               beq.s    IGSil
               cmp.w    #DEEP_WATER,(a2)
               beq.s    IGSil

               move.l   #monster_map,a1
               add.l    d2,a1
               cmp.w    #0,(a1)
               bne.s    IGSil
               move.w   #GHOST,(a1)          ; Kirjataan mörkö monster_map'iin
               
               move.l   d0,(a0)+             ; Monsterin x
               move.l   d1,(a0)+             ; Monsterin y
               move.l   #GHOST,(a0)+         ; Blockin järjestysnumero
               move.l   #GhostMask,(a0)+
               move.l   #0,(a0)+             ; Liikkuvako (0 = liikkuva)
               move.l   #1,(a0)+
               dbf      d7,IGSil

; Kirjoitetaan kuitenkin erilliset liikkumattomat hahmot monster_map'iin

               lea      Hahmot,a0
               move.l   #monster_map,a1
               move.l   (a0),d0
               move.l   4(a0),d1
               lsl.w    #1,d0                ; Hahmon mapX parilliseksi
               lsl.w    #1,d1                ; Hahmon mapY parilliseksi
               mulu.w   #MAP_WIDTH,d1
               add.l    d1,d0
               add.l    d0,a1
               move.l   8(a0),d2
               move.w   d2,(a1)              ; Kirjataan hahmon gfx-numero
                                             ; monster_map'iin

; Initioidaan "kaupungin" hahmokartta...

               lea      Ihmiset_Town,a0
itsil          lea      TownHahmoMap,a1
               cmp.l    #-1,(a0)
               beq.s    exitinit
               move.l   (a0)+,d0             ; Otetaan hahmon x-koord
               move.l   (a0)+,d1             ;         hahmon y-koord
               subq.l   #1,d0                ; HUOM!!!
               lsl.w    #1,d0
               lsl.w    #1,d1
               mulu.w   #MAP_WIDTH,d1
               add.l    d0,a1                ; Mennään hahmon koordinaatteja
               add.l    d1,a1                ; vastaavaan paikkaan
               move.l   (a0)+,d2             ;         hahmon gfx-numero
               move.l   d2,(a1)              ; Kirjataan hahmo hahmokarttaan
               add.l    #12,a0               ; Seuraavan hahmon kohdalle
               bra.s    itsil
exitinit       rts

;-------------------------------------------------------------------------------
; Integer2ASCII_32bit, '020 + FPU version. Coded by Markus Ketola 4/2000.
; Uses CPU registers D0-D3,D7 & A2 and FPU register FP0.
;
; - Converts 32 bit unsigned integer given in D0 to ASCII, destination
;   address (where the digits are stored) is given in A2
;-------------------------------------------------------------------------------
Integer2ASCII_32bit
               movem.l  d0-d7/a0-a6,-(sp)

               lea      Number,a2            ; The digits will be stored here

               cmp.l    #0,d0                ; If the number to be converted is
               beq      justzero             ; 0 we skip the actual converting
                                             ; and write directly ASCII code of
                                             ; 0. Also, LOG10(0) is not defined;
                                             ; FLOG10 FP0 would crash the
                                             ; machine if FP0 = 0.

               fmove.x  #0,fp0
               fmove.l  d0,fp0               ; Number to be converted to FP0
               moveq    #0,d2
               moveq    #0,d3
               moveq    #0,d7

; Count the amount of digits; n = trunc(LOG10(number)) + 1

               flog10.l fp0                  ; LOG10
               fmove.l  fp0,d7               ; Minus 1 for loop below
                                             ; "internally included" :)

; Convert given 32 bit unsigned integer to its ASCII version

dloop          move.l   d0,d1                ; Working copy of D0

               fmove.l  d7,fp0
               ftentox.l   fp0               ; D = 10^(k-1)
               fmove.l  fp0,d3
goon                                         
               divs.l   d3,d1                ; Number / D ; reminder
                                             ; automatically disregarded
               divsl.l  #10,d2:d1            ; Divide by 10 once more;
                                             ; reminder goes to D2, which in
                                             ; fact holds the desired digit now.
               add.b    #'0',d2              ; Add ASCII code of 0 to the digit
               move.b   d2,(a2)+             ; and save the digit as ASCII...
               dbf      d7,dloop

; The actual Integer2ASCII routine ends here

               move.b   #10,(a2)             ; Line feed
               bra      printthenumber
justzero       move.b   #'0',(a2)+
               move.b   #10,(a2)

; Print the number
printthenumber lea      Number,a0
               bsr      Print                ; Print the number...

Clear_number   lea      Number,a0
               move.l   #14-1,d7
nollaa         clr.b    (a0)+
               dbf      d7,nollaa

               movem.l  (sp)+,d0-d7/a0-a6
               rts

;------------------------------------------------------------------------------
; Clean up -hommat
;------------------------------------------------------------------------------
CleanUp        jsr      _endmusic

clean          move.l   iff,d0
               beq.s    closekehys
               move.l   d0,a1
               LibCall  IFF,_LVOCloseIFF

closekehys     move.l   iff_kehysfile,d0
               beq.s    closeblock
               move.l   d0,a1
               LibCall  IFF,_LVOCloseIFF

closeblock     move.l   iff_blockfile,d0
               beq.s    suljeGFXbase
               move.l   d0,a1
               LibCall  IFF,_LVOCloseIFF

suljeGFXbase   move.l   GFXbase,d0
               beq.s    su2
               move.l   d0,a1
               LibCall  Exec,CloseLibrary
su2
               move.l   Om_Ikkuna,d0
               beq.s    sulje_1
               move.l   d0,a0
               LibCall  Intui,CloseWindow

sulje_1        move.l   Om_Naytto,d0
               beq.s    sulje_2
               move.l   d0,a0
               LibCall  Intui,CloseScreen

sulje_2        move.l   OmistusIkkuna,d0
               beq.s    sulje_IFFlib
               move.l   d0,a0
               LibCall  Intui,CloseWindow

sulje_IFFlib   move.l   IFFbase,d0
               beq.s    Loppu
               move.l   d0,a1
               LibCaLL  Exec,CloseLibrary

Loppu          move.l   MinunIkkuna,d0
               beq.s    Loppu1
               move.l   d0,a0
               LibCall  Intui,CloseWindow  

Loppu1         move.l   MinunNaytto,d0
               beq.s    Loppu2
               move.l   d0,a0
               LibCall  Intui,CloseScreen
 
Loppu2         move.l   Intuibase,d0
               beq.s    Loppu3
               move.l   d0,a1
               LibCall  Exec,CloseLibrary

Loppu3         move.l   Dosbase,d0
               beq.s    Loppu4
               move.l   d0,a1
               LibCall  Exec,CloseLibrary

Loppu4         move.l   DiskFontbase,d0
               beq.s    Loppu5
               move.l   d0,a1
               LibCall  Exec,CloseLibrary

Loppu5         move.l   Font,d0
               beq      Pois
               move.l   d0,a1
               LibCall  GFX,CloseFont

Pois           movem.l  (sp)+,d2-d7/a2-a6
               clr.l    d0
               rts

;------------------------------------------------------------------------------
; Vakioina pysyvää kamaa code-lohkon lopussa...
;------------------------------------------------------------------------------
Pomppu         dc.l  1*40,1*40,1*40,2*40,2*40,2*40
               dc.l  2*40,2*40,2*40,1*40,1*40,1*40
               dc.l  0,0,0,0,0,-1*40,-1*40,-1*40,0,0,0,0,0,1

Pomppu2        dc.l  0,0,0,-1*40,-1*40,-1*40,-2*40,-2*40,-2*40,-2*40,-1*40,-1*40,-1*40
               dc.l  0,0,0,1*40,1*40,1*40,2*40,2*40,2*40,2*40
               dc.l  2*40,2*40,2*40,2*40,1*40,1*40,1*40,0,0,0
               dc.l  -1*40,-1*40,-1*40,-2*40,-2*40,-2*40,-2*40,-1*40,-1*40,-1*40,-1*40
               dc.l  0,0,0,1

Gamefield      incbin   "Work:MyProjects/QoL/Gamefield/Map6.gamefield"
Battle_land    incbin   "Work:MyProjects/QoL/Gamefield/Battle_land.gamefield"
Battle_wood    incbin   "Work:MyProjects/QoL/Gamefield/Battle_wood.gamefield"
Battle_mount   incbin   "Work:MyProjects/QoL/Gamefield/Battle_mount.gamefield"
Lovefield      incbin   "Work:MyProjects/QoL/Gamefield/Lovefield.gamefield"
Townfield      incbin   "Work:MyProjects/QoL/Gamefield/Town.gamefield"

blockdata      incbin   "Work:MyProjects/QoL/BPLs/blocks8vert.bin"
GhostMask      incbin   "Work:MyProjects/QoL/BPLs/GhostMask_invert.bin"
boyMask        incbin   "Work:MyProjects/QoL/BPLs/boyMask_invert.bin"
girlMask       incbin   "Work:MyProjects/QoL/BPLs/girlMask_invert.bin"

; Merkit '2','4','6','8' tarkoittavat suuntia, muut merkit aiheuttavat viivettä,
; 0 on loppumerkki, mikä lopettaa demon, ja ukkoa voi ohjata näppikseltä.
Demoliike      dc.b  'ViiveViiveViiveViiveViiveViiveViive'
               dc.b  '2','2','2','4','2','2','Vii'
               dc.b  '2','6','2','6','2','2','4','2','Vii'
               dc.b  '2','4','2','6','2','2','2','6','6','Viive'
               dc.b  '8','6','6','6','8','Viive'
               dc.b  '8','8','8','8','4','8','8','6','6','Viiv'
               dc.b  '8','6','6','8','6','6','6','8','6','6','Viive'
               dc.b  '2','4','4','2','4','4','4','Vi','2','2','2','Vii'
               dc.b  '6','6','6','6','6','6','6','6','6','6','6','V','8'
               dc.b  'ViiveViiveViiveViiveViiveViiveViiveViiveViive'  ; "Joen ranta"
               dc.b  '2','4','4','4','4','4','4','4','4','4','4','4','2','2'
               dc.b  '2','2','2','2','2','2','Vi','4','4','2','4','4','4','4'
               dc.b  '4','8','4','4'
               dc.b  '2','V','6','6','2','V','4','V','2','6','6','6','6','2'
               dc.b  '8','6','6','6','6','6','6','6','6','6','6','6','2','6'
               dc.b  '2','6','2','2','2','6','6','6','8','8','6','6','8'
               dc.b  '6','8','8','6','8','8','6','6','6','6','6'
               dc.b  '8','8','6','8','8','8','8','8','ViiveViiveViive'
               dc.b  '6','6','6','6','6','6','2','6','6','6','6','6','6','6'
               dc.b  '6','Viive','2','2','2','2','2','6','6','6'
               dc.b  '2','2','6','ViiveViive','2','4','4','4','8','8','4','4'
               dc.b  'Vi','2','V','2','V','2','V','2','V','2','6','6','2','2'
               dc.b  '6','6','2','Vii','6','V','6','ViiveV','6','6','6','6','6','6'
               dc.b  0  ; Loppumerkki
               even

ScrolliTeksti  dc.b  "   Olipa kerran yksinäinen poika. Hän oli sisäisesti "
               dc.b  "tyhjä ja vailla ystäviä. Hän harhaili päämäärättömästi "
               dc.b  "ympäri metsiä...                                         "
               dc.b  "                                                         "
               dc.b  "                                                         "
               dc.b  "                                                         "
               dc.b  "                    "
               dc.b  "Lopulta hän pysähtyi järven rannalle...                  "
               dc.b  "        Hän keksi, mitä häneltä puuttui, ja hän päätti et"
               dc.b  "siä sen...                                               "
               dc.b  "...         ...                                          "
               dc.b  " ...hän etsi...                            ...hän etsi..."
               dc.b  "                               ...                       "
               dc.b  " ...etsi...                                    ...etsi..."
               dc.b  "                                    ....................."
               dc.b  "                "
               dc.b  "...ja sitten...       Hän alkoi täyttymään miellyttävästä"
               dc.b  " lämmöstä...                                ...ja.....   "
               dc.b  "          Hän LÖYSI sen !!! "
               dc.b  "Hän löysi Rakkauden !                                    "
               dc.b  "...ja he elivät onnellisina jne...                       "
               dc.b  "                                                         "
               dc.b  0

               even


;------------------------------------------------------------------------------
; Muuttujat
;------------------------------------------------------------------------------
   section  Muuttujat,DATA

DB

OmaHahmo       dc.l  0,0,-48,-48 ; MapX,MapY, ScreenX,ScreenY
               dc.l  16          ; gfx
               dc.l  0           ; Frame-counter sädekehälle

Hahmot         dc.l  58,28       ; Hahmon x- ja y-koordinaatit kartalla
               dc.l  17          ; Järjestysnumero blockdatassa
               dc.l  MaskOfZeros ; Maski
               dc.l  -1          ; Liikkuvako (-1 = ei, 0 = kyllä)
               dc.l  1           ; Elossako (1 = elossa, 0 = ei elossa)

               dc.l  8,10        ; MapX, MapY
               dc.l  18          ; gfx
               dc.l  GhostMask   ; Maski
               dc.l  0           ; Liikkuvako
               dc.l  1           ; Elossako (1 = elossa, 0 = ei elossa)

tenghosts      ds.l  6*10        ; Varataan tilaa vielä 10:lle mörölle

               dc.l  -1          ; Hahmojen loppumerkki


Ihmiset_Town   dc.l  31,47       ; x,y
               dc.l  20          ; Miespuolinen
               dc.l  MaskOfZeros
               dc.l  -1
               dc.l  1

               dc.l  9,9         ; x,y
               dc.l  21          ; Naispuolinen
               dc.l  MaskOfZeros
               dc.l  -1
               dc.l  1

               dc.l  29,15       ; x,y
               dc.l  21
               dc.l  MaskOfZeros
               dc.l  -1
               dc.l  1

               dc.l  7,15
               dc.l  20
               dc.l  MaskOfZeros
               dc.l  -1
               dc.l  1

               dc.l  38,7
               dc.l  20
               dc.l  MaskOfZeros
               dc.l  -1
               dc.l  1

               dc.l  51,52
               dc.l  21
               dc.l  MaskOfZeros
               dc.l  -1
               dc.l  1

               dc.l  -1          ; Loppumerkki!

; Varsinaisesti näkyvä näyttö

; Screen-struktuuri
UusiNaytto     dc.w  0           ; Näytön vas. yläkulman x-koord.
               dc.w  0           ; Näytön vas. yläkulman y-koord.
               dc.w  320         ; x-koko
               dc.w  256         ; y-koko
               dc.w  5           ; Syvyys (bittitasojen määrä)
               dc.b  0           ; Otsikkopalkin väri 1       
               dc.b  1           ; Otsikkopalkin väri 2
               dc.w  0           ; Moodi (Tässä LO-RES) 
               dc.w  CUSTOMSCREEN!CUSTOMBITMAP  ; Näytön tyyppi      
               dc.l  0           ; Käytettävät fontit
               dc.l  Otsikko     ; Näytön nimen osoitin
               dc.l  0           ; Osoitin gadgetteihin
               dc.l  myBitMap1   ; Osoitin käyttäjän määrittelemään
                                 ; BitMap-structureen

; Tämä on scrolli-ikkuna varsinaisesti näkyvällä alueella, mistä ikkunasta
; lisäksi tarkkaillaan hiiren napin painalluksia.

UusiIkkuna     dc.w  0           ; Näytön vas. yläkulman x-koord.
               dc.w  0           ; Näytön vas. yläkulman y-koord.
               dc.w  320         ; x-koko
               dc.w  256         ; y-koko
               dc.b  0,1         ; Otsikkopalkkien värit
               dc.l  IDCMPf      ; IDCMP-liput
               dc.l  Liput       ; liput
               dc.l  0           ; Osoitin to 1st gadget structure
               dc.l  0           ; Osoitin valintamerkkiin
               dc.l  0           ; Osoitin ikkunan nimeen
NaytonOsoite   dc.l  0           ; Osoitin näytön Screen-structureen
               dc.l  0           ; Osoitin omaan  BitMap-structureen
               dc.w  0,0,0,0     ; Pienimmät sallitut koot
               dc.w  CUSTOMSCREEN ; Tyyppi

; Tämä ikkuna on varsinaisesti näkyvällä screenillä, mihin ikkunaan
; tulostetaan pisteittäin omistuskuva

UusiIkkuna3    dc.w  105         ; Näytön vas. yläkulman x-koord.
               dc.w  80          ; Näytön vas. yläkulman y-koord.
               dc.w  110         ; x-koko
               dc.w  50          ; y-koko
               dc.b  0,1         ; Otsikkopalkkien värit
               dc.l  0           ; IDCMP-liput
               dc.l  BORDERLESS!RMBTRAP ; Liput
               dc.l  0           ; Osoitin to 1st gadget structure
               dc.l  0           ; Osoitin valintamerkkiin
               dc.l  0           ; Osoitin ikkunan nimeen
screenaddy     dc.l  0           ; Osoitin näytön Screen-structureen
omistusbm      dc.l  0           ; Osoitin omaan  BitMap-structureen
               dc.w  0,0,0,0     ; Pienimmät sallitut koot
               dc.w  15          ; Tyyppi (tässä CUSTOM)

textattr       dc.l  FontinNimi
               dc.w  12
               dc.b  0
               dc.b  0

; Screen-struktuuri
OmistusNaytto  dc.w  0           ; Näytön vas. yläkulman x-koord.
               dc.w  0           ; Näytön vas. yläkulman y-koord.
               dc.w  320         ; x-koko
               dc.w  256         ; y-koko
               dc.w  5           ; Syvyys (bittitasojen määrä)
               dc.b  0           ; Otsikkopalkin väri 1       
               dc.b  1           ; Otsikkopalkin väri 2
               dc.w  0           ; Moodi (Tässä LO-RES) 
               dc.w  CUSTOMSCREEN ; Näytön tyyppi      
               dc.l  textattr    ; Käytettävät fontit
               dc.l  0           ; Näytön nimen osoitin
               dc.l  0           ; Gadgetit
               dc.l  0           ; Oma bitmap-struktuuri

; Tämä on scrolli-ikkuna varsinaisesti näkyvällä alueella, mistä ikkunasta
; lisäksi tarkkaillaan hiiren napin painalluksia.

UusiIkkuna4    dc.w  0           ; Näytön vas. yläkulman x-koord.
               dc.w  0           ; Näytön vas. yläkulman y-koord.
               dc.w  320         ; x-koko
               dc.w  256         ; y-koko
               dc.b  0,1         ; Otsikkopalkkien värit
               dc.l  0           ; IDCMP-liput
               dc.l  BORDERLESS!RMBTRAP ; liput
               dc.l  0           ; Osoitin to 1st gadget structure
               dc.l  0           ; Osoitin valintamerkkiin
               dc.l  0           ; Osoitin ikkunan nimeen
oms_addy       dc.l  0           ; Osoitin näytön Screen-structureen
               dc.l  0           ; Osoitin omaan  BitMap-structureen
               dc.w  0,0,0,0     ; Pienimmät sallitut koot
               dc.w  15          ; Tyyppi (tässä CUSTOM)

myBitMap1      dc.w  40,256      ; Leveys tavuina, korkeus pixeleinä
               dc.b  0,5         ; Liput, Syvyys
               dc.w  0           ; Pad
               dc.l  BitPlane1_1
               dc.l  BitPlane2_1
               dc.l  BitPlane3_1
               dc.l  BitPlane4_1
               dc.l  BitPlane5_1
               dc.l  0
               dc.l  0
               dc.l  0

myBitMap2      dc.w  40,256      ; Leveys tavuina, korkeus pixeleinä
               dc.b  0,5         ; Liput, Syvyys
               dc.w  0           ; Pad
               dc.l  BitPlane1_2
               dc.l  BitPlane2_2
               dc.l  BitPlane3_2
               dc.l  BitPlane4_2
               dc.l  BitPlane5_2
               dc.l  0
               dc.l  0
               dc.l  0

blockBitMap    dc.w  2,512       ; Leveys tavuina, korkeus pixeleinä
               dc.b  0,5         ; Liput, Syvyys
               dc.w  0           ; Pad
               dc.l  blockplane1
               dc.l  blockplane2
               dc.l  blockplane3
               dc.l  blockplane4
               dc.l  blockplane5
               dc.l  0
               dc.l  0
               dc.l  0

hahmo_map      dc.l  0
hahmot         dc.l  0
gamefield      dc.l  0
x              dc.l  0
y              dc.l  0
demomoveind    dc.l  0
iff            dc.l  0
iff_kehysfile  dc.l  0
iff_blockfile  dc.l  0
IFFbase        dc.l  0
MinunNaytto    dc.l  0
MinunIkkuna    dc.l  0
OmistusIkkuna  dc.l  0
o_rastport     dc.l  0
Om_Naytto      dc.l  0
Om_Ikkuna      dc.l  0
Om_rastport    dc.l  0
rastport       dc.l  0
viewport       dc.l  0
DrawBitMap     dc.l  0
ShowBitMap     dc.l  0
Intuibase      dc.l  0
Dosbase        dc.l  0
GFXbase        dc.l  0
DiskFontbase   dc.l  0
TextInd        dc.l  0
CopyInd        dc.l  0
FontColor      dc.l  0              ; Alustetaan ohjelmassa
Font           dc.l  0
outfile        dc.l  0
pind           dc.l  4*11
pind2          dc.l  0
frameY         dc.l  0
rnd_number     dc.l  0
rnd_more       dc.w  0
mm_delay       dc.b  0              ; Monster move delay
cind           dc.b  0              ; Värienkierrätysindikaattori
Laskuri        dc.b  0
BigBlit        dc.b  0
Demoonko       dc.b  0              ; Joka 16. frame demoon
DemoDone       dc.b  0              ; Ilmoittaa, onko demo suoritettu
points         dc.b  0
inTown         dc.b  0
Kumpi          dc.b  0
Quit           dc.b  0
DemoMode       dc.b  1
RestartAll     dc.b  0
Number         dc.b  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
               even

IFFnimi        dc.b  "iff.library",0
intuinimi      dc.b  "intuition.library",0
dosnimi        dc.b  "dos.library",0
GFXnimi        dc.b  "graphics.library",0
DiskFontnimi   dc.b  "diskfont.library",0
FontinNimi     dc.b  "diamond.font",0
Otsikko        dc.b  "",0
IkkunanNimi    dc.b  "",0
kehysfile      dc.b  "IFFs/Kehys5.iff",0
omistusfile    dc.b  "IFFs/Omistus4.iff",0
blockfile      dc.b  "IFFs/TestBlocks.iff",0
Tuloste        dc.b  0,0
Testi_txt      dc.b  "Testi",10,0
               even

   section  Puskurit,bss,chip

blockplane1    ds.b  1024
blockplane2    ds.b  1024
blockplane3    ds.b  1024
blockplane4    ds.b  1024
blockplane5    ds.b  1024
               
BitPlane1_2    ds.b  10240
BitPlane2_2    ds.b  10240
BitPlane3_2    ds.b  10240
BitPlane4_2    ds.b  10240
BitPlane5_2    ds.b  10240

BitPlane1_1    ds.b  10240
BitPlane2_1    ds.b  10240
BitPlane3_1    ds.b  10240
BitPlane4_1    ds.b  10240
BitPlane5_1    ds.b  10240

Puskuri        ds.b  40*5

MaskOfZeros    ds.b  32

   section  puskurit,bss

monster_map    ds.w  (MAP_WIDTH*MAP_HEIGHT)*2
TownHahmoMap   ds.w  (MAP_WIDTH*MAP_HEIGHT)*2

battle_monst   ds.l  (8*7)+1     ; Tämä on taistelutilanteen monstereita
                                 ; varten. Rakenne:
                                 ; LONG x
                                 ; LONG y
                                 ; LONG HitPoints
                                 ; LONG ampuva? (0 tai 1, 1 = ampuva)
                                 ; LONG GFX
                                 ; LONG Maski
                                 ; LONG Rank
                                 ;
                                 ; Yhteensä siis varataan 8 monsterille
                                 ; tilaa, lopuksi loppumerkille vielä LONG
colortable     ds.w  32
;colortable    incbin   "Work:Assembler/MJS/Rendez-vous/IFFs/colors.iff"
copytable      ds.w  8

;  section  ChipData,data,chip


              end


Here’s source code to my old experiment in Amiga game coding. The source I found, doesn’t seem to be exactly the same used in the code of the video showing below. There are more than one pieces of music in the unfinished game, but in the source there isn’t “incbin” for any Amiga music module.

The project started in 1992, when I was at high school (lukio), when I was experimenting in multiplexing Amiga’s hardware sprites. Much later I continued the project in order to see, if I could still do some Amiga coding in assembly.

The musics are not made by me, I used some nice music modules, I found from the Aminet.

There should be color stripes in the energy bar made with Copper, but for some reason the colors were lost in the emulation.

The source is a bit messy and labels and comments are partly in English and partly in Finnish.

As a reminder old Amigas have Motorola’s processors and the assembly is Motorola’s 68000 processor’s assembly code.

As you can see from the source, the ProTracker replay routine is not coded by me.

Some words about the vertical scrolling… This “game” 🙂 works on an A500 with only 512kb of CHIP memory, if my memory serves my right. The reason why this little project uses quite a lot of CHIP memory is because of the way the vertical scrolling is made: The game uses in fact three (3) screens in CHIP memory in total, two for double buffering and in addition there is one screen that only scrolls vertically. The latter is “ClearScreen”, it is used for clearing the drawing buffer from earlier bob (blitter object) movement (of course for sake of limited speed, the whole ClearScreen is not copied, but only the needed 16 x 16 pixel areas). As a reminder, the movement of sprites doesn’t need the clearing of earlier position, the sprites are drawn in a special way to the screen. Bobs (blitter objects) represent “normal” graphical objects, that require clearing of earlier position.

The smartest idea for fast (that is: takes only little raster time) vertical scrolling on an Amiga 500 I’ve ever seen, was on one book written in Finnish. In that idea if the area to be scrolled vertically is for example 320 x 256 pixels, again a lot of CHIP memory is used: For only scrolling the screen vertically 3 * (320 x 256) pixels area is used for scrolling and this area is used in a very smart manner in order to achieve vertical scrolling that takes on only few raster lines. Probably this idea also requires little extra CHIP memory for blitting new graphics to area… Over 20 years ago I implemented and tested this idea and this really is  a fast way to implement vertical scrolling on an Amiga!

The game isn’t any state of the art assembly code, just an experiment… See below:

        incdir  "ADCD_2.1:NDK/NDK_3.5/Include/include_i"

        include "exec/types.i"
        include "libraries/dosextens.i"
        include "graphics/gfxbase.i"
        include "exec/libraries.i"
        include "exec/execbase.i"
        include "Hardware/intbits.i"

;------------------------------------------------------------------------------
; Makroja
;------------------------------------------------------------------------------
WaitForBlitter  MACRO
W\@     btst    #14,$2(a5)
        bne.s   W\@
        ENDM

;------------------------------------------------------------------------------
; Vakioita
;------------------------------------------------------------------------------
Forbid         equ     -$0084
Permit         equ     -$008a
Disable        equ     -$0078
Enable         equ     -$007e
Write          equ     -$0030
Output         equ     -$003c
OpenLibrary    equ     -$0228
CloseLibrary   equ     -$019e

Execbase       equ      4

Screen_X_Size  equ     320
Screen_Y_Size  equ     256
Height_OBullet equ     8       ; Oman laakin korkeus
Frames         equ     3
OwnSpeed       equ     3       ; Oman aluksen nopeus
BSpeed         equ     4       ; Oman laakin nopeus
AmountBullets  equ     (Screen_Y_Size/(Height_OBullet*BSpeed))-1
AmountEBullets equ     10-1    ; Vihollisten laakien määrä
Dest           equ     (256+16+16)*4*32        ; Palikka sinne alapuolelle
max_bobs       equ     32
max_asteroids_on_screen equ 20

NOCHIPREV      equ 0

;------------------------------------------------------------------------------
; Startup-koodi
;------------------------------------------------------------------------------

        SECTION CODE,code

startup:
        movem.l d0/a0,-(sp)             ; Tallennetaan d0 ja a0
        move.l  4,a6                    ; SysBase
        move.l  #0,a1
        jsr     -$0126(a6)              ; Haetaan oma prosessi, FindTask()
        move.l  d0,a4
        move.l  d0,process
        tst.l   pr_CLI(a4)              ; CLI?
                                        ; tst.l $ac(a4)
        bne.s   check_aga               ; jos CLI niin check_aga
wb:
        lea     pr_MsgPort(a4),a0       ; Haetaan prosessin viestiportti
                                        ; lea $5c(a4),a0
        jsr     -$0180(a6)              ; Odotetaan viestiä, WaitPort()
        lea     pr_MsgPort(a4),a0
        jsr     -$0174(a6)              ; Haetaan viesti
                                        ; GetMsg()
        move.l  d0,wbenchmsg            ; tallennetaan ohjelman tarvetta
                                        ; varten
check_aga:                              ; Tämä toimii OCS ja ECS koneissa,
        moveq   #0,d0                   ; joten AGA-checkiä ei tarvita...
        lea     gfxname,a1              
        jsr     -$0228(a6)              ; OpenLibrary()
        move.l  d0,gfxbase
        beq.w   reply_to_wb             ; jostain syystä ei saatu avattua
        move.l  d0,a4

        moveq   #0,d0
        lea     intuiname,a1
        jsr     -$0228(a6)
        move.l  d0,intuibase
        beq     Sulje

;        move.l  4,a6
;        jsr     -$0078(a6)              ; keskeytykset pois, Disable()
        cmp.w   #39,LIB_VERSION(a4)     ; onko ChipRevBits0 määritelty
                                        ; cmp.w #39,$14(a4)
        bne.s   no_chiprev

        move.b  gb_ChipRevBits0(a4),chiprev
                                        ; move.b $ec(a4),chiprev
        bra.s   check_proc
no_chiprev:
        move.b  #NOCHIPREV,chiprev      ; Ei pystyta hakemaan ChipRevBits:ia
check_proc:
        move.w  AttnFlags(a6),processor ; CPU ja FPU
                                        ; move.w $128(a6),processor
clear_view:
        move.l  gfxbase,a6
        move.l  gb_ActiView(a6),oldview ; nykyinen View talteen
                                        ; move.l $22(a6),oldview
        move.l  #0,a1                   ; NULL View tilalle
        jsr     -$00de(a6)              ; LoadView()
        jsr     -$010e(a6)     
        jsr     -$010e(a6)              ; WaitTOF()

        move.l  4,a6                    ; SysBase valmiiksi
        movem.l (sp)+,d0/a0             ; d0/a0 pois pinosta
        bsr.s   _start                  ; hypätään pääohjelmaan
        move.l  d0,-(sp)                ; palautuskoodi turvaan
old_view:
        move.l  gfxbase,a0
        move.l  $26(a0),$dff080         ; Copperlistan palautus

        move.l  gfxbase,a6
        move.l  oldview,a1              ; vanha View
        jsr     -$00de(a6)              ; LoadView()
;        move.l  4,a6
;        jsr     -$007e(a6)              ; keskeytykset päälle, Enable() 
        move.l  intuibase,a6
        jsr     -$0186(a6)              ; RethinkDisplay()

        move.l  4,a6
        move.l  intuibase,a1
        jsr     -$019e(a6)              ; CloseLibrary()

Sulje   move.l  4,a6
        move.l  gfxbase,a1              ; suljetaan graphics.library
        jsr     -$019e(a6)              ; CloseLibrary()

        reply_to_wb:
        tst.l   wbenchmsg               ; onko workbench
        beq.s   exit                    ; jos ei niin exit
        jsr     -$0084(a6)              ; huomaa ettei tarvitse Permit()
                                        ; Forbid()
        move.l  wbenchmsg,a1
        jsr     -$017a(a6)              ; ReplyMsg()
exit:
        move.l  (sp)+,d0
        rts                             ; poistutaan ohjelmasta


_start

;------------------------------------------------------------------------------
; Itse ohjelma!
;------------------------------------------------------------------------------

        movem.l d2-d7/a2-a6,-(sp)

;         move.l  4,a6
;        lea     dosname,a1
;        moveq   #0,d0
;        jsr         OpenLibrary(a6)
;        move.l  d0,dosbase

;         move.l  dosbase,a6
;        jsr     Output(a6)           ; For printing...
;        move.l  d0,outfile           ;

        move.l  4,a6
        jsr     Forbid(a6)

        move.l  4,a6
        move.l  #((256+16)*2+16)*32*4,d0
        move.l  #65538,d1
        jsr     -$00c6(a6)
        move.l  d0,ClearScreen
        beq     Pois

        move.l  #((256+16)*2+16)*32*4,d0
        move.l  #65538,d1
        jsr     -$00c6(a6)
        move.l  d0,BitMap1
        beq     Vap1

        move.l  #((256+16)*2+16)*32*4,d0
        move.l  #65538,d1
        jsr     -$00c6(a6)
        move.l  d0,BitMap2
        beq     Vap2

        move.l  #32768,d0                       ; 256 x 256 pixeliä
        move.l  #65538,d1
        jsr     -$00c6(a6)
        move.l  d0,bitmap
        beq     Vap3
 
        lea     Gamefield,a6                ; Lisätään blockien osoite valmiiksi
        lea     Coolfield,a4
        move.l  #5120-1,d7        
GBSil:  move.l  #Blocks,a1
        moveq   #0,d0
        move.w  (a6)+,d0
        lsl.l   #1,d0
;       add.l   d0,d0
        add.l   d0,a1
        move.l  a1,(a4)+
        dbf     d7,GBSil

        lea      Gamefield2,a6
        lea      Coolfield2,a4
        move.l   #5120-1,d7
GBSil2  move.l  #Blocks,a1
        moveq   #0,d0
        move.w  (a6)+,d0
        lsl.l   #1,d0
        add.l   d0,a1
        move.l  a1,(a4)+
        dbf      d7,GBSil2

        lea     Gamefield3,a6
        lea     Coolfield3,a4
        move.l  #5120-1,d7
GBSil3  move.l  #Blocks,a1
        moveq   #0,d0
        move.w  (a6)+,d0
        lsl.l   #1,d0
        add.l    d0,a1
        move.l  a1,(a4)+
        dbf     d7,GBSil3

      ;  move.l  4,a6
     ;   move.l  #0,d0
    ;    lea     gfxname,a1
   ;     jsr     -$228(a6)
  ;      move.l  d0,gfxbase
 ;       cmp.l   #0,d0
;        beq     CleanUp

;           bsr     mt_init
;           st          mt_Enable

;           move.l  #INTB_VERTB,d0
;           move.l  #Vert_str,a1    ; VBI -keskeytysstrukture
;           move.l  4,a6
;           jsr     -$00a8(a6)      ; AddIntServer

        move.l      #Laakit,LaakiPT

        move.l      #$dff000,a5
        move.l      #CopperLista,$080(a5)
        tst.w       $088(a5)

        move.w      #$87f0,$096(a5)
;       move.w  #$0400,$096(a5)
;       move.w  #$0020,$096(a5)
        move.l   #$ffffffff,$044(a5)
;         move.l  #$0,$044(a5)
        move.w  #$cce,$01a2(a5)
        move.w  #$789,$01a4(a5)
        move.w  #$446,$01a6(a5)
;         move.w  #$0fff,$01aa(a5)
;           move.w  #0,$106(a5) ; Spritet lo-res -tilaan (ECS default)
        and.w      #%1111111100111111,$106(a5)

        bsr     AlkuRoskat


JumpToAlkuScreen

        bra     AlkuScreen

JumpToAlustus

        bsr      Alustus                ; Nollataan "muuttujat"

        bsr     FillTheScreen
        bsr     SwapScreens

MainProgram
          cmp.b   #1,gameOver
          beq     GameOver

          cmp.b  #4,level
          beq    LoppuScreen

          bsr     SwapScreens
          bsr     Show
          bsr     Scroll
          bsr     ClearScore
          bsr     HandlePlayer
          bsr     Joystick
          bsr     PalautaExpTausta
          bsr     ReadAttackWaves
          bsr     CheckUnits
          bsr     CheckCoordBobs    ; Tsekataan koordinaattivalmiit enemyt
          bsr     CheckAsteroids
          bsr     CheckMonster
          bsr     HandleExplosions
          bsr     BlitScore
;           move.w  #$0f0,$180(a5)
          bsr     BlitNumbers
;           move.w  #$000f,$180(a5)
          bsr        HandleEnergySprite

          move.w  #$000,$180(a5)
          bsr     WaitForBeam
;         move.w  #$333,$180(a5)
;         move.w  #$779,$1a4(a5)

          bsr     RMB

          btst    #6,$bfe001
          bne.s   MainProgram

CleanUp     
            ;move.l  4,a6
        ;move.l  #0,d0
;        lea     gfxnimi,a1
;        jsr     -$228(a6)
;        move.l  d0,gfxbase
;        move.l  #0,d0
;        lea     intuinimi,a1
;        jsr     -$228(a6)
;        move.l  d0,intuibase
;        move.l  gfxbase,a0       
;        move.l  $26(a0),$dff080 
;        move.l  intuibase,a6      
;        jsr     -$186(a6)        
;        move.l  4,a6
;        move.l  intuibase,a1
;        jsr     -$19e(a6)
;        move.l  gfxbase,a1
;        jsr     -$19e(a6)

;         move.l  4,a6
;         move.l  dosbase,d0
;         beq.s   Vap3
;         move.l  d0,a1
;         jsr     CloseLibrary(a6)

;           bsr     mt_end

;           move.l  #INTB_VERTB,d0
;           lea     Vert_str,a1
;           move.l  4,a6
;           jsr     -$00ae(a6)          ; RemIntServer

          move.l  4,a6
          move.l  #32768,d0
          move.l  bitmap,a1
          jsr     -$00d2(a6)

Vap3:     move.l  4,a6
          move.l  #((256+16)*2+16)*32*4,d0
          move.l  BitMap2,a1
          jsr     -$00d2(a6)
Vap2:     move.l  4,a6
          move.l  #((256+16)*2+16)*32*4,d0
          move.l  BitMap1,a1
          jsr     -$00d2(a6)
Vap1:     move.l  4,a6
          move.l  #((256+16)*2+16)*32*4,d0
          move.l  ClearScreen,a1
          jsr     -$00d2(a6)

Pois      move.l  4,a6
          jsr     Permit(a6)
          movem.l (sp)+,d2-d7/a2-a6
          moveq   #0,d0
          rts

CheckUnits
          bsr       HandleUnit
          rts


CheckAsteroids
          cmp.b   #1,AsteroidsRunning
          bne.s   ExitCA

          cmp.b   #1,LastAsteroidFrames
          beq.s   LastFrames

          cmp.w   #0,Nr_of_asteroids
          ble.s   IsThereOnScreen
          bra.s   Mene
IsThereOnScreen
          cmp.b   #0,Asteroids_on_screen
          bne.s   Mene
          move.b  #1,LastAsteroidFrames
          rts  

Mene      bsr     PalautaAsteroidienTausta
          bsr     PutAsteroid
          bsr     MoveAsteroids
          bsr     AsteroidCollisions

ExitCA    rts
LastFrames
          bsr     PalautaAsteroidienTausta
          subq.b  #1,LastAsteroidFrames
Okay      move.b  #0,AsteroidsRunning
          rts


;-----------------------------------------------------------------------------
; Käsitellään unit. Pointteri tietueeseen annetaan A1:ssä.
;-----------------------------------------------------------------------------
HandleUnit
           bsr      PalautaUnitinTausta
           bsr      PalautaUnitBulletinTausta
           move.l   UnitsVanhaSij,a6
           lea      Units,a1
           moveq        #5-1,d7

           WaitForBlitter
           move.w   #0000,$062(a5)  ; BLTBMOD
           move.w   #0028,$060(a5)  ; BLTCMOD 
           move.w   #0000,$064(a5)  ; BLTAMOD
           move.w   #0028,$066(a5)  ; BLTDMOD

HUSil      cmp.w    #0,(a1)         ; Onko liikkeellä?
           beq.s    NextUnit
           move.l   2(a1),d0        ; X
           move.l   6(a1),d1        ; Y
           move.l   28(a1),a2       ; Bob-data
           move.l   32(a1),a3       ; Mask-data

           bsr      BlitBob

           cmp.w    #1,46(a1)
           beq.s    liikutetaan
           cmp.w    #0,6(a1)
           bge.s    NextUnit
           addq.l    #1,6(a1)
           bra.s    NextUnit

liikutetaan
           addq.l   #1,6(a1)
           cmp.l    #256,6(a1)
           bge.s    RemoveUnit  
NextUnit
           add.l    #48,a1
           add.l    #10,a6
           dbf      d7,HUSil

           bra.s    HandleUnitBullet

RemoveUnit
           move.w   #0,(a1)
           add.l    #48,a1
           add.l    #10,a6
           dbf      d7,HUSil

; Käsitellään unitin laaki

HandleUnitBullet
            moveq   #5-1,d7
            move.l  UnitsVBSij,a6

            lea     Units,a1
HUBSil      cmp.w   #1,10(a1)
            beq.s   BlitAndMoveUnitBullet

; Jos ei ole liikkeellä, niin katsotaan, onko unit kehissä; jos on, niin
; laitetaan laaki liikkeelle ehkä.

            cmp.l   #ExplodedUnit,28(a1)
            beq.s   Eilaakia
            cmp.w   #1,(a1)                 ; Onko unit kehissä?
            beq.s   Ampuukho
Eilaakia    add.l   #48,a1
            add.l   #10,a6
            dbf     d7,HUBSil

            bra.s   HandleUnitCollisions

Ampuukho
            move.w  $6(a5),d0               ; Jos ei ollut, niin arvotaan,
            add.w   Random,d0              ; laitetaanko liikkeelle
            and.l   #7,d0
            cmp.w   #7,d0
            beq.s   Ampuu

            add.l   #48,a1
            add.l   #10,a6
            dbf     d7,HUBSil

            bra.s       HandleUnitCollisions
         
Ampuu       move.l      2(a1),d0                ; Asetetaan laakille alkukoordinaatit
            move.l      6(a1),d1
            addq.l      #7,d0
            add.l       #16,d1
            lsl.l       #7,d0
            lsl.l       #7,d1
            move.l      d0,12(a1)               ; Talletetaan
            move.l      d1,16(a1)

            lsr.l       #7,d0
            lsr.l       #7,d1

            moveq       #0,d2                   ; Tähdätyt laukauset uniteille
            moveq       #0,d3
            move.w      x,d2
            move.w      y,d3

            sub.l       d0,d2
            sub.l       d1,d3

            lsl.l       #7,d2                   ; "desimaaliluvuksi"
            lsl.l       #7,d3
            lsr.l       #6,d2
            lsr.l       #6,d3
            move.l      d2,20(a1)               ; AddX
            move.l      d3,24(a1)               ; AddY

            move.w      #1,10(a1)              ; Laaki liikkeellä -merkki

            add.l       #48,a1
            add.l       #10,a6 
            dbf         d7,HUBSil
            rts

            bra.s       HandleUnitCollisions

BlitAndMoveUnitBullet
            move.l      12(a1),d0       ; x
            move.l      16(a1),d1       ; y
            lsr.l       #7,d0               ; Kokonaisluvuksi
            lsr.l       #7,d1
            bsr         BlitBullet

            move.l      20(a1),d2       ; AddX
            move.l      24(a1),d3       ; AddY
            add.l       d2,12(a1)       ; Liikutetaan laakia
            add.l       d3,16(a1)

            move.l      12(a1),d0
            move.l      16(a1),d1
            lsr.l       #7,d0
            lsr.l       #7,d1

            cmp.w       #255-4,d0
            bgt.s       RemoveUnitBullet
            cmp.w       #4,d0
            ble.s       RemoveUnitBullet

            cmp.w       #256,d1
            bge.s       RemoveUnitBullet
            cmp.w       #4,d1
            ble.s       RemoveUnitBullet

            add.l       #48,a1
            add.l       #10,a6
            dbf         d7,HUBSil
            rts

            bra.s       HandleUnitCollisions

RemoveUnitBullet
            move.w      #0,10(a1)

            add.l       #48,a1
            add.l       #10,a6
            dbf         d7,HUBSil
            rts

; Käsitellään unittien törmäykset

HandleUnitCollisions
            lea         Units,a1
            moveq       #5-1,d6

HUCSil      cmp.w       #1,(a1)         ; Unit kehissä?
            beq.s       Proceed
            cmp.w       #1,10(a1)       ; Laaki kehissä?
            beq.s       Proceed

            add.l       #48,a1
            dbf         d6,HUCSil
            rts

Proceed
            move.l      2(a1),d0
            move.l      6(a1),d1
            move.l      12(a1),d4
            move.l      16(a1),d5
            asr.l       #7,d4
            asr.l       #7,d5
            bsr         UnitCollisions

            add.l       #48,a1
            dbf         d6,HUCSil
            rts
                
;-----------------------------------------------------------------------------
; Unit törmäykset
; Idea: Verrataan pelaajan koordinaatteja unitiin ja sen bullettiin
;-----------------------------------------------------------------------------
UnitCollisions

; Vihollisien x,y on D0,D1:ssä

; Player to enemies

;         cmp.l   #ExplodedUnit,28(a1)      ; Jos unit on ammuttu, niin
;        beq.s   NoCollisionToEnemy         ; törmäystä ei tsekata

;         moveq   #0,d2
;         moveq   #0,d3
;         move.w  x,d2
;         move.w  y,d3
; x-test
;         sub.w  d0,d2
;         cmp.w  #-15,d2
;         blt.s  NoCollisionToEnemy
;        cmp.w   #15,d2
;         bge.s  NoCollisionToEnemy
; y-test
;         sub.w   d1,d3
;         cmp.w   #-15,d3
;         blt.s   NoCollisionToEnemy
;         cmp.w   #15,d3
;         bge.s   NoCollisionToEnemy          
;         move.w     #$0f00,$01a4(a5)

NoCollisionToEnemy

; Player bullets to enemies
          cmp.l   #ExplodedUnit,28(a1)
          beq.s   PlayerToUnitBullet

          lea     Laakit,a0
          move.w  #AmountBullets,d7
OnkoLaakiLiikkeella
          cmp.w   #0,(a0)
          bne.s   LaakiLiikkeellä
          addq.l  #6,a0
          dbf     d7,OnkoLaakiLiikkeella
          bra.s   PlayerToUnitBullet    
LaakiLiikkeellä
          move.l  d0,d2
          move.l  d1,d3
          sub.w   2(a0),d2
          cmp.w   #-16,d2
          blt.s   NextBullet
          cmp.w   #4,d2
          bge.s   NextBullet
          sub.w   4(a0),d3
          cmp.w   #16,d3
          bge.s   NextBullet
          cmp.w   #-16,d3
          blt.s   NextBullet

          move.l  #ExplodedUnit,28(a1)
          move.l  #ExplodedUnitM,32(a1)
          move.w  #0,(a0)                   ; Laaki pois kehistä
;        subq.b  #1,OwnBulletsOnScreen

          addq.w  #5,Pisteet                ; Jos osuttu niin listään pelaajan
                                                ; pisteitä
          move.l  Exp_PT,a4             ; Piirretään räjähdys
          move.w  #1,(a4)
          move.w  d0,2(a4)
          move.w  d1,4(a4)
          move.w  #4,6(a4)
          add.l   #12,a4
          cmp.w   #-1,(a4)
          bne.s   Jatkuu
          move.l  #Explosions,Exp_PT
          bra.s   NextBullet
Jatkuu    move.l  a4,Exp_PT

NextBullet
          addq.l  #6,a0
          dbf       d7,OnkoLaakiLiikkeella

; Vihollisen laakin x,y on d4,d5
PlayerToUnitBullet
          moveq   #0,d2
          moveq   #0,d3
          move.w  x,d2
          move.w  y,d3
          sub.w   d2,d4
          cmp.w   #-3,d4
          blt.s   ExitUnitCollisions
          cmp.w   #14,d4
          bge.s   ExitUnitCollisions
          sub.w   d3,d5
          cmp.w   #-3,d5
          ble.s   ExitUnitCollisions
          cmp.w   #14,d5
          bge.s   ExitUnitCollisions
          move.w  #$0ff0,$01a4(a5)
;           move.b  #1,gameOver
          subq.b  #1,energia

ExitUnitCollisions
          rts

          
;-----------------------------------------------------------------------------
; Palautetaan unitin alta tausta
;-----------------------------------------------------------------------------
PalautaUnitinTausta
            move.l  UnitsVanhaSij,a6
            moveq   #5-1,d7

PalUniTau
            cmp.l   #0,(a6)
            beq.s   NextYksi

            WaitForBlitter
            move.w  #$9f0,$040(a5)  ; BLTCON0
            move.w  #$0000,$042(a5) ; BLTCON1
            move.w  #0028,$064(a5)  ; BLTAMOD
            move.w  #0028,$066(a5)  ; BLTDMOD
            move.l  (a6),$050(a5)   ; BLTAPTR
            move.l  4(a6),$054(a5)  ; BLTDPTR kohde
            move.w  8(a6),$058(a5)  ; BLTSIZE
            move.l  #0,(a6)
NextYksi    add.l   #10,a6
            dbf     d7,PalUniTau
            rts

PalautaUnitBulletinTausta:
            move.l  UnitsVBSij,a6
            moveq   #5-1,d7

PalUniBul
            cmp.l   #0,(a6)
            beq.s   NextUnitBullet

            WaitForBlitter
            move.w  #$9f0,$040(a5)  ; BLTCON0
            move.w  #$0000,$042(a5) ; BLTCON1
            move.w  #0028,$064(a5)  ; BLTAMOD
            move.w  #0028,$066(a5)  ; BLTDMOD
            move.l  (a6),$050(a5)   ; BLTAPTR
            move.l  4(a6),$054(a5)  ; BLTDPTR kohde
            move.w  8(a6),$058(a5)  ; BLTSIZE
            move.l  #0,(a6)
NextUnitBullet
            add.l   #10,a6
            dbf     d7,PalUniBul
            rts

;-----------------------------------------------------------------------------
; Blitataan unit-bob
;-----------------------------------------------------------------------------
BlitBob
        move.w  #4098,d6        ; BLTSIZE

        asl.l   #2,d1           ; Kerrotaan y-koord. 4:llä
        cmp.l   #256*4,d1
        bge.s   ExitBlitBob
        cmp.l   #-16*4,d1       ; -(Bobin korkeus)
        ble.s   ExitBlitBob

;        move.l  28(a1),a2
;        move.l  32(a1),a3
        cmp.l   #(255-16)*4,d1  ; Alalaita
        ble.s   NxtTest
        move.l  #256*4,d6       ; Screenin lainien määrä (eli korkeus)
        sub.l   d1,d6           ; Kuinka monta pixelia näkyvissä
        lsl.l   #6,d6           ; Lasketaan BLTSIZE
        addq.l  #2,d6           ; X lisätään suoraan tässä versiossa..  
        bra.s   Ready
NxtTest
        cmp.l   #0,d1           ; Ylälaita (käsitellään negatiiviset
        bge.s   Ready             ; koordinaatit)
        moveq    #0,d6
        move.l  #16*4,d6        ; Bobin korkeus (siis y-pituus)
        add.l   d1,d6           ; Nyt d6:ssa bobin korkeus!
        lsl.l   #6,d6           ; Lasketaan BLTSIZE
        add.l   #2,d6           ; X lisätään suoraan tässä versiossa..  
        neg.l   d1              ; Lasketaan kohta, mistä bobbi-dataa
        lsl.l   #2,d1           ; aletaan blittaamaan
        add.l   d1,a2
        add.l   d1,a3
        moveq   #0,d1           ; Y-koordinaatti on tietysti nolla..
;------------------------------------------------------------------------------
;-- Lasketaan osoite
;------------------------------------------------------------------------------
Ready
        lsl.l   #5,d1
        move.b  d0,d2
        lsr.l   #3,d0
        add.l   d1,d0
        ext.l   d0
        add.l   ScrollOffset,d0 ; ScrollOffset
        and.l   #$000f,d2
        mulu    #$1000,d2
        move.l  DrawScreen,a4
        add.l   d0,a4
        move.l  ClearScreen,a0
        add.l   d0,a0   

        move.l  a0,(a6)         ; Vastaava paikka ClearScreenissä
        move.l  a4,4(a6)        ; Vanha Sijainti
        move.w  d6,8(a6)        ; Talletetaan BLTSIZE

;        WaitForBlitter
;        move.w  #0000,$062(a5)  ; BLTBMOD
;        move.w  #0028,$060(a5)  ; BLTCMOD 
;        move.w  #0000,$064(a5)  ; BLTAMOD
;        move.w  #0028,$066(a5)  ; BLTDMOD

        move.w  d2,$042(a5)     ; BLTCON1
        or.w   #$0fce,d2       ; ynnätään minterm+use shift valueen
        move.w  d2,$040(a5)     ; BLTCON0
        move.l  a4,$048(a5)     ; BLTCPTR kohde
        move.l  a2,$04c(a5)     ; BLTBPTR bob-data
        move.l  a3,$050(a5)     ; BLTAPTR mask
        move.l  a4,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE
ExitBlitBob
        rts

BlitBullet
        move.w  #1026,d6        ; BLTSIZE

        asl.l   #2,d1             ; Kerrotaan y-koord. 4:llä
        cmp.l   #256*4,d1
        bge.s   ExitBlitBullet
        cmp.l   #-4*4,d1       ; -(Bobin korkeus)
        ble.s   ExitBlitBullet

        move.l  #EnBulletBob,a2
        move.l  #EnBulletMask,a3
        cmp.l   #(255-4)*4,d1  ; Alalaita
        ble.s   NxTest
        move.l  #256*4,d6       ; Screenin lainien määrä (eli korkeus)
        sub.l   d1,d6           ; Kuinka monta pixelia näkyvissä
        lsl.l   #6,d6           ; Lasketaan BLTSIZE
        addq.l  #2,d6           ; X lisätään suoraan tässä versiossa..  
        bra.s   Ready
NxTest
        cmp.l   #0,d1           ; Ylälaita (käsitellään negatiiviset
        bge.s   Readyjoo              ; koordinaatit)
        moveq   #0,d6
        move.l  #4*4,d6        ; Bobin korkeus (siis y-pituus)
        add.l   d1,d6           ; Nyt d6:ssa bobin korkeus!
        lsl.l   #6,d6           ; Lasketaan BLTSIZE
        add.l   #2,d6           ; X lisätään suoraan tässä versiossa..  
        neg.l   d1              ; Lasketaan kohta, mistä bobbi-dataa
        lsl.l   #2,d1           ; aletaan blittaamaan
        add.l   d1,a2
        add.l   d1,a3
        moveq   #0,d1           ; Y-koordinaatti on tietysti nolla..
;------------------------------------------------------------------------------
;-- Lasketaan osoite
;------------------------------------------------------------------------------
Readyjoo
        lsl.l   #5,d1
        move.b  d0,d2
        lsr.l   #3,d0
        add.l   d1,d0
        ext.l   d0
        add.l   ScrollOffset,d0 ; ScrollOffset
        and.l   #$000f,d2
        mulu    #$1000,d2
        move.l  DrawScreen,a4
        add.l   d0,a4
        move.l  ClearScreen,a0
        add.l   d0,a0   

        move.l  a0,(a6)         ; Vastaava paikka ClearScreenissä
        move.l  a4,4(a6)        ; Vanha Sijainti
        move.w  d6,8(a6)        ; Talletetaan BLTSIZE

        WaitForBlitter
        move.w  #0000,$062(a5)  ; BLTBMOD
        move.w  #0028,$060(a5)  ; BLTCMOD 
        move.w  #0000,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD

        move.w  d2,$042(a5)     ; BLTCON1
        or.w    #$0fce,d2       ; ynnätään minterm+use shift valueen
        move.w  d2,$040(a5)     ; BLTCON0
        move.l  a4,$048(a5)     ; BLTCPTR kohde
        move.l  a2,$04c(a5)     ; BLTBPTR bob-data
        move.l  a3,$050(a5)     ; BLTAPTR mask
        move.l  a4,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE
ExitBlitBullet
        rts

;------------------------------------------------------------------------------
;
;------------------------------------------------------------------------------
ReadAttackWaves
          move.l  pt_toCoolF,d0

          moveq   #0,d1
          move.b  level,d1
          cmp.b   #2,d1
          beq     Level2

          cmp.b   #3,d1
          beq     Level3

; LEVEL 1

          cmp.l  #1280,d0
          beq.s  Kla
;         beq.s LM  ; HUOM!

          cmp.l   #2904,d0
          beq.s   Yep

          cmp.l   #6400,d0
          beq.s   AsteroiditKehiin

          cmp.l   #13480,d0
          beq.s   LM

          rts

Level2
          cmp.l  #1216,d0
          beq.s  putunits

          cmp.l  #2904,d0
          beq.s  putships

          cmp.l  #6400,d0
          beq.s  AsteroiditKehiin

          cmp.l #13408,d0
          beq.s  PutLoppuUnits

          cmp.l  #13440,d0
          beq    LM

          rts

Level3
          cmp.l  #320,d0
          beq.s  l3_aw1

          cmp.l  #6400,d0
          beq.s  AsteroiditKehiin

          cmp.l  #13480,d0
          beq    LM

          rts

; 3. hyökkäysaalto

Yep       move.b  #1,CoordBobsRunning

          move.l  #Coords1,Coords

          move.l  #RengasBob,a3
          move.l  #RengasMask,a4
          move.b  #16,nr_of_bobs
          lea     PTRsAndONOFF,a0
          moveq   #0,d7
          move.b  nr_of_bobs,d7
          subq.l     #1,d7
          moveq   #0,d0
DefSil    move.l  d0,(a0)+        ; Pointteri koordinaatteihin
          move.w  #1,(a0)+        ; "Enemy kehissä" -merkki
          move.w  #1,(a0)+        ; Kestävyys
          move.l  a3,(a0)+        ; Bob-data
          move.l  a4,(a0)+       ; Maski

          add.l   #32,d0          ; 
          dbf     d7,DefSil
          move.b  nr_of_bobs,AmEnemies
          rts


; 2. Hyökkäysaalto

Kla     
            lea     Units,a1
            move.w  #1,(a1)
            move.l  #96,2(a1)
            move.l  #-16,6(a1)

            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #1,46(a1)

            add.l   #48,a1

            move.w  #1,(a1)
            move.l  #112,2(a1)
            move.l  #-16,6(a1)

            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #1,46(a1)

            add.l   #48,a1

            move.w  #1,(a1)
            move.l  #128,2(a1)
            move.l  #-16,6(a1)

            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #1,46(a1)

            add.l   #48,a1

            move.w  #1,(a1)
            move.l  #144,2(a1)
            move.l  #-16,6(a1)

            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #1,46(a1)

            rts

; 3. Hyökkäysaalto

;Yea      move.b  #1,CoordBobsRunning
;
;        move.l  #Coords2,Coords
;
;         move.l     #UfoBob,a1
;         move.l     #UfoMask,a4
;         move.b  #16,nr_of_bobs
;       lea     PTRsAndONOFF,a0
;         moveq   #0,d7
;        move.b  nr_of_bobs,d7
;         subq.l  #1,d7
;         moveq   #0,d0
;DSil    move.l  d0,(a0)+               ; Pointteri koordinaatteihin
;         move.w  #1,(a0)+              ; Kehissä
;         move.w  #3,(a0)+              ; Kestävyys
;         move.l  a1,(a0)+              ; Bob-data
;       move.l  a4,(a0)+                ; Mask-data
;        add.l   #32,d0
;        dbf     d7,DSil
;        move.b  nr_of_bobs,AmEnemies

;         rts

; 4. Hyökkäysaalto

AsteroiditKehiin
        move.b  #1,AsteroidsRunning
        move.w  #164,Nr_of_asteroids
        rts

LM      move.b  #1,MonsterKehissa
        rts

; Level 2

PutLoppuUnits
            lea     Units,a1
            move.w  #1,(a1)
            move.l  #112,2(a1)
            move.l  #-16,6(a1)
            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #0,46(a1)

            add.l   #48,a1

            move.w  #1,(a1)
            move.l  #128,2(a1)
            move.l  #-16,6(a1)
            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #0,46(a1)

            rts

putunits
            lea     Units,a1
            move.w  #1,(a1)
            move.l  #112,2(a1)
            move.l  #-16,6(a1)
            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #1,46(a1)

            add.l   #48,a1

            move.w  #1,(a1)
            move.l  #128,2(a1)
            move.l  #-16,6(a1)
            move.l  #Unit,28(a1)
            move.l  #UnitMask,32(a1)
            move.l  #ExplodedUnit,36(a1)
            move.l  #ExplodedUnitM,40(a1)
            move.w  #1,46(a1)
            rts

putships
            move.b  #1,CoordBobsRunning

            move.l  #Coords2,Coords

            move.l  #ShipBob,a3
            move.l  #ShipMask,a4
            move.b  #16,nr_of_bobs
            lea     PTRsAndONOFF,a0
            moveq   #0,d7
            move.b  nr_of_bobs,d7
            subq.l  #1,d7
            moveq   #0,d0
initSil     move.l  d0,(a0)+          ; Pointteri koordinaatteihin
            move.w  #1,(a0)+        ; "Enemy kehissä" -merkki
            move.w  #3,(a0)+          ; Kestävyys
            move.l  a3,(a0)+          ; Bob-data
            move.l  a4,(a0)+         ; Maski

            add.l   #32,d0          ; 
            dbf     d7,initSil
            move.b  nr_of_bobs,AmEnemies
            rts

l3_aw1
            move.b  #1,CoordBobsRunning

            move.l  #Coords3,Coords

            move.l  #WBob,a3
            move.l  #WMask,a4
            move.b  #16,nr_of_bobs
            lea     PTRsAndONOFF,a0
            moveq   #0,d7
            move.b  nr_of_bobs,d7
            subq.l   #1,d7
            moveq   #0,d0
init_l3_aw1
            move.l  d0,(a0)+          ; Pointteri koordinaatteihin
            move.w  #1,(a0)+        ; "Enemy kehissä" -merkki
            move.w  #3,(a0)+          ; Kestävyys
            move.l  a3,(a0)+          ; Bob-data
            move.l  a4,(a0)+         ; Maski

            add.l   #32,d0          ; 
            dbf     d7,init_l3_aw1
            move.b  nr_of_bobs,AmEnemies
            rts

;------------------------------------------------------------------------------
; Katsotaan pitääkö koordinaativalmiita bobbjea liikuttaa
;------------------------------------------------------------------------------
CheckCoordBobs
          cmp.b  #1,CoordBobsRunning
          beq.s  Yes
          rts
Yes       cmp.b  #0,AmEnemies
          beq.s  Ye
          bra.s  CCBR
Ye        cmp.b  #0,MovingEBullets
          beq.s  Chess
          
CCBR      bsr    PalautetaanTaustat
          bsr    HandleBob
          bsr    HandleEBullets
          bsr    Collisions
ExitCheck
          rts
Chess     cmp.b   #1,DoLastCoordBobFrames
          beq.s   Yeah
          move.b  #1,DoLastCoordBobFrames
          move.b  #1,LastCBFrames
Yeah      bsr     PalautetaanTaustat
          subq.b  #1,LastCBFrames
          cmp.b   #0,LastCBFrames
          beq.s   OliNolla
          rts
OliNolla
          move.b  #0,LastCBFrames
          move.b  #0,CoordBobsRunning
          move.b  #0,DoLastCoordBobFrames
          rts

;------------------------------------------------------------------------------
Collisions
; 1° Ovatko pelaajan laakit osuneet vihollisiin?
; Periaate: Otetaan laaki 1. Verrataan sitä kaikkiin enemyihin.
;           Otetaan laaki 2. Verrataan sitä kaikkiin enemyihin. JNE.
;------------------------------------------------------------------------------
;        move.w  #$0779,$01a4(a5)
        lea     Laakit,a0
        move.w  #AmountBullets,d7       ; Omien laakien määrä
CSil1:  lea     PTRsAndONOFF,a1
        moveq    #0,d6
        move.b  nr_of_bobs,d6        ; Vihollisten määrä -1
        subq.l  #1,d6

CSil2:  cmp.w   #0,(a0)
        bne.s   CSil3
        addq.l  #6,a0
        dbf     d7,CSil2
        bra.s   EnemiesToPlayer
CSil3:  cmp.w   #0,4(a1)        ; Katsotaan onko ko. enemy kehissä;
        beq.s   Nxt             ; ei -> seuraava enemy
        move.w  4(a0),d0        ; y-test ; Otetaan laakin (Ply) y-koord.
        move.l  Coords,a2       ; Pointteri enemyn
        add.l   (a1),a2         ; liikerataan!
        move.w  (a2),d2        ; Enemyn x-koord.
        move.w  2(a2),d1         ; Enemyn y-koord.
        sub.w   d1,d0
;       cmp.w   #0,d0
        blt.s   Nxt
        cmp.w   #8+8,d0
        bgt.s   Nxt
        move.w  2(a0),d0        ; x-test ; Laakin (Ply) x-koord.
        sub.w   d2,d0           ; Pelaajan x miinus enemyn x
        cmp.w   #-5,d0
        blt.s   Nxt
        cmp.w   #13,d0
        bgt.s   Nxt
        move.w  #0,(a0)         ; Laaki pois kehistä -merkki
;         subq.b  #1,OwnBulletsOnScreen
        subq.w  #1,6(a1)
        cmp.w   #0,6(a1)          ; Onko hajalla?
        bne.s   Nxt

        move.w  #0,4(a1)        ; Enemy pois kehistä -merkki
        subq.b  #1,AmEnemies
        addq.w  #5,Pisteet        ; Lisätään pelaajan pisteitä
          
        move.l   Exp_PT,a4
        move.w   #1,(a4)
        move.w   (a2),2(a4)
        move.w   2(a2),4(a4)
        move.w   #4,6(a4)
        add.l    #12,a4
        cmp.w    #-1,(a4)
        bne.s     ptr_ok
        move.l   #Explosions,Exp_PT
;         move.w   #$fff,$dff180
        bra.s    Nxt
ptr_ok  move.l   a4,Exp_PT

Nxt     add.l   #16,a1          ; Seuraava enemy
        dbf     d6,CSil3
        addq.l  #6,a0           ; Seuraava laaki (Ply)
        dbf     d7,CSil1

;------------------------------------------------------------------------------
; 2° Onko joku vihulainen onnistunut krunssaamaan pelaajan aluksen?
; Periaate: Verrataan kaikkien vihollisten koordinaatteja pelaajan x,y:hyn
;------------------------------------------------------------------------------
EnemiesToPlayer
        moveq   #0,d7
        move.b  nr_of_bobs,d7       ; Tässä oli bugi ennen!
        subq.l  #1,d7

        lea     PTRsAndONOFF,a0 ; Vihollisten pointterit koordinaatteihin
        move.w  x,d0            ; Pelaajan x ja
        move.w  y,d1            ; y
EToPly: cmp.w   #0,4(a0)        ; Jos vihulainen ei oo kehissä, niin next!
        beq.s   Nekst
        move.l  Coords,a1
        add.l   (a0),a1
        move.w  (a1)+,d2        ; Vihollisen x
        move.w  (a1),d3         ; Vihollisen y
        sub.w   d0,d2           ; VihX-PelX
        cmp.w   #-16,d2         ; Vasemmanpuoleinen raja
        blt.s   Nekst
        cmp.w   #13,d2          ; Oikeanpuolinen raja
        bgt.s   Nekst
        sub.w   d1,d3           ; VihY-PelY
        cmp.w   #-15,d3         ; Yläraja
        blt.s   Nekst
        cmp.w   #14,d3          ; Alaraja
        bgt.s   Nekst
        move.w  #$0ff0,$01a4(a5) ; CRASH!!!!!!!!!!!!!!
;         move.b  #1,gameOver
        subq.b  #1,energia
    
;        bra.s   EBulletsToPlayer   ; ???
Nekst:  add.l   #16,a0
        dbf     d7,EToPly

;------------------------------------------------------------------------------
; 3° Onko vihulaisen laaki ehkä jopa osunut?
; Periaate: Verrataan kaikkien enemylaakien koordinaatteja pelaajan x,y:hyn
;------------------------------------------------------------------------------
; Tähän tultaessa pelaajan x on D0:ssa ja y D1:ssä

EBulletsToPlayer
        move.w  #AmountEBullets,d7
        lea     EnemyLaakit,a0  ; Vihollisten laakien koordinaatit
BToPly  move.w  (a0)+,d2        ; Laakin x
        bmi.s   Seuraava        ; Jos x=-1, niin seuraava laaki!
        move.w  (a0)+,d3        ; Laakin y
        sub.w   d0,d2           ; LaakiX-PelaX
        cmp.w   #-3,d2          ; Vasemmanpuoleinen raja
        blt.s   Nekzt
        cmp.w   #14,d2        ; Oikeanpuolinen raja
        bgt.s   Nekzt
        sub.w   d1,d3           ; LaakiY-PelaY
        cmp.w   #-3,d3           ; Yläraja
        blt.s   Nekzt
        cmp.w   #14,d3           ; Alaraja
        bgt.s   Nekzt
        move.w  #$0ff0,$01a4(a5) ; CRASH!!!!!!!!!!!!!!!!
;         move.b     #1,gameOver
        subq.b  #1,energia
        bra.s   Ex_BTP          ; (Future: Lives/Energy -1)
Nekzt   dbf     d7,BToPly
Ex_BTP  rts
Seuraava
        addq.l  #2,a0           ; Seuraava laaki
        dbf     d7,BToPly
        rts

;------------------------------------------------------------------------------
PalautetaanTaustat
;------------------------------------------------------------------------------
; Enemyiden alla olevat taustat

        move.l  VanhaSij,a2     ; ClearScreen,VanhaSij,BLTSIZE
        moveq   #0,d7
        move.b  nr_of_bobs,d7
        subq.l   #1,d7
        move.l  VanhaESij,a1    ; ClearScreen,VanhaESij
        move.w  #AmountEBullets,d6
        move.w  #1026,d0
        WaitForBlitter
        move.w  #$09f0,$040(a5) ; BLTCON0
        move.w  #$0000,$042(a5) ; BLTCON0
        move.w  #0028,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD
PalautaTausta
        cmp.l   #0,(a2)
        bne.s   NoSkip
        add.l   #4+4+2,a2
        dbf     d7,PalautaTausta
        bra.s   PalautaTausta2
NoSkip  WaitForBlitter
        move.l  (a2)+,$050(a5)  ; BLTAPTR
        move.l  (a2)+,$054(a5)  ; BLTDPTR kohde
        move.w  (a2)+,$058(a5)  ; BLTSIZE
        dbf     d7,PalautaTausta

; Vihollisten laakien alla olevat taustat
PalautaTausta2 
        cmp.l   #0,(a1)
        bne.s   NoSkip2
        addq.l  #4+4,a1
        dbf     d6,PalautaTausta2
        bra.s   ExitPal
NoSkip2 WaitForBlitter
        move.l  (a1)+,$050(a5)  ; BLTAPTR
        move.l  (a1)+,$054(a5)  ; BLTDPTR kohde
        move.w  d0,$058(a5)     ; BLTSIZE
        dbf     d6,PalautaTausta2
ExitPal move.w  $6(a5),Random   ; Avitetaan satunnaislukugeneraattoria
        rts

;------------------------------------------------------------------------------
; Palautetaan asteroidien alta tausta
;------------------------------------------------------------------------------
PalautaAsteroidienTausta
          moveq   #max_asteroids_on_screen-1,d7
;         lea       Asteroids,a0
          move.l  VanhaAstSij,a6

          WaitForBlitter
          move.w  #$09f0,$040(a5) ; BLTCON0
          move.w  #$0000,$042(a5) ; BLTCON0
          move.w  #0028,$064(a5)  ; BLTAMOD
          move.w  #0028,$066(a5)  ; BLTDMOD

PalAstTausta
          cmp.l   #0,(a6)          ; Onko liikkeellä?
          beq.s   SkipAst
          WaitForBlitter
          move.l  (a6)+,$050(a5) ; BLTAPTR
          move.l  (a6)+,$054(a5) ; BLTDPTR
          move.w  (a6)+,$058(a5) ; BLTSIZE
;         move.l  #0,-10(a6)
SkipAst
;         add.l   #10,a0                ; Oli 20
          dbf     d7,PalAstTausta

          rts

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
HandlePlayer:
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; Put the player's ship
        lea     SPR1,a1         ; Oma alus
        move.w  x,d0            ; x
        move.w  y,d1            ; y
        move.w  #15,d2          ; korkeus
        bsr     SpriteKondikseen

;------------------------------------------------------------------------------
; Tässä liikutetaan ja pistetään kehiin omat spritelaakit.
; Laakimuuttujille täytyy
; siis varata kiinteästi muistia kuvaruudulle mahtuvien laakien määrä kertaa 3!
;------------------------------------------------------------------------------
        moveq   #AmountBullets,d7

        move.l  LaakiPT,a0
        lea     SPR0,a1         ; Laakisprite

BSil:   cmp.w   #0,(a0)         ; Onko laaki liikenteessä = kehiinkö?
        beq.s   NextB
        subq.w  #BSpeed,4(a0)   ; Laakin liikutus!
        move.w  2(a0),d0        ; Laakin x
        move.w  4(a0),d1        ; Laakin y
        cmp.w   #-8,d1
        bgt.s   Continue
        move.w  #0,(a0)         ; Laaki ei kehissä -merkki
;         subq.b  #1,OwnBulletsOnScreen
        bra.s   NextB
Continue:
        moveq   #8,d2           ; Laakispriten korkeus
        bsr     SpriteKondikseen
        add.l   #36,a1          ; Seuraava sprite

NextB:  addq.l  #6,a0
        cmp.w   #-1,(a0)
        bne.s   NoEi
        lea     Laakit,a0
NoEi:   dbf     d7,BSil
        move.l  #0,(a1)         ; Stop usage of LaakiSprite (SPR 0 tai 1)
Ex:     rts

;------------------------------------------------------------------------------
Joystick:
;------------------------------------------------------------------------------
        move.w  $c(a5),d6       ; Joikkis rekisteri

        btst    #1,d6           ; Ohjataanko oikealle?
        beq.s   jskip           ; Jos ei niin ...

        cmp.b   #1,phase
        beq.s   rdec1
        cmp.b   #2,phase
        beq.s   rdec2
        cmp.b   #3,phase
        beq.s   rdec3

        move.b   #1,phase
        move.b   #10,delay
rdec1   subq.b   #1,delay
        addq.w   #1,x
        cmp.b   #0,delay
        bne.s   ei1
        addq.b  #1,phase
        move.b  #5,delay
ei1     bra.s   ROnkoRajoissa

rdec2   subq.b  #1,delay
        addq.w  #2,x
        cmp.b   #0,delay
        bne.s   ei2
        addq.b  #1,phase
ei2     bra.s   ROnkoRajoissa

rdec3   addq.w  #3,x

ROnkoRajoissa

        cmp.w   #255-16,x
        ble.s   Nappi
        move.w  #255-16,x
        bra.s   EsiNappi

jskip:  btst    #9,d6           ; Ohjataanko vasemalle?
        beq.s   EsiNappi           ; Jos ei niin ...

        cmp.b   #1,phase
        beq.s   ldec1
        cmp.b   #2,phase
        beq.s   ldec2
        cmp.b   #3,phase
        beq.s   ldec3

        move.b  #1,phase
        move.b  #10,delay
ldec1   subq.b  #1,delay
        subq.w  #1,x
        cmp.b   #0,delay
        bne.s   ei3
        addq.b  #1,phase
        move.b  #5,delay
ei3     bra.s   LOnkoRajoissa

ldec2   subq.b  #1,delay
        subq.w  #2,x
        cmp.b   #0,delay
        bne.s   ei4
        addq.b  #1,phase
ei4     bra.s   LOnkoRajoissa

ldec3   subq.w  #3,x

LOnkoRajoissa

        cmp.w   #0,x
        bge.s   Nappi
        move.w  #0,x

EsiNappi
        move.b  #0,phase

Nappi   cmp.b   #0,Laskuri
        beq.s   Test
        subq.b  #1,Laskuri
        rts
Test:   btst    #7,$bfe001      ; Katsotaan painetaanko joikkiksen nappia ja
        bne.s   ExitJoystick    ; jos kyllä, niin laaki kehiin jos ei niin ei
        cmp.b   #1,NPohjassa
        bne.s   EiOo
Here:   rts
EiOo:   
;        cmp.b   #3,OwnBulletsOnScreen
;         beq.s   Here
;         addq.b  #1,OwnBulletsOnScreen
        move.b  #1,NPohjassa
        move.b  #Frames,Laskuri
        move.l  LaakiPT,a0
        move.w  x,d0            ; Laakille koordinaatit
        move.w  y,d1
        addq.w  #5,d0
        subq.w  #8,d1
        move.w  #1,(a0)         ; Laaki liikkellä merkki
        move.w  d0,2(a0)        ; Laakille alku-x
        move.w  d1,4(a0)        ; Laakille alky-y
        addq.l  #6,a0
        cmp.w   #-1,(a0)
        bne.s   Tedve
        lea     Laakit,a0
Tedve:  move.l  a0,LaakiPT
        rts
ExitJoystick
        cmp.b   #1,NPohjassa
        bne.s   Eij
        move.b  #0,NPohjassa
Eij:    rts

;------------------------------------------------------------------------------
; Sprite Kondikseen
; Usage: a1=sprite,d0=x,d1=y,d2=korkeus
; Kantsii ehkä kehitellä semmoinen sprite-macro, niin koodi lyhenee vähän
SpriteKondikseen 
X_kuntoon 
        and.b   #%10000000,3(a1)
        add.w   #32,d0
        add.w   #128,d0         ; Koodia kannattanee optimoida niin, että
        add.w   #44,d1          ; nämä on jo lisätty valmiiksi..
        add.w   d1,d2           ; VSTART+Korkeus=VSTOP

        ror.w   #1,d0           ; 8 ylintä x:n bittiä
        move.b  d0,1(a1)        ; HSTARTiin.
        btst    #15,d0          ; Katsotaan pitääkö
        beq.s   Y_kuntoon       ; "the HSTART low bit"
        bset    #0,3(a1)        ; asettaa.
Y_kuntoon
        move.b  d1,(a1)         ; 8 alinta y:n bittiä VSTARTiin
        btst    #8,d1           ; Katsotaan pitääkö
        beq.s   VSTOP_kuntoon   ; "the VSTART high bit"
        bset    #2,3(a1)        ; asettaa.
VSTOP_kuntoon 
        move.b  d2,2(a1)        ; 8 alinta vstop:in bittiä VSTOPpiin
        btst    #8,d2           ; Katsotaan pitääkö
        beq.s   SprOut          ; "the VSTOP high bit"
        bset    #1,3(a1)        ; asettaa.
SprOut  rts

;------------------------------------------------------------------------------
; Käsitellään energiasprite
;------------------------------------------------------------------------------
HandleEnergySprite
          moveq   #0,d2
          move.b  energia,d2            ; Korkeus
          cmp.b   #0,d2
          bgt.s   energiaa
          moveq   #0,d2
          move.b  #1,gameOver
energiaa
          moveq   #16,d3
          sub.l   d2,d3
          move.l  #235,d0
          moveq   #5,d1
          add.l   d3,d1
          move.l  #SPR2,a1
          bsr     SpriteKondikseen
          rts

;------------------------------------------------------------------------------
Scroll  cmp.b   #1,MonsterKehissa
        beq.s   GoOn

;        lea     Coolfield,a6
        move.l  coolfield,a6
        cmp.l   #5120*4,pt_toCoolF
        bne.s   Neij
        move.l  #0,pt_toCoolF

Neij    add.l   pt_toCoolF,a6
        bsr     DrawBlocks      ; Piirrettän 1 blocki kaikkiin (3) screeneihin
        sub.l   #32*4,ScrollOffset      ; Scrollataan 1 pixeli

        addq.b  #1,Frame
        cmp.b   #16,Frame
        bne.s   GoOn
        move.l  #0,Bl_paikka
        move.b  #0,Frame        
        cmp.b   #1,LameFrame
        bne.s   EiLameFrame
        move.b  #0,LameFrame
        move.l  #(256+16+16)*4*32,ScrollOffset
EiLameFrame
        sub.l   #16,LineN
        cmp.l   #-16,LineN
        bne.s   GoOn
        move.l  #0,Bl_paikka
        move.b  #1,LameFrame
        move.l  #256+16,LineN
GoOn    rts

;------------------------------------------------------------------------------
Show:   move.l  ShowScreen,d1
        add.l   ScrollOffset,d1
        move.w  d1,low1
        swap    d1
        move.w  d1,high1
        swap    d1
        add.l   #32,d1
        move.w  d1,low2
        swap    d1
        move.w  d1,high2
        swap    d1
        add.l   #32,d1
        move.w  d1,low3
        swap    d1
        move.w  d1,high3
        swap    d1
        add.l   #32,d1
        move.w  d1,low4
        swap    d1
        move.w  d1,high4
        rts

;------------------------------------------------------------------------------
DrawBlocks:     
        move.w  #4097,d6        ; BLTSIZE (16*(16*4))
        move.l  LineN,d1        ; Rivinumero, mihin blocki blitataan
        lsl.l   #7,d1           ; Kerrotaan 32*4:llä = screen's width * nr. bpls

        cmp.b   #1,LameFrame
        beq     Lame

; Kopsataan aluksi sama pala kahteen eri paikkaan ClearScreeniin

        move.l  ClearScreen,a2
        add.l   d1,a2           
        add.l   Bl_paikka,a2

        WaitForBlitter
        move.w  #$09f0,$040(a5) ; BLTCON0
        move.w  #$0000,$042(a5) ; BLTCON0
        move.w  #0038,$064(a5)  ; BLTAMOD
        move.w  #0030,$066(a5)  ; BLTDMOD
        
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE

        add.l   #Dest,a2        ; Dest-osoite
        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE (16*(16*4))

; ..sitten BitMap1:een

        move.l  BitMap1,a2
        add.l   d1,a2           
        add.l   Bl_paikka,a2

        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE

        add.l   #Dest,a2        ; Dest-osoite
        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE (16*(16*4))

; ..sitten BitMap2:een

        move.l  BitMap2,a2
        add.l   d1,a2           
        add.l   Bl_paikka,a2

        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE

        add.l   #Dest,a2        ; Dest-osoite
        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE (16*(16*4))
        addq.l  #2,Bl_paikka
        addq.l  #4,pt_toCoolF
        rts

; Blitataan ensin ClearScreeniin

Lame:   move.l  ClearScreen,a2
        add.l   d1,a2           
        add.l   Bl_paikka,a2

        WaitForBlitter
        move.w  #$09f0,$040(a5) ; BLTCON0
        move.w  #$0000,$042(a5) ; BLTCON0
        move.w  #0038,$064(a5)  ; BLTAMOD
        move.w  #0030,$066(a5)  ; BLTDMOD

        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE (16*(16*4))

; Sitten BitMap1:een

        move.l  BitMap1,a2
        add.l   d1,a2           
        add.l   Bl_paikka,a2

        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE (16*(16*4))

; Sitten BitMap2:een

        move.l  BitMap2,a2
        add.l   d1,a2           
        add.l   Bl_paikka,a2

        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE (16*(16*4))
        addq.l  #2,Bl_paikka
        addq.l  #4,pt_toCoolF
        rts

;------------------------------------------------------------------------------
SwapScreens:
        cmp.b   #1,Kumpainen
        beq     LetItBeOneThen
        move.l  BitMap2,DrawScreen
        move.l  BitMap1,ShowScreen
;         cmp.b   #1,CoordBobsRunning
;         bne.s   Ej
        move.l  #VanhaSij1,VanhaSij
        move.l  #VanhaESij1,VanhaESij
;         lea     Asteroids,a0
;         move.l  #AstVanhaSij0,10(a0)
        cmp.b   #1,AsteroidsRunning
        bne.s   Eii
        move.l  #VanhaAstSij0,VanhaAstSij
Eii     
        move.l  #UnitsVanhaSij0,UnitsVanhaSij
        move.l  #UnitsVBSij0,UnitsVBSij

        move.l  #ExpVanhaSij0,VanhaExpSij

        move.l  #MonstVanhaSij0,MonsterVanhaSij
        move.l  #MonstBVanhaSij0,MonstBVanhaSij

        move.l  #MExp_VanhaSij0,MExp_vanhasij

        move.b  #1,Kumpainen
        rts

LetItBeOneThen:
        move.l  BitMap1,DrawScreen
        move.l  BitMap2,ShowScreen
;         lea     Asteroids,a0
;        move.l  #AstVanhaSij1,10(a0)
        cmp.b   #1,AsteroidsRunning
        bne.s   Eiii
        move.l  #VanhaAstSij1,VanhaAstSij
Eiii    move.l  #VanhaSij2,VanhaSij
        move.l  #VanhaESij2,VanhaESij

        move.l  #UnitsVanhaSij1,UnitsVanhaSij
        move.l  #UnitsVBSij1,UnitsVBSij

        move.l  #ExpVanhaSij1,VanhaExpSij

        move.l  #MonstVanhaSij1,MonsterVanhaSij
        move.l  #MonstBVanhaSij1,MonstBVanhaSij

        move.l  #MExp_VanhaSij1,MExp_vanhasij

        move.b  #0,Kumpainen
        rts

;------------------------------------------------------------------------------
; Tsekataan ovatko pelaajan laakit osuneet asteroideihin tai asteroidit pelaajaan
;------------------------------------------------------------------------------
AsteroidCollisions
; Ovatko pelaajan laakit osuneet asteroideihin
; Idea: Otetaan järjestyksessä pelaajan laakeja ja verrataan niitä liikkeellä
; oleviin asteroideihin.

         moveq    #0,d4
         moveq    #0,d5
         move.w   x,d4                      ; Pelaajan X
         move.w   y,d5                      ; Pelaajan Y

         lea      Laakit,a0
         moveq    #AmountBullets,d7
LaakiKehissa
         cmp.w    #0,(a0)                  ; Onko laaki liikkeellä
         beq.s    NextLaaki           ; Jos ei ole, niin otetaan seuraava laaki
;       moveq    #0,d0
;       moveq    #0,d1
         move.w   2(a0),d0              ; Laakin X
         move.w   4(a0),d1              ; Laakin Y
         bra.s    CompareToAsteroids
NextLaaki
         addq.l   #6,a0
         dbf      d7,LaakiKehissa
         bra.s    PlayerToAsteroids

CompareToAsteroids
         moveq    #max_asteroids_on_screen-1,d6
         lea      Asteroids,a1
AstCollSil
         cmp.w    #0,(a1)                   ; Onko liikkeellä
        beq.s    NextAster           ; Jos ei ole niin seuraava asteroidi
;        moveq    #0,d2
;       moveq    #0,d3
         move.w   2(a1),d2              ; Asteroidin X
         move.w   4(a1),d3              ; Asteroidin Y
         sub.w    d0,d2                 ; AstX - PelX
         cmp.w    #-15,d2               ; -15
         blt.s    NextAster
         cmp.w    #2,d2             ; 2
         bgt.s    NextAster
         sub.w    d1,d3
         cmp.w    #-15,d3           ; -15
         blt.s    NextAster
         cmp.w    #16,d3            ; 16
         bgt.s    NextAster

         move.w   #0,(a0)                   ; Jos osuttu asteroidiin, niin laaki pois
;        subq.b   #1,OwnBulletsOnScreen

         subq.w   #1,8(a1)              ; Vähennetään asteroidin kestävyyttä
         cmp.w    #0,8(a1)              ; Jos tuhoutunut, niin laitetaan
         bne.s    NextAster             ; pois kehistä ja lisätään
         move.w   #0,(a1)                   ; pelaajan pisteitä
         add.w    #10,Pisteet
         subq.b   #1,Asteroids_on_screen ; Vähennetään ruudulla olevien
                                                    ; asteroidien määrää
         move.l   Exp_PT,a4
         move.w   #1,(a4)
         move.w   2(a1),2(a4)
         move.w   4(a1),4(a4)
         move.w   #4,6(a4)
         add.l    #12,a4
         move.l   a4,Exp_PT
         cmp.w    #-1,(a4)
         bne.s   NextAster
         move.l   #Explosions,Exp_PT

NextAster
         add.l    #10,a1
         dbf      d6,AstCollSil         ; Kun kaikki asteroidit on katsottu
         addq.l   #6,a0                 ; otetaan seuraava laaki
         dbf      d7,LaakiKehissa

; Katsotaan onko pelaaja törmännyt asteroidiin

PlayerToAsteroids
         moveq   #max_asteroids_on_screen-1,d7
         lea     Asteroids,a1
AsterSil
         cmp.w   #0,(a1)                    ; Jos asteroidi ei ole liikkeellä, niin
         beq.s   NxtAster                   ; seuraava asteroidi
         moveq   #0,d2
         moveq   #0,d3
         move.w  2(a1),d2                  ; Asteroidin X
         move.w  4(a1),d3                   ; Asteroidin Y
         sub.w   d4,d2
         cmp.w   #-15,d2
         blt.s   NxtAster
         cmp.w   #13,d2
         bgt.s   NxtAster
         sub.w   d5,d3
         cmp.w   #-15,d3
         blt.s   NxtAster
         cmp.w   #14,d3
         bgt.s   NxtAster
         move.w  #$0ff0,$1a4(a5)
;        move.b #1,gameOver
         subq.b  #1,energia
NxtAster
         add.l   #10,a1
         dbf     d7,AsterSil
         rts

;------------------------------------------------------------------------------
; Laitetaan uusi asteroidi näytölle
;------------------------------------------------------------------------------
PutAsteroid
         cmp.w    #0,Nr_of_asteroids    ; Paljonko asteroideja jäljellä
         ble.s    ExitPA              ; (yo. on kokonaismäärä)

         cmp.b   #max_asteroids_on_screen,Asteroids_on_screen
         bge.s    ExitPA

         move.w   Random,d5
         lea      Asteroids,a0
         moveq    #max_asteroids_on_screen-1,d7
PASil    cmp.w    #0,Nr_of_asteroids    ; Onko kaikki asteroidit käytetty?
         ble.s    ExitPA

         cmp.b    #max_asteroids_on_screen,Asteroids_on_screen ; Onko ruudulla max määrä
         beq.s    ExitPA                  ; asteroideja

         cmp.w    #1,(a0)                   ; Onko jo kehissä?
         beq.s    NextAsteroid         ; Jos on niin seuraava asteroidi
         move.w   $6(a5),d0            ; Arvotaan uudelle asteroidille
         add.w    Random,d0            ; X-koordinaatti
         and.l    #255,d0
         cmp.w    #239,d0
         blt.s    Ookoo
         sub.l    #16,d0
Ookoo    move.w   d0,2(a0)
         move.w   #-16,4(a0)                ; Y-koordinaatti
         add.w    d5,d0                ; Arvotaan nopeus, D5:ssä random
         and.l    #3,d0
         cmp.l    #0,d0                ; Nolllaa ei kelpuuteta nopeudeksi
         bne.s    EiNolla
         moveq    #1,d0
EiNolla
         move.w   d0,6(a0)             ; Speed
         move.w   #9,8(a0)             ; Kestävyys, asteroidit kestävät 3 laakia
         move.w   #1,(a0)                  ; Asteroidi kehissä merkki
         addq.b   #1,Asteroids_on_screen
         subq.w   #1,Nr_of_asteroids
NextAsteroid
         add.l    #10,a0
         dbf      d7,PASil

ExitPA rts
OutOfAsteroidField
         cmp.b    #0,Asteroids_on_screen
         beq.s    Out
         rts
Out      
         move.b   #1,LastAsteroidFrames
         rts

;------------------------------------------------------------------------------
; Liikutetaan ja piirretään asteroidit
;------------------------------------------------------------------------------
MoveAsteroids
 
         lea        Asteroids,a1
;        move.l   a1,a6
;       add.l    #10,a6
         move.l   VanhaAstSij,a6

         moveq    #max_asteroids_on_screen-1,d7

        move.l  ScrollOffset,d5
        WaitForBlitter
        move.w  #0000,$062(a5)  ; BLTBMOD
        move.w  #0028,$060(a5)  ; BLTCMOD 
        move.w  #0000,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD

AstSil  cmp.w    #0,(a1)              ; Onko liikkeellä? Jos ei ole, niin mennään
        beq.s    NextAst              ; seuraavan asteroidin kohdalle
        moveq    #0,d0
        moveq    #0,d1
        move.w   2(a1),d0         ; Asteroidin X
        move.w   4(a1),d1         ; Asteroidin Y
;        move.l   a1,a6           ; PutBob-rutiinia varten pointteri
;        add.l    #10,a6              ; kohdalleen
        move.l   #AsteroidBob,a2 ; A2:ssa bob-data
        move.l   #AsteroidMask,a3 ; A3:ssa mask-data
        bsr      PutBob
        add.l    #10,a6           ; HUOM !!!
        moveq    #0,d0
        move.w   6(a1),d0         ; Speed
        add.w    d0,4(a1)        ; Liikutetaan asteroidia
        cmp.w    #256+4,4(a1)         ; Onko poissa näkyvistä?
        blt.s    NextAst
        move.w   #0,(a1)              ; Jos on, niin pois kehistä merkki päälle
        subq.b   #1,Asteroids_on_screen
NextAst
        add.l    #10,a1
        dbf      d7,AstSil
        rts
Jooo    cmp.b    #0,Asteroids_on_screen
        beq.s    Out

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
HandleBob:
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
        cmp.b   #0,AmEnemies      ; Jos ei ole yhtään enemyä kehissä, niin
        bne.s   SumLeft          ; poistutaan
        rts

SumLeft lea     PTRsAndONOFF,a1 ; Pointterit koordinaatteihin + ON/OFF merkki
        move.l  VanhaSij,a6
        moveq   #0,d7
        move.b  nr_of_bobs,d7
        subq.l   #1,d7

        move.l  ScrollOffset,d5
        WaitForBlitter
        move.w  #0000,$062(a5)  ; BLTBMOD
        move.w  #0028,$060(a5)  ; BLTCMOD 
        move.w  #0000,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD
;------------------------------------------------------------------------------
BobbyLoop:
;------------------------------------------------------------------------------
        cmp.w   #0,4(a1)        ; Jos "Pois päältä" -merkki on päällä,
        bne.s   Cont            ; mennään seuraavaan bobbiin
        add.l   #16,a1          ; Seuraava bob
        add.l   #4+4+2,a6       ; Seuraava vanhasijainti stuff
        dbf     d7,BobbyLoop
        rts
Cont:   move.l  Coords,a0       ; Täällä on koordinaatit
        add.l   (a1),a0         ; Pointteri koordinaatteihin
        cmp.w   #999,(a0)       ; Jos A0:ssa on loppumerkki, niin
        bne.s   GoMan           ; pistetään "pois päältä"-merkki päälle
        move.w  #0,4(a1)
        add.l   #16,a1

;        subq.l  #4,(a1)+        ; Pointteri pois 999:n kohdalta
;        move.w  #0,(a1)+        ; "Pois päältä" -merkki päälle
;        move.l  #0,(a6)+
        addq.l  #4+2,a6
        subq.b  #1,AmEnemies
        dbf     d7,BobbyLoop
        rts

GoMan:  moveq    #0,d1
        addq.l  #4,(a1)         ; Pointteri seuraaviin koordinaatteihin
        move.w  (a0)+,d0        ; x
        move.w  (a0),d1         ; y
        move.l  8(a1),a2
        move.l  12(a1),a3

        bsr     PutBob

        add.l   #10,a6          ; HUOM !!!
        add.l   #16,a1          ; Mennään seuraavan bobin tietojen kohdalle
        dbf     d7,BobbyLoop
        rts

;------------------------------------------------------------------------------
; Blitataan 16 x 16 pixelin bob.
; D5:ssä on oltava ScrollOffsett ja A6:ssa pointteri rakenteeseen, missä on
; LONG, LONG, WORD, mitkä tarkoittavat ClearScreen sijainti, vanha sijainti ja
; BLTSIZE. Modulorekisterit asetettava alussa.
;------------------------------------------------------------------------------

PutBob  move.w  #4098,d6        ; BLTSIZE

;------------------------------------------------------------------------------
        asl.w   #2,d1             ; 4 bittitasoa
        cmp.w   #256*4,d1
        bge.w   ExitPutBob

        cmp.w   #-16*4,d1       ; -(Bobin korkeus)
        ble.w   ExitPutBob

        cmp.w   #(255-16)*4,d1  ; Alalaita
        ble.s   NextTest
        move.w  #256*4,d6       ; Screenin lainien määrä (eli korkeus)
        sub.w   d1,d6           ; Kuinka monta pixelia näkyvissä
        lsl.l   #6,d6           ; Lasketaan BLTSIZE
        addq.w  #2,d6           ; X lisätään suoraan tässä versiossa..  
        bra.s   ReadyToBeBlitted
NextTest
        cmp.w   #0,d1           ; Ylälaita (käsitellään negatiiviset
        bge.s   ReadyToBeBlitted ; koordinaatit)
        moveq   #0,d6
        move.w  #16*4,d6        ; Bobin korkeus (siis y-pituus)
        add.w   d1,d6           ; Nyt d6:ssa bobin korkeus!
        lsl.w   #6,d6           ; Lasketaan BLTSIZE
        add.w   #2,d6           ; X lisätään suoraan tässä versiossa..  
        neg.w   d1              ; Lasketaan kohta, mistä bobbi-dataa
GMan    lsl.w   #2,d1           ; aletaan blittaamaan
        add.l   d1,a2
        add.l   d1,a3
        moveq   #0,d1           ; Y-koordinaatti on tietysti nolla..
;------------------------------------------------------------------------------
;-- Lasketaan osoite
;------------------------------------------------------------------------------
ReadyToBeBlitted:
        lsl.w   #5,d1
        moveq   #0,d2
        move.b  d0,d2
        lsr.w   #3,d0
        add.w   d1,d0
        ext.l   d0
        add.l   d5,d0           ; ScrollOffset
        and.w   #$000f,d2
        mulu    #$1000,d2
        move.l  DrawScreen,a4
        add.l   d0,a4
        move.l  ClearScreen,a0
        add.l   d0,a0   
        move.l  a0,(a6)         ; Vastaava paikka ClearScreenissä
        move.l  a4,4(a6)        ; Vanha Sijainti
        move.w  d6,8(a6)        ; Talletetaan BLTSIZE

        WaitForBlitter
        move.w  d2,$042(a5)     ; BLTCON1
        or.w    #$0fce,d2       ; ynnätään minterm+use shift valueen
        move.w  d2,$040(a5)     ; BLTCON0
        move.l  a4,$048(a5)     ; BLTCPTR kohde
        move.l  a2,$04c(a5)     ; BLTBPTR bob-data
        move.l  a3,$050(a5)     ; BLTAPTR mask
        move.l  a4,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE
ExitPutBob
        rts


;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
HandleEBullets:
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
NewEBullets:
;------------------------------------------------------------------------------
        cmp.b   #AmountEBullets+1,MovingEBullets
        bge.s   MoveEBullets
        moveq   #0,d5
        move.w  #AmountEBullets,d7
        moveq    #0,d6
        move.b  nr_of_bobs,d6
        subq.l   #1,d6

        lea     PTRsAndONOFF,a0 ; Enemyiden koordinaatit ja ON/OFF
        lea     EnemyLaakit,a2  ; x,y
HEBSil: cmp.w   #0,4(a0)        ; Onko enmy kehissä? Jos ei, niin seuraava
        beq.s   NextE
Hee:    cmp.w   #-1,(a2)        ; Onko laaki jo liikkeellä? (-1=EI , >-1=ON)
        beq.s   Ok
        addq.l  #4,a2
        dbf     d7,Hee
        bra.s   MoveEBullets
Ok:     move.w  $6(a5),d0       ; Katsotaan "satunnaisluvun" perusteella
        add.w   Random,d0       ; pistetäänkö sittenkään laakia kehiin
        and.w   #%0000000000000111,d0
        cmp.w   #7,d0
        bne.s   NextE
        move.l  Coords,a1
        move.l  (a0),d0         ; Kas näin se bugi-laaki eliminoidaan!!
        subq.l  #4,d0           ; ..näin..
        add.l   d0,a1           ; ..ja näin!!
;        move.w  (a1)+,(a2)+     ; Enemyn x laakin alku-x:ksi
;        move.w  (a1),(a2)+      ; Enemyn y laakin alku-y:ksi
        moveq   #0,d5             ; Jos y-koordinaatti 
	  subq.l   #1,d5

	  cmp.l   #-1,d5
      beq.s    dsil

;        add.l    d5,a2                 ; Nyt numerot alkavat oikeasta kohdasta
nolla     move.b      #0,(a2)+
      dbf         d5,nolla
      subq.l   #1,d7                    ; DBF-käskyn vuoksi

dsil  move.l   d0,d1              ; Working copy of D0

      moveq    #1,d3                ; Määritetään 10 potensiin
      move.l   d7,d2                ; digitin järjestysnumero - 1
potsil  subq.l   #1,d2              ;
      cmp.l    #-1,d2               ;
      ble.s    Jatka              ;
      mulu.w   #10,d3             ;
      bra.s    potsil             ;

Jatka   move.l   d3,d2              ; Jaetaan muutettava luku
      divu.w   d2,d1              ; yllä määritetyllä luvulla
      and.l    #$0000ffff,d1      ; Nollataan jakojäännös
      divu.w   #10,d1             ; Jaetaan vielä 10:llä
      swap     d1                 ; Otetaan jakojäännös ja nollataan
      and.l    #$0000ffff,d1      ; muu osa luvusta; jäljellä on
                                    ; on haettu digit!
      move.b   d1,(a2)+           ; ja kirjoitetaan digit talteen
      dbf      d7,dsil

; Tulostetaan Number "muuttujassa" oleva numerosarja

Blit    lea     Number,a1
        moveq   #5-1,d7

        move.l  #192,d5             ; x-koordinaatti

        WaitForBlitter
        move.w  #0000,$062(a5)  ; BLTBMOD
        move.w  #0028,$060(a5)  ; BLTCMOD 
        move.w  #0000,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD

BNSil   lea      Numbers,a2
        lea     NumbersMask,a3

        moveq   #0,d4
        move.b  (a1)+,d4
        lsl.l   #7,d4
        add.l   d4,a2
        add.l   d4,a3
        move.l  d5,d0
        moveq   #13,d1              ; y-koordinaatti
        lsl.l   #2,d1               ; 4 bittitasoa
        bsr     BlitNumber

        add.l   #8,d5

        dbf     d7,BNSil
ExitBlitNumbers
        rts

;------------------------------------------------------------------------------
; Tulostetaan numero
;------------------------------------------------------------------------------
BlitNumber
;------------------------------------------------------------------------------
;-- Lasketaan osoite
;------------------------------------------------------------------------------
        lsl.l   #5,d1
        move.b  d0,d2
        lsr.l   #3,d0
        add.l   d1,d0
        ext.l   d0
        add.l   ScrollOffset,d0 ; ScrollOffset
        and.l   #$000f,d2
        mulu    #$1000,d2
        move.l  DrawScreen,a4
        add.l   d0,a4

        WaitForBlitter
        move.w  d2,$042(a5)     ; BLTCON1
        or.w    #$0fce,d2       ; ynnätään minterm+use shift valueen
        move.w  d2,$040(a5)     ; BLTCON0
        move.l  a4,$048(a5)     ; BLTCPTR kohde
        move.l  a2,$04c(a5)     ; BLTBPTR bob-data
        move.l  a3,$050(a5)     ; BLTAPTR mask
        move.l  a4,$054(a5)     ; BLTDPTR kohde
        move.w  #2050,$058(a5)  ; BLTSIZE

        rts

;------------------------------------------------------------------------------
; Palautetaan räjähdysten tausta
;------------------------------------------------------------------------------
PalautaExpTausta
        move.l  VanhaExpSij,a1
        moveq   #20-1,d7

        WaitForBlitter
        move.w  #$09f0,$040(a5) ; BLTCON0
        move.w  #$0000,$042(a5) ; BLTCON0
        move.w  #0028,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD
Pal
        cmp.l   #0,(a1)
        bne.s   Palauta
        add.l   #10,a1
        dbf     d7,Pal
          rts
Palauta WaitForBlitter
        move.l  (a1)+,$050(a5)  ; BLTAPTR
        move.l  (a1)+,$054(a5)  ; BLTDPTR kohde
        move.w  (a1)+,$058(a5)  ; BLTSIZE
        move.l  #0,-10(a1)
        dbf     d7,Pal
        rts

;------------------------------------------------------------------------------
; Hoidellaan räjähdykset
;------------------------------------------------------------------------------
HandleExplosions

        lea     Explosions,a1
        moveq   #20-1,d7
        move.l  ScrollOffset,d5
        move.l  VanhaExpSij,a6

        WaitForBlitter
        move.w  #0000,$062(a5)  ; BLTBMOD
        move.w  #0028,$060(a5)  ; BLTCMOD 
        move.w  #0000,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD

ExpSil  cmp.w   #0,(a1)             ; Onko kehissä
        beq.s    NextExp
        move.l  #Explosion,a2
        add.l   8(a1),a2
        move.l  #ExplosionMask,a3
        add.l   8(a1),a3
        moveq   #0,d0
        moveq   #0,d1
        move.w  2(a1),d0
        move.w  4(a1),d1
        cmp.b   #1,MonsterKehissa
        beq.s   blit
        addq.w  #1,4(a1)
        cmp.w   #256,4(a1)
        blt.s   blit
        move.w  #0,(a1)
        bra.s   NextExp
blit    bsr     PutBob

        cmp.w   #0,6(a1)            ; Onko viive nolla
        beq.s   NextExpFrame        ; Jos on, niin mennään seuraavaan frameen
        subq.w  #1,6(a1)            ; Jos ei ollut, niin vähennetään viivettä
        bra.s   NextExp

NextExpFrame
        add.l   #256,8(a1)          ; Seuraava frame
        move.w  #4,6(a1)            ; Laitetaan viive ennalleen
        cmp.l   #256*8,8(a1)        ; Ollaanko käyty kaikissa?
        bne.s   NextExp             ; Jos ei olla, niin mennään seuraavaan
        move.l  #0,8(a1)            ; Jos oltiin, niin nollataan framepointteri
        move.w  #0,(a1)             ; ja laitetaan pois kehistä-merkki

NextExp add.l   #12,a1
        add.l   #10,a6
        dbf     d7,ExpSil
exithe  rts

;------------------------------------------------------------------------------
; Katsotaan, onko monsteri liikkeellä
;------------------------------------------------------------------------------
CheckMonster
         cmp.b   #1,MonsterKehissa
         beq.s   HandleMonster
         rts

;------------------------------------------------------------------------------
; Käsitellään monsteri
;------------------------------------------------------------------------------
HandleMonster
          lea     Monster,a1
          cmp.w   #32,2(a1)
          bge.s   LiikutaHorisontaalisesti
          addq.w  #1,2(a1)
          moveq   #0,d0
          moveq   #0,d1
          moveq   #0,d2
          move.w  (a1),d0
          move.w  2(a1),d1
          bsr     PyyhiMonster

          moveq   #0,d0
          moveq   #0,d1
          lea     Monster,a1
          move.w  (a1),d0
          move.w  2(a1),d1

          move.l  60(a1),a2          ; Bob-data
          move.l  64(a1),a3          ; Mask-data
          move.l  MonsterVanhaSij,a6

          bsr     BlitMonster
          bsr     CheckMColl
          rts

LiikutaHorisontaalisesti
          cmp.b   #1,Monster_destroyed
          beq.s   ME
          move.w  DX,d0
          add.w   d0,(a1)
          cmp.w   #96,(a1)
          bne.s   Tst
          neg.w   DX
Tst       cmp.w   #0,(a1)
          bne.s   Blittaa
          neg.w   DX
Blittaa
          bsr     PyyhiMonster
          moveq   #0,d0
          moveq   #0,d1

          bsr     AmpuukoMonster
          bsr     HandleMonsterBullet

          moveq   #0,d0
          moveq   #0,d1
          lea     Monster,a1
          move.w  (a1),d0
          move.w  2(a1),d1
          move.l  60(a1),a2
          move.l  64(a1),a3
          move.l  MonsterVanhaSij,a6

          bsr     BlitMonster

ME        lea        Monster_explosion,a0
;         cmp.w   #0,(a0)
;         beq.s   CheckMColl
          cmp.b   #0,Monster_destroyed
          beq.s   CheckMColl
          bsr     HandleMonstExplosion

CheckMColl
          lea     Monster,a1
          bsr     MCollisions
          rts

;------------------------------------------------------------------------------
; Hoidellaan hirviön räjähdys
;------------------------------------------------------------------------------
HandleMonstExplosion
          cmp.b   #3,MExpFinished                   ; Peli on pelattu, kun MExpFinished = 3
          beq.s   NextLevel

          cmp.b   #1,MExpFinished
          bne.s   jatkuu
          bsr        PM                             ; Huom!
          bsr     PyyhiMonstExplosion
          subq.b  #1,LastMExpFrames
          cmp.b   #0,LastMExpFrames
          bne.s   erteees
          move.b  #3,MExpFinished
          rts

jatkuu  ;bsr      PM
          bsr     PyyhiMonstExplosion
          bsr     PyyhiMonster
          bsr     HandleMonsterBullet
          move.l  #Monster,a1
          bsr     MCollisions
          move.l  #Monster_explosion,a0
          moveq   #0,d0
          moveq   #0,d1
          move.w  2(a0),d0
          move.w  4(a0),d1

          subq.w  #1,6(a0)              ; Vähennetään viivettä yhdellä
          cmp.w   #0,6(a0)
          bgt.s   MonstExp
          add.l   #3840,8(a0)
          move.w  #4,6(a0)              ; Viive
          cmp.l   #3840*2,8(a0)
          bne.s   MonstExp
          addq.b  #1,kierros
          move.l  #0,8(a0)              ; Mennään räjähdysframen alkuun
          cmp.b   #9,kierros
          bne.s  MonstExp

          move.b  #1,MExpFinished
          move.b  #3,LastMExpFrames ; 3
          move.l  #0,8(a0)
          rts

NextLevel
          addq.b  #1,level
          cmp.b   #3,level
          beq     putlevel3
          cmp.b   #4,level
          beq.s   erteees

          move.l  #Coolfield2,coolfield
          bsr     Alustus
          bsr     FillTheScreen
erteees rts
putlevel3
          move.l  #Coolfield3,coolfield
          bsr     Alustus
          bsr     FillTheScreen
          rts

MonstExp
          move.l  8(a0),d4
          move.l  #MonsterExplosionBob,a2
          add.l   d4,a2
          move.l  #MonsterExplosionMask,a3
          move.l  MExp_vanhasij,a6
          add.l   d4,a3
          bsr     BlitMonster

          rts

HandleMonsterBullet
          moveq   #3-1,d7
          lea     Monster,a1
          addq.l  #6,a1
          move.l  ScrollOffset,d5
          move.l  MonstBVanhaSij,a6

          WaitForBlitter
          move.w  #0000,$062(a5)  ; BLTBMOD
          move.w  #0028,$060(a5)  ; BLTCMOD 
          move.w  #0000,$064(a5)  ; BLTAMOD
          move.w  #0028,$066(a5)  ; BLTDMOD

HMBSil    cmp.w   #0,(a1)
          beq.s   NextMonsterBullet

          move.l  2(a1),d0              ; Bullet X
          move.l  6(a1),d1              ; Bullet Y
          lsr.l   #7,d0
          lsr.l   #7,d1

;         move.l  #MonsterBullet,a2
;         move.l  #MonsterBulMask,a3

          bsr     BlitBullet            ; Tulostetaan monsterin laaki

          move.l  10(a1),d0
          move.l  14(a1),d1
          add.l   d0,2(a1)          ; Lisätään bulletin X:ään addX
          add.l   d1,6(a1)          ; Sama addY:lle

          move.l  2(a1),d0
          move.l  6(a1),d1
          asr.l   #7,d0
          asr.l   #7,d1

; Katsotaan pysyykö laaki rajoissa

          cmp.w   #256+4,d1
          blt.s   ookoo
          move.w  #0,(a1)
          bra.s   NextMonsterBullet
ookoo     cmp.w   #0,d0
          bge.s   AllRight
          move.w  #0,(a1)
          bra.s   NextMonsterBullet
AllRight
          cmp.w   #255-4,d0
          blt.s   NextMonsterBullet
          move.w  #0,(a1)

NextMonsterBullet

          add.l   #18,a1
          add.l   #10,a6

          dbf     d7,HMBSil
          rts


AmpuukoMonster
          cmp.b  #1,Monster_destroyed
          beq.s  xit
          moveq  #3-1,d7
          moveq  #0,d0
          moveq  #0,d1
          move.w (a1),d0
          move.w 2(a1),d1
          move.l d0,d4                  ; Monsterin X
          move.l d1,d5                  ; Monsterin Y

          addq.l #6,a1
AMPSil    cmp.w  #0,(a1)                ; Onko laaki vapaa?
          beq.s  Ampuuko                ; Jos on, niin arvotaan, ammutaanko
          add.l  #18,a1
          dbf    d7,AMPSil
xit       rts

Ampuuko   move.w $6(a5),d0
          add.w  Random,d0
          and.l  #7,d0
          cmp.w  #7,d0
          beq.s  MAmpuu
          add.l  #18,a1
          dbf    d7,AMPSil
          rts

MAmpuu  
          move.w #1,(a1)
          moveq  #0,d2
          moveq  #0,d3
          move.w x,d2                   ; Pelaajan X
          move.w y,d3                   ; Pelaajan Y

          move.l d4,d0                  ; Otetaan monsterin X ja Y
          move.l d5,d1                  ; tallesta

          add.l  #72,d0                 ; Keskitetään
          add.l  #48,d1

          sub.l  d0,d2                  ; Lasketaan X-etäisyys
          sub.l  d1,d3                  ; Lasketaan Y-etäisyys

          lsl.l  #7,d2
          lsl.l  #7,d3
          lsr.l  #6,d2
          lsr.l  #6,d3
          
          move.l d2,10(a1)              ; Talletetaan addX
          move.l d3,14(a1)              ; Talletetaan addY

          lsl.l  #7,d0
          lsl.l  #7,d1

          move.l d0,2(a1)               ; Talletetaan bullet X
          move.l d1,6(a1)               ; Talletataan bullet Y
          add.l  #18,a1
          dbf    d7,AMPSil        
ExitAmpuuko
          rts

MCollisions
; Ovatko pelaajan laakit osuneet monsteriin

          lea   Monster_explosion,a0    ; Jos monsteri räjähtänyt,
          cmp.w #1,(a0)                 ; niin ei tsekata törmäyksiä
          beq.s OMLOP

          lea    Laakit,a0
          lea    Monster,a4
          moveq  #AmountBullets,d7

MCSil     cmp.w  #1,(a0)
          beq.s  OnkoOsunut
          addq.l #6,a0
          dbf    d7,MCSil
          bra.s  OMLOP
OnkoOsunut        
          move.w 2(a0),d0               ; Laakin X
          move.w 4(a0),d1               ; Laakin Y

          sub.w  (a1),d0

          cmp.w  #0,d0
          blt.s  Seur
          cmp.w  #144,d0                ; 192
          bge.s  Seur
          sub.w  2(a1),d1

          cmp.w  #48,d1             ; 64
          bgt.s  Seur
          cmp.w  #0,d1
          blt.s  Seur
;         move.w #$fff,$1a4(a5)
          move.w #0,(a0)
          subq.w #1,4(a4)               ; Vähennetään monsterin kestävyyttä
          addq.w #5,Pisteet         ; Lisätään pelaajan pisteitä
          cmp.w  #0,4(a4)               ; Onko tuhoutunut?
          bne.s Seur
          move.b #1,Monster_destroyed
          lea    Monster_explosion,a2
          move.w #1,(a2)
          move.w (a4),2(a2)
          move.w 2(a4),4(a2)
        
Seur      addq.l #6,a0
          dbf    d7,MCSil

; Onko monsterin laakit osuuneet pelaajaan

OMLOP    lea     Monster,a1
         moveq   #3-1,d7
         addq.l  #6,a1

OMLOPSil
         cmp.w   #0,(a1)                ; Onko laaki liikkeellä?
         beq.s   nextbullet

         moveq   #0,d0
         moveq   #0,d1  
         move.w  x,d0
         move.w  y,d1
         move.l  2(a1),d2               ; Monst bullet X
         move.l  6(a1),d3               ; Monst bullet Y
         asr.l   #7,d2
         asr.l   #7,d3

         sub.w   d0,d2

         cmp.w   #-3,d2
         blt.s   nextbullet
         cmp.w   #14,d2
         bge.s   nextbullet

         sub.w   d1,d3

         cmp.w   #-3,d3
         blt.s   nextbullet
         cmp.w   #14,d3
         blt.s   nextbullet  
         move.w  #$fff,$1a4(a5)
         subq.b #1,energia

nextbullet
         add.l   #18,a1
         dbf     d7,OMLOPSil

         rts

;------------------------------------------------------------------------------
; Piirretään monsteri
;------------------------------------------------------------------------------
BlitMonster
          move.l  #12298,d6
          asl.w   #2,d1             ; 4 bittitasoa
          cmp.w   #-4*48,d1
          ble.s   ExitBM
          
          cmp.w   #0,d1           ; Ylälaita (käsitellään negatiiviset
          bge.s   Valmis             ; koordinaatit)
          moveq  #0,d6
          move.w  #4*48,d6        ; Bobin korkeus (siis y-pituus)
          add.w   d1,d6           ; Nyt d6:ssa bobin korkeus!
          lsl.w   #6,d6           ; Lasketaan BLTSIZE
          add.w   #10,d6          ; X lisätään suoraan tässä versiossa..  
          neg.w   d1              ; Lasketaan kohta, mistä bobbi-dataa
          mulu    #20,d1              ; aletaan blittaamaan.
          add.l   d1,a2
          add.l   d1,a3
          moveq   #0,d1           ; Y-koordinaatti on tietysti nolla..

Valmis  moveq    #0,d2

        lsl.l   #5,d1
        move.b  d0,d2
        lsr.l   #3,d0
        add.l   d1,d0
        ext.l   d0
        add.l   ScrollOffset,d0 ; ScrollOffset
        and.l   #$000f,d2
        mulu    #$1000,d2
        move.l  DrawScreen,a4
        add.l   d0,a4
        move.l  ClearScreen,a0
        add.l   d0,a0
        move.l  a0,(a6)+
        move.l  a4,(a6)+
        move.w  d6,(a6)+

        WaitForBlitter
        move.w  #0000,$062(a5)  ; BLTBMOD
        move.w  #0012,$060(a5)  ; BLTCMOD 
        move.w  #0000,$064(a5)  ; BLTAMOD
        move.w  #0012,$066(a5)  ; BLTDMOD

        move.w  d2,$042(a5)     ; BLTCON1
        or.w    #$0fce,d2       ; ynnätään minterm+use shift valueen
        move.w  d2,$040(a5)     ; BLTCON0
        move.l  a4,$048(a5)     ; BLTCPTR kohde
        move.l  a2,$04c(a5)     ; BLTBPTR bob-data
        move.l  a3,$050(a5)     ; BLTAPTR mask
        move.l  a4,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE
ExitBM
        rts

PyyhiMonstExplosion
        move.l  MExp_vanhasij,a6
        cmp.l   #0,(a6)
        beq.s   ExitPME

        WaitForBlitter
        move.w  #$9f0,$040(a5)  ; BLTCON0
        move.w  #$0000,$042(a5) ; BLTCON0
        move.w  #0012,$064(a5)  ; BLTAMOD
        move.w  #0012,$066(a5)  ; BLTDMOD

        move.l  (a6)+,$050(a5)  ; BLTAPTR
        move.l  (a6)+,$054(a5)  ; BLTDPTR kohde
        move.w  (a6)+,$058(a5)  ; BLTSIZE

ExitPME rts

PyyhiMonster
; Pyyhitään ensin mahdollinen monsterin bullet
        move.l  MonstBVanhaSij,a4
        moveq   #3-1,d7

PML     cmp.l   #0,(a4)
        beq.s   NextMonstBullet

        WaitForBlitter
        move.w  #$9f0,$040(a5)  ; BLTCON0
        move.w  #0000,$042(a5)  ; BLTCON0
        move.w  #0028,$064(a5)  ; BLTAMOD
        move.w  #0028,$066(a5)  ; BLTDMOD
        move.l  (a4)+,$050(a5)  ; BLTAPTR
        move.l  (a4)+,$054(a5)  ; BLTDPTR
        move.w  (a4)+,$058(a5)  ; BLTSIZE
        dbf     d7,PML
        bra.s   PM
NextMonstBullet
        add.l   #10,a4
        dbf     d7,PML

PM      move.l  MonsterVanhaSij,a4
        cmp.l   #0,(a4)
        beq.s   ExitPM

        WaitForBlitter
        move.w  #$9f0,$040(a5)  ; BLTCON0
        move.w  #$000,$042(a5)  ; BLTCON0
        move.w  #0012,$064(a5)  ; BLTAMOD
        move.w  #0012,$066(a5)  ; BLTDMOD

        move.l  (a4)+,$050(a5)  ; BLTAPTR
        move.l  (a4)+,$054(a5)  ; BLTDPTR kohde
        move.w  (a4)+,$058(a5)  ; BLTSIZE
ExitPM  rts

;------------------------------------------------------------------------------
;
;------------------------------------------------------------------------------
GameOver
            move.l      #Dummy,d0           ; Spritet pois päältä
            move.w      d0,s0_low
            swap        d0
            move.w      d0,s0_high

            move.w      d0,s1_low
            swap        d0
            move.w      d0,s1_high

            move.w      d0,s2_low
            swap        d0
            move.w      d0,s2_high

            move.b      #0,gameOver
            move.b      #0,letterstyped

            move.b   #1,level
            move.l   #Coolfield,coolfield
;           move.w   #0,Pisteet

            move.l   #0,$180(a5)

            bsr     pyyhi_bitmap

            move.l  bitmap,d1
            move.w  d1,low1
            swap     d1
            move.w   d1,high1
            swap     d1
            add.l    #32,d1
            move.w   d1,low2
            swap     d1
            move.w   d1,high2
            swap     d1
            add.l    #32,d1
            move.w   d1,low3
            swap     d1
            move.w   d1,high3
            swap     d1
            add.l    #32,d1
            move.w   d1,low4
            swap     d1
            move.w   d1,high4

            lea     gameover,a2
            move.l  bitmap,a1
            add.l    #14090,a1
            bsr     TulostaTeksti

            moveq    #5-1,d7
            lea      hiscoretable,a1
vertailu    move.w   4(a1),d1
            cmp.w    Pisteet,d1
            add.l    #6,a1
            blt.s    typeinname
            dbf     d7,vertailu

            bra.s    waitforjoybutton
typeinname

            move.l  bitmap,a1
            add.l   #1664,a1
            lea     usejoy,a2
            bsr     TulostaTeksti

            move.l  bitmap,a1
            add.l   #4864,a1
            lea     type,a2
            bsr     TulostaTeksti

            move.l   bitmap,a1
            add.l    #25738,a1
            move.b  #1,NPohjassa
            bsr     PrintLetter

gosil       bsr     JoystickForLetters
            bsr     WaitForBeam

            cmp.b   #3,letterstyped         
            beq.s   JumpToAlkuScreen

            btst    #6,$bfe001
            beq     CleanUp

            bra.s   gosil

;          bra.s    JumpToAlkuScreen

waitforjoybutton
            lea     pressjoy,a2
            move.l  bitmap,a1
            add.l   #29445,a1
            bsr     TulostaTeksti

loop        btst    #6,$bfe001
            beq     CleanUp

            bsr     WaitForBeam
            cmp.b   #1,NPohjassa
            bne.s   checkjoybutton
            move.b  #0,NPohjassa
            bra.s   loop

checkjoybutton
            btst    #7,$bfe001      ; Katsotaanko painetaanko joikkiksen nappia
            bne.s   loop
            move.b  #1,NPohjassa
            bra     JumpToAlkuScreen

;------------------------------------------------------------------------------
;
;------------------------------------------------------------------------------
LoppuScreen
            move.l   #Dummy,d0
            move.w   d0,s0_low
            swap     d0
            move.w   d0,s0_high

            move.w   d0,s1_low
            swap     d0
            move.w   d0,s1_high

            move.w   d0,s2_low
            swap     d0
            move.w   d0,s2_high

            bsr      WaitForBeam
            bsr      pyyhi_bitmap

            move.l   bitmap,d1
            move.w   d1,low1
            swap     d1
            move.w   d1,high1
            swap     d1
            add.l    #32,d1
            move.w   d1,low2
            swap     d1
            move.w   d1,high2
            swap     d1
            add.l    #32,d1
            move.w   d1,low3
            swap     d1
            move.w   d1,high3
            swap     d1
            add.l    #32,d1
            move.w   d1,low4
            swap     d1
            move.w   d1,high4

            move.w  #0,$180(a5)

            lea     udidit,a2
            move.l  bitmap,a1
            add.l   #13060,a1
            bsr     TulostaTeksti

checkbut    btst    #6,$bfe001
            beq     CleanUp

            btst    #7,$bfe001      ; Katsotaanko painetaanko joikkiksen nappia
            bne.s   exitcbut
            cmp.b   #1,NPohjassa
            bne.s   eio
            bra.s   checkbut
eio         bra     GameOver
exitcbut    cmp.b   #1,NPohjassa
            bne.s   eiole
            move.b  #0,NPohjassa
eiole       bra.s   checkbut


;------------------------------------------------------------------------------
; Level-Screen. Tämä tulostuu ennen alkavaa tasoa. Tänne hypätään alustuksesta.
;------------------------------------------------------------------------------
LevelScreen
            move.l  #Dummy,d0
            move.w  d0,s0_low
            swap    d0
            move.w  d0,s0_high

            move.w  d0,s1_low
            swap    d0
            move.w  d0,s1_high

            move.w  d0,s2_low
            swap    d0
            move.w  d0,s2_high

            bsr     pyyhi_bitmap

            move.l  bitmap,d1
            move.w   d1,low1
            swap     d1
            move.w   d1,high1
            swap     d1
            add.l    #32,d1
            move.w   d1,low2
            swap     d1
            move.w   d1,high2
            swap     d1
            add.l    #32,d1
            move.w   d1,low3
            swap     d1
            move.w   d1,high3
            swap     d1
            add.l    #32,d1
            move.w   d1,low4
            swap     d1
            move.w   d1,high4

            moveq    #0,d0
            move.b   level,d0
            add.b    #'0',d0
    
            lea      LevelTXT,a2
            move.b   d0,7(a2)

            move.l   bitmap,a1
            add.l    #13067,a1
            bsr      TulostaTeksti

            move.l   #150,d7
Wait        bsr      WaitForBeam
            dbf      d7,Wait

            rts

;------------------------------------------------------------------------------
; Alkuscreen-rutiineita
;------------------------------------------------------------------------------
AlkuScreen

            move.w   #0,Pisteet

            bsr      pyyhi_bitmap

            move.l   bitmap,d1
            move.w   d1,low1
            swap     d1
            move.w   d1,high1
            swap     d1
            add.l    #32,d1
            move.w   d1,low2
            swap     d1
            move.w   d1,high2
            swap     d1
            add.l    #32,d1
            move.w   d1,low3
            swap     d1
            move.w   d1,high3
            swap     d1
            add.l    #32,d1
            move.w   d1,low4
            swap     d1
            move.w   d1,high4

            move.w   #$0,$180(a5)

            bsr      WaitForBeam

            lea      xwars,a2
            move.l   bitmap,a1
            add.l    #7,a1
            bsr      TulostaTeksti

            move.b   #1,small_font
            lea      press,a2
            move.l   bitmap,a1
            add.l    #30080,a1
            bsr      TulostaTeksti

            lea      leftmouse,a2
            move.l   bitmap,a1
            add.l    #31488,a1
            bsr      TulostaTeksti

            lea      codingby,a2
            move.l   bitmap,a1
            add.l    #2435,a1                    ; 19
            bsr      TulostaTeksti

            lea      musicby,a2
            move.l   bitmap,a1
            add.l    #3715,a1
            bsr      TulostaTeksti
            
            move.b   #0,small_font
            bsr      PrintHiScoreList

AlkuMP      btst     #6,$bfe001
            beq      CleanUp

            bsr      WaitForBeam
checkbutton
            btst     #7,$bfe001      ; Katsotaanko painetaanko joikkiksen nappia
            bne.s    exitcb
            cmp.b    #1,NPohjassa
            bne.s    eioo
            bra.s    AlkuMP
eioo        bra      JumpToAlustus
exitcb      cmp.b    #1,NPohjassa
            bne.s    eij
            move.b   #0,NPohjassa
eij         bra.s    AlkuMP

;------------------------------------------------------------------------------
; Pyyhitään bitmap
;------------------------------------------------------------------------------
pyyhi_bitmap
            move.l   #4*2048-1,d7
            move.l   bitmap,a1
pyyhi       move.l   #0,(a1)+
            dbf      d7,pyyhi
            rts

;------------------------------------------------------------------------------
; Tulostetaan tekstiä kunnes törmätään nollaan
;------------------------------------------------------------------------------
TulostaTeksti
        lea         Fontti,a0

        moveq       #0,d0
        move.b      (a2)+,d0
        cmp.b       #0,d0
        beq.s       ExitPrintLetter
        sub.b       #'0',d0
        lsl.l       #6,d0
        add.l       d0,a0

        cmp.b       #1,small_font
        beq.s       printsmallletter

        moveq       #64-1,d7                    ; 64 - 1
lettersil
        move.b      (a0)+,(a1)
        add.l       #32,a1                  ; 16
        dbf         d7,lettersil
        addq.l      #1,a1
        sub.l       #2048,a1                    ; 1024
        bra.s       TulostaTeksti
    
ExitPrintLetter
        rts

printsmallletter
        move.l      #4*8-1,d7
smalllettersil
        move.b      (a0)+,(a1)
        addq.l      #1,a0
        add.l       #32,a1
        dbf         d7,smalllettersil
        sub.l       #1024,a1
        addq.l      #1,a1
        bra.s       TulostaTeksti

;------------------------------------------------------------------------------
; Tulostetaan yksi merkki fontista.
; A0:ssa osoitin fonttiin. A1:ssä osoitin kohteeseen. 
;------------------------------------------------------------------------------
PrintLetter
       lea          Fontti+17*64,a0
       add.l        pt_Font,a0

        moveq       #64-1,d7
letsil
        move.b      (a0)+,(a1)
        add.l       #32,a1                  ; 16
        dbf         d7,letsil
        sub.l       #2048,a1                    ; 1024

; Kirjoitetaan merkki myös merkki-bufferiin

merkkibufferiin

        lea         Nimi,a2
        moveq       #0,d0
        move.b      letterstyped,d0
        add.l       d0,a2
        move.b      currentchar,(a2)

        rts

;------------------------------------------------------------------------------
; Tulostetaan HiScore-lista
;------------------------------------------------------------------------------
PrintHiScoreList

        move.l      bitmap,a1
        add.l       #10250,a1

        lea         hiscoretable,a4
        moveq       #5-1,d6
hiscoresil
        move.l      (a4)+,a2
        bsr         TulostaTeksti
        moveq       #0,d0
        move.w      (a4)+,d0
        addq.l      #1,a1                   ; 1 välilyönti nimien jälkeen
        lea         Luku,a2
        bsr         ConvertToASCII
        lea         Luku,a2
        bsr         TulostaTeksti
        sub.l       #9,a1
        add.l       #2176,a1                ; 1280
        dbf         d6,hiscoresil       
        rts

;------------------------------------------------------------------------------
JoystickForLetters
; A0:ssa on fontin osoite
;------------------------------------------------------------------------------
        move.w      $c(a5),d6       ; Joikkis rekisteri

          cmp.b     #0,viive
          beq.s     oikealle
          subq.b    #1,viive
          bra.s     JNappi
oikealle
        btst        #1,d6           ; Ohjataanko oikealle?
        beq.s       vasemmalle      ; Jos ei niin ...

        move.b      #10,viive
          
        add.l       #64,pt_Font
        addq.b      #1,currentchar
        cmp.b       #'[',currentchar
        blt.s       pri
        move.b      #'Z',currentchar
        sub.l       #64,pt_Font

pri     bsr         PrintLetter
        bra.s       JNappi

vasemmalle
        btst        #9,d6            ; Ohjataanko vasemalle?
        beq.s       JNappi           ; Jos ei niin ...

        move.b      #10,viive

        sub.l       #64,pt_Font
        subq.b      #1,currentchar
        cmp.b       #'@',currentchar
        bgt.s       prin
        move.b      #'A',currentchar
        add.l       #64,pt_Font

prin    bsr      PrintLetter

JNappi  cmp.b   #0,Laskuri
        beq.s   TestN
        subq.b  #1,Laskuri
        rts
TestN   btst    #7,$bfe001      ; Katsotaanko painetaanko joikkiksen nappia
        bne.s   ExtJoystick    ;
        cmp.b   #1,NPohjassa
        bne.s   EiO
        rts
EiO     move.b  #1,NPohjassa
        move.b  #Frames,Laskuri
        bsr      PrintLetter
        addq.l   #1,a1
        addq.b   #1,letterstyped
        cmp.b    #3,letterstyped    ; Nollas on ensimmäinen kirjain
        bne.s    ei

        bsr      NewEntry
;         bsr        PrintHiScoreList
        rts

ExtJoystick
        cmp.b   #1,NPohjassa
        bne.s   ei
        move.b  #0,NPohjassa
ei      rts

NewEntry
        moveq    #5-1,d7
        lea     hiscoretable,a1
nesil   moveq   #0,d0
        move.w  4(a1),d0
        cmp.w   Pisteet,d0          ; Jos tietuessa oleva arvo on pienempi, on
        blt.s   yeah                    ; Pisteet suurempi...
        addq.l  #6,a1
        dbf     d7,nesil
        rts
yeah    lea     hiscoretable,a4
        subq.l  #1,d7
        cmp.l   #-1,d7              ; Jos kyseessä alimmainen, niin vain
        beq.s   JustPutNewEntry ; laitetaan entry...
        move.l  d7,d6
        mulu    #6,d6

; Siirretään listaa yhdellä pykälällä alaspäin

;       moveq       #4-1,d7
;       add.l       d6,a4
        add.l   #3*6,a4
sil moveq    #4-1,d5
        move.l  (a4),a1
        move.l  6(a4),a2
        move.l  (a2),a2
csil    move.b   (a1)+,(a2)+
        dbf     d5,csil

        move.w  4(a4),10(a4)
        subq.l  #6,a4
        dbf     d7,sil
        addq.l  #6,a4

        move.l  a4,a1
        move.l  (a4),a4
        lea     Nimi,a3
        moveq   #4-1,d7
nimisil
        move.b  (a3)+,(a4)+
        dbf     d7,nimisil

        move.w  Pisteet,4(a1)
        rts

JustPutNewEntry
        add.l   #4*6,a4

        move.l  a4,a1
        move.l  (a4),a4
        lea     Nimi,a3
        moveq   #4-1,d7
anothernimisil
        move.b  (a3)+,(a4)+
        dbf     d7,anothernimisil
        move.w  Pisteet,4(a1)
        rts

;------------------------------------------------------------------------------
; Muutetaan kokonaisluku ASCII:ksi
;------------------------------------------------------------------------------
ConvertToASCII
; Muutettava luku D0:aan, tulos tulee A2:een.

      moveq    #0,d2

; Lasketaan digittien määrä
        move.l   d0,d1              ; Lasketaan digittien määrä
nrdigits
        addq.l   #1,d2
        divu.w   #10,d1
        and.l    #$0000ffff,d1
        cmp.w    #0,d1
        bgt.s    nrdigits
        move.l   d2,d7              ; Digittien määrä-1 D7:ään

        moveq    #5,d5                  ; Hoidellaan eteen tarpeellinen
        sub.l    d7,d5                  ; määrä nollia -->
        subq.l   #1,d5
        cmp.l    #0,d5
        blt.s    skipnolla
zerosil
        move.b    #'0',(a2)+
        dbf       d5,zerosil
;        add.l    d5,a2                 ; Nyt numerot alkavat oikeasta kohdasta

skipnolla

        subq.l   #1,d7                  ; DBF-käskyn vuoksi

digitsil
        move.l   d0,d1              ; Working copy of D0

        moveq    #1,d3                  ; Määritetään 10 potensiin
        move.l   d7,d2                  ; digitin järjestysnumero - 1
posil   subq.l   #1,d2              ;
        cmp.l    #-1,d2                 ;
        ble.s    Jaa                ;
        mulu.w   #10,d3             ;
        bra.s    posil              ;

Jaa     move.l   d3,d2              ; Jaetaan muutettava luku
        divu.w   d2,d1              ; yllä määritetyllä luvulla
        and.l    #$0000ffff,d1      ; Nollataan jakojäännös
        divu.w   #10,d1             ; Jaetaan vielä 10:llä
        swap     d1                 ; Otetaan jakojäännös ja nollataan
        and.l    #$0000ffff,d1      ; muu osa luvusta; jäljellä on
        add.b    #'0',d1            ; on haettu digit!
        move.b   d1,(a2)+           ; ja kirjoitetaan digit talteen
        move.b   #0,(a2)
        dbf      d7,digitsil
        rts

;------------------------------------------------------------------------------
FillTheScreen:
; Fillataan 16*17 suuruinen alue blo(c)keisssa(16*16,what else?)
; (..ja tietysti kaikkissa (3) screeneissä!!)

        move.l  #(256+16)*4*32,d1
        move.l  BitMap1,a1
        move.l  BitMap2,a2
        move.l  ClearScreen,a3
        add.l   d1,a1
        add.l   d1,a2
        add.l   d1,a3
        move.l  coolfield,a6
;        lea     Coolfield,a6
        move.w  #16/16+(16*4*64),d6
        WaitForBlitter
        move.w  #$09f0,$040(a5) ; BLTCON0
        move.w  #$0000,$042(a5) ; BLTCON0
        move.w  #0038,$064(a5)  ; BLTAMOD
        move.w  #0030,$066(a5)  ; BLTDMOD

        moveq   #17-1,d7
YSil:   moveq   #16-1,d5
XSil:   WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a1,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE 16*(16*4)
        addq.l  #2,a1

        WaitForBlitter
        move.l  (a6),$050(a5)   ; BLTAPTR source
        move.l  a2,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE 16*(16*4)
        addq.l  #2,a2

        WaitForBlitter
        move.l  (a6)+,$050(a5)  ; BLTAPTR source
        move.l  a3,$054(a5)     ; BLTDPTR kohde
        move.w  d6,$058(a5)     ; BLTSIZE 16*(16*4)
        addq.l  #2,a3
        dbf     d5,XSil
        add.l   #(4*32*16)-32,a1
        add.l   #(4*32*16)-32,a2
        add.l   #(4*32*16)-32,a3
        dbf     d7,YSil
        rts

WaitForBeam 
        cmp.b   #$ff,$006(a5)
        bne.s   WaitForBeam
WFBeam 
        cmp.b   #$2c,$006(a5)
        bne.s   WFBeam
        rts

RMB     btst    #10,$016(a5)
        beq.s    changecol
        rts
changecol
         move.w  #$333,$180(a5)
         rts

;------------------------------------------------------------------------------
; Asetetaan tarvittavt alkuarvot, jotta uusi peli voi alkaa
;------------------------------------------------------------------------------
Alustus
        bsr     LevelScreen     ; Tulostetaan tason numero

        move.l  #(256+16+16)*4*32,ScrollOffset
;       move.w  #0,Pisteet
        move.l  #256,LineN      ; Blo(c)kin y-paikka
        move.l  #0,Bl_paikka   ; Blo(c)kin x-paikka
        move.l  #0,pt_toCoolF
        move.l  #0,pt_toClear
        move.b  #0,Frame            ; Scrollaukseen liittyvä
        move.b  #0,LameFrame
; 
        move.b   #16,energia

        lea     Explosions,a0
        lea     ExpVanhaSij0,a1
        lea     ExpVanhaSij1,a4

        moveq   #20-1,d7
Exps    move.w  #0,(a0)+        ; Kehissä
        move.w  #0,(a0)+        ; x
        move.w  #0,(a0)+        ; y
        move.w  #4,(a0)+        ; viive
        move.l  #0,(a0)+        ; Pointteri grafiikkadataan

        move.l  #0,(a1)+        ; ClearScreen-osoite
        move.l  #0,(a1)+        ; VanhaSijainti-osoite
        move.w  #0,(a1)+        ; BLTSIZE

        move.l  #0,(a4)+
        move.l  #0,(a4)+
        move.w  #0,(a4)+

        dbf     d7,Exps     

        move.l  #0,Exp_PT
        move.l  #0,VanhaExpSij
        move.l  #Explosions,Exp_PT

;
        lea     MExp_VanhaSij0,a1
        lea     MExp_VanhaSij1,a4
        move.l  #0,(a1)+        ; ClearScreen-sijainti
        move.l  #0,(a1)+        ; VanhaSijainti
        move.w  #0,(a1)+        ; BLTSIZE

        move.l  #0,(a4)+        ; ClearScreen-sijainti
        move.l  #0,(a4)+        ; VanhaSijainti
        move.w  #0,(a4)+        ; BLTSIZE

        move.l  #0,MExp_vanhasij

        moveq   #3-1,d7
        lea     MonstBVanhaSij0,a0
        lea     MonstBVanhaSij1,a1

MBalustus
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.w  #0,(a0)+

        move.l  #0,(a1)+
        move.l  #0,(a1)+
        move.w  #0,(a1)+
        dbf     d7,MBalustus

; Coordbob-stuff

        lea     VanhaSij1,a0
        lea     VanhaSij2,a1
        lea     PTRsAndONOFF,a4
        moveq   #max_bobs-1,d7
CoordBobAlustus
        move.l  #0,(a0)+        ; ClearScreen
        move.l  #0,(a0)+        ; VanhaSijainti
        move.w  #0,(a0)+        ; BLTSIZE
        move.l  #0,(a1)+        ; ClearScreen
        move.l  #0,(a1)+        ; VanhaSijainti
        move.w  #0,(a1)+        ; BLTSIZE

        move.l  #0,(a4)+        ; Pointteri koordinaatteihin
        move.w  #0,(a4)+        ; ON/OFF
        move.w  #0,(a4)+        ; Kestävyys
        move.l  #0,(a4)+        ; Pointteri bob-dataan
        move.l  #0,(a4)+        ; Pointteri mask-dataan
        dbf     d7,CoordBobAlustus

        move.b  #0,DoLastCoordBobFrames
        move.b  #0,CoordBobsRunning
        move.b  #0,nr_of_bobs
        move.b  #0,AmEnemies

        move.l  #0,VanhaSij

; Enemylaakit coordbobeille

        lea     VanhaESij1,a0
        lea     VanhaESij2,a1
        lea     EnemyLaakit,a2
        moveq   #AmountEBullets,d7

enbullet
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a1)+
        move.l  #0,(a1)+

        move.w  #-1,(a2)+   ; x HUOM!!!
        move.w  #0,(a2)+        ; y
        
        dbf     d7,enbullet

; Omat laakit

        lea     Laakit,a0
        moveq   #AmountBullets,d7
omatlaakitalustus
        move.w  #0,(a0)+        ; Kehissä
        move.w  #0,(a0)+        ; x
        move.w  #0,(a0)+        ; y
        dbf     d7,omatlaakitalustus

        move.l  #0,LaakiPT
        move.l   #Laakit,LaakiPT

; Unittien alkuarvot kuntoon

        lea     Units,a0
        lea     UnitsVanhaSij0,a1
        lea     UnitsVanhaSij1,a2
        lea     UnitsVBSij0,a3
        lea     UnitsVBSij1,a4
        moveq       #5-1,d7
UnitInit
        move.w  #0,(a0)+        ; Liikkeellä
        move.l  #0,(a0)+        ; UnitX
        move.l  #0,(a0)+        ; UnitY
        move.w  #0,(a0)+        ; Laaki liikkeellä
        move.l  #0,(a0)+        ; BulletX
        move.l  #0,(a0)+    ; BulletY
        move.l  #0,(a0)+        ; Bullet add X
        move.l  #0,(a0)+        ; Bullet add Y
        move.l  #0,(a0)+        ; UnitBob
        move.l  #0,(a0)+        ; UnitBobMask
        move.l  #0,(a0)+        ; ExplodedUnit
        move.l  #0,(a0)+        ; ExplodedUnitMask
        move.w  #0,(a0)+        ; Kestävyys
        move.w  #0,(a0)+        ; Liikkuvako

        move.l  #0,(a1)+
        move.l  #0,(a1)+
        move.w  #0,(a1)+
        move.l  #0,(a2)+
        move.l  #0,(a2)+
        move.w  #0,(a2)+
        move.l  #0,(a3)+
        move.l  #0,(a3)+
        move.w  #0,(a3)+
        move.l  #0,(a4)+
        move.l  #0,(a4)+
        move.w  #0,(a4)+

        dbf     d7,UnitInit

; Asteroidien alkuarvot kuntoon

        lea     Asteroids,a0
        moveq       #28-1,d7
AsterInit
        move.w  #0,(a0)+        ; Liikkeellä merkki
        move.w  #0,(a0)+        ; X
        move.w  #0,(a0)+        ; Y
        move.w  #0,(a0)+        ; Speed
        move.w  #0,(a0)+        ; Kestävyys
        dbf     d7,AsterInit
        moveq       #28-1,d7
        lea     VanhaAstSij0,a0
        lea     VanhaAstSij1,a1
AsterVSijInit
        move.l  #0,(a0)+        ; ClearScreen
        move.l  #0,(a0)+        ; VanhaSijainti
        move.w  #0,(a0)+        ; BLTSIZE
        move.l  #0,(a1)+
        move.l  #0,(a1)+
        move.w  #0,(a1)+
        dbf     d7,AsterVSijInit

        move.b  #0,Asteroids_on_screen
        move.b  #0,AsteroidsRunning
        move.b  #3,LastAsteroidFrames

; Monsterin alkuarvot kuntoon

        move.b  #0,MExpFinished
        move.b  #0,Monster_destroyed
        move.b  #0,MonsterKehissa

        lea     Monster,a0
        move.w  #32,(a0)+       ; X-koordinaatti
        move.w  #-64,(a0)+      ; Y
        move.w  #60,(a0)+       ; Kestävyys
        move.w  #0,(a0)+            ; Laaki liikkeellä
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.w  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.w  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+
        move.l  #0,(a0)+

        cmp.b    #2,level
        beq.s    level2monsterbob

        cmp.b    #3,level
        beq.s    level3monsterbob

        move.l   #MonsterBob,(a0)+
        move.l   #MonsterMask,(a0)+
        bra.s    monsterjatkuu

level2monsterbob
        move.l   #Monster2Bob,(a0)+
        move.l   #MonsterMask,(a0)+
        bra.s    monsterjatkuu

level3monsterbob
        move.l  #Monster3Bob,(a0)+
        move.l  #MonsterMask,(a0)+

monsterjatkuu
        move.w  #1,DX

        lea     Monster_explosion,a0
        move.w  #0,(a0)+
        move.w  #0,(a0)+
        move.w  #0,(a0)+
        move.w  #4,(a0)+        ; Viive
        move.l  #0,(a0)+

        move.b  #0,kierros

; Taso 1 aloitustasoksi

;       move.b  #1,level
;       move.l   #Coolfield,coolfield

        move.l  #SPR0,d0
        move.w  d0,s0_low
        swap    d0
        move.w  d0,s0_high

        move.l  #SPR1,d0
        move.w  d0,s1_low
        swap    d0
        move.w  d0,s1_high

        move.l  #SPR2,d0
        move.w  d0,s2_low
        swap      d0
        move.w  d0,s2_high

;

        move.l  #0,pt_Font
        move.b  #'A',currentchar

        move.w  #128,x          ; Pelaajan koordinaatit
        move.w  #235,y

        rts


;------------------------------------------------------------------------------
;
;------------------------------------------------------------------------------
AlkuRoskat:
        move.w  #5-1,d7         ; Spritejen määrä (mitkä "nollataan")
        move.l  #Dummy,d0       ; "Nollataan" käyttämättämät spritet
        lea     empty,a0
SprNl:  move.w  d0,2(a0)
        swap    d0
        move.w  d0,6(a0)
        addq.l  #8,a0
        dbf     d7,SprNl

;        lea     PTRsAndONOFF,a0 ; Lasketaan Enemyille koord. PTR:t
;         moveq   #0,d7
;        move.b  nr_of_bobs,d7
;         subq.l     #1,d7

;        move.l  #0,d0
;AlArv:  move.l  d0,(a0)+
;        move.w  #1,(a0)+        ; "Enemy kehissä" -merkki
;        add.l   #32,d0          ; 
;        dbf     d7,AlArv

        lea     EnemyLaakit,a0
        move.l  #AmountEBullets,d7
ELSil:  move.w  #-1,(a0)+
        move.w  #0,(a0)+
        dbf     d7,ELSil

        lea     Laakit,a0
        move.l  #AmountBullets,d7
SilL:   move.w  #0,(a0)+
        move.w  #0,(a0)+
        move.w  #0,(a0)+
        dbf     d7,SilL

        lea     VanhaESij1,a0
        move.l  #AmountEBullets,d7
VES1Sil move.l  #0,(a0)+
        move.l  #0,(a0)+
        dbf     d7,VES1Sil

        lea     VanhaESij2,a0
        move.l  #AmountEBullets,d7
VES2Sil move.l  #0,(a0)+
        move.l  #0,(a0)+
        dbf     d7,VES2Sil

;        lea     VanhaSij1,a0
;         moveq   #0,d7
;        move.b  nr_of_bobs,d7
;         subq.l     #1,d7
;ZIL:    move.l  #0,(a0)+
;        move.l  #0,(a0)+
;        move.w  #0,(a0)+
;        dbf     d7,ZIL

;        lea     VanhaSij2,a0
;         moveq  #0,d7
;        move.b  nr_of_bobs,d7
;         subq.l     #1,d7
;ZIL2:   move.l  #0,(a0)+
;        move.l  #0,(a0)+
;        move.w  #0,(a0)+
;        dbf     d7,ZIL2

        move.l  #SPR0,d0
        move.w  d0,s0_low
        swap    d0
        move.w  d0,s0_high

        move.l  #SPR1,d0
        move.w  d0,s1_low
        swap    d0
        move.w  d0,s1_high

        move.l  #SPR2,d0
        move.w   d0,s2_low
        swap    d0
        move.w  d0,s2_high

;        lea     Blocks+2560+2,a0               ; Blockien loppu + skip 1 väri
        move.l   #Blocks+2560+2,a0
;        lea     Colours+2,a1
        move.l   #Colours+2,a1
        moveq   #15-1,d7
CSil    move.w  (a0)+,(a1)                      ; Asetetaan värit
        addq.l  #4,a1
        dbf     d7,CSil

;         lea        Monster,a0
;         move.w  #60,4(a0)         ; Monsterin kestävyys

        move.b  #1,level
        move.l  #Coolfield,coolfield
        rts

;------------------------------------------------------------------------------
; Musiikkikeskeytys
;------------------------------------------------------------------------------
Keskeytysrutiini
        bsr mt_music
        rts

;********************************************
;* ----- Protracker V1.1B Playroutine ----- *
;* Lars "Zap" Hamre/Amiga Freelancers 1991  *
;* Bekkeliveien 10, N-2010 STRØMMEN, Norway *
;********************************************

; CIA Version 1:
; Call SetCIAInt to install the interrupt server. Then call mt_init
; to initialize the song. Playback starts when the mt_enable flag
; is set to a nonzero value. To end the song and turn off all voices,
; call mt_end. At last, call ResetCIAInt to remove the interrupt.

; This playroutine is not very fast, optimized or well commented,
; but all the new commands in PT1.1 should work.
; If it's not good enough, you'll have to change it yourself.
; We'll try to write a faster routine soon...

; Changes from V1.0C playroutine:
; - ViBRAto depth changed to be compatible with Noisetracker 2.0.
;   You'll have to double all vib. depths on old PT modules.
; - Funk Repeat changed to Invert Loop.
; - Period set back earlier when stopping an effect.

; You can use this routine to play a module. Just remove the semicolons.
; Exit by pressing both mousebuttons.
;
;main   BSR.S   SetCIAInt
;   BSR mt_init
;   ST  mt_Enable
;   MOVE.L  4.W,A6
;   LEA DOSname(PC),A1
;   MOVEQ   #0,D0
;   JSR LVOOpenLiBRAry(A6)
;   TST.L   D0
;   BEQ.S   theend
;   MOVE.L  D0,A6
;wloop  MOVEQ   #10,D1
;   JSR LVODelay(A6)
;   BTST    #6,$BFE001
;   BNE.S   wloop
;   BTST    #2,$DFF016
;   BNE.S   wloop
;   MOVE.L  A6,A1
;   MOVE.L  4.W,A6
;   JSR LVOCloseLiBRAry(A6)
;theend BSR mt_end
;   BSR ResetCIAInt
;   RTS
;
;DOSname    dc.b "dos.liBRAry",0

;---- CIA Interrupt ----

AddICRVector    =   -6
RemICRVector    =  -12
LVOOpenResource = -498
LVOOpenLiBRAry  = -552
LVOCloseLiBRAry = -414
LVODelay    = -198

ciatalo = $400
ciatahi = $500
ciatblo = $600
ciatbhi = $700
ciacra  = $E00
ciacrb  = $F00

SetCIAInt
    MOVEQ   #2,D6
    LEA $BFD000,A5
    MOVE.B  #'b',CIAAname+3
SetCIALoop
    MOVEQ   #0,D0
    LEA CIAAname(PC),A1
    MOVE.L  4.W,A6
    JSR LVOOpenResource(A6)
    MOVE.L  D0,CIAAbase
    BEQ mt_Return

    LEA GfxName(PC),A1
    MOVEQ   #0,D0
    JSR LVOOpenLiBRAry(A6)
    TST.L   D0
    BEQ ResetCIAInt
    MOVE.L  D0,A1
    MOVE.W  206(A1),D0  ; DisplayFlags
    BTST    #2,D0       ; PAL?
    BEQ.S   WasNTSC
    MOVE.L  #1773447,D7 ; PAL
    BRA.S   sciask
WasNTSC MOVE.L  #1789773,D7 ; NTSC
sciask  MOVE.L  D7,TimerValue
    DIVU    #125,D7 ; Default to normal 50 Hz timer
    JSR CloseLiBRAry(A6)

    MOVE.L  CIAAbase(PC),A6
    CMP.W   #2,D6
    BEQ.S   TryTimerA
TryTimerB
    LEA MusicIntServer(PC),A1
    MOVEQ   #1,D0   ; Bit 1: Timer B
    JSR AddICRVector(A6)
    MOVE.L  #1,TimerFlag
    TST.L   D0
    BNE.S   CIAError
    MOVE.L  A5,CIAAaddr
    MOVE.B  D7,ciatblo(A5)
    LSR.W   #8,D7
    MOVE.B  D7,ciatbhi(A5)
    BSET    #0,ciacrb(A5)
    RTS

TryTimerA
    LEA MusicIntServer(PC),A1
    MOVEQ   #0,D0   ; Bit 0: Timer A
    JSR AddICRVector(A6)
    CLR.L   TimerFlag
    TST.L   D0
    BNE.S   CIAError
    MOVE.L  A5,CIAAaddr
    MOVE.B  D7,ciatalo(A5)
    LSR.W   #8,D7
    MOVE.B  D7,ciatahi(A5)
    BSET    #0,ciacra(A5)
    RTS

CIAError
    MOVE.B  #'a',CIAAname+3
    LEA $BFE001,A5
    SUBQ.W  #1,D6
    BNE SetCIALoop
    CLR.L   CIAAbase
    RTS

ResetCIAInt
    MOVE.L  CIAAbase(PC),D0
    BEQ mt_Return
    CLR.L   CIAAbase
    MOVE.L  D0,A6
    MOVE.L  CIAAaddr(PC),A5
    TST.L   TimerFlag
    BEQ.S   ResTimerA

    BCLR    #0,ciacrb(A5)
    MOVEQ   #1,D0
    BRA.S   RemInt

ResTimerA
    BCLR    #0,ciacra(A5)
    MOVEQ   #0,D0
RemInt  LEA MusicIntServer(PC),A1
    MOVEQ   #0,d0
    JSR RemICRVector(A6)
    RTS

;---- Tempo ----

SetTempo
    MOVE.L  CIAAbase(PC),D2
    BEQ mt_Return
    CMP.W   #32,D0
    BHS.S   setemsk
    MOVEQ   #32,D0
setemsk MOVE.W  D0,RealTempo
    MOVE.L  TimerValue(PC),D2
    DIVU    D0,D2
    MOVE.L  CIAAaddr(PC),A4
    MOVE.L  TimerFlag(PC),D0
    BEQ.S   SetTemA
    MOVE.B  D2,ciatblo(A4)
    LSR.W   #8,D2
    MOVE.B  D2,ciatbhi(A4)
    RTS

SetTemA MOVE.B  D2,ciatalo(A4)
    LSR.W   #8,D2
    MOVE.B  D2,ciatahi(A4)
    RTS

RealTempo   dc.w 125
CIAAaddr    dc.l 0
CIAAname    dc.b "ciaa.resource",0
CIAAbase    dc.l 0
TimerFlag   dc.l 0
TimerValue  dc.l 0
GfxName     dc.b "graphics.liBRAry",0,0

MusicIntServer
    dc.l 0,0
    dc.b 2,5 ; type, priority
    dc.l musintname
    dc.l 0,mt_music

musintname  dc.b "Protracker MusicInt",0

;---- Playroutine ----

n_note      EQU 0  ; W
n_cmd       EQU 2  ; W
n_cmdlo     EQU 3  ; B
n_start     EQU 4  ; L
n_length    EQU 8  ; W
n_loopstart EQU 10 ; L
n_replen    EQU 14 ; W
n_period    EQU 16 ; W
n_finetune  EQU 18 ; B
n_volume    EQU 19 ; B
n_dmabit    EQU 20 ; W
n_toneportdirec EQU 22 ; B
n_toneportspeed EQU 23 ; B
n_wantedperiod  EQU 24 ; W
n_viBRAtocmd    EQU 26 ; B
n_viBRAtopos    EQU 27 ; B
n_tremolocmd    EQU 28 ; B
n_tremolopos    EQU 29 ; B
n_wavecontrol   EQU 30 ; B
n_glissfunk EQU 31 ; B
n_sampleoffset  EQU 32 ; B
n_pattpos   EQU 33 ; B
n_loopcount EQU 34 ; B
n_funkoffset    EQU 35 ; B
n_wavestart EQU 36 ; L
n_reallength    EQU 40 ; W

mt_init ;LEA    mt_data,A0
    MOVE.L  A0,mt_SongDataPtr
    MOVE.L  A0,A1
    LEA 952(A1),A1
    MOVEQ   #127,D0
    MOVEQ   #0,D1
    MOVEQ   #0,D2
mtloop  MOVE.B  (A1)+,D1
    CMP.B   D2,D1
    BCS.S   mtloop2
    MOVE.L  D1,D2
mtloop2 DBRA    D0,mtloop
    ADDQ.B  #1,D2

    LEA mt_SampleStarts(PC),A1
    ASL.L   #8,D2
    ASL.L   #2,D2
    ADD.L   #1084,D2
    ADD.L   A0,D2
    MOVE.L  D2,A2
    MOVEQ   #30,D0
mtloop3 CLR.L   (A2)
    MOVE.L  A2,(A1)+
    MOVEQ   #0,D1
    MOVE.W  42(A0),D1
    ASL.L   #1,D1
    ADD.L   D1,A2
    ADD.L   #30,A0
    DBRA    D0,mtloop3

    OR.B    #2,$BFE001
    MOVE.B  #6,mt_speed
    CLR.B   mt_counter
    CLR.B   mt_SongPos
    CLR.W   mt_PatternPos
mt_end  SF  mt_Enable
    LEA $DFF000,A0
    CLR.W   $A8(A0)
    CLR.W   $B8(A0)
    CLR.W   $C8(A0)
    CLR.W   $D8(A0)
    MOVE.W  #$F,$DFF096
    RTS

mt_music
    MOVEM.L D0-D4/A0-A6,-(SP)
    TST.B   mt_Enable
    BEQ mt_exit
    ADDQ.B  #1,mt_counter
    MOVE.B  mt_counter(PC),D0
    CMP.B   mt_speed(PC),D0
    BLO.S   mt_NoNewNote
    CLR.B   mt_counter
    TST.B   mt_PattDelTime2
    BEQ.S   mt_GetNewNote
    BSR.S   mt_NoNewAllChannels
    BRA mt_dskip

mt_NoNewNote
    BSR.S   mt_NoNewAllChannels
    BRA mt_NoNewPosYet

mt_NoNewAllChannels
    LEA $DFF0A0,A5
    LEA mt_chan1temp(PC),A6
    BSR mt_CheckEfx
    LEA $DFF0B0,A5
    LEA mt_chan2temp(PC),A6
    BSR mt_CheckEfx
    LEA $DFF0C0,A5
    LEA mt_chan3temp(PC),A6
    BSR mt_CheckEfx
    LEA $DFF0D0,A5
    LEA mt_chan4temp(PC),A6
    BRA mt_CheckEfx

mt_GetNewNote
    MOVE.L  mt_SongDataPtr(PC),A0
    LEA 12(A0),A3
    LEA 952(A0),A2  ;pattpo
    LEA 1084(A0),A0 ;patterndata
    MOVEQ   #0,D0
    MOVEQ   #0,D1
    MOVE.B  mt_SongPos(PC),D0
    MOVE.B  (A2,D0.W),D1
    ASL.L   #8,D1
    ASL.L   #2,D1
    ADD.W   mt_PatternPos(PC),D1
    CLR.W   mt_DMACONtemp

    LEA $DFF0A0,A5
    LEA mt_chan1temp(PC),A6
    BSR.S   mt_PlayVoice
    LEA $DFF0B0,A5
    LEA mt_chan2temp(PC),A6
    BSR.S   mt_PlayVoice
    LEA $DFF0C0,A5
    LEA mt_chan3temp(PC),A6
    BSR.S   mt_PlayVoice
    LEA $DFF0D0,A5
    LEA mt_chan4temp(PC),A6
    BSR.S   mt_PlayVoice
    BRA mt_SetDMA

mt_PlayVoice
    TST.L   (A6)
    BNE.S   mt_plvskip
    BSR mt_PerNop
mt_plvskip
    MOVE.L  (A0,D1.L),(A6)
    ADDQ.L  #4,D1
    MOVEQ   #0,D2
    MOVE.B  n_cmd(A6),D2
    AND.B   #$F0,D2
    LSR.B   #4,D2
    MOVE.B  (A6),D0
    AND.B   #$F0,D0
    OR.B    D0,D2
    TST.B   D2
    BEQ mt_SetRegs
    MOVEQ   #0,D3
    LEA mt_SampleStarts(PC),A1
    MOVE    D2,D4
    SUBQ.L  #1,D2
    ASL.L   #2,D2
    MULU    #30,D4
    MOVE.L  (A1,D2.L),n_start(A6)
    MOVE.W  (A3,D4.L),n_length(A6)
    MOVE.W  (A3,D4.L),n_reallength(A6)
    MOVE.B  2(A3,D4.L),n_finetune(A6)
    MOVE.B  3(A3,D4.L),n_volume(A6)
    MOVE.W  4(A3,D4.L),D3 ; Get repeat
    TST.W   D3
    BEQ.S   mt_NoLoop
    MOVE.L  n_start(A6),D2  ; Get start
    ASL.W   #1,D3
    ADD.L   D3,D2       ; Add repeat
    MOVE.L  D2,n_loopstart(A6)
    MOVE.L  D2,n_wavestart(A6)
    MOVE.W  4(A3,D4.L),D0   ; Get repeat
    ADD.W   6(A3,D4.L),D0   ; Add replen
    MOVE.W  D0,n_length(A6)
    MOVE.W  6(A3,D4.L),n_replen(A6) ; Save replen
    MOVEQ   #0,D0
    MOVE.B  n_volume(A6),D0
    MOVE.W  D0,8(A5)    ; Set volume
    BRA.S   mt_SetRegs

mt_NoLoop
    MOVE.L  n_start(A6),D2
    ADD.L   D3,D2
    MOVE.L  D2,n_loopstart(A6)
    MOVE.L  D2,n_wavestart(A6)
    MOVE.W  6(A3,D4.L),n_replen(A6) ; Save replen
    MOVEQ   #0,D0
    MOVE.B  n_volume(A6),D0
    MOVE.W  D0,8(A5)    ; Set volume
mt_SetRegs
    MOVE.W  (A6),D0
    AND.W   #$0FFF,D0
    BEQ mt_CheckMoreEfx ; If no note
    MOVE.W  2(A6),D0
    AND.W   #$0FF0,D0
    CMP.W   #$0E50,D0
    BEQ.S   mt_DoSetFineTune
    MOVE.B  2(A6),D0
    AND.B   #$0F,D0
    CMP.B   #3,D0   ; TonePortamento
    BEQ.S   mt_ChkTonePorta
    CMP.B   #5,D0
    BEQ.S   mt_ChkTonePorta
    CMP.B   #9,D0   ; Sample Offset
    BNE.S   mt_SetPeriod
    BSR mt_CheckMoreEfx
    BRA.S   mt_SetPeriod

mt_DoSetFineTune
    BSR mt_SetFineTune
    BRA.S   mt_SetPeriod

mt_ChkTonePorta
    BSR mt_SetTonePorta
    BRA mt_CheckMoreEfx

mt_SetPeriod
    MOVEM.L D0-D1/A0-A1,-(SP)
    MOVE.W  (A6),D1
    AND.W   #$0FFF,D1
    LEA mt_PeriodTable(PC),A1
    MOVEQ   #0,D0
    MOVEQ   #35,D2
mt_ftuloop
    CMP.W   (A1,D0.W),D1
    BHS.S   mt_ftufound
    ADDQ.L  #2,D0
    DBRA    D2,mt_ftuloop
mt_ftufound
    MOVEQ   #0,D1
    MOVE.B  n_finetune(A6),D1
    MULU    #36*2,D1
    ADD.L   D1,A1
    MOVE.W  (A1,D0.W),n_period(A6)
    MOVEM.L (SP)+,D0-D1/A0-A1

    MOVE.W  2(A6),D0
    AND.W   #$0FF0,D0
    CMP.W   #$0ED0,D0 ; Notedelay
    BEQ mt_CheckMoreEfx

;   MOVE.W  n_dmabit(A6),$DFF096
    BTST    #2,n_wavecontrol(A6)
    BNE.S   mt_vibnoc
    CLR.B   n_viBRAtopos(A6)
mt_vibnoc
    BTST    #6,n_wavecontrol(A6)
    BNE.S   mt_trenoc
    CLR.B   n_tremolopos(A6)
mt_trenoc
    MOVE.L  n_start(A6),(A5)    ; Set start
    MOVE.W  n_length(A6),4(A5)  ; Set length
;   MOVE.W  n_period(A6),6(A5)  ; Set period
    MOVE.W  n_dmabit(A6),D0
    OR.W    D0,mt_DMACONtemp
    BRA mt_CheckMoreEfx

mt_SetDMA
    MOVE.W  mt_DMACONtemp(PC),D0
    BSR mt_PlaySamples      ; this does the magic
    LEA $DFF000,A5
    LEA mt_chan1temp(PC),A6
    MOVE.L  n_loopstart(A6),$A0(A5)
    MOVE.W  n_replen(A6),$A4(A5)
    LEA mt_chan2temp(PC),A6
    MOVE.L  n_loopstart(A6),$B0(A5)
    MOVE.W  n_replen(A6),$B4(A5)
    LEA mt_chan3temp(PC),A6
    MOVE.L  n_loopstart(A6),$C0(A5)
    MOVE.W  n_replen(A6),$C4(A5)
    LEA mt_chan4temp(PC),A6
    MOVE.L  n_loopstart(A6),$D0(A5)
    MOVE.W  n_replen(A6),$D4(A5)

mt_dskip
    ADD.W   #16,mt_PatternPos
    MOVE.B  mt_PattDelTime,D0
    BEQ.S   mt_dskc
    MOVE.B  D0,mt_PattDelTime2
    CLR.B   mt_PattDelTime
mt_dskc TST.B   mt_PattDelTime2
    BEQ.S   mt_dska
    SUBQ.B  #1,mt_PattDelTime2
    BEQ.S   mt_dska
    SUB.W   #16,mt_PatternPos
mt_dska TST.B   mt_PBreakFlag
    BEQ.S   mt_nnpysk
    SF  mt_PBreakFlag
    MOVEQ   #0,D0
    MOVE.B  mt_PBreakPos(PC),D0
    CLR.B   mt_PBreakPos
    LSL.W   #4,D0
    MOVE.W  D0,mt_PatternPos
mt_nnpysk
    CMP.W   #1024,mt_PatternPos
    BLO.S   mt_NoNewPosYet
mt_NextPosition 
    MOVEQ   #0,D0
    MOVE.B  mt_PBreakPos(PC),D0
    LSL.W   #4,D0
    MOVE.W  D0,mt_PatternPos
    CLR.B   mt_PBreakPos
    CLR.B   mt_PosJumpFlag
    ADDQ.B  #1,mt_SongPos
    AND.B   #$7F,mt_SongPos
    MOVE.B  mt_SongPos(PC),D1
    MOVE.L  mt_SongDataPtr(PC),A0
    CMP.B   950(A0),D1
    BLO.S   mt_NoNewPosYet
    CLR.B   mt_SongPos
mt_NoNewPosYet  
    TST.B   mt_PosJumpFlag
    BNE.S   mt_NextPosition
mt_exit MOVEM.L (SP)+,D0-D4/A0-A6
    RTS

;
; busywait-fixed by Delirium Softdesign.
;
; the old routine wasted about 2*10 rasterlines, this routine needs 2-8 lines
; (depending on the module). It was tested on an A500/A3000/A4000 and seems to
; play all modules ok. BTW, using this new technique it should be no problem
; to fix the busywait-loops of almost every other replay !
;
; known bugs:
;
;  sometimes when a module starts playing and the first note is played on
;  a channel, the routine needs ~100 rasterlines (in the mt_Wait2 loop).
;  perhaps this is a dma problem ?
;
; if you know how to fix these bugs please contact me:
; kunath@informatik.tu-muenchen.de (Peter Kunath)
;

mt_PlaySamples
    movem.l d0-d2/a5-a6,-(sp)
    lea $DFF000,a5
    move.w  d0,d2

    move.b  $06(a5),d0      ; wait until end of line
;   move.w  #$0ff,$180(a5)
mt_Wait1
    cmp.b   $06(a5),d0      ; the wait should be enough even on
    beq.s   mt_Wait1        ; an A4000 running DBLPAL screenmode
mt_MaxPer0
    btst    #0,d2
    beq.s   mt_MaxPer1
    move.w  #1,$A6(a5)      ; max. speed
mt_MaxPer1
    btst    #1,d2
    beq.s   mt_MaxPer2
    move.w  #1,$B6(a5)      ; max. speed
mt_MaxPer2
    btst    #2,d2
    beq.s   mt_MaxPer3
    move.w  #1,$C6(a5)      ; max. speed
mt_MaxPer3
    btst    #3,d2
    beq.s   mt_MaxPer4
    move.w  #1,$D6(a5)      ; max. speed
mt_MaxPer4
    move.w  $02(a5),d0      ; get active channels
    and.w   d2,d0
    move.w  d0,d1
    lsl.w   #7,d0
    move.w  d0,$9C(a5)      ; stop channels
    move.w  d1,$96(a5)
;   move.w  #$f00,$180(a5)
mt_Wait2
    move.w  $1E(a5),d1      ; wait until all channels are stopped
    and.w   d0,d1
    cmp.w   d0,d1
    bne.s   mt_Wait2

    move.w  $02(a5),d0      ; get active channels
    not.w   d0
    and.w   d2,d0
    move.w  d0,d1
    lsl.w   #7,d0
    move.w  d0,$9C(a5)
    or.w    #$8000,d1
    move.w  d1,$96(a5)      ; start channels
;   move.w  #$0f0,$180(a5)
mt_Wait3
    move.w  $1E(a5),d1      ; wait until all channels are running
    and.w   d0,d1
    cmp.w   d0,d1
    bne.s   mt_Wait3
    move.b  $06(a5),d0      ; wait until end of line
;   move.w  #$00f,$180(a5)
mt_Wait4
    cmp.b   $06(a5),d0      ; the wait should be enough even on
    beq.s   mt_Wait4        ; an A4000 running DBLPAL screenmode
mt_SetPer0
    btst    #0,d2
    beq.s   mt_SetPer1
    lea mt_chan1temp(pc),a6
    move.w  n_period(a6),$A6(a5)
mt_SetPer1
    btst    #1,d2
    beq.s   mt_SetPer2
    lea mt_chan2temp(pc),a6
    move.w  n_period(a6),$B6(a5)
mt_SetPer2
    btst    #2,d2
    beq.s   mt_SetPer3
    lea mt_chan3temp(pc),a6
    move.w  n_period(a6),$C6(a5)
mt_SetPer3
    btst    #3,d2
    beq.s   mt_SetPer4
    lea mt_chan4temp(pc),a6
    move.w  n_period(a6),$D6(a5)
mt_SetPer4
;   move.w  #$000,$180(a5)
    movem.l (sp)+,d0-d2/a5-a6
    rts

mt_CheckEfx
    BSR mt_UpdateFunk
    MOVE.W  n_cmd(A6),D0
    AND.W   #$0FFF,D0
    BEQ.S   mt_PerNop
    MOVE.B  n_cmd(A6),D0
    AND.B   #$0F,D0
    BEQ.S   mt_Arpeggio
    CMP.B   #1,D0
    BEQ mt_PortaUp
    CMP.B   #2,D0
    BEQ mt_PortaDown
    CMP.B   #3,D0
    BEQ mt_TonePortamento
    CMP.B   #4,D0
    BEQ mt_ViBRAto
    CMP.B   #5,D0
    BEQ mt_TonePlusVolSlide
    CMP.B   #6,D0
    BEQ mt_ViBRAtoPlusVolSlide
    CMP.B   #$E,D0
    BEQ mt_E_Commands
SetBack MOVE.W  n_period(A6),6(A5)
    CMP.B   #7,D0
    BEQ mt_Tremolo
    CMP.B   #$A,D0
    BEQ mt_VolumeSlide
mt_Return
    RTS

mt_PerNop
    MOVE.W  n_period(A6),6(A5)
    RTS

mt_Arpeggio
    MOVEQ   #0,D0
    MOVE.B  mt_counter(PC),D0
    DIVS    #3,D0
    SWAP    D0
    CMP.W   #0,D0
    BEQ.S   mt_Arpeggio2
    CMP.W   #2,D0
    BEQ.S   mt_Arpeggio1
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    LSR.B   #4,D0
    BRA.S   mt_Arpeggio3

mt_Arpeggio1
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #15,D0
    BRA.S   mt_Arpeggio3

mt_Arpeggio2
    MOVE.W  n_period(A6),D2
    BRA.S   mt_Arpeggio4

mt_Arpeggio3
    ASL.W   #1,D0
    MOVEQ   #0,D1
    MOVE.B  n_finetune(A6),D1
    MULU    #36*2,D1
    LEA mt_PeriodTable(PC),A0
    ADD.L   D1,A0
    MOVEQ   #0,D1
    MOVE.W  n_period(A6),D1
    MOVEQ   #35,D3
mt_arploop
    MOVE.W  (A0,D0.W),D2
    CMP.W   (A0),D1
    BHS.S   mt_Arpeggio4
    ADDQ.L  #2,A0
    DBRA    D3,mt_arploop
    RTS

mt_Arpeggio4
    MOVE.W  D2,6(A5)
    RTS

mt_FinePortaUp
    TST.B   mt_counter
    BNE.S   mt_Return
    MOVE.B  #$0F,mt_LowMask
mt_PortaUp
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   mt_LowMask(PC),D0
    MOVE.B  #$FF,mt_LowMask
    SUB.W   D0,n_period(A6)
    MOVE.W  n_period(A6),D0
    AND.W   #$0FFF,D0
    CMP.W   #113,D0
    BPL.S   mt_PortaUskip
    AND.W   #$F000,n_period(A6)
    OR.W    #113,n_period(A6)
mt_PortaUskip
    MOVE.W  n_period(A6),D0
    AND.W   #$0FFF,D0
    MOVE.W  D0,6(A5)
    RTS 
 
mt_FinePortaDown
    TST.B   mt_counter
    BNE mt_Return
    MOVE.B  #$0F,mt_LowMask
mt_PortaDown
    CLR.W   D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   mt_LowMask(PC),D0
    MOVE.B  #$FF,mt_LowMask
    ADD.W   D0,n_period(A6)
    MOVE.W  n_period(A6),D0
    AND.W   #$0FFF,D0
    CMP.W   #856,D0
    BMI.S   mt_PortaDskip
    AND.W   #$F000,n_period(A6)
    OR.W    #856,n_period(A6)
mt_PortaDskip
    MOVE.W  n_period(A6),D0
    AND.W   #$0FFF,D0
    MOVE.W  D0,6(A5)
    RTS

mt_SetTonePorta
    MOVE.L  A0,-(SP)
    MOVE.W  (A6),D2
    AND.W   #$0FFF,D2
    MOVEQ   #0,D0
    MOVE.B  n_finetune(A6),D0
    MULU    #36*2,D0
    LEA mt_PeriodTable(PC),A0
    ADD.L   D0,A0
    MOVEQ   #0,D0
mt_StpLoop
    CMP.W   (A0,D0.W),D2
    BHS.S   mt_StpFound
    ADDQ.W  #2,D0
    CMP.W   #36*2,D0
    BLO.S   mt_StpLoop
    MOVEQ   #35*2,D0
mt_StpFound
    MOVE.B  n_finetune(A6),D2
    AND.B   #8,D2
    BEQ.S   mt_StpGoss
    TST.W   D0
    BEQ.S   mt_StpGoss
    SUBQ.W  #2,D0
mt_StpGoss
    MOVE.W  (A0,D0.W),D2
    MOVE.L  (SP)+,A0
    MOVE.W  D2,n_wantedperiod(A6)
    MOVE.W  n_period(A6),D0
    CLR.B   n_toneportdirec(A6)
    CMP.W   D0,D2
    BEQ.S   mt_ClearTonePorta
    BGE mt_Return
    MOVE.B  #1,n_toneportdirec(A6)
    RTS

mt_ClearTonePorta
    CLR.W   n_wantedperiod(A6)
    RTS

mt_TonePortamento
    MOVE.B  n_cmdlo(A6),D0
    BEQ.S   mt_TonePortNoChange
    MOVE.B  D0,n_toneportspeed(A6)
    CLR.B   n_cmdlo(A6)
mt_TonePortNoChange
    TST.W   n_wantedperiod(A6)
    BEQ mt_Return
    MOVEQ   #0,D0
    MOVE.B  n_toneportspeed(A6),D0
    TST.B   n_toneportdirec(A6)
    BNE.S   mt_TonePortaUp
mt_TonePortaDown
    ADD.W   D0,n_period(A6)
    MOVE.W  n_wantedperiod(A6),D0
    CMP.W   n_period(A6),D0
    BGT.S   mt_TonePortaSetPer
    MOVE.W  n_wantedperiod(A6),n_period(A6)
    CLR.W   n_wantedperiod(A6)
    BRA.S   mt_TonePortaSetPer

mt_TonePortaUp
    SUB.W   D0,n_period(A6)
    MOVE.W  n_wantedperiod(A6),D0
    CMP.W   n_period(A6),D0
    BLT.S   mt_TonePortaSetPer
    MOVE.W  n_wantedperiod(A6),n_period(A6)
    CLR.W   n_wantedperiod(A6)

mt_TonePortaSetPer
    MOVE.W  n_period(A6),D2
    MOVE.B  n_glissfunk(A6),D0
    AND.B   #$0F,D0
    BEQ.S   mt_GlissSkip
    MOVEQ   #0,D0
    MOVE.B  n_finetune(A6),D0
    MULU    #36*2,D0
    LEA mt_PeriodTable(PC),A0
    ADD.L   D0,A0
    MOVEQ   #0,D0
mt_GlissLoop
    CMP.W   (A0,D0.W),D2
    BHS.S   mt_GlissFound
    ADDQ.W  #2,D0
    CMP.W   #36*2,D0
    BLO.S   mt_GlissLoop
    MOVEQ   #35*2,D0
mt_GlissFound
    MOVE.W  (A0,D0.W),D2
mt_GlissSkip
    MOVE.W  D2,6(A5) ; Set period
    RTS

mt_ViBRAto
    MOVE.B  n_cmdlo(A6),D0
    BEQ.S   mt_ViBRAto2
    MOVE.B  n_viBRAtocmd(A6),D2
    AND.B   #$0F,D0
    BEQ.S   mt_vibskip
    AND.B   #$F0,D2
    OR.B    D0,D2
mt_vibskip
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$F0,D0
    BEQ.S   mt_vibskip2
    AND.B   #$0F,D2
    OR.B    D0,D2
mt_vibskip2
    MOVE.B  D2,n_viBRAtocmd(A6)
mt_ViBRAto2
    MOVE.B  n_viBRAtopos(A6),D0
    LEA mt_ViBRAtoTable(PC),A4
    LSR.W   #2,D0
    AND.W   #$001F,D0
    MOVEQ   #0,D2
    MOVE.B  n_wavecontrol(A6),D2
    AND.B   #$03,D2
    BEQ.S   mt_vib_sine
    LSL.B   #3,D0
    CMP.B   #1,D2
    BEQ.S   mt_vib_rampdown
    MOVE.B  #255,D2
    BRA.S   mt_vib_set
mt_vib_rampdown
    TST.B   n_viBRAtopos(A6)
    BPL.S   mt_vib_rampdown2
    MOVE.B  #255,D2
    SUB.B   D0,D2
    BRA.S   mt_vib_set
mt_vib_rampdown2
    MOVE.B  D0,D2
    BRA.S   mt_vib_set
mt_vib_sine
    MOVE.B  (A4,D0.W),D2
mt_vib_set
    MOVE.B  n_viBRAtocmd(A6),D0
    AND.W   #15,D0
    MULU    D0,D2
    LSR.W   #7,D2
    MOVE.W  n_period(A6),D0
    TST.B   n_viBRAtopos(A6)
    BMI.S   mt_ViBRAtoNeg
    ADD.W   D2,D0
    BRA.S   mt_ViBRAto3
mt_ViBRAtoNeg
    SUB.W   D2,D0
mt_ViBRAto3
    MOVE.W  D0,6(A5)
    MOVE.B  n_viBRAtocmd(A6),D0
    LSR.W   #2,D0
    AND.W   #$003C,D0
    ADD.B   D0,n_viBRAtopos(A6)
    RTS

mt_TonePlusVolSlide
    BSR mt_TonePortNoChange
    BRA mt_VolumeSlide

mt_ViBRAtoPlusVolSlide
    BSR.S   mt_ViBRAto2
    BRA mt_VolumeSlide

mt_Tremolo
    MOVE.B  n_cmdlo(A6),D0
    BEQ.S   mt_Tremolo2
    MOVE.B  n_tremolocmd(A6),D2
    AND.B   #$0F,D0
    BEQ.S   mt_treskip
    AND.B   #$F0,D2
    OR.B    D0,D2
mt_treskip
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$F0,D0
    BEQ.S   mt_treskip2
    AND.B   #$0F,D2
    OR.B    D0,D2
mt_treskip2
    MOVE.B  D2,n_tremolocmd(A6)
mt_Tremolo2
    MOVE.B  n_tremolopos(A6),D0
    LEA mt_ViBRAtoTable(PC),A4
    LSR.W   #2,D0
    AND.W   #$001F,D0
    MOVEQ   #0,D2
    MOVE.B  n_wavecontrol(A6),D2
    LSR.B   #4,D2
    AND.B   #$03,D2
    BEQ.S   mt_tre_sine
    LSL.B   #3,D0
    CMP.B   #1,D2
    BEQ.S   mt_tre_rampdown
    MOVE.B  #255,D2
    BRA.S   mt_tre_set
mt_tre_rampdown
    TST.B   n_viBRAtopos(A6)
    BPL.S   mt_tre_rampdown2
    MOVE.B  #255,D2
    SUB.B   D0,D2
    BRA.S   mt_tre_set
mt_tre_rampdown2
    MOVE.B  D0,D2
    BRA.S   mt_tre_set
mt_tre_sine
    MOVE.B  (A4,D0.W),D2
mt_tre_set
    MOVE.B  n_tremolocmd(A6),D0
    AND.W   #15,D0
    MULU    D0,D2
    LSR.W   #6,D2
    MOVEQ   #0,D0
    MOVE.B  n_volume(A6),D0
    TST.B   n_tremolopos(A6)
    BMI.S   mt_TremoloNeg
    ADD.W   D2,D0
    BRA.S   mt_Tremolo3
mt_TremoloNeg
    SUB.W   D2,D0
mt_Tremolo3
    BPL.S   mt_TremoloSkip
    CLR.W   D0
mt_TremoloSkip
    CMP.W   #$40,D0
    BLS.S   mt_TremoloOk
    MOVE.W  #$40,D0
mt_TremoloOk
    MOVE.W  D0,8(A5)
    MOVE.B  n_tremolocmd(A6),D0
    LSR.W   #2,D0
    AND.W   #$003C,D0
    ADD.B   D0,n_tremolopos(A6)
    RTS

mt_SampleOffset
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    BEQ.S   mt_sononew
    MOVE.B  D0,n_sampleoffset(A6)
mt_sononew
    MOVE.B  n_sampleoffset(A6),D0
    LSL.W   #7,D0
    CMP.W   n_length(A6),D0
    BGE.S   mt_sofskip
    SUB.W   D0,n_length(A6)
    LSL.W   #1,D0
    ADD.L   D0,n_start(A6)
    RTS
mt_sofskip
    MOVE.W  #$0001,n_length(A6)
    RTS

mt_VolumeSlide
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    LSR.B   #4,D0
    TST.B   D0
    BEQ.S   mt_VolSlideDown
mt_VolSlideUp
    ADD.B   D0,n_volume(A6)
    CMP.B   #$40,n_volume(A6)
    BMI.S   mt_vsuskip
    MOVE.B  #$40,n_volume(A6)
mt_vsuskip
    MOVE.B  n_volume(A6),D0
    MOVE.W  D0,8(A5)
    RTS

mt_VolSlideDown
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
mt_VolSlideDown2
    SUB.B   D0,n_volume(A6)
    BPL.S   mt_vsdskip
    CLR.B   n_volume(A6)
mt_vsdskip
    MOVE.B  n_volume(A6),D0
    MOVE.W  D0,8(A5)
    RTS

mt_PositionJump
    MOVE.B  n_cmdlo(A6),D0
    SUBQ.B  #1,D0
    MOVE.B  D0,mt_SongPos
mt_pj2  CLR.B   mt_PBreakPos
    ST  mt_PosJumpFlag
    RTS

mt_VolumeChange
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    CMP.B   #$40,D0
    BLS.S   mt_VolumeOk
    MOVEQ   #$40,D0
mt_VolumeOk
    MOVE.B  D0,n_volume(A6)
    MOVE.W  D0,8(A5)
    RTS

mt_PatternBreak
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    MOVE.L  D0,D2
    LSR.B   #4,D0
    MULU    #10,D0
    AND.B   #$0F,D2
    ADD.B   D2,D0
    CMP.B   #63,D0
    BHI.S   mt_pj2
    MOVE.B  D0,mt_PBreakPos
    ST  mt_PosJumpFlag
    RTS

mt_SetSpeed
    MOVEQ   #0,D0
    MOVE.B  3(A6),D0
    BEQ mt_end
    CMP.B   #32,D0
    BHS SetTempo
    CLR.B   mt_counter
    MOVE.B  D0,mt_speed
    RTS

mt_CheckMoreEfx
    BSR mt_UpdateFunk
    MOVE.B  2(A6),D0
    AND.B   #$0F,D0
    CMP.B   #$9,D0
    BEQ mt_SampleOffset
    CMP.B   #$B,D0
    BEQ mt_PositionJump
    CMP.B   #$D,D0
    BEQ.S   mt_PatternBreak
    CMP.B   #$E,D0
    BEQ.S   mt_E_Commands
    CMP.B   #$F,D0
    BEQ.S   mt_SetSpeed
    CMP.B   #$C,D0
    BEQ mt_VolumeChange
    BRA mt_PerNop

mt_E_Commands
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$F0,D0
    LSR.B   #4,D0
    BEQ.S   mt_FilterOnOff
    CMP.B   #1,D0
    BEQ mt_FinePortaUp
    CMP.B   #2,D0
    BEQ mt_FinePortaDown
    CMP.B   #3,D0
    BEQ.S   mt_SetGlissControl
    CMP.B   #4,D0
    BEQ mt_SetViBRAtoControl
    CMP.B   #5,D0
    BEQ mt_SetFineTune
    CMP.B   #6,D0
    BEQ mt_JumpLoop
    CMP.B   #7,D0
    BEQ mt_SetTremoloControl
    CMP.B   #9,D0
    BEQ mt_RetrigNote
    CMP.B   #$A,D0
    BEQ mt_VolumeFineUp
    CMP.B   #$B,D0
    BEQ mt_VolumeFineDown
    CMP.B   #$C,D0
    BEQ mt_NoteCut
    CMP.B   #$D,D0
    BEQ mt_NoteDelay
    CMP.B   #$E,D0
    BEQ mt_PatternDelay
    CMP.B   #$F,D0
    BEQ mt_FunkIt
    RTS

mt_FilterOnOff
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #1,D0
    ASL.B   #1,D0
    AND.B   #$FD,$BFE001
    OR.B    D0,$BFE001
    RTS 

mt_SetGlissControl
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    AND.B   #$F0,n_glissfunk(A6)
    OR.B    D0,n_glissfunk(A6)
    RTS

mt_SetViBRAtoControl
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    AND.B   #$F0,n_wavecontrol(A6)
    OR.B    D0,n_wavecontrol(A6)
    RTS

mt_SetFineTune
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    MOVE.B  D0,n_finetune(A6)
    RTS

mt_JumpLoop
    TST.B   mt_counter
    BNE mt_Return
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    BEQ.S   mt_SetLoop
    TST.B   n_loopcount(A6)
    BEQ.S   mt_jumpcnt
    SUBQ.B  #1,n_loopcount(A6)
    BEQ mt_Return
mt_jmploop  MOVE.B  n_pattpos(A6),mt_PBreakPos
    ST  mt_PBreakFlag
    RTS

mt_jumpcnt
    MOVE.B  D0,n_loopcount(A6)
    BRA.S   mt_jmploop

mt_SetLoop
    MOVE.W  mt_PatternPos(PC),D0
    LSR.W   #4,D0
    MOVE.B  D0,n_pattpos(A6)
    RTS

mt_SetTremoloControl
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    LSL.B   #4,D0
    AND.B   #$0F,n_wavecontrol(A6)
    OR.B    D0,n_wavecontrol(A6)
    RTS

mt_RetrigNote
    MOVE.L  D1,-(SP)
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    BEQ.S   mt_rtnend
    MOVEQ   #0,D1
    MOVE.B  mt_counter(PC),D1
    BNE.S   mt_rtnskp
    MOVE.W  (A6),D1
    AND.W   #$0FFF,D1
    BNE.S   mt_rtnend
    MOVEQ   #0,D1
    MOVE.B  mt_counter(PC),D1
mt_rtnskp
    DIVU    D0,D1
    SWAP    D1
    TST.W   D1
    BNE.S   mt_rtnend
mt_DoRetrig
;   MOVE.W  n_dmabit(A6),$DFF096    ; Channel DMA off
    MOVE.L  n_start(A6),(A5)    ; Set sampledata pointer
    MOVE.W  n_length(A6),4(A5)  ; Set length
    MOVE.W  n_dmabit(A6),D0
    BSR mt_PlaySamples      ; this does the magic
    MOVE.L  n_loopstart(A6),(A5)
    MOVE.L  n_replen(A6),4(A5)
mt_rtnend
    MOVE.L  (SP)+,D1
    RTS

mt_VolumeFineUp
    TST.B   mt_counter
    BNE mt_Return
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$F,D0
    BRA mt_VolSlideUp

mt_VolumeFineDown
    TST.B   mt_counter
    BNE mt_Return
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    BRA mt_VolSlideDown2

mt_NoteCut
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    CMP.B   mt_counter(PC),D0
    BNE mt_Return
    CLR.B   n_volume(A6)
    MOVE.W  #0,8(A5)
    RTS

mt_NoteDelay
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    CMP.B   mt_counter,D0
    BNE mt_Return
    MOVE.W  (A6),D0
    BEQ mt_Return
    MOVE.L  D1,-(SP)
    BRA mt_DoRetrig

mt_PatternDelay
    TST.B   mt_counter
    BNE mt_Return
    MOVEQ   #0,D0
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    TST.B   mt_PattDelTime2
    BNE mt_Return
    ADDQ.B  #1,D0
    MOVE.B  D0,mt_PattDelTime
    RTS

mt_FunkIt
    TST.B   mt_counter
    BNE mt_Return
    MOVE.B  n_cmdlo(A6),D0
    AND.B   #$0F,D0
    LSL.B   #4,D0
    AND.B   #$0F,n_glissfunk(A6)
    OR.B    D0,n_glissfunk(A6)
    TST.B   D0
    BEQ mt_Return
mt_UpdateFunk
    MOVEM.L A0/D1,-(SP)
    MOVEQ   #0,D0
    MOVE.B  n_glissfunk(A6),D0
    LSR.B   #4,D0
    BEQ.S   mt_funkend
    LEA mt_FunkTable(PC),A0
    MOVE.B  (A0,D0.W),D0
    ADD.B   D0,n_funkoffset(A6)
    BTST    #7,n_funkoffset(A6)
    BEQ.S   mt_funkend
    CLR.B   n_funkoffset(A6)

    MOVE.L  n_loopstart(A6),D0
    MOVEQ   #0,D1
    MOVE.W  n_replen(A6),D1
    ADD.L   D1,D0
    ADD.L   D1,D0
    MOVE.L  n_wavestart(A6),A0
    ADDQ.L  #1,A0
    CMP.L   D0,A0
    BLO.S   mt_funkok
    MOVE.L  n_loopstart(A6),A0
mt_funkok
    MOVE.L  A0,n_wavestart(A6)
    MOVEQ   #-1,D0
    SUB.B   (A0),D0
    MOVE.B  D0,(A0)
mt_funkend
    MOVEM.L (SP)+,A0/D1
    RTS


mt_FunkTable dc.b 0,5,6,7,8,10,11,13,16,19,22,26,32,43,64,128

mt_ViBRAtoTable 
    dc.b   0, 24, 49, 74, 97,120,141,161
    dc.b 180,197,212,224,235,244,250,253
    dc.b 255,253,250,244,235,224,212,197
    dc.b 180,161,141,120, 97, 74, 49, 24

mt_PeriodTable
; Tuning 0, Normal
    dc.w    856,808,762,720,678,640,604,570,538,508,480,453
    dc.w    428,404,381,360,339,320,302,285,269,254,240,226
    dc.w    214,202,190,180,170,160,151,143,135,127,120,113
; Tuning 1
    dc.w    850,802,757,715,674,637,601,567,535,505,477,450
    dc.w    425,401,379,357,337,318,300,284,268,253,239,225
    dc.w    213,201,189,179,169,159,150,142,134,126,119,113
; Tuning 2
    dc.w    844,796,752,709,670,632,597,563,532,502,474,447
    dc.w    422,398,376,355,335,316,298,282,266,251,237,224
    dc.w    211,199,188,177,167,158,149,141,133,125,118,112
; Tuning 3
    dc.w    838,791,746,704,665,628,592,559,528,498,470,444
    dc.w    419,395,373,352,332,314,296,280,264,249,235,222
    dc.w    209,198,187,176,166,157,148,140,132,125,118,111
; Tuning 4
    dc.w    832,785,741,699,660,623,588,555,524,495,467,441
    dc.w    416,392,370,350,330,312,294,278,262,247,233,220
    dc.w    208,196,185,175,165,156,147,139,131,124,117,110
; Tuning 5
    dc.w    826,779,736,694,655,619,584,551,520,491,463,437
    dc.w    413,390,368,347,328,309,292,276,260,245,232,219
    dc.w    206,195,184,174,164,155,146,138,130,123,116,109
; Tuning 6
    dc.w    820,774,730,689,651,614,580,547,516,487,460,434
    dc.w    410,387,365,345,325,307,290,274,258,244,230,217
    dc.w    205,193,183,172,163,154,145,137,129,122,115,109
; Tuning 7
    dc.w    814,768,725,684,646,610,575,543,513,484,457,431
    dc.w    407,384,363,342,323,305,288,272,256,242,228,216
    dc.w    204,192,181,171,161,152,144,136,128,121,114,108
; Tuning -8
    dc.w    907,856,808,762,720,678,640,604,570,538,508,480
    dc.w    453,428,404,381,360,339,320,302,285,269,254,240
    dc.w    226,214,202,190,180,170,160,151,143,135,127,120
; Tuning -7
    dc.w    900,850,802,757,715,675,636,601,567,535,505,477
    dc.w    450,425,401,379,357,337,318,300,284,268,253,238
    dc.w    225,212,200,189,179,169,159,150,142,134,126,119
; Tuning -6
    dc.w    894,844,796,752,709,670,632,597,563,532,502,474
    dc.w    447,422,398,376,355,335,316,298,282,266,251,237
    dc.w    223,211,199,188,177,167,158,149,141,133,125,118
; Tuning -5
    dc.w    887,838,791,746,704,665,628,592,559,528,498,470
    dc.w    444,419,395,373,352,332,314,296,280,264,249,235
    dc.w    222,209,198,187,176,166,157,148,140,132,125,118
; Tuning -4
    dc.w    881,832,785,741,699,660,623,588,555,524,494,467
    dc.w    441,416,392,370,350,330,312,294,278,262,247,233
    dc.w    220,208,196,185,175,165,156,147,139,131,123,117
; Tuning -3
    dc.w    875,826,779,736,694,655,619,584,551,520,491,463
    dc.w    437,413,390,368,347,328,309,292,276,260,245,232
    dc.w    219,206,195,184,174,164,155,146,138,130,123,116
; Tuning -2
    dc.w    868,820,774,730,689,651,614,580,547,516,487,460
    dc.w    434,410,387,365,345,325,307,290,274,258,244,230
    dc.w    217,205,193,183,172,163,154,145,137,129,122,115
; Tuning -1
    dc.w    862,814,768,725,684,646,610,575,543,513,484,457
    dc.w    431,407,384,363,342,323,305,288,272,256,242,228
    dc.w    216,203,192,181,171,161,152,144,136,128,121,114

mt_chan1temp    dc.l    0,0,0,0,0,$00010000,0,  0,0,0,0
mt_chan2temp    dc.l    0,0,0,0,0,$00020000,0,  0,0,0,0
mt_chan3temp    dc.l    0,0,0,0,0,$00040000,0,  0,0,0,0
mt_chan4temp    dc.l    0,0,0,0,0,$00080000,0,  0,0,0,0

mt_SampleStarts dc.l    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        dc.l    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

mt_SongDataPtr  dc.l 0
mt_speed    dc.b 6
mt_counter  dc.b 0
mt_SongPos  dc.b 0
mt_PBreakPos    dc.b 0
mt_PosJumpFlag  dc.b 0
mt_PBreakFlag   dc.b 0
mt_LowMask  dc.b 0
mt_PattDelTime  dc.b 0
mt_PattDelTime2 dc.b 0
mt_Enable   dc.b 0
mt_PatternPos   dc.w 0
mt_DMACONtemp   dc.w 0

;------------------------------------------------------------------------------

;------------------------------------------------------------------------------

Gamefield       incbin  "Work:MyProjects/Game/GameFieldStuff/level1.gamefield"
Gamefield2      incbin  "Work:MyProjects/Game/GameFieldStuff/level2.gamefield"
Gamefield3      incbin  "Work:MyProjects/Game/GameFieldStuff/level3.gamefield"

Coords1         incbin  "Work:MyProjects/Game/Coords/Coords4"
Coords2         incbin  "Work:MyProjects/Game/Coords/3Coords2"
Coords3         incbin  "Work:MyProjects/Game/Coords/3Coords3"
                even

Fontti          incbin  "Work:MyProjects/Game/BPL/Font"

gfxname         dc.b    "graphics.liBRAry",0
intuiname       dc.b    "intuition.liBRAry",0
dosname         dc.b    "dos.liBRAry",0

vertname        dc.b    "Music interrupt",0

xwars           dc.b    "A?JOURNEY?TO?HOME",0
codingby        dc.b    "CODING?BY?MARKUS?KETOLA",0
musicby         dc.b    "MUSIC?BY?VARIOUS?PEOPLE",0
titlemusicby    dc.b    "TITLE?MUSIC?BY?CHIPPER",0
ingamemusicby   dc.b    "IN?GAME?MUSIC?BY?MERLIN?M",0
endmusicby      dc.b    "END?MUSIC?BY?HEATBEAT",0

press           dc.b    "PRESS?JOYSTICK?BUTTON?TO?PLAY",0
gameover        dc.b    "GAME?OVER",0
pressjoy        dc.b    "PRESS?JOYSTICK?BUTTON",0
udidit          dc.b    "YOU?DID?IT",0
leftmouse       dc.b    "PRESS?LEFT?MOUSEBUTTON?TO?EXIT",0
usejoy          dc.b    "USE?JOYSTICK?TO",0
type            dc.b    "TYPE?YOUR?INITIALS",0
                even

        section Muuttujat,DATA

intuibase       dc.l    0
gfxbase         dc.l    0
dosbase         dc.l    0
ptbase          dc.l    0

;------------------------------------------------------------------------------
; Räjähdystietue
; WORD  Kehissä 0/1
; WORD   x
; WORD   y
; WORD   viive
; LONG   Pointteri grafiikkadataan. Tämä on pelkkä lisäysarvo
Explosions       ds.b   12*20
                 dc.w   -1

; ExpVanhaSij0 rakenne
; LONG  ClearScreen-osoite
; LONG   Vanha sijainti -osoite
; WORD   BLITSIZE

ExpVanhaSij0     ds.b   10*20
ExpVanhaSij1     ds.b   10*20

;------------------------------------------------------------------------------
; Monsterin räjähdystietue
;------------------------------------------------------------------------------
; WORD Kehissä 0/1
; WORD x
; WORD y
; WORD viive
; LONG Pointteri grafiikkadataan, pelkkä lisäysarvo

Monster_explosion   ds.b    12

MExp_VanhaSij0      ds.b    10
MExp_VanhaSij1      ds.b    10

;------------------------------------------------------------------------------
; VanhaSijX:n rakenne: LONG,LONG,WORD
; 1.LONG: ClearScreen-addy, 2.LONG: Screen1/2-addy, WORD: BLTSIZE

VanhaSij1           ds.w    max_bobs+(4*max_bobs)
VanhaSij2           ds.w    max_bobs+(4*max_bobs)

;------------------------------------------------------------------------------
; Rakenne: LONG,WORD
; LONG: Pointteri Coordinaatteihin, WORD: ON/OFF (1=ON, 0=OFF)
; WORD kestävyys, LONG pointteri bob-dataan, LONG pointteri mask-dataan
; Tässä versiossa kaikkien wordien pitää olla ykkösiä aluksi!

PTRsAndONOFF        ds.b    16*max_bobs

;------------------------------------------------------------------------------
; Rakenne: LONG,LONG: ClearScreen(osoite),Vanhasijainti(osoite)

VanhaESij1          ds.l    (AmountEBullets+1)*2
VanhaESij2          ds.l    (AmountEBullets+1)*2
;------------------------------------------------------------------------------
; Rakenne WORD,WORD=x,y. Jos x=-1,niin laaki ei ole liikenteessä (=vapaa)
; Aluksi kaikkien x:ien pitää olla -1!!

EnemyLaakit         ds.w    (AmountEBullets+1)*2

;------------------------------------------------------------------------------
; (0,0,0)=Laaki kehissä/ei kehissä,x,y)

Laakit              ds.w    (AmountBullets+1)*3
                    dc.w    -1

;------------------------------------------------------------------------------
; Monster-tietue
;
; WORD MX
; WORD MY
; WORD Kestävyys
; WORD Laaki liikkeelä      
; LONG Bullet X             
; LONG Bullet Y             
; LONG AddX                     
; LONG AddY                     
; WORD Laaki liikkeellä     
; LONG Bullet X             
; LONG Bullet Y             
; LONG AddX                     
; LONG AddY                     
; WORD Laaki liikkeellä     
; LONG Bullet X             
; LONG Bullet Y             
; LONG AddX                     
; LONG AddY                     
; LONG BobData
; LONG MaskData

Monster ds.b    68

;------------------------------------------------------------------------------
; Unit rakenne.
; WORD Liikkellä 0/1        0
; LONG UnitX                2
; LONG UnitY                6
; WORD Laaki liikkeellä     10
; LONG Bullet X             12
; LONG Bullet Y             16
; LONG BulletAddX           20
; LONG BulletAddY           24
; LONG UnitBob              28
; LONG UnitBobMask          32
; LONG ExplodedUnit         36
; LONG ExplodedUnitMask     40
; WORD Kestävyys            44
; WORD Liikkuvako           46 Jos 0, niin liikkuu vain 1.:set 16 pikseliä
;--------------------------
;                       48
Units           ds.b    48*5
UnitsVanhaSij0  ds.b    10*5
UnitsVanhaSij1  ds.b    10*5
UnitsVBSij0     ds.b    10*5
UnitsVBSij1     ds.b    10*5

; UnitLiikkeellä, unit x, unit y, laaki liikkeellä, bullet X, bullet Y,
; UnitClearScr, UnitVanhaSij, UnitBulletClearScr, UnitBulletVanhaSij,
; UnitBob, UnitMask
;


;------------------------------------------------------------------------------
; Asteroids-tietue: Liikkeellä-merkki, x,y,speed, Kestävyys
;
; Tässä laitetaan 28 asteroidia
;

Asteroids       ds.w    5*28
VanhaAstSij0    ds.w    28+(4*28)
VanhaAstSij1    ds.w    28+(4*28)

;------------------------------------------------------------------------------
; Monsterille vanhasijaintistuff
MonstVanhaSij0  ds.b    10
MonstVanhaSij1  ds.b    10
MonstBVanhaSij0 ds.b    30
MonstBVanhaSij1 ds.b    30

;------------------------------------------------------------------------------
ScrollOffset    dc.l    (256+16+16)*4*32
LaakiPT         dc.l    0       ; Missä kohtaa laakeja ollaan menossa

Exp_PT          dc.l    0           ;
VanhaExpSij     dc.l    0
MExp_vanhasij   dc.l    0

UnitsVanhaSij   dc.l    0
UnitsVBSij      dc.l    0

VanhaAstSij     dc.l    0
VanhaSij        dc.l    0       ; Vihollisten vanha sijainti
VanhaESij       dc.l    0       ; Vihollisten laakien vanha sijainti

MonsterVanhaSij dc.l    0
MonstBVanhaSij  dc.l    0

coolfield       dc.l    0

x               dc.w    128
y               dc.w    235
MX              dc.w    32
MY              dc.w    -64
DX              dc.w    1

Nr_of_asteroids dc.w    0

LineN           dc.l    256     ; Blo(c)kin y-paikka
Bl_paikka       dc.l    0       ; Blo(c)kin x-paikka
pt_toCoolF      dc.l    0       ; 2048
pt_toClear      dc.l    0
Coords          dc.l    0
BitMap1         dc.l    0
BitMap2         dc.l    0
ClearScreen     dc.l    0       ; Pelkästään scrollaava alue 
ShowScreen      dc.l    0
DrawScreen      dc.l    0
AttackWavePointer dc.l  0
monster         dc.l   0

outfile         dc.l    0

Random          dc.w    0
Pisteet         dc.w    0

wbenchmsg       dc.l    0
oldview         dc.l    0
process         dc.l    0
processor       dc.w    0
chiprev         dc.b    0 

level           dc.b    1

LastCBFrames    dc.b    0
Kumpainen       dc.b    0
LameFrame       dc.b    0
Frame           dc.b    0
Laskuri         dc.b    0
NPohjassa       dc.b    0
AmEnemies       dc.b    0
MovingEBullets  dc.b    0       ; Liikkeellä olevien EnemyBullettien määrä
energia         dc.b    16

gameOver        dc.b    0

DoLastCoordBobFrames    dc.b 0
CoordBobsRunning        dc.b 0      ; Ovatko koordinaativalmiit bobit liikkeellä
nr_of_bobs              dc.b 0
Asteroids_on_screen     dc.b 0
AsteroidsRunning        dc.b 0
LastAsteroidFrames      dc.b 3
OwnBulletsOnScreen      dc.b 0
NrOfOwnBullets          dc.b 0
MonsterKehissa          dc.b 0
Monster_destroyed       dc.b 0
MExpFinished            dc.b 0
LastMExpFrames          dc.b 0

phase                   dc.b    0
delay                   dc.b    0
kierros                 dc.b    0

                        even

viive           dc.b  0
letterstyped    dc.b    0
currentchar     dc.b    'A'
small_font      dc.b    0
                    even
bitmap          dc.l    0
pt_Font         dc.l    0

hiscoretable
                    dc.l    Nimi1
                    dc.w    12345
                    dc.l    Nimi2
                    dc.w    2345
                    dc.l    Nimi3
                    dc.w    345
                    dc.l    Nimi4
                    dc.w    45
                    dc.l    Nimi5
                    dc.w    5

Nimi1               dc.b    "ABC",0
Nimi2               dc.b    "DEF",0
Nimi3               dc.b    "GHI",0
Nimi4               dc.b    "JKL",0
Nimi5               dc.b    "MNO",0

Nimi                dc.b    "   ",0,0,0,0,0,0,0,0,0
Luku                dc.b    0,0,0,0,0,0
LevelTXT            dc.b    "LEVEL?0",0,0

Number              dc.b     0,0,0,0,0
                even


; Vertical blanking -keskeytyksen strukture

Vert_str:       dc.l    0           ; Käyttis asettaa
                dc.l    0           ;
                dc.b    2           ; Nodetyyppi=NT_INTERRUPT
                dc.b    0           ; Priotiteetti
                dc.l    vertname
                dc.l    0           ; Kesk.rut.lle tuleva tieto
                dc.l    Keskeytysrutiini ; Kesk. alkuosoite

        section ChipData,DATA,CHIP

Coolfield       ds.b    5120*4
                dc.l    999     ; Loppumerrki
Coolfield2       ds.b    5120*4
                    dc.l       999
Coolfield3       ds.b    5120*4
                     dc.l       999

Dummy           dc.l    0

;EsBob          incbin  "Work:MyProjects/Game/BPL/NewEs.bob"
;EsMask         incbin  "Work:MyProjects/Game/BPL/NewEs.mask"
RengasBob       incbin  "Work:MyProjects/Game/BPL/Rengas.bob"
RengasMask      incbin  "Work:MyProjects/Game/BPL/Rengas.mask"

;UfoBob         incbin  "Work:MyProjects/Game/BPL/Ufo.bob"
;UfoMask        incbin  "Work:MyProjects/Game/BPL/Ufo.mask"
ShipBob         incbin  "Work:MyProjects/Game/BPL/alus.bob"
ShipMask        incbin  "Work:MyProjects/Game/BPL/alus.mask"
WBob            incbin  "Work:MyProjects/Game/BPL/w.bob"
WMask           incbin  "Work:MyProjects/Game/BPL/w.mask"
;ThreeShipBob   incbin  "Work:MyProjects/Game/BPL/3-osainen_alus.bob"
;ThreeShipMask  incbin  "Work:MyProjects/Game/BPL/3-osainen_alus.mask"

Bob             incbin  "Work:MyProjects/Game/BPL/es.bob"
Mask            incbin  "Work:MyProjects/Game/BPL/es.mask"
;LBob           incbin  "Work:MyProjects/Game/BPL/OmaLaaki.mask"
EnBulletBob     incbin  "Work:MyProjects/Game/BPL/newEnemyBullet.bob"
EnBulletMask    incbin  "Work:MyProjects/Game/BPL/newEnemyBullet.mask"
Blocks          incbin  "Work:MyProjects/Game/BPL/4BPLBlocks"
Unit            incbin  "Work:MyProjects/Game/BPL/Unit.bob"
UnitMask        incbin  "Work:MyProjects/Game/BPL/Unit.mask"
ExplodedUnit    incbin  "Work:MyProjects/Game/BPL/ExplodedUnit.bob"
ExplodedUnitM   incbin  "Work:MyProjects/Game/BPL/ExplodedUnit.mask"
AsteroidBob     incbin  "Work:MyProjects/Game/BPL/NewAsteroid.bob"
AsteroidMask    incbin  "Work:MyProjects/Game/BPL/NewAsteroid.mask"
Explosion       incbin  "Work:MyProjects/Game/BPL/Explosion8Frames"
ExplosionMask   incbin  "Work:MyProjects/Game/BPL/Explosion8Frames.mask"
MonsterBob      incbin  "Work:MyProjects/Game/BPL/Monster_draft_smaller.bob"
MonsterMask     incbin  "Work:MyProjects/Game/BPL/Monster_draft_smaller.mask"
MonsterBullet   incbin  "Work:MyProjects/Game/BPL/Monster_bullet.bob"
MonsterBulMask  incbin  "Work:MyProjects/Game/BPL/Monster_bullet.mask"
MonsterExplosionBob incbin "Work:MyProjects/Game/BPL/Monster_explosion_smaller_2.bo"
MonsterExplosionMask incbin "Work:MyProjects/Game/BPL/Monster_explosion_smaller_2.ma"
Monster2Bob     incbin  "Work:MyProjects/Game/BPL/Monster2_draft_smaller.bob"
Monster3Bob     incbin  "Work:MyProjects/Game/BPL/Monster3_draft_smaller.bob"

Score           incbin  "Work:MyProjects/Game/BPL/NewScore"
ScoreMask       incbin  "Work:MyProjects/Game/BPL/NewScore.mask"

Numbers         incbin  "Work:MyProjects/Game/BPL/NewNumbers"
NumbersMask     incbin  "Work:MyProjects/Game/BPL/NewNumbers.mask"

    even

CopperLista
        dc.w    $00e0
high1   dc.w    $0000
        dc.w    $00e2
low1    dc.w    $0000
        dc.w    $00e4
high2   dc.w    $0000
        dc.w    $00e6
low2    dc.w    $0000
        dc.w    $00e8
high3   dc.w    $0000
        dc.w    $00ea
low3    dc.w    $0000
        dc.w    $00ec
high4   dc.w    $0000
        dc.w    $00ee
low4    dc.w    $0000
        dc.w    $0100,$4200
        dc.w    $0102,$0000
        dc.w    $0108,$0060
        dc.w    $010a,$0060
        dc.w    $0092,$0048
        dc.w    $0094,$00c0
        dc.w    $008e,$2c81
        dc.w    $0090,$2ca1

        dc.w    $0120
s0_high dc.w    $0000
        dc.w    $0122
s0_low: dc.w    $0000
        dc.w    $0124
s1_high dc.w    $0000
        dc.w    $0126
s1_low: dc.w    $0000
        dc.w    $0128
s2_high dc.w    $0000
        dc.w    $012a
s2_low  dc.w    $0000
empty   dc.w    $012c
        dc.w    $0000
        dc.w    $012e
        dc.w    $0000
        dc.w    $0130
        dc.w    $0000
        dc.w    $0132 
        dc.w    $0000
        dc.w    $0134
        dc.w    $0000
        dc.w    $0136
        dc.w    $0000
        dc.w    $0138
        dc.w    $0000
        dc.w    $013a
        dc.w    $0000
        dc.w    $013c,$0000
        dc.w    $013e,$0000

Colours
        dc.w    $0182,$0000
        dc.w    $0184,$0000
        dc.w    $0186,$0000
        dc.w    $0188,$0000
        dc.w    $018a,$0000
        dc.w    $018c,$0000
        dc.w    $018e,$0000
        dc.w    $0190,$0000
        dc.w    $0192,$0000
        dc.w    $0194,$0000
        dc.w    $0196,$0000
        dc.w    $0198,$0000
        dc.w    $019a,$0000
        dc.w    $019c,$0000
        dc.w    $019e,$0000

; Energiapalkin värit

        dc.w    $3101,$ff00,$01aa,$0ff0
        dc.w    $3201,$ff00,$01aa,$0cf0
        dc.w    $3301,$ff00,$01aa,$09f0
        dc.w    $3401,$ff00,$01aa,$06f0
        dc.w    $3501,$ff00,$01aa,$03f0
        dc.w    $3601,$ff00,$01aa,$00f0
        dc.w    $3701,$ff00,$01aa,$00f3
        dc.w    $3801,$ff00,$01aa,$00f6
        dc.w    $3901,$ff00,$01aa,$00f9
        dc.w    $3a01,$ff00,$01aa,$00fc
        dc.w    $3b01,$ff00,$01aa,$00ff
        dc.w    $3c01,$ff00,$01aa,$00cf
        dc.w    $3d01,$ff00,$01aa,$009f
        dc.w    $3e01,$ff00,$01aa,$006f
        dc.w    $3f01,$ff00,$01aa,$003f
        dc.w    $4001,$ff00,$01aa,$000f

;           dc.w    $4101,$ff00,$01aa,$0fff

        dc.w    $ffff,$fffe


SPR2    dc.l    $00000000
        dc.l    $e0000000,$e0000000,$e0000000,$e0000000
        dc.l    $e0000000,$e0000000,$e0000000,$e0000000
        dc.l    $e0000000,$e0000000,$e0000000,$e0000000
        dc.l    $e0000000,$e0000000,$e0000000,$e0000000
        dc.l    $00000000

; Aluksi oma sprite-alus, sitten spritelaakit (30)
SPR1            dc.w    $0000,$0000,$0100,$0000,$4284,$0180,$A28A,$6186,$A44A,$63C6,$A44A,$63C6,$A92A,$66E6,$AAAA,$65E6,$B29A,$6DF6
                dc.w    $B45A,$6BF6,$B55A,$6BF6,$B55A,$6AF6,$B45A,$6BF6,$F7DE,$2872,$1010,$0FF0,$1FF0,$0010,$0000,$0000
                
SPR0            dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000

                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000

                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000
                dc.w    $0000,$0000,$2000,$0000,$5000,$3000,$5000,$3000,$5000,$3000,$8800,$7800,$8800,$7800,$8800,$7800,$7000,$7000

                dc.w    $0000,$0000

;mt_data        incbin  "ram:thinktwiceiii.mod"

       end


Many, many years ago I came up with an idea about a fractal that would be based on right triangles and squares. People that had less mathematical experience than I, didn’t take me seriously, when I told about my idea. They thought that this was just some kind of nonsense.

I didn’t visualize my idea and forgot the whole thing… Later, after many years when I started to read e-books about fractals, I found sophisticated ideas how to make nice colored Pythagorean fractal trees. I think I’ve been dealing with wrong people in the past… 🙂

This article discusses only about simplest possible Pythagorean fractal tree, most symmetrical version of it.

We start with a right triangle with two 45 degrees angles and one 90 degrees angle and visually speaking turn the triangle so that hypotenuse is at the bottom:

right triangle

 

Next we draw squares against the sides of the triangle so that the length of the side of the square is the length of the side of the triangle:

squares and triangle
Next we imagine new right triangles to the farthest side of the ”branch” squares and do the same process as earlier: We draw squares to all the sides of the triangles.

This process is continued infinitely and we have a fractal! …that looks like a tree.pytree

The length of the new hypotenuse c‘ = cos(45°) * c, where c is the length of the hypotenuse of previous iteration loop’s right triangle(s).

When generating the tree, I recommend using Java with JavaFX package or using JavaScript, because with those one can use the following methods:

  • beginPath
  • translate
  • rotate
  • save
  • restore

These methods make it quite easy to generate a fractal tree. When drawing the tree into screen, only the squares are drawn.

The e-book below discusses lots of fractal programming and has also an example codes in JavaScript generating these kinds of trees (also colored):


The Cantor’s set is somewhat fascinating fractal, when one gets to more familiar with it.

The basic idea is to handle real number interval [0,1]. This is divided to three parts of same width removing the middle part. The remaining parts are again divided to three parts of same width removing always the middle part. This is continued infinitely.

The Cantor’s set consists of the points that are left in this process.

In the language of the set theory the Cantor’s set can be expressed as follows:

Cantorin joukko

The union tells what doesn’t belong to the set.

I have used this formula to implement the Cantor’s set in my program. The idea is to examine the union interval and draw a pixel, when the point does belong to the set.

Below is a picture from the program’s output:

Cantor set

 

Here’s the Java program in full:

import java.awt.*;
import javax.swing.*;
import java.awt.event.WindowEvent;
import java.awt.event.WindowAdapter;
import java.lang.Math;

public class Cantor {

    private JFrame frame;
    private CantorPanel panel;
    
    public Cantor() {
        frame = new JFrame("The Cantor's Set");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        initialize();
        frame.pack();
        frame.setVisible(true);
    }
    
    private void initialize() {
        panel = new CantorPanel();
        frame.getContentPane().add(panel);
    }
    
    public static void main(String args[]) {
        new Cantor();
    }
}
    
class CantorPanel extends JPanel {
    
    public CantorPanel() {
        
        setBackground(Color.lightGray);
        setPreferredSize(new Dimension(1024,100));
    }
    
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;

        drawCantor(g, 7);
    }
    
    public void drawCantor(Graphics g, int maxIter) {
        
        int y = 17;
        
        for (int m = 1; m < maxIter + 1; m++) {

            for (int x = 0; x < 1024; x++) {
            
                if (belongsToSet(m,x) == true) g.drawOval(x,y,1,1);
            }
            y = y + 10;
        }
    }
    
    public boolean belongsToSet(int m, double x) {

        double line = 1024;
        double x1,x2;

        for(int mm = 1; mm < m ; mm++) {
                
            for (int k = 0; k < (int)((Math.pow(3,(mm-1))) - 1 + 1); k++) {

                x1 = (3.0*k + 1) / Math.pow(3.0,mm);
                x2 = (3.0*k + 2) / Math.pow(3.0,mm);
            
                if ((x > x1 * line) && (x < x2 * line)) return false;
    
            }

        }
        return true;
    }
    
}

Because of the calculation precision with “big” number of iterations drawing accuracy isn’t very good.

The program is free for personal and educational use.

On Georg Cantor


Mathematically the number of digits in given integer > 0 can be determined with logarithm.

The number of digits in an integer > 0 is

Trunc(Logk(number)) + 1

Trunc comes from the Pascal programming language and means truncation. ”number” is 10 base system number of k base system number.

The idea is to examine how many powers of base system k there is in the number, that is how many times the given number can be divided with the base number until we get number < 1. With this our friend logarithm helps us to determine that. As a reminder, logarithm is reverse operation to power.

Examples:

In 10 base system in number 12345678 there is 7 powers of 10: Trunc(Log1012345678) = 7, the number of digits is 7 + 1 = 8.

The hexdecimal system number 99916 = 245710, Log16 2457 = 2.8156…, the number of digits is 2 + 1 = 3.

Hex number FF16 = 25510, Log16 255 = 1.9985…, the number of digits is 1 + 1 = 2.

Binary number (k = 2) 100000002 = 128, Log2 128 = 7, the number of digits is 7 + 1 = 8.

Binary number 101000012 = 16110, Trunc(Log2 161) = Trunc(7.33091…) = 7, the number of digits is 7 + 1 = 8.

ID-100291565

Image courtesy of Stuart Miles at FreeDigitalPhotos.net

Via programming the number of digits can be determined by dividing the number by the base system number k until the number being divided is < 1. Now the number of digits is the number of divisions.

Below is a C programming language program that determines the number digits of 10 base system number that can be positive or negative decimal number:

#include <stdio.h>
#include <math.h>

int detDigits(double);

void main(void) {

  double decimalnumber;
  int number_of_digits;

  printf("Give a decimal number: ");
  scanf("%lf", &decimalnumber);

  number_of_digits = detDigits(decimalnumber);

  printf("The number of digits is %d.",number_of_digits);

}

int detDigits(double dn) {

  int digits_integer_part, digits_decimal_part;
  int worknumber;

  if (dn == 0) return 1;

  if (dn < 0) dn = -dn;

  digits_integer_part = ((int)log10(dn)) + 1;
  dn = dn – (int)dn;

  worknumber = (int) dn;

  while (worknumber % 10 != 0) {
    dn = dn * 10;
    worknumber = (int)dn;
}

/* Variable "worknumber" now holds the number of digits
of decimal part of the given number + 1 */

  digits_decimal_part = worknumber – 1;

  return digits_integer_part + digits_decimal_part;
}

Another way of determining the number of the digits is of course converting the decimal number to string and by examining the number of characters.


The Mandelbrot Set is one of the most famous fractals. This fractal carries the name of the French mathematician Benoit Mandelbrot (1924 – 2010). The first ones how implemented the Mandelbrot Set with computer where mathematicians Robert Brooks and Peter Matelski.

The mathematical definition of the Mandelbrot Set

The Mandelbrot Set is set M, where belong all the points c, to which zn is finite, when n approaches infinity, where

z0 = c

zn+1 = zn2 + c

The initial point is (0,0i). Here both z and c are complex numbers. The c is held constant and z is variable that’s value changes.

The Mandelbrot Set on the complex plane

The Mandelbrot Set is typically generated from rectangle on the complex plane from bottom left (-2.25 -1.5i) and upper right (0.75 + 1.5i). The zooming of the Mandelbrot Set is done by selecting different coordinates on this rectangle from somewhere on the border of the set. See the picture below:

mandelbrot
The set M is the black area in the picture. The other colors represent the distance from the set. In a way when you’re looking other colors than black, you’re watching infinity.

The helpful proof

Fortunately there’s is mathematical proof, that says that is sufficient to test that is the absolute value of iterated point > 2. If the absolute value of iterated complex number is greater than 2, the iterated point is to divergence to infinity and does not belong to the set. Otherwise the point belongs to the set.

The idea of the generating the Mandelbrot Set

The recursive formula will be implemented by iterative way.

The Mandelbort set is generated to computer screen by taking each pixel point and by choosing that point as constant C (after converting this to correspond the complex plane point). When each iteration loop begins, z is first set to (0 + 0i). Next the formula z = z + c is iterated with checking if z is to divergence to infinity by calculating the absolute value of z. If the absolute value of z > 2, the point is to divergence to infinity and does not belong to the set. Otherwise the point belongs to set.

Imagine each pixel point as a point on the chosen complex plane rectangle.

Pixel’s width and height on the complex plane are calculated as follows:

dr = (maxR - minR) / SCREEN_WIDTH
di = (maxI - minI) / SCREEN_HEIGHT

Other thing to consider is the scale of the picture: The complex plane rectangle’s ratio must be scaled to same as screen area’s ratio.

This is calculated as follows:

The width of the rectangle wmaxR – minR
The height of the rectangle h = maxI – minI
Scaled width sW = h * (SCREEN_WIDTH / SCREEN_HEIGHT)
Difference of the scaled width and original width: diff = sW – w

Next we subtract half of the difference of the widths from the left side of the complex plane rectangle and add half of the difference of the widths to the right side of the complex plane rectangle:

minR = minR – diff / 2
maxR = maxR + diff / 2

Now the length of the complex plane rectangle is scaled to screen’s width. In practice SCREEN_WIDTH can refer in general to width of the screen’s pixel rectangle’s width.

Below is complete BlitzMax program that generates the Mandelbrot set and scales the complex plane rectangle to same ratio as the screen area’s ratio:

Const SCREEN_WIDTH:Int = 640
Const SCREEN_HEIGHT:Int = 480
Const MAX_ITER:Int = 32

Graphics SCREEN_WIDTH, SCREEN_HEIGHT

 Global minR:Float = -2.25, maxR:Float = 0.75
 Global minI:Float = -1.5, maxI:Float = 1.5

 Global dr:Float, di:Float

 Local w:Float, h:Float, sW:Float, diff:Float
 Local shade:Int

 w = maxR - minR
 h = maxI - minI
 sW = h * (Float(SCREEN_WIDTH) / Float(SCREEN_HEIGHT))
 diff = sW - w

 minR = minR - diff / 2
 maxR = maxR + diff / 2

 dr = (maxR - minR) / SCREEN_WIDTH
 di = (maxI - minI) / SCREEN_HEIGHT

 For Local y:Int = 0 To SCREEN_HEIGHT - 1
  For Local x:Int = 0 To SCREEN_WIDTH - 1
   shade = mandelbrot(x,y)
   shade = 255 - Float(MAX_ITER - shade) / 32.0 * 255.0
   SetColor 0,0,shade
   Plot x,y
  Next
Next

Flip
WaitKey
End

Function mandelbrot:Int(x,y)

 Local iterations:Int = 0

 Local cr:Float = minR + x * dr
 Local ci:Float = minI + y * di
 Local zr:Float = 0.0
 Local zi:Float = 0.0
 Local zr_temp:Float = 0.0
 Local zi_temp:Float = 0.0

 While (iterations < MAX_ITER)
  zr_temp = zr * zr - zi * zi + cr
  zi_temp = 2.0 * zr * zi + ci
  zr = zr_temp
  zi = zi_temp

  iterations = iterations + 1
  ' Below is same as sqrt(zr^2 + zi^2) > 2.0
  ' but faster
  If zr * zr + zi * zi > 4.0 Then Return iterations

 Wend

 Return 0

End Function

With greater amount of iterations it may be the case, that a point that doesn’t diverge to infinity with lower amount of iterations, diverges to infinity with greater amount of iterations. Thus, with computers in fact every generated Mandelbrot set picture is some kind of approximation of the Mandelbrot set.

Shortly about the colors

If the point c belongs to the set, the pixel is usually colored black. The other colors are calculated from the iterations. Easiest way to calculate different shades from the iterations is the following:

shade = mandelbrot(x,y) ; The function returns the number of iterations
shade = 255 - (MAX_ITERATIONS - shade) / MAX_ITERATIONS * 255

This gives values 0…255 to variable shade.

Below is is picture from rectangle, that’s bottom left is (-0.22 – 0.70i) and upper right is (-0.21 – 0.69i) with different kind of coloring:

mandelbrot2

Here the maximum amount of iterations is 250. In this case the number of iterations has dramatic impact to the generated picture. How colorful can the infinity be!

Mandelbrot mountain

For curiosity below is a Mandelbrot mountain generated with Python program (also my own program):

mandelbrot3

The program uses the Mayavi extension, which makes it easy to do 3D visualization.

Amazon e-books on fractals

I recommend especially

If you’re interested in generating Mandelbrot or Julia set mountains, I recommend the e-book below: