THINK and WORK

A small game published in the Happy Computer magazine, written by Johann Schilcher for the Atari XL. I copied the levels and wrote the game from the scratch for the Atari ST. It was published with the source code together with the TurboAss and can now be found at GitHub.

  • LEVEL.DAT The file with the levels
  • THNKWORK.PIC Atari ST 640×400 b/w bitmap with the b/w images
  • THNKWORK.PI2 Atari ST 640×200 4 color bitmap with the color images

The image files can be opened with GraphicConverter.

The original source code (also on GitHub)

                OPT F+      ;Fast-Load (siehe 68000er 11/89)
                OPT X+      ;Symboltabelle an (für den Debugger)
                IFEQ ^^SYMTAB
                DEFAULT 9
                OUTPUT 'TNHKWORK'
                ELSE
                DEFAULT 8
                ENDC

max_level       EQU 100     ;max.Anzahl der Level
;************************************************************************
;*                     Think & Work ST-Version                          *
;*       nach einer Idee von Johann Schilcher (Atari XL-Version)        *
;*          Die Level entsprechen den Leveln auf dem Atari XL           *
;* ©1989 by ∑-soft, written by Markus Fritze              13-15.01.1989 *
;*      ----------> Graphix by Harald Weinreich <-------------  1.2.'89 *
;************************************************************************
                BASE A6,varbase
                TEXT
                pea     start(PC)
                move.w  #$26,-(SP)
                trap    #14             ;Superexec(start)
                addq.l  #6,SP
                clr.w   -(SP)
                trap    #1              ;Pterm0()

start:          lea     varbase(PC),A6  ;Globale Offset-Variable
                bsr     init
                clr.w   akt_level(A6)   ;Nach dem Demo auf Level 1 schalten
                move.w  #-1,demo_level(A6) ;Start bei Level "-1" = Titeldemo
                bra     demo            ;Titeldemo laufen lassen
restart_clr:    clr.b   dir(A6)         ;Joystick-Richtungen löschen
restart:        move.w  save_level(A6),D0
                bmi.s   restart1
                move.w  D0,akt_level(A6) ;Level setzen
restart1:       clr.w   big_score(A6)   ;Gesamtscore löschen
                sf      demo_mode(A6)   ;Demo-Mode aus
                clr.w   timer2(A6)      ;Timer für den Demo-Mode löschen
                st      save_level(A6)  ;ungültig machen
                st      out_of_game(A6) ;Spiel nicht aktiv
                tst.w   level_anz(A6)   ;Level vorhanden?
                bne.s   menü_loop       ;ja, alles ok
                lea     all_level_data(A6),A0 ;Hier stehen die Level
                moveq   #15,D0
restart2:       tst.l   (A0)+           ;Level komplett leer?
                dbne    D0,restart2
                beq.s   menü_loop       ;ja! =>
                move.w  #1,level_anz(A6) ;Sonst ist min. ein Level vorhanden
menü_loop:      lea     text2(A6),A0
                bsr     print_text
                move.w  level_anz(A6),D1 ;Levelanzahl
                lea     restart(PC),A5  ;Rücksprungadr
                bsr     get_key         ;Tastatur auswerten, Joystick auch
                cmpi.w  #10*200,timer2(A6) ;Das Demo startet nach 10 Sekunden
                bcc     demo
                tst.b   dir(A6)         ;Feuertaste?
                bmi     play_game       ;dann das Spiel starten
                btst    #0,dir(A6)
                bne     inc_level
                btst    #1,dir(A6)
                bne     dec_level
                move.w  key(A6),D0
                subi.w  #$3B,D0
                bmi.s   menü_loop
                cmp.w   #9,D0           ;keine F-Taste ?
                bhi.s   menü_loop
                add.w   D0,D0
                move.w  menü_jumps(PC,D0.w),D0
                jmp     menü_jumps(PC,D0.w)

                BASE DC.W,menü_jumps
menü_jumps:     DC.W play_game,editor,dec_level,inc_level,joykey
                DC.W autorep,copyright,load_levels,save_levels,exit

;*******************************************************************************
;* Der Copyright-Hinweis                                                       *
;*******************************************************************************
copyright:      clr.w   timer2(A6)
                lea     copyright_txt(A6),A0
                bsr     print_text
copyright1:     bsr     get_key
                cmpi.w  #10*200,timer2(A6) ;Demo startet nach 10 Sekunden
                bcc     demo
                tst.w   key(A6)
                beq.s   copyright1
                jmp     (A5)

;*******************************************************************************
;* Der Leveleditor                                                             *
;*******************************************************************************
editor:         lea     all_level_data(A6),A4 ;Hier stehen die originalen Level
                move.w  akt_level(A6),D0
                lsl.w   #6,D0
                adda.w  D0,A4           ;Adresse des akt.editierten Levels
                movea.l A4,A1
                lea     level_buffer(A6),A0
                moveq   #15,D0
editor_save:    move.l  (A1)+,(A0)+     ;Level retten
                dbra    D0,editor_save
                sf      out_of_game(A6) ;Spiel aktiv (Blöcke setzen)
                moveq   #10,D6          ;aktuelle X-Koordinate
                moveq   #6,D7           ;aktuelle Y-Koordinate
                moveq   #2,D5           ;Wall selected
                clr.b   dir(A6)         ;Joystick-Daten löschen
editor_loop:    bsr     init_level      ;Levelarray aufbauen, Zeit löschen, etc.
                bsr     plot_level      ;Level zeichnen
                movea.l logbase(A6),A1
                move.w  D7,D0           ;Y*32*80
                mulu    #32*80,D0
                adda.w  D0,A1           ;zur logbase
                move.w  D6,D0
                lsl.w   #2,D0           ;X*4
                tst.b   rez(A6)         ;Farbe oder s/w
                bpl.s   editor_pnt1
                lea     farb_grafik+7*128(A6),A0
                add.w   D0,D0           ;X*8
                adda.w  D0,A1
                moveq   #15,D1
editor_pnt0:    move.l  (A0)+,D0        ;Cursor darstellen
                or.l    D0,(A1)+
                move.l  (A0)+,D0        ;Cursor darstellen
                or.l    D0,(A1)
                lea     156(A1),A1
                dbra    D1,editor_pnt0
                bra.s   editor_pnt2
editor_pnt1:    lea     mono_grafik+7*128(A6),A0
                adda.w  D0,A1           ;zur logbase
                moveq   #31,D1
editor_pointer: move.l  (A0)+,D0        ;Cursor darstellen
                eor.l   D0,(A1)
                lea     80(A1),A1
                dbra    D1,editor_pointer
editor_pnt2:    lea     text3(A6),A0
                bsr     print           ;untere Textzeile neu ausgeben
                bsr     switch_screen   ;Seite anzeigen
                bsr     get_key         ;Tastatur auswerten, Joystick auch
                btst    #0,dir(A6)      ;Joystickbewegung umsetzen
                beq.s   editor_jump1
                subq.w  #1,D7
                bpl.s   editor_jump1
                moveq   #0,D7
editor_jump1:   btst    #1,dir(A6)
                beq.s   editor_jump2
                cmp.w   #11,D7
                beq.s   editor_jump2
                addq.w  #1,D7
editor_jump2:   btst    #2,dir(A6)
                beq.s   editor_jump3
                subq.w  #1,D6
                bpl.s   editor_jump3
                moveq   #0,D6
editor_jump3:   btst    #3,dir(A6)
                beq.s   editor_jump4
                cmp.w   #19,D6
                beq.s   editor_jump4
                addq.w  #1,D6
editor_jump4:   tst.b   dir(A6)
                beq.s   editor_jump6
                bsr     verzögerung
editor_jump6:   btst    #7,dir(A6)      ;Feuertaste gedrückt
                bne     edt_draw
                clr.b   button_pressed(A6) ;Flag zurücksetzen
                lea     editor_keys-2(PC),A0
                move.w  key(A6),D0      ;aktuelle Taste holen
editor_jump5:   addq.l  #2,A0
                tst.w   (A0)
                bmi     editor_loop
                cmp.w   (A0)+,D0
                bne.s   editor_jump5
                adda.w  (A0),A0
                jmp     (A0)

                BASE DC.W,*
editor_keys:    DC.W $3B,edt_wall ;F1 - Mauer setzen
                DC.W $3C,edt_target ;F2 - Target setzen
                DC.W $3D,edt_block ;F3 - Block setzen
                DC.W $3E,edt_exit ;F4 - EXIT setzen
                DC.W $47,edt_clr_all ;Clr/Home - Level löschen
                DC.W $61,edt_undo ;UNDO - Level rekonstruieren
                DC.W $44,restart_clr ;F10 - Editor verlassen
                DC.W $39,edt_plot ;Space - Zeichen setzen
                DC.W $31,edt_new ;N - Neuen Level einrichten
                DC.W $53,edt_delete ;Delete - Level löschen
                DC.W -1

