欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

自己写的俄罗斯方块

自己写的俄罗斯方块

编译环境: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

levels    equ 9;放块种类个数
level    equ 11;等级速度调整
data segment 
;;;;定义方块形状,一个word的每4位是一个小方块的位置
tetris  dw 98ech,0,0cc7h,1,98ech,0,0cc7h,1,2;反z
    dw 18ebh,1,04c7h,0,18ebh,1,04c7h,0,3;z
    dw 447h, 0,994bh,0,14c7h,0,88cbh,0,4;反L
    dw 443h, 0,9970h,0,443h, 0,9970h,0,1;I
    dw 445h, 0,4cbh, 0,14c7h,1,996ch,0,5;L
    dw 94c7h,0,98ebh,0,446h, 0,94cbh,0,7;T
    dw 88c7h,0,88c7h,0,88c7h,0,88c7h,0,6;田
tetris1  dw 0,0,0,0,0,0,0,0,8eh        ;一个点,有穿透属性
    dw 22h  ,0,84cbh,10h, 22h  ,  0,84cbh,10h,5h;...
;这里一tetris1为分界线,在它前的显示4次,从它往后都是5次,另外,颜色不许有第4位的高亮属性
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;显示
  
  jmp @2
@1:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;到底了
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint;清除当前显示
  mov ax,15
  push ax
  mov ax,offset nowtetris
  push ax
  call paint;;;;;;改变颜色(前景高亮+白色)
  mov al,mark
  push ax
  call testtetris;判断是否可以得分 
  pop ax
  mov ah,mark
  sub ah,al
  jz tests
  dec ah
  add mark,ah
tests:
  call printfc
  mov al,mark
  cmp al,250
  jb @next@1
  call @winner
@next@1:
  push es
  push ds
  pop es
  mov si,offset nexttetris
  mov di,offset nowtetris
  mov cx,10
  cld
  rep movsb;把下一个方块给当前方块
  pop es
  mov nowdot,0945h
  push nexttetris+4
  mov ax,offset nexttetris
  push ax
  call paint;清除"下一个"方块
  mov ax,offset nexttetris
  push ax
  call gettetris
  push nowdot
  mov nowdot,0945h
  push nexttetris+4
  mov ax,offset nexttetris
  push ax
  call paint;;;;;;;;显示"下一个"方块
  
  pop nowdot
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint;显示当前方块
  mov ax,offset nowtetris
  push ax
  mov ax, nowdot;
  inc ah
  push ax
  call canmove
  or ax,ax;;;如果刚显示出来,但是不能往下"落",表示下面的方块很高了,要结束了
  jnz restart;不能下了就结束了
  
@2:
  mov ah,11;判断用户是否按键了
  int 21h
  or al,al
  jnz @5;按了就读出按键的扫描码和ascii
  jmp near ptr startthis
@5:
  xor ax,ax
  int 16h
  call dispatch;处理按键
  jmp startthis
restart:;;;;;失败了
  mov al,0
  xor di,di
  mov cx,4000
  cld
  rep stosb
  lea si,over;显示失败信息
  mov di,12*80+28
  MOV CX,18
  rep movsb
  add di,118
  mov cx,72
  rep movsb
  xor ax,ax
  int 16h;按Y再玩一次
  cmp ah,15h
  jnz codeend
  jmp main
codeend:
call quitgame
;<<<<<<<<<<<<<<<<<<<<<<<<<<<
;void @winner proto void
;显示胜利信息并退出
@winner:
  mov ax,400h
  xor di,di
  mov cx,1000
  cld
  rep stosw
  mov si,offset winner
  mov ah,2
  mov di,13*80+2
  mov cx,38
  cld
  @win:
    lodsb
    stosw
  loop @win
  mov ah,7
  int 21h
  call quitgame
  ret
;<<<<<<<<<<<<<<<<<<<<<
;viod init proto
;功能:设置屏幕,"画"界线
;入口:无
;返回:无
init:
  push cx
  push di
  push es
  xor ax,ax
  mov es,ax
  mov cx,es:[1ch*4+2]
  mov ax,cs
  pop es
  cmp ax,cx
  jz @init1;如果中断已经设过,就不再设置
  call initwindow;欢迎界面
  call setint1ch;设置中断
@init1:
  mov cx,1000
  xor di,di
  mov ax,di
  cld
  rep stosw
  mov si,offset score;显示"score"
  mov di,1250
  mov cx,12
  rep movsb
  mov cx,6
  mov di,1410
  mov si,offset szlevel;显示"level:"
  mov ah,10
  cld
  @init:
    lodsb
    stosw
  loop @init
  mov word ptr es:[di+2],431h;等级
  call help;显示按键信息
  call interface;画可移动区域
  mov mark,0;分数
  mov byte ptr cs:[offlevel+5],level;设置初始等级下落速度
  call printfc;显示分数
  pop di
  pop cx
  ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
initwindow:
  push ds
  push si
  push di
  push cx
  push bx
  call draw
  db "TTTTT   EEEEE   TTTTT   RRRR   III   SSS"
  db "  T     E         T     R  R    I    S  "
    db "  T     EEEEE     T     RRRR    I     S "
  db "  T     E         T     R R     I      S"
  db "  T     EEEEE     T     R  R   III   SSS"
  @name db "by chinatree"
  @data db "Copyright (c) 2012  www.asmedu.net"
draw:
  pop si;上面字符的首地址
  mov color,0
  push cs
  pop ds
  mov di,720
  cld
  mov cx,200
  @draw:
    lodsb
    mov ah,al
    xor ah,75h
    stosw
  loop @draw;TETRIS这几个大字母
  mov cx,12
  mov ah,3h
  mov di,1550
  cld
  @draw3:
    lodsb
    stosw
  loop @draw3;显示"by chinatree"
  mov cx,34
  mov di,1606
  cld
  @draw4:
    lodsb
    stosw
  loop @draw4;显示"Copyright (c) 2012..."
  mov cx,2
  @draw2:
    push cx
    mov cx,0
    @draw6:
      mov ah,11
      int 21h
      or al,al
      jnz @draw1
    loop @draw6;判断用户是否按键了,如果按了,就返回,没按就延时
    pop cx
  loop @draw2
  jmp @draw7
  @draw1:
  xor ax,ax
  int 16h
  pop cx;Illegal use of CS register
  @draw7:
  pop bx
  pop cx
  pop di
  pop si
  pop ds
  ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;void interface proto
;功能;画出方块移动范围
;入口:无
;返回:无
interface:
  push di
  push cx
  xor di,di
  mov ax,77dbh
  mov cx,40
  cld
  rep stosw
  mov cx,23
@s:
  mov es:[di],ax
  mov es:[di+40],ax
  mov es:[di+78],ax
  add di,80
  loop @s
  mov cx,40
  rep stosw
  pop cx
  pop di
  ret
;<<<<<<<<<<<<<<<<<<<<<
;viod quitgame proto void
;退出
quitgame:
  mov ax,2
  int 10h
  mov ax,0b800h
  mov es,ax
  mov ax,720h
  mov cx,2000
  xor di,di
  cld 
  rep stosw
  xor ax,ax
  mov es,ax
  cli
  push cs:oldint1ch;把原来的中断还设回去
  pop es:[1ch*4]
  push cs:oldint1ch+2
  pop es:[1ch*4+2]
  sti
  mov ax,4c00h
  int 21h 
;<<<<<<<<<<<<<<<<
;void help proto
;功能:显示帮助和版本信息
;入口:无
;出口:无
help:
  push cx
  push di
  mov si,offset helps
  mov di,208
  mov cx,7
  mov ah,6
  @loop@:
    push cx
    mov cx,14
    @lloop:
      lodsb
      stosw
    loop @lloop
    pop cx
    add di,52
  loop @loop@
  pop di
  pop cx
  ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;void abouts proto void
;显示版本信息
abouts:
  push es
  push ds
  push si
  push di
  push cx
  
  push ds
  
  push es
  pop ds
  xor si,si
  mov di,2000
  mov cx,di
  cld
  rep movsb
  xor di,di
  mov ax,di
  mov cx,1000
  rep stosw
  pop ds
  mov si,offset about
  mov ah,6
  mov di,904
  mov cx,4
  @loop1@:
    push cx
    mov cx,18
    @loop2@:
      lodsb
      stosw
    loop @loop2@
    pop cx
    add di,44
  loop @loop1@
  mov ah,7
  int 21h
  push es
  pop ds
  xor di,di
  mov cx,2000
  mov si,cx
  cld 
  rep movsb
  pop cx
  pop di
  pop si
  pop ds
  pop es
  ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
;viod dispatch proto
;功能判断用户是否按下了一些功能键并处理,不是就不处理
;入口:ax=扫描码(高16位):ascii(低16位)
;出口:无
dispatch:
  cmp ah,left;处理左键
  jnz next1
  mov ax,offset nowtetris
  push ax
  mov ax,nowdot
  dec al
  push ax
  call canmove
  or ax,ax 
  jnz @l77
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint
  dec byte ptr nowdot;位置x-=1
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint
@l77:
  ret
next1:
  cmp ah,up;上键
  jnz next2
  push es
  push ds
  pop es
  mov si,offset nowtetris
  mov di,offset oldtetris
  mov cx,10
  cld
  rep movsb
  pop es
  mov bx,offset nowtetris
  mov cx,[bx+6]
  mov ax,[bx+8]
  add ax,4
  mov bl,16
  div bl
  xchg ah,al
  mov ah,0
  mov bx,ax
  mov nowtetris+8,ax
  add bx,cx
  push [bx]
  pop nowtetris
  push [bx+2]
  pop nowtetris+2
  mov ax,offset nowtetris
  push ax
  push nowdot
  call canmove
  or ax,ax
  jz @llll
  push es
  push ds
  pop es
  mov di,offset nowtetris
  mov si,offset oldtetris
  mov cx,10
  cld
  rep movsb
  pop es
  jmp near ptr return
@llll:
  push oldtetris+4
  mov ax,offset oldtetris
  push ax
  call paint;消除当前方块
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint
  ret
next2:
  cmp ah,right;右键
  jnz next3
  mov ax,offset nowtetris
  push ax
  mov ax,nowdot
  inc al
  push ax
  call canmove
  or ax,ax 
  jnz @l9
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint
  inc byte ptr nowdot;位置x+=1
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint
@l9:
  ret
next3:
  cmp ah,down;下键
  jnz next4
  mov ax,offset nowtetris
  push ax
  mov ax,nowdot
  inc ah
  push ax
  call canmove
  or ax,ax 
  jnz retur
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint
  inc byte ptr nowdot+1;位置y+=1
  push nowtetris+4
  mov ax,offset nowtetris
  push ax
  call paint
  retur:
  ret
next4:
  cmp ah,space;空格键,暂停程序
  jnz next5
  @next@2:
  xor ax,ax
  int 16h
  cmp ah,F1;暂停时只支持显示版本的F1
  jnz @next_1
  call dispatch;递归一次
  jmp @next@2
  @next_1:
  cmp al,32
  jnz @next@2
  mov al,cs:time+1
  mov nowtime,al
  ret
next5:
  cmp ah,F1;F1显示帮助
  jnz next7
  call abouts
  ret
next7:
  cmp ah,ESCkey;ESC退出
  jnz return
  push ds
  push ds
  
  push es
  pop ds
  mov di,1000h
  mov cx,1000
  xor si,si
  cld
  rep movsw
  xor ax,ax
  mov cx,1000
  mov di,ax
  cld
  rep movsw
  pop ds
  mov si,offset quit
  mov di,990
  mov cx,22
  rep movsb
  xor ax,ax
  int 16h
  cmp ah,15h
  jz return1;;;;Y退出
  push es
  pop ds
  mov si,1000h
  mov cx,1000
  xor di,di
  cld
  rep movsw
  pop ds
  jmp return
