tetros/code.asm
2016-09-23 09:03:40 +02:00

365 lines
7.5 KiB
NASM

%macro sleep 0
pusha
mov ah, 0x86
int 0x15
popa
%endmacro
section .text
; TODO zufallszahlen
; TODO lodsw untersuchen
; TODO print_brick optimieren ähnlich wie check_collision
; TODO volle zeilen löschen
; ----------------------------------------------------------------------
xor ax, ax ; init ds for lodsb
mov ds, ax
;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:
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
;call wait_abit
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
cmp bl, 0
je clear_keys ; no collision
inc dl
jmp clear_keys
right_arrow:
inc dl
call check_collision
cmp bl, 0
je clear_keys ; no collision
dec dl
jmp clear_keys
up_arrow:
; TODO
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
cmp bl, 0
je no_collision
dec dh
mov bx, 9
call print_brick
jmp new_brick
no_collision:
jmp loop
; DX = position (DH = row), AL = brick
; return BL = 0 -> no collision
check_collision:
pusha
call brick_offset ; result in SI
lodsb
mov ah, al
lodsb
;call print_ax
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
cmp ah, 0 ; check if color is black
je is_zero_x
inc bl
is_zero_x:
pop ax
is_zero:
shl ax, 1
inc dl
loop dd
sub dl, 4
inc dh
pop cx
loop cc
popa
ret
; ======================================================================
select_brick:
mov ah, 2 ; get time
int 0x1a
mov ax, word [seed_value + 0x7c00]
mul dx ; result in dx: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
; ======================================================================
brick_offset:
xor ah, ah ; compute the offset of the brick
shl ax, 3 ; ax = ax * 8
xchg si, ax ; mov si, ax
add si, bricks + 0x7c00
ret
clear_brick:
xor bx, bx
; AL = number of brick
; DL = column
; DH = row
; BX = 9 -> show brick; 0 -> delete brick (BL = start color for brick)
; on return AX and DX will not be modified
print_brick:
pusha
cmp bx, 0
jz print_brick_no_color
add bl, al
mov bh, bl
shl bl, 4
or bl, bh
xor bh, bh
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, 0x0958 ; 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
; ----------------------------------------------------------------------
init_screen:
call clear_screen
mov cx, 18 ; 18 rows
mov dh, 3 ; row 3
init_screen_a:
push cx
inc dh ; inc row
xor bx, bx
mov ah, 2 ; set cursor position
mov dl, 33 ; column
int 0x10
call init_screen_write_x
mov ah, 2 ; set cursor position
mov dl, 46 ; column
int 0x10
call init_screen_write_x
pop cx
loop init_screen_a
mov ah, 2 ; set cursor position
mov dl, 33
int 0x10
mov ax, 0x0958 ; write character
mov cx, 13
mov bl, 0x77 ; gray on gray
int 0x10
ret
init_screen_write_x:
mov ax, 0x0958
mov cx, 1
mov bx, 0x77
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
; ----------------------------------------------------------------------
; print_ax:
; mov cx, 16
; mov dx, ax
; print_ax_loop:
; push cx
; test dx, 1000000000000000b
; jz print_ax_zero
; mov al, '1'
; jmp print_ax_do
; print_ax_zero:
; mov al, '0'
; print_ax_do:
; mov bx, 0x0006
; mov ah, 0x09 ; print brick
; mov cx, 1
; int 0x10
; call cursor_right
; pop cx
; shl dx, 1
; loop print_ax_loop
; jmp $