edt_delete:     bsr.s   edt_clr_all     ;Level erstmal löschen
                move.w  level_anz(A6),D0
                beq.s   edt_delete2     ;keine Level mehr da!
                subq.w  #1,D0
                move.w  D0,level_anz(A6)
                lea     all_level_data+64*max_level(A6),A0 ;Daten aller Level
                movea.l A4,A2
                lea     64(A4),A1
edt_delete1:    move.l  (A1)+,(A2)+     ;Level überkopieren
                cmpa.l  A0,A1
                bcs.s   edt_delete1
edt_delete2:    bra.s   edt_new1        ;ab in die Hauptschleife

edt_new:        move.w  level_anz(A6),D0
                cmp.w   #max_level-1,D0 ;max.100 Level
                beq.s   edt_new1
                move.w  D0,akt_level(A6)
                addq.w  #1,level_anz(A6)
                lea     all_level_data(A6),A4 ;Hier stehen die originalen Level
                lsl.w   #6,D0
                adda.w  D0,A4           ;Adresse des akt.editierten Levels
edt_clr_all:    movea.l A4,A1
                moveq   #15,D0          ;Level löschen
edt_clr_all1:   clr.l   (A1)+
                dbra    D0,edt_clr_all1
edt_new1:       bra     editor_loop     ;ab in die Hauptschleife

edt_wall:       moveq   #2,D5           ;Wand
                bra.s   edt_new1
edt_target:     moveq   #1,D5           ;Zielfeld
                bra.s   edt_new1
edt_block:      moveq   #3,D5           ;Block
                bra.s   edt_new1
edt_exit:       moveq   #-1,D5          ;Ausgang (nur zu verschieben)
                bra.s   edt_new1

edt_undo:       movea.l A4,A1
                lea     level_buffer(A6),A0
                moveq   #15,D0
edt_undo1:      move.l  (A0)+,(A1)+     ;Level zurückholen
                dbra    D0,edt_undo1
                bra.s   edt_new1

edt_plot:       clr.b   button_pressed(A6)
edt_draw:       tas.b   button_pressed(A6)
                bne.s   edt_draw1       ;war schon gedrückt
                moveq   #-1,D4          ;Löschen?
                bsr.s   edt_get         ;akt.Zeichen holen
                cmp.b   D0,D5
                beq.s   edt_draw1       ;steht dort was? =>
                moveq   #0,D4           ;sonst setzen
edt_draw1:      move.w  D5,D3
                tst.b   D4              ;setzen oder löschen?
                beq.s   edt_draw2       ;setzen
                moveq   #0,D3           ;löschen
edt_draw2:      tst.w   D5              ;Exit? (Ist nur verschiebbar)
                bpl.s   edt_draw3       ;Nein =>
                move.w  D6,D0
                add.b   D0,D0
                move.b  D0,60(A4)
                move.w  D7,D0
                add.b   D0,D0
                or.b    #$80,D0
                move.b  D0,61(A4)
                bra     editor_loop

edt_draw3:      move.w  D7,D0           ;Position im Level errechnen
                lsl.w   #2,D0
                add.w   D7,D0
                move.w  D6,D1
                lsr.w   #2,D1
                add.w   D1,D0           ;D0=5*Y+Int(X/4)
                moveq   #3,D1
                and.w   D6,D1           ;D1=X and %11
                move.b  edt_put_tab2(PC,D1.w),D2 ;Byte holen
                and.b   D2,0(A4,D0.w)   ;entsprechendes Feld löschen
                move.b  edt_put_tab(PC,D1.w),D1
                lsl.b   D1,D3           ;Element in Position schieben
                or.b    D3,0(A4,D0.w)   ;und einsetzen
                bra     editor_loop

edt_put_tab:    DC.B 6,4,2,0 ;Verschiebetabelle
edt_put_tab2:   DC.B $3F,$CF,$F3,$FC ;Löschmaske

edt_get:        move.w  D7,D0           ;Position im Level errechnen
                lsl.w   #2,D0
                add.w   D7,D0
                move.w  D6,D1
                lsr.w   #2,D1
                add.w   D1,D0           ;D0=5*Y+Int(X/4)
                moveq   #3,D1
                and.w   D6,D1           ;D1=X and %11
                move.b  edt_put_tab(PC,D1.w),D1 ;Byte holen
                move.b  0(A4,D0.w),D0   ;eines der 4 Felder isolieren
                lsr.b   D1,D0           ;in die unteren 2 Bit schieben
                and.w   #3,D0
                rts

;*******************************************************************************
;* Die restlichen F-Tasten                                                     *
;*******************************************************************************
load_levels:    move.l  #'load',D0
                bsr     do_dialog       ;Wirklich laden?
                beq     restart_clr     ;NEIN! =>
do_load_levels: move.w  #$2F,-(SP)
                trap    #1              ;Fgetdta()
                addq.l  #2,SP
                movea.l D0,A4           ;DTA-Buffer-Adr merken
                move.w  #7,-(SP)
                pea     fname(A6)
                move.w  #$4E,-(SP)
                trap    #1              ;Fsfirst(path,satt)
                addq.l  #8,SP
                tst.l   D0
                bmi.s   load_levelerr   ;nicht gefunden
                move.l  26(A4),D7       ;Länge der Datei
                moveq   #$3F,D0
                and.w   D7,D0
                bne.s   load_levelerr   ;Dateilänge nicht durch 64 teilbar
                clr.w   -(SP)
                pea     fname(A6)
                move.w  #$3D,-(SP)
                trap    #1              ;Fopen(path,attr)
                addq.l  #8,SP
                move.w  D0,D6           ;fhandle merken
                bmi.s   load_levelerr   ;??? TOS-Fehler
                pea     all_level_data(A6) ;Adresse des Buffers
                move.l  D7,-(SP)        ;Dateilänge
                move.w  D6,-(SP)        ;fhandle
                move.w  #$3F,-(SP)
                trap    #1              ;Fread(hndl,byts,buff)
                lea     12(SP),SP
                move.l  D0,D5
                move.w  D6,-(SP)
                move.w  #$3E,-(SP)
                trap    #1              ;Fclose(hndl)
                addq.l  #4,SP
                cmp.l   D5,D7
                bne.s   load_levelerr   ;Datei nicht komplett gelesen
                lsr.l   #6,D7
                move.w  D7,level_anz(A6) ;Anzahl der geladenen Level setzen
                moveq   #0,D0
                jmp     (A5)
load_levelerr:  lea     all_level_data(A6),A4
                bsr     edt_clr_all     ;1.Level löschen
                clr.w   level_anz(A6)   ;keine Level da!
                moveq   #-1,D0
                jmp     (A5)

save_levels:    move.l  #'save',D0
                bsr     do_dialog       ;Wirklich speichern?
                beq     restart_clr     ;NEIN! =>
                moveq   #0,D7
                move.w  level_anz(A6),D7
                beq.s   save_levelerr   ;keine Levels zum Speichern
                lsl.l   #6,D7           ;mal 64 (Levelgröße) = Dateilänge
                pea     fname(A6)
                move.w  #$41,-(SP)
                trap    #1              ;Fdelete(path)
                addq.l  #6,SP
                clr.w   -(SP)
                pea     fname(A6)
                move.w  #$3C,-(SP)
                trap    #1              ;Fcreate(path,attr)
                addq.l  #8,SP
                move.w  D0,D6           ;fhandle merken
                bmi.s   save_levelerr   ;??? TOS-Fehler
                pea     all_level_data(A6) ;Adresse des Buffers
                move.l  D7,-(SP)        ;Dateilänge
                move.w  D6,-(SP)        ;fhandle
                move.w  #$40,-(SP)
                trap    #1              ;Fwrite(hndl,byts,buff)
                lea     12(SP),SP
                move.l  D0,D5
                move.w  D6,-(SP)
                move.w  #$3E,-(SP)
                trap    #1              ;Fclose(hndl)
                addq.l  #4,SP
                cmp.l   D5,D7
                bne.s   save_levelerr   ;Datei nicht komplett geschrieben
                moveq   #0,D0
                jmp     (A5)
save_levelerr:  moveq   #-1,D0
                jmp     (A5)

inc_level:      addq.w  #1,akt_level(A6)
                cmp.w   akt_level(A6),D1
                bhi.s   inc_level1
                clr.w   akt_level(A6)
