Ideas in the Night

Tag Archives: programming

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

Advertisements

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


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 w = maxR – 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: