您的位置:首页 > 其它

汇编打字游戏程序(别人写的,我修改了部分,然后写了详细的注释)

2011-11-19 18:20 441 查看
Init_game macro op1,op2,op3,op4,op5

local ns

mov cx,00h

mov dh,op1

mov dl,op2

ns:mov ah,02h;设置光标位置

mov bh,00h;页号为0

int 10h

push cx

mov ah,0ah;在当前光标位置写字符

mov al,op3;al=字符的ascii码

mov bh,00h;bh=页号bl=字符属性

mov cx,01h;cx=写入字符重复次数

int 10h

pop cx;cx=0

inc cx;cx=cx+1

inc op4

cmp cx,op5

jne ns

endm

clear_screen macro op1,op2,op3,op4 ;清屏宏定义 cx,屏幕的左上角,dx屏幕的右下角

mov ah,06h

mov al,00h

mov bh,0eh;改变行属性的色彩,字的色彩,bh空白行的属性/07就是正常的黑底白字

mov ch,op1

mov cl,op2

mov dh,op3

mov dl,op4

int 10h

mov ah,02h;设置光标的位置从0000开始

mov bh,00h

mov dh,00h

mov dl,00h

int 10h

endm

menu macro op1,op2,op3 ;菜单显示宏定义

mov ah,02h

mov bh,00h

mov dh,op1

mov dl,op2

int 10h

mov ah,09h

lea dx,op3

int 21h

endm

data segment

ZK db "WELCOME TO PLAY$"

no db "date:2003/6/24$"

meg db "press Enter key to continue.......$"

meg1 db "when a letter is dropping,please hit it!$"

meg2 db "press space key to pause!$"

meg3 db "press ESC key to return main interface!$"

meg4 db "press letter 'E' to exit!$"

speed dw 600d

;-----原作者写的程序,因为写得欠缺一点,我都重新写了-----

;letters db "jwmilzoeucgpravskntxhdyqfb"

; db "iytpkwnxlsvxrmofzhgaebudjq"

; db "nwimzoexrphysfqtvdcgljukda"

;---------------------------------------------------------------

letters_bak db "jwmilzoeucgpravskntxhdyqfb"

db "iytpkwnxlsvxrmofzhgaebudjq"

db "nwimzoexrphysfqtvdcgljukda"

letters db 78d dup(0)

letter_counter db 0

life_flag db 78 dup(0)

position_flag db 78 dup(0)

present_position db 1

data ends

stack segment para stack 'stack'

db 64 dup(0)

stack ends

code segment

main proc far

assume cs:code,ds:data,ss:stack

start: mov ax,data

mov ds,ax

mov letter_counter,00h

mov present_position,1

lea si,position_flag;

mov ah,00h

mov cx,00h

;------------------原代码很多重复操作的代码,修改后---------------------

;init_postion_flag:

;mov [si],ah;[si]的值为00h

;inc si;

;inc cx;cx=1

;cmp cx,78d;输入78次,把position_flag全部变成0

;jne init_postion_flag;不为0,跑回init_postion_flag

;以上代码是作者吃饱了撑得慌,写出来的初始化position_flag的代码

;----------------------------------------------------------------------------

lea di,letters;di的偏移地址为letters

lea si,letters_bak;si的偏移地址为letter_bak

mov cx,00h;cx=0

init_letters:

mov ah,[si];ah=j

mov [di],ah;ah的值放到letters里面;letters_bak的值放入letters里面

inc si;si+1

inc di;di+1

inc cx;cx+1

cmp cx,78d;

jne init_letters;不为0就到init_letters,一直循环到letters里

mov ah,00h

lea si,life_flag;

mov cx,00h

;---------------作者又在初始化life_flag,其实他在定义的时候就初始化了,估计应该是为了游戏over后,自动回去吧

init_life_flag:

mov [si],ah

inc si

inc cx

cmp cx,78d

jne init_life_flag

;-----------------------------------------------------------------------

mov cx,00h ;ch=光标开始行,cl=光标结束行 根据CX给出光标的大小

mov ah,01h