inc_level1:     jmp     (A5)

dec_level:      subq.w  #1,akt_level(A6)
                bpl.s   dec_level1
                tst.w   D1
                beq.s   dec_level2
                subq.w  #1,D1
dec_level2:     move.w  D1,akt_level(A6)
dec_level1:     jmp     (A5)

joykey:         lea     joy_text(A6),A0
                lea     joy1_txt(A6),A1 ;Joystick
                cmpi.b  #'K',(A0)
                beq.s   joykey1
                lea     joy2_txt(A6),A1 ;Keyboard
joykey1:        move.b  (A1)+,(A0)+
                bne.s   joykey1
                move.b  #' ',-(A0)
                jmp     (A5)

autorep:        bchg    #1,$0484.w
                bsr     set_autorep_txt
                jmp     (A5)

;*******************************************************************************
;* Ein kleines Demo für den Titel & Level 1                                    *
;*******************************************************************************
demo:           move.w  akt_level(A6),save_level(A6) ;akt.Level merken
                move.w  demo_level(A6),D0
                addq.w  #1,D0
                and.w   #1,D0
                move.w  D0,demo_level(A6)
                subq.w  #1,D0           ;Die Demo-Level zählen ab 0
                move.w  D0,akt_level(A6) ;Die normalen Level zählen ab -1
                st      demo_mode(A6)   ;Demo-Mode an
                st      demo_count2(A6) ;gespeicherte Schritte löschen
                clr.w   demo_count(A6)  ;Demo-Position auf den Anfang setzen
demo1:

;*******************************************************************************
;* Die Hauptroutine: Das Game                                                  *
;*******************************************************************************
play_game:      sf      out_of_game(A6) ;Spiel nun aktiv
                bsr     init_level      ;Levelarray aufbauen, Zeit löschen, etc.
                st      timer_stop(A6)  ;Uhr starten
play_game1:     bsr     plot_level      ;Level zeichnen
                bsr     update_line     ;untere Textzeile neu ausgeben
                bsr     switch_screen   ;Seite anzeigen
                bsr     get_key         ;Tastatur auswerten, Joystick auch
                move.w  key(A6),D0
                tst.b   demo_mode(A6)   ;Demo an?
                beq.s   play_game11     ;Dann geht's hinten weiter ...
                tst.w   D0              ;Taste gedrückt?
                bne     restart_clr     ;dann Ende
play_game11:    cmpi.w  #$44,D0         ;F10 - Abbruch
                beq     restart_clr
                cmpi.w  #$61,D0         ;UNDO - Level neu starten
                beq.s   play_game       ;Level-Neustart
                cmpi.w  #$39,D0         ;Pause
                bne.s   play_game5      ;Nein! =>
                clr.b   timer_stop(A6)  ;Uhr stoppen
                movea.l logbase(A6),A0  ;2. Seite ist am Anfang "logbase"
                move.w  #7999,D0
                moveq   #-1,D1
play_game2:     move.l  D1,(A0)+        ;logbase löschen
                dbra    D0,play_game2
                bsr     switch_screen   ;und schwarze Seite anzeigen
                clr.w   key(A6)
                clr.b   dir(A6)
play_game3:     bsr     get_key
                tst.w   key(A6)         ;weiter, wenn Taste gedrückt
                bne.s   play_game4
                tst.b   dir(A6)         ;oder Joystick bewegt
                beq.s   play_game3
play_game4:     st      timer_stop(A6)  ;Uhr wieder starten
play_game5:     bsr     movement        ;Spieler bewegen
                bsr.s   check_win       ;Alle Steine ok?
                beq.s   play_game1      ;Nein, noch nicht.

                tst.b   demo_mode(A6)
                bne     restart_clr     ;Ende des Demos

                move.w  akt_score(A6),D0 ;erreichtes Levelergebnis holen
                cmp.w   hiscore(A6),D0  ;> der Hiscore?
                bls.s   play_game6      ;NEIN! => kein neuer Hiscore ...
                move.w  D0,hiscore(A6)  ;wird allerdings gleich gelöscht
                lea     all_level_data(A6),A0 ;Hier steht der originale Level
                move.w  akt_level(A6),D1
                muls    #64,D1          ;Da auch "-1" möglich ist!!!
                move.w  D0,62(A0,D1.w)  ;Hiscore auch im Level setzen
play_game6:     add.w   D0,big_score(A6) ;und zum Gesamtscore addieren

                move.w  akt_level(A6),D0
                move.w  level_anz(A6),D1
                beq     restart_clr     ;Ende, wenn nur ein Level vorhanden
                addq.w  #1,D0           ;nächster Level
                move.w  D0,akt_level(A6)
                cmp.w   D1,D0           ;höchster Level erreicht
                bcs     play_game       ;Nächsten Level
                subq.w  #1,akt_level(A6)
                bra     restart_clr     ;und Ende

;*******************************************************************************
;* Sind alle Steine am richtigen Ort? (Z=1, wenn nicht)                        *
;*******************************************************************************
check_win:      movem.l D0-D1/A0,-(SP)
                lea     level_dat(A6),A0 ;Hier steht der Level
                move.w  #22*15-1,D0     ;Feldgröße
                moveq   #0,D1
check_win1:     cmpi.b  #8|6,(A0)       ;Spieler auf Exit?
                bne.s   check_win2
                moveq   #-1,D1          ;Flag dafür setzen
check_win2:     cmpi.b  #3,(A0)+
                dbeq    D0,check_win1   ;Nein, noch nicht
                beq.s   check_win3
                clr.b   timer_stop(A6)  ;Uhr anhalten
                tst.b   D1              ;Spieler auf dem Ausgang? Z=1, wenn nicht
check_win3:     movem.l (SP)+,D0-D1/A0
                rts

;*******************************************************************************
;* Score um einen Punkt erniedrigen                                            *
;*******************************************************************************
score_down:     tst.w   demo_mode(A6)   ;Demo-Mode an?
                bne.s   score_down0     ;dann Score löschen
                subq.w  #1,akt_score(A6) ;sonst ein Punkt abziehen
                bpl.s   score_down1     ;Ende, wenn noch positiv
score_down0:    clr.w   akt_score(A6)   ;sonst Score löschen
score_down1:    rts

;*******************************************************************************
;* Bewegung des Spieler und Verschieben der Objekte                            *
;*******************************************************************************
movement:       move.w  akt_koord_y(A6),D0
                move.w  akt_koord_x(A6),D1
                bsr     get_char

                moveq   #0,D6
                moveq   #0,D7
                btst    #3,dir(A6)      ;Cursor right?
                beq.s   movement1
                moveq   #1,D6
                bsr     move_check
                ble.s   movement4       ;Feld ist gültig
                moveq   #0,D6
                bra.s   movement4

movement1:      lsr.w   #8,D3
                btst    #2,dir(A6)      ;Cursor left?
                beq.s   movement2
                moveq   #-1,D6
                bsr.s   move_check
                ble.s   movement4       ;Feld ist gültig
                moveq   #0,D6
                bra.s   movement4

movement2:      swap    D3
                btst    #1,dir(A6)      ;Cursor down?
                beq.s   movement3
                moveq   #1,D7
                bsr.s   move_check
                ble.s   movement4       ;Feld ist gültig
                moveq   #0,D7
                bra.s   movement4

movement3:      lsr.w   #8,D3
                btst    #0,dir(A6)      ;Cursor up?
                beq.s   movement4
                moveq   #-1,D7
                bsr.s   move_check
                ble.s   movement4       ;Feld ist gültig
                moveq   #0,D7
movement4:      bsr     clear_object    ;Object an (D0;D1) entfernen
                add.w   D7,D0
                add.w   D6,D1
                move.w  D0,akt_koord_y(A6)
                move.w  D1,akt_koord_x(A6)
                moveq   #-1,D2          ;Spieler setzen
                bsr     set_object      ;Object an (D0;D1) setzen
                tst.w   D7
                bne.s   movement5
                tst.w   D6
                beq.s   move_end
movement5:      addq.w  #1,moves(A6)
                bsr     verzögerung
move_end:       btst    #1,$0484.w
                bne.s   move_end2
                btst    #7,dir(A6)      ;Feuertaste?
                bne.s   move_end2       ;dann Autorepeat
                clr.b   dir(A6)         ;Joystick-Daten löschen
move_end2:      rts

move_tab:       DC.B 1,0,0,-1,-1,0
move_check:     ext.w   D3
                move.b  move_tab(PC,D3.w),D5
                bpl.s   move_checke     ;Mauer oder nix => Fertig
                movem.l D0-A6,-(SP)     ;Block bewegen
                add.w   D7,D0           ;Position des Blockes errechnen
                add.w   D6,D1
                bsr     get_char        ;Umgebung des Blocks holen
                moveq   #0,D2
                cmp.b   #1,D6           ;nach rechts?
                beq.s   move_check1
                moveq   #8,D2
                cmp.b   #-1,D6
                beq.s   move_check1
                moveq   #16,D2
                cmp.b   #1,D7
                beq.s   move_check1
                moveq   #24,D2
                cmp.b   #-1,D7
                bne.s   move_checke1    ;Keine gültige Bewegung
move_check1:    lsr.l   D2,D3
                subq.b  #1,D3           ;Hintergrund ist möglich
                beq.s   move_check2
                subq.b  #1,D3           ;Zielfeld ist möglich
                bne.s   move_checke1
move_check2:    bsr.s   clear_object
                add.w   D7,D0           ;Zielposition des Blockes errechnen
                add.w   D6,D1
                moveq   #0,D2
                bsr.s   set_object
                addq.w  #1,pushes(A6)   ;Verschiebungen+1
                bsr     score_down
                bsr     score_down
                bsr     score_down
                bsr     score_down      ;fünf Punkte weniger
                moveq   #0,D0           ;Bewegung ist möglich
                movem.l (SP)+,D0-A6
                rts
move_checke1:   moveq   #1,D0           ;Bewegung nicht möglich
                movem.l (SP)+,D0-A6
move_checke:    rts

;*******************************************************************************
;* Objekt an (D1;D0) löschen                                                   *
;*******************************************************************************
clear_object:   movem.l D0-D1,-(SP)
                mulu    #22,D0          ;Y*22
                add.w   D1,D0           ;+X
                lea     level_dat(A6),A0 ;Hier steht der Level
                lea     0(A0,D0.w),A0   ;Adresse des Feldes
                move.b  (A0),D1         ;Object holen
                cmp.b   #4,D1           ;Diamand an?
                bne.s   clear_object1   ;Weg, wenn nicht
                move.b  #2,(A0)         ;Zielfeld setzen
                bra.s   clear_objecte
clear_object1:  lsr.b   #3,D1
                moveq   #1,D0           ;freies Feld
                tst.b   D1
                beq.s   clear_object2   ;Nix los!
                moveq   #5,D0           ;Exit
                subq.b  #1,D1
                beq.s   clear_object2
                moveq   #2,D0           ;Zielfeld
clear_object2:  move.b  D0,(A0)         ;Hintergrund setzen
clear_objecte:  movem.l (SP)+,D0-D1
                rts

;*******************************************************************************
;* Mauer oder Spieler an (D1;D0) setzen (D2<0: Spieler)                        *
;*******************************************************************************
set_object:     movem.l D0-D1,-(SP)
                mulu    #22,D0          ;Y*22
                add.w   D1,D0           ;+X
                lea     level_dat(A6),A0 ;Hier steht der Level
                lea     0(A0,D0.w),A0   ;Adresse der Position
                move.b  (A0),D1         ;Object holen
                tst.b   D2              ;Block oder Spieler
                bmi.s   set_object1     ;der Spieler =>
                moveq   #3,D0           ;Diamant aus
                subq.b  #1,D1           ;Leeres Feld
                beq.s   set_object2
                moveq   #4,D0           ;Diamant an
                subq.b  #1,D1           ;Zielfeld
                bne.s   set_objecte
                bra.s   set_object2

set_object1:    moveq   #6,D0           ;Spieler auf freiem Feld
                subq.b  #1,D1
                beq.s   set_object2
                moveq   #6|16,D0        ;Spieler auf Zielfeld
                subq.b  #1,D1
                beq.s   set_object2
                moveq   #6|8,D0         ;Spieler auf Exit
                subq.b  #3,D1
                bne.s   set_objecte
set_object2:    move.b  D0,(A0)
set_objecte:    movem.l (SP)+,D0-D1
                rts

;*******************************************************************************
;* Level nach level_dat umkopieren und in ein erweitertes Format wandeln       *
;*******************************************************************************
init_level:     movem.l D0-A6,-(SP)
                clr.b   timer_stop(A6)  ;Uhr anhalten
                clr.w   moves(A6)       ;Bewegungen löschen
                clr.w   pushes(A6)      ;Verschiebungen löschen
                moveq   #'0',D0
                move.b  D0,time_std_txt(A6)
                move.b  D0,time_min_txt(A6) ;Uhrzeit löschen
                move.b  D0,time_min_txt+1(A6)
                move.b  D0,time_sek_txt(A6)
                move.b  D0,time_sek_txt+1(A6)
                lea     all_level_data(A6),A0 ;Hier steht der originale Level
                move.w  akt_level(A6),D0
                muls    #64,D0          ;Da auch "-1" möglich ist!!!
                adda.w  D0,A0
                lea     level_dat+23(A6),A1 ;und hier soll er hin
                lea     init_leveltab(PC),A2
                move.l  #$01020001,(A2)
                tst.b   out_of_game(A6)
                bne.s   init_level0
                move.l  #$01020003,(A2)
init_level0:    moveq   #11,D1          ;12 Zeilen kopieren
init_level1:    moveq   #4,D0           ;5 Byte pro Zeile
init_level2:    move.b  (A0)+,D2
                moveq   #3,D4           ;4 Felder pro Byte
init_level3:    rol.b   #2,D2
                moveq   #3,D3
                and.b   D2,D3
                move.b  0(A2,D3.w),(A1)+
                dbra    D4,init_level3
                dbra    D0,init_level2
                addq.l  #2,A1           ;rechten & linken Rand überspringen
                dbra    D1,init_level1
                moveq   #0,D0
                move.b  (A0)+,D0
                lsr.b   #1,D0           ;X-Koordinate des Starts holen
                addq.w  #1,D0
                move.w  D0,D1
                swap    D0
                move.b  (A0)+,D0
                and.b   #$7F,D0         ;oberstes Bit löschen
                lsr.b   #1,D0           ;Y-Koordinate des Starts holen
                addq.w  #1,D0
                move.l  D0,akt_koord_x(A6) ;aktuelle Spielerkoordinate
                mulu    #22,D0          ;Y*22
                add.w   D1,D0           ;+X
                move.w  (A0),hiscore(A6) ;Highscore setzen
                lea     level_dat(A6),A0 ;Hier steht der originale Level
                move.b  #6|8,0(A0,D0.w) ;Player auf Exit setzen
                clr.w   akt_score(A6)
                move.w  #22*15-1,D0
                moveq   #0,D1
init_level4:    cmpi.b  #2,(A0)+        ;Anzahl der Ziel-Felder ermitteln
                beq.s   init_level5
                cmpi.b  #4,-1(A0)       ;Block auf Zielfeld
                bne.s   init_level6
init_level5:    addi.w  #100,akt_score(A6) ;pro Feld 100 Punkte mehr
init_level6:    dbra    D0,init_level4
                movem.l (SP)+,D0-A6
                rts
init_leveltab:  DC.B 1,2,0,3

;*******************************************************************************
;* Level nach logbase zeichnen                                                 *
;*******************************************************************************
plot_level:     tst.b   rez(A6)         ;Farbmonitor?
                bmi     plotc_level     ;Level in Farbe zeichnen
                movem.l D0-A6,-(SP)
                lea     level_dat(A6),A0 ;Level-Daten
                movea.l logbase(A6),A1  ;Bildschirmadresse
                lea     mono_grafik(A6),A2 ;Grafik-Daten
                moveq   #1,D0           ;Zeile=1
plot_level1:    moveq   #1,D1           ;Spalte=1
plot_level2:    bsr     get_char        ;Zeichen an der Position ermitteln
                and.w   #7,D2           ;Zusatzsbits ausmaskieren
                beq.s   plot_level6     ;Die Wand bekommt eine Extra-Behandlung
                lsl.w   #7,D2
                lea     0(A2,D2.w),A3
                movea.l A1,A4
                moveq   #31,D4          ;32 Pixelzeilen kopieren
plot_level3:    move.l  (A3)+,(A4)      ;Zeichen kopieren
                lea     80(A4),A4
                dbra    D4,plot_level3
plot_level4:    addq.l  #4,A1           ;Nächste Bildschirmposition
                addq.w  #1,D1
                cmp.w   #21,D1          ;Zeile voll?
                bne.s   plot_level2     ;nein, noch nicht
                lea     31*80(A1),A1    ;Nächstes Bildschirmposition errechnen
                addq.w  #1,D0
                cmp.w   #13,D0          ;letzte Zeile bereits ausgegeben?
                bne.s   plot_level1     ;Nein! Oben geht's weiter ^^^
                lea     -80(A1),A1
                moveq   #19,D0
                moveq   #-1,D1
plot_level5:    move.l  D1,(A1)+        ;untere Linie ziehen
                dbra    D0,plot_level5
                movem.l (SP)+,D0-A6
                rts

;Wände erfahren eine Sonderbehandlung, da evtl.Rahmen gezeichnet werden müssen
plot_level6:    movea.l A2,A3
                movea.l A1,A4
                moveq   #30,D4          ;31 Pixelzeilen kopieren
plot_level7:    move.l  (A3)+,D5
                cmp.w   #30,D4          ;1.Zeile?
                bne.s   plot_level71    ;Weiter, wenn nicht
                move.l  #$FF000000,D2
                and.l   D3,D2           ;Oben eine Mauer?
                beq.s   plot_level71    ;Ende, wenn ja
                moveq   #-1,D5          ;sonst oben eine Linie ziehen
                bra.s   plot_level91
plot_level71:   tst.b   D3              ;Ist rechts eine Wand?
                beq.s   plot_level8     ;Nein! =>
                or.b    #1,D5           ;Dann Wand rechts abschließen
plot_level8:    ror.w   #8,D3
                tst.b   D3              ;Ist links auch eine Wand?
                beq.s   plot_level9     ;Nein! =>
                bset    #31,D5          ;Dann Wand links abschließen
plot_level9:    rol.w   #8,D3           ;Wert wieder rekonstruieren
plot_level91:   move.l  D5,(A4)         ;Pixelzeile schreiben
                lea     80(A4),A4       ;Nächste Pixelzeile
                dbra    D4,plot_level7

;Nun kommt die Abhandlung der 31. & letzten Pixelzeile einer Wand:
                move.l  (A3)+,D5        ;letzte Pixelzeile holen
                swap    D3
                tst.b   D3              ;Ist unten auch eine Wand?
                beq.s   plot_level11    ;Ja! =>
                moveq   #-1,D5          ;sonst eine Linie ziehen

;Ab hier werden evtl. zwei einzelne Punkte gesetzt, welche einen sonst
;erkennbaren Schönheitsfehler korrigieren.
;z.B:   Wand1 Wand2
;       Leer  Wand3
;Es wird bei Wand2 ein Pixel in der linken unteren Ecke gesetzt (Eckstück)
;2. Möglichkeit: Wand1 Wand2
;                Wand3 Leer
;Hier wird bei Wand1 ein Pixel in der rechten unteren Ecke gesetzt
plot_level11:   addq.w  #1,D0           ;Zeile+1 (dewegen unten zwei Wandzeilen!)
                bsr     get_char        ;umgebende Zeichen der nächsten Zeile holen
                subq.w  #1,D0           ;Zeile wieder zurück
                tst.b   D3              ;rechts auch eine Wand?
                beq.s   plot_level12    ;dann nichts tun =>
                or.b    #1,D5           ;rechts einen Punkt setzen
plot_level12:   ror.w   #8,D3
                tst.b   D3              ;links auch eine Wand?
                beq.s   plot_level13    ;dann nichts tun =>
                bset    #31,D5          ;links einen Punkt setzen
plot_level13:   move.l  D5,(A4)         ;letzte Pixelzeile schreiben
                bra     plot_level4     ;Nächstes Zeichen ausgeben

;*******************************************************************************
;* Level in Farbe nach logbase zeichnen                                        *
;*******************************************************************************
plotc_level:    tst.b   demo_mode(A6)   ;Im Demo keine Verzögerung
                bne.s   plotc_level0
                bsr.s   plotc_level0    ;3 mal zeichnen => etwa die monochrom
                bsr     plotc_level0    ;Geschwindigkeit
plotc_level0:   movem.l D0-A6,-(SP)
                lea     level_dat(A6),A0 ;Level-Daten
                movea.l logbase(A6),A1  ;Bildschirmadresse
                lea     farb_grafik(A6),A2 ;Grafik-Daten
                moveq   #1,D0           ;Zeile=1
plotc_level1:   moveq   #1,D1           ;Spalte=1
plotc_level2:   bsr.s   get_char        ;Zeichen an der Position ermitteln
                and.w   #7,D2           ;Zusatzsbits ausmaskieren
                lsl.w   #7,D2
                lea     0(A2,D2.w),A3   ;Adresse der Grafiken
                movea.l A1,A4
                moveq   #15,D4          ;16 Pixelzeilen kopieren
plotc_level3:   move.l  (A3)+,(A4)+     ;Zeichen kopieren
                move.l  (A3)+,(A4)
                lea     156(A4),A4
                dbra    D4,plotc_level3
                addq.l  #8,A1           ;Nächste Bildschirmposition
                addq.w  #1,D1
                cmp.w   #21,D1          ;Zeile voll?
                bne.s   plotc_level2    ;nein, noch nicht
                lea     15*160(A1),A1   ;Nächstes Bildschirmposition errechnen
                addq.w  #1,D0
                cmp.w   #13,D0          ;letzte Zeile bereits ausgegeben?
                bne.s   plotc_level1    ;Nein! Oben geht's weiter ^^^
                lea     -160(A1),A1
                moveq   #39,D0
                moveq   #-1,D1
plotc_level5:   move.w  D1,(A1)+        ;untere Linie ziehen
                clr.w   (A1)+
                dbra    D0,plotc_level5
                movem.l (SP)+,D0-A6
                rts

;*******************************************************************************
;* Zeichen um bzw. an einer bestimmten Position ermitteln                      *
;* => D0.W:Zeile (1-12)                                                        *
;*    D1.W:Spalte (1-20)                                                       *
;* <= D2.W:aktuelles Zeichen (5, siehe Tabelle unten)                          *
;*    D3.L:Byte 3 - oberes Zeichen (2)                                         *
;*         Byte 2 - unteres Zeichen (8)                                        *
;*         Byte 1 - linkes Zeichen (4)                                         *
;*         Byte 0 - rechtes Zeichen (6)                                        *
;*    1 2 3                                                                    *
;*    4 5 6                                                                    *
;*    7 8 9                                                                    *
;*******************************************************************************
get_char:       lea     level_dat(A6),A0 ;Level-Daten
                move.w  D0,D2
                mulu    #22,D2          ;Zeile*22
                add.w   D1,D2           ;+Spalte
                lea     0(A0,D2.w),A0   ;Adresse des aktuellen Zeichens
                movep.w -22(A0),D3      ;oberes Zeichen holen
                move.b  22(A0),D3       ;unteres Zeichen holen
                swap    D3
                movep.w -1(A0),D3       ;linkes & rechtes Zeichen holen
                move.b  (A0),D2         ;aktuelles Zeichen holen
                ext.w   D2
                rts

;*******************************************************************************
;* Verzögerung bei Bewegung des Joysticks (Spiel sich besser)                  *
;*******************************************************************************
verzögerung:    move.w  #20000,D0
verzögerung1:   dbra    D0,verzögerung1
                rts

;*******************************************************************************
;* Taste holen (D0=0, wenn keine gedrückt, sonst D0.W=Scancode der Taste)      *
;*******************************************************************************
get_key:        movem.l D0-D2/A0-A2,-(SP)
                move.w  #$0B,-(SP)
                trap    #1              ;Cconis()
                addq.l  #2,SP
                tst.l   D0              ;Taste gedrückt?
                beq.s   get_key1        ;Nein, dann weiter
                move.w  #7,-(SP)
                trap    #1              ;Crawin()
                addq.l  #2,SP
                swap    D0              ;Scancode nach unten
get_key1:       move.w  D0,key(A6)      ;Tastencode merken
                tst.b   demo_mode(A6)   ;Demo-Mode aktiv?
                bne.s   get_demo        ;Richtungen für's Demo holen
                cmpi.b  #'J',joy_text(A6)
                beq.s   get_key3        ;Joystick-Steuerung
                clr.b   dir(A6)         ;Richtungen löschen
                lea     key_tab-1(PC),A0
get_key2:       tst.b   (A0)+
                bmi.s   get_key3
                cmp.b   (A0)+,D0
                bne.s   get_key2
                move.b  (A0),dir(A6)
get_key3:       movem.l (SP)+,D0-D2/A0-A2
                rts
                DC.B 0
key_tab:        DC.B $4D,8,$4B,4,$50,2,$48,1,-1,-1 ;Joystick-Richtungen
                EVEN

