THINK and WORK

Think & Work Title Image

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.

Think & Work Menu Image

Think & Work Game Image

The image files can be opened with GraphicConverter.

The original source code

                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
Previous post:
Next post: