.MODEL TINY public RandSeed public GetKey extrn InitScreen:near extrn Bottom:near extrn PrintLong:near extrn Print:near extrn TestSpace:near extrn GameOverPrompt:near extrn PrintPause:near extrn RemovePause:near LEVEL_WAIT_INIT equ 700 START_POS equ 280 HISCORE_POS equ 24 SCORE_POS equ 264 LEVEL_POS equ 424 PREVIEW_POS equ 380 .CODE ORG 100h Start proc near ; INITIALIZATION ; ************** cld ; Test command line xor bx,bx xor dl,dl mov cl,byte ptr ds:[80h] ; Command line length cmd_loop: and cl,cl ;cl=0? je short cmd_loop_end mov al,byte ptr ds:[81h+bx] dec cl inc bx cmp al,' ' ;skip space jne short not_space cmp dl,10 jne short cmd_loop xor dl,dl jmp short cmd_loop not_space: cmp dl,0 je short get_minus push ax mov ax, word ptr StartLevel mov dl, 10 mul dl mov word ptr StartLevel, ax pop ax sub al, byte ptr '0' add StartLevel,ax jmp short cmd_loop get_minus: cmp al,'-' jne cmd_error and cl,cl je cmd_error mov al,byte ptr ds:[81h+bx] dec cl inc bx cmp al,'p' ; preview mode je preview_mode cmp al,'l' jne cmd_error inc dx ; dx type boolean jmp short cmd_loop preview_mode: inc word ptr PreView jmp short cmd_loop cmd_loop_end: cmp word ptr StartLevel,0 je short set_level cmp word ptr StartLevel,17 jbe short level_ok cmd_error: lea dx, ErrorText mov ah,09h int 21h mov ax,0h int 21h set_level: mov word ptr StartLevel,1 level_ok: ; Get old int 1ch mov ax,351ch ; Function 35 interrupt 1c int 21h ; Get interrupt adress mov word ptr OldInt1c,bx ; 1c clock tick mov ax,es mov word ptr OldInt1c+2,ax ; Store new int 1ch mov dx,offset _NewInt1c ; Set clock tick mov ax,251ch ; to point to NewInt1c int 21h ; Set ctrl/break int mov dx,offset quit mov al,23h int 21h ; Play again starts here restart: mov ax,word ptr StartLevel mov word ptr Level,ax mov word ptr Score,0 mov word ptr Score+2,0 call near ptr RandInit ; Initialize random numbers call near ptr InitScreen ; Initialize screen ; Print hiscore holder mov ah,02h mov dl,10 int 21h mov dl,13 int 21h lea dx, HiScoreName mov ah,09h int 21h ; Print first preview cmp PreView,0 je no_init_preview mov ax,OldRand shl ax,1 shl ax,1 mov PreItem,ax mov si,1 mov di,PREVIEW_POS call Print no_init_preview: ; Calculate clicks before next level change mov ax, LEVEL_WAIT_INIT ; wait level*700 clicks mov dx, word ptr Level ; befor next level change mov word ptr TimerInit,18 sub word ptr TimerInit,dx mul dx mov word ptr LevelWait,ax ; set LevelWait to 18-level ; Print out level xor dx,dx mov ax,word ptr Level ; print level mov di,LEVEL_POS call PrintLong ; Print Hiscore mov dx, word ptr HiScore+2 mov ax, word ptr Hiscore mov di, HISCORE_POS call PrintLong ; Main loop ; ********* jmp short while_kbhit for_ever: cmp word ptr Timer,0 jne short while_kbhit mov ax,word ptr TimerInit mov Timer,ax call near ptr Down ; go down or ax,ax jne while_kbhit jmp game_over while_kbhit: mov ah,0bh int 21h or al,al je short for_ever call near ptr GetKey ; al=getkey cmp al,'p' jne short not_p xor PreView,1 jnz short prev_on call near ptr RemovePreView jmp not_p prev_on: call near ptr PrintPreView not_p: or al,al je zero_key xor ah,ah sub ax,'2' mov bx,ax cmp bx,7 ja short while_kbhit shl bx,1 jmp word ptr cs:jump_table2[bx] zero_key: call near ptr GetKey ; al=getkey ; switch(ch) cbw ; ax=al sub ax,72 mov bx,ax cmp bx,8 ja short while_kbhit shl bx,1 jmp word ptr cs:jump_table[bx] go_left: push si mov si,-2 call Move pop si jmp short while_kbhit go_right: push si mov si,2 call Move pop si jmp short while_kbhit go_drop: call Drop or ax,ax je short game_over jmp short while_kbhit go_rotate: call Rotate jmp short while_kbhit inc_level: cmp Level,17 jge short while_kbhit add LevelWait,LEVEL_WAIT_INIT inc word ptr Level dec word ptr TimerInit xor dx,dx mov ax,word ptr Level mov di,LEVEL_POS call PrintLong jmp while_kbhit game_over: mov Timer,0 mov Paused,1 ; Test for new hiscore mov dx,word ptr Score+2 mov ax,word ptr Score cmp word ptr HiScore+2,dx ja no_hiscore jb short new_hi test_lsw: cmp word ptr HiScore,ax jb short new_hi jmp short no_hiscore new_hi: mov word ptr HiScore,ax mov word ptr Hiscore+2,dx ; Get name of hiscore holder lea dx, EnterName mov ah,09h int 21h mov dx, offset HiScoreData mov ah,0ah int 21h mov bl,HiScoreData+1 inc bl xor bh,bh mov HiscoreName[bx],13 inc bl mov HiscoreName[bx],'$' ; Get tetris filename push ds mov ah,30h int 21h mov ax,ds:[002ch] mov es,ax xor di,di mov ax,di mov cx,07fffh cld EnvLoop: repnz scasb cmp es:[di],ah jne EnvLoop or ch,10000000b neg cx mov si,cx inc si inc si push ds push es pop ds mov dx,si mov ax,3d00h + 010b ; 010b = read/write int 21h ; open tetris.com pop ds mov bx,ax ; file handle mov ax,4200h ; lseek from start of file mov dx,offset HiscoreName sub dx,0100h xor cx,cx ; cx:dx=hiscorename int 21h mov ah,40h mov cx,offset OldInt1c-offset HiScoreName ; number of bytes to write mov dx,offset HiScoreName int 21h mov ah,3eh ; close file int 21h no_hiscore: call near ptr GameOverPrompt yesno: call near ptr GetKey cmp al,'n' je quit cmp al,'y' jne yesno ; Play again! jmp restart ; Close down ; ********** quit: mov dx,word ptr OldInt1c ; restore old mov bx,word ptr OldInt1c+2 ; interrupt 1c vector push ds mov ds,bx mov ax,251ch int 21h pop ds mov ax,0003h int 10h ; Enter dos mov ax,0 int 21h Start endp jump_table label word dw go_rotate dw inc_level dw while_kbhit dw go_left dw while_kbhit dw go_right dw while_kbhit dw while_kbhit dw go_drop jump_table2 label word dw go_drop dw while_kbhit dw go_left dw go_rotate dw go_right dw while_kbhit dw inc_level _NewInt1c proc far push ax push bx push cx push dx push di push si push bp push ds push es mov bp,cs mov ds,bp pushf call dword ptr OldInt1c inc word ptr randseed cmp word ptr Timer,0 je short pause cmp Paused,0 je short pause_ok call RemovePause mov Paused,0 pause_ok: dec word ptr Timer dec word ptr LevelWait jne short return mov word ptr LevelWait,LEVEL_WAIT_INIT cmp TimerInit,0 je short return dec word ptr TimerInit inc word ptr Level xor dx,dx mov ax,word ptr Level mov di,LEVEL_POS call PrintLong jmp return pause: cmp Paused,0 jne short return call PrintPause mov Paused,1 return: pop es pop ds pop bp pop si pop di pop dx pop cx pop bx pop ax iret _NewInt1c endp Move proc near ; si=dPos push si xor si,si mov ax,word ptr Item add ax,word ptr Rotated mov di,word ptr Pos call near ptr Print ; remove old mov ax,word ptr Item add ax,word ptr Rotated mov di,word ptr Pos pop si add di,si push si call near ptr TestSpace ; test if room pop si push ax or ax,ax je short no_room add word ptr Pos,si ; ok, add Pos no_room: push si mov si,1 mov ax,word ptr Item add ax,word ptr Rotated mov di,word ptr Pos call near ptr Print pop si pop ax ret Move endp Rotate proc near push si xor si,si mov ax,word ptr Item add ax,word ptr Rotated mov di,word ptr Pos call near ptr Print mov ax,word ptr Rotated inc ax mov bx,4 cwd idiv bx mov ax,word ptr Item add ax,dx mov di,word ptr Pos call near ptr TestSpace or ax,ax je short no_room1 mov ax,word ptr Rotated inc ax mov bx,4 cwd idiv bx mov word ptr Rotated,dx no_room1: mov si,1 mov ax,word ptr Item add ax,word ptr Rotated mov di,Pos call near ptr Print pop si ret Rotate endp Down proc near push si mov si,80 call Move or ax,ax ; room? je get_new ; no pop si ret get_new: mov ax,word ptr Item add ax,word ptr Rotated mov di,word ptr Pos call near ptr Bottom ; reached the bottom call near ptr Rand7 ; get new item shl ax,1 shl ax,1 mov word ptr Item,ax mov word ptr Pos,START_POS mov word ptr Rotated,0 ; Calculate score mov ax,word ptr Drops shr ax,1 add ax,2 sub ax,PreView mov dx,word ptr Level mul dx add Score,ax adc Score+2,dx mov di,SCORE_POS mov ax,Score mov dx,Score+2 call PrintLong mov word ptr Drops,0 ; Test if new tetris can be printed mov ax,word ptr Item add ax,word ptr Rotated mov di,Pos call TestSpace or ax,ax jne place_new ; There was no room. Return false! pop si ret ; There was room. Print tetris. place_new: mov si,1 mov ax,word ptr Item add ax,word ptr Rotated mov di,Pos call Print mov ax, word ptr TimerInit mov word ptr Timer,ax ; Display preview tetris cmp PreView,0 je short no_preview call near ptr RemovePreView call near ptr PrintPreview ; Return true. no_preview: mov ax,1 pop si ret Down endp Drop proc near push si mov si,80 drop_more: call Move inc word ptr Drops or ax,ax jne drop_more call near ptr Down pop si ret Drop endp PrintPreView proc near mov si,1 mov ax,OldRand shl ax,1 shl ax,1 mov PreItem,ax mov di,PREVIEW_POS call Print ret PrintPreView endp RemovePreView proc near xor si,si mov ax,word ptr PreItem mov di,PREVIEW_POS call Print ret RemovePreView endp GetKey proc near mov ah,07h mov dl,0ffh int 21h ret GetKey endp RandInit proc near mov bp,sp sub sp,4 mov ah,02h int 1ah mov [bp-2],cl mov [bp-4],dh mov ax,word ptr [bp-2] imul word ptr [bp-4] mov word ptr randseed,ax mov sp,bp call near ptr Rand7 ret RandInit endp Rand7 proc near mov ax,word ptr randseed imul word ptr randseed test ax,1 je short even_number add ax,3172 mov word ptr randseed,ax jmp short skip_even even_number: shl ax,1 add ax,Score skip_even: mov word ptr randseed,ax mov bx,7 xor dx,dx div bx mov ax, word ptr OldRand mov word ptr OldRand, dx ret Rand7 endp .DATA Timer dw 0 LevelWait dw LEVEL_WAIT_INIT Level dw 1 StartLevel dw 0 Pos dw START_POS Item dw 0 Rotated dw 0 Drops dw 0 RandSeed dw 0 PreView dw 0 Paused db 0 ErrorText db 'Bad arguments',10,'$' EnterName db 'Enter name:',10,13,'$' HiScoreData db 14,0 HiScoreName db 15 dup ('$') HiScore dd 0 OldInt1c db 4 dup (?) Score dw 2 dup (?) OldRand dw 1 dup (?) PreItem dw 1 dup (?) TimerInit dw 1 dup (?) end Start