or ch,00010000b;ch>20h,光标消失,cl>20h,覆盖字符

int 10h

clear_screen 00d,00d,24d,79d ;清屏,0000- 2479

Init_game 00d,00d,0ah,dl,80d ;这个四个是初始化屏幕的上下左右的框框

Init_game 24d,00d,0ah,dl,80d

Init_game 00d,00d,0ah,dh,25d

Init_game 00d,79d,0ah,dh,25d

menu 05d,15d,ZK ;菜单信息的宏调用,这五行是在屏幕上显示提示消息

menu 07h,15d,no

menu 09d,15d,meg

menu 11d,15d,meg1

menu 13d,15d,meg2

menu 15d,15d,meg3

menu 17d,15d,meg4

put: mov ah,02h ;设置光标位置

mov bh,00h;设置页码

mov dh,22d;dx行列坐标

mov dl,33d

int 10h

mov ah,01h ;从键盘输入任意字符并回显示,al=输入字符

int 21h

cmp al,0dh;是否为换行符

je speed3;如果是换行符则跳转到speed3处

cmp al,45h;比较是否为e

je exit;如果为e,转到exit

exit: mov ah,4ch

int 21h

speed3:

mov ax,speed+12

mov speed,ax

jmp begin

begin: clear_screen 01d,01d,23d,78d ;清屏宏调用

; clear_screen 01d,01d,23d,78d

Init_game 23d,01d,03h,dl,78d;23d01d行列坐标,初始化倒数第二行的字符

mov ah,02h

mov bh,00h

mov dh,01h

mov dl,01h

int 10h

mov cx,00h

lea si,letters ;si的偏移地址是letters

nextletter:

mov ah,02h ;显示字母

mov dl,[si] ;把letters的字符放到dl里

int 21h ;通过dos中断的2号功能项,把字符显示出来

inc si

inc cx

cmp cx,78d

je nextcycle;全部显示完了后,跳到nextcycle

jmp nextletter

from_front:

sub present_position,78d ;当超过78个字时的处理方式 减去78

jmp gobackto_si;跑到gobackto_si这来

find_zero:

cmp letter_counter,78d ;letter_counter有78了,初始化

je recycle;如果有跑到recycle

cmp present_position,78d;如果present_position等于78d,

je from_one

mov ah,00h

nextsi: add present_position,01h

inc si

cmp [si],ah

je gobackto_di

cmp present_position,78d

je from_one

jmp nextsi

from_one:mov present_position,01h ;present_position=01

jmp gobackto_si

;---------------------------------------------------------------------------------------

recycle:mov letter_counter,00h;letter_counter=0

mov present_position,01d;present_position=01

lea si,position_flag;si=position_flag的偏移地址

mov cx,00h

mov ah,00h

clearsi:

mov [si],ah;position_flag地址搞成0

inc cx

cmp cx,78d

je nextcycle

inc si

jmp clearsi

nextcycle:

lea di,letters;di的偏移地址是letters[字母]

lea si,position_flag;si的偏移地址是position_flag

add present_position,31d;31一跳,这个你可以随便设置

cmp present_position,78d;;超过78个字节

ja from_front

;------------------------------------------------------------------------------------------------

gobackto_si:

add si,word ptr present_position;si=si+present_position,si向后偏移

dec si; 要不要都无所谓,只不过,因为开始就觉定了是要31一跳,所以这里减一个1位

mov ah,[si];把position_flag放到ah里

cmp ah,01h;看看position_flag里面有没有标志1

je find_zero;如果ah为1转移,否则

gobackto_di:

mov ah,01h

mov [si],ah

add di,word ptr present_position

dec di;因为列坐标是从0开始,而字符是从1开始,所以这里是32-1

mov dl,present_position;

mov ah,02h

mov bh,00h

mov dh,01h

int 10h

mov cx,00h

;------------------------------------------------------------------------------------------------------------------------

nextrow: push cx

mov cx,00h

out_cycle: ; 延迟

push cx

mov cx,00h

in_cycle:

add cx,01h

cmp cx,1000 ;

jne in_cycle ;zf=0转到标号处执行,

