📄 cmd_tetris.asm
字号:
%include "util.mac"
%include "vxdn.inc"
%include "icedump.inc"
%include "wiat.inc"
%ifndef MAKEDEP
global Parse_Tetris
extern sdata
extern Parser.error
extern Parser.errorMsg
extern ParseExpression
extern GetVideoMem
bits 32
segment _LTEXT
; original: Tetris v1.0 by Joe Wingbermuehle
; 19981226
; http://www.usmo.com/~joewing
; joewing@usmo.com
;
; adaptation: The Owl 2000/07
;
; keys: left/right arrows to move the block
; up arrow to rotate it
; down arrow to make it fall faster
; esc to end the game
;
;
;-------------------------------------------------------------------------------
; TETRIS [<speed>]
;-------------------------------------------------------------------------------
Parse_Tetris:
; get <speed>
call ParseExpression ; parse <speed>
jnc @F
mov eax,150
@@
mov [speed],eax
; clear screen
mov ecx,[bLINES_current]
movzx ecx,byte [ecx]
mov [LINES],ecx
mov eax,[dWIDTH_current]
imul ecx,[eax]
mov eax,[eax]
mov [WIDTH],eax
xor edx,edx
mov ebx,0x20
call [pPrintChar]
; init timer/kbd/board
and dword [ticks],byte 0
cmp dword [seed],byte 0
jnz @F
VMMCall Get_Last_Updated_System_Time
mov [seed],eax
@@
call [pEmptyKbdBuffer]
mov eax,[WIDTH]
sub eax,[board.width]
shr eax,1
mov [board.x],eax
mov eax,[LINES]
sub eax,[board.lines]
shr eax,1
mov [board.y],eax
call DrawBoard
call DrawNewBlock
; game loop
.main:
call Tick
mov eax,[ticks]
cmp eax,[speed]
jb @F
and dword [ticks],byte 0
call ScrollDown
jnc .main
call DrawNewBlock
jnc .main
jmp short .exit
@@
call [pReadFromKbdBuffer_char]
cmp al,KBD_ESC
jz .exit
push dword .main
cmp al,KBD_LEFT
jz near .scrollLeft
cmp al,KBD_RIGHT
jz near .scrollRight
cmp al,KBD_DOWN
jz near .fastDown
cmp al,KBD_UP
jz near .rotateBlock
retn ; back to .main
.exit:
call [pUpdateAllWindows]
popad
retn
.rotateBlock:
call EraseBlock
push dword [block.id]
push dword [block.lines]
inc dword [block.id]
test byte [block.id],3
jnz @F
sub dword [block.id],byte 4
@@
imul eax,[block.id],byte blocks.01-blocks.00
add eax,blocks+2*4*4
mov eax,[eax]
mov [block.lines],eax
call DrawBlock
jc @F
add esp,byte 8
retn
@@
pop dword [block.lines]
pop dword [block.id]
call DrawBlock
retn
.scrollLeft:
call EraseBlock
dec dword [block.x]
call DrawBlock
jnc @F
inc dword [block.x]
call DrawBlock
@@
retn
.scrollRight:
call EraseBlock
inc dword [block.x]
call DrawBlock
jnc @F
dec dword [block.x]
call DrawBlock
@@
retn
.fastDown:
call ScrollDown
jnc @F
call DrawNewBlock
jnc @F
mov dword [esp], .exit
@@
retn
Tick:
mov eax,1
call [pDelayMilliSec]
inc dword [ticks]
retn
DrawBoard:
mov dl,[board.x]
dec dl
mov dh,[board.y]
add dh,[board.lines]
mov ecx,[board.width]
add ecx,byte 2
mov ebx,0x7F20
call DrawHLine
mov dl,[board.x]
dec dl
mov dh,[board.y]
mov ecx,[board.lines]
inc ecx
mov ebx,0x7F20
call DrawVLine
mov dl,[board.x]
add dl,[board.width]
mov dh,[board.y]
mov ecx,[board.lines]
inc ecx
mov ebx,0x7F20
call DrawVLine
retn
;-------------------------------------------------------------------------------
; stc if board is full
;-------------------------------------------------------------------------------
DrawNewBlock:
mov eax,[board.width]
sub eax,byte 2
shr eax,1
add eax,[board.x]
mov [block.x],eax
mov eax,[board.y]
mov [block.y],eax
call GetRandomBlockID
mov [block.id],eax
imul eax,byte blocks.01-blocks.00
add eax,blocks+2*4*4
mov eax,[eax]
mov [block.lines],eax
call DrawBlock
retn
GetRandomBlockID:
push edx
xor edx,edx
mov eax,[seed]
idiv dword [q]
imul eax,[r]
imul edx,[a]
sub edx,eax
lea eax,[edx+0x7FFFFFFF]
test edx,edx
jle @F
mov eax,edx
@@
mov [seed],eax
xor edx,edx
idiv dword [NumOfBlocks]
lea eax,[4*edx]
pop edx
retn
;-------------------------------------------------------------------------------
; dl: left.x
; dh: left.y
; ecx: length
; bl: char
; bh: color
;-------------------------------------------------------------------------------
DrawHLine:
call [pPrintChar]
retn
;-------------------------------------------------------------------------------
; dl: top.x
; dh: top.y
; ecx: length
; bl: char
; bh: color
;-------------------------------------------------------------------------------
DrawVLine:
push ecx
mov ecx,1
call [pPrintChar]
inc dh
pop ecx
loop DrawVLine
retn
;-------------------------------------------------------------------------------
; stc if block cannot be drawn
;-------------------------------------------------------------------------------
DrawBlock:
push ebx
push ecx
push edx
push esi
push edi
mov ebx,[WIDTH]
call GetVideoMem
mov edi,eax
mov eax,[block.y]
imul eax,ebx
add eax,[block.x]
lea edi,[2*eax+edi] ; edi: upper left corner of blockwindow
imul esi,[block.id],byte blocks.01-blocks.00
add esi,blocks ; esi: upper left corner of blockdata
mov edx,esi
mov ecx,[block.lines]
.loop_check:
lodsd
and eax,[edi]
and eax,0x0F000F00
jz @F
stc
jmp .ret
@@
lodsd
and eax,[edi+4]
and eax,0x0F000F00
jz @F
stc
jmp short .ret
@@
lea edi,[edi+2*ebx]
loop .loop_check
; now let's draw it
imul eax,[block.lines],2
imul eax,ebx
sub edi,eax ; edi: upper left corner of blockwindow
mov esi,edx ; esi: upper left corner of blockdata
mov ecx,[block.lines]
.loop_draw:
lodsw
test ax,ax
jz @F
mov [edi],ax
@@
lodsw
test ax,ax
jz @F
mov [edi+2],ax
@@
lodsw
test ax,ax
jz @F
mov [edi+4],ax
@@
lodsw
test ax,ax
jz @F
mov [edi+6],ax
@@
lea edi,[edi+2*ebx]
loop .loop_draw
call [pUpdateScreen]
clc
.ret:
pop edi
pop esi
pop edx
pop ecx
pop ebx
retn
EraseBlock:
push ebx
push ecx
push edx
push esi
push edi
mov ebx,[WIDTH]
call GetVideoMem
mov edi,eax
mov eax,[block.y]
imul eax,ebx
add eax,[block.x]
lea edi,[2*eax+edi] ; edi: upper left corner of blockwindow
imul esi,[block.id],byte blocks.01-blocks.00
add esi,blocks ; esi: upper left corner of blockdata
mov edx,0x20
mov ecx,[block.lines]
.loop_draw:
lodsw
test ax,ax
jz @F
mov [edi],dx
@@
lodsw
test ax,ax
jz @F
mov [edi+2],dx
@@
lodsw
test ax,ax
jz @F
mov [edi+4],dx
@@
lodsw
test ax,ax
jz @F
mov [edi+6],dx
@@
lea edi,[edi+2*ebx]
loop .loop_draw
call [pUpdateScreen]
pop edi
pop esi
pop edx
pop ecx
pop ebx
retn
;-------------------------------------------------------------------------------
; stc if new block is needed
;-------------------------------------------------------------------------------
ScrollDown:
call EraseBlock
inc dword [block.y]
call DrawBlock
jnc @F
dec dword [block.y]
call DrawBlock
call CompactLines
stc
@@
retn
CompactLines:
push ebx
push ecx
push edx
push esi
push edi
mov ebx,[WIDTH]
call GetVideoMem
mov esi,eax
mov eax,[block.y]
imul eax,ebx
add eax,[board.x]
lea esi,[2*eax+esi] ; esi: left border of blockwindow
mov ecx,[block.lines]
.loop_outer:
push ecx
mov edx,esi
mov ecx,[board.width]
.loop_inner:
lodsw
test ax,0x0F00
loopnz .loop_inner
mov esi,edx
jz @F
; compact a line
mov ecx,[block.y]
sub ecx,[board.y]
inc ecx
.loop_moveline:
push ecx
; move down upper neighbour
mov edi,esi
sub esi,ebx
sub esi,ebx
push esi
mov ecx,[board.width]
rep movsw
pop esi
pop ecx
loop .loop_moveline
mov esi,edx
@@
lea esi,[2*ebx+esi]
pop ecx
loop .loop_outer
call [pUpdateScreen]
pop edi
pop esi
pop edx
pop ecx
pop ebx
retn
segment _LDATA
align 4
ticks: dd 0
seed: dd 0
a: dd 16807
r: dd 2836
q: dd 127773
speed: dd 150
LINES: dd 0
WIDTH: dd 0
NumOfBlocks: dd 7
board:
.x: dd 0
.y: dd 0
.lines: dd 20
.width: dd 12
block:
.x: dd 0
.y: dd 0
.id: dd 0
.lines: dd 0
blocks:
.00:
dw 0x7F20, 0x0000, 0x0000, 0x0000
dw 0x7F20, 0x0000, 0x0000, 0x0000
dw 0x7F20, 0x0000, 0x0000, 0x0000
dw 0x7F20, 0x0000, 0x0000, 0x0000
dd 4
.01:
dw 0x7F20, 0x7F20, 0x7F20, 0x7F20
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 1
.02:
dw 0x7F20, 0x0000, 0x0000, 0x0000
dw 0x7F20, 0x0000, 0x0000, 0x0000
dw 0x7F20, 0x0000, 0x0000, 0x0000
dw 0x7F20, 0x0000, 0x0000, 0x0000
dd 4
.03:
dw 0x7F20, 0x7F20, 0x7F20, 0x7F20
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 1
.10:
dw 0xAF20, 0x0000, 0x0000, 0x0000
dw 0xAF20, 0x0000, 0x0000, 0x0000
dw 0xAF20, 0xAF20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.11:
dw 0x0000, 0x0000, 0xAF20, 0x0000
dw 0xAF20, 0xAF20, 0xAF20, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.12:
dw 0xAF20, 0xAF20, 0x0000, 0x0000
dw 0x0000, 0xAF20, 0x0000, 0x0000
dw 0x0000, 0xAF20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.13:
dw 0xAF20, 0xAF20, 0xAF20, 0x0000
dw 0xAF20, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.20:
dw 0x5F20, 0x0000, 0x0000, 0x0000
dw 0x5F20, 0x5F20, 0x0000, 0x0000
dw 0x5F20, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.21:
dw 0x0000, 0x5F20, 0x0000, 0x0000
dw 0x5F20, 0x5F20, 0x5F20, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.22:
dw 0x0000, 0x5F20, 0x0000, 0x0000
dw 0x5F20, 0x5F20, 0x0000, 0x0000
dw 0x0000, 0x5F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.23:
dw 0x5F20, 0x5F20, 0x5F20, 0x0000
dw 0x0000, 0x5F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.30:
dw 0x4F20, 0x0000, 0x0000, 0x0000
dw 0x4F20, 0x4F20, 0x0000, 0x0000
dw 0x0000, 0x4F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.31:
dw 0x0000, 0x4F20, 0x4F20, 0x0000
dw 0x4F20, 0x4F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.32:
dw 0x4F20, 0x0000, 0x0000, 0x0000
dw 0x4F20, 0x4F20, 0x0000, 0x0000
dw 0x0000, 0x4F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.33:
dw 0x0000, 0x4F20, 0x4F20, 0x0000
dw 0x4F20, 0x4F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.40:
dw 0x0000, 0x3F20, 0x0000, 0x0000
dw 0x0000, 0x3F20, 0x0000, 0x0000
dw 0x3F20, 0x3F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.41:
dw 0x3F20, 0x3F20, 0x3F20, 0x0000
dw 0x0000, 0x0000, 0x3F20, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.42:
dw 0x3F20, 0x3F20, 0x0000, 0x0000
dw 0x3F20, 0x0000, 0x0000, 0x0000
dw 0x3F20, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.43:
dw 0x3F20, 0x0000, 0x0000, 0x0000
dw 0x3F20, 0x3F20, 0x3F20, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.50:
dw 0x0000, 0x2F20, 0x0000, 0x0000
dw 0x2F20, 0x2F20, 0x0000, 0x0000
dw 0x2F20, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.51:
dw 0x2F20, 0x2F20, 0x0000, 0x0000
dw 0x0000, 0x2F20, 0x2F20, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.52:
dw 0x0000, 0x2F20, 0x0000, 0x0000
dw 0x2F20, 0x2F20, 0x0000, 0x0000
dw 0x2F20, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 3
.53:
dw 0x2F20, 0x2F20, 0x0000, 0x0000
dw 0x0000, 0x2F20, 0x2F20, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.60:
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.61:
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.62:
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
.63:
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x9F20, 0x9F20, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dw 0x0000, 0x0000, 0x0000, 0x0000
dd 2
%endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -