;Betriebssystem Space-Fight
;(c) by Thilo Ackermann 2004
;Start: 01.11.2004
;assemblieren mit nasm -f bin -o spiel.bin spiel.asm
;Image direkt auf Diskette schreiben, z.B. mit rawrite
;Ziel: Spiel, welches kein Betriebssystem ben”tigt auf einem 80286 Rechner
;mit maximal 2kb Speicher auf der Diskette

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;BOOT-VORGANG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


boot_anfang:                            ;dieses label wird sp„ter ben”tigt

;stack setzen
cli                                     ;Interrupts aus
xor ax,ax                               ;ax = 0
mov sp,ax                               ;stackpointer auf 0
mov ax,3000h                            ;segment 2000h soll stacksegment werden
mov ss,ax                               ;nun aber setzen
sti                                     ;Interrupts wieder an

cld                                     ;direction flag l”schen

;an eine "bessere" stelle (seg 1000h) kopieren
;quelldaten
mov ax,cs                               ;codesegment nach ax
mov ds,ax                               ;ax nach datensegment --> ds=cs
mov si,07c00h                           ;aktueller offset des bootloaders
;zieldaten
mov ax,1000h                            ;zielsegment
mov es,ax                               ;und nun nach es
xor di,di                               ;di auf 0
;kopieren
mov cx,256                              ;256 words sollen kopiert werden (2*256=512)
rep movsw                               ;kopieren
;in das ziel springen
db 0eah
dw boot_kopieren_ende
dw 1000h
boot_kopieren_ende:

;alles l”schen
mov di,2048
mov cx,65536-2048
xor al,al
rep stosb

;nun gehts richtig los

;segmente setzen
mov ax,cs                               ;codesegment nach ax
mov ds,ax                               ;ds = cs
mov es,ax

;restlichen 3 sektoren nachladen
boot_nachladen:
;es ist schon gesetzt
mov bx,512                              ;an offset 512, da bytes 0-511 schon belegt sind
mov ax,0203h                             ;funktionsnummer 2 und 3 sektoren
mov cx,2                                ;beginne bei sektor 2 (erster sektor ist hier 1)
xor dx,dx                               ;kopf 0
int 13h
jc boot_nachladen                       ;bei einem fehler, neu lesen