get_demo:       tst.b   demo_count2(A6)
                bpl.s   get_demo1
                move.w  demo_level(A6),D0
                add.w   D0,D0           ;und mal 2
                lea     demo_level_tab(PC),A0
                adda.w  0(A0,D0.w),A0   ;Adresse der Demo-Daten des Levels
                move.w  demo_count(A6),D0
                move.b  0(A0,D0.w),D0
                beq.s   get_demo2       ;Ende des Demos (nix mehr tun)
                addq.w  #1,demo_count(A6)
                move.b  D0,D1
                lsr.b   #4,D1           ;Anzahl isolieren
                move.b  D1,demo_count2(A6)
                and.b   #$0F,D0
                move.b  D0,demo_dir(A6) ;Richtung merken
get_demo1:      subq.b  #1,demo_count2(A6)
                move.b  demo_dir(A6),D0
get_demo2:      move.b  D0,dir(A6)
                movem.l (SP)+,D0-D2/A0-A2
                rts
                BASE DC.W,demo_level_tab
demo_level_tab: DC.W demo_titel,demo_level1
demo_titel:     DC.B $41,$68,$02,$08,$01,$08,$01,$F4,$14,$02,$04,$31
                DC.B $22,$C8,$11,$04,$02,$08,$02,$B4,$02,$04,$21
                DC.B $12,$58,$11,$04,$02,$08,$02,$44,$02,$04,$11
                DC.B $12,$18,$12,$08,$11,$08,$01,$24,$02,$04,$01
                DC.B $02,$98,$42
demo_level1:    DC.B $44,$42,$14,$12,$08,$12,$04,$31,$08,$01,$14,$01,$04,$42
                DC.B $31,$18,$22,$28,$02,$18,$01,$34,$02,$04,$21,$08,$01,$14
                DC.B $01,$04,$32
                DC.B $21,$18,$22,$38,$11,$28,$12,$54,$02,$04,$21,$08,$01,$14
                DC.B $01,$04,$22
                DC.B $11,$18,$22,$38,$11,$08,$02,$01,$18,$12,$54,$02,$04,$21
                DC.B $08,$01,$14,$01,$04,$12
                DC.B $11,$34,$01,$34,$11,$08,$02,$04,$02,$08,$38,$01,$08,$12
                DC.B $04,$02,$18,$01,$08,$42
                DC.B $31,$44,$02,$14,$01,$58,$01,$08,$32
                DC.B $21,$64,$32,$18,$21,$04,$01,$48,$01,$08,$22
                DC.B $11,$44,$32,$28,$11,$04,$02,$08,$02,$24,$02,$14,$01,$08
                DC.B $02,$08,$31,$04,$01,$48,$01,$08,$22
                DC.B $01,$48,$31,$48
                EVEN

;*******************************************************************************
;* Autorepeat-Ausgabe setzen                                                   *
;*******************************************************************************
set_autorep_txt:lea     autorep_text(A6),A0
                btst    #1,$0484.w
                bne.s   set_autorep1
                move.b  #'f',(A0)+      ;'off'
                move.b  #'f',(A0)
                rts
set_autorep1:   move.b  #'n',(A0)+      ;'on '
                move.b  #' ',(A0)+
                rts

;*******************************************************************************
;* switch_screen: Physbase & Logbase vertauschen                               *
;*******************************************************************************
switch_screen:  movem.l D0-D2/A0-A2,-(SP)
                move.l  physbase(A6),D0
                move.l  logbase(A6),D1
                move.l  D1,physbase(A6)
                move.l  D0,logbase(A6)
                move.w  #-1,-(SP)
                move.l  D1,-(SP)
                move.l  D0,-(SP)
                move.w  #5,-(SP)
                trap    #14
                lea     12(SP),SP
                movem.l (SP)+,D0-D2/A0-A2
                rts

;*******************************************************************************
;* Untere Zeile neu ausgeben                                                   *
;*******************************************************************************
update_line:    movem.l D0-A6,-(SP)
                moveq   #0,D0
                move.w  akt_level(A6),D0
                addq.w  #1,D0
                divu    #10,D0
                or.l    #$300030,D0
                move.b  D0,level_txt(A6) ;Levelnummer einsetzen
                move.b  D0,level_text(A6)
                swap    D0
                move.b  D0,level_txt+1(A6)
                move.b  D0,level_text+1(A6)
                moveq   #0,D0
                move.w  moves(A6),D0
                moveq   #3,D4
                lea     moves_txt(A6),A0
                bsr     dez_out

                move.w  pushes(A6),D0
                moveq   #3,D4
                lea     pushes_txt(A6),A0
                bsr     dez_out

                move.w  akt_score(A6),D0
                add.w   big_score(A6),D0
                moveq   #3,D4
                lea     score_txt(A6),A0
                bsr     dez_out

                move.w  hiscore(A6),D0
                lea     hiscore_txt(A6),A0
                bsr     dez_out

                lea     text(A6),A0     ;und ausgeben
                bsr.s   print
                movem.l (SP)+,D0-A6
                rts

;*******************************************************************************
;* Frage in D0 stellen, auf "Y" oder "Z" bzw. "N" warten                       *
;*******************************************************************************
do_dialog:      moveq   #3,D1
                lea     dialog_string(A6),A0
do_dialog0:     rol.l   #8,D0           ;die vier Zeichen übertragen
                move.b  D0,(A0)+
                dbra    D1,do_dialog0
                lea     dialog_txt(A6),A0
                bsr.s   print_text      ;String ausgeben
do_dialog1:     bsr     get_key         ;Tastatur auswerten
                move.w  key(A6),D0      ;Taste holen
                cmp.w   #$31,D0
                beq.s   do_dialog2
                cmp.w   #$15,D0         ;Z
                beq.s   do_dialog2
                cmp.w   #$2C,D0         ;Y
                bne.s   do_dialog1
do_dialog2:     sub.w   #$31,D0         ;0= NEIN, <>0= JA
                rts

;*******************************************************************************
;* Text ab A0 ausgeben, aber ganze Seite auch noch neu ausgeben                *
;*******************************************************************************
print_text:     bsr     init_level      ;Level intern entpacken
                bsr     plot_level      ;Level zeichnen
                bsr     update_line     ;untere Textzeile neu ausgeben
                bsr.s   print           ;Text ausgeben
                bra     switch_screen   ;Bildschirmseiten umschalten

;*******************************************************************************
;* Text ab A0 ausgeben                                                         *
;*******************************************************************************
print:          movem.l D0-D4/A0-A3,-(SP)
                tst.b   rez(A6)         ;Farbmonitor?
                bmi.s   print_color0    ;ja! =>
print0:         moveq   #0,D1
                move.b  (A0)+,D1        ;Spalte holen
                moveq   #0,D0
                move.b  (A0)+,D0        ;Zeile holen
                mulu    #16*80,D0       ;Spaltenoffset errechnen
                add.w   D1,D0           ;Spalte dazu
                movea.l logbase(A6),A1
                adda.w  D0,A1           ;Adresse auf dem Schirm
                movea.l font_adr(A6),A2 ;Adresse des 16x16-Fonts
print1:         moveq   #0,D0
                move.b  (A0)+,D0        ;Zeichen holen
                beq.s   print3          ;Ende des Strings
                cmp.b   #$FF,D0         ;Noch ein String
                beq.s   print0          ;nächste Koordinate holen
                moveq   #0,D2           ;nur einmal ausgeben
                cmp.b   #1,D0           ;Zeichen mehrfach ausgeben?
                bne.s   print4
                move.b  (A0)+,D2        ;Anzahl holen
                moveq   #' ',D0         ;Space ausgeben
print4:         lea     0(A2,D0.w),A3   ;Adresse des Zeichens
                moveq   #15,D1          ;16 Pixelzeilen ausgeben
print2:         move.b  (A3),D4
                not.b   D4              ;Zeichen invertieren
                move.b  D4,(A1)
                lea     256(A3),A3
                lea     80(A1),A1
                dbra    D1,print2
                lea     -16*80+1(A1),A1 ;Pointer auf das nächste Zeichen
                dbra    D2,print4       ;Zeichen mehrfach ausgeben?
                bra.s   print1
print3:         movem.l (SP)+,D0-D4/A0-A3
                rts
print_color0:   moveq   #0,D1
                move.b  (A0)+,D1        ;Spalte holen
                moveq   #1,D2
                and.w   D1,D2
                and.w   #-2,D1
                add.w   D1,D1
                add.w   D2,D1
                moveq   #0,D0
                move.b  (A0)+,D0        ;Zeile holen
                mulu    #8*160,D0       ;Spaltenoffset errechnen
                add.w   D1,D0           ;Spalte dazu
                movea.l logbase(A6),A1
                adda.w  D0,A1           ;Adresse auf dem Schirm
                movea.l font_adr+4(A6),A2 ;Adresse des 16x16-Fonts
print_color1:   moveq   #0,D0
                move.b  (A0)+,D0        ;Zeichen holen
                beq.s   print3          ;Ende des Strings
                cmp.b   #$FF,D0         ;Noch ein String
                beq.s   print_color0    ;nächste Koordinate holen
                moveq   #0,D2           ;nur einmal ausgeben
                cmp.b   #1,D0           ;Zeichen mehrfach ausgeben?
                bne.s   print_color4
                move.b  (A0)+,D2        ;Anzahl holen
                moveq   #' ',D0         ;Space ausgeben
print_color4:   lea     0(A2,D0.w),A3   ;Adresse des Zeichens
                moveq   #7,D1           ;8 Pixelzeilen ausgeben
print_color2:   move.b  (A3),D4
                not.b   D4              ;Zeichen invertieren
                move.b  D4,(A1)
                clr.b   2(A1)
                lea     256(A3),A3
                lea     160(A1),A1
                dbra    D1,print_color2
                lea     -8*160+1(A1),A1 ;Pointer auf das nächste Zeichen
                move.w  A1,D4
                btst    #0,D4
                bne.s   print_color5
                addq.l  #2,A1
print_color5:   dbra    D2,print_color4
                bra.s   print_color1

;************************************************************************
;* Dezimal-Zahl in D0 nach A0 ausgeben                                  *
;* Anzahl der Stellen in D4                                             *
;************************************************************************
dez_out:        movem.l D0-D5/A3,-(SP)
                lea     dez_out_tab(PC),A3
                move.w  D4,D5
                lsl.w   #2,D5
                lea     4(A3,D5.w),A3
                moveq   #'0',D5
dez_out1:       move.l  -(A3),D3
                moveq   #$D0,D2
dez_out2:       sub.l   D3,D0
                dbcs    D2,dez_out2
                neg.b   D2
                move.b  D2,D1
                cmp.b   #'0',D1
                beq.s   dez_out4
                moveq   #'0',D5
dez_out3:       move.b  D1,(A0)+        ;Zahl in den Buffer
                add.l   D3,D0
                dbra    D4,dez_out1
                movem.l (SP)+,D0-D5/A3
                rts
dez_out4:       move.w  D5,D1
                tst.w   D4
                bne.s   dez_out3
                moveq   #'0',D1
                bra.s   dez_out3

dez_out_tab:    DC.L 1,10,100,1000,10000,100000
                DC.L 1000000,10000000,100000000,1000000000

;*******************************************************************************
;* Allgemeines Init                                                            *
;*******************************************************************************
init:           move.w  #2,-(SP)        ;Bildschirmadressen merken
                trap    #14
                addq.l  #2,SP
                move.l  D0,old_physbase(A6)
                move.w  #3,-(SP)
                trap    #14
                addq.l  #2,SP
                move.l  D0,old_logbase(A6)

                movem.l $FFFF8240.w,D0-D7
                movem.l D0-D7,old_pal(A6) ;Farben retten
                moveq   #3,D0
                and.b   $FFFF8260.w,D0
                move.b  D0,rez(A6)      ;die akt.Auflösung
                subq.b  #2,rez(A6)
                move.w  D0,old_rez(A6)  ;und die Auflösung merken
                btst    #1,D0
                bne.s   init4
                pea     farb_pal(A6)
                move.w  #6,-(SP)
                trap    #14             ;Farbpalette setzen
                addq.l  #6,SP
                moveq   #-1,D0
                move.w  #1,-(SP)
                move.l  D0,-(SP)
                move.l  D0,-(SP)
                move.w  #5,-(SP)
                trap    #14             ;geringe Auflösung an
                lea     12(SP),SP
init4:          lea     screens+255(A6),A0
                move.l  A0,D0
                clr.b   D0              ;Bildschirmadresse durch 256 teilbar
                movea.l D0,A0           ;machen
                move.l  A0,physbase(A6) ;1.Seite ist am Anfang "physbase"
                lea     32000(A0),A0
                move.l  A0,logbase(A6)  ;2. Seite ist am Anfang "logbase"

                pea     own_timer(PC)
                move.l  #$050045,-(SP)
                trap    #13             ;eigener 200Hz-Timer
                addq.l  #8,SP
                lea     org_timer(PC),A0
                move.l  D0,2(A0)        ;originalen 200Hz-Timer auch noch nutzen

                move.w  #$22,-(SP)
                trap    #14
                addq.l  #2,SP
                movea.l D0,A0
                lea     24(A0),A0
                move.l  A0,old_joyadr(A6)
                move.l  (A0),old_joyvec(A6)
                lea     own_joyvec(PC),A1
                move.l  A1,(A0)         ;eigene Joystickroutine

                pea     init_joy(PC)
                move.l  #$190001,-(SP)
                trap    #14             ;Joystick an, Maus aus
                addq.l  #8,SP

                linea   #10 [ Hidem ]
                linea   #0 [ Init ]
                movea.l 4(A1),A0        ;Adresse des 8x8-Fonts
                move.l  76(A0),font_adr+4(A6)
                movea.l 8(A1),A0        ;Adresse des 16x16-Fonts
                move.l  76(A0),font_adr(A6)

init1:          bsr     get_key         ;Keyboard-Buffer löschen
                tst.w   key(A6)
                bne.s   init1

                lea     titel_level(A6),A0
                lea     all_level_data-64(A6),A1
                moveq   #15,D0
init3:          move.l  (A0)+,(A1)+     ;Titel-Level kopieren
                dbra    D0,init3

                move.b  $0484.w,old_conterm(A6)
                andi.b  #$F6,$0484.w    ;Tastaturklick aus / Kbshift-Bits aus
                bsr     set_autorep_txt ;Autorepeat-Text setzen

                lea     init2(PC),A5
                bra     do_load_levels  ;Level laden

init2:          rts

;*******************************************************************************
;* Allgemeines Exit                                                            *
;*******************************************************************************
exit:           move.l  #'quit',D0
                bsr     do_dialog
                beq     restart_clr     ;Nicht beenden

                movea.l old_joyadr(A6),A0
                move.l  old_joyvec(A6),(A0) ;Joystick-Vektor zurück

                move.b  old_conterm(A6),$0484.w

                movem.l old_pal(A6),D0-D7 ;Farben zurück
                movem.l D0-D7,$FFFF8240.w
                move.w  old_rez(A6),-(SP) ;Bildschirmadressen zurücksetzen
                move.l  old_physbase(A6),-(SP)
                move.l  old_logbase(A6),-(SP)
                move.w  #5,-(SP)
                trap    #14
                lea     12(SP),SP

                move.l  org_timer+2(PC),-(SP)
                move.l  #$050045,-(SP)
                trap    #13             ;alter 200Hz-Timer
                addq.l  #8,SP

                pea     exit_joy(PC)
                move.l  #$190000,-(SP)
                trap    #14             ;Maus wieder an
                addq.l  #8,SP
                rts

;*******************************************************************************
;* Eigene Joystick-IRQ-Routine                                                 *
;*******************************************************************************
own_joyvec:     move.l  A6,-(SP)
                lea     varbase(PC),A6
                tst.b   demo_mode(A6)   ;Demo aktiv?
                bne.s   own_joyvec1     ;dann nix tun
                cmpi.b  #'J',joy_text(A6)
                bne.s   own_joyvec1     ;Joystick-Steuerung
                move.b  2(A0),dir(A6)
own_joyvec1:    movea.l (SP)+,A6
                rts

;*******************************************************************************
;* Eigene 200Hz-IRQ-Timer-Routine                                              *
;*******************************************************************************
own_timer:      movem.l A0/A6,-(SP)
                lea     varbase(PC),A6
                addq.w  #1,timer2(A6)
                subq.w  #1,timer(A6)    ;200Hz-Zähler
                bpl.s   own_timer_e
                move.w  #199,timer(A6)

                tst.b   timer_stop(A6)
                beq.s   own_timer_e

                bsr     score_down      ;pro Sekunde einen Punkt weniger

                lea     time_sek_txt+1(A6),A0
                addq.b  #1,(A0)
                cmpi.b  #$3A,(A0)
                bne.s   own_timer_e     ;Sekunden hochzählen
                move.b  #'0',(A0)
                subq.l  #1,A0
                addq.b  #1,(A0)
                cmpi.b  #'6',(A0)
                bne.s   own_timer_e
                move.b  #'0',(A0)

                lea     time_min_txt+1(A6),A0
                addq.b  #1,(A0)
                cmpi.b  #$3A,(A0)
                bne.s   own_timer_e     ;Minuten hochzählen
                move.b  #'0',(A0)
                subq.l  #1,A0
                addq.b  #1,(A0)
                cmpi.b  #'6',(A0)
                bne.s   own_timer_e
                move.b  #'0',(A0)

                addq.b  #1,time_std_txt(A6) ;Stunden erhöhen

own_timer_e:    movem.l (SP)+,A0/A6
org_timer:      jmp     $12345678

;*******************************************************************************
;* Hier beginnt nun der DATA-Bereich                                           *
;*******************************************************************************
                DATA
                BASE DC.W,*
                DC.L 'MRF!'
                DC.L 0      ;Offset zum Anfang
                DC.W mono_grafik
                DC.W 8      ;8 mal
                DC.W 32     ;Zeilenanzahl
                DC.W 4      ;je 4 Byte
                DC.W 80     ;Zeilenoffset

                DC.L 32034  ;Offset zum Anfang
                DC.W farb_grafik
                DC.W 8      ;8 mal
                DC.W 16     ;Zeilenanzahl
                DC.W 8      ;je 8 Byte
                DC.W 160    ;Zeilenoffset

                DC.L 32002  ;Offset zum Anfang
                DC.W farb_pal
                DC.W 16     ;1 mal
                DC.W 1      ;eine Zeile
                DC.W 2      ;je ein Wort
                DC.W 0      ;keine 2.Zeile

                DC.W -1

mono_grafik:    DC.W 8*32*4 ;Platz für die Daten
                DS.W 8*32*4-2
farb_grafik:    DC.W 8*16*8
                DS.W 8*16*8-2
farb_pal:       DC.W 16*1*2
                DS.W 16*1*2-2

titel_level:    DC.B $A8,$82,$22,$08,$82,$60,$82,$22,$88,$88,$60,$AA,$22,$28,$A0,$60
                DC.B $82,$22,$08,$88,$60,$B2,$22,$C8,$82,$00,$00,$00,$00,$00,$00,$00
                DC.B $00,$00,$0C,$83,$8A,$A2,$A8,$82,$80,$88,$22,$08,$88,$88,$88,$22
                DC.B $A8,$A0,$A2,$88,$22,$20,$88,$80,$8A,$A2,$08,$82,$14,$96,$00,$00

text:           DC.B 0,24   ;Bildschirmposition
                DC.B 1,2,'Level:'
level_txt:      DC.B '00'
                DC.B '  Moves:'
moves_txt:      DC.B '0000'
                DC.B '  Pushes:'
pushes_txt:     DC.B '0000'
                DC.B '  Time:'
time_std_txt:   DC.B '0'
                DC.B ':'
time_min_txt:   DC.B '00'
                DC.B ':'
time_sek_txt:   DC.B '00'
                DC.B '  Score:'
score_txt:      DC.B '0000'
                DC.B '  Hiscore:'
hiscore_txt:    DC.B '0000'
                DC.B 1,3,0

text2:          DC.B 30,5,1,21,-1
                DC.B 30,6,1,3,'THINK and WORK',1,3,-1
                DC.B 30,7,1,2,'©1989  by ∑-soft',1,2,-1
                DC.B 30,8,1,21,-1
                DC.B 30,9,' F1  - Start level '
level_text:     DC.B '00 ',-1
                DC.B 30,10,' F2  - Edit level',1,4,-1
                DC.B 30,11,' F3  - Level - 1',1,5,-1
                DC.B 30,12,' F4  - Level + 1',1,5,-1
                DC.B 30,13,' F5  - '
joy_text:       DC.B 'Joystick       ',-1
                DC.B 30,14,' F6  - Autorepeat o'
autorep_text:   DC.B 'ff ',-1
                DC.B 30,15,' F7  - Copyrights',1,4,-1
                DC.B 30,16,' F8  - Load levels',1,3,-1
                DC.B 30,17,' F9  - Save levels',1,3,-1
                DC.B 30,18,' F10 - Quit',1,10,-1
                DC.B 30,19,1,21,0

joy1_txt:       DC.B 'Joystick',0
joy2_txt:       DC.B 'Keyboard',0
dialog_txt:     DC.B 28,11,1,23,-1
                DC.B 28,12,' Sure you want to '
dialog_string:  DC.B 'xxxx? ',-1
                DC.B 28,13,1,23,0

copyright_txt:  DC.B 30,6,1,21,-1
                DC.B 30,7,1,3,'THINK and WORK',1,3,-1
                DC.B 30,8,1,2,'©1989  by ∑-soft',1,2,-1
                DC.B 30,9,1,21,-1
                DC.B 30,10,' ATARI ST Version by  ',-1
                DC.B 30,11,1,2,'Markus Fritze',1,5,-1
                DC.B 30,12,' Written with the',1,4,-1
                DC.B 30,13,1,2,'OMIKRON.Assembler  ',-1
                DC.B 30,14,1,21,-1
                DC.B 30,15,' ATARI XL-Version',1,4,-1
                DC.B 30,16,' and Levels by',1,7,-1
                DC.B 30,17,1,2,'Johann Schilcher',1,2,-1
                DC.B 30,18,1,21,0

text3:          DC.B 0,24
                DC.B ' F1-Wall F2-Target F3-Block F4-Exit'
                DC.B 1,2,'Clr/Home-Clr level',1,2,'UNDO-Undo',1,2,'F10:Quit ',0

fname:          DC.B 'LEVEL.DAT',0
init_joy:       DC.B $12,$14
exit_joy:       DC.B $08

;*******************************************************************************
;* Hier beginnt nun der BSS-Bereich                                            *
;*******************************************************************************
varbase:        BSS         ;Die Globale Offset-Variable steht stets in A6
rez:            DS.B 1      ;0=Monochrom, <>0=Farbe
                EVEN
physbase:       DS.L 1      ;angezeigte Bildschirmseite
logbase:        DS.L 1      ;aktuell zu bearbeitende Bildschirmseite
font_adr:       DS.L 2      ;Adressen der Fonts
akt_level:      DS.W 1      ;aktueller Level (0-24)
save_level:     DS.W 1      ;gemerkter Level (da das Demo den Level ändert)
akt_koord_x:    DS.W 1      ;X-Koordinate des Spielers
akt_koord_y:    DS.W 1      ;Y           -"-
level_anz:      DS.W 1      ;Levelanzahl (hier 25)
demo_count:     DS.W 1      ;Position des Demos
demo_level:     DS.W 1      ;akt.Level des Demos
demo_count2:    DS.B 1      ;Anzahl der Schritte in die gespeicherte Richtung
demo_dir:       DS.B 1      ;gespeicherte Richtung
demo_mode:      DS.B 1      ;<>0 => Demo-Mode aktiv
out_of_game:    DS.B 1      ;=0 => Spiel läuft gerade (Blockanzeige ...)
dir:            DS.B 1      ;Joystick-Daten (Bits 0-3)
timer_stop:     DS.B 1      ;=0 => Zeit steht
timer:          DS.W 1      ;200Hz Zähler mit Werten von 0-199
timer2:         DS.W 1      ;200Hz Zähler
key:            DS.W 1      ;akt.Tastencode
moves:          DS.W 1      ;Anzahl der Bewegungen des Spielers
pushes:         DS.W 1      ;Anzahl der Verschiebungen durch den Spieler
akt_score:      DS.W 1      ;Die erreichten Punkte
big_score:      DS.W 1      ;gesamter Score
hiscore:        DS.W 1      ;Hiscore des akt.Levels
old_joyvec:     DS.L 1      ;alter Joystick-Vektor
old_joyadr:     DS.L 1      ;alte Joystick-Vektor-Adresse
old_physbase:   DS.L 1      ;Bildschirmadresse beim Start
old_logbase:    DS.L 1
old_rez:        DS.W 1      ;Bildschirmauflösung beim Start
old_pal:        DS.W 16     ;alte Farbpalette
old_conterm:    DS.B 1      ;gemerkte conterm-Variable
button_pressed: DS.B 1      ;<>0, wenn Feuertaste im Editor gedrückt
level_buffer:   DS.L 16     ;für UNDO im Editor (64 Byte Levelbuffer)
level_dat:      DS.B 22*15  ;Platz für den aktuellen Level
                DS.B 64     ;Level "-1" = Titel
all_level_data: DS.B 64*max_level ;Platz für max.100 Level
                DS.L 256    ;eigener Stack
own_stack:      DS.L 0
screens:        DS.B 32000*2+255 ;die 2 Bildschirmseiten
                END