Так как она не использует графический режим (думаю запустится)
и в современной ОС. Собрать программу нужно таким образом:
Tasm Tetris
Tlink Tetris
- Код: Выделить всё
%TITLE "Tetris.asm"
IDEAL
P386
SMART
JUMPS
LOCALS @@
MODEL small
STACK 256
VGA_SEGMENT equ 0A000h
VGA_SEGMENT_T equ 0B800h
LEFT = 4Bh ; Key values
RIGHT = 4Dh
DOWN = 50h
SPACE = 39h
ENTERK = 1Ch
ESCAPE = 1
F10 = 44h
DATASEG
exCode db 0
VGASeg dw VGA_SEGMENT_T ; Vga Segment in High Memmory
CustomFont db 14 dup(-1), 192, 128, -1, -2, 12 dup(-4), 0, 0
PieceStart dw offset Piece1, offset Piece2
dw offset Piece3, offset Piece4
dw offset Piece5, offset Piece6
dw offset Piece7
db 1 ; AND mask
Piece1 db -1, 0, 1, 0, 2, 0 ; ЬЬЬЬ
db 0, -1, 0, 1, 0, 2
db 3 ; AND mask
Piece2 db 1, -1, 1, 0, -1, 0 ; ЫЬЬ
db 1, 1, 0, 1, 0, -1
db -1, 1, -1, 0, 1, 0
db -1, -1, 0,-1, 0, 1
db 3 ; AND mask
Piece3 db -1,-1, -1, 0, 1, 0 ; ЬЬЫ
db 1,-1, 0,-1, 0, 1
db 1, 1, 1, 0, -1, 0
db -1, 1, 0, 1, 0,-1
db 3 ; AND mask
Piece4 db 1, 0, 0, -1, -1, 0 ; ЬЫЬ
db 0, 1, 1, 0, 0,-1
db -1, 0, 0, 1, 1, 0
db 0,-1, -1, 0, 0, 1
db 1 ; AND mask
Piece5 db -1, 0, 0,-1, 1,-1 ; ЬЫЯ
db 0, 1, -1, 0, -1,-1
db 1 ; AND mask
Piece6 db 1, 0, 0,-1, -1,-1 ; ЯЫЬ
db 0,-1, -1, 0, -1, 1
db 0 ; AND mask
Piece7 db 0,-1, -1,-1, -1, 0 ; ЫЫ
TitleStr db '* TinyTetris v1.0 *',0
PlayAgain db 'Play again (Y/N) ?',0
OverStr db ' G A M E O V E R ',0
ScoreStr db 'Score:',0
LevelStr db 'Level:',0
LinesStr db 'Lines:',0
LeftStr db 'Lines Left:',0
Spaces10 db 3 dup(?)
Spaces7 db 8 dup(?)
GOBottom db 19 dup(?)
GOTop db 19 dup(?)
RandNum dw ?,?
Score dw ?
Lines dw ?
Level dw ?
DelayTime dw ?
LinesLeft dw ?
Piece dw ?
Rotate dw ?
X dw ?
Y dw ?
szBuffer db 256 dup (?)
CODESEG
proc Tetris
pusha
call ClearScreen
mov di, 18 ; Start at (9, 0)
mov cx, 25 ; 25 lines
mov ax, 7FB1h ; Color and character
WellLoop:
stosw ; Left side of well
mov [word es:di+40], ax ; Right side
add di, 158 ; Next line
loop WellLoop ; Loop back
mov al, 7 ; Color
mov cx, 38 ; Print title string
mov dx, 0
mov si, offset TitleStr
call PutStr
dec cx ; Print initial lines left
dec cx
mov dx, 17
mov si, offset LeftStr
call PutStr
dec dx ; Print initial lines
dec dx
mov si, offset LinesStr
call PutStr
dec dx ; Print initial level
dec dx
mov si, offset LevelStr
call PutStr
dec dx ; Print initial score
dec dx
mov si, offset ScoreStr
call PutStr
; --- Initialization
mov ax, 0 ; Initialize variables
mov [Score], ax
mov [Level], 1
mov [Lines], ax
mov [LinesLeft], 5
mov [DelayTime], 1
;mov [DelayTime], 750
mov [Rotate], ax
mov [X], 4
mov [Y], 24
call Rand7
mov [Piece], ax
MainLoop:
call ShowStatus
mov cx, [DelayTime] ; Delay specified time
;mov ax, [DelayTime] ; Delay specified time
call Delay
inc bp ; Ctr = (Ctr + 1) mod 4
and bp, 3
KeyLoop:
mov ah, 1 ; Check for keys
int 16h
jz NoKeys
call LoadVals ; Erase current piece
mov di, 0
call PutPiece
mov ax, 0 ; Get the key
int 16h
cmp ah, LEFT ; Left arrow?
je KeyLeft
cmp ah, RIGHT ; Right arrow?
je KeyRight
cmp ah, DOWN ; Down arrow?
je KeyDown
cmp ah, ENTERK ; Enter?
je KeyDown
cmp ah, SPACE ; Space?
je KeySpace
cmp ah, ESCAPE ; Escape?
je KeyEsc
cmp ah, F10 ; F10?
je KeyF10
jmp KeyDone ; Not a recognized key
KeyLeft:
call LoadVals ; If it fits at (X - 1)
dec cx
call Fits
jnc KeyDone
mov [X], cx ; move it to (X - 1)
jmp KeyDone
KeyRight:
call LoadVals ; If it fits at (X + 1)
inc cx
call Fits
jnc KeyDone
mov [X], cx ; move it to (X + 1)
jmp KeyDone
KeyDown:
call LoadVals ; Load values
mov si, dx ; Save old Y
DownLoop:
dec dx ; While it fits at (Y-1)
call Fits ; decrement Y
jc DownLoop
inc dx ; Move to where it last fit
mov [Y], dx ; Save it in Y
call PutPiece ; Display the piece
mov ax, dx ; Lock using (Y + old Y)
add ax, si
call PieceDown ; Piece is down
jmp KeyDone ; Done
KeySpace:
call LoadVals ; Load values
inc ax ; Next rotation
and ax, 3
call Fits ; If it fits
jnc KeyDone
mov [Rotate], ax ; Update rotation value
jmp KeyDone
KeyEsc:
call GameOver ; Done with game
KeyF10:
call LVPutPiece ; Show piece
xor ax, ax ; Wait for a key
int 16h
KeyDone:
call LVPutPiece ; Show piece
jmp KeyLoop
; --- Piece Fall
NoKeys:
test bp, bp ; Only if counter is zero
jne MainLoop
call LoadVals ; Erase current piece
xor di, di
call PutPiece
dec dx ; Check for fit at (Y - 1)
call Fits
jnc NoFit ; Jump if it doesn't fit
mov [Y], dx ; Save new Y
call LVPutPiece ; Show piece
jmp MainLoop
NoFit:
call LVPutPiece ; Show piece
mov ax, dx ; Lock using Y
call PieceDown ; Piece is down
call LVPutPiece ; Show piece
jmp MainLoop ; Loop back
; --- Game Over
GameOver:
pop ax ; Pop junk-word
mov cx, 11 ; Print GO-top string
mov dx, 11
mov si, offset GOTop
mov ax, 4
call PutStr
inc dx ; Print game-over message
mov si, offset OverStr ; in blinking blue
mov ax, 0C9h
call PutStr
inc dx ; Print GO-bottom string
mov si, offset GOBottom
mov ax, 4
call PutStr
mov cx, 1
;mov ax, 5000 ; Delay 1/2 second
call Delay
call FlushBuffer ; Flush key buffer
xor ax, ax ; Wait for a key
int 16h
popa ; Restore registers
ret
PieceDown:
call LockPiece
cmp dx, 24 ; Too high, game over
jge GameOver
mov [Rotate], 0 ; New piece, type (random, 0)
call Rand7
mov [Piece], ax
mov [X], 4 ; Position (4, 24)
mov [Y], 24
call FlushBuffer ; Flush key buffer
ret
LoadVals:
mov cx, [X] ; Load piece values
mov dx, [Y]
mov bx, [Piece]
mov ax, [Rotate]
mov di, bx
inc di
ret
LVPutPiece:
call LoadVals ; Load piece values
jmp PutPiece
endp Tetris
proc LockPiece
; Locks a piece in place
pusha ; Save all registers
mov ax, [Level] ; AX = Level
imul ax, 10 ; 10 * Level
add [Score], ax ; add to score
call DelLines ; Delete lines
add [Lines], ax ; Adjust line counter
sub [LinesLeft], ax
imul ax, 50 ; Line score value
add [Score], ax ; add to score
cmp [LinesLeft], 0 ; Done with level?
jg NotNew
mov [LinesLeft], 0 ; LinesLeft = 0
call ShowStatus ; Show status
call ClearWell ; Clear well
imul ax, [Level], 100 ; Score = Score + 100 * Level
add [Score], ax
inc [Level] ; Next level
;imul ax, [DelayTime], 7 ; Reduce delay by 12%
;shr ax, 3
;mov [DelayTime], ax
imul ax, [Level], 2 ; LinesLeft = 6 + 2 * Level
add ax, 6
mov [LinesLeft], ax
NotNew:
call ShowStatus ; Show status
popa ; Restore registers
ret
endp LockPiece
proc ShowStatus
; Display score, level, etc
pusha ; Save all registers
mov cx, 43 ; Clear Score field
mov dx, 11
mov si, offset Spaces7
mov al, 7
call PutStr
inc dx ; Clear Level field
inc dx
call PutStr
inc dx ; Clear Lines field
inc dx
call PutStr
inc dx ; Clear Lines Left field
inc dx
add cx, 5
add si, 5
call PutStr
mov si, offset szBuffer ; Offset of buffer
mov ax, [Score] ; Get decimal string for Score
mov di, si
call Cvt16
mov cx, 43 ; Print it at (43, 11)
mov dx, 11
mov al, 0Ah
call PutStr
mov ax, [Level] ; Get decimal string for Level
mov di, si
call Cvt16
inc dx ; Print it at (43, 13)
inc dx
mov al, 0Ah
call PutStr
mov ax, [Lines] ; Get decimal string for Lines
mov di, si
call Cvt16
inc dx ; Print it at (43, 15)
inc dx
mov al, 0Ah
call PutStr
mov ax, [LinesLeft] ; Get decimal string for Lines Left
mov di, si
call Cvt16
mov cx, 48 ; Print it at (48, 17)
inc dx
inc dx
mov al, 0Ah
call PutStr
popa ; Restore registers
ret
endp ShowStatus
proc PutBlock
; Put block on screen
; Supply CX = x, DX = y, AL = color
pusha ; Save all registers
imul di, dx, 160 ; DI = DX * 160
add di, cx ; DI = DX * 160 + CX * 2
add di, cx
test al, al ; If zero, erase block
jz short IS_ZERO
mov ah, al ; AH = color
shl ah, 4
add ah, 8 ; Foreground = color + 8
add ah, al
mov al, 0CEh ; Store first half
stosw
inc ax ; Store second half
stosw
popa ; Restore registers
ret ; Return
IS_ZERO:
mov ax, 720h ; Zero, store spaces
stosw
stosw
popa ; Restore registers
ret
endp PutBlock
proc IsBlock
; Check for block
; Supply CX = x, DX = y
; Returns Carry = 1 if block
pusha ; Save all registers
add cx, cx
add cx, 10 ; Adjust to screen position
neg dx
add dx, 24
imul di, dx, 160 ; DI = DX * 160
add di, cx ; DI = DX * 160 + CX * 2
add di, cx
mov al, [es:di] ; Load byte
cmp al, 0CEh ; If it's < 0CEh
jb NoBlock ; it isn't a block
stc ; Set carry flag
popa ; Restore registers
ret
NoBlock:
clc ; Clear carry flag
popa ; Restore registers
ret
endp IsBlock
proc PutPiece
; Put piece in well
; Supply CX = x, DX = y
; BX = piece, AX = rotation, DI = color
pusha ; Save all registers
mov bp, di ; Color in BP
add bx, bx
mov si, [PieceStart+bx] ; SI = piece start
and al, [si-1] ; AND mask
imul ax, 6 ; AX * 6
add si, ax ; SI = piece offset
mov di, 4 ; 4 blocks
xor ax, ax ; Start with (0, 0)
BlockLoop:
push cx dx ; Save position
mov bl, ah ; Get offsets in AX, BX
cbw
xchg ax, bx
cbw
xchg ax, bx
add cx, ax ; Add in offsets
add dx, bx
cmp cx, 10 ; Out of well, don't show
jae BlockNope
cmp dx, 25
jae BlockNope
add cx, cx
add cx, 10 ; Adjust to screen position
neg dx
add dx, 24
mov ax, bp ; Color in AL
call PutBlock ; Show block
BlockNope:
pop dx cx ; Restore position
lodsw ; Load word
dec di ; Loop back using DI
jnz BlockLoop
popa ; Restore registers
ret
endp PutPiece
proc Fits
; Check whether piece fits
; Supply CX = x, DX = y
; BX = piece, AX = rotation
; Returns: Carry = 1 if it fits, 0 if it doesn't
pusha ; Save all registers
add bx, bx
mov si, [PieceStart+bx] ; SI = piece start
and al, [si-1] ; AND mask
imul ax, 6 ; AX * 6
add si, ax ; SI = piece offset
mov di, 4 ; 4 blocks
xor ax, ax ; Start with (0, 0)
FitsLoop:
push cx dx ; Save position
mov bl, ah ; Get offsets in AX, BX
cbw
xchg ax, bx
cbw
xchg ax, bx
add cx, ax ; Add in offsets
add dx, bx
cmp cx, 10 ; Out of well, doesn't fit
jae DoesntFit
test dx, dx
jl DoesntFit
call IsBlock ; Check for block
jc DoesntFit
pop dx cx ; Restore position
lodsw ; Load word
dec di ; Loop back using DI
jnz FitsLoop
stc ; Set carry flag
popa ; Restore registers
ret
DoesntFit:
clc ; Clear carry flag
pop dx cx ; Pop extra off stack
popa ; Restore registers
ret
endp Fits
proc DelLine
; Delete line
; Supply AX = y
pusha ; Save all registers
push ds ; Save DS
push es ; DS = ES
pop ds
neg ax ; Adjust for screen position
add ax, 24
xchg dx, ax
imul di, dx, 160 ; DI = DX * 160
add di, 20 ; DI = DX * 160 + 20
mov si, di ; SI = previous line
sub si, 160
ScDnLoop:
push si si ; Save offsets
mov cx, 20 ; Move line
rep movsw
pop si di ; DI = old SI,
sub si, 160 ; SI = old SI - 160
dec dx ; Loop back using DX
jnz ScDnLoop
pop ds
popa ; Restore registers
ret
endp DelLine
proc DelLines
; Delete all completed lines
push cx ; Save CX
xor cx, cx ; Zero CX
mov ax, 24 ; AX = 24
DelLoop:
pusha ; Save all registers
xchg dx, ax ; Y in DX
mov cx, 9 ; CX = 9
LChkLoop:
call IsBlock ; Check for block
jnc NotLine ; Not a line if no block
dec cx ; Loop back using CX
jns LChkLoop
stc ; Set carry flag
NotLine:
popa ; Restore registers
jnc $+6 ; Jump if not line
call DelLine ; Delete line
inc cx ; Increment counter
dec ax ; Next line
jns DelLoop ; Loop back
xchg ax, cx ; Lines in AX
pop cx ; Restore CX
ret
endp DelLines
proc ClearWell
; Clear the well
pusha ; Save all registers
mov di, 20 ; Start at offset 20
mov dx, 25 ; 25 rows on screen
mov ax, 720h ; Fill with spaces
ClearWLoop:
mov cx, 20 ; Width of well
rep stosw ; Clear line
add di, 120 ; Go to next line
dec dx ; Loop back using DX
jnz ClearWLoop
popa ; Restore registers
ret
endp ClearWell
proc ClearScreen
pusha ; Save all registers
xor di, di ; Zero DI
mov ax, 720h ; Fill with spaces
mov cx, 4000 ; 4000 words
rep stosw ; Clear screen
popa ; Restore registers
ret
endp ClearScreen
proc PutStr
; Print ASCIIZ string
; CX, DX = position
; AL = color, DS:SI = string
push ax cx dx di
imul di, dx, 160 ; DI = DX * 160
add di, cx ; DI = DX * 160 + CX * 2
add di, cx
mov ah, al ; AH = color
@@10:
lodsb ; Load byte
cmp al, 0 ; Quit if zero
je @@99
stosw ; Store word
jmp @@10
@@99:
pop di dx cx ax
ret
endp PutStr
proc FlushBuffer
; Flush keyboard buffer
push ds ; Save DS
push 0 ; DS = 0
pop ds
push [word 41Ah] ; Key tail = key head
pop [word 41Ch]
pop ds ; Restore DS
ret
endp FlushBuffer
proc Cvt16
; Convert 16-bit binary to decimal
; Supply AX = binary value
; DS:DI = 5 bytes string space
pusha ; Save registers
pop di
test ax, ax ; If zero, then just
je U16Zero ; output a zero
xor cx, cx ; Zero CX
mov si, 10 ; SI = 10
U16DivLoop:
xor dx, dx ; Zero DX
div si ; Divide by 10
mov bl, dl ; Remainder in BL
add bl, 30h ; Convert to digit
push bx ; Save digit
inc cx ; Increment CX
test ax, ax ; Zero now?
jnz U16DivLoop ; Loop back if not
U16PopLoop:
pop ax ; Pop digit
mov [di], al ; Store digit
inc di
loop U16PopLoop ; Loop back
U16Ret:
mov [byte di], 0 ; Store ending null
push di ; Restore registers
popa
ret
U16Zero:
mov [byte di], 30h ; It was zero, so store a '0'
inc di
jmp U16Ret
endp Cvt16
proc Rand7
; Generate a random number from 1 to 7
mov ax, 7 ; Call Rand with value 7
call Rand
ret
endp Rand7
proc Rand
; Generate a random number
push bx cx dx ax ; Save registers, push AX
mov ax, 4E35h
mul [RandNum] ; Here the Random Number is
mov cx, dx ; multiplied by the value
xchg bx, ax ; 015A4E35h This is one of
imul ax, [RandNum], 015Ah ; the optimal values for
add cx, ax ; this type of random number.
imul ax, [RandNum+2], 4E35h
add cx, ax
add bx, 1 ; Increment the number
adc cx, 0
mov [RandNum], bx ; Save random number
mov [RandNum+2], cx
xchg ax, cx ; Now the bits are re-arranged
shl ax, 1 ; and the number is divided by
and bx, 1 ; the value originally in AX
add ax, bx
pop bx
xor dx, dx
div bx
xchg ax, dx ; Place result in AX
pop dx cx bx ; Restore registers
ret
endp Rand
proc Delay_1
; Supply AX = milliseconds * 10.
pusha ; Save all registers
mov dx, 100
mul dx
mov cx, dx
xchg dx, ax ; CX:DX = time in microseconds
mov ah, 86h ; INT 15/86 = BIOS delay
int 15h
popa ; Restore registers
ret
endp Delay_1
proc Delay
; Simple BIOS delay
; Requires number of reiterations in CX on entry
push ds
mov ax, 40h
mov ds, ax
mov bx, 6Ch ; BIOS timer, 40:6C
@@10:
mov al, [bx]
@@99:
cmp al, [bx] ; Is it the same?
je @@99 ; Yes, try again
loop @@10 ; Loop and decrement CX
pop ds ; Restore registers and exit
ret
endp Delay
;
; Entry point
;
Start:
mov ax, @data ; Set DS to point to data segment
mov ds, ax
mov es, ax
mov ax, 3 ; Set text mode
int 10h
mov ax, 1110h ; Set font chars CE, CF to
mov bx, 1000h ; the 'block' image
mov cx, 2
mov dx, 0CEh
mov bp, offset CustomFont
int 10h
mov ah, 2 ; Turn off the cursor by
xor bh, bh ; placing it off the screen
mov dx, 1E00h
int 10h
mov di, offset Spaces10 ; Set up space buffer
mov cx, 10
mov al, 20h
rep stosb ; Copy, fill memory
mov al, 0
stosb ; Copy, fill memory
mov cx, 18 ; Set up top/bottom lines
mov al, 0DFh
rep stosb
mov al, 0
stosb ; Copy, fill memory
mov cx, 18
mov al, 0DCh
rep stosb
mov ax, 0
stosb ; Copy, fill memory
push ax ; ES = 0
pop es
mov ax, [es:046Ch] ; Seed random number with
mov [RandNum], ax ; the BIOS time counter
mov ax, [es:046Eh]
mov [RandNum+2], ax
;push 0B800h ; ES = 0B800h (text video memory)
;pop es
mov es, [VGASeg] ; Set ES to point to video segment
GameLoop:
call Tetris ; Play game
call ClearScreen ; Clear screen
mov al, 9Fh ; Color = blinking white on blue
mov cx, 31 ; Print 'Play again?' string
mov dx, 12 ; in the middle of the screen
mov si, offset PlayAgain
call PutStr
call FlushBuffer ; Flush key buffer
@@GETCH:
xor ax, ax ; Get a key
int 16h
cmp ah, 15h ; If it's a 'Y', then play again
je GameLoop
cmp ah, 31h ; If it's an 'N', then quit
jne @@GETCH
GameDone:
mov ax, 3 ; Set text mode, restore font
int 10h
Exit:
mov ax, 3 ; Set 80x25x16 char mode
int 10h
mov ah, 4Ch ; Return to DOS
mov al, [exCode]
int 21h
END Start