;timer auf 20 hz stellen
cli
mov al,00110110b                        ;chip einstellungen (timer0,schreiben low/high,
                                        ;rechteckwelle, 16-bit format
out 43h,al                              ;und ausgeben
mov al,0Bh                              ;lobyte f�r interval
out 40h,al                              ;und speichern
mov al,0e9h                             ;hibyte f�r interwall
out 40h,al

;tastaturtreiber und timer setzen
xor ax,ax                               ;segment 0
mov fs,ax                               ;nach fs
mov dx,cs                               ;codesegment nach dx

mov word [fs:9*4],fkt_keypress          ;in die interrupt vektortabelle eintragen
mov word [fs:9*4+2],dx                  ;codesement eintragen

mov cx,word [fs:8*4]                    ;alter offset nach cx
mov word [2185],cx                      ;offset speichern
mov cx,word [fs:8*4+2]                  ;altes segment nach cx
mov word [2183],cx                      ;segment speichern

mov word [fs:8*4],fkt_timer             ;in die interrupt vektortabelle eintragen
mov word [fs:8*4+2],dx

sti                                     ;interrupts wieder aktivieren

;farbtabelle generieren
mov si,2187                             ;si auf anfang der farbtabelle
xor dx,dx                               ;dx auf 0
fkt_setvga_loop1:
xor cx,cx                               ;cx auf 0
fkt_setvga_loop2:
xor ax,ax                               ;ax auf 0
fkt_setvga_loop3:
mov byte [si],al
mov byte [si+1],cl
mov byte [si+2],dl
add si,3
add al,12
cmp al,6*12                              ;6 farbstufen?
jne fkt_setvga_loop3                    ;wenn nicht dann nochmal
add cl,12
cmp cl,6*12                              ;6 farbstufen?
jne fkt_setvga_loop2                    ;wenn nicht dann nochmal
add dl,12
cmp dl,6*12                              ;6 farbstufen?
jne fkt_setvga_loop1                    ;wenn nicht dann nochmal
;grafikmodus setzen
;ah ist noch null
mov al,13h                              ;modus 13h
cli                                     ;keine interrupts
int 10h                                 ;setzen
;farbtabelle setzen
cli                                     ;keine interrupts
mov dx,03c8h                            ;portnummer f�r farbtabelle
xor al,al                               ;beginne bei farbe 0
out dx,al                               ;ausgeben
inc dx                                  ;n„chster port
mov si,2187                             ;si auf anfang der farbtabelle
mov cx,3*256                            ;3*256 words ausgeben
rep outsb                               ;alles ausgeben
sti                                     ;interrupts wieder zulassen

call fkt_expandfont

mov ax,2000h
mov fs,ax

mov si,dat_bild1
mov di,6000
call fkt_expandpic

mov si,dat_bild2
mov di,7000
call fkt_expandpic

mov si,dat_bild3
mov di,8000
call fkt_expandpic

mov si,dat_bild4
mov di,9000
call fkt_expandpic

mov si,dat_bild5
mov di,10000
call fkt_expandpic

mov di,12000
call fkt_genexplode

call fkt_ctrlgame
db 0Eah
dw 0000h
dw 0FFFFh
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;STRING-FUNKTIONEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;funktion inttostr wandelt eine zahl in einen nullterminierten string um
;parameter: ds:si pointer auf string (6 byte), ax zahl

fkt_inttostr:
;zahl umwandeln
mov di,si                               ;si in di speichern
xor cx,cx                               ;cx auf 0
add di,6                                ;an das ende des puffers
mov bx,10                               ;teiler bx
fkt_inttostr_schleife1:
xor dx,dx                               ;dx auf 0
div bx                                  ;ax/bx (zahl/10)
add dl,'Z'+1                            ;zum rest 30h addieren ('0')
dec di                                  ;eins weiter nach vorne im puffer
mov [di],dl                             ;zeichen in den puffer speichern
inc cx                                  ;z„hler um eins erh”hen
cmp ax,0                                ;alle ziffern ausgegeben?
jne fkt_inttostr_schleife1              ;wenn nicht, dann nochmal

mov ax,ds
mov es,ax
xchg di,si
rep movsb
mov byte [di],0                         ;nullbyte anf�gen
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;TASTATUR-FUNKTIONEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;funktion keypress wird bei dr�cken/loslassen einer taste aufgerufen
fkt_keypress:
cli                                     ;interrupts ausschalten
pusha                                   ;alle register sichern
;push ds
;mov ax,1000h
;mov ds,ax
in al,60h                               ;taste einlesen

mov si,2054
mov bl,[si]                             ;pufferposition
cmp bl,128                              ;puffer voll? (schon 128?)
je fkt_keypress_ende                    ;dann ende
xor bh,bh                               ;bh auf 0
add bx,2055                             ;puffer beginnt bei 2055
mov [bx],al
inc byte [si]                           ;pufferz„hler erh”hen

fkt_keypress_ende:
mov al,20h                              ;20h nach al
out 20h,al                              ;interrupt best„tigen
;pop ds
popa                                    ;alle register wieder herstellen
sti                                     ;wieder an
iret

;funktion getkey ermittelt den letzten tastaturcode
;r�ckgabewert: al=tastaturcode, ah=1 bei leerem puffer, sonst 0
fkt_getkey
cli                                     ;interrupts aus
mov si,2054
cmp byte [si],0                         ;gar kein zeichen im puffer?
je fkt_getkey_leer
dec byte [si]                           ;z„hler um eins veringern
mov al,[2055]                             ;zeichen ermitteln
;aufr�cken
;mov cl,127
;xor ch,ch
mov cx,127
inc si

fkt_getkey_schleife1:
mov dl,[si+1]
mov [si],dl
inc si
;dec cl
;cmp cl,0
;jne fkt_getkey_schleife1
loop fkt_getkey_schleife1

xor ah,ah                               ;mind. 1 zeichen war im puffer
sti                                     ;interrupts wieder an
ret

fkt_getkey_leer:
mov ah,1                                ;puffer leer
sti                                     ;interrupts an
ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;AUSGABE-FUNKTIONEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


;funktion print
;parameter: ds:si adresse des strings (nullterminiert)
;parameter: di:pos, ch farbe

fkt_print:
lodsb                                   ;ein byte lesen
cmp al,0                                ;0?
je fkt_print_ende                       ;wenn wirklich null, dann ende
;mov ah,0eh                              ;funktionsnummer zeichen ausgeben
;mov bx,7                                ;farbe 7
;int 10h                                 ;bios funktion 10h

;parameter: ax zeichennr,di pos,ch:farbe
cmp al,32                               ;leerzeichen �berspringen
je fkt_print_weiter1
sub al,'A'
push di
push si
call fkt_setchar
mov ch,dh
pop si
pop di
fkt_print_weiter1:
add di,8

jmp fkt_print
fkt_print_ende:
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;GRAFIK-FUNKTIONEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;funktion drawbuffer zeichnet den hintergrundpuffer auf den bildschirm
;zuerst auf vertical retrace warten
fkt_drawbuffer:
push ds
mov dx,03dah                            ;portadresse f�r vga-status
fkt_drawbuffer_schleife1:
in al,dx                                ;einlesen
test al,1000b                           ;bit 3 gesetzt?
jne fkt_drawbuffer_schleife1            ;wenn nicht, dann nochmal zeichnen
;und nochmal pr�fen
fkt_drawbuffer_schleife2:
in al,dx                                ;einlesen
test al,1000b                           ;bit 3 gesetzt?
jne fkt_drawbuffer_schleife2
mov ax,2000h                            ;segment des grafikpuffers
mov ds,ax                               ;nach quellsegment
xor si,si                               ;si auf 0
mov ax,0A000h                           ;segment der grafikkarte
mov es,ax                               ;nach zielsegment
xor di,di                               ;di auf 0
mov cx,320*200/2                        ;den gesamten bildschirm in words kopieren
rep movsw
pop ds
ret

dat_rumpf db "RUMPF",0
dat_punkte db "PUNKTE",0
dat_willkommen db "WILLKOMMEN ZU SPACE FIGHT",0
dat_esc db "ESC FUER ENDE",0
dat_gameover db "GAME OVER",0
dat_leer db "LEERTASTE DRUECKEN",0

boot_ende:                              ;nun kommt das ende des ersten sektors
times 510-(boot_ende-boot_anfang) db 0  ;ungenutzer speicher mit 0 auff�llejn
dw 0aa55h                               ;bootsektor signatur anh„ngen

;funktion clearscreen l”scht den gesamten bildschirm
fkt_clearscreen:
mov ax,2000h
mov es,ax
xor di,di
mov cx,320*200/2
xor ax,ax
rep stosw
ret

;funktion expandfont entpackt die schriftart
fkt_expandfont:
mov si,dat_schrift                      ;startadresse der schrift
mov di,4000                             ;zieladresse der entpackten schriftart
mov cl,27*7                             ;anzahl der bytes ermitteln

fkt_expandfont_schleife1:
mov al,[si]
xor dl,dl                               ;bitz„hler auf 0
fkt_expandfont_schleife2:
xor bl,bl                               ;auf 0
test al,1b                              ;erstes bit testen
jz fkt_expandfont_weiter                ;nicht gesetzt
mov bl,255                              ;gesetzt
fkt_expandfont_weiter:
shr al,1                                ;al durch 2 teilen
mov [di],bl                             ;in das ziel kopieren
inc di                                  ;zielz„hler erh”hen
inc dl                                  ;bitz„hler erh”hen
cmp dl,8                                ;alle 8 bits durch?
jne fkt_expandfont_schleife2            ;nein, dann nochmal
inc si                                  ;n„chstes byte
dec cl                                  ;z„hler erniedriegen
cmp cl,0                                ;bei 0?
jne fkt_expandfont_schleife1            ;nein, dann nochmal
ret

;funktion setchar zeichnet ein zeichen
;parameter: al zeichennr,di pos,ch:farbe
fkt_setchar:
mov cl,6                                ;zeichen mal 6 nehmen
mul cl                                  ;in ax sind nun 6 zeichen
xor ah,ah
add ax,4000                             ;start in 4000
mov si,ax                               ;nach si
mov bx,216-6                            ;schriftbreite nach bx

mov dh,ch
mov cx,7                                ;7 zeilen z„hler auf 7
fkt_setchar_schleife1:
xor dl,dl                               ;6 pixel z„hler auf 0
fkt_setchar_schleife2:
cmp byte [si],255                       ;pixel setzen?
jne fkt_setchar_weiter                  ;wenn nicht, dann �berspringen
mov [fs:di],dh                          ;pixel setzen
fkt_setchar_weiter:
inc si
inc di
inc dl
cmp dl,6
jne fkt_setchar_schleife2
add di,320-6
add si,bx
;inc cl
;cmp cl,7
;jne fkt_setchar_schleife1
loop fkt_setchar_schleife1
ret

;funktion genexplode generiert explosionsbilder
;parameter: di: ziel
fkt_genexplode:
mov cx,25*25
mov [di],byte 25
mov [di+1],byte 25
add di,2
fkt_genexplode_schleife:
push cx
mov cx,6
call fkt_random
pop cx
mov bx,dx
add bx,dat_farbexplo
mov dl,[bx]
mov [di],dl
inc di
;inc cx
;cmp cx,25*25
;jne fkt_genexplode_schleife
loop fkt_genexplode_schleife
ret

;funktion expandpic dekomprimiert ein bild
;parameter: si: quelldaten, di:ziel
fkt_expandpic:
mov cl,[si]                             ;pixelanzahl ermitteln
xor ch,ch
mov al,[si+1]                           ;breite und h”he ermitteln
mov [di],al                             ;einspeichern
add si,2                                ;si erh”hen
mov dx,si                               ;dx enth„lt source+3
add si,4                                ;farbtabelle �berspringen
inc di

fkt_expandpic_schleife1:
mov al,[si]                             ;nach al wert kopieren
mov bl,al                               ;bl ist eine kopie von al
shr al,3                                ;al um drei nach rechts -> linienl„nge
and bl,111b                             ;bl enth„lt die farbnummer
xor bh,bh                               ;bh auf 0
add bx,dx                               ;startadresse anf�gen
mov bl,[bx]
fkt_expandpic_schleife2:
mov [di],bl
inc di
dec al
cmp al,0
jne fkt_expandpic_schleife2
inc si
;dec cl
;cmp cl,0
;jne fkt_expandpic_schleife1
loop fkt_expandpic_schleife1
ret

;funktion showpic zeigt ein bild an

;parameter: si: quelldaten des bildes, ax: ypos, di:xpos
fkt_showpic:
;xor ch,ch
;mov cl,25                               ;h”he
mov cx,25

cmp ax,0                                ;ypos mit 0 vergleichen
jl fkt_showpic_kleiner                  ;dann zur kleiner stelle springen
mov dx,ax
add dx,cx
cmp dx,199                              ;ypos >199
jg fkt_showpic_grosser                  ;dann zur gr”áer stelle springen
mov bx,320                              ;zeilengr”áe
mul bx                                  ;sonst mit 320 multiplizieren
add di,ax                               ;und zu di addieren
xor ax,ax                               ;keine si-verschiebung
jmp fkt_showpic_weiter

fkt_showpic_kleiner:
neg ax                                  ;vorzeichen umkehren
sub cx,ax                               ;von der bildh”he subtrahieren
mov bl,[si]                             ;*breite
xor bh,bh
mul bx                                  ;ax*bx ax=si-verschiebung
jmp fkt_showpic_weiter

fkt_showpic_grosser:
push dx
mov bx,320                              ;zeilengr”áe
mul bx                                  ;sonst mit 320 multiplizieren
add di,ax                               ;und zu di addieren
pop dx
sub dx,200                              ;200 abziehen
sub cx,dx                               ;abziehen
xor ax,ax                               ;keine si-verschiebung

fkt_showpic_weiter:
mov dl,cl
mov dh,[si]                             ;breite
xor ch,ch
;add si,2
inc si
add si,ax                               ;verschiebung addieren

mov ax,fs                               ;fs nach...
mov es,ax                               ;... es

mov al,dh                               ;in ax ist jetzt die breite
xor ah,ah
fkt_showpic_schleife1:
mov cl,al                               ;breite nach cl (ch ist 0)
rep movsb                               ;kopieren
add di,320                              ;n„chste zeile
sub di,ax                               ;breite wieder abziehen
dec dl                                  ;h”he veringern
cmp dl,0                                ;alle zeilen ausgegeben?
jne fkt_showpic_schleife1               ;wenn nicht, dann nochmal
ret

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;TIMER-FUNKTIONEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

fkt_timer:
pusha
push ds
mov ax,1000h                            ;aktuelles segment
mov ds,ax                               ;nach ds
;timertick

inc byte [2955]

;daten des alten timers holen
mov ax,[2183]                           ;segment holen
mov dx,[2185]                           ;offset holen

;r�cksprung wieder nach hierher
pushf                                   ;flags
push 1000h                              ;r�cksprungsegment
push fkt_timer_ende                     ;r�cksprungoffset

;ziel des alten timers
push ax                                 ;zielsegment
push dx                                 ;zieloffset
retf                                    ;und zum alten timer springen
fkt_timer_ende:
pop ds
popa
iret



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;DATEN-BEREICH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;dat_schriftlen db 27*7
;dat_schriftwidth db 216
dat_schrift:
db 204, 231, 127, 255, 239, 133, 204, 31, 5, 225, 232, 61, 222, 227, 125, 97, 24, 134, 225, 239, 33, 222, 23, 252, 222, 239, 121
db 82, 24, 132, 65, 16, 132, 12, 152, 4, 243, 25, 70, 97, 20, 16, 97, 24, 206, 33, 24, 50, 33, 152, 4, 33, 24, 134
db 82, 24, 132, 65, 16, 132, 12, 88, 4, 109, 27, 70, 97, 20, 16, 161, 20, 122, 18, 20, 42, 16, 152, 4, 1, 20, 134
db 210, 23, 132, 223, 23, 252, 12, 184, 4, 97, 26, 62, 225, 227, 17, 161, 20, 50, 30, 211, 34, 136, 247, 127, 31, 239, 249
db 127, 24, 132, 65, 208, 133, 12, 152, 5, 97, 30, 6, 105, 1, 18, 161, 212, 122, 136, 16, 34, 4, 136, 128, 33, 18, 130
db 97, 24, 132, 65, 16, 134, 76, 24, 7, 97, 28, 6, 81, 2, 18, 33, 211, 206, 68, 16, 34, 2, 136, 128, 33, 18, 134
db 225, 231, 127, 127, 224, 135, 140, 23, 254, 97, 232, 5, 110, 228, 17, 30, 35, 133, 194, 239, 33, 255, 135, 124, 30, 226, 121

dat_bild1:
db 65
db 25
db 0,197,134,0
db 248, 248, 248, 248, 88, 41, 152, 57, 144, 57, 144, 57, 144, 57, 144, 57, 96, 26, 24, 57, 24, 26, 48, 26, 24, 57, 24, 26, 48, 26, 24, 57, 24, 26, 48, 26, 24, 57, 24, 26, 48, 26, 24, 57, 24, 26, 48, 26, 24, 57, 24, 26, 48, 26, 24, 57, 24, 26, 24, 249, 249, 249, 249, 249, 161

dat_bild2:
db 40
db 25
db 180,5,0,30
db 248, 248, 248, 248, 248, 248, 248, 248, 216, 249, 153, 10, 185, 26, 169, 42, 153, 58, 137, 74, 121, 90, 105, 106, 33, 27, 33, 122, 25, 27, 25, 138, 57, 154, 41, 162, 41, 170, 25, 90

dat_bild3:
db 55
db 25
db 126,207,0,212
db 248, 248, 248, 248, 248, 248, 248, 248, 248, 40, 57, 128, 89, 104, 105, 48, 10, 40, 105, 40, 26, 40, 89, 40, 34, 56, 57, 56, 42, 144, 74, 120, 90, 16, 11, 56, 11, 16, 114, 11, 56, 11, 130, 11, 58, 11, 130, 11, 58, 11, 130, 11, 58, 11, 250

dat_bild4:
db 61
db 25
db 181,0,147,112
db 200, 9, 184, 25, 168, 41, 152, 57, 136, 73, 24, 10, 56, 10, 24, 89, 16, 10, 56, 10, 16, 105, 8, 10, 56, 10, 8, 121, 10, 56, 10, 129, 10, 56, 10, 129, 10, 9, 40, 9, 10, 129, 10, 17, 24, 17, 10, 161, 11, 193, 11, 193, 11, 193, 11, 193, 11, 193, 11, 193, 11


dat_bild5:
db 8
db 5
db 0,5,17,0
db 16, 9, 24, 25, 8, 41, 250, 234

;dat_bild6:
;db 21
;db 5,25
;db 0,50,215,30,0,0,0,0
;db 8, 25, 16, 25, 16, 25, 16, 25, 16, 25, 8, 241, 8, 25, 16, 26, 16, 26, 24, 10, 16

dat_addr:
dw 7000,8000,9000,10000,11000,12000

dat_farbexplo:
db 0,0,5,17,35,0

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;SPIEL-FUNKTIONEN;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;funktion ctrlgame kontrolliert das spiel
fkt_ctrlgame:
;men�
;f�r neues spiel vorbereiten
mov di,2955
mov cx,3999-2955
xor al,al
rep stosb
mov byte [3478],100                     ;rumpf auf 100
;men� anzeigen
call fkt_clearscreen                    ;l”schen des puffers
mov si,dat_willkommen
mov di,10*320+320/2-25*8/2
mov ch,150
call fkt_print
mov si,dat_leer
mov di,100*320+320/2-18*8/2
mov ch,5
call fkt_print
mov si,dat_esc
mov di,120*320+320/2-13*8/2
mov ch,5
call fkt_print
call fkt_drawbuffer                     ;puffer auf bildschirm bringen

fkt_ctrlgame_menu:
mov [2955],byte 0                       ;timer auf 0
call fkt_getkey                         ;taste ermitteln
cmp ah,1                                ;keine taste gedr�ckt?
je fkt_ctrlgame_menu                    ;dann weiter
cmp al,57                               ;leertaste?
je fkt_ctrlgame_main
cmp al,1
jne fkt_ctrlgame_menu
ret                                     ;im men� ende ausw„hlen

;spiel
fkt_ctrlgame_main:
call fkt_getkey                         ;taste ermitteln
cmp ah,1                                ;keine taste gedr�ckt?
je fkt_ctrlgame_weiter1                 ;dann weiter

cmp al,0fah                             ;best„tigungscode?
je fkt_ctrlgame_weiter1                 ;dann weiter

cmp al,224                              ;erweiterter code
jne fkt_ctrlgame_weiter2                ;nein, dann weiter

fkt_ctrlgame_schleife1:
call fkt_getkey                         ;noch eine taste
cmp ah,1                                ;gedr�ckt?
je fkt_ctrlgame_schleife1               ;wenn nicht, dann nochmal

cmp al,75
je fkt_ctrlgame_tastelinks
cmp al,77
je fkt_ctrlgame_tasterechts
mov byte [3470],0
jmp fkt_ctrlgame_weiter1                ;weiter

fkt_ctrlgame_tasterechts:
mov byte [3470],1
jmp fkt_ctrlgame_weiter1
fkt_ctrlgame_tastelinks:
mov byte [3470],2
jmp fkt_ctrlgame_weiter1


fkt_ctrlgame_weiter2:

cmp al,57
je fkt_ctrlgame_tastefeuer
cmp al,1
jne fkt_ctrlgame_weiter1
jmp fkt_ctrlgame_gameover

fkt_ctrlgame_tastefeuer:
mov byte [3471],1

fkt_ctrlgame_weiter1:


mov di,2955
cmp byte[di],0                          ;timer kontrolle
je fkt_ctrlgame_main                    ;wenn kein timersignal dann nochmal
dec byte[di]                            ;timersignal entfernen

mov di,3475
inc byte [di]                           ;timerz„hler erh”hen
cmp byte [di],7                         ;mit 32 vergleichen
jne fkt_ctrlgame_weiter9
mov byte [di],0
fkt_ctrlgame_weiter9:

mov di,3470
mov si,2956
cmp [di],byte 1                         ;nach rechts?
je fkt_ctrlgame_geherechts
cmp [di],byte 2                         ;nach links?
je fkt_ctrlgame_gehelinks
jmp fkt_ctrlgame_weiter4

fkt_ctrlgame_geherechts:
cmp word [si],320-25
je fkt_ctrlgame_weiter4
add word [si],5
jmp fkt_ctrlgame_weiter4

fkt_ctrlgame_gehelinks:
cmp word [si],0
je fkt_ctrlgame_weiter4
sub word [si],5

fkt_ctrlgame_weiter4:

cmp byte [3471],1                       ;rakete ablassen
jne fkt_ctrlgame_weiter5
cmp byte [3475],0                       ;vergleichen ob timerz„hler auf 0
jne fkt_ctrlgame_weiter5
mov ax,[2956]

add ax,25/2-5/2
;mov dl,200-25
;mov dh,5
mov dx,05afh
;mov bl,8
;mov bh,0
mov bx,8
call fkt_objekt
mov byte [3471],0

fkt_ctrlgame_weiter5:
call fkt_clearscreen
;zeichnen deines raumschiffes
mov di,[2956]
mov ax,200-25
mov si,6000
call fkt_showpic

;objekte
;;;;;;;;
xor cx,cx                               ;z„hler auf 0
mov di,2958                             ;startadresse der objekte
mov byte [3472],0                       ;raumschiffanzahl auf 0
fkt_ctrlgame_schleife2:
push di                                 ;di sichern
push cx                                 ;cx sichern
cmp byte [di+3],0                       ;ist dieses objekt benutzt?
je fkt_ctrlgame_weiter3                 ;wenn nicht, dann an das ende der schleife

cmp byte [di+5],0                       ;nach oben?
je fkt_ctrlgame_hoch
call fkt_movedown
jmp fkt_ctrlgame_weiter6

fkt_ctrlgame_hoch:
call fkt_moveup

fkt_ctrlgame_weiter6:

mov bl,[di+3]                           ;typ laden
cmp bl,0                                ;ist dieses objekt benutzt?
je fkt_ctrlgame_weiter3                 ;wenn nicht, dann an das ende der schleife

;bild anzeigen (ax ist schon gesetzt)
cmp bl,7                                ;ist es feuer?
jae fkt_ctrlgame_weiter10
cmp bl,4                                ;ist es ein schuss
ja fkt_ctrlgame_weiter7                 ;dann direkt weiter
inc byte [3472]                         ;sonst raumschiffanzahl erh”hen
call fkt_checkcrash
jmp fkt_ctrlgame_weiter10

;dein schuss
fkt_ctrlgame_weiter7:
push ax
push bx
call fkt_checkrakete
pop bx
pop ax

fkt_ctrlgame_weiter10:
sub bl,2
shl bl,1                                ;typ*2 (da words gelesen werden)
xor bh,bh
add bx,dat_addr                         ;startadresse der bilder
mov si,[bx]                             ;startadresse des bildes suchen
mov di,[di]                             ;xpos laden
call fkt_showpic                        ;und bild ”ffnen

fkt_ctrlgame_weiter3:
pop cx                                  ;cx wiederherstellen
pop di                                  ;di wiederherstellen
add di,8                                ;n„chstes objekt 8 bytes weiter
inc cx                                  ;n„chstes objekt
cmp cx,64                               ;64 objekte?
jne fkt_ctrlgame_schleife2              ;wenn nicht, dann nochmal

cmp [3472],byte 5                       ;genug raumschiffe?
ja fkt_ctrlgame_weiter8

;random x-position
mov cx,290
call fkt_random
push dx

;random geschwindigkeit
mov cx,10
call fkt_random
inc dl
mov bl,dl                               ;geschwindigkeit
mov bh,1                                ;nach unten
push bx

;random raumschifftypen
mov cx,3
call fkt_random
add dl,2
mov dh,dl

pop bx
pop ax

mov dl,1                                ;y-pos
call fkt_objekt

fkt_ctrlgame_weiter8:

;rumpftext
mov si,dat_rumpf
mov di,0
mov ch,215
call fkt_print

mov al,[3478]
cmp al,0
je fkt_ctrlgame_gameover
xor ah,ah
mov si,2048
call fkt_inttostr

mov si,2048
mov di,7*8
mov ch,215
call fkt_print

;punktetext
mov si,dat_punkte
mov di,8*320
mov ch,215
call fkt_print

mov ax,[3476]
mov si,2048
call fkt_inttostr

mov si,2048
mov di,8*8+8*320
mov ch,215
call fkt_print


;zeichnen
call fkt_drawbuffer
jmp fkt_ctrlgame_main

fkt_ctrlgame_gameover:
call fkt_clearscreen                    ;l”schen des puffers
mov si,dat_gameover
mov di,30*320+320/2-9*8/2
mov ch,150
call fkt_print
mov si,dat_leer
mov di,100*320+320/2-18*8/2
mov ch,5
call fkt_print
call fkt_drawbuffer                     ;puffer auf bildschirm bringen

fkt_ctrlgame_ctrlgameover:
call fkt_getkey                         ;taste ermitteln
cmp ah,1                                ;keine taste gedr�ckt?
je fkt_ctrlgame_ctrlgameover            ;dann weiter
cmp al,57                               ;leertaste?
je fkt_ctrlgame_gameover1
jmp fkt_ctrlgame_ctrlgameover

fkt_ctrlgame_gameover1:
jmp fkt_ctrlgame

;funktion objekt erstellt eine neues objekt
;parameter: ax=xpos, dl=ypos, dh=typ, bl=geschwindigkeit, bh=richtung
fkt_objekt:
xor cx,cx
mov di,2958
fkt_objekt_schleife1:
cmp byte [di+3],0
je fkt_objekt_gef
add di,8
inc cx
cmp cx,64
jne fkt_objekt_schleife1
ret

fkt_objekt_gef:
mov [di],ax
mov [di+2],dx
mov [di+4],bx
ret

;funktion moveup bewegt das objekt in di nach oben und entfernt es, wenn es auáerhalb des randes ist
fkt_moveup:
mov al,[di+2]                           ;y-position
mov cl,[di+4]                           ;geschwindigkeit
cmp al,cl                               ;mit geschwindigkeit vergleichen
jb fkt_delobj                           ;dann entfernen
sub [di+2],cl                           ;y-position erniedriegen
xor ah,ah                               ;ah auf 0
sub ax,25                               ;25 pixel in das minus
ret

;funktion delobj l”scht ein objekt (funktion mit jmp aufrufen)
fkt_delobj:
mov byte [di+3],0                       ;typ auf 0
ret

;funktion movedown bewegt das objekt in di nach unten und entfernt es, wenn es auáerhalb des randes ist
fkt_movedown:
mov al,[di+2]                           ;y-position
mov cl,[di+4]                           ;geschwindigkeit
cmp al,220                              ;mit 200 vergleichen
ja fkt_delobj                           ;dann entfernen
add [di+2],cl                           ;y-position erniedriegen
xor ah,ah                               ;ah auf 0
sub ax,25                               ;25 pixel in das minus
ret

;funktion random berechnet einen zufallswert
;parameter: cx: 0-(cx-1)
;r�ckgabe: dx rest
fkt_random:
mov ax,[3473]                           ;faktor1
mov dx,8405h                            ;faktor2
mul dx
inc ax
mov [3473],ax
mov ax,dx                               ;rest nach ax
xor dx,dx                               ;dx auf 0
div cx                                  ;durch cx
ret

;funktion checkrakete �berpr�ft, ob ein raumschiff von der rakete getroffen wurde
fkt_checkrakete:
;xor cx,cx
mov cx,64
mov si,2958
mov dl,[di+2]                           ;y-position der rakete
mov bx,[di]                             ;x-position der rakete
fkt_checkrakete_schleife:
cmp [si+3], byte 0                      ;ist das �berhaupt ein objekt?
je fkt_checkrakete_weiter1
cmp [si+3], byte 4                      ;ist das eine rakete?
ja fkt_checkrakete_weiter1              
;hier ein raumschiff
mov al,[si+2]                           ;y-pos des raumschiffes
add al,25
cmp dl,al                               ;rakete gr”áer raumschiff?
ja fkt_checkrakete_weiter1              ;dann nicht kaputtgehen
mov ax,[si]                             ;x-pos des raumschiffes
cmp bx,ax                               ;xpos der rakete kleiner?
jb fkt_checkrakete_weiter1
add ax,25                               ;breite des raumschiffes + xpos
cmp bx,ax                               ;xpos der rakete gr”áer als ax?
ja fkt_checkrakete_weiter1
xor ah,ah
mov al,[si+3]                           ;typ des raumschiffes
shl ax,1                                ;x2
add [3476],ax                           ;punkte addieren
mov [si+3],byte 7                       ;explosion
mov [si+4],byte 10                      ;geschwindigkeit hoch
mov [di+3],byte 0                       ;rakete l”schen
ret

fkt_checkrakete_weiter1:
add si,8
;inc cx
;cmp cx,64
;jne fkt_checkrakete_schleife
loop fkt_checkrakete_schleife
ret

;funktion checkcrash �berpr�ft ob ein raumschiff mit deinem raumschiff zusammengeprallt ist
fkt_checkcrash:
;y-check
mov cl,[di+2]                           ;y-koordinate holen
cmp cl,200-25                           ;noch nicht unten?
jb fkt_checkcrash_weiter
;x-check
mov cx,[di]                             ;x-koordinate des raumschiffes
mov dx,[2956]                           ;deine koordinate
add cx,25
cmp cx,dx
jb fkt_checkcrash_weiter
add dx,25
sub cx,25
cmp cx,dx
ja fkt_checkcrash_weiter

xor ch,ch
mov cl,[di+3]                           ;typ des raumschiffes
shl cx,1                                ;x2
add [3476],cx                           ;punkte addieren
mov [di+3],byte 7                       ;explosion
sub byte [3478],5
fkt_checkcrash_weiter:
ret

;die verbleibenden f�nf byte kann ich jetzt ruhig verschwenden ;-)


db "T.ACK"                              ;und eine sch”ne signatur ;-)

ende:
times 2048-(ende-boot_anfang) db 0      ;und weil es so sch”n ist, noch auf 2048 bytes auff�llen