push dx

mov ah,06h ;从键盘输入字符,al等于字符

mov dl,0ffh

int 21h

pop dx

jz pass ;这个屁地方,害我弄了一个下午,我一直都不知道到底通过哪里修改了zf的值去影响后面的操作,其实这里要不要都无所谓

;在上面的中断中,如果你输入了字符,zf=0,无字符,zf=1,他是无字符就直接执行后面的程序,从这里可以看出来作者对汇编

;是相当熟练的!

cmp al,1bh ;如果键入ESC,则返回主菜单

je to_start1

cmp al," " ;如果键入SPACE,则游戏暂停

je pause

cmp al,[di] ;输入字母正确!则字母消失

je disappear

pass: pop cx

inc cx

cmp cx,speed

je print

jmp out_cycle

pause: push dx ;暂停处理 第一次知道暂停是这样的,循环空代码

mov ah,06h

mov dl,0ffh

int 21h

pop dx

cmp al," "

jne pause

jmp pass

to_start1: ;返回主菜单

jmp start

print:

mov ah,0ah ;在当前光标位置写空格

mov al," "

mov bh,00h

mov cx,01h

int 10h

inc dh

mov ah,02h ;改变光标位置

mov bh,00h

int 10h

mov ah,0ah ;在当前光标位置写字母

mov al,[di]

mov bh,00h

mov cx,01h

int 10h

pop cx

inc cx

cmp cx,21d

je print_next_letter

jmp nextrow ;下一行

disappear: ;击中字母后输出空格

pop cx

pop cx

mov ah,0ah;在光标处按原来属性显示字符

mov al," "

mov bh,00h

mov cx,01h

int 10h

jmp hit

print_next_letter:

lea si,life_flag

add si,word ptr present_position

dec si

mov ah,0ah;在当前光标处按原有属性显示字符

mov al," ";最倒数第二排写入字符,意思是当掉下来的字符到倒数第二行的时候,自动变成空格消失

mov bh,00h

mov cx,01h

int 10h

inc dh ;这就是到了最后一行

mov ah,02h;2号中断,设置文本光标位置

mov bh,00h

int 10h

mov ah,0ah;把最后一行的字符变成空格

mov al," "

mov bh,00h

mov cx,01h;重复输出,这里的重复输出的意思就是输入一个空格

int 10h

mov ah,1;把life_flag变成1,这样下次就可以不在同一个位置掉字符下来

mov [si],ah

hit: mov ah,02h;设置光标

mov bh,00h

mov dh,01h;第一行

mov dl,present_position;下一个字符的列

int 10h

mov al,[di] ; 出现下一个新字母的数法

add al,7;di+7

cmp al,7ah;z的ascii码就是7ah,所以当al大于7ah时转移

ja convey_letter

mov ah,0ah;在当前光标按原有属性显示字符,al=字符

mov bh,00h

mov cx,01h

int 10h

mov [di],al

add letter_counter,01h;统计次数

jmp nextcycle

convey_letter:

sub al,7ah

add al,61h;al等于要显示的字符,加61表示是小写字母

mov ah,0ah

mov bh,00h

mov cx,01h

int 10h

mov [di],al

add letter_counter,01h

jmp nextcycle ;没弄懂作者这里是什么意思,到了这里就jmp了那写下面的程序做屁

clear_screen 01,01,23,78

mov ah,02h

mov bh,00h

mov dh,11d

mov dl,20d

int 10h

inc dh

inc dh

mov ah,02h

mov bh,00h

int 10h

notkey:

mov ah,07h

int 21h

cmp al,0dh

je to_start

cmp al,1bh

je over

jmp notkey

to_start:

clear_screen 00,00,24,79

jmp start

over: clear_screen 01,01,23,78

mov ah,02h

mov bh,00h

mov dh,11d

mov dl,15h

int 10h

mov ah,02h

mov bh,00h

mov dh,13d

mov dl,15h

int 10h

mov ah,07h

int 21h

mov ah,07h

int 21h

clear_screen 00,00,24,79

mov ax,4c00h

int 21h

main endp

code ends

end start
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