;****************** TETRIS.ASM -- TinyTetris v1.3
; This is a Tetris game written in ASM.
Ideal
Jumps
LEFT = 4Bh ;Key values
RIGHT = 4Dh
DOWN = 50h
SPACE = 39h
ENTERK = 1Ch
ESCAPE = 01h
BKSPACE = 0Eh
F10 = 44h
Model Tiny
P186
CodeSeg
Org 100h
Start: jmp Main
;**************************** Static data for program
CustomFont db 255,255,6 dup(213,234),192,128
db 255,254,6 dup(84,168),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.3 ---',0
PlayAgain db 'Do you want to play again (Y/N) ?',0
YMHS db 'You made a High Score!',0
NameStr db 'Enter your name:',0
HiStr db 'TinyTetris High Scores',0
HST1 db 'Name',0
HST2 db 'Score Lines Level',0
FileName db 'TETRIS.SCO',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
;**************************** Main program
Proc Main
mov ax,3 ;Set text mode
int 10h
mov ax,1114h ;Set 8x16 font
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 dx,03CCh ;Set 8 dot chars
in al,dx
and al,0F3h
mov dx,03C2h
out dx,al
mov dx,03C4h
mov ax,0101h
out dx,ax
mov ah,2 ;Turn off the cursor by
xor bh,bh ;placing it off the screen
mov dx,1E00h
int 10h
cld
mov di,offset HiScores ;Zero out high scores
mov cx,580
xor ax,ax
rep stosw
mov di,offset Spaces10 ;Set up space buffer
mov cx,10
mov al,20h
rep stosb
xor al,al
stosb
mov cx,18 ;Set up top/bottom lines
mov al,0DFh
rep stosb
xor al,al
stosb
mov cx,18
mov al,0DCh
rep stosb
xor ax,ax
stosb
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 ax,3D00h ;Open scorefile
mov dx,offset FileName
int 21h
jc GameLoop ;No scorefile, ignore
xchg bx,ax ;Read hiscores
mov ah,3Fh
mov cx,1160
mov dx,offset HiScores
int 21h
mov ah,3Eh ;Close scorefile
int 21h
GameLoop: call Tetris ;Play game
call AddHiScore ;Add in score, show scores
call ClearScreen ;Clear screen
mov cx,22 ;Print 'Play again?' string
mov dx,12 ;in the middle of the screen
mov si,offset PlayAgain
mov al,9Fh ;Color = blinking white on blue
call PutStr
call FlushBuffer ;Flush key buffer
PKeyLoop: 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 PKeyLoop
GameDone: mov ah,3Ch ;Create/truncate scorefile
xor cx,cx
mov dx,offset FileName
int 21h
xchg bx,ax ;Write hiscores
mov ah,40h
mov cx,1160
mov dx,offset HiScores
int 21h
mov ah,3Eh ;Close scorefile
int 21h
mov ax,3 ;Set text mode, restore font
int 10h
ret ;Exit
EndP Main
;**************************** Tetris -- This is the actual game
Proc Tetris
pusha ;Save all registers
;****************** TETRIS Screen Setup
call ClearScreen ;Clear the screen
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 di,1668 ;Start at (34, 10)
mov cx,9 ;9 lines
mov al,0DBh ;AL = character
SBoxLoop: stosb ;Left side of status box
mov [es:di+33],al ;Right side
add di,159 ;Next line
loop SBoxLoop ;Loop back
mov di,708 ;Start at (34, 4)
mov cx,5 ;5 lines
NBoxLoop: stosb ;Left side of next piece box
mov [es:di+25],al ;Right side
add di,159 ;Next line
loop NBoxLoop ;Loop back
mov cx,38 ;Print title string
xor dx,dx
mov si,offset TitleStr
mov al,07h
call PutStr
mov cx,35 ;Print S-box top
mov dx,10
mov si,offset BoxTop
call PutStr
mov dx,18 ;Print S-box bottom
mov si,offset BoxBottom
call PutStr
mov cx,35 ;Print N-box top
mov dx,4
mov si,offset BoxTop+4
call PutStr
dec cx ;Print N-box bottom
mov dx,9
dec si
dec si
call PutStr
inc cx ;Print initial lines left
inc 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
;****************** TETRIS Initialization
xor ax,ax ;Initialize variables
mov [Score],ax
mov [Score+2],ax
mov [Level],1
mov [Lines],ax
mov [LinesLeft],5
mov [DelayTime],750
mov [Rotate],ax
mov [X],4
mov [Y],24
call Rand7
mov [Piece],ax
call Rand7
mov [NxPiece],ax
;****************** TETRIS Main Loop
MainLoop: call ShowStatus ;Show status
mov ax,[DelayTime] ;Delay specified time
call Delay
inc bp ;Ctr = (Ctr + 1) mod 4
and bp,3
;****************** TETRIS Key Loop
KeyLoop: mov ah,1 ;Check for keys
int 16h
jz NoKeys
call LoadVals ;Erase current piece
xor di,di
call PutPiece
xor ax,ax ;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
;****************** TETRIS 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
;****************** TETRIS Game Over
GameOver: pop ax ;Pop junk-word
mov cx,11 ;Print GO-top string
mov dx,11
mov si,offset GOTop
mov ax,04h
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,04h
call PutStr
mov ax,3333 ;Delay 1/3 second
call Delay
call FlushBuffer ;Flush key buffer
xor ax,ax ;Wait for a key
int 16h
popa ;Restore registers
ret ;Return
PieceDown: call LockPiece
cmp dx,24 ;Too high, game over
jge GameOver
mov [Rotate],0 ;New piece, type (NxPiece, 0)
mov ax,[NxPiece]
mov [Piece],ax
call Rand7 ;New next-piece
mov [NxPiece],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
;**************************** LockPiece -- Locks a piece in place
Proc LockPiece
pusha ;Save all registers
push ax ;Save y-value
mov ax,150 ;15 msecs
mov bx,660 ;Sound at 660
call Sound
call NoSound ;End of sound
pop ax ;Get back y-value
add ax,25 ; y + 25
mov dx,[Level]
mul dx ; Level * (y + 25)
imul ax,10 ; 10 * Level * (y + 25)
cwd
mov bx,25 ; (10 * Level * (y + 25)) / 25
div bx
add [Score],ax ;add to score
adc [Score+2],0
call DelLines ;Delete lines
add [Lines],ax ;Adjust line counter
sub [LinesLeft],ax
mul ax ; (l ^ 3)
mul ax
add ax,4 ; (l ^ 3) + 4
mov bx,5
cwd
div bx ; ((l ^ 3) + 4) / 5
imul ax,100 ;Line score value
add [Score],ax ;add to score
adc [Score+2],0
cmp [LinesLeft],0 ;Done with level?
jg NotNew
pusha ;Save all registers
mov ax,200 ;20 msec
mov bx,440 ;Start at 440
SndLoop1: call Sound ;Sound 440 to 880
add bx,20
cmp bx,880
jne SndLoop1
SndLoop2: call Sound ;Sound 880 to 660
sub bx,20
cmp bx,660
jne SndLoop2
SndLoop3: call Sound ;Sound 660 to 1100
add bx,20
cmp bx,1100
jne SndLoop3
call Sound ;Last sound
call NoSound ;End of sound
popa ;Restore registers
mov [LinesLeft],0 ;LinesLeft = 0
call ShowStatus ;Show status
call ClearWell ;Clear well
imul ax,[Level],100 ;Score = Score + 100 * Level
add [Score],ax
adc [Score+2],0
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 ;Return
EndP LockPiece
;**************************** ShowStatus -- Display score, level, etc.
Proc ShowStatus
pusha ;Save all registers
mov cx,43 ;Clear Score field
mov dx,11
mov si,offset Spaces7
mov al,07h
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 Buffer ;Offset of buffer
mov ax,[Score] ;Get decimal string for Score
mov dx,[Score+2]
mov di,si
call Cvt32
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
mov si,offset Spaces10 ;Clear Next-Piece area
mov cx,36
mov dx,5
mov al,07h
call PutStr
inc dx
call PutStr
inc dx
call PutStr
inc dx
call PutStr
mov bx,[NxPiece]
mov bp,bx
inc bp
xor ax,ax
mov cx,40
mov dx,6
add bx,bx
mov si,[PieceStart+bx] ;SI = piece offset
mov di,4 ;4 blocks
xor ax,ax ;Start - (0, 0)
SSBlkLoop: push cx dx ;Save position
mov bl,ah ;Get offsets in AX, BX
cbw
xchg ax,bx
cbw
xchg ax,bx
add ax,ax ;Add in offsets
add cx,ax
sub dx,bx
mov ax,bp ;Color in AL
call PutBlock ;Show block
pop dx cx ;Restore position
lodsw ;Load word
dec di ;Loop back using DI
jnz SSBlkLoop
popa ;Restore registers
ret ;Return
EndP ShowStatus
;**************************** PutBlock -- Put block on screen
Proc PutBlock
;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 IsZero
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
IsZero: mov ax,0720h ;Zero, store spaces
stosw
stosw
popa ;Restore registers
ret ;Return
EndP PutBlock
;**************************** IsBlock -- Check for block
Proc IsBlock
;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 ;Return
NoBlock: clc ;Clear carry flag
popa ;Restore registers
ret ;Return
EndP IsBlock
;**************************** PutPiece -- Put piece in well
Proc PutPiece
;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 ;Return
EndP PutPiece
;**************************** Fits -- Check whether piece fits
Proc 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 ;Return
DoesntFit: clc ;Clear carry flag
pop dx cx ;Pop extra off stack
popa ;Restore registers
ret ;Return
EndP Fits
;***************************** DelLine -- Delete line
Proc DelLine
;Supply AX = y
pusha ;Save all registers
push ds ;Save DS
push ax ;Save AX
mov ax,250 ;25 msecs
mov bx,440 ;Sound at 440
call Sound
call Delay
mov bx,660 ;Sound at 660
call Sound
call Delay
mov bx,880 ;Sound at 880
call Sound
call Delay
call NoSound ;End of sound
pop ax ;Restore AX
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 ;Return
EndP DelLine
;***************************** DelLines -- Delete all completed lines
Proc DelLines
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 ;Return
EndP DelLines
;**************************** ClearWell -- Clear the well
Proc ClearWell
pusha ;Save all registers
mov di,20 ;Start at offset 20
mov dx,25 ;25 rows on screen
mov ax,0720h ;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 ;Return
EndP ClearWell
;**************************** AddHiScore -- Add high score to list
Proc AddHiScore
pusha ;Save all registers
push es ;Save ES
push ds ;ES = DS
pop es
mov ax,[Score] ;DX:AX = Score
mov dx,[Score+2]
mov bx,offset HiScores+1102 ;Last Score field
cmp dx,[bx+2] ;Make sure it's in the hiscores
jb AddDone
ja HSStart
cmp ax,[bx]
jbe AddDone
HSStart: mov cx,19
HSCmpLoop: cmp dx,[bx+2] ;If Score <= HiScores[i].score,
ja HSCmpLB ;then it is done
jb HSCmpDone
cmp ax,[bx]
jbe HSCmpDone
HSCmpLB: sub bx,58 ;Previous hiscore
dec cx ;Loop back using CX
jns HSCmpLoop
HSCmpDone: inc cx ;Get the actual position
mov dx,cx ;DX = CX
mov bp,cx ;BP = CX
mov cx,19 ;CX = 19
mov di,offset HiScores+1102 ;DI = HS #19
mov si,offset HiScores+1044 ;SI = HS #18
HSMovLoop: cmp cx,dx ;CX > DX, done
je HSMovDone
push cx si si ;Save offsets
mov cx,29 ;Move hiscore
rep movsw
pop si di cx ;DI = old SI
sub si,58 ;SI = old SI - 58
loop HSMovLoop
HSMovDone: pop es ;Restore ES
call ClearScreen ;Clear the screen
mov cx,4 ;Print 'You made a High Score'
mov dx,11 ;at (4, 11), in cyan on blue
mov si,offset YMHS
mov al,9Bh
call PutStr
xor cx,cx ;Print 'Enter your name:'
mov dx,13 ;at (0, 13), in blue
mov si,offset NameStr
mov al,09h
call PutStr
mov bx,2114 ;Current position (17, 13)
mov [word es:bx],0A5Fh ;Show pseudo-cursor
xor si,si ;Cursor position 0
imul bp,58 ;BP = offset of hiscore
add bp,offset HiScores
HSKeyLoop: xor ax,ax ;Get a key
int 16h
cmp ah,BKSPACE ;Backspace?
je HSKeyBksp
cmp ah,LEFT ;Left-arrow?
je HSKeyBksp
cmp ah,ENTERK ;Enter?
je HSKeyEnter
cmp al,20h ;Is it a printable char?
jb HSKeyLoop ;Ignore it if it isn't
cmp al,7Eh
ja HSKeyLoop
cmp si,49 ;Already at limit?
je HSKeyLoop
mov ah,0Ah ;Color is green
mov [es:bx],ax ;Show character
mov [bp+si+8],al ;Put it in string
inc si
inc bx ;Advance cursor
inc bx
mov [word es:bx],0A5Fh ;Show pseudo-cursor
jmp HSKeyLoop
HSKeyBksp: test si,si ;Already at left?
jz HSKeyLoop
mov [byte es:bx],20h
dec si
dec bx ;Move cursor left
dec bx
mov [byte es:bx],5Fh ;Show pseudo-cursor
jmp HSKeyLoop
HSKeyEnter: mov [byte bp+si+8],0 ;Terminate string
mov ax,[Score] ;Put in values
mov [bp],ax
mov ax,[Score+2]
mov [bp+2],ax
mov ax,[Lines]
mov [bp+4],ax
mov ax,[Level]
mov [bp+6],ax
push es ;Dummy
AddDone: pop es
;****************** Show High Scores
call ClearScreen ;Clear the screen
mov cx,29 ;Display the title
xor dx,dx
mov si,offset HiStr
mov al,0Fh
call PutStr
xor cx,cx ;Display HS 'table-top'
mov dx,3
mov si,offset HST1
call PutStr
mov cx,61
mov si,offset HST2
call PutStr
mov bp,1 ;Counter is 1
mov bx,offset HiScores ;Offset of first Hiscore
mov si,offset Buffer ;SI = buffer
ShowLoop: mov ax,bp ;AX = counter
mov di,si ;Convert into buffer
call Cvt16
mov [word di],002Eh ;Add a period (like '15.')
mov dx,bp ;DX = row
add dx,4
mov cx,2 ;Column 2
mov al,09h ;in blue
call PutStr
push si
mov si,bx ;Display name
add si,8
mov cx,6 ;Column 6
mov al,0Ah ;in green
call PutStr
pop si
push dx ;Save row
mov ax,[bx]
mov dx,[bx+2]
mov di,si
call Cvt32 ;Display score
pop dx
mov cx,66 ;Column 66
add cx,si ;on the right
sub cx,di
mov al,0Bh ;in cyan
call PutStr
mov ax,[bx+4] ;Display lines
mov di,si
call Cvt16
mov cx,72 ;Column 72
add cx,si ;on the right
sub cx,di
mov al,0Bh ;in cyan
call PutStr
mov ax,[bx+6] ;Display level
mov di,si
call Cvt16
mov cx,77 ;Column 77
add cx,si ;on the right
sub cx,di
mov al,0Bh ;in cyan
call PutStr
inc bp
add bx,58 ;Next score
cmp bp,20 ;Loop back
jbe ShowLoop
call FlushBuffer ;Flush key buffer
xor ax,ax ;Wait for a key
int 16h
popa ;Restore registers
ret ;Return
EndP AddHiScore
;**************************** ClearScreen -- Clear the screen
Proc ClearScreen
pusha ;Save all registers
xor di,di ;Zero DI
mov ax,0720h ;Fill with spaces
mov cx,32768 ;32768 words
rep stosw ;Clear screen
popa ;Restore registers
ret ;Return
EndP ClearScreen
;**************************** PutStr -- Print ASCIIZ string
Proc PutStr
;Supply (CX, DX) = position, AL = color, DS:SI = string
pusha ;Save all registers
imul di,dx,160 ;DI = DX * 160
add di,cx ;DI = DX * 160 + CX * 2
add di,cx
mov ah,al ;AH = color
PutLoop: lodsb ;Load byte
test al,al ;Quit if zero
jz PutDone
stosw ;Store word
jmp PutLoop
PutDone: popa ;Restore registers
ret ;Return
EndP PutStr
;**************************** FlushBuffer -- flush keyboard buffer
Proc FlushBuffer
push ds ;Save DS
push 0 ;DS = 0
pop ds
push [word 041Ah] ;Key tail = key head
pop [word 041Ch]
pop ds ;Restore DS
ret ;Return
EndP FlushBuffer
;**************************** Cvt16 -- Convert 16-bit binary to decimal
Proc Cvt16
;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 ;Return
U16Zero: mov [byte di],30h ;It was zero, so store a '0'.
inc di
jmp U16Ret
EndP Cvt16
;**************************** Cvt32 -- Convert 32-bit binary to decimal
Proc Cvt32
;Supply DX:AX = binary value, DS:DI = 5 bytes string space
push ax bx dx ;Save all registers
mov bx,10000 ;Divide it by 10000
div bx
test ax,ax ;Don't do first part if it's zero
jz Cvt32Less
call Cvt16 ;Convert first part
xchg ax,dx ;Remainder in AX
call Cvt16B ;Convert last 4
Cvt32Done: pop dx bx ax ;Restore all registers
ret ;Return
Cvt32Less: xchg ax,dx
call Cvt16
jmp Cvt32Done
EndP Cvt32
;**************************** Cvt16B -- Convert 16-bit binary to decimal
Proc Cvt16B
;Supply AX = binary value, DS:DI = 5 bytes string space
pusha ;Save registers
pop di
mov si,10 ;SI = 10
mov bp,4
mov cx,bp
Z16DivLoop: 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
dec bp ;Done?
jnz Z16DivLoop ;Loop back if not
Z16PopLoop: pop ax ;Pop digit
mov [di],al ;Store digit
inc di
loop Z16PopLoop ;Loop back
mov [byte di],0 ;Store ending null
push di ;Restore registers
popa
ret ;Return
EndP Cvt16B
;**************************** Rand7 -- Generate a random number from 1 to 7
Proc Rand7
mov ax,7 ;call Rand with value 7
call Rand
ret
EndP Rand7
;**************************** Rand -- Generate a random number
Proc Rand
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 ;Return
EndP Rand
;**************************** Sound -- Sound the speaker.
Proc Sound
;Supply AX = delay, BX = frequency
pusha ;Save all registers
mov dx,12h ;BX = 1193180 / freq.
mov ax,34DCh
div bx
mov bx,ax
mov al,0B6h ;Set frequency
out 43h,al
mov ax,bx
out 42h,al
mov al,ah
out 42h,al
in al,61h ;Turn on speaker
or al,3
out 61h,al
popa ;Restore registers
call Delay ;Do the delay
ret ;Return
EndP Sound
;**************************** NoSound -- Turn off the speaker.
Proc NoSound
push ax ;Save AX
in al,61h ;Turn off speaker
and al,0FCh
out 61h,al
pop ax ;Restore AX
ret ;Return
EndP NoSound
;**************************** Delay -- Delay.
Proc Delay
;Supply AX = msecs * 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 ;Return
EndP Delay
;****************** Variables
Spaces10 db 3 dup(?)
Spaces7 db 8 dup(?)
GOBottom db 2 dup(?)
BoxTop db 17 dup(?)
GOTop db 2 dup(?)
BoxBottom db 17 dup(?)
RandNum dw ?,?
Score dw ?,?
Lines dw ?
Level dw ?
DelayTime dw ?
LinesLeft dw ?
Piece dw ?
Rotate dw ?
NxPiece dw ?
X dw ?
Y dw ?
HiScores dw 580 dup(?)
Buffer:
End Start