TETRISK1.A
Assembly source for Tetrisk, 1370 lines. Raw file
; TETRISK v1.0 - Basic graphics.
; <c> LKS 1994.
; History: Create 2/5/94. Now 2/5/94.
POINTER_SIZE equ 11+256*17
POINTER_SPRITE equ 16
POINTER_MASK equ 16+11
POINTER_UNDER equ 16+22
TINYNUM_SIZE equ 4+256*5
TINYNUM_SPRITE equ 16+320*27
SMALLNUM_SIZE equ 5+256*7
SMALLNUM_SPRITE equ 49+320*10
BIGNUM_SIZE equ 7+256*9
BIGNUM_SPRITE equ 49
dseg
filename: db 'TETRISK.V10', 00h
handle: dw 0000h
mouseflag: dw 0000h ; Contains -1 if mouse present.
oldmode: db 00h ; Screen mode before change to graphics.
loadmagic: dw 0000h
loadver: dw 0000h
checkmagic: db 'TR'
checkver: db 01h,00h
mousex: dw 0000h
mousey: dw 0000h
score: db 00h, 00h, 00h, 00h, 00h, 00h, 00h, 01h
scoreadd: dd 00h, 00h, 00h, 00h, 00h, 00h, 00h, 00h
speed: db 10
piecenum: db 00h ; Number of active pieces (up to 8).
;piece_x: dq 0000h ; X co-ordinates of pieces.
;piece_y: dq 0000h ; Y co-ordinate.
;piece_type: dq 0000h ; Type of piece (0-6).
cseg
; Processor registers.
stor_cs: dw 0000h
stor_ds: dw 0000h
stor_gs: dw 0A000h
stor_ss: dw 0000h
; Memory allocation registers. (Each one is a free 64k segment).
stor_s1: dw 0000h ; A copy of the background screen + pal.
stor_s2: dw 0000h ; The character storage space.
stor_s3: dw 0000h ; Reserved for future expansion.
stor_s4: dw 0000h ; Reserved for future expansion
public main_
main_:
call logon
jc main_end
call maingame
call logoff
main_end:
ret
;----------------------------- Interrupt handler(s) -------------------------
; Graphics bitblt.
; CL - Length.
; CH - Height.
; DS:SI - Source sprite.
; ES:DI - Destination sprite.
graph_blit:
cld
xor bh, bh
mov bl, cl
mov ax, 320
sub ax, bx
graph_blit_y:
mov bx, cx
xor ch, ch
rep movsb
mov cx, bx
add si, ax
add di, ax
dec ch
jnz graph_blit_y
ret
; Graphics bitblt on green.
; CL - Length.
; CH - Height.
; DS:SI - Source sprite.
; ES:DI - Destination sprite.
graph_blitg:
xor bh, bh
mov bl, cl
mov dx, 320
sub dx, bx
graph_blitg_y:
mov bx, cx
xor ch, ch
graph_blitg_x:
mov al, ds: [si]
cmp byte es: [di], 224
jl graph_blitg_no
cmp byte es: [di], 240
jge graph_blitg_no
mov es: [di], al
graph_blitg_no:
inc di
inc si
loop graph_blitg_x
mov cx, bx
add si, dx
add di, dx
dec ch
jnz graph_blitg_y
ret
; Graphics bitblt special.
; CL - Length.
; CH - Height.
; DS:SI - Source sprite.
; ES:DI - Destination sprite.
graph_blitspec:
xor bh, bh
mov bl, cl
mov dx, 320
sub dx, bx
graph_blitspec_y:
mov bx, cx
xor ch, ch
graph_blitspec_x:
mov al, ds: [si]
db 26h
graph_blitsin:
db 88h ; MOV ES:[DI], AL = 26 88 05
db 05h ; AND ES:[DI], AL = 26 20 05
inc di ; XOR ES:[DI], AL = 26 30 05
inc si
loop graph_blitspec_x
mov cx, bx
add si, dx
add di, dx
dec ch
jnz graph_blitspec_y
ret
; Score addon.
; Adds var scoreadd to score (both byte decimals (one byte = one digit)).
score_addon:
mov cx, 8
mov bx, offset cs: scoreadd + 7
score_addloop:
mov al, ds: [bx + 8]
add al, ds: [bx]
score_testcarry:
cmp al, 10
jl score_noverflow
sub al, 10
cmp cx, 1
je score_testcarry
inc byte ds: [bx - 1]
jmp score_testcarry
score_noverflow:
mov ds: [bx], al
loop score_addloop
ret
;----------------------------- Game subfunctions ----------------------------
; Maingame.
maingame:
call game_logon
maingame_loop:
mov cx, 200
mov es, cs: stor_gs
mov di, 0
l2:
mov byte es: [di], 0
add di, 320
loop l2
call graphwait
mov cx, 200
mov es, cs: stor_gs
mov di, 0
l1:
mov byte es: [di], 255
add di, 320
loop l1
call game_mouseoff
; call score_addon
; REST OF GAME CODE GOES IN HERE!!!
call game_conveyor
call game_display1
call game_display2
call game_mouseon
in al, 60h
cmp al, 129
jne maingame_loop
call game_logoff
ret
; Game mouse off.
game_mouseoff:
; Turn off mouse pointer.
mov ax, 320
mul word ds: mousey
add ax, word ds: mousex
mov ds, cs: stor_s2
mov si, POINTER_UNDER
mov es, cs: stor_gs
mov di, ax
mov cx, POINTER_SIZE
call graph_blit
mov ds, cs: stor_ds
ret
; Game move conveyor.
game_conveyor:
; Move conveyor up.
mov ds, cs: stor_gs
mov es, cs: stor_gs
mov si, 133+320*94
mov di, 133+320*93
mov cx, 39+256*28
call graph_blit ; Top part.
mov si, 133+320*140
mov di, 133+320*139
mov cx, 39+256*60
call graph_blit ; Bottom part.
; Put in extra sections.
mov ds, cs: stor_s2
mov si, cs: game_conv_pat
mov di, 133+320*121
mov cx, 39+256*1
call graph_blit
mov si, cs: game_conv_pat
mov di, 133+320*199
mov cx, 39+256*1
call graph_blit
mov ax, cs: game_conv_pat
add ax, 39
cmp ax, 64000-39
jl game_conv_nover
sub ax, 320*12-39
game_conv_nover:
mov cs: game_conv_pat, ax
mov ds, cs: stor_ds
; Put on the highlight....
mov di, 133+320*93
mov al, 4
game_conv_hiloop_y:
mov cx, 39
game_conv_hiloop_x:
inc byte es: [di]
inc di
loop game_conv_hiloop_x
add di, 320-39
dec al
jnz game_conv_hiloop_y
; ...And the shadow.
mov di, 133+320*142
mov al, 2
game_conv_shadloop_y:
mov cx, 39
game_conv_shadloop_x:
cmp byte es: [di], 32
jge game_conv_nomore
dec byte es: [di]
game_conv_nomore:
inc di
loop game_conv_shadloop_x
add di, 320-39
dec al
jnz game_conv_shadloop_y
ret
game_conv_pat: dw 64000-320*12
; Game display 1.
game_display1:
; Put on flashing 0's and timer :.
mov es, cs: stor_gs
mov ax, cs: game_disp1_flash
inc ax
mov cs: game_disp1_flash, ax
cmp al, 45
jl game_disp1_flashon
mov ds, cs: stor_s1
mov es, cs: stor_gs
mov si, 270+320*88
mov di, si
mov cx, 5+256*5
call graph_blitg
mov si, 275+320*88
mov di, si
mov cx, 16+256*16
call graph_blit
mov ds, cs: stor_ds
mov byte es: [280+320*83], 236
mov byte es: [280+320*85], 236 ; Draw colon.
jmp game_disp1_flashoff
game_disp1_flashon:
mov ds, cs: stor_s2
mov es, cs: stor_gs
mov si, TINYNUM_SPRITE
mov di, 270+320*88
mov cx, TINYNUM_SIZE
call graph_blitg
mov si, TINYNUM_SPRITE
mov di, 275+320*88
mov cx, TINYNUM_SIZE
call graph_blit
mov si, TINYNUM_SPRITE
mov di, 282+320*88
mov cx, TINYNUM_SIZE
call graph_blit
mov si, TINYNUM_SPRITE
mov di, 287+320*88
mov cx, TINYNUM_SIZE
call graph_blit
mov ds, cs: stor_ds
mov byte es: [280+320*83], 224
mov byte es: [280+320*85], 224 ; Clear colon.
game_disp1_flashoff:
; Display clock.
mov ah, 02h
int 1Ah ; Read real-time clock.
mov ds, cs: stor_s2
mov es, cs: stor_gs
cmp dh, cs: game_disp1_sec
je game_disp1_nosec
mov cs: game_disp1_sec, dh
mov word cs: game_disp1_flash, 0 ; Reset flash counter if sec passed.
game_disp1_nosec:
; 0x:xx
cmp ch, 00h
jne game_disp1_no0
mov ch, 12h
game_disp1_no0:
cmp ch, 12h
jle game_disp1_no24
cmp ch, 20h
jne game_disp1_not20
mov ch, 08h
jmp game_disp1_no24
game_disp1_not20:
cmp ch, 21h
jne game_disp1_not21
mov ch, 09h
jmp game_disp1_no24
game_disp1_not21:
sub ch, 12h
game_disp1_no24:
push cx
xor cl, cl
and ch, 0F0h
shr ch, 1
shr ch, 1
xchg cl, ch
mov si, TINYNUM_SPRITE
add si, cx
mov di, 270+320*82
mov cx, TINYNUM_SIZE
call graph_blitg
pop cx
; x0:xx
push cx
xor cl, cl
and ch, 0Fh
shl ch, 1
shl ch, 1
xchg cl, ch
mov si, TINYNUM_SPRITE
add si, cx
mov di, 275+320*82
mov cx, TINYNUM_SIZE
call graph_blit
pop cx
; xx:0x
push cx
xor ch, ch
and cl, 0F0h
shr cl, 1
shr cl, 1
mov si, TINYNUM_SPRITE
add si, cx
mov di, 282+320*82
mov cx, TINYNUM_SIZE
call graph_blit
pop cx
; xx:x0
push cx
xor ch, ch
and cl, 0Fh
shl cl, 1
shl cl, 1
mov si, TINYNUM_SPRITE
add si, cx
mov di, 287+320*82
mov cx, TINYNUM_SIZE
call graph_blit
pop cx
cmp ch, 10 ; Is hour < 10 ?
jg game_disp1_hour2
mov ds, cs: stor_s1
mov si, 270+320*82
mov di, si
mov cx, TINYNUM_SIZE
call graph_blitg
game_disp1_hour2:
mov ds, cs: stor_ds
ret
game_disp1_flash: dw 0000h
game_disp1_sec: db 00h
; Game diplay 2.
game_display2:
ret
; Game mouse on.
game_mouseon:
; Turn mouse pointer on.
mov ax, 3
int 33h ; Get mouse position.
mov ds: mousex, cx
mov ds: mousey, dx
; Get sprite under pointer.
mov ax, 320
mul dx
add ax, cx
push ax
mov ds, cs: stor_gs
mov si, ax
mov es, cs: stor_s2
mov di, POINTER_UNDER
mov cx, POINTER_SIZE
call graph_blit
mov ds, cs: stor_ds
; Blit the AND mask.
mov ds, cs: stor_s2
mov si, POINTER_MASK
mov es, cs: stor_gs
pop di
push di
mov cx, POINTER_SIZE
mov byte cs: graph_blitsin, 20h
call graph_blitspec
; Blit XOR sprite.
mov ds, cs: stor_s2
mov si, POINTER_SPRITE
mov es, cs: stor_gs
pop di
mov cx, POINTER_SIZE
mov byte cs: graph_blitsin, 30h
call graph_blitspec
mov ds, cs: stor_ds
ret
; Game logon.
game_logon:
; Fade down text screen.
mov ax, 1017h
mov bx, 0
mov cx, 100h
mov dx, 64000
mov es, cs: stor_s2
int 10h ; Get old palette.
xor bx, bx
mov cx, 100h
mov dl, 6
mov si, 64000
mov ds, cs: stor_s2
call graphfadedown
mov ds, cs: stor_ds
; Get old graphics mode and set it to MCGA 320x200x256.
mov ah, 0Fh
int 10h
mov ds: oldmode, al
mov ax, 13h
int 10h
; Clear the palette and copy S1 into GS.
xor bx, bx
mov cx, 100h
call graphclearpalette
cld
xor di, di
and si, di
mov si, 0
mov ds, cs: stor_s1
mov es, cs: stor_gs
mov cx, 32000
rep movsw
mov ds, cs: stor_ds
; Set up variables.
mov ax, 7
mov cx, 10
mov dx, 298
int 33h ; Set mouse X bounds.
mov ax, 8
mov cx, 60
mov dx, 180
int 33h ; Set mouse Y bounds.
; Set mouse position.
mov ax, 4
mov cx, 159
mov dx, 99
int 33h
mov ds: mousex, 159
mov ds: mousey, 99
; Set up sprites.
call game_mouseon
; Fade up palette.
xor bx, bx
mov cx, 100h
mov dl, 5
mov si, 64000
mov ds, cs: stor_s1
call graphfadeup
mov ds, cs: stor_ds
ret
; Game logoff
game_logoff:
; Fade down graphics screen.
xor bx, bx
mov cx, 100h
mov dl, 5
mov si, 64000
mov ds, cs: stor_s1
call graphfadedown
mov ds, cs: stor_ds
; Back to text mode.
mov ah, 0
mov al, ds: oldmode
int 10h
xor bx, bx
mov cx, 100h
; Get text palette before clearing.
mov ax, 1017h
mov bx, 0
mov cx, 100h
mov dx, 64000
mov es, cs: stor_s2
int 10h
call graphclearpalette
; Pause one second.
mov cx, 60
call graphdelay
call text
db 0Dh, 0Ah, 'þ Thank you for playing TETRISK v1.0 þ', 0Dh, 0Ah, 00h
; Fade up.
xor bx, bx
mov cx, 100h
mov dl, 4
mov si, 64000
mov ds, cs: stor_s2
call graphfadeup
mov ds, cs: stor_ds
ret
;----------------------------- Main subfunctions ----------------------------
; Logon.
logon:
call logon_storesegs
jc logon_error
call logon_message
jc logon_error
call logon_sysinfo
jc logon_error
call logon_memalloc
jc logon_error
call logon_testmouse
jc logon_error
call logon_openfile
jc logon_error
call logon_hookkbd
jc logon_error
call text
db 0Dh, 0Ah, 'þ Press any key...', 00h
call getkey
call newline
logon_error:
ret
; Logon store segments.
logon_storesegs:
; Store segments.
mov cs: stor_cs, cs
mov cs: stor_ds, ds
mov cs: stor_ss, ss
clc
ret
; Logon message.
logon_message:
; Get screen mode.
mov ah, 0Fh
int 10h
and al, 7Fh ; Mask out bit 7 (no clear screen).
mov ds: oldmode, al
; Clear screen.
xor ah, ah
int 10h
; Introduction.
call text
db 0Dh, 0Ah, 'þ TETRISK v1.0 þ <c> LKS 1994.', 0Dh, 0Ah, 0DH, 0Ah, 00h
clc
ret
; Logon system information.
logon_sysinfo:
; Get and interpret equipment status word.
int 11h
push ax
call text
db ' Processor: 80x86.', 0Dh, 0Ah, ' Co-processor: ', 00h
pop ax
and ax, 1
jz logon_nocopro
call text
db 'Present.', 0Dh, 0Ah, 00h
jmp logon_aftercopro
logon_nocopro:
call text
db 'Not present.', 0Dh, 0Ah, 00h
logon_aftercopro:
; Get DOS info.
mov ax, 3306h
int 21h
push dx
add cs: logon_dosmax, bl
add cs: logon_dosmin, bh
and dl, 11b
add cs: logon_dosrev, dl
call text
db ' DOS info: v'
logon_dosmax: db '0.'
logon_dosmin: db '0 r'
logon_dosrev: db '0 ', 00h
pop dx
push dx
test dh, 1000b
jnz logon_romdos
call text
db 'RAM', 00h
jmp logon_ramdos
logon_romdos:
call text
db 'ROM', 00h
logon_ramdos:
pop dx
test dh, 10000b
jz logon_nohidos
call text
db ' HMA', 00h
logon_nohidos:
call text
db '.', 0Dh, 0Ah, 00h
; See which disk DOS booted from.
mov ax, 3305h
int 21h
add logon_dosboot, dl
call text
db ' DOS boot drive: '
logon_dosboot: db '@:.', 0Dh, 0Ah, 00h
clc
ret
; Logon memory allocation.
logon_memalloc:
; See how much memory spare by trying to allocate too much.
mov ah, 48h
mov bx, 0FFFFh
int 21h
push bx
mov ax, bx
mov bx, offset cs: logon_memalloc_mem
mov ch, 4
mov ds, cs: stor_cs
call hex2text
mov ds, cs: stor_ds
call text
db ' Free memory: '
logon_memalloc_mem: db '____h paragraphs.', 0Dh, 0Ah, 00h
pop bx
cmp bx, 4010h ; 10h more just to be on the safe side.
jge logon_memok ; There is enough memory.
call text
db 0Dh, 0Ah, 'þ ERROR þ Not enough memory.', 0Dh, 0Ah, 00h
stc
ret
logon_memok:
; Allocate 4000h paragraphs of memory as four 64k chunks, S1-S4.
mov ah, 48h
mov bx, 1000h
int 21h
jc logon_memalloc_err
mov cs: stor_s1, ax
mov ah, 48h
mov bx, 1000h
int 21h
jc logon_memalloc_err
mov cs: stor_s2, ax
mov ah, 48h
mov bx, 1000h
int 21h
jc logon_memalloc_err
mov cs: stor_s3, ax
mov ah, 48h
mov bx, 1000h
int 21h
jc logon_memalloc_err
mov cs: stor_s4, ax
; Display error contents of S1-S4.
mov ds, cs: stor_cs
mov ax, cs: stor_s1
mov bx, offset cs: logon_memalloc_s1
mov ch, 4
call hex2text
mov ax, cs: stor_s2
mov bx, offset cs: logon_memalloc_s2
mov ch, 4
call hex2text
mov ax, cs: stor_s3
mov bx, offset cs: logon_memalloc_s3
mov ch, 4
call hex2text
mov ax, cs: stor_s4
mov bx, offset cs: logon_memalloc_s4
mov ch, 4
call hex2text
mov ds, cs: stor_ds
call text
db ' þ S1: '
logon_memalloc_s1: db '____h', 0Dh, 0Ah, ' þ S2: '
logon_memalloc_s2: db '____h', 0Dh, 0Ah, ' þ S3: '
logon_memalloc_s3: db '____h', 0Dh, 0Ah, ' þ S4: '
logon_memalloc_s4: db '____h', 0Dh, 0Ah, 00h
; Check how much memory spare after allocation.
mov ah, 48h
mov bx, 0FFFFh
int 21h
mov ax, bx
mov bx, offset cs: logon_memalloc_aftermem
mov ch, 4
mov ds, cs: stor_cs
call hex2text
mov ds, cs: stor_ds
call text
db ' After allocation: '
logon_memalloc_aftermem: db '____h paragraphs.', 0Dh, 0Ah, 00h
clc
ret
logon_memalloc_err:
; Display error message.
call text
db 0Dh, 0Ah, 'þ ERROR þ Cannot allocate a 64k segment.', 0Dh, 0Ah, 00h
stc
ret
; Logon test mouse
logon_testmouse:
; Check if mouse driver loaded.
call text
db ' Mouse: ', 00h
xor ax, ax
int 33h
mov ds: mouseflag, ax
or ax, ax
jnz logon_mouseok
call text
db 'Not present.', 0Dh, 0Ah, 00h
jmp logon_aftermouse
logon_mouseok:
add cs: logon_mouseb, bl
call text
db 'Present ('
logon_mouseb: db '0 Buttons).', 0Dh, 0Ah, 00h
; Set mouse speed.
mov ax, 0Fh
mov cx, 24
mov dx, 24
int 33h
logon_aftermouse:
clc
ret
; Logon open data file.
logon_openfile:
mov ax, 3D00h
mov dx, offset cs: filename
mov ds, cs: stor_ds
int 21h
jnc logon_fileok
call text
db 0Dh, 0Ah, 'þ ERROR þ Cannot open data file TETRISK.V10.', 0Dh, 0Ah, 00h
stc
ret
logon_fileok:
mov ds: handle, ax
call text
db ' TETRISK data file: TETRISK.V10', 0Dh, 0Ah, 00h
; Read 4-byte magic and version number pair and check.
mov ah, 3Fh
mov bx, ds: handle
mov cx, 4
mov dx, offset ds: loadmagic
int 21h
jnc logon_filetestok
call text
db 0Dh, 0Ah, 'þ ERROR þ Cannot read data file.', 0Dh, 0Ah, 00h
stc
ret
logon_filetestok:
call text
db ' þ Data magic: ', 00h
mov ax, ds: loadmagic
cmp ax, word ds: checkmagic
je logon_magicok
call text
db 'Illegal.', 0Dh, 0Ah, 0Dh, 0Ah, 'þ ERROR þ Illegal data file magic.', 0Dh, 0Ah, 00h
stc
ret
logon_magicok:
mov ax, loadver
xchg ah, al
mov bx, offset cs: logon_version
mov ch, 2
mov ds, cs: stor_cs
call hex2text
inc bx
mov ch, 2
call hex2text
mov ds, cs: stor_ds
call text
db 'Accepted.', 0Dh, 0Ah, ' þ Data version: '
logon_version: db '__.__', 0Dh, 0Ah, ' Loading file: ------------------.', 00h
; Read palette.
mov ax, 4200h
mov bx, ds: handle
xor cx, cx
mov dx, 10h
int 21h ; Position file pointer.
mov ah, 3Fh
mov bx, ds: handle
mov cx, 300h
mov dx, 64000
mov ds, stor_s1
int 21h
mov ds, cs: stor_ds
; Load background screen into S1.
mov ax, 4200h
mov bx, ds: handle
xor cx, cx
mov dx, 310h
int 21h ; Position file pointer.
mov bx, offset cs: logon_loadbackbar
mov dx, 0
logon_loadback:
push bx
push dx
mov ah, 3Fh
mov bx, ds: handle
mov cx, 6400
mov ds, cs: stor_s1
int 21h
mov ds, cs: stor_ds
call text
db 0Dh, ' Loading file: '
logon_loadbackbar: db '------------------.', 00h
pop dx
pop bx
mov byte cs: [bx], 254
inc bx
add dx, 6400
cmp dx, 64000
jne logon_loadback
; Load character screen into S2.
mov bx, offset cs: logon_loadcharbar
mov dx, 0
logon_loadchar:
push bx
push dx
mov ah, 3Fh
mov bx, ds: handle
mov cx, 6400
mov ds, cs: stor_s2
int 21h
mov ds, cs: stor_ds
call text
db 0Dh, ' Loading file: þþþþþþþþþ'
logon_loadcharbar: db '---------.', 00h
pop dx
pop bx
mov byte cs: [bx], 254
inc bx
add dx, 6400
cmp dx, 64000
jne logon_loadchar
call newline
; Close data file.
mov ah, 3Eh
mov bx, ds: handle
int 21h
clc
ret
; Logon hook keyboard IRQ.
logon_hookkbd:
call text
db ' Keyboard IRQ: Cannot hook.', 0Dh, 0Ah, 00h
clc
ret
; Logoff.
logoff:
clc
ret
;----------------------------- Library Functions ----------------------------
; Text
; Usage: call text
; db 'Message... ', 00h ; Null terminated.
; <next instruction>
text:
pop si
textloop:
push si
mov ah, 0Eh
mov al, byte cs: [si]
mov bx, 7
int 10h
pop si
inc si
cmp byte cs: [si], 0
jne textloop
inc si
push si
ret
; NewLine
newline:
call text
db 0Dh, 0Ah, 00h
ret
; Delete
delete:
mov ah, 0Eh
mov al, 08
mov bx, 15
int 10h
ret
; Hex2Text
; Inputs: AX = Hex number.
; CH = Number of digits.
; DS:BX = Pointer to output string.
hex2text:
mov di, ax
mov cl, 12
shr di, cl
add di, offset cs: hex2textlookup
mov cl, cs: [di]
mov ds: [bx], cl
mov cl, 4
shl ax, cl
inc bx
dec ch
jne hex2text
ret
hex2textlookup:
db '0123456789ABCDEF'
; GetKey
; Returns character in AL.
getkey:
mov ah, 7
int 21h
cmp ah, 0
jne getkey_notext ; Not an extended keycode.
mov ah, 7
int 21h
mov ah, al
xor al, al
getkey_notext:
ret
; GetKeyExt
; Returns char in AL, and sets carry if it is an extended keycode.
getkeyext:
call getkey
cmp al, 0
jne getkeyextnot
call getkey
stc
ret
getkeyextnot:
ret
; Clear Key Buf
clearkeybuf:
mov ah, 0Bh
int 21h ; Check for character waiting.
cmp al, 0
jne clearkeybufget ; Jump over the RET if there is.
ret
clearkeybufget:
call getkey
jmp clearkeybuf
; Error
; Usage: call error ; No return from this function.
; db '<Error message>' ; Null terminated.
error:
call text
db 'ERROR - þ'
; Display error message.
pop si
errortext:
push si
mov ah, 0Eh
mov al, byte cs: [si]
mov bx, 15
int 10h
pop si
inc si
cmp byte cs: [si], 0
jne errortext
inc si
push si
call newline
; Get extended error information.
mov ah, 59h
mov bx, 00h
int 21h
push cx
push bx
push ax
; Put AX into string.
pop ax
mov bx, offset cs: errorax
mov ch, 4
mov ds, word cs: stor_cs
call hex2text
; Put BX into string.
pop ax
mov bx, offset cs: errorbx
mov ch, 4
mov ds, word cs: stor_cs
call hex2text
; Put CH into string.
pop ax
mov bx, offset cs: errorch
mov ch, 2
mov ds, word cs: stor_cs
call hex2text
mov ds, word cs: stor_ds
; Write error information.
call text
db ' Return codes (21/59) - AX:'
errorax: db '0000 BX:'
errorbx: db '0000 CH:'
errorch: db '00þ'
call newline
ret
;----------------------------- Graphics Functions ---------------------------
; 768-byte buffer for temporary storage of palettes.
; Filled with very misleading text for anyone who looks at the executable.
graphpal:
db 'ERROR - There seems to be a sheep in the computer.$n'
db 'Please contact us immediately on: 0296 613225.þ'
db 'ERROR - This computer is not a PC compatible$nþ'
db 'ERROR - Not enough memory (BATTEROID requires at least 4Gb)$nþ'
db 'FATAL ERROR - No processor detected (BATTEROID needs at least one to run!)$nþ'
db 'ERROR - Fixed disk fault$nþ'
db 'ERROR - Printer not connected$nþ'
db 'WARNING - The %s has %s$nþ'
db 'Initiating self destruct sequence. $nþ10þ09þ08þ07þ06þ05þ04þ03þ02þ01þ00þ'
db '$n$nþ'
db 'DEBUG Mode activated. Please type in your authorization code:þ'
db '%sþ0123675440þPOVþ$n$n$dþ'
db 'ERROR - Indirect maximum payload already sequenced.$nþ'
db 'TEST System: AX:þ BX:þ CX:þ DX:þ $nSegment:%Xh Offset:%Xh$nþ'
db 'This program requires Microsoft Golfþ'
db 'LKSþJDWþTgGWfpOn*íþ'
db 'ERROR - Cannot relocate BOOT sector.$nþ'
db ' Motorcycle Emptyness...$n'
; Graphics Wait.
graphwait:
mov dx, 3DAh ; Vertical reset @ bit 3 of port 3DAh.
graphwaitloop:
in al, dx ; Read the port.
test al, 08h ; Test bit 3.
jz graphwaitloop ; Not set? Repeat until it is.
ret
; Graphics Delay
; Input: CX - Number of vertical retraces to wait.
graphdelay:
push ax ; Store registers which are used.
push dx
graphdelayloop:
call graphwait
graphdelaywait:
in al, dx ; Read the port.
and al, 08h ; Test bit 3.
cmp al, 0
jne graphdelaywait ; Is it set? Repeat until it is not set.
loop graphdelayloop ; Decrement CX and loop until CX = 0.
pop dx
pop ax ; Restore the trashed registers.
ret
; Graphics Clear Palette.
; Inputs: BX - First colour to clear.
; CX - Number of colours.
graphclearpalette:
mov ax, cx ; Multiply CX by three to get the size of the
add cx, ax ; palette in bytes (each colour is three bytes).
add cx, ax
push ax ; Keep a copy of the old CX for after the loop.
push bx ; Keep a backup of BX for after the loop.
graphclearpaletteloop:
mov byte cs: graphpal[bx], 0
inc bx
loop graphclearpaletteloop
mov ax, 1012h
pop bx
pop cx
mov dx, offset cs: graphpal
mov es, word cs: stor_cs
int 10h
ret
; Graphics Fade up.
; Inputs:
;
; BX - First colour register to be faded.
; CX - Number of colours.
; DL - Number of steps (2^DL).
; DS:SI - Destination palette.
graphfade_first: dw 0000h
graphfade_bytes: dw 0000h
graphfade_cols: dw 0000h
graphfade_steps: db 00h
graphfade_loop: db 00h
graphfadeup:
; Set up the fade variables.
mov word cs: graphfade_first, bx ; Store the params.
mov word cs: graphfade_cols, cx
mov byte cs: graphfade_steps, dl
mov bx, cx ; Multiply the number of colours
add bx, cx ; by three - the size of the pal
add bx, cx ; in bytes. There are three bytes
mov word cs: graphfade_bytes, bx ; per colour.
; Copy the dest pal into the pal buffer.
push si
cld ; Copy direction = forward.
mov cx, bx
mov es, word cs: stor_cs
mov di, offset graphpal
rep movsb
pop si
; Copy DS into ES now instead of before the palette change to save time.
mov ax, ds
mov es, ax
; The dest palette is used as fade workspace as it will end up back in
; it's original state after the fade up.
mov byte cs: graphfade_loop, 0 ; Clear counter.
graphfadeuploop:
xor bx, bx
graphfadeupcolloop:
mov al, byte cs: graphfade_loop
mul byte cs: graphpal[bx]
mov cl, byte cs: graphfade_steps
shr ax, cl
mov byte ds: [si+bx], al
inc bx
cmp bx, word cs: graphfade_bytes
jl graphfadeupcolloop
; Wait for VScan.
call graphwait
; Set palette.
mov ax, 1012h
mov bx, word cs: graphfade_first
mov cx, word cs: graphfade_cols
mov dx, si
int 10h
inc byte cs: graphfade_loop
mov bl, byte cs: graphfade_loop
mov cl, byte cs: graphfade_steps
shr bl, cl
cmp bl, 1
jne graphfadeuploop
; Set the palette to the dest palette.
mov cx, word cs: graphfade_bytes
mov ds, word cs: stor_cs
mov di, si
mov si, offset cs: graphpal
rep movsb
; Set palette.
mov ax, 1012h
mov bx, word cs: graphfade_first
mov cx, word cs: graphfade_cols
mov dx, offset cs: graphpal
mov es, word cs: stor_cs
int 10h
ret
; Graphics Fade down.
; Inputs:
;
; BX - First colour register to be faded.
; CX - Number of colours.
; DL - Number of steps (2^DL).
; DS:SI - Destination palette.
graphfadedown:
; Set up the fade variables.
mov word cs: graphfade_first, bx ; Store the params.
mov word cs: graphfade_cols, cx
mov byte cs: graphfade_steps, dl
mov bx, cx ; Multiply the number of colours
add bx, cx ; by three - the size of the pal
add bx, cx ; in bytes. There are three bytes
mov word cs: graphfade_bytes, bx ; per colour.
; Copy the dest pal into the pal buffer.
push si
cld ; Copy direction = forward.
mov cx, bx
mov es, word cs: stor_cs
mov di, offset cs: graphpal
rep movsb
pop si
; Copy DS into ES now instead of before the palette change to save time.
mov ax, ds
mov es, ax
; The dest palette is used as fade workspace and is reset to
; it's original state after the fade down.
mov cl, dl
mov dl, 1
shl dl, cl
mov byte cs: graphfade_loop, dl ; Set counter to maximum.
graphfadedownloop:
xor bx, bx
graphfadedowncolloop:
mov al, byte cs: graphfade_loop
mul byte cs: graphpal[bx]
mov cl, byte cs: graphfade_steps
shr ax, cl
mov byte ds: [si+bx], al
inc bx
cmp bx, word cs: graphfade_bytes
jne graphfadedowncolloop
; Wait for VScan.
call graphwait
; Set palette.
mov ax, 1012h
mov bx, word cs: graphfade_first
mov cx, word cs: graphfade_cols
mov dx, si
int 10h
; Decrement counter and loop if greater than or equal to zero.
dec byte cs: graphfade_loop
cmp byte cs: graphfade_loop, 0
jge graphfadedownloop
; Reset the source palette to it's original values by copying the
; palette buffer into it.
mov cx, word cs: graphfade_bytes
mov ax, ds
mov es, ax
mov ds, word cs: stor_cs
mov di, si
mov si, offset cs: graphpal
rep movsb
mov ds, word cs: stor_ds ; Restore DS.
ret