tetros/code.asm
2016-09-26 08:58:01 +02:00

380 lines
7.9 KiB
NASM

%macro print_reg 1
mov dx, %1
mov cx, 16
print_reg_loop:
push cx
test dx, 1000000000000000b
jz print_reg_zero
mov al, '1'
jmp print_reg_do
print_reg_zero:
mov al, '0'
print_reg_do:
mov bx, 0x0006
mov ah, 0x09 ; print brick
mov cx, 1
int 0x10
call cursor_right
pop cx
shl dx, 1
loop print_reg_loop
jmp $
%endmacro
%macro sleep 0
mov ah, 0x86
int 0x15
%endmacro
section .text
; TODO print_brick optimieren ähnlich wie check_collision
; TODO volle zeilen löschen
; TODO Nachricht game over
; TODO intro
; TODO beim rotieren check_collision aufrufen
; ----------------------------------------------------------------------
xor ax, ax ; init ds for lodsb
mov ds, ax
start_tetris:
;call initial_animation
call init_screen
new_brick:
mov word [delay + 0x7c00], 500 ; time
call select_brick ; returns the selected brick in AL
mov dx, 0x0426 ; start at row 4 and col 38
loop:
call check_collision
jne game_over
mov bx, 9 ; show brick
call print_brick
; if you modify AL or DX here, you should know what you're doing
wait_or_keyboard:
mov cx, word [delay + 0x7c00]
wait_a:
pusha
xor cx, cx
mov dx, 100 ; wait 100 microseconds
sleep
popa
push ax
mov ah, 1 ; check for keystroke
int 0x16 ; http://www.ctyme.com/intr/rb-1755.htm
mov bx, ax
pop ax
jz no_key ; no keystroke
push bx
call clear_brick
pop bx
cmp bh, 0x4b ; left arrow
je left_arrow ; http://stackoverflow.com/questions/16939449/how-to-detect-arrow-keys-in-assembly
cmp bh, 0x48 ; up arrow
je up_arrow
cmp bh, 0x4d
je right_arrow
cmp bh, 0x50
je down_arrow
jmp clear_keys
down_arrow:
mov word [delay + 0x7c00], 30
jmp clear_keys
left_arrow:
dec dl
call check_collision
je clear_keys ; no collision
inc dl
jmp clear_keys
right_arrow:
inc dl
call check_collision
je clear_keys ; no collision
dec dl
jmp clear_keys
up_arrow:
ror al, 3
inc al
and al, 11100011b
rol al, 3
clear_keys:
mov bx, 9
call print_brick
push ax
xor ah, ah ; remove key from buffer
int 0x16
pop ax
no_key:
loop wait_a
call clear_brick
inc dh ; increase row
call check_collision
je no_collision
dec dh
mov bx, 9
call print_brick
jmp new_brick
no_collision:
jmp loop
game_over:
xor bh, bh
xor dx, dx
mov ah, 2 ; set cursor position
int 0x10
mov ax, 0x0947 ; print brick
mov cx, 80
int 0x10
xor ax, ax ; wait for keyboard
int 16h
jmp start_tetris
; DX = position (DH = row), AL = brick
; flag
check_collision:
pusha
call brick_offset ; result in SI
lodsw
xchg ah, al
xor bx, bx
mov cx, 4
cc:
push cx
mov cl, 4
dd:
test ax, 1000000000000000b
jz is_zero
push ax
mov ah, 2 ; set cursor position, BH = 0
int 0x10
mov ah, 8 ; read character and attribute
int 0x10
shr ah, 4 ; background color
jz is_zero_x
inc bl
is_zero_x:
pop ax
is_zero:
shl ax, 1
inc dl ; move to next column
loop dd
sub dl, 4 ; reset column
inc dh ; move to next row
pop cx
loop cc
cmp bl, 0 ; bl != 0 -> collision
popa
ret
; ======================================================================
select_brick:
mov ah, 2 ; get time
int 0x1a
mov ax, word [seed_value + 0x7c00]
xor ax, dx
mov bx, 33797
mul bx
inc ax
mov word [seed_value + 0x7c00], ax
xor dx, dx
mov bx, 7
div bx
xchg ax, dx
ret
; TODO below mem optimized
; ======================================================================
clear_screen:
mov ax, 3 ; clear screen
int 0x10
mov ah, 1 ; hide cursor
mov cx, 0x2607
int 0x10
ret
; ======================================================================
; AL = number of brick
; 00000000
; ^^^ = number of brick
; ^^ = rotation
brick_offset:
xor ah, ah ; compute the offset of the brick
push ax
and al, 7
shl al, 3 ; al *= 8
xchg si, ax ; mov si, ax
add si, bricks + 0x7c00
pop ax
shr al, 3 ; add rotation to offset
shl al, 1
add si, ax
ret
clear_brick:
xor bx, bx
; AL = brick data
; DL = column
; DH = row
; BX = 9 -> show brick; 0 -> delete brick (BL = start color for brick)
print_brick:
pusha
cmp bx, 0
jz print_brick_no_color
push ax
and al, 7
add bl, al
shl bl, 4
pop ax
print_brick_no_color:
call brick_offset ; result in si
; bl = color
; ds:si = address of brick
; dx = position of brick
mov cx, 2
ccc:
push cx
lodsb ; load next two rows of brick
call brick_line ; print first row
inc dh
call brick_line ; print second row
inc dh
pop cx
loop ccc
popa
ret
brick_line:
; bh = 0
; bl = color
; dx = position
; al = brick data
mov ah, 2 ; set cursor position
int 0x10
mov cx, 4
brick_line_a:
pusha
and al, 128
jz brick_line_d
mov ax, 0x0920 ; print brick
mov cx, 1
int 0x10
brick_line_d:
call cursor_right
popa
shl al, 1
loop brick_line_a
ret
; ----------------------------------------------------------------------
cursor_right:
pusha
mov ah, 3 ; get cursor position
xor bx, bx
int 0x10
inc dl ; increase column
mov ah, 2 ; set new cursor position
int 0x10
popa
ret
; ----------------------------------------------------------------------
; this should be highly memory optimized
init_screen:
call clear_screen
mov dh, 3
mov cx, 18
ia:
push cx
inc dh ; increment row
mov dl, 33 ; set column
mov cx, 14 ; width of box
mov bx, 0x77 ; color
call write_data
cmp dh, 21 ; don't remove last line
je ib ; if last line jump
inc dl ; increase column
mov cx, 12 ; width of box
xor bx, bx ; color
call write_data
ib:
pop cx
loop ia
ret
write_data:
mov ah, 2 ; set cursor
int 0x10
mov ax, 0x0900 ; write boxes
int 0x10
ret
; ----------------------------------------------------------------------
initial_animation:
; call clear_screen
; mov ah, 2 ; set cursor position
; xor bx, bx
; mov dh, 5
; mov dl, 10
; int 0x10
; mov si, message + 0x7c00 ; MBR is loaded at address 0000:7C00
initial_animation_next:
; cld
; lodsb
; cmp al, 0
; jne initial_animation_do
; xor ax, ax ; wait for keyboard
; int 16h
; ret
initial_animation_do:
; mov bx, 0x0a ; write character
; mov cx, 1
; mov ah, 9
; int 0x10
; call cursor_right
; push dx
; mov cx, 2 ; wait 2x65536 microseconds
; xor dx, dx
; call wait_abit
; pop dx
; jmp initial_animation_next
; ----------------------------------------------------------------------
;message: db "Let's play tetris ...", 0
seed_value: dw 0x1234
delay: dw 500
bricks:
db 01000100b, 01000100b, 11110000b, 00000000b
db 01000100b, 01000100b, 11110000b, 00000000b
db 00100010b, 01100000b, 11100010b, 00000000b
db 01100100b, 01000000b, 10001110b, 00000000b
db 01000100b, 01100000b, 00101110b, 00000000b
db 01100010b, 00100000b, 11101000b, 00000000b
db 01100110b, 00000000b, 01100110b, 00000000b
db 01100110b, 00000000b, 01100110b, 00000000b
db 11000110b, 00000000b, 00100110b, 01000000b
db 11000110b, 00000000b, 00100110b, 01000000b
db 01001110b, 00000000b, 01001100b, 01000000b
db 11100100b, 00000000b, 10001100b, 10000000b
db 01101100b, 00000000b, 10001100b, 01000000b
db 01101100b, 00000000b, 10001100b, 01000000b
; ----------------------------------------------------------------------
; DEBUGGING
; ----------------------------------------------------------------------