tetros/code.asm
2016-09-27 08:51:22 +02:00

414 lines
8.9 KiB
NASM

; TODO Nachricht game over
; TODO intro
; TODO show next brick
; ==============================================================================
; DEBUGGING MACROS
; ==============================================================================
%macro print_reg 1
mov dx, %1
mov cx, 16
print_reg_loop:
push cx
mov al, '0'
test dh, 10000000b
jz print_reg_do
mov al, '1'
print_reg_do:
mov bx, 0x0006 ; page = 0 (BH), color = gray on black (BL)
mov ah, 0x09 ; write character stored in AL
mov cx, 1
int 0x10
mov ah, 3 ; move cursor one column forward
int 0x10
inc dx
mov ah, 2 ; set cursor
int 0x10
pop cx
shl dx, 1
loop print_reg_loop
jmp $
%endmacro
; ==============================================================================
; MACROS
; ==============================================================================
%macro sleep 1
pusha
xor cx, cx
mov dx, %1
mov ah, 0x86
int 0x15
popa
%endmacro
%macro select_brick 0
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 ; move result in AL
%endmacro
%macro init_screen 0
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 dx ; increase column
mov cx, 12 ; width of box
xor bx, bx ; color
call write_data
ib:
pop cx
loop ia
%endmacro
; ==============================================================================
section .text
xor ax, ax ; init ds for lodsb
mov ds, ax
start_tetris:
;call initial_animation
init_screen
new_brick:
mov word [delay + 0x7c00], 500
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
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:
push cx
sleep 100 ; wait 100 microseconds
push ax
mov ah, 1 ; check for keystroke; AX modified
int 0x16 ; http://www.ctyme.com/intr/rb-1755.htm
mov cx, ax
pop ax
jz no_key ; no keystroke
call clear_brick
; 4b left, 48 up, 4d right, 50 down
cmp ch, 0x4b ; left arrow
je left_arrow ; http://stackoverflow.com/questions/16939449/how-to-detect-arrow-keys-in-assembly
cmp ch, 0x48 ; up arrow
je up_arrow
cmp ch, 0x4d
je right_arrow
mov word [delay + 0x7c00], 30 ; every other key is fast down
jmp clear_keys
left_arrow:
dec dx
call check_collision
je clear_keys ; no collision
inc dx
jmp clear_keys
right_arrow:
inc dx
call check_collision
je clear_keys ; no collision
dec dx
jmp clear_keys
up_arrow:
mov bl, al
ror al, 3
inc ax ; inc al, but inc ax needs less memory
and al, 11100011b
rol al, 3
call check_collision
je clear_keys ; no collision
mov al, bl
clear_keys:
call print_brick
push ax
xor ah, ah ; remove key from buffer
int 0x16
pop ax
no_key:
pop cx
loop wait_a
call clear_brick
inc dh ; increase row
call check_collision
je no_collision
dec dh
call print_brick
call check_filled
jmp new_brick
no_collision:
jmp loop
write_data:
mov ah, 2 ; set cursor
int 0x10
mov ax, 0x0900 ; write boxes
int 0x10
ret
set_and_read:
mov ah, 2 ; set cursor position
int 0x10
mov ah, 8 ; read character and attribute, BH = 0
int 0x10 ; result in AX
ret
check_filled:
pusha
mov dh, 21 ; row
next_row:
dec dh
jz cf_done
xor bx, bx
mov cx, 12
mov dl, 34 ; column
cf_loop:
call set_and_read
shr ah, 4 ; rotate to get background color in AH
jz cf_is_zero ; jmp if background color is 0
inc bx
inc dx
cf_is_zero:
loop cf_loop
cmp bl, 12
jne next_row
replace_next_row:
call replace_current_row
dec dh
jnz replace_next_row
popa
call check_filled
ret
cf_done:
popa
ret
replace_current_row: ; DH = current row
pusha
mov dl, 34 ; replace current row with row above
mov cx, 12
cf_aa:
push cx
dec dh
call set_and_read
inc dh
mov bl, ah ; color from AH to BL
mov ah, 2 ; set cursor position
int 0x10
mov ax, 0x920 ; write character
mov cx, 1
int 0x10
inc dx
pop cx
loop cf_aa
popa
ret
game_over:
jmp $
; 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
clear_brick:
xor bx, bx
jmp print_brick_no_color
print_brick:
mov bx, 9
push ax
and al, 7
add bl, al
shl bl, 4
pop ax
print_brick_no_color:
inc bx
mov di, bx
jmp check_collision_main
; BL = color of brick
; DX = position (DH = row), AL = brick
; return: flag
check_collision:
mov di, 0
check_collision_main: ; DI = 1 -> check, 0 -> print
pusha
call brick_offset ; result in SI
lodsw
xchg ah, al
xor bx, bx ; set BH = BL = 0
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
or di, di
jz ee ; jump if we want to check for collisions
; print space with color stored in DI at postion DX
pusha
mov bx, di
dec bx
mov ax, 0x0920 ; print brick
mov cx, 1
int 0x10
popa
jmp is_zero_a
ee:
mov ah, 8 ; read character and attribute, BH = 0
int 0x10 ; result in AX
shr ah, 4 ; rotate to get background color in AH
jz is_zero_a ; jmp if background color is 0
inc bx
is_zero_a:
pop ax
is_zero:
shl ax, 1
inc dx ; 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
; ======================================================================
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
; ----------------------------------------------------------------------
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
;current_brick: db 0
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
; ----------------------------------------------------------------------