编译环境:masm5.0+link3.6
assume cs:code,ds:data,ss:stack,es:data
;;;;;;;;按键的扫描码
down equ 50h
left equ 4bh
right equ 4dh
up equ 48h
ESCkey equ 1
F1 equ 3bh
F2 equ 3ch
space equ 39h
nowdot dw 0 ;位置y:x 当前显示的方块的位置
nowtetris dw 0,0,0,0,0;当前方块的形状(2字),颜色,种类的指针,第几个子形状*4
nexttetris dw 0,0,0,0,0;同nowtetris,下一个要显示的方块
oldtetris dw 0,0,0,0,0
nowtime db 0;;;; 时间
mark db 0,0;;;; 得到的分数
lptetris dw 0,18,36
dw 18*3,18*4,18*5
dw 18*6,18*7,18*8
;;;直接定址表,每个种类的偏移地址
color db 0;颜色
over db "GBABMBEBOBVBEBRB!B"
db "RBeBsBtBaBrBtB BkBeByB(BYB)B B BQBuBiBtB B(BoBtBhBeBrB BaBnByB BkBeByB)B"
;;;;;;;;;游戏失败提示
quit db "QBuBiBtB?B B(BYB/BNB)B"
;ESC键退出提示
szlevel db "LEVEL:"
score db "S@C@O@R@E@:@"
winner db "Thank you for everyone.You are winner!$"
helps db 24," :deformation"
db 25," :moves down "
db 27," :moves left "
db 26," :moves right"
db "space:pause "
db "F1 : about "
db "ESC : exit "
about db " About Tetris "
db " Version 1.0 "
db " www.asmedu.net "
db "Copyright (c) 2012"
data ends
stack segment
db 128 dup (?);;;;128字节栈
stack ends
code segment
oldint1ch dw 0,0;旧int1ch的地址
time db 0,0
timechar db 4,2,0
newint1c:
pushf ;新1ch中断入口
call dword ptr cs:oldint1ch ; 这里都是老程序了
inc cs:time
offlevel:
cmp cs:time,level;offlevel指向这个15来达到控制下落速度的目的
jb returnd
mov cs:time,0
inc cs:time+1
call showtime
returnd:
iret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<
showtime:
push ax ;主意不要寄存器冲突就好
push cx
push si
push di
push es
mov ax,0b800h
mov es,ax
mov di,1742
xor si,si
mov cx,3
mov ah,2
mov al,':'
mov es:[di+4],ax
mov es:[di+10],ax;先将两个":"显示出来
s1:push cx
mov cl,4
mov al,cs:timechar[si]
out 70h,al
in al,71h
mov ah,al
shr ah,cl
and al,0fh
add ax,3030h
mov es:[di],ah
mov ah,2
mov es:[di+1],ah
mov es:[di+2],ax
inc si
add di,6
pop cx
loop s1
pop es
pop di
pop si
pop cx
pop ax
ret
; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;void paint proto lptetris:word,color:word
;功能:采取xor显示,在相同位置显示相同形状的方块,第一次是显示,第二次是清除
; 入口 : lptetris指向方块结构的指针,color方块的颜色
; 出口 :无
paint:
push bp
mov bp,sp
push cx
push bx
push dx
push si
push di
mov cx,4
mov bx,[bp+4];方块指针
mov ax,[bx]
mov dx,[bp+6];颜色
mov dh,1
xchg dh,dl
mov si,dx
mov dx,[bx+2]
cmp word ptr [bx+6],offset tetris1
jb loop1
mov cx,5
loop1:
push cx
push dx
push ax
mov cx,5
xor dx,dx
and ax,31
div cx
mov bx,nowdot;当前位置
add bl,dl
add bh,al
mov al,80
mul bh
mov di,ax;位置x=(ax&15)%4+nowdot低8位
mov al,bl
mov ah,0
shl ax,1
add di,ax;位置y=(ax%15)/4+nowdot高8位
xor es:[di],si;
pop ax
pop dx
call div32
pop cx
loop loop1
loop_2:
pop di
pop si
pop dx
pop bx
pop cx
pop bp
ret 4
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;viod gettetris proto lptetris
;功能 :随机设置要显示的方块
;入口 :指向4字指针(方块的形状,颜色,当前种类指针,第几个形状)
;返回 :无
;
gettetris:
push bp
mov bp,sp
push bx
push si
push cx
mov si,[bp+4]
in al,40h;;汇编没有rand函数,从40h端口读取一个字节当随机数,毕竟伪随机数的算法得好多代码
mov ah,0
mov cl,levels
div cl
xchg ah,al
shl al,1
mov ah,0
mov bx,ax
mov bx,lptetris[bx]
mov [si+6],bx;种类指针
push [bx+16];颜色
pop [si+4]
in al,40h
mov ah,0
mov cl,4
div cl
xchg ah,al
shl al,1
shl al,1
mov ah,0
mov [si+8],ax;第几个形状(*2)
add bx,ax
push [bx+2]
push [bx]
pop [si];形状
pop [si+2];形状
pop cx
pop si
pop bx
mov sp,bp
pop bp
mov nowdot,107h;x:y
ret 2
;<<<<<<<<<<<<<<<<<<<<<<<<<<<
; bool canmovedot proto [bp+4]:位置
;canmove的穿透版,判断能否下落
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<
canmovedot:
push bp
mov bp,sp
push bx
push di
mov bx,[bp+4]
cmp bh,23;不允许超过第23行
ja @cannot
mov al,80
mul bh
mov di,ax
mov bh,0
shl bx,1
or bx,bx
jz @cannot;第0列是边界线,不允许
cmp bx,38
ja @cannot;第20列是边界,不允许
add di,bx
inc di;测试的是颜色
@can1:
test byte ptr es:[di],08
jz @can;当前位置没有高亮属性,就可以返回允许(0标志)
add di,80;测试下一行
cmp di, 1900;不能超过第23行
jb @can1
@cannot:
mov ax,1;1 no
jmp canret
@can:
xor ax,ax;0 ok
canret:
pop di
pop bx
mov sp,bp
pop bp
ret 2
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; bool canmove proto dot:[bp+4],lpmodel:[bp+6]
;功能:判断给定位置能否显示给定形状
;入口: dot指定的位置,lpmodel指定形状指针
;出口: 如果可以显示返回0,否则返回1
canmove:
push bp
mov bp,sp
push cx
push bx
push dx
push di
mov cx,4
mov bx,[bp+6]
mov ax,[bx]
mov dx,[bx+2]
or ax,ax
jnz @l_oop1
push [bp+4]
call canmovedot
jmp nret
@l_oop1:
cmp word ptr [bx+6],offset tetris1+18
jb l_oop1
mov cx,5
l_oop1:
push cx
push dx
push ax
mov cx,5
xor dx,dx
and ax,31
div cx
mov bx,[bp+4];当前位置
add bl,dl
add bh,al
cmp bh,23
ja l_oop3
mov al,80
mul bh
mov di,ax;位置x=(ax&31)%5+nowdot低8位
mov al,bl
mov ah,0
shl ax,1
or ax,ax
jz l_oop3
cmp ax,38
ja l_oop3
add di,ax;位置y=(ax%31)/5+nowdot高8位
test byte ptr es:[di+1],8;
jz l_oop2
l_oop3: mov ax,1
add sp,6
jmp nret
l_oop2:
pop ax
pop dx
call div32;ax>>=5
pop cx
loop l_oop1
nret:
pop di
pop dx
pop bx
pop cx
pop bp
ret 4
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
div32:
push bx
push ax
mov ax,dx
xor dx,dx
mov cx,32
div cx
mov bx,ax
pop ax
div cx
mov dx,bx
pop bx
ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
; void movewindow proto
;功能:把上一行(x-1)复制到当前行x
;入口:无
;出口:无
movewindow:
push cx
push di
push bx
push ds
push es
pop ds
push bp
mov bp,sp
mov cx,[bp+12];;取testtetris函数的当前行cx值
pop bp
dec cx
moveloop:
push cx
mov cx,38
mov di,39
lea si,[bx+di-80]
lea di,[bx+di]
std
rep movsb
pop cx
sub bx,80
loop moveloop
mov cx,38
mov al,0
mov di,82
cld
rep stosb;第一行填0
pop ds
inc mark
pop bx
add bx,80
pop di
pop cx
ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;void testtetris proto
;功能:判断是否可以得分,如果可以,就清除满的那行,并让上面的"砖头 落"下来
;入口 无
;出口 无
testtetris:
push cx
push di
push bx
mov bx,1840
mov di,39
mov cx,23
@loop:
push cx;;如果会调用movewindow函数,这个值会被movewindow从栈中复制
mov cx,18
@loop1:
test byte ptr es:[bx+di],8
jz @loop2
sub di,2
loop @loop1
call movewindow
@loop2:
pop cx
sub bx,80
mov di,39
loop @loop
pop bx
pop di
pop cx
ret
;<<<<<<<<<<<<<<<
;void printfc void
;显示分数
printfc:
push bx
push di
mov di,1270;显示位置
mov al,mark
mov ah,0
mov bl,5
div bl
cmp al,1
jnz @p1;;;;;;;;;;;;设置速度
mov byte ptr cs:[offlevel+5],level-3
mov word ptr es:[1424],432h
jmp @p4
@p1:
cmp al,2
jnz @p2
mov byte ptr cs:[offlevel+5],level-5
mov word ptr es:[1424],433h
jmp @p4
@p2:
cmp al,3
jnz @p3
mov byte ptr cs:[offlevel+5],level-7
mov word ptr es:[1424],434h
jmp @p4
@p3:
cmp al,4
jnz @p4
mov byte ptr cs:[offlevel+5],level-8
mov word ptr es:[1424],435h
@p4:
mov al,mark
mov bl,10
@p:
mov ah,0
div bl
add ah,30h
mov byte ptr es:[di],ah
mov byte ptr es:[di+1],4
or al,al
jz retret
dec di;倒序显示
dec di
jmp @p
retret:
pop di
pop bx
ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;void setint1ch proto void
;设置1c中断
setint1ch:
push es
xor ax,ax
mov es,ax
push es:[1ch*4]
pop cs:oldint1ch
push es:[1ch*4+2]
pop cs:oldint1ch+2
cli
mov word ptr es:[1ch*4],offset newint1c
mov es:[1ch*4+2],cs
sti
setret:
pop es
ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;;程序开始
main:
mov ax,stack
mov ss,ax
mov sp,128
mov ax,data
mov ds,ax
xor ax,ax
int 10h;设置屏幕40*25
mov ah,1
mov ch,20h
int 10h;不显示光标
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
mov ax,0b800h
mov es,ax
call init
mov ax,offset nexttetris
push ax
call gettetris
mov nowdot,0945h
push nexttetris+4
mov ax,offset nexttetris
push ax
call paint;显示 "下一个"方块
mov ax,offset nowtetris
push ax
call gettetris
push nowtetris+4
mov ax,offset nowtetris
push ax
call paint;显示当前方块
mov al,cs:time+1
mov nowtime,al;获得当前秒数
startthis:
mov al,cs:time+1
cmp al,nowtime;获得当前秒数,并和nowtime比较,不同就可以下落了
jnz @3
jmp @2
@3: ;时间到了,是时候往下"落"了
mov nowtime,al
mov ax,offset nowtetris
push ax
mov ax,nowdot
inc ah;
push ax
call canmove;判断可以"落"不
or ax,ax
jnz @1
push nowtetris+4;清除当前显示
mov ax,offset nowtetris
push ax
call paint
inc byte ptr nowdot+1;"落"一行
push nowtetris+4
mov ax,offset nowtetris
push ax
call paint;显示