mirror of
https://github.com/daniel-e/tetros.git
synced 2025-04-25 03:08:05 +02:00
380 lines
7.9 KiB
NASM
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
|
|
; ----------------------------------------------------------------------
|