return1:
  call quitgame
return: 
ret
;<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
code ends
end main

MASM提示Extra characters on line:
先看下那行是否有多余的字符,如果没有,查看下文件的编码方式,UTF-8等编码会在文件的开始部分加上2个字节的标志,只有ANSI编码不会添加任何东西.
1,假如第24行和第23行全是方块,在调用testdiamond函数时,会先调用movewindow清除第24行,结果就是把第23行给了第24行,然后去检测第23行(没清除前的第22行),这样当前的第24行会被漏掉.
2,显示带穿透效果的那个方块时,由于定义成0000h的形式,在paint函数中的显示时,每次显示的都是那一个点,由于采用的是xor来显示,这样第一次xor时显示,第2次消除,3显示,4清除,结果发现会出现一个空的方块,我解决的办法是根据方块形状值来有针对的显示.形状值为0时只xor一次.
现在改了,由于可以显示5次,这样虽然xor了5次,浪费了些,但是可以让代码量小些,感觉也足够了.
3,必须针对穿透属性的方块增加一中判断函数,判断方式就是给定一个位置,如果它往下能下就直接返回0表示允许,不能下时循环判断当前位置这一列往下是否有空缺的方块位置,有就返回0表示允许.
4,对于空格暂停,不能使用ah=7/int21h来做.因为它不能处理ascii为0的按键,会对按键进行递归操作.
5,改版了以前显示的方式,改为5位表示一个相对位置,并写了个段代码用于输入相对位置,得到一个数据,tc下通过:
  #include <stdio.h>
int main()
{
  int i[5];
  int j,l;
  long k;
  while (scanf("%x %x %x %x %x",i,i+1,i+2,i+3,i+4))
  {          /*当然这里只能输入字母等能退出了*/
          /*输入比如,10 11 12 21 20这样,xy xy xy xy xy,当然这里是相对坐标*/
    for(j=0,k=0;j<5;j++)
    {
      l=i[j]&15;
      l+=(i[j]>>4)*5;
      k<<=5;
      k|=l;
    }
    printf("%lX\n",k);/*x大写表示显示的a~f用大写表示哦*/
  }
  return 0;
}
第一次使用自己写的代码来帮自己解决另外的一些问题,虽然比较丑陋,但是有点不一样的感觉.
6,由于使用的是判断颜色是否高亮来确定是否可以移动,定义时不能有高亮颜色位存在,否则动不了.如果使用别的方法来判断,还没有想出.不然就可以落底后不变色了.
7,对于设置等级,我把它放到了显示分数的代码块中,因为只有每个方块到底后才会调用那块代码来刷新.
8,当清除某一行时,不能忘记把最上行用0填充掉.不然会有个bug,虽然比较深.
9,为判断,显示这俩函数增加了个不除法溢出的模块,因为在右移5位时,有可能发生除法溢出,shl等指令又不能把dx:ax当成一个整体.
10,方块的下落速度是由自定义的int1ch来操作的.每秒被调18.2次,每次将某个变量加1,再判断是否可以"进位",需要进位就把另一变量加1,当主函数比较时间时,发现不同了,就是时间到了,该下落了.但是在失败后重新开始时,要进行判断,不要重复设置中断,以及开始画面,开始画面在整个进程的生命周期中只需要出现一次.
11,退出时不要忘记把中断还设回去,因为并没有安装,中断体还在自己的代码段,有可能会被后面的进程覆盖,那样系统就崩溃了.
12,随机函数还是蛮重要的,它和每种方块出现的频率有关,有时会连续出现几个相同的方块,有时间我要找个公式做个随机函数出来
13,把程序模块化是很有必要的,还有缩进格式.
14, lea指令的妙用:
lea的功能就是把源操作数[]内的表达式求值并把这个值给目的操作数.正因为这个特性,用它来做加法是非常简单的,如lea ax,[bx+si+100]就是ax=bx+si+100,这比add指令要方便吧,呵呵.
求指点.

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途。